PluginEditor.cpp (16262B)
1 /* 2 ============================================================================== 3 4 This file was auto-generated! 5 6 It contains the basic framework code for a JUCE plugin editor. 7 8 ============================================================================== 9 */ 10 11 #include "PluginProcessor.h" 12 #include "PluginEditor.h" 13 14 //============================================================================== 15 ProteusAudioProcessorEditor::ProteusAudioProcessorEditor (ProteusAudioProcessor& p) 16 : AudioProcessorEditor (&p), processor (p) 17 { 18 // Make sure that before the constructor has finished, you've set the 19 // editor's size to whatever you need it to 20 21 // Overall Widgets 22 addAndMakeVisible(loadButton); 23 loadButton.setButtonText("LOAD MODEL"); 24 loadButton.addListener(this); 25 26 addAndMakeVisible(modelSelect); 27 modelSelect.setColour(juce::Label::textColourId, juce::Colours::black); 28 modelSelect.setScrollWheelEnabled(true); 29 int c = 1; 30 for (const auto& jsonFile : processor.jsonFiles) { 31 modelSelect.addItem(jsonFile.getFileName(), c); 32 c += 1; 33 } 34 modelSelect.onChange = [this] {modelSelectChanged();}; 35 36 auto font = modelLabel.getFont(); 37 float height = font.getHeight(); 38 font.setHeight(height); 39 40 // Set Widget Graphics 41 bigKnobLAF.setLookAndFeel(ImageCache::getFromMemory(BinaryData::big_knob_png, BinaryData::big_knob_pngSize)); 42 smallKnobLAF.setLookAndFeel(ImageCache::getFromMemory(BinaryData::small_knob_png, BinaryData::small_knob_pngSize)); 43 44 // Pre Amp Pedal Widgets 45 46 /* 47 // Overdrive 48 odFootSw.setImages(true, true, true, 49 ImageCache::getFromMemory(BinaryData::footswitch_up_png, BinaryData::footswitch_up_pngSize), 1.0, Colours::transparentWhite, 50 Image(), 1.0, Colours::transparentWhite, 51 ImageCache::getFromMemory(BinaryData::footswitch_down_png, BinaryData::footswitch_down_pngSize), 1.0, Colours::transparentWhite, 52 0.0); 53 addAndMakeVisible(odFootSw); 54 odFootSw.addListener(this); 55 */ 56 57 cabOnButton.setImages(true, true, true, 58 ImageCache::getFromMemory(BinaryData::cab_switch_on_png, BinaryData::cab_switch_on_pngSize), 1.0, Colours::transparentWhite, 59 Image(), 1.0, Colours::transparentWhite, 60 ImageCache::getFromMemory(BinaryData::cab_switch_on_png, BinaryData::cab_switch_on_pngSize), 1.0, Colours::transparentWhite, 61 0.0); 62 addAndMakeVisible(cabOnButton); 63 cabOnButton.addListener(this); 64 65 driveSliderAttach = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.treeState, GAIN_ID, odDriveKnob); 66 addAndMakeVisible(odDriveKnob); 67 odDriveKnob.setLookAndFeel(&bigKnobLAF); 68 odDriveKnob.addListener(this); 69 odDriveKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); 70 odDriveKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, false, 50, 20); 71 odDriveKnob.setDoubleClickReturnValue(true, 0.5); 72 73 masterSliderAttach = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.treeState, MASTER_ID, odLevelKnob); 74 addAndMakeVisible(odLevelKnob); 75 odLevelKnob.setLookAndFeel(&smallKnobLAF); 76 odLevelKnob.addListener(this); 77 odLevelKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); 78 odLevelKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, false, 50, 20); 79 odLevelKnob.setDoubleClickReturnValue(true, 0.5); 80 81 bassSliderAttach = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.treeState, BASS_ID, ampBassKnob); 82 addAndMakeVisible(ampBassKnob); 83 ampBassKnob.setLookAndFeel(&smallKnobLAF); 84 ampBassKnob.addListener(this); 85 ampBassKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); 86 ampBassKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, false, 50, 20); 87 ampBassKnob.setDoubleClickReturnValue(true, 0.0); 88 89 midSliderAttach = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.treeState, MID_ID, ampMidKnob); 90 addAndMakeVisible(ampMidKnob); 91 ampMidKnob.setLookAndFeel(&smallKnobLAF); 92 ampMidKnob.addListener(this); 93 ampMidKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); 94 ampMidKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, false, 50, 20); 95 ampMidKnob.setDoubleClickReturnValue(true, 0.0); 96 97 trebleSliderAttach = std::make_unique<AudioProcessorValueTreeState::SliderAttachment>(processor.treeState, TREBLE_ID, ampTrebleKnob); 98 addAndMakeVisible(ampTrebleKnob); 99 ampTrebleKnob.setLookAndFeel(&smallKnobLAF); 100 ampTrebleKnob.addListener(this); 101 ampTrebleKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); 102 ampTrebleKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, false, 50, 20); 103 ampTrebleKnob.setDoubleClickReturnValue(true, 0.0); 104 105 addAndMakeVisible(versionLabel); 106 versionLabel.setText("v1.2", juce::NotificationType::dontSendNotification); 107 versionLabel.setJustificationType(juce::Justification::left); 108 versionLabel.setColour(juce::Label::textColourId, juce::Colours::white); 109 versionLabel.setFont(font); 110 111 // Size of plugin GUI 112 setSize (500, 650); 113 114 resetImages(); 115 116 loadFromFolder(); 117 } 118 119 ProteusAudioProcessorEditor::~ProteusAudioProcessorEditor() 120 { 121 odDriveKnob.setLookAndFeel(nullptr); 122 odLevelKnob.setLookAndFeel(nullptr); 123 ampBassKnob.setLookAndFeel(nullptr); 124 ampMidKnob.setLookAndFeel(nullptr); 125 ampTrebleKnob.setLookAndFeel(nullptr); 126 } 127 128 //============================================================================== 129 void ProteusAudioProcessorEditor::paint (Graphics& g) 130 { 131 // Workaround for graphics on Windows builds (clipping code doesn't work correctly on Windows) 132 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) 133 //if (processor.fw_state == 0) { 134 // g.drawImageAt(background_off, 0, 0); // Debug Line: Redraw entire background image 135 if (processor.fw_state == 1 && processor.conditioned == true) { 136 g.drawImageAt(background_on, 0, 0); // Debug Line: Redraw entire background image 137 } else if (processor.fw_state == 1 && processor.conditioned == false) { 138 g.drawImageAt(background_on_blue, 0, 0); // Debug Line: Redraw entire background image 139 } 140 #else 141 // Redraw only the clipped part of the background image 142 143 juce::Rectangle<int> ClipRect = g.getClipBounds(); 144 //if (processor.fw_state == 0) { 145 // g.drawImage(background_off, ClipRect.getX(), ClipRect.getY(), ClipRect.getWidth(), ClipRect.getHeight(), ClipRect.getX(), ClipRect.getY(), ClipRect.getWidth(), ClipRect.getHeight()); 146 if (processor.fw_state == 1 && processor.conditioned == true) { 147 g.drawImage(background_on, ClipRect.getX(), ClipRect.getY(), ClipRect.getWidth(), ClipRect.getHeight(), ClipRect.getX(), ClipRect.getY(), ClipRect.getWidth(), ClipRect.getHeight()); 148 } else if (processor.fw_state == 1 && processor.conditioned == false) 149 g.drawImage(background_on_blue, ClipRect.getX(), ClipRect.getY(), ClipRect.getWidth(), ClipRect.getHeight(), ClipRect.getX(), ClipRect.getY(), ClipRect.getWidth(), ClipRect.getHeight()); 150 #endif 151 } 152 153 void ProteusAudioProcessorEditor::resized() 154 { 155 // This is generally where you'll want to lay out the positions of any 156 // subcomponents in your editor.. 157 158 //Overall Widgets 159 loadButton.setBounds(186, 48, 120, 24); 160 modelSelect.setBounds(52, 11, 400, 28); 161 //modelLabel.setBounds(197, 2, 90, 25); 162 versionLabel.setBounds(462, 632, 60, 10); 163 cabOnButton.setBounds(115, 233, 53, 39); 164 165 // Overdrive Widgets 166 odDriveKnob.setBounds(168, 242, 190, 190); 167 odLevelKnob.setBounds(340, 225, 62, 62); 168 //odFootSw.setBounds(185, 416, 175, 160); 169 170 ampBassKnob.setBounds(113, 131, 62, 62); 171 ampMidKnob.setBounds(227, 131, 62, 62); 172 ampTrebleKnob.setBounds(340, 131, 62, 62); 173 } 174 175 bool ProteusAudioProcessorEditor::isValidFormat(File configFile) 176 { 177 // Read in the JSON file 178 String path = configFile.getFullPathName(); 179 const char* char_filename = path.toUTF8(); 180 181 std::ifstream i2(char_filename); 182 nlohmann::json weights_json; 183 i2 >> weights_json; 184 185 int hidden_size_temp = 0; 186 std::string network = ""; 187 188 // Check that the hidden_size and unit_type fields exist and are correct 189 if (weights_json.contains("/model_data/unit_type"_json_pointer) == true && weights_json.contains("/model_data/hidden_size"_json_pointer) == true) { 190 // Get the input size of the JSON file 191 int input_size_json = weights_json["/model_data/hidden_size"_json_pointer]; 192 std::string network_temp = weights_json["/model_data/unit_type"_json_pointer]; 193 194 network = network_temp; 195 hidden_size_temp = input_size_json; 196 } else { 197 return false; 198 } 199 200 if (hidden_size_temp == 40 && network == "LSTM") { 201 return true; 202 } else { 203 return false; 204 } 205 } 206 207 void ProteusAudioProcessorEditor::loadButtonClicked() 208 { 209 myChooser = std::make_unique<FileChooser> ("Select a folder to load models from", 210 processor.folder, 211 "*.json"); 212 213 auto folderChooserFlags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectDirectories | FileBrowserComponent::canSelectFiles; 214 215 myChooser->launchAsync (folderChooserFlags, [this] (const FileChooser& chooser) 216 { 217 if (!chooser.getResult().exists()) { 218 return; 219 } 220 processor.model_loaded = false; 221 Array<File> files; 222 if (chooser.getResult().existsAsFile()) { // If a file is selected 223 224 if (isValidFormat(chooser.getResult())) { 225 processor.saved_model = chooser.getResult(); 226 } 227 228 files = chooser.getResult().getParentDirectory().findChildFiles(2, false, "*.json"); 229 processor.folder = chooser.getResult().getParentDirectory(); 230 231 } else if (chooser.getResult().isDirectory()){ // Else folder is selected 232 files = chooser.getResult().findChildFiles(2, false, "*.json"); 233 processor.folder = chooser.getResult(); 234 } 235 236 processor.jsonFiles.clear(); 237 238 modelSelect.clear(); 239 240 if (files.size() > 0) { 241 for (auto file : files) { 242 243 if (isValidFormat(file)) { 244 modelSelect.addItem(file.getFileNameWithoutExtension(), processor.jsonFiles.size() + 1); 245 processor.jsonFiles.push_back(file); 246 processor.num_models += 1; 247 } 248 } 249 if (chooser.getResult().existsAsFile()) { 250 251 if (isValidFormat(chooser.getResult()) == true) { 252 modelSelect.setText(processor.saved_model.getFileNameWithoutExtension()); 253 processor.loadConfig(processor.saved_model); 254 } 255 } 256 else { 257 if (!processor.jsonFiles.empty()) { 258 modelSelect.setSelectedItemIndex(0, juce::NotificationType::dontSendNotification); 259 modelSelectChanged(); 260 } 261 } 262 } else { 263 processor.saved_model = ""; // Clear the saved model since there's nothing in the dropdown 264 } 265 }); 266 267 } 268 269 void ProteusAudioProcessorEditor::loadFromFolder() 270 { 271 processor.model_loaded = false; 272 Array<File> files; 273 files = processor.folder.findChildFiles(2, false, "*.json"); 274 275 processor.jsonFiles.clear(); 276 modelSelect.clear(); 277 278 if (files.size() > 0) { 279 for (auto file : files) { 280 281 if (isValidFormat(file)) { 282 modelSelect.addItem(file.getFileNameWithoutExtension(), processor.jsonFiles.size() + 1); 283 processor.jsonFiles.push_back(file); 284 processor.num_models += 1; 285 } 286 } 287 // Try to load model from saved_model, if it doesnt exist and jsonFiles is not empty, load the first model (if it exists and is valid format) 288 if (!processor.jsonFiles.empty()) { 289 if (processor.saved_model.existsAsFile() && isValidFormat(processor.saved_model)) { 290 processor.loadConfig(processor.saved_model); 291 modelSelect.setText(processor.saved_model.getFileNameWithoutExtension(), juce::NotificationType::dontSendNotification); 292 } else { 293 if (processor.jsonFiles[0].existsAsFile() && isValidFormat(processor.jsonFiles[0])) { 294 processor.loadConfig(processor.jsonFiles[0]); 295 modelSelect.setText(processor.jsonFiles[0].getFileNameWithoutExtension(), juce::NotificationType::dontSendNotification); 296 } 297 } 298 } 299 } 300 } 301 302 303 void ProteusAudioProcessorEditor::buttonClicked(juce::Button* button) 304 { 305 //if (button == &odFootSw) { 306 // odFootSwClicked(); 307 if (button == &loadButton) { 308 loadButtonClicked(); 309 } else if (button == &cabOnButton) { 310 cabOnButtonClicked(); 311 } 312 } 313 314 void ProteusAudioProcessorEditor::odFootSwClicked() { 315 //if (processor.fw_state == 0) 316 // processor.fw_state = 1; 317 //else 318 // processor.fw_state = 0; 319 //resetImages(); 320 } 321 322 void ProteusAudioProcessorEditor::cabOnButtonClicked() { 323 if (processor.cab_state == 0) { 324 processor.cab_state = 1; 325 } 326 else { 327 processor.cab_state = 0; 328 } 329 resetImages(); 330 repaint(); 331 } 332 333 void ProteusAudioProcessorEditor::sliderValueChanged(Slider* slider) 334 { 335 // Amp 336 if (slider == &BassKnob || slider == &MidKnob || slider == &TrebleKnob) { 337 processor.set_ampEQ(ampBassKnob.getValue(), ampMidKnob.getValue(), ampTrebleKnob.getValue()); 338 } 339 } 340 341 void ProteusAudioProcessorEditor::modelSelectChanged() 342 { 343 const int selectedFileIndex = modelSelect.getSelectedItemIndex(); 344 if (selectedFileIndex >= 0 && selectedFileIndex < processor.jsonFiles.size() && processor.jsonFiles.empty() == false) { //check if correct 345 if (processor.jsonFiles[selectedFileIndex].existsAsFile() && isValidFormat(processor.jsonFiles[selectedFileIndex])) { 346 processor.loadConfig(processor.jsonFiles[selectedFileIndex]); 347 processor.current_model_index = selectedFileIndex; 348 processor.saved_model = processor.jsonFiles[selectedFileIndex]; 349 } 350 } 351 repaint(); 352 } 353 354 355 void ProteusAudioProcessorEditor::resetImages() 356 { 357 repaint(); 358 /* 359 if (processor.fw_state == 0) { 360 odFootSw.setImages(true, true, true, 361 ImageCache::getFromMemory(BinaryData::footswitch_up_png, BinaryData::footswitch_up_pngSize), 1.0, Colours::transparentWhite, 362 Image(), 1.0, Colours::transparentWhite, 363 ImageCache::getFromMemory(BinaryData::footswitch_up_png, BinaryData::footswitch_up_pngSize), 1.0, Colours::transparentWhite, 364 0.0); 365 } 366 else { 367 odFootSw.setImages(true, true, true, 368 ImageCache::getFromMemory(BinaryData::footswitch_down_png, BinaryData::footswitch_down_pngSize), 1.0, Colours::transparentWhite, 369 Image(), 1.0, Colours::transparentWhite, 370 ImageCache::getFromMemory(BinaryData::footswitch_down_png, BinaryData::footswitch_down_pngSize), 1.0, Colours::transparentWhite, 371 0.0); 372 } 373 */ 374 // Set On/Off cab graphic 375 if (processor.cab_state == 0) { 376 cabOnButton.setImages(true, true, true, 377 ImageCache::getFromMemory(BinaryData::cab_switch_off_png, BinaryData::cab_switch_off_pngSize), 1.0, Colours::transparentWhite, 378 Image(), 1.0, Colours::transparentWhite, 379 ImageCache::getFromMemory(BinaryData::cab_switch_off_png, BinaryData::cab_switch_off_pngSize), 1.0, Colours::transparentWhite, 380 0.0); 381 } 382 else { 383 cabOnButton.setImages(true, true, true, 384 ImageCache::getFromMemory(BinaryData::cab_switch_on_png, BinaryData::cab_switch_on_pngSize), 1.0, Colours::transparentWhite, 385 Image(), 1.0, Colours::transparentWhite, 386 ImageCache::getFromMemory(BinaryData::cab_switch_on_png, BinaryData::cab_switch_on_pngSize), 1.0, Colours::transparentWhite, 387 0.0); 388 } 389 }