commit e68cf3962f9af8b20ce51530f9c7c08156f86dae
parent e97eea28e64bcb5ca27a023391fd98ddba99bcd0
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Tue, 28 Dec 2021 16:32:21 +0100
bring back dummy UI
Diffstat:
2 files changed, 298 insertions(+), 47 deletions(-)
diff --git a/source/jucePlugin/PluginEditor.cpp b/source/jucePlugin/PluginEditor.cpp
@@ -1,50 +1,203 @@
#include "PluginProcessor.h"
#include "PluginEditor.h"
-#include "ui/VirusEditor.h"
#include "version.h"
+#include "ui/VirusEditor.h"
+
//==============================================================================
-AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor (AudioPluginAudioProcessor& p)
- : AudioProcessorEditor (&p), processorRef (p)
- , m_btSingleMode("Single Mode")
- , m_btMultiMode("Multi Mode")
+AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor(AudioPluginAudioProcessor &p) :
+ AudioProcessorEditor(&p), processorRef(p), m_btSingleMode("Single Mode"), m_btMultiMode("Multi Mode"),
+ m_btLoadFile("Load bank"), m_cmbMidiInput("Midi Input"), m_cmbMidiOutput("Midi Output"),
+ deviceManager(), m_tempEditor(p)
{
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 (400, 300);
+ 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.setTopLeftPosition(m_btSingleMode.getPosition().x + m_btSingleMode.getWidth() + 10, 0);
+ m_btMultiMode.getToggleStateValue().referTo(*processorRef.getController().getParam(0, 2, 0x7a));
+ 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);
- m_btSingleMode.onClick = [this]()
- {
- switchPlayMode(0);
+ 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();
};
- m_btMultiMode.onClick = [this]()
+ for (auto pt = 0; pt < 16; pt++)
+ {
+ m_partSelectors[pt].onClick = [this, pt]() {
+
+ juce::PopupMenu selector;
+
+ for(auto b=0; b<processorRef.getController().getBankCount(); ++b)
+ {
+ auto bank = processorRef.getController().getSinglePresetNames(b);
+ juce::PopupMenu p;
+ for (auto i = 0; i < 128; i++)
+ {
+ p.addItem(bank[i], [this, b, i, pt] { processorRef.getController().setCurrentPartPreset(pt, b, i); });
+ }
+ std::stringstream bankName;
+ bankName << "Bank " << static_cast<char>('A' + b);
+ selector.addSubMenu(std::string(bankName.str()), p);
+ }
+ selector.showMenu(juce::PopupMenu::Options());
+ };
+ addAndMakeVisible(m_partSelectors[pt]);
+ }
+
+ auto midiIn = m_properties->getValue("midi_input", "");
+ auto midiOut = m_properties->getValue("midi_output", "");
+ if (midiIn != "")
{
- switchPlayMode(2);
+ 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.onClick = [this]()
+ {
+ 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(), 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_openEditor.setButtonText ("Show Editor");
- m_openEditor.onClick = [this]() {
- 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(), true);
- };
- addAndMakeVisible (m_openEditor);
+ m_cmbMidiOutput.setSelectedItemIndex(index+1, juce::dontSendNotification);
+ m_lastOutputIndex = index;
}
AudioPluginAudioProcessorEditor::~AudioPluginAudioProcessorEditor()
@@ -65,22 +218,102 @@ void AudioPluginAudioProcessorEditor::paint (juce::Graphics& g)
if(!processorRef.isPluginValid())
message += "\n\nNo ROM, no sound!\nCopy ROM next to plugin, must end with .bin";
- g.drawFittedText(message, getLocalBounds(), juce::Justification::centred, 2);
- g.drawFittedText("To donate: paypal.me/dsp56300", getLocalBounds(), juce::Justification::centredBottom, 2);
+ 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);
+ if (singlePartOrInMulti)
+ m_partSelectors[pt].setButtonText(processorRef.getController().getCurrentPartPresetName(pt));
+ }
}
void AudioPluginAudioProcessorEditor::resized()
{
// This is generally where you'll want to lay out the positions of any
// subcomponents in your editor..
- m_openEditor.setBounds (0,0, 80, 20);
-}
+ 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));
+ }
-void AudioPluginAudioProcessorEditor::switchPlayMode(uint8_t _playMode) const
-{
- synthLib::SMidiEvent ev;
- ev.sysex = { 0xf0, 0x00, 0x20, 0x33, 0x01, 0x00, 0x72, 0x0, 0x7a, _playMode, 0xf7};
- processorRef.addMidiEvent(ev);
- // This is generally where you'll want to lay out the positions of any
- // subcomponents in your editor..
+ 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);
+ const bool result = chooser.browseForFileToOpen();
+ if (result)
+ {
+ 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().parseMessage(Virus::SysEx(it, it + 267));
+ }
+ }
+ 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().parseMessage(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().parseMessage(syx);
+ it += 266;
+ }
+ }
+ }
+ }
+ }
+}
+\ No newline at end of file
diff --git a/source/jucePlugin/PluginEditor.h b/source/jucePlugin/PluginEditor.h
@@ -1,30 +1,47 @@
#pragma once
#include "PluginProcessor.h"
-
+#include <juce_audio_devices/juce_audio_devices.h>
//==============================================================================
-class AudioPluginAudioProcessorEditor : public juce::AudioProcessorEditor
+class AudioPluginAudioProcessorEditor : public juce::AudioProcessorEditor, private juce::Timer
{
public:
explicit AudioPluginAudioProcessorEditor (AudioPluginAudioProcessor&);
~AudioPluginAudioProcessorEditor() override;
//==============================================================================
+ //void handleIncomingMidiMessage(juce::MidiInput *source, const juce::MidiMessage &message) override;
void paint (juce::Graphics&) override;
void resized() override;
private:
- void switchPlayMode(uint8_t _playMode) const;
-
- // This reference is provided as a quick way for your editor to
- // access the processor object that created it.
- AudioPluginAudioProcessor& processorRef;
+ 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;
+
+ juce::GenericAudioProcessorEditor m_tempEditor;
+ juce::TextButton m_partSelectors[16];
juce::TextButton m_btSingleMode;
juce::TextButton m_btMultiMode;
-
- juce::TextButton m_openEditor; // temporary until integrated - will be rebased!
- std::unique_ptr<juce::ResizableWindow> m_virusEditor;
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessorEditor)
+ 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;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessorEditor)
+
};