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 dfafe64487eca9327bd32a9ff000af8ecab46dac
parent 25d85521fdcb1c3147372637393a9e98e5d4cfd8
Author: dsp56300 <87139854+dsp56300@users.noreply.github.com>
Date:   Mon,  4 Oct 2021 10:04:48 +0200

Merge pull request #27 from 790/midibanks

Add midi/syx bank loading
Diffstat:
Msource/jucePlugin/PluginEditor.cpp | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msource/jucePlugin/PluginEditor.h | 3+++
Msource/jucePlugin/VirusController.cpp | 2+-
Msource/jucePlugin/VirusController.h | 2+-
4 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/source/jucePlugin/PluginEditor.cpp b/source/jucePlugin/PluginEditor.cpp @@ -6,6 +6,7 @@ //============================================================================== AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor(AudioPluginAudioProcessor &p) : AudioProcessorEditor(&p), processorRef(p), m_btSingleMode("Single Mode"), m_btMultiMode("Multi Mode"), + m_btLoadFile("Load bank"), m_tempEditor(p) { ignoreUnused (processorRef); @@ -33,6 +34,13 @@ AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor(AudioPluginAudi m_btMultiMode.setTopLeftPosition(m_btSingleMode.getPosition().x + m_btSingleMode.getWidth() + 10, 0); m_btMultiMode.setSize(120,30); + addAndMakeVisible(m_btLoadFile); + m_btLoadFile.setTopLeftPosition(m_btSingleMode.getPosition().x + m_btSingleMode.getWidth() + m_btMultiMode.getWidth() + 10, 0); + m_btLoadFile.setSize(120, 30); + m_btLoadFile.onClick = [this]() { + loadFile(); + }; + for (auto pt = 0; pt < 16; pt++) { m_partSelectors[pt].onClick = [this, pt]() { @@ -110,3 +118,69 @@ void AudioPluginAudioProcessorEditor::resized() m_partSelectors[pt].setBounds(area.removeFromTop(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 @@ -15,6 +15,7 @@ public: private: 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; @@ -25,6 +26,8 @@ private: juce::TextButton m_btSingleMode; juce::TextButton m_btMultiMode; + juce::TextButton m_btLoadFile; + juce::String m_previousPath; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessorEditor) }; diff --git a/source/jucePlugin/VirusController.cpp b/source/jucePlugin/VirusController.cpp @@ -86,7 +86,7 @@ namespace Virus } else if (i == 5) { - if (msg[i] != m_deviceId) + if (msg[i] != m_deviceId && msg[i] != 0x10) return; // not intended to this device! } else if (i == 6) diff --git a/source/jucePlugin/VirusController.h b/source/jucePlugin/VirusController.h @@ -36,6 +36,7 @@ namespace Virus void setCurrentPartPreset(uint8_t part, uint8_t bank, uint8_t prg); juce::String getCurrentPartPresetName(uint8_t part); uint32_t getBankCount() const { return static_cast<uint32_t>(m_singles.size()); } + void parseMessage(const SysEx &); private: void timerCallback() override; @@ -89,7 +90,6 @@ namespace Virus static inline uint8_t copyData(const SysEx &src, int startPos, uint8_t *dst); template <typename T> juce::String parseAsciiText(const T &, int startPos) const; - void parseMessage(const SysEx &); void parseSingle(const SysEx &); void parseMulti(const SysEx &); void parseParamChange(const SysEx &);