gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit 97a219cb75c76fcb6640b6aaf3ec725b734cbc55
parent 866fe953a5d4d25d8b4300922a087aba48a69f95
Author: 790 <790@users.noreply.github.com>
Date:   Thu,  6 Jan 2022 17:42:45 +0000

remove temporary ui

Diffstat:
Msource/jucePlugin/PluginEditor.cpp | 320+------------------------------------------------------------------------------
Msource/jucePlugin/PluginEditor.h | 22++--------------------
Msource/jucePlugin/VirusParameterBinding.cpp | 22+++++++++++++++++-----
Msource/jucePlugin/VirusParameterBinding.h | 13+++++++------
Msource/jucePlugin/ui/VirusEditor.cpp | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msource/jucePlugin/ui/VirusEditor.h | 20++++++++++++++++++--
Msource/jucePlugin/ui/Virus_LfoEditor.cpp | 44++++++++++++++++++++++++++------------------
Msource/jucePlugin/ui/Virus_LfoEditor.h | 2+-
8 files changed, 258 insertions(+), 377 deletions(-)

diff --git a/source/jucePlugin/PluginEditor.cpp b/source/jucePlugin/PluginEditor.cpp @@ -7,220 +7,13 @@ //============================================================================== AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor(AudioPluginAudioProcessor &p) : - AudioProcessorEditor(&p), processorRef(p), m_btSingleMode("Single Mode"), m_btMultiMode("Multi Mode"), - m_parameterBinding(p), - m_btLoadFile("Load bank"), m_cmbMidiInput("Midi Input"), m_cmbMidiOutput("Midi Output"), - m_tempEditor(p) + AudioProcessorEditor(&p), processorRef(p), m_parameterBinding(p), m_virusEditor(new VirusEditor(m_parameterBinding, processorRef)) { ignoreUnused (processorRef); - juce::PropertiesFile::Options opts; - opts.applicationName = "DSP56300 Emulator"; - opts.filenameSuffix = ".settings"; - opts.folderName = "DSP56300 Emulator"; - opts.osxLibrarySubFolder = "Application Support/DSP56300 Emulator"; - m_properties = new juce::PropertiesFile(opts); - - // Make sure that before the constructor has finished, you've set the - // editor's size to whatever you need it to be. - setSize(800, 800); - - // Resizable UI - setResizable(true, true); - setResizeLimits(800,400,800,1600); - - m_btSingleMode.setRadioGroupId(0x3cf); - m_btMultiMode.setRadioGroupId(0x3cf); - addAndMakeVisible(m_btSingleMode); - addAndMakeVisible(m_btMultiMode); - m_btSingleMode.setTopLeftPosition(0,0); - m_btSingleMode.setSize(120,30); - m_btMultiMode.getToggleStateValue().referTo(*processorRef.getController().getParamValue(Virus::Param_PlayMode)); - const auto isMulti = processorRef.getController().isMultiMode(); - m_btSingleMode.setToggleState(!isMulti, juce::dontSendNotification); - m_btMultiMode.setToggleState(isMulti, juce::dontSendNotification); - m_btSingleMode.setClickingTogglesState(true); - m_btMultiMode.setClickingTogglesState(true); - m_btMultiMode.setTopLeftPosition(m_btSingleMode.getPosition().x + m_btSingleMode.getWidth() + 10, m_btSingleMode.getY()); - m_btMultiMode.setSize(120,30); - - addAndMakeVisible(m_btLoadFile); - m_btLoadFile.setTopLeftPosition(m_btSingleMode.getPosition().x + m_btSingleMode.getWidth() + m_btMultiMode.getWidth() + 10, m_btSingleMode.getY()); - m_btLoadFile.setSize(120, 30); - m_btLoadFile.onClick = [this]() { - loadFile(); - }; - - for (uint8_t pt = 0; pt < 16; pt++) - { - m_partSelectors[pt].onClick = [this, pt]() { - - juce::PopupMenu selector; - - for(uint8_t b=0; b<processorRef.getController().getBankCount(); ++b) - { - const auto bank = virusLib::fromArrayIndex(b); - auto presetNames = processorRef.getController().getSinglePresetNames(bank); - juce::PopupMenu p; - for (uint8_t i = 0; i < 128; i++) - { - p.addItem(presetNames[i], [this, bank, i, pt] { processorRef.getController().setCurrentPartPreset(pt, bank, i); }); - } - std::stringstream bankName; - bankName << "Bank " << static_cast<char>('A' + b); - selector.addSubMenu(std::string(bankName.str()), p); - } - selector.showMenu(juce::PopupMenu::Options()); - }; - m_partSelectors[pt].setSize(m_partSelectors[pt].getWidth() - 48, m_partSelectors[pt].getHeight()); - m_partSelectors[pt].setTopLeftPosition(m_partSelectors[pt].getPosition() + juce::Point(24, 0)); - addAndMakeVisible(m_partSelectors[pt]); - - m_prevPatch[pt].setSize(24, m_partSelectors[pt].getHeight()); - m_nextPatch[pt].setSize(24, m_partSelectors[pt].getHeight()); - m_prevPatch[pt].setTopLeftPosition(m_partSelectors[pt].getPosition() - juce::Point(24, 0)); - m_nextPatch[pt].setTopLeftPosition(m_partSelectors[pt].getPosition() + juce::Point(m_partSelectors[pt].getWidth(), 0)); - m_prevPatch[pt].setButtonText("<"); - m_nextPatch[pt].setButtonText(">"); - m_prevPatch[pt].onClick = [this, pt]() { - processorRef.getController().setCurrentPartPreset(pt, processorRef.getController().getCurrentPartBank(pt), - std::max(0, processorRef.getController().getCurrentPartProgram(pt) - 1)); - }; - m_nextPatch[pt].onClick = [this, pt]() { - processorRef.getController().setCurrentPartPreset(pt, processorRef.getController().getCurrentPartBank(pt), - std::min(127, processorRef.getController().getCurrentPartProgram(pt) + 1)); - }; - addAndMakeVisible(m_prevPatch[pt]); - addAndMakeVisible(m_nextPatch[pt]); - } - - auto midiIn = m_properties->getValue("midi_input", ""); - auto midiOut = m_properties->getValue("midi_output", ""); - if (midiIn != "") - { - processorRef.setMidiInput(midiIn); - } - if (midiOut != "") - { - processorRef.setMidiOutput(midiOut); - } - - m_cmbMidiInput.setSize(160, 30); - m_cmbMidiInput.setTopLeftPosition(0, 400); - m_cmbMidiOutput.setSize(160, 30); - m_cmbMidiOutput.setTopLeftPosition(164, 400); - addAndMakeVisible(m_cmbMidiInput); - addAndMakeVisible(m_cmbMidiOutput); - m_cmbMidiInput.setTextWhenNoChoicesAvailable("No MIDI Inputs Enabled"); - auto midiInputs = juce::MidiInput::getAvailableDevices(); - juce::StringArray midiInputNames; - midiInputNames.add(" - Midi In - "); - auto inIndex = 0; - for (int i = 0; i < midiInputs.size(); i++) - { - const auto input = midiInputs[i]; - if (processorRef.getMidiInput() != nullptr && input.identifier == processorRef.getMidiInput()->getIdentifier()) - { - inIndex = i + 1; - } - midiInputNames.add(input.name); - } - m_cmbMidiInput.addItemList(midiInputNames, 1); - m_cmbMidiInput.setSelectedItemIndex(inIndex, juce::dontSendNotification); - m_cmbMidiOutput.setTextWhenNoChoicesAvailable("No MIDI Outputs Enabled"); - auto midiOutputs = juce::MidiOutput::getAvailableDevices(); - juce::StringArray midiOutputNames; - midiOutputNames.add(" - Midi Out - "); - auto outIndex = 0; - for (int i = 0; i < midiOutputs.size(); i++) - { - const auto output = midiOutputs[i]; - if (processorRef.getMidiOutput() != nullptr && output.identifier == processorRef.getMidiOutput()->getIdentifier()) - { - outIndex = i+1; - } - midiOutputNames.add(output.name); - } - m_cmbMidiOutput.addItemList(midiOutputNames, 1); - m_cmbMidiOutput.setSelectedItemIndex(outIndex, juce::dontSendNotification); - m_cmbMidiInput.onChange = [this]() { updateMidiInput(m_cmbMidiInput.getSelectedItemIndex()); }; - m_cmbMidiOutput.onChange = [this]() { updateMidiOutput(m_cmbMidiOutput.getSelectedItemIndex()); }; - - addAndMakeVisible(m_tempEditor); - - startTimerHz(5); - - m_openEditor.setButtonText("Show Editor"); - m_openEditor.setTopLeftPosition(0, 500); - auto ctrl =& processorRef.getController(); - m_openEditor.onClick = [this, ctrl]() - { - m_virusEditor.reset(new juce::ResizableWindow("VirusEditor", true)); - m_virusEditor->setTopLeftPosition(0, 0); - m_virusEditor->setUsingNativeTitleBar(true); - m_virusEditor->setVisible(true); - m_virusEditor->setResizable(true, false); - m_virusEditor->setContentOwned(new VirusEditor(m_parameterBinding, *ctrl), true); - }; - addAndMakeVisible(m_openEditor); -} -void AudioPluginAudioProcessorEditor::updateMidiInput(int index) -{ - auto list = juce::MidiInput::getAvailableDevices(); - - if (index == 0) - { - m_properties->setValue("midi_input", ""); - m_properties->save(); - m_lastInputIndex = index; - m_cmbMidiInput.setSelectedItemIndex(index, juce::dontSendNotification); - return; - } - index--; - auto newInput = list[index]; - - if (!deviceManager.isMidiInputDeviceEnabled(newInput.identifier)) - deviceManager.setMidiInputDeviceEnabled(newInput.identifier, true); - - if (!processorRef.setMidiInput(newInput.identifier)) - { - m_cmbMidiInput.setSelectedItemIndex(0, juce::dontSendNotification); - m_lastInputIndex = 0; - return; - } - - m_properties->setValue("midi_input", newInput.identifier); - m_properties->save(); - - m_cmbMidiInput.setSelectedItemIndex(index+1, juce::dontSendNotification); - m_lastInputIndex = index; -} -void AudioPluginAudioProcessorEditor::updateMidiOutput(int index) -{ - auto list = juce::MidiOutput::getAvailableDevices(); - - if (index == 0) - { - m_properties->setValue("midi_output", ""); - m_properties->save(); - m_cmbMidiOutput.setSelectedItemIndex(index, juce::dontSendNotification); - m_lastOutputIndex = index; - processorRef.setMidiOutput(""); - return; - } - index--; - auto newOutput = list[index]; - if(!processorRef.setMidiOutput(newOutput.identifier)) - { - m_cmbMidiOutput.setSelectedItemIndex(0, juce::dontSendNotification); - m_lastOutputIndex = 0; - return; - } - m_properties->setValue("midi_output", newOutput.identifier); - m_properties->save(); - - m_cmbMidiOutput.setSelectedItemIndex(index+1, juce::dontSendNotification); - m_lastOutputIndex = index; + setSize(1377, 800); + m_virusEditor->setTopLeftPosition(0, 0); + addAndMakeVisible(m_virusEditor); } AudioPluginAudioProcessorEditor::~AudioPluginAudioProcessorEditor() @@ -230,36 +23,11 @@ AudioPluginAudioProcessorEditor::~AudioPluginAudioProcessorEditor() //============================================================================== void AudioPluginAudioProcessorEditor::paint (juce::Graphics& g) { - // (Our component is opaque, so we must completely fill the background with a solid colour) - g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); - - g.setColour (juce::Colours::white); - g.setFont (15.0f); - - std::string message = "DSP 56300 Emulator\nVersion " + std::string(g_pluginVersionString) + "\n" __DATE__ " " __TIME__; - - if(!processorRef.isPluginValid()) - message += "\n\nNo ROM, no sound!\nCopy ROM next to plugin, must end with .bin"; - - g.drawFittedText(message, getLocalBounds().removeFromLeft(400).removeFromBottom(45), juce::Justification::centred, - 2); - g.drawFittedText("To donate: paypal.me/dsp56300", getLocalBounds().removeFromRight(400).removeFromTop(35), - juce::Justification::centred, 2); } void AudioPluginAudioProcessorEditor::timerCallback() { // ugly (polling!) way for refreshing presets names as this is temporary ui - const auto multiMode = processorRef.getController().isMultiMode(); - for (auto pt = 0; pt < 16; pt++) - { - bool singlePartOrInMulti = pt == 0 || multiMode; - m_partSelectors[pt].setVisible(singlePartOrInMulti); - m_prevPatch[pt].setVisible(singlePartOrInMulti); - m_nextPatch[pt].setVisible(singlePartOrInMulti); - if (singlePartOrInMulti) - m_partSelectors[pt].setButtonText(processorRef.getController().getCurrentPartPresetName(pt)); - } } void AudioPluginAudioProcessorEditor::resized() @@ -268,84 +36,4 @@ void AudioPluginAudioProcessorEditor::resized() // subcomponents in your editor.. auto area = getLocalBounds(); area.removeFromTop(35); - m_tempEditor.setBounds(area.removeFromRight(400)); - for (auto pt = 0; pt < 16; pt++) - { - m_partSelectors[pt].setBounds(area.removeFromTop(20)); - } - - m_openEditor.setBounds(0, 0, 80, 20); -} - -void AudioPluginAudioProcessorEditor::loadFile() { - juce::FileChooser chooser("Choose syx/midi banks to import", - m_previousPath.isEmpty() ? juce::File::getSpecialLocation(juce::File::currentApplicationFile).getParentDirectory() : m_previousPath, - "*.syx,*.mid,*.midi", - true); - - if (!chooser.browseForFileToOpen()) - return; - bool sentData = false; - const auto result = chooser.getResult(); - m_previousPath = result.getParentDirectory().getFullPathName(); - const auto ext = result.getFileExtension().toLowerCase(); - if (ext == ".syx") - { - juce::MemoryBlock data; - result.loadFileAsData(data); - for (auto it = data.begin(); it != data.end(); it += 267) - { - if ((it + 267) < data.end()) - { - processorRef.getController().sendSysEx(Virus::SysEx(it, it + 267)); - sentData = true; - } - } - m_btLoadFile.setButtonText("Loaded"); - } - else if (ext == ".mid" || ext == ".midi") - { - juce::MemoryBlock data; - if (!result.loadFileAsData(data)) - { - return; - } - const uint8_t *ptr = (uint8_t *)data.getData(); - const auto end = ptr + data.getSize(); - - for (auto it = ptr; it < end; it += 1) - { - if ((uint8_t)*it == (uint8_t)0xf0 && (it+267) < end) - { - if ((uint8_t) *(it + 1) == (uint8_t)0x00) - { - auto syx = Virus::SysEx(it, it + 267); - syx[7] = 0x01; // force to bank a - syx[266] = 0xf7; - - processorRef.getController().sendSysEx(syx); - - it += 266; - } - else // some midi files have two bytes after the 0xf0 - { - auto syx = Virus::SysEx(); - syx.push_back(0xf0); - for (auto i = it + 3; i < it + 3 + 266; i++) - { - syx.push_back((uint8_t)*i); - } - syx[7] = 0x01; // force to bank a - syx[266] = 0xf7; - processorRef.getController().sendSysEx(syx); - it += 266; - } - - sentData = true; - } - } - } - - if (sentData) - processorRef.getController().onStateLoaded(); } diff --git a/source/jucePlugin/PluginEditor.h b/source/jucePlugin/PluginEditor.h @@ -1,6 +1,7 @@ #pragma once #include "VirusParameterBinding.h" +#include "ui/VirusEditor.h" #include "PluginProcessor.h" #include <juce_audio_devices/juce_audio_devices.h> //============================================================================== @@ -16,34 +17,15 @@ public: void resized() override; private: - void updateMidiInput(int index); - void updateMidiOutput(int index); void timerCallback() override; - void loadFile(); // This reference is provided as a quick way for your editor to // access the processor object that created it. AudioPluginAudioProcessor& processorRef; VirusParameterBinding m_parameterBinding; - juce::GenericAudioProcessorEditor m_tempEditor; - juce::TextButton m_partSelectors[16]; - juce::TextButton m_prevPatch[16]; - juce::TextButton m_nextPatch[16]; - juce::TextButton m_btSingleMode; - juce::TextButton m_btMultiMode; - juce::TextButton m_btLoadFile; - juce::String m_previousPath; - juce::ComboBox m_cmbMidiInput; - juce::ComboBox m_cmbMidiOutput; - - juce::AudioDeviceManager deviceManager; - juce::PropertiesFile *m_properties; - int m_lastInputIndex = 0; - int m_lastOutputIndex = 0; // New "real" editor - juce::TextButton m_openEditor; // temporary until integrated - will be rebased! - std::unique_ptr<juce::ResizableWindow> m_virusEditor; + VirusEditor *m_virusEditor; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessorEditor) diff --git a/source/jucePlugin/VirusParameterBinding.cpp b/source/jucePlugin/VirusParameterBinding.cpp @@ -1,8 +1,18 @@ #include "VirusParameterBinding.h" - +#include "VirusParameter.h" #include "PluginProcessor.h" -void VirusParameterBinding::bind(juce::Slider& _slider, Virus::ParameterType _param) const +void VirusParameterBinding::setPart(uint8_t _part) { + m_part = _part; + + for (const auto b : m_bindings) + { + b->onValueChanged = nullptr; + } + m_bindings.clear(); + +} +void VirusParameterBinding::bind(juce::Slider &_slider, Virus::ParameterType _param) { const auto v = m_processor.getController().getParameter(_param, m_part); if (!v) @@ -16,7 +26,7 @@ void VirusParameterBinding::bind(juce::Slider& _slider, Virus::ParameterType _pa _slider.getValueObject().referTo(v->getValueObject()); } -void VirusParameterBinding::bind(juce::ComboBox& _combo, Virus::ParameterType _param) const +void VirusParameterBinding::bind(juce::ComboBox& _combo, Virus::ParameterType _param) { const auto v = m_processor.getController().getParameter(_param, m_part); if (!v) @@ -31,10 +41,12 @@ void VirusParameterBinding::bind(juce::ComboBox& _combo, Virus::ParameterType _p //v->setValue(_combo.getSelectedId() - 1); v->getValueObject().getValueSource().setValue(_combo.getSelectedItemIndex()); }; + v->onValueChanged = [this, &_combo, v]() { _combo.setSelectedItemIndex(v->getValueObject().getValueSource().getValue(), juce::NotificationType::dontSendNotification); }; + m_bindings.add(v); } -void VirusParameterBinding::bind(juce::DrawableButton &_btn, Virus::ParameterType _param) const +void VirusParameterBinding::bind(juce::DrawableButton &_btn, Virus::ParameterType _param) { const auto v = m_processor.getController().getParameter(_param, m_part); if (!v) @@ -45,7 +57,7 @@ void VirusParameterBinding::bind(juce::DrawableButton &_btn, Virus::ParameterTyp _btn.getToggleStateValue().referTo(v->getValueObject()); } -void VirusParameterBinding::bind(juce::Component &_btn, Virus::ParameterType _param) const +void VirusParameterBinding::bind(juce::Component &_btn, Virus::ParameterType _param) { const auto v = m_processor.getController().getParameter(_param, m_part); if (!v) diff --git a/source/jucePlugin/VirusParameterBinding.h b/source/jucePlugin/VirusParameterBinding.h @@ -1,6 +1,6 @@ #pragma once #include "VirusController.h" - +#include "VirusParameter.h" namespace juce { class Value; } @@ -14,11 +14,12 @@ public: { m_part = _part; } - - void bind(juce::Slider& _control, Virus::ParameterType _param) const; - void bind(juce::ComboBox &_control, Virus::ParameterType _param) const; - void bind(juce::DrawableButton &_control, Virus::ParameterType _param) const; - void bind(juce::Component &_control, Virus::ParameterType _param) const; + void setPart(uint8_t _part); + void bind(juce::Slider& _control, Virus::ParameterType _param); + void bind(juce::ComboBox &_control, Virus::ParameterType _param); + void bind(juce::DrawableButton &_control, Virus::ParameterType _param); + void bind(juce::Component &_control, Virus::ParameterType _param); AudioPluginAudioProcessor& m_processor; uint8_t m_part; + juce::Array<Virus::Parameter*> m_bindings; }; diff --git a/source/jucePlugin/ui/VirusEditor.cpp b/source/jucePlugin/ui/VirusEditor.cpp @@ -1,6 +1,6 @@ #include "VirusEditor.h" #include "BinaryData.h" - +#include "../version.h" #include "Virus_ArpEditor.h" #include "Virus_FxEditor.h" #include "Virus_LfoEditor.h" @@ -13,8 +13,8 @@ using namespace juce; constexpr auto kPanelWidth = 1377; constexpr auto kPanelHeight = 800; -VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, Virus::Controller& _controller) : - m_parameterBinding(_parameterBinding), m_controller(_controller) +VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAudioProcessor &_processorRef) : + m_parameterBinding(_parameterBinding), processorRef(_processorRef), m_controller(processorRef.getController()), m_btSingleMode("Single Mode"), m_btMultiMode("Multi Mode") { setLookAndFeel(&m_lookAndFeel); @@ -61,7 +61,7 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, Virus::Contro addAndMakeVisible(m_partSelect[pt]); m_presetNames[pt].setBounds(80, 172 + pt * (36), 136, 16); - m_presetNames[pt].setButtonText(_controller.getCurrentPartPresetName(pt)); + m_presetNames[pt].setButtonText(m_controller.getCurrentPartPresetName(pt)); m_presetNames[pt].setColour(0, juce::Colours::white); m_presetNames[pt].onClick = [this, pt]() { @@ -106,6 +106,102 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, Virus::Contro addAndMakeVisible(m_nextPatch[pt]); } m_partSelect[0].setToggleState(true, NotificationType::sendNotification); + + m_btSingleMode.setRadioGroupId(0x3cf); + m_btMultiMode.setRadioGroupId(0x3cf); + addAndMakeVisible(m_btSingleMode); + addAndMakeVisible(m_btMultiMode); + m_btSingleMode.setTopLeftPosition(102, 756); + m_btSingleMode.setSize(100, 30); + m_btMultiMode.getToggleStateValue().referTo(*m_controller.getParamValue(Virus::Param_PlayMode)); + const auto isMulti = m_controller.isMultiMode(); + m_btSingleMode.setToggleState(!isMulti, juce::dontSendNotification); + m_btMultiMode.setToggleState(isMulti, juce::dontSendNotification); + m_btSingleMode.setClickingTogglesState(false); + m_btMultiMode.setClickingTogglesState(false); + m_btSingleMode.onClick = [this]() { setPlayMode(0); }; + m_btMultiMode.onClick = [this]() { setPlayMode(1); }; + + m_btMultiMode.setTopLeftPosition(m_btSingleMode.getPosition().x + m_btSingleMode.getWidth() + 10, + m_btSingleMode.getY()); + m_btMultiMode.setSize(100, 30); + + juce::PropertiesFile::Options opts; + opts.applicationName = "DSP56300 Emulator"; + opts.filenameSuffix = ".settings"; + opts.folderName = "DSP56300 Emulator"; + opts.osxLibrarySubFolder = "Application Support/DSP56300 Emulator"; + m_properties = new juce::PropertiesFile(opts); + auto midiIn = m_properties->getValue("midi_input", ""); + auto midiOut = m_properties->getValue("midi_output", ""); + if (midiIn != "") + { + processorRef.setMidiInput(midiIn); + } + if (midiOut != "") + { + processorRef.setMidiOutput(midiOut); + } + + m_cmbMidiInput.setSize(160, 30); + m_cmbMidiInput.setTopLeftPosition(350, 760); + m_cmbMidiOutput.setSize(160, 30); + m_cmbMidiOutput.setTopLeftPosition(350+164, 760); + addAndMakeVisible(m_cmbMidiInput); + addAndMakeVisible(m_cmbMidiOutput); + m_cmbMidiInput.setTextWhenNoChoicesAvailable("No MIDI Inputs Enabled"); + auto midiInputs = juce::MidiInput::getAvailableDevices(); + juce::StringArray midiInputNames; + midiInputNames.add(" - Midi In - "); + auto inIndex = 0; + for (int i = 0; i < midiInputs.size(); i++) + { + const auto input = midiInputs[i]; + if (processorRef.getMidiInput() != nullptr && input.identifier == processorRef.getMidiInput()->getIdentifier()) + { + inIndex = i + 1; + } + midiInputNames.add(input.name); + } + m_cmbMidiInput.addItemList(midiInputNames, 1); + m_cmbMidiInput.setSelectedItemIndex(inIndex, juce::dontSendNotification); + m_cmbMidiOutput.setTextWhenNoChoicesAvailable("No MIDI Outputs Enabled"); + auto midiOutputs = juce::MidiOutput::getAvailableDevices(); + juce::StringArray midiOutputNames; + midiOutputNames.add(" - Midi Out - "); + auto outIndex = 0; + for (int i = 0; i < midiOutputs.size(); i++) + { + const auto output = midiOutputs[i]; + if (processorRef.getMidiOutput() != nullptr && + output.identifier == processorRef.getMidiOutput()->getIdentifier()) + { + outIndex = i + 1; + } + midiOutputNames.add(output.name); + } + m_cmbMidiOutput.addItemList(midiOutputNames, 1); + m_cmbMidiOutput.setSelectedItemIndex(outIndex, juce::dontSendNotification); + m_cmbMidiInput.onChange = [this]() { updateMidiInput(m_cmbMidiInput.getSelectedItemIndex()); }; + m_cmbMidiOutput.onChange = [this]() { updateMidiOutput(m_cmbMidiOutput.getSelectedItemIndex()); }; + + std::string message = + "DSP 56300 Emulator\nVersion " + std::string(g_pluginVersionString) + "\n" __DATE__ " " __TIME__; + if (!processorRef.isPluginValid()) + message += "\n\nNo ROM, no sound!\nCopy ROM next to plugin, must end with .bin"; + message += "\n\nTo donate: paypal.me/dsp56300"; + m_version.setText(message, NotificationType::dontSendNotification); + m_version.setBounds(94, 2, 220, 150); + m_version.setColour(juce::Label::textColourId, juce::Colours::white); + m_version.setJustificationType(Justification::centred); + addAndMakeVisible(m_version); + + m_patchName.setBounds(410, 48, 362, 36); + m_patchName.setJustificationType(Justification::left); + m_patchName.setFont(juce::Font(32.0f, juce::Font::bold)); + m_patchName.setColour(juce::Label::textColourId, juce::Colours::red); + addAndMakeVisible(m_patchName); + startTimerHz(5); setSize (kPanelWidth, kPanelHeight); } @@ -124,7 +220,72 @@ void VirusEditor::timerCallback() m_nextPatch[pt].setVisible(singlePartOrInMulti); if (singlePartOrInMulti) m_presetNames[pt].setButtonText(m_controller.getCurrentPartPresetName(pt)); + if (pt == m_parameterBinding.m_part) + { + m_patchName.setText(m_controller.getCurrentPartPresetName(pt), + NotificationType::dontSendNotification); + } } + +} + +void VirusEditor::updateMidiInput(int index) +{ + auto list = juce::MidiInput::getAvailableDevices(); + + if (index == 0) + { + m_properties->setValue("midi_input", ""); + m_properties->save(); + m_lastInputIndex = index; + m_cmbMidiInput.setSelectedItemIndex(index, juce::dontSendNotification); + return; + } + index--; + auto newInput = list[index]; + + if (!deviceManager.isMidiInputDeviceEnabled(newInput.identifier)) + deviceManager.setMidiInputDeviceEnabled(newInput.identifier, true); + + if (!processorRef.setMidiInput(newInput.identifier)) + { + m_cmbMidiInput.setSelectedItemIndex(0, juce::dontSendNotification); + m_lastInputIndex = 0; + return; + } + + m_properties->setValue("midi_input", newInput.identifier); + m_properties->save(); + + m_cmbMidiInput.setSelectedItemIndex(index + 1, juce::dontSendNotification); + m_lastInputIndex = index; +} +void VirusEditor::updateMidiOutput(int index) +{ + auto list = juce::MidiOutput::getAvailableDevices(); + + if (index == 0) + { + m_properties->setValue("midi_output", ""); + m_properties->save(); + m_cmbMidiOutput.setSelectedItemIndex(index, juce::dontSendNotification); + m_lastOutputIndex = index; + processorRef.setMidiOutput(""); + return; + } + index--; + auto newOutput = list[index]; + if (!processorRef.setMidiOutput(newOutput.identifier)) + { + m_cmbMidiOutput.setSelectedItemIndex(0, juce::dontSendNotification); + m_lastOutputIndex = 0; + return; + } + m_properties->setValue("midi_output", newOutput.identifier); + m_properties->save(); + + m_cmbMidiOutput.setSelectedItemIndex(index + 1, juce::dontSendNotification); + m_lastOutputIndex = index; } void VirusEditor::updatePartsPresetNames() { @@ -150,22 +311,35 @@ void VirusEditor::resized() m_presetButtons.setBounds(statusArea.removeFromRight(188)); applyToSections([this](Component *s) { s->setTopLeftPosition(338, 133); }); } -void VirusEditor::changePart(uint8_t _part) { - m_parameterBinding.m_part = _part; +void VirusEditor::setPlayMode(uint8_t _mode) { + m_controller.getParameter(Virus::Param_PlayMode)->setValue(_mode); + changePart(0); +} + +void VirusEditor::changePart(uint8_t _part) +{ + for (auto &p : m_partSelect) + { + p.setToggleState(false, juce::dontSendNotification); + } + m_partSelect[_part].setToggleState(true, juce::dontSendNotification); + m_parameterBinding.setPart(_part); + removeChildComponent(m_oscEditor.get()); + removeChildComponent(m_lfoEditor.get()); + removeChildComponent(m_fxEditor.get()); + removeChildComponent(m_arpEditor.get()); + m_oscEditor = std::make_unique<OscEditor>(m_parameterBinding); addChildComponent(m_oscEditor.get()); - removeChildComponent(m_lfoEditor.get()); m_lfoEditor = std::make_unique<LfoEditor>(m_parameterBinding); addChildComponent(m_lfoEditor.get()); - removeChildComponent(m_fxEditor.get()); m_fxEditor = std::make_unique<FxEditor>(m_parameterBinding); addChildComponent(m_fxEditor.get()); - removeChildComponent(m_arpEditor.get()); m_arpEditor = std::make_unique<ArpEditor>(m_parameterBinding); addChildComponent(m_arpEditor.get()); diff --git a/source/jucePlugin/ui/VirusEditor.h b/source/jucePlugin/ui/VirusEditor.h @@ -1,6 +1,7 @@ #pragma once #include <juce_gui_extra/juce_gui_extra.h> +#include <juce_audio_devices/juce_audio_devices.h> #include "Virus_Buttons.h" #include "Virus_LookAndFeel.h" #include "../VirusController.h" @@ -14,22 +15,36 @@ class ArpEditor; class VirusEditor : public juce::Component, private juce::Timer { public: - VirusEditor(VirusParameterBinding& _parameterBinding, Virus::Controller& _controller); + VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAudioProcessor &_processorRef); ~VirusEditor() override; void resized() override; void changePart(uint8_t _part); void updatePartsPresetNames(); void loadFile(); + void setPlayMode(uint8_t _mode); + private: void timerCallback() override; + void updateMidiInput(int index); + void updateMidiOutput(int index); + juce::Label m_version; + juce::Label m_patchName; Buttons::PartSelectButton m_partSelect[16]; juce::Label m_partLabels[16]; juce::TextButton m_presetNames[16]; juce::TextButton m_nextPatch[16]; juce::TextButton m_prevPatch[16]; + juce::TextButton m_btSingleMode; + juce::TextButton m_btMultiMode; + juce::ComboBox m_cmbMidiInput; + juce::ComboBox m_cmbMidiOutput; + juce::AudioDeviceManager deviceManager; + juce::PropertiesFile *m_properties; + int m_lastInputIndex = 0; + int m_lastOutputIndex = 0; - static constexpr auto kPartGroupId = 0x3FBBA; + static constexpr auto kPartGroupId = 0x3FBBC; struct MainButtons : juce::Component, juce::Value::Listener { MainButtons(); @@ -56,6 +71,7 @@ private: void applyToSections(std::function<void(juce::Component *)>); VirusParameterBinding& m_parameterBinding; + AudioPluginAudioProcessor &processorRef; Virus::Controller& m_controller; std::unique_ptr<OscEditor> m_oscEditor; std::unique_ptr<LfoEditor> m_lfoEditor; diff --git a/source/jucePlugin/ui/Virus_LfoEditor.cpp b/source/jucePlugin/ui/Virus_LfoEditor.cpp @@ -27,8 +27,8 @@ LfoEditor::LfoBase::LfoBase(VirusParameterBinding& _parameterBinding, uint8_t _l { for (auto *s : {&m_rate, &m_keytrack, &m_amount}) setupRotary(*this, *s); - addAndMakeVisible(m_subWaveform); - m_subWaveform.setBounds(8, 123, Buttons::HandleButton::kWidth, Buttons::HandleButton::kHeight); + addAndMakeVisible(m_mode); + m_mode.setBounds(8, 123, Buttons::HandleButton::kWidth, Buttons::HandleButton::kHeight); addAndMakeVisible(m_shape); m_shape.setBounds(10, 37, 84, comboBoxHeight); @@ -44,12 +44,15 @@ LfoEditor::LfoBase::LfoBase(VirusParameterBinding& _parameterBinding, uint8_t _l const Virus::ParameterType clock[] = {Virus::Param_Lfo1Clock, Virus::Param_Lfo2Clock, Virus::Param_Lfo3Clock}; const Virus::ParameterType assignDest[] = {Virus::Param_Lfo1AssignDest, Virus::Param_Lfo2AssignDest, Virus::Param_Lfo3Destination}; + const Virus::ParameterType lfoModes[] = {Virus::Param_Lfo1Mode, Virus::Param_Lfo2Mode, Virus::Param_Lfo3Mode}; + _parameterBinding.bind(m_rate, rate[_lfoIndex]); _parameterBinding.bind(m_keytrack, keytrack[_lfoIndex]); _parameterBinding.bind(m_amount, amount[_lfoIndex]); _parameterBinding.bind(m_shape, shapes[_lfoIndex]); _parameterBinding.bind(m_clock, clock[_lfoIndex]); _parameterBinding.bind(m_assignDest, assignDest[_lfoIndex]); + _parameterBinding.bind(m_mode, lfoModes[_lfoIndex]); } LfoEditor::LfoTwoOneShared::LfoTwoOneShared(VirusParameterBinding& _parameterBinding, uint8_t _lfoIndex) : LfoBase(_parameterBinding, _lfoIndex), m_link(false) @@ -73,7 +76,7 @@ LfoEditor::LfoTwoOneShared::LfoTwoOneShared(VirusParameterBinding& _parameterBin _parameterBinding.bind(m_phase, _lfoIndex == 0 ? Virus::Param_Lfo1KeyTrigger : Virus::Param_Lfo2Keytrigger); //parameterBinding.bind(m_amount, Virus::Param_Lfo1AssignAmount); _parameterBinding.bind(m_envMode, _lfoIndex == 0 ? Virus::Param_Lfo1EnvMode : Virus::Param_Lfo2EnvMode); - _parameterBinding.bind(m_link, _lfoIndex == 0 ? Virus::Param_Lfo1Mode : Virus::Param_Lfo2Mode); + //_parameterBinding.bind(m_link, _lfoIndex == 0 ? Virus::Param_Lfo1Mode : Virus::Param_Lfo2Mode); //_parameterBinding.bind(m_assignDest, Virus::Param_Lfo1AssignDest); } @@ -137,29 +140,34 @@ LfoEditor::ModMatrix::ModMatrix(VirusParameterBinding& _parameterBinding) setupSlot(4, {{255, 338}}, {320, 314}); setupSlot(5, {{255, 462}}, {320, 439}); - _parameterBinding.bind(m_modMatrix[0]->m_source, Virus::Param_Assign1Source); - _parameterBinding.bind(m_modMatrix[1]->m_source, Virus::Param_Assign2Source); - _parameterBinding.bind(m_modMatrix[2]->m_source, Virus::Param_Assign3Source); + // slot 0 is assign2, slot 1 is assign3, then 1,4,5,6 + _parameterBinding.bind(m_modMatrix[0]->m_source, Virus::Param_Assign2Source); + _parameterBinding.bind(m_modMatrix[1]->m_source, Virus::Param_Assign3Source); + _parameterBinding.bind(m_modMatrix[2]->m_source, Virus::Param_Assign1Source); _parameterBinding.bind(m_modMatrix[3]->m_source, Virus::Param_Assign4Source); _parameterBinding.bind(m_modMatrix[4]->m_source, Virus::Param_Assign5Source); _parameterBinding.bind(m_modMatrix[5]->m_source, Virus::Param_Assign6Source); - _parameterBinding.bind(m_modMatrix[0]->m_destinations[0]->m_amount, Virus::Param_Assign1Amount); - _parameterBinding.bind(m_modMatrix[1]->m_destinations[0]->m_amount, Virus::Param_Assign2Amount1); - //_parameterBinding.bind(m_modMatrix[1]->m_destinations[1]->m_amount, Virus::Param_Assign2Amount2); - //_parameterBinding.bind(m_modMatrix[1]->m_destinations[2]->m_amount, Virus::Param_Assign2Amount3); - _parameterBinding.bind(m_modMatrix[2]->m_destinations[0]->m_amount, Virus::Param_Assign3Amount1); - //_parameterBinding.bind(m_modMatrix[2]->m_destinations[1]->m_amount, Virus::Param_Assign3Amount2); + _parameterBinding.bind(m_modMatrix[0]->m_destinations[0]->m_amount, Virus::Param_Assign2Amount1); + _parameterBinding.bind(m_modMatrix[0]->m_destinations[1]->m_amount, Virus::Param_Assign2Amount2); + _parameterBinding.bind(m_modMatrix[0]->m_destinations[2]->m_amount, Virus::Param_Assign2Amount3); + + _parameterBinding.bind(m_modMatrix[1]->m_destinations[0]->m_amount, Virus::Param_Assign3Amount1); + _parameterBinding.bind(m_modMatrix[1]->m_destinations[1]->m_amount, Virus::Param_Assign3Amount2); + + _parameterBinding.bind(m_modMatrix[2]->m_destinations[0]->m_amount, Virus::Param_Assign1Amount); + _parameterBinding.bind(m_modMatrix[3]->m_destinations[0]->m_amount, Virus::Param_Assign4Amount); _parameterBinding.bind(m_modMatrix[4]->m_destinations[0]->m_amount, Virus::Param_Assign5Amount); _parameterBinding.bind(m_modMatrix[5]->m_destinations[0]->m_amount, Virus::Param_Assign6Amount); - _parameterBinding.bind(m_modMatrix[0]->m_destinations[0]->m_dest, Virus::Param_Assign1Destination); - _parameterBinding.bind(m_modMatrix[1]->m_destinations[0]->m_dest, Virus::Param_Assign2Destination1); - //_parameterBinding.bind(m_modMatrix[1]->m_destinations[1]->m_dest, Virus::Param_Assign2Destination2); - //_parameterBinding.bind(m_modMatrix[1]->m_destinations[2]->m_dest, Virus::Param_Assign2Destination3); - _parameterBinding.bind(m_modMatrix[2]->m_destinations[0]->m_dest, Virus::Param_Assign3Destination1); - //_parameterBinding.bind(m_modMatrix[2]->m_destinations[1]->m_dest, Virus::Param_Assign3Destination2); + _parameterBinding.bind(m_modMatrix[0]->m_destinations[0]->m_dest, Virus::Param_Assign2Destination1); + _parameterBinding.bind(m_modMatrix[0]->m_destinations[1]->m_dest, Virus::Param_Assign2Destination2); + _parameterBinding.bind(m_modMatrix[0]->m_destinations[2]->m_dest, Virus::Param_Assign2Destination3); + _parameterBinding.bind(m_modMatrix[1]->m_destinations[0]->m_dest, Virus::Param_Assign3Destination1); + _parameterBinding.bind(m_modMatrix[1]->m_destinations[1]->m_dest, Virus::Param_Assign3Destination2); + + _parameterBinding.bind(m_modMatrix[2]->m_destinations[0]->m_dest, Virus::Param_Assign1Destination); _parameterBinding.bind(m_modMatrix[3]->m_destinations[0]->m_dest, Virus::Param_Assign4Destination); _parameterBinding.bind(m_modMatrix[4]->m_destinations[0]->m_dest, Virus::Param_Assign5Destination); _parameterBinding.bind(m_modMatrix[5]->m_destinations[0]->m_dest, Virus::Param_Assign6Destination); diff --git a/source/jucePlugin/ui/Virus_LfoEditor.h b/source/jucePlugin/ui/Virus_LfoEditor.h @@ -17,7 +17,7 @@ private: juce::Slider m_rate; juce::Slider m_keytrack; juce::Slider m_amount; - Buttons::HandleButton m_subWaveform; + Buttons::HandleButton m_mode; juce::ComboBox m_shape, m_clock; juce::ComboBox m_assignDest; };