/* ============================================================================== This file was auto-generated by the Introjucer! It contains the basic startup code for a Juce application. ============================================================================== */ #include "PluginProcessor.h" #include "PluginEditor.h" #include #include "Gui/ImageButton.h" // #include "GUI/BinaryData.h" #include "Utils.h" //============================================================================== ObxdAudioProcessorEditor::ObxdAudioProcessorEditor (ObxdAudioProcessor& ownerFilter) : AudioProcessorEditor (&ownerFilter), ScalableComponent(&ownerFilter), processor (ownerFilter), skinFolder (processor.getSkinFolder()), progStart (3000), bankStart (2000), skinStart (1000), skins (processor.getSkinFiles()), banks (processor.getBankFiles()) { setLookAndFeel(new CustomLookAndFeel(&this->processor)); //LookAndFeel& lf = getLookAndFeel(); // Popup Menu Look and Feel //lf.setColour(PopupMenu::backgroundColourId, Colour(20, 20, 20)); //lf.setColour(PopupMenu::textColourId, Colour(245, 245, 245)); //lf.setColour(PopupMenu::highlightedBackgroundColourId, Colour(60, 60, 60)); //skinFolder = ownerFilter.getCurrentSkinFolder(); // initialized above commandManager.registerAllCommandsForTarget(this); commandManager.setFirstCommandTarget(this); // reset KeyPressMappingSet commandManager.getKeyMappings()->resetToDefaultMappings(); // having set up the default key-mappings, you might now want to load the last set // of mappings that the user configured. //commandManager.getKeyMappings()->restoreFromXml(lastSavedKeyMappingsXML); // Now tell our top-level window to send any keypresses that arrive to the // KeyPressMappingSet, which will use them to invoke the appropriate commands. //addKeyListener(commandManager.getKeyMappings()); getTopLevelComponent()->addKeyListener (commandManager.getKeyMappings()); //Timer::callAfterDelay (100, [this] { this->grabKeyboardFocus(); }); // ensure that key presses are sent to the KeyPressTarget object if (PluginHostType().isProTools()) { } else { startTimer(100); }; // Fix ProTools file dialog focus issues //startTimer(100); // This will fix the issue DBG("W: " <(processor.getActiveEditor())) { auto w = proportionOfWidth(0.25f); auto h = proportionOfHeight(0.3f); auto x = proportionOfWidth(0.5f) - (w / 2); auto y = wrapper->getY(); if (setPresetNameWindow != nullptr) { y += proportionOfHeight(0.15f); setPresetNameWindow->setBounds(x, y, w, h); } } } skinFolder = processor.getCurrentSkinFolder(); File coords = skinFolder.getChildFile ("coords.xml"); if (!coords.existsAsFile()) { return; } XmlDocument skin (coords); auto doc = skin.getDocumentElement(); if (doc){ //int xScreen = getWidth(), yScreen = getHeight(); if (doc->getTagName() == "PROPERTIES"){ forEachXmlChildElementWithTagName(*doc, child, "VALUE"){ if (child->hasAttribute("NAME") && child->hasAttribute("x") && child->hasAttribute("y")) { String name = child->getStringAttribute("NAME"); int x = child->getIntAttribute("x"); int y = child->getIntAttribute("y"); int d = child->getIntAttribute("d"); int w = child->getIntAttribute("w"); int h = child->getIntAttribute("h"); bool tooltipEnabled = child->getBoolAttribute("tooltip", false); DBG(" COmponent : " << name); if (mappingComps[name] != nullptr){ if (auto* knob = dynamic_cast(mappingComps[name])){ knob->setBounds(transformBounds(x, y, d,d)); if (!tooltipEnabled) knob->setPopupDisplayEnabled(false, false, nullptr); } else if (dynamic_cast(mappingComps[name])){ mappingComps[name]->setBounds(transformBounds(x, y, w, h)); //((ButtonList *)mappingComps[name])->getRootMenu()->setLookAndFeel(& getLookAndFeel()); } else if (dynamic_cast(mappingComps[name])){ mappingComps[name]->setBounds(transformBounds(x, y, w, h)); } else if (dynamic_cast(mappingComps[name])){ mappingComps[name]->setBounds(transformBounds(x, y, d, d)); } else if (dynamic_cast(mappingComps[name])){ mappingComps[name]->setBounds(transformBounds(x, y, w, h)); } } } } } } } void ObxdAudioProcessorEditor::loadSkin (ObxdAudioProcessor& ownerFilter) { knobAttachments.clear(); buttonListAttachments.clear(); toggleAttachments.clear(); imageButtons.clear(); popupMenus.clear(); mappingComps.clear(); ownerFilter.removeChangeListener (this); skinFolder = ownerFilter.getCurrentSkinFolder(); File coords = skinFolder.getChildFile ("coords.xml"); bool useClassicSkin = coords.existsAsFile(); if (!useClassicSkin) { addMenuButton (14, 25, 20, "menu"); rebuildComponents (processor); return; } //if (coords.createInputStream()) XmlDocument skin (coords); auto doc = skin.getDocumentElement(); if (!doc) { notLoadSkin = true; setSize (1440, 450); } else { int xScreen = getWidth(), yScreen = getHeight(); if (doc->getTagName() == "PROPERTIES"){ forEachXmlChildElementWithTagName(*doc, child, "VALUE"){ if (child->hasAttribute("NAME") && child->hasAttribute("x") && child->hasAttribute("y")) { String name = child->getStringAttribute("NAME"); int x = child->getIntAttribute("x"); int y = child->getIntAttribute("y"); int d = child->getIntAttribute("d"); int w = child->getIntAttribute("w"); int h = child->getIntAttribute("h"); if (name == "resonanceKnob"){ resonanceKnob = addKnob (x, y, d, ownerFilter, RESONANCE, "Resonance", 0); mappingComps["resonanceKnob"] = resonanceKnob; } if (name == "cutoffKnob"){ cutoffKnob = addKnob (x, y, d, ownerFilter, CUTOFF, "Cutoff", 0.4); mappingComps["cutoffKnob"] = cutoffKnob; } if (name == "filterEnvelopeAmtKnob"){ filterEnvelopeAmtKnob = addKnob (x, y, d, ownerFilter, ENVELOPE_AMT, "Envelope", 0); mappingComps["filterEnvelopeAmtKnob"] = filterEnvelopeAmtKnob; } if (name == "multimodeKnob"){ multimodeKnob = addKnob (x, y, d, ownerFilter, MULTIMODE, "Multimode", 0.5); mappingComps["multimodeKnob"] = multimodeKnob; } if (name == "volumeKnob"){ volumeKnob = addKnob (x, y, d, ownerFilter, VOLUME, "Volume", 0.4); mappingComps["volumeKnob"] = volumeKnob; } if (name == "portamentoKnob"){ portamentoKnob = addKnob (x, y, d, ownerFilter, PORTAMENTO, "Portamento", 0); mappingComps["portamentoKnob"] = portamentoKnob; } if (name == "osc1PitchKnob"){ osc1PitchKnob = addKnob (x, y, d, ownerFilter, OSC1P, "Osc1Pitch", 0); osc1PitchKnob->shiftDragCallback = [](double value) { if (value < 0.125) return 0.0; if (value < 0.375) return 0.25; if (value < 0.625) return 0.5; if (value < 0.875) return 0.75; return 1.0; }; mappingComps["osc1PitchKnob"] = osc1PitchKnob; } if (name == "pulseWidthKnob"){ pulseWidthKnob = addKnob (x, y, d, ownerFilter, PW, "PW", 0); mappingComps["pulseWidthKnob"] = pulseWidthKnob; } if (name == "osc2PitchKnob"){ osc2PitchKnob = addKnob (x, y, d, ownerFilter, OSC2P, "Osc2Pitch", 0); osc2PitchKnob->shiftDragCallback = [](double value) { if (value < 0.125) return 0.0; if (value < 0.375) return 0.25; if (value < 0.625) return 0.5; if (value < 0.875) return 0.75; return 1.0; }; mappingComps["osc2PitchKnob"] = osc2PitchKnob; } if (name == "osc1MixKnob"){ osc1MixKnob = addKnob (x, y, d, ownerFilter, OSC1MIX, "Osc1", 1); mappingComps["osc1MixKnob"] = osc1MixKnob; } if (name == "osc2MixKnob"){ osc2MixKnob = addKnob (x, y, d, ownerFilter, OSC2MIX, "Osc2", 1); mappingComps["osc2MixKnob"] = osc2MixKnob; } if (name == "noiseMixKnob"){ noiseMixKnob = addKnob (x, y, d, ownerFilter, NOISEMIX, "Noise", 0); mappingComps["noiseMixKnob"] = noiseMixKnob; } if (name == "xmodKnob"){ xmodKnob = addKnob (x, y, d, ownerFilter, XMOD, "Xmod", 0); mappingComps["xmodKnob"] = xmodKnob; } if (name == "osc2DetuneKnob"){ osc2DetuneKnob = addKnob (x, y, d, ownerFilter, OSC2_DET, "Detune", 0); mappingComps["osc2DetuneKnob"] = osc2DetuneKnob; } if (name == "envPitchModKnob"){ envPitchModKnob = addKnob (x, y, d, ownerFilter, ENVPITCH, "PEnv", 0); mappingComps["envPitchModKnob"] = envPitchModKnob; } if (name == "brightnessKnob"){ brightnessKnob = addKnob (x, y, d, ownerFilter, BRIGHTNESS, "Bri", 1); mappingComps["brightnessKnob"] = brightnessKnob; } if (name == "attackKnob"){ attackKnob = addKnob (x, y, d, ownerFilter, LATK, "Atk", 0); mappingComps["attackKnob"] = attackKnob; } if (name == "decayKnob"){ decayKnob = addKnob (x, y, d, ownerFilter, LDEC, "Dec", 0); mappingComps["decayKnob"] = decayKnob; } if (name == "sustainKnob"){ sustainKnob = addKnob (x, y, d, ownerFilter, LSUS, "Sus", 1); mappingComps["sustainKnob"] = sustainKnob; } if (name == "releaseKnob"){ releaseKnob = addKnob (x, y, d, ownerFilter, LREL, "Rel", 0); mappingComps["releaseKnob"] = releaseKnob; } if (name == "fattackKnob"){ fattackKnob = addKnob (x, y, d, ownerFilter, FATK, "Atk", 0); mappingComps["fattackKnob"] = fattackKnob; } if (name == "fdecayKnob"){ fdecayKnob = addKnob (x, y, d, ownerFilter, FDEC, "Dec", 0); mappingComps["fdecayKnob"] = fdecayKnob; } if (name == "fsustainKnob"){ fsustainKnob = addKnob (x, y, d, ownerFilter, FSUS, "Sus", 1); mappingComps["fsustainKnob"] = fsustainKnob; } if (name == "freleaseKnob"){ freleaseKnob = addKnob (x, y, d, ownerFilter, FREL, "Rel", 0); mappingComps["freleaseKnob"] = freleaseKnob; } if (name == "lfoFrequencyKnob"){ lfoFrequencyKnob = addKnob (x, y, d, ownerFilter, LFOFREQ, "Freq", 0); mappingComps["lfoFrequencyKnob"] = lfoFrequencyKnob; } if (name == "lfoAmt1Knob"){ lfoAmt1Knob = addKnob (x, y, d, ownerFilter, LFO1AMT, "Pitch", 0); mappingComps["lfoAmt1Knob"] = lfoAmt1Knob; } if (name == "lfoAmt2Knob"){ lfoAmt2Knob = addKnob (x, y, d, ownerFilter, LFO2AMT, "PWM", 0); mappingComps["lfoAmt2Knob"] = lfoAmt2Knob; } if (name == "lfoSinButton"){ lfoSinButton = addButton (x, y, w, h, ownerFilter, LFOSINWAVE, "Sin"); mappingComps["lfoSinButton"] = lfoSinButton; } if (name == "lfoSquareButton"){ lfoSquareButton = addButton (x, y, w, h, ownerFilter, LFOSQUAREWAVE, "SQ"); mappingComps["lfoSquareButton"] = lfoSquareButton; } if (name == "lfoSHButton"){ lfoSHButton = addButton (x, y, w, h, ownerFilter, LFOSHWAVE, "S&H"); mappingComps["lfoSHButton"] = lfoSHButton; } if (name == "lfoOsc1Button"){ lfoOsc1Button = addButton (x, y, w, h, ownerFilter, LFOOSC1, "Osc1"); mappingComps["lfoOsc1Button"] = lfoOsc1Button; } if (name == "lfoOsc2Button"){ lfoOsc2Button = addButton (x, y, w, h, ownerFilter, LFOOSC2, "Osc2"); mappingComps["lfoOsc2Button"] = lfoOsc2Button; } if (name == "lfoFilterButton"){ lfoFilterButton = addButton (x, y, w, h, ownerFilter, LFOFILTER, "Filt"); mappingComps["lfoFilterButton"] = lfoFilterButton; } if (name == "lfoPwm1Button"){ lfoPwm1Button = addButton (x, y, w, h, ownerFilter, LFOPW1, "Osc1"); mappingComps["lfoPwm1Button"] = lfoPwm1Button; } if (name == "lfoPwm2Button"){ lfoPwm2Button = addButton (x, y, w, h, ownerFilter, LFOPW2, "Osc2"); mappingComps["lfoPwm2Button"] = lfoPwm2Button; } if (name == "hardSyncButton"){ hardSyncButton = addButton (x, y, w, h, ownerFilter, OSC2HS, "Sync"); mappingComps["hardSyncButton"] = hardSyncButton; } if (name == "osc1SawButton"){ osc1SawButton = addButton (x, y, w, h, ownerFilter, OSC1Saw, "S"); mappingComps["osc1SawButton"] = osc1SawButton; } if (name == "osc2SawButton"){ osc2SawButton = addButton (x, y, w, h, ownerFilter, OSC2Saw, "S"); mappingComps["osc2SawButton"] = osc2SawButton; } if (name == "osc1PulButton"){ osc1PulButton = addButton (x, y, w, h, ownerFilter, OSC1Pul, "P"); mappingComps["osc1PulButton"] = osc1PulButton; } if (name == "osc2PulButton"){ osc2PulButton = addButton (x, y, w, h, ownerFilter, OSC2Pul, "P"); mappingComps["osc2PulButton"] = osc2PulButton; } if (name == "pitchQuantButton"){ pitchQuantButton = addButton (x, y, w, h, ownerFilter, OSCQuantize, "Step"); mappingComps["pitchQuantButton"] = pitchQuantButton; } if (name == "filterBPBlendButton"){ filterBPBlendButton = addButton (x, y, w, h, ownerFilter, BANDPASS, "Bp"); mappingComps["filterBPBlendButton"] = filterBPBlendButton; } if (name == "fourPoleButton"){ fourPoleButton = addButton (x, y, w, h, ownerFilter, FOURPOLE, "24"); mappingComps["fourPoleButton"] = fourPoleButton; } if (name == "filterHQButton"){ filterHQButton = addButton (x, y, w, h, ownerFilter, FILTER_WARM, "HQ"); mappingComps["filterHQButton"] = filterHQButton; } if (name == "filterKeyFollowButton"){ filterKeyFollowButton = addButton (x, y, w, h, ownerFilter, FLT_KF, "Key"); mappingComps["filterKeyFollowButton"] = filterKeyFollowButton; } if (name == "unisonButton"){ unisonButton = addButton (x, y, w, h, ownerFilter, UNISON, "Uni"); mappingComps["unisonButton"] = unisonButton; } if (name == "tuneKnob"){ tuneKnob = addKnob (x, y, d, ownerFilter, TUNE, "Tune", 0.5); mappingComps["tuneKnob"] = tuneKnob; } if (name == "transposeKnob"){ transposeKnob = addKnob (x, y, d, ownerFilter, OCTAVE, "Transpose", 0.5); mappingComps["transposeKnob"] = transposeKnob; } if (name == "voiceDetuneKnob"){ voiceDetuneKnob =addKnob (x, y, d, ownerFilter, UDET, "VoiceDet", 0); mappingComps["voiceDetuneKnob"] = voiceDetuneKnob; } if (name == "bendLfoRateKnob"){ bendLfoRateKnob = addKnob (x, y, d, ownerFilter, BENDLFORATE, "ModRate", 0.4); mappingComps["bendLfoRateKnob"] = bendLfoRateKnob; } if (name == "veloFltEnvKnob"){ veloFltEnvKnob = addKnob (x, y, d, ownerFilter, VFLTENV, "VFE", 0); mappingComps["veloFltEnvKnob"] = veloFltEnvKnob; } if (name == "veloAmpEnvKnob"){ veloAmpEnvKnob = addKnob (x, y, d, ownerFilter, VAMPENV, "VAE", 0); mappingComps["veloAmpEnvKnob"] = veloAmpEnvKnob; } if (name == "midiLearnButton"){ midiLearnButton = addButton (x, y, w, h, ownerFilter, MIDILEARN, "LEA"); mappingComps["midiLearnButton"] = midiLearnButton; } if (name == "midiUnlearnButton"){ midiUnlearnButton = addButton (x, y, w, h, ownerFilter, UNLEARN, "UNL"); mappingComps["midiUnlearnButton"] = midiUnlearnButton; } if (name == "pan1Knob"){ pan1Knob = addKnob (x, y, d, ownerFilter, PAN1, "1", 0.5); pan1Knob->resetOnShiftClick(true, Action::panReset); pan1Knob->addActionListener(this); mappingComps["pan1Knob"] = pan1Knob; } if (name == "pan2Knob"){ pan2Knob = addKnob (x, y, d, ownerFilter, PAN2, "2", 0.5); pan2Knob->resetOnShiftClick(true, Action::panReset); pan2Knob->addActionListener(this); mappingComps["pan2Knob"] = pan2Knob; } if (name == "pan3Knob"){ pan3Knob = addKnob (x, y, d, ownerFilter, PAN3, "3", 0.5); pan3Knob->resetOnShiftClick(true, Action::panReset); pan3Knob->addActionListener(this); mappingComps["pan3Knob"] = pan3Knob; } if (name == "pan4Knob"){ pan4Knob = addKnob (x, y, d, ownerFilter, PAN4, "4", 0.5); pan4Knob->resetOnShiftClick(true, Action::panReset); pan4Knob->addActionListener(this); mappingComps["pan4Knob"] = pan4Knob; } if (name == "pan5Knob"){ pan5Knob = addKnob (x, y, d, ownerFilter, PAN5, "5", 0.5); pan5Knob->resetOnShiftClick(true, Action::panReset); pan5Knob->addActionListener(this); mappingComps["pan5Knob"] = pan5Knob; } if (name == "pan6Knob"){ pan6Knob = addKnob (x, y, d, ownerFilter, PAN6, "6", 0.5); pan6Knob->resetOnShiftClick(true, Action::panReset); pan6Knob->addActionListener(this); mappingComps["pan6Knob"] = pan6Knob; } if (name == "pan7Knob"){ pan7Knob = addKnob (x, y, d, ownerFilter, PAN7, "7", 0.5); pan7Knob->resetOnShiftClick(true, Action::panReset); pan7Knob->addActionListener(this); mappingComps["pan7Knob"] = pan7Knob; } if (name == "pan8Knob"){ pan8Knob = addKnob (x, y, d, ownerFilter, PAN8, "8", 0.5); pan8Knob->resetOnShiftClick(true, Action::panReset); pan8Knob->addActionListener(this); mappingComps["pan8Knob"] = pan8Knob; } if (name == "bendOsc2OnlyButton"){ bendOsc2OnlyButton = addButton (x, y, w, h, ownerFilter, BENDOSC2, "Osc2"); mappingComps["bendOsc2OnlyButton"] = bendOsc2OnlyButton; } if (name == "bendRangeButton"){ bendRangeButton = addButton (x, y, w, h, ownerFilter, BENDRANGE, "12"); mappingComps["bendRangeButton"] = bendRangeButton; } if (name == "asPlayedAllocButton"){ asPlayedAllocButton = addButton (x, y, w, h, ownerFilter, ASPLAYEDALLOCATION, "APA"); mappingComps["asPlayedAllocButton"] = asPlayedAllocButton; } if (name == "filterDetuneKnob"){ filterDetuneKnob = addKnob (x, y, d, ownerFilter, FILTERDER, "Flt", 0.2); mappingComps["filterDetuneKnob"] = filterDetuneKnob; } if (name == "portamentoDetuneKnob"){ portamentoDetuneKnob = addKnob (x, y, d, ownerFilter, PORTADER, "Port", 0.2); mappingComps["portamentoDetuneKnob"] = portamentoDetuneKnob; } if (name == "envelopeDetuneKnob"){ envelopeDetuneKnob = addKnob (x, y, d, ownerFilter, ENVDER, "Env", 0.2); mappingComps["envelopeDetuneKnob"] = envelopeDetuneKnob; } if (name == "voiceSwitch"){ voiceSwitch = addList (x, y, w, h, ownerFilter, VOICE_COUNT, "VoiceCount", "voices"); voiceSwitch->setLookAndFeel(&this->getLookAndFeel()); mappingComps["voiceSwitch"] = voiceSwitch; } if (name == "legatoSwitch"){ legatoSwitch = addList (x, y, w, h, ownerFilter, LEGATOMODE, "Legato", "legato"); legatoSwitch->setLookAndFeel(&this->getLookAndFeel()); mappingComps["legatoSwitch"] = legatoSwitch; } if (name == "menu") { ImageButton *img = addMenuButton (x, y, d, "menu"); mappingComps["menu"] = img; } /* if (name == "guisize") { xScreen = x; yScreen = y; if (processor.getShowPresetBar()) { setSize(xScreen, yScreen + 40); } else { setSize(xScreen, yScreen); } } */ //DBG(" Name: " << name << " X: " <setVisible(processor.getShowPresetBar()); presetBar->leftClicked = [this](juce::Point &pos){ PopupMenu menu; menu.setLookAndFeel(&this->getLookAndFeel()); for (int i = 0; i < processor.getNumPrograms(); ++i) { menu.addItem (i + progStart + 1, processor.getProgramName (i), true, i == processor.getCurrentProgram()); } int result = menu.showAt (Rectangle (pos.getX(), pos.getY(), 1, 1)); if (result >= (progStart + 1) && result <= (progStart + processor.getNumPrograms())){ result -= 1; result -= progStart; processor.setCurrentProgram (result); } }; resized(); } // Prepare data if (voiceSwitch) { for (int i = 1; i <= 32; ++i) { voiceSwitch->addChoice (String (i)); } auto voiceOption = ownerFilter.getPluginState().getParameter (ownerFilter.getEngineParameterId (VOICE_COUNT))->getValue(); voiceSwitch->setValue (voiceOption, dontSendNotification); } if (legatoSwitch) { legatoSwitch->addChoice ("Keep All"); legatoSwitch->addChoice ("Keep Filter Envelope"); legatoSwitch->addChoice ("Keep Amplitude Envelope"); legatoSwitch->addChoice ("Retrig"); auto legatoOption = ownerFilter.getPluginState().getParameter (ownerFilter.getEngineParameterId (LEGATOMODE))->getValue(); legatoSwitch->setValue (legatoOption, dontSendNotification); } createMenu(); ownerFilter.addChangeListener (this); scaleFactorChanged(); repaint(); } ObxdAudioProcessorEditor::~ObxdAudioProcessorEditor() { processor.removeChangeListener (this); // deleteAllChildren(); // WATCH OUT! } void ObxdAudioProcessorEditor::scaleFactorChanged() { // update background const bool highResolutionDisplay = isHighResolutionDisplay(); const float scaleFactor = getScaleFactor(); // notify child components for (int i = 0; i < getNumChildComponents(); i++) { ScalableComponent* object = dynamic_cast(getChildComponent(i)); if (object != nullptr) { object->setScaleFactor(scaleFactor, highResolutionDisplay); } // update look and feel CustomLookAndFeel* laf = dynamic_cast(&getChildComponent(i)->getLookAndFeel()); if (laf != nullptr) { laf->setScaleFactor(scaleFactor, highResolutionDisplay); } } // redraw everything backgroundImage = getScaledImageFromCache("main", scaleFactor, highResolutionDisplay); int width = backgroundImage.getWidth(); int height = backgroundImage.getHeight(); if (!highResolutionDisplay) { if (scaleFactor == 1.5f) { width = roundFloatToInt(width * 0.75f); height = roundFloatToInt(height * 0.75f); } else if (scaleFactor == 2.0f) { width /= 2; height /= 2; } } else { if (scaleFactor == 1.0f) //2x image { width /= 2; height /= 2; } else if (scaleFactor == 1.5f) //4x images =>150% { width = roundFloatToInt(width * (0.25f + 0.125f)); height = roundFloatToInt(height * (0.25f + 0.125f)); } else if (scaleFactor == 2.0f) //4x images =>200x { width /= 2; height /= 2; } } if (processor.getShowPresetBar()) { setSize(width, height + presetBar->getHeight()); presetBar->setBounds((width - presetBar->getWidth()) / 2, height, presetBar->getWidth(), presetBar->getHeight()); } else setSize(width, height); } void ObxdAudioProcessorEditor::placeLabel (int x, int y, String text) { Label* lab = new Label(); lab->setBounds (x, y, 110, 20); lab->setJustificationType (Justification::centred); lab->setText (text,dontSendNotification); lab->setInterceptsMouseClicks (false, true); addAndMakeVisible (lab); } ButtonList* ObxdAudioProcessorEditor::addList (int x, int y, int width, int height, ObxdAudioProcessor& filter, int parameter, String /*name*/, String imgName) { #if JUCE_WINDOWS || JUCE_LINUX ButtonList *bl = new ButtonList (imgName, height, &processor); #else ButtonList *bl = new ButtonList (imgName, height, &processor); #endif buttonListAttachments.add (new ButtonList::ButtonListAttachment (filter.getPluginState(), filter.getEngineParameterId (parameter), *bl)); bl->setBounds (x, y, width, height); addAndMakeVisible (bl); return bl; } Knob* ObxdAudioProcessorEditor::addKnob (int x, int y, int d, ObxdAudioProcessor& filter, int parameter, String /*name*/, float defval) { Knob* knob = new Knob ("knob", 48, &processor); knobAttachments.add (new Knob::KnobAttachment (filter.getPluginState(), filter.getEngineParameterId (parameter), *knob)); knob->setSliderStyle (Slider::RotaryVerticalDrag); knob->setTextBoxStyle (knob->NoTextBox, true, 0, 0); knob->setRange (0, 1); knob->setBounds (x, y, d+(d/6), d+(d/6)); knob->setTextBoxIsEditable (false); knob->setDoubleClickReturnValue (true, defval); knob->setValue (filter.getPluginState().getParameter (filter.getEngineParameterId (parameter))->getValue()); addAndMakeVisible (knob); return knob; } void ObxdAudioProcessorEditor::clean() { this->removeAllChildren(); } TooglableButton* ObxdAudioProcessorEditor::addButton (int x, int y, int w, int h, ObxdAudioProcessor& filter, int parameter, String name) { TooglableButton* button = new TooglableButton ("button", &processor); if (parameter != UNLEARN){ toggleAttachments.add (new AudioProcessorValueTreeState::ButtonAttachment (filter.getPluginState(), filter.getEngineParameterId (parameter), *button)); } else { button->addListener(this); } button->setBounds (x, y, w, h); button->setButtonText (name); button->setToggleState(filter.getPluginState().getParameter (filter.getEngineParameterId (parameter))->getValue(), dontSendNotification); addAndMakeVisible (button); return button; } void ObxdAudioProcessorEditor::actionListenerCallback(const String& message) { if (message.equalsIgnoreCase(Action::panReset)) { const StringArray parameters{ "pan1Knob", "pan2Knob", "pan3Knob", "pan4Knob", "pan5Knob", "pan6Knob", "pan7Knob", "pan8Knob" }; for (const auto& parameter : parameters) { if (auto* knob = dynamic_cast(mappingComps[parameter])) { knob->setValue(knob->getDoubleClickReturnValue()); } } } } Rectangle ObxdAudioProcessorEditor::transformBounds(int x, int y, int w, int h) { if (getScaleFactor() == 1.0f) return Rectangle(x, y, w, h); return Rectangle(x, y, w, h).toFloat().transformedBy(AffineTransform::scale(getScaleFactor())).toNearestInt(); } ImageButton* ObxdAudioProcessorEditor::addMenuButton (int x, int y, int d, String imgName) { ImageMenu* imageButton = new ImageMenu(imgName, &processor); imageButtons.add (imageButton); imageButton->setBounds (x, y, d, d); imageButton->onClick = [this](){ ImageButton *imageButton = this->imageButtons[0]; auto x = imageButton->getScreenX(); auto y = imageButton->getScreenY(); auto dx = imageButton->getWidth(); auto pos = Point (x, y + dx); resultFromMenu (pos); }; addAndMakeVisible (imageButton); return imageButton; } void ObxdAudioProcessorEditor::rebuildComponents (ObxdAudioProcessor& ownerFilter) { skinFolder = ownerFilter.getCurrentSkinFolder(); ownerFilter.removeChangeListener (this); // deleteAllChildren(); // WATCH OUT! setSize (1440, 450); ownerFilter.addChangeListener (this); repaint(); } void ObxdAudioProcessorEditor::createMenu () { popupMenus.clear(); PopupMenu* menu = new PopupMenu(); //menu->setLookAndFeel(new CustomLookAndFeel(&this->processor)); PopupMenu progMenu; PopupMenu bankMenu; PopupMenu skinMenu; PopupMenu fileMenu; //PopupMenu viewMenu; PopupMenu midiMenu; menu->setLookAndFeel(&this->getLookAndFeel()); progMenu.setLookAndFeel(&this->getLookAndFeel()); bankMenu.setLookAndFeel(&this->getLookAndFeel()); skinMenu.setLookAndFeel(&this->getLookAndFeel()); fileMenu.setLookAndFeel(&this->getLookAndFeel()); midiMenu.setLookAndFeel(&this->getLookAndFeel()); skins = processor.getSkinFiles(); banks = processor.getBankFiles(); { fileMenu.addItem(static_cast(MenuAction::ImportPreset), "Import Preset...", true, false); fileMenu.addItem(static_cast(MenuAction::ImportBank), "Import Bank...", true, false); fileMenu.addSeparator(); fileMenu.addItem(static_cast(MenuAction::ExportPreset), "Export Preset...", true, false); fileMenu.addItem(static_cast(MenuAction::ExportBank), "Export Bank...", true, false); fileMenu.addSeparator(); fileMenu.addItem(static_cast(MenuAction::NewPreset), "New Preset...", true,//enableNewPresetOption, false); fileMenu.addItem(static_cast(MenuAction::RenamePreset), "Rename Preset...", true, false); fileMenu.addItem(static_cast(MenuAction::SavePreset), "Save Preset...", true, false); fileMenu.addItem(static_cast(MenuAction::DeletePreset), "Delete Preset...", true, false); /* fileMenu.addItem(static_cast(MenuAction::DeleteBank), "Delete Bank...", true, false); */ menu->addSubMenu("File", fileMenu); } { for (int i = 0; i < processor.getNumPrograms(); ++i) { progMenu.addItem (i + progStart + 1, processor.getProgramName (i), true, i == processor.getCurrentProgram()); } menu->addSubMenu("Programs", progMenu); } menu->addItem(progStart + 1000, "Preset Bar", true, processor.showPresetBar); { const String currentBank = processor.getCurrentBankFile().getFileName(); for (int i = 0; i < banks.size(); ++i) { const File bank = banks.getUnchecked (i); bankMenu.addItem (i + bankStart + 1, bank.getFileNameWithoutExtension(), true, bank.getFileName() == currentBank); } menu->addSubMenu ("Banks", bankMenu); } { for (int i = 0; i < skins.size(); ++i) { const File skin = skins.getUnchecked (i); skinMenu.addItem (i + skinStart + 1, skin.getFileName(), true, skin.getFileName() == skinFolder.getFileName()); } menu->addSubMenu ("Themes", skinMenu); // About // menu.addItem(1, String("Release ") + String(JucePlugin_VersionString).dropLastCharacters(2), false); } //menu->addSubMenu ("View", viewMenu); menuMidiNum = progStart +2000; createMidi(menuMidiNum, midiMenu); menu->addSubMenu ("MIDI", midiMenu); popupMenus.add (menu); PopupMenu scaleMenu; menuScaleNum =progStart +2000 + 3000; scaleMenu.addItem(menuScaleNum, "1x", true, getScaleFactor() == 1.0f); scaleMenu.addItem(menuScaleNum+1, "1.5x", true, getScaleFactor() == 1.5f); scaleMenu.addItem(menuScaleNum+2, "2x", true, getScaleFactor() == 2.0f); menu->addSubMenu("GUI Size", scaleMenu, true); #ifdef LINUX menu->addItem(1, String("Release ") + String(JucePlugin_VersionString).dropLastCharacters(2), false); #endif #if defined(JUCE_MAC) || defined(WIN32) PopupMenu helpMenu; helpMenu.setLookAndFeel(&this->getLookAndFeel()); String version = String("Release ") + String(JucePlugin_VersionString);//.dropLastCharacters(2); helpMenu.addItem(menuScaleNum+4, "Manual", true); helpMenu.addItem(menuScaleNum+3, version, false); menu->addSubMenu("Help", helpMenu, true); #endif } void ObxdAudioProcessorEditor::createMidi(int menuNo, PopupMenu &menuMidi) { File midi_dir = processor.getMidiFolder(); File default_file = midi_dir.getChildFile("Default.xml"); if(default_file.exists()){ if (processor.currentMidiPath != default_file.getFullPathName()){ menuMidi.addItem(menuNo++, default_file.getFileNameWithoutExtension(), true, false); } else { menuMidi.addItem(menuNo++, default_file.getFileNameWithoutExtension(), true, true); } midiFiles.add(default_file.getFullPathName()); } File custom_file = midi_dir.getChildFile("Custom.xml"); if(custom_file.exists()){ if (processor.currentMidiPath != custom_file.getFullPathName()){ menuMidi.addItem(menuNo++, custom_file.getFileNameWithoutExtension(), true, false); } else { menuMidi.addItem(menuNo++, custom_file.getFileNameWithoutExtension(), true, true); } midiFiles.add(custom_file.getFullPathName()); } DirectoryIterator iter (midi_dir, true, "*.xml"); StringArray list; while (iter.next()) { list.add(iter.getFile().getFullPathName()); } list.sort(true); for (int i =0; i < list.size() ; i ++){ File f (list[i]); if (f.getFileNameWithoutExtension() != "Default" && f.getFileNameWithoutExtension() != "Custom" && f.getFileNameWithoutExtension() != "Config") { if (processor.currentMidiPath != f.getFullPathName()){ menuMidi.addItem(menuNo++, f.getFileNameWithoutExtension(), true, false); } else { menuMidi.addItem(menuNo++, f.getFileNameWithoutExtension(), true, true); } midiFiles.add(f.getFullPathName()); } } } void ObxdAudioProcessorEditor::resultFromMenu (const Point pos) { createMenu(); int result = popupMenus[0]->showAt (Rectangle (pos.getX(), pos.getY(), 1, 1)); if (result >= (skinStart + 1) && result <= (skinStart + skins.size())) { result -= 1; result -= skinStart; const File newSkinFolder = skins.getUnchecked (result); processor.setCurrentSkinFolder (newSkinFolder.getFileName()); //rebuildComponents (processor); clean(); loadSkin (processor); } else if (result >= (bankStart + 1) && result <= (bankStart + banks.size())) { result -= 1; result -= bankStart; const File bankFile = banks.getUnchecked (result); processor.loadFromFXBFile (bankFile); //clean(); //loadSkin (processor); // Check this } else if (result >= (progStart + 1) && result <= (progStart + processor.getNumPrograms())) { result -= 1; result -= progStart; processor.setCurrentProgram (result); //clean(); //loadSkin (processor); // Check this } else if (result < progStart){ MenuActionCallback(result); } else if (result == progStart + 1000){ processor.setShowPresetBar(!processor.getShowPresetBar()); //createMenu(); updatePresetBar(true); } else if (result >= menuScaleNum){ if (result ==menuScaleNum){ ScalableComponent::setScaleFactor(1.0f, isHighResolutionDisplay()); processor.setGuiSize(1); } else if (result == menuScaleNum+1){ ScalableComponent::setScaleFactor(1.5f, isHighResolutionDisplay()); processor.setGuiSize(2); } else if (result == menuScaleNum+2) { ScalableComponent::setScaleFactor(2.0f, isHighResolutionDisplay()); processor.setGuiSize(4); } else if (result == menuScaleNum+4) { File manualFile = processor.getDocumentFolder().getChildFile("OB-Xd Manual.pdf"); openInPdf(manualFile); } } else if (result >= menuMidiNum){ unsigned int selected_idx = result - menuMidiNum; if (selected_idx >= 0 && selected_idx < midiFiles.size()){ File f(midiFiles[selected_idx]); if (f.exists()) { processor.currentMidiPath = midiFiles[selected_idx]; processor.bindings.loadFile(f); processor.updateConfig(); //createMenu(); } } } } void ObxdAudioProcessorEditor::updatePresetBar(bool resize){ DBG(" H: " << getHeight() <<" W:" <getWidth() << " CH" <getHeight() << " CX:" <getX() << " CY: " <getY()); if (processor.getShowPresetBar()) { if (resize) { this->setSize(this->getWidth(), this->getHeight() + presetBar->getHeight()); } presetBar->setVisible(true); presetBar->update(); presetBar->setBounds((getWidth() - presetBar->getWidth()) / 2, getHeight() -presetBar->getHeight(), presetBar->getWidth(), presetBar->getHeight()); } else if (presetBar->isVisible()) { if (resize) { this->setSize(this->getWidth(), this->getHeight() - presetBar->getHeight()); } presetBar->setVisible(false); } } void ObxdAudioProcessorEditor::MenuActionCallback(int action){ if (action == MenuAction::ImportBank) { fileChooser = std::make_unique("Import Bank (*.fxb)", juce::File(), "*.fxb", true); if (fileChooser->browseForFileToOpen()) { File result = fileChooser->getResult(); auto name = result.getFileName().replace("%20", " "); auto file = processor.getBanksFolder().getChildFile(name); if (result == file || result.copyFileTo(file)){ processor.loadFromFXBFile(file); processor.scanAndUpdateBanks(); //createMenu(); } } }; if (action == MenuAction::ExportBank) { auto file = processor.getDocumentFolder().getChildFile("Banks"); FileChooser myChooser ("Export Bank (*.fxb)", file, "*.fxb", true); if(myChooser.browseForFileToSave(true)) { File result = myChooser.getResult(); String temp = result.getFullPathName(); if (!temp.endsWith(".fxb")) { temp += ".fxb"; } processor.saveBank(File(temp)); } }; if (action == MenuAction::DeleteBank) { if(NativeMessageBox::showOkCancelBox(AlertWindow::NoIcon, "Delete Bank", "Delete current bank: " + processor.currentBank + "?")){ processor.deleteBank(); } } if (action == MenuAction::SavePreset) { auto presetName = processor.currentPreset; if (presetName.isEmpty() ) { processor.saveBank(); return; } processor.savePreset(); processor.saveBank(); } if (action == MenuAction::NewPreset) { setPresetNameWindow = std::make_unique(); //preventBackgroundClick(); addAndMakeVisible(setPresetNameWindow.get()); resized(); auto callback = [this](int i, juce::String name) { if (i) { if (name.isNotEmpty()) { processor.newPreset(name); //createMenu(); } } setPresetNameWindow.reset(); //preventBackgroundClickComponent.reset(); }; setPresetNameWindow->callback = callback; setPresetNameWindow->grabTextEditorFocus(); return; } if (action == MenuAction::RenamePreset) { setPresetNameWindow = std::make_unique(); //preventBackgroundClick(); setPresetNameWindow->setText(processor.getProgramName(processor.getCurrentProgram())); addAndMakeVisible(setPresetNameWindow.get()); resized(); auto callback = [this](int i, juce::String name) { if (i) { if (name.isNotEmpty()) { processor.changePresetName(name); //createMenu(); } } setPresetNameWindow.reset(); //preventBackgroundClickComponent.reset(); }; setPresetNameWindow->callback = callback; setPresetNameWindow->grabTextEditorFocus(); return; } if (action == MenuAction::DeletePreset) { if(NativeMessageBox::showOkCancelBox(AlertWindow::NoIcon, "Delete Preset", "Delete current preset " + processor.currentPreset + "?")){ processor.deletePreset(); //createMenu(); } return; } if (action == MenuAction::ImportPreset) { DBG("Import Preset"); fileChooser = std::make_unique("Import Preset (*.fxp)", juce::File(), "*.fxp", true); if (fileChooser->browseForFileToOpen()) { File result = fileChooser->getResult(); //auto name = result.getFileName().replace("%20", " "); //auto file = processor.getPresetsFolder().getChildFile(name); DBG("Import Preset: " << result.getFileName()); //if (result == file || result.copyFileTo(file)){ processor.loadPreset(result); //createMenu(); //} } }; if (action == MenuAction::ExportPreset) { auto file = processor.getPresetsFolder(); FileChooser myChooser ("Export Preset (*.fxp)", file, "*.fxp", true); if(myChooser.browseForFileToSave(true)) { File result = myChooser.getResult(); String temp = result.getFullPathName(); if (!temp.endsWith(".fxp")) { temp += ".fxp"; } processor.savePreset(File(temp)); } }; } void ObxdAudioProcessorEditor::deleteBank() { } void ObxdAudioProcessorEditor::nextProgram() { int cur = processor.getCurrentProgram() + 1; if (cur == processor.getNumPrograms()) { cur = 0; } processor.setCurrentProgram (cur, false); needNotifytoHost = true; countTimer = 0; // Define for win and mac? //clean(); //loadSkin (processor); // check } void ObxdAudioProcessorEditor::prevProgram() { int cur = processor.getCurrentProgram() - 1; if (cur < 0) { cur = processor.getNumPrograms() - 1; } processor.setCurrentProgram (cur, false); needNotifytoHost = true; countTimer = 0; //clean(); //loadSkin (processor); } void ObxdAudioProcessorEditor::buttonClicked (Button* b) { /* auto imageButton = dynamic_cast (b); if (imageButton == imageButtons[0]) { auto x = imageButton->getScreenX(); auto y = imageButton->getScreenY(); auto dx = imageButton->getWidth(); auto pos = Point (x, y + dx); resultFromMenu (pos); }*/ auto toggleButton = dynamic_cast (b); if (toggleButton == midiUnlearnButton){ if (midiUnlearnButton->getToggleState()){ countTimerForLed = 0; processor.getMidiMap().reset(); processor.getMidiMap().set_default(); processor.sendChangeMessage(); } } } //============================================================================== void ObxdAudioProcessorEditor::updateFromHost() { for (int i = 0; i < knobAttachments.size(); ++i) { knobAttachments[i]->updateToSlider(); } /* for (int i = 0; i < toggleAttachments.size(); ++i) { toggleAttachments[i]->updateToSlider(); }*/ for (int i = 0; i < buttonListAttachments.size(); ++i) { buttonListAttachments[i]->updateToSlider(); } // Set to unlearn to false //if ( midiUnlearnButton && midiUnlearnButton->getToggleState()) { // Thread::sleep(500); // midiUnlearnButton->setToggleState(false, NotificationType:: sendNotification); //} repaint(); } void ObxdAudioProcessorEditor::changeListenerCallback (ChangeBroadcaster* source) { updateFromHost(); } void ObxdAudioProcessorEditor::mouseUp (const MouseEvent& e) { if (e.mods.isRightButtonDown() || e.mods.isCommandDown()) { resultFromMenu (e.getMouseDownScreenPosition()); } } void ObxdAudioProcessorEditor::handleAsyncUpdate() { scaleFactorChanged(); repaint(); } void ObxdAudioProcessorEditor::paint(Graphics& g) { const float newPhysicalPixelScaleFactor = g.getInternalContext().getPhysicalPixelScaleFactor(); if (newPhysicalPixelScaleFactor != processor.physicalPixelScaleFactor) { processor.physicalPixelScaleFactor = newPhysicalPixelScaleFactor; scaleFactorChanged(); } g.fillAll (Colours::black); // background gui if(processor.showPresetBar){ g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight() - 40, 0, 0, backgroundImage.getWidth(), backgroundImage.getHeight()); } else { g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), 0, 0, backgroundImage.getWidth(), backgroundImage.getHeight()); } /* #if JUCE_WINDOWS || JUCE_LINUX const File mainFile(skinFolder.getChildFile("main.png")); #else const File mainFile(skinFolder.getChildFile("main@2x.png")); #endif if (!notLoadSkin && skinFolder.exists() && mainFile.exists()) { const Image image = ImageCache::getFromFile(mainFile); #if JUCE_WINDOWS || JUCE_LINUX g.drawImage (image, 0, 0, image.getWidth(), image.getHeight(), 0, 0, image.getWidth(), image.getHeight()); #else g.drawImage (image, 0, 0, image.getWidth()/2, image.getHeight()/2, 0, 0, image.getWidth(), image.getHeight()); #endif } else { const Image image = ImageCache::getFromMemory(BinaryData::main_png, BinaryData::main_pngSize); // g.setImageResamplingQuality(Graphics::ResamplingQuality::highResamplingQuality); g.drawImage (image, 0, 0, image.getWidth(), image.getHeight(), 0, 0, image.getWidth(), image.getHeight()); } */ } bool ObxdAudioProcessorEditor::isInterestedInFileDrag(const StringArray& files) { StringArray extensions; extensions.add(".fxp"); extensions.add(".fxb"); if (files.size() == 1) { File file = File(files[0]); String ext = file.getFileExtension().toLowerCase(); return file.existsAsFile() && extensions.contains(ext); } else { for (int q = 0; q < files.size(); q++) { File file = File(files[q]); String ext = file.getFileExtension().toLowerCase(); if (ext == ".fxb" || ext == ".fxp") { return true; } } } return false; } void ObxdAudioProcessorEditor::filesDropped(const StringArray& files, int x, int y) { if (files.size() == 1) { File file = File(files[0]); String ext = file.getFileExtension().toLowerCase(); if (ext == ".fxp") { processor.loadPreset(file); //createMenu(); } else if (ext == ".fxb") { auto name = file.getFileName().replace("%20", " "); auto result = processor.getBanksFolder().getChildFile(name); if (file.copyFileTo(result)){ processor.loadFromFXBFile(result); processor.scanAndUpdateBanks(); //createMenu(); } } } else { int i = processor.getCurrentProgram(); for (int q = 0; q < files.size(); q++) { File file = File(files[q]); String ext = file.getFileExtension().toLowerCase(); if (ext == ".fxp") { processor.setCurrentProgram(i++); processor.loadPreset(file); } if (i >=processor.getNumPrograms()){ i = 0; } } processor.sendChangeMessage(); //createMenu(); } } const String ObxdAudioProcessorEditor::Action::panReset{ "panReset" }; /* bool ObxdAudioProcessorEditor::keyPressed(const KeyPress & press) { if (press.getKeyCode() == '+' || press.getKeyCode() == KeyPress::numberPadAdd) { nextProgram(); return false; // r+eturn true when the keypress was handled } if (press.getKeyCode() == '-' || press.getKeyCode() == KeyPress::numberPadSubtract) { prevProgram(); return false; // return true when the keypress was handled } return false; // return false if you don't handle the keypress }*/