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 1921e0c3704e3127ae6f935d99816ad88ead1d41
parent 3f49b7901dc3f831b46eda08a7c951713e573351
Author: trancy2k5 <63122430+trancy2k5@users.noreply.github.com>
Date:   Wed, 19 Jan 2022 21:05:08 +0100

- Changed font colour to white to get a better contrast
- Removed comments that do not make sense
- Presets counter and bank counter both start at 1 instead of 0
- Destructur added + to prevent memory leakage
- Knobs that are double assigned (e.g. Rebverb/Delay) are now only turned in which mode you are in.
- Comment out code removed
- Removed delay clock for reverb
- Patchbrowser updated to the latest version

Diffstat:
Msource/jucePlugin/PluginEditorSkin2.cpp | 5++---
Msource/jucePlugin/ui2/VirusEditor.cpp | 54++++++++++++++++++++++++++----------------------------
Msource/jucePlugin/ui2/VirusEditor.h | 3+++
Msource/jucePlugin/ui2/Virus_LookAndFeel.cpp | 20+++++++++++---------
Msource/jucePlugin/ui2/Virus_Panel1_OscEditor.h | 5+----
Msource/jucePlugin/ui2/Virus_Panel3_FxEditor.cpp | 13+++----------
Msource/jucePlugin/ui2/Virus_Panel3_FxEditor.h | 1-
Msource/jucePlugin/ui2/Virus_Panel4_ArpEditor.cpp | 14+++++++++-----
Msource/jucePlugin/ui2/Virus_Panel4_ArpEditor.h | 2++
Msource/jucePlugin/ui2/Virus_Panel5_PatchBrowser.cpp | 332+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msource/jucePlugin/ui2/Virus_Panel5_PatchBrowser.h | 22++++++++++++++++------
11 files changed, 270 insertions(+), 201 deletions(-)

diff --git a/source/jucePlugin/PluginEditorSkin2.cpp b/source/jucePlugin/PluginEditorSkin2.cpp @@ -9,12 +9,10 @@ AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor(AudioPluginAudioProcessor &p) : AudioProcessorEditor(&p), processorRef(p), m_parameterBinding(p), m_virusEditor(new VirusEditor(m_parameterBinding, processorRef)) { - double dScaleFactor = 0.75; const auto config = processorRef.getController().getConfig(); setResizable(true,false); - dScaleFactor = config->getDoubleValue("skin_scale_factor", 0.75f); - setScaleFactor(dScaleFactor); + setScaleFactor(config->getDoubleValue("skin_scale_factor", 0.75f)); setSize(m_virusEditor->iSkinSizeWidth, m_virusEditor->iSkinSizeHeight); m_virusEditor->m_AudioPlugInEditor = (AudioPluginAudioProcessorEditor*)this; @@ -23,6 +21,7 @@ AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor(AudioPluginAudi AudioPluginAudioProcessorEditor::~AudioPluginAudioProcessorEditor() { + delete m_virusEditor; } //============================================================================== diff --git a/source/jucePlugin/ui2/VirusEditor.cpp b/source/jucePlugin/ui2/VirusEditor.cpp @@ -66,18 +66,20 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu }; uint8_t index = 0; - - applyToSections([this, index](Component *s) mutable { - if (currentTab == index) { + applyToSections([this, index](Component *s) mutable + { + if (currentTab == index) + { s->setVisible(true); } index++; }); index = 0; - - m_mainButtons.applyToMainButtons([this, &index](DrawableButton *s) mutable { - if (currentTab == index) { + m_mainButtons.applyToMainButtons([this, &index](DrawableButton *s) mutable + { + if (currentTab == index) + { s->setToggleState(true, juce::dontSendNotification); } index++; @@ -87,11 +89,9 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu m_mainMenu.onClick = [this]() { - juce::PopupMenu selector; - juce::PopupMenu SubSkinSizeSelector; - - selector.setLookAndFeel(&m_landfButtons); + selectorMenu.setLookAndFeel(&m_landfButtons); SubSkinSizeSelector.setLookAndFeel(&m_landfButtons); + SubSkinSizeSelector.clear(); for (float d = 375; d < 1250; d = d + 125) { @@ -105,9 +105,9 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu }); } - selector.addSubMenu("Skin size", SubSkinSizeSelector, true); - selector.addItem("About", [this]() { AboutWindow(); }); - selector.showMenu(juce::PopupMenu::Options()); + selectorMenu.addSubMenu("Skin size", SubSkinSizeSelector, true); + selectorMenu.addItem("About", [this]() { AboutWindow(); }); + selectorMenu.showMenu(juce::PopupMenu::Options()); }; //draw Main Menu Button @@ -118,7 +118,6 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu m_patchName.setBounds(1473, 35, 480, 58); m_patchName.setJustificationType(Justification::left); m_patchName.setFont(juce::Font("Register", "Normal", 30.f)); - m_patchName.setColour(juce::Label::textColourId, juce::Colours::red); m_patchName.setEditable(false, true, true); m_patchName.onTextChange = [this]() { @@ -135,14 +134,12 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu //MainDisplay m_controlLabel.setBounds(1473, 35, 650, 58); - m_controlLabel.setColour(juce::Label::textColourId, juce::Colours::red); m_controlLabel.setFont(juce::Font("Register", "Normal", 30.f)); addAndMakeVisible(m_controlLabel); //ToolTip //m_ToolTip.setLookAndFeel(&m_landfToolTip); m_ToolTip.setBounds(200, 50, 200, 200); - m_ToolTip.setColour(juce::Label::textColourId, juce::Colours::red); m_ToolTip.setFont(juce::Font("Register", "Normal", 15.f)); m_ToolTip.setColour(juce::Label::ColourIds::backgroundColourId, juce::Colours::black); m_ToolTip.setColour(juce::Label::ColourIds::textColourId, juce::Colours::white); @@ -153,7 +150,7 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu //MainDisplay Value m_controlLabelValue.setBounds(1900, 35, 197, 58); m_controlLabelValue.setJustificationType(Justification::centredRight); - m_controlLabelValue.setColour(juce::Label::textColourId, juce::Colours::red); + //m_controlLabelValue.setColour(juce::Label::textColourId, juce::Colours::red); m_controlLabelValue.setFont(juce::Font("Register", "Normal", 30.f)); addAndMakeVisible(m_controlLabelValue); @@ -218,10 +215,19 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu updateParts(); } +VirusEditor::~VirusEditor() +{ + m_mainMenu.onClick = nullptr; + selectorMenu.setLookAndFeel(nullptr); + SubSkinSizeSelector.setLookAndFeel(nullptr); + m_mainMenu.setLookAndFeel (nullptr); + selector.setLookAndFeel (nullptr); + m_controller.onProgramChange = nullptr; + setLookAndFeel(nullptr); +} void VirusEditor::updateParts() { - // ugly (polling!) way for refreshing presets names as this is temporary ui const auto multiMode = m_controller.isMultiMode(); for (auto pt = 0; pt < 16; pt++) { @@ -244,17 +250,15 @@ void VirusEditor::updateParts() m_patchName.setText("["+juce::String(m_controller.getCurrentPart()+1) +"][" + getCurrentPartBankStr(m_controller.getCurrentPartBank(m_controller.getCurrentPart())) + "] " + sZero - + juce::String(processorRef.getController().getCurrentPartProgram(m_controller.getCurrentPart()))+": " + patchName, NotificationType::dontSendNotification); + + juce::String(processorRef.getController().getCurrentPartProgram(m_controller.getCurrentPart())+1)+": " + patchName, NotificationType::dontSendNotification); } } } } - void VirusEditor::ShowMenuePatchList() { - juce::PopupMenu selector; auto pt = m_controller.getCurrentPart(); selector.setLookAndFeel (&m_landfButtons); @@ -279,13 +283,6 @@ void VirusEditor::ShowMenuePatchList() selector.showMenu(juce::PopupMenu::Options()); } - -VirusEditor::~VirusEditor() -{ - setLookAndFeel(nullptr); - m_controller.onProgramChange = nullptr; -} - void VirusEditor::applyToSections(std::function<void(Component *)> action) { for (auto *section : {static_cast<Component *>(m_arpEditor.get()), static_cast<Component *>(m_fxEditor.get()), @@ -295,6 +292,7 @@ void VirusEditor::applyToSections(std::function<void(Component *)> action) action(section); } } + void VirusEditor::MainButtons::applyToMainButtons(std::function<void(DrawableButton *)> action) { for (auto *section : {static_cast<juce::DrawableButton *>(&m_arpSettings), static_cast<DrawableButton *>(&m_effects), diff --git a/source/jucePlugin/ui2/VirusEditor.h b/source/jucePlugin/ui2/VirusEditor.h @@ -48,6 +48,9 @@ private: Buttons::ButtonMenu m_mainMenu; juce::PopupMenu m_mainMenuSubSkinsize; + juce::PopupMenu selector; + juce::PopupMenu selectorMenu; + juce::PopupMenu SubSkinSizeSelector; struct MainButtons : juce::Component, juce::Value::Listener { diff --git a/source/jucePlugin/ui2/Virus_LookAndFeel.cpp b/source/jucePlugin/ui2/Virus_LookAndFeel.cpp @@ -25,11 +25,12 @@ namespace Virus float rotaryStartAngle, float rotaryEndAngle, Slider &s) { Drawable *knob = m_genKnob.get(); - //s.setPopupDisplayEnabled(true, true, nullptr, 2000); - const auto step = roundToInt(m_knobImageSteps.convertFrom0to1(sliderPosProportional)); - knob->setOriginWithOriginalSize({0.0f, -float(kKnobSize) * step}); + int step; + (s.isEnabled())?step=roundToInt(m_knobImageSteps.convertFrom0to1(sliderPosProportional)):step=0; + knob->setOriginWithOriginalSize({0.0f, -float(kKnobSize) * step}); + // this won't support scaling! knob->drawAt(g, x, y, 1.0f); } @@ -45,21 +46,22 @@ namespace Virus void LookAndFeel::drawRotarySlider(Graphics &g, int x, int y, int width, int height, float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle, Slider &s) - { + { Drawable *knob = m_genKnob.get(); - //s.setPopupDisplayEnabled(true, true, nullptr, 2000); - const auto step = roundToInt(m_knobImageSteps.convertFrom0to1(sliderPosProportional)); - knob->setOriginWithOriginalSize({0.0f, -float(kKnobSize) * step}); + int step; + (s.isEnabled())?step=roundToInt(m_knobImageSteps.convertFrom0to1(sliderPosProportional)):step=0; + knob->setOriginWithOriginalSize({0.0f, -float(kKnobSize) * step}); + // this won't support scaling! knob->drawAt(g, x, y, 1.0f); } void LookAndFeel::drawComboBox (juce::Graphics& gGrafik, int width, int height, bool isButtonDown, int buttonX, int buttonY, int buttonW, int buttonH, juce::ComboBox& box) { - gGrafik.setOpacity(0); - box.setColour(juce::ComboBox::textColourId, juce::Colours::red); + //gGrafik.setOpacity(0); + //box.setColour(juce::ComboBox::textColourId, juce::Colours::red); }; //LookAndFeelPatchBrowser diff --git a/source/jucePlugin/ui2/Virus_Panel1_OscEditor.h b/source/jucePlugin/ui2/Virus_Panel1_OscEditor.h @@ -2,7 +2,6 @@ #include "../PluginProcessor.h" #include "Virus_Buttons.h" -#include "Virus_LookAndFeel.h" class VirusParameterBinding; @@ -11,11 +10,9 @@ class OscEditor : public juce::Component public: OscEditor(VirusParameterBinding& _parameterBinding); void resized() override; - //Virus::BoxLookAndFeel landf; - private: - + // OSC1 juce::Slider m_osc1Shape, m_osc1PulseWidth, m_osc1Semitone, m_osc1KeyFollow; juce::ComboBox m_osc1WaveSelect; diff --git a/source/jucePlugin/ui2/Virus_Panel3_FxEditor.cpp b/source/jucePlugin/ui2/Virus_Panel3_FxEditor.cpp @@ -158,9 +158,6 @@ FxEditor::FxEditor(VirusParameterBinding &_parameterBinding) m_reverbPredelay.setBounds(909 - knobSize / 2, 854 - knobSize / 2, knobSize, knobSize); m_reverbFeedback.setBounds(1052 - knobSize / 2, 854 - knobSize / 2, knobSize, knobSize); - addAndMakeVisible(m_reverbClock); - m_reverbClock.setBounds(467+comboBoxXMargin - comboBox3Width / 2, 803 - comboBox3Height / 2, comboBox3Width, comboBox3Height); - addAndMakeVisible(m_reverbType); m_reverbType.setBounds(467+comboBoxXMargin - comboBox3Width / 2, 900 - comboBox3Height / 2, comboBox3Width, comboBox3Height); @@ -169,10 +166,8 @@ FxEditor::FxEditor(VirusParameterBinding &_parameterBinding) _parameterBinding.bind(m_reverbColoration, Virus::Param_DelayColor); _parameterBinding.bind(m_reverbPredelay, Virus::Param_DelayTime); _parameterBinding.bind(m_reverbFeedback, Virus::Param_DelayFeedback); - _parameterBinding.bind(m_reverbClock, Virus::Param_DelayClock); _parameterBinding.bind(m_reverbType, Virus::Param_DelayDepthReverbRoomSize); - // todo Need to check these parameters bindings for delay and reverb // Delay for (auto *s : {&m_delayTime, &m_delayRate, &m_delayFeedback, &m_delayColoration, &m_delayDepth}) @@ -256,9 +251,9 @@ void FxEditor::timerCallback() //Delay/Reverb int iSelectedIndex = m_delayReverbMode.getSelectedItemIndex(); bool bReverb = (iSelectedIndex >= 2 && iSelectedIndex <= 4); - float fReverbAlpha = (iSelectedIndex >= 2 && iSelectedIndex <= 4)?1.0f:0.3f; + float fReverbAlpha = (bReverb)?1.0f:0.3f; bool bDelay = (iSelectedIndex ==1 || iSelectedIndex > 5); - float fDelayAlpha = (iSelectedIndex ==1 || iSelectedIndex > 5)?1.0f:0.3f; + float fDelayAlpha = (bDelay)?1.0f:0.3f; m_reverbDecayTime.setEnabled(bReverb); m_reverbDecayTime.setAlpha(fReverbAlpha); @@ -270,8 +265,6 @@ void FxEditor::timerCallback() m_reverbPredelay.setAlpha(fReverbAlpha); m_reverbFeedback.setEnabled(bReverb); m_reverbFeedback.setAlpha(fReverbAlpha); - m_reverbClock.setEnabled(bReverb); - m_reverbClock.setAlpha(fReverbAlpha); m_reverbType.setEnabled(bReverb); m_reverbType.setAlpha(fReverbAlpha); @@ -294,7 +287,7 @@ void FxEditor::timerCallback() //m_vocoderMode iSelectedIndex = m_vocoderMode.getSelectedItemIndex(); bool bVocoder = (iSelectedIndex > 0); - float fAlpha = (iSelectedIndex > 0)?1.0f:0.3f; + float fAlpha = (bVocoder)?1.0f:0.3f; m_vocoderCenterFreq.setEnabled(bVocoder); m_vocoderCenterFreq.setAlpha(fAlpha); diff --git a/source/jucePlugin/ui2/Virus_Panel3_FxEditor.h b/source/jucePlugin/ui2/Virus_Panel3_FxEditor.h @@ -51,7 +51,6 @@ private: //Reverb juce::Slider m_reverbDecayTime, m_reverbDaming, m_reverbColoration, m_reverbPredelay, m_reverbFeedback; - juce::ComboBox m_reverbClock; juce::ComboBox m_reverbType; //Vocoder diff --git a/source/jucePlugin/ui2/Virus_Panel4_ArpEditor.cpp b/source/jucePlugin/ui2/Virus_Panel4_ArpEditor.cpp @@ -7,8 +7,6 @@ using namespace juce; using namespace virusLib; -Virus::LookAndFeelSmallButton m_lookAndFeelSmallButton; - static uint8_t g_playMode = 0; ArpEditor::ArpEditor(VirusParameterBinding &_parameterBinding, AudioPluginAudioProcessor &_processorRef): @@ -17,7 +15,6 @@ ArpEditor::ArpEditor(VirusParameterBinding &_parameterBinding, AudioPluginAudioP setupBackground(*this, m_background, BinaryData::panel_4_png, BinaryData::panel_4_pngSize); setBounds(m_background->getDrawableBounds().toNearestIntEdges()); bRunning = false; - //setLookAndFeel(&m_lookAndFeel); //Mode m_WorkingMode.addItem("Single",1); @@ -240,12 +237,19 @@ ArpEditor::ArpEditor(VirusParameterBinding &_parameterBinding, AudioPluginAudioP m_btMultiMode.setToggleState(true, juce::dontSendNotification); }*/ - - startTimerHz(5); } +ArpEditor::~ArpEditor() +{ + for (auto pt = 0; pt < 16; pt++) + { + m_partVolumes[pt].setLookAndFeel(nullptr); + m_partPans[pt].setLookAndFeel(nullptr); + } +} + void ArpEditor::changePart(uint8_t _part) { for (auto &p : m_partSelect) diff --git a/source/jucePlugin/ui2/Virus_Panel4_ArpEditor.h b/source/jucePlugin/ui2/Virus_Panel4_ArpEditor.h @@ -12,10 +12,12 @@ class ArpEditor : public juce::Component, private juce::Timer { public: ArpEditor(VirusParameterBinding &_parameterBinding, AudioPluginAudioProcessor &_processorRef); + ArpEditor::~ArpEditor(); static constexpr auto kPartGroupId = 0x3FBBC; private: void updateMidiInput(int index); void updateMidiOutput(int index); + Virus::LookAndFeelSmallButton m_lookAndFeelSmallButton; //WorkingMode juce::ComboBox m_WorkingMode; diff --git a/source/jucePlugin/ui2/Virus_Panel5_PatchBrowser.cpp b/source/jucePlugin/ui2/Virus_Panel5_PatchBrowser.cpp @@ -3,6 +3,8 @@ #include "Ui_Utils.h" #include "Virus_Panel5_PatchBrowser.h" #include <juce_gui_extra/juce_gui_extra.h> +#include <juce_cryptography/juce_cryptography.h> +#include "VirusEditor.h" using namespace juce; using namespace virusLib; @@ -18,37 +20,36 @@ PatchBrowser::PatchBrowser(VirusParameterBinding & _parameterBinding, AudioPlugi m_controller(_processorRef.getController()), m_patchList("Patch browser"), m_fileFilter("*.syx;*.mid;*.midi", "*", "virus patch dumps"), - m_bankList(FileBrowserComponent::canSelectFiles, File::getSpecialLocation(File::SpecialLocationType::currentApplicationFile), &m_fileFilter, NULL) + m_bankList(FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles, File::getSpecialLocation(File::SpecialLocationType::currentApplicationFile), &m_fileFilter, NULL), + m_search("Search Box") { setupBackground(*this, m_background, BinaryData::panel_5_png, BinaryData::panel_5_pngSize); bRunning = false; + m_bankList.setLookAndFeel(&m_landf); + + m_modeIndex = m_properties->getIntValue("patch_mode", 1); + m_bankList.setBounds(0, 50/fBrowserScaleFactor , 1030/fBrowserScaleFactor , 935/fBrowserScaleFactor ); + + //PatchBrowser auto bankDir = m_properties->getValue("virus_bank_dir", ""); if (bankDir != "" && juce::File(bankDir).isDirectory()) { m_bankList.setRoot(bankDir); } - setLookAndFeel(&m_landf); - setBounds(0, 0, kPanelWidth, kPanelHeight); - m_modeIndex = m_properties->getIntValue("patch_mode", 1); - - m_bankList.setBounds(0, 50/fBrowserScaleFactor , 1030/fBrowserScaleFactor , 935/fBrowserScaleFactor ); - //m_bankList.setLookAndFeel (&m_landf); - - //PatchList m_patchList.setBounds(1049/fBrowserScaleFactor , 50/fBrowserScaleFactor , 1010/fBrowserScaleFactor , 930/fBrowserScaleFactor ); - //m_patchList.setLookAndFeel (&m_landf); m_patchList.getHeader().addColumn("#", ColumnsPatch::INDEX, 32); - m_patchList.getHeader().addColumn("Name", ColumnsPatch::NAME, 140); - m_patchList.getHeader().addColumn("Category 1", ColumnsPatch::CAT1, 90); - m_patchList.getHeader().addColumn("Category 2", ColumnsPatch::CAT2, 90); + m_patchList.getHeader().addColumn("Name", ColumnsPatch::NAME, 130); + m_patchList.getHeader().addColumn("Category1", ColumnsPatch::CAT1, 84); + m_patchList.getHeader().addColumn("Category2", ColumnsPatch::CAT2, 84); m_patchList.getHeader().addColumn("Arp", ColumnsPatch::ARP, 32); m_patchList.getHeader().addColumn("Uni", ColumnsPatch::UNI, 32); + m_patchList.getHeader().addColumn("ST+-", ColumnsPatch::ST, 32); m_patchList.getHeader().addColumn("Ver", ColumnsPatch::VER, 32); addAndMakeVisible(m_patchList); @@ -59,17 +60,39 @@ PatchBrowser::PatchBrowser(VirusParameterBinding & _parameterBinding, AudioPlugi m_bankList.addListener(this); m_patchList.setModel(this); + //Search + m_search.setSize(m_patchList.getWidth(), 20); + m_search.setColour(TextEditor::textColourId, juce::Colours::white); + m_search.setTopLeftPosition(m_patchList.getBounds().getBottomLeft().translated(0, 8)); + m_search.onTextChange = [this] { + m_filteredPatches.clear(); + for(auto patch : m_patches) { + const auto searchValue = m_search.getText(); + if (searchValue.isEmpty()) { + m_filteredPatches.add(patch); + } + else if(patch.name.containsIgnoreCase(searchValue)) { + m_filteredPatches.add(patch); + } + } + m_patchList.updateContent(); + m_patchList.deselectAllRows(); + m_patchList.repaint(); + }; + m_search.setTextToShowWhenEmpty("search...", juce::Colours::grey); + addAndMakeVisible(m_search); + //ROM Bank m_romBankList.setBounds(10, 50/fBrowserScaleFactor , 970/fBrowserScaleFactor , 935/fBrowserScaleFactor ); m_romBankList.getHeader().addColumn("ROM BANK", ColumnsRomBanks::ROM_BANK_NAME, 450); m_romBankList.setTransform(AffineTransform::scale(fBrowserScaleFactor)); - RomBank rRomBank; + /*RomBank rRomBank; for (int i=1;i<=m_controller.getBankCount();i++) { rRomBank.m_RomNumber = static_cast<virusLib::BankNumber>(static_cast<int>(rRomBank.m_RomNumber) + 1) ; m_romBankes.add(rRomBank); - } + }*/ m_romBankList.setModel(this); m_romBankList.updateContent(); @@ -77,7 +100,6 @@ PatchBrowser::PatchBrowser(VirusParameterBinding & _parameterBinding, AudioPlugi m_romBankList.repaint(); // force repaint since row number doesn't often change m_romBankList.selectRow(0); - //Show Options Buttons/Cmb addAndMakeVisible(m_LoadBank); addAndMakeVisible(m_SavePreset); @@ -95,46 +117,44 @@ PatchBrowser::PatchBrowser(VirusParameterBinding & _parameterBinding, AudioPlugi m_Mode.onChange = [this]() { - if(bRunning) + if (m_Mode.getSelectedItemIndex()==0) { - if (m_Mode.getSelectedItemIndex()==0) - { - //ROM - m_romBankList.setVisible(true); - m_bankList.setVisible(false); - m_romBankList.updateContent(); - m_romBankList.deselectAllRows(); - m_romBankList.repaint(); // force repaint since row number doesn't often change - m_romBankList.selectRow(0); - } - else - { - //FILE - m_romBankList.setVisible(false); - m_bankList.setVisible(true); - } - m_properties->setValue("patch_mode", m_Mode.getSelectedItemIndex()); - m_properties->save(); - m_modeIndex = m_Mode.getSelectedItemIndex(); + //ROM + m_romBankList.setVisible(true); + m_bankList.setVisible(false); + m_romBankList.updateContent(); + m_romBankList.deselectAllRows(); + m_romBankList.repaint(); // force repaint since row number doesn't often change + m_romBankList.selectRow(0); } + else + { + //FILE + m_romBankList.setVisible(false); + m_bankList.setVisible(true); + } + m_properties->setValue("patch_mode", m_Mode.getSelectedItemIndex()); + m_properties->save(); + m_modeIndex = m_Mode.getSelectedItemIndex(); }; m_Mode.setSelectedItemIndex(m_modeIndex); m_LoadBank.onClick = [this]() { loadFile(); }; m_SavePreset.onClick = [this]() { savePreset(); }; - - startTimerHz(4); } -void PatchBrowser::timerCallback() +PatchBrowser::~PatchBrowser() { - + setLookAndFeel(nullptr); + m_Mode.setLookAndFeel(nullptr); + m_bankList.setLookAndFeel(nullptr); } + void PatchBrowser::selectionChanged() { - bRunning=true; //ugly + } VirusModel guessVersion(uint8_t *data) @@ -160,21 +180,18 @@ VirusModel guessVersion(uint8_t *data) //return VirusModel::C; } -void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e) -{ + +int PatchBrowser::loadBankFile(const juce::File& file, const int _startIndex = 0, const bool dedupe = false) { auto ext = file.getFileExtension().toLowerCase(); auto path = file.getParentDirectory().getFullPathName(); - juce::MemoryBlock data; - - file.loadFileAsData(data); - - m_properties->setValue("virus_bank_dir", path); + int loadedCount = 0; + int index = _startIndex; if (ext == ".syx") { - m_patches.clear(); - loadBankFileToRom(file); - - int index = 0; + juce::MemoryBlock data; + if (!file.loadFileAsData(data)) { + return 0; + } for (auto it = data.begin(); it != data.end(); it += 267) { if ((uint8_t)*it == (uint8_t)0xf0 @@ -191,28 +208,29 @@ void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e patch.category1 = patch.data[251]; patch.category2 = patch.data[252]; patch.unison = patch.data[97]; + patch.transpose = patch.data[93]; if ((uint8_t)*(it + 266) != (uint8_t)0xf7 && (uint8_t)*(it + 266) != (uint8_t)0xf8) { patch.model = VirusModel::TI; } else { patch.model = guessVersion(patch.data); } - m_patches.add(patch); - index++; + auto md5 = juce::MD5(it+9 + 17, 256-17-3).toHexString(); + if(!dedupe || !m_checksums.contains(md5)) { + m_checksums.set(md5, true); + m_patches.add(patch); + index++; + } } } - - m_patchList.updateContent(); - m_patchList.deselectAllRows(); - m_patchList.repaint(); // force repaint since row number doesn't often change - m_patchList.selectRow(0); } else if (ext == ".mid" || ext == ".midi") { - m_patches.clear(); - loadBankFileToRom(file); - - uint8_t index = 0; + juce::MemoryBlock data; + if (!file.loadFileAsData(data)) + { + return 0; + } const uint8_t *ptr = (uint8_t *)data.getData(); const auto end = ptr + data.getSize(); @@ -238,14 +256,20 @@ void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e patch.category1 = patch.data[251]; patch.category2 = patch.data[252]; patch.unison = patch.data[97]; + patch.transpose = patch.data[93]; if ((uint8_t)*(it + 266) != (uint8_t)0xf7 && (uint8_t)*(it + 266) != (uint8_t)0xf8) { patch.model = VirusModel::TI; } else { patch.model = guessVersion(patch.data); } - m_patches.add(patch); - index++; + auto md5 = juce::MD5(it+9 + 17, 256-17-3).toHexString(); + if(!dedupe || !m_checksums.contains(md5)) { + m_checksums.set(md5, true); + m_patches.add(patch); + index++; + } + it += 266; } else if((uint8_t)*(it+3) == 0x00 // some midi files have two bytes after the 0xf0 @@ -270,28 +294,79 @@ void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e patch.category1 = patch.data[251]; patch.category2 = patch.data[252]; patch.unison = patch.data[97]; + patch.transpose = patch.data[93]; if ((uint8_t)*(it + 2 + 266) != (uint8_t)0xf7 && (uint8_t)*(it + 2 + 266) != (uint8_t)0xf8) { patch.model = VirusModel::TI; } else { patch.model = guessVersion(patch.data); } - m_patches.add(patch); - index++; + auto md5 = juce::MD5(it+2+9 + 17, 256-17-3).toHexString(); + if(!dedupe || !m_checksums.contains(md5)) { + m_checksums.set(md5, true); + m_patches.add(patch); + index++; + } + loadedCount++; it += 266; } - } - - } + } + return index; +} +void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e) +{ + auto ext = file.getFileExtension().toLowerCase(); + auto path = file.getParentDirectory().getFullPathName(); + if (file.isDirectory() && e.mods.isRightButtonDown()) { + auto p = juce::PopupMenu(); + p.addItem("Add directory contents to patch list", [this, file]() { + m_patches.clear(); + m_checksums.clear(); + int lastIndex = 0; + for (auto f : juce::RangedDirectoryIterator(file, false, "*.syx;*.mid;*.midi", juce::File::findFiles)) { + lastIndex = loadBankFile(f.getFile(), lastIndex, true); + } + m_filteredPatches.clear(); + for(auto patch : m_patches) { + const auto searchValue = m_search.getText(); + if (searchValue.isEmpty()) { + m_filteredPatches.add(patch); + } + else if(patch.name.containsIgnoreCase(searchValue)) { + m_filteredPatches.add(patch); + } + } + m_patchList.updateContent(); + m_patchList.deselectAllRows(); + m_patchList.repaint(); + }); + p.showMenu(juce::PopupMenu::Options()); + + return; + } + m_properties->setValue("virus_bank_dir", path); + if(file.existsAsFile() && ext == ".syx" || ext == ".midi" || ext == ".mid") { + m_patches.clear(); + loadBankFile(file); + m_filteredPatches.clear(); + for(auto patch : m_patches) { + const auto searchValue = m_search.getText(); + if (searchValue.isEmpty()) { + m_filteredPatches.add(patch); + } + else if(patch.name.containsIgnoreCase(searchValue)) { + m_filteredPatches.add(patch); + } + } m_patchList.updateContent(); m_patchList.deselectAllRows(); m_patchList.repaint(); - m_patchList.selectRow(0); } + } void PatchBrowser::fileDoubleClicked(const juce::File &file) {} @@ -326,12 +401,12 @@ void PatchBrowser::paintCell(Graphics &g, int rowNumber, int columnId, int width //Banks from file if(m_modeIndex==1) { - g.setColour(rowIsSelected ? juce::Colours::darkblue: getLookAndFeel().findColour(juce::ListBox::textColourId)); // [5] - juce::String text = ""; - - auto rowElement = m_patches[rowNumber]; + g.setColour(rowIsSelected ? juce::Colours::darkblue + : getLookAndFeel().findColour(juce::ListBox::textColourId)); // [5] + + auto rowElement = m_filteredPatches[rowNumber]; //auto text = rowElement.name; - + juce::String text = ""; if (columnId == ColumnsPatch::INDEX) text = juce::String(rowElement.progNumber); else if (columnId == ColumnsPatch::NAME) @@ -344,94 +419,81 @@ void PatchBrowser::paintCell(Graphics &g, int rowNumber, int columnId, int width text = rowElement.data[129] != 0 ? "Y" : " "; else if(columnId == ColumnsPatch::UNI) text = rowElement.unison == 0 ? " " : juce::String(rowElement.unison+1); - else if (columnId == ColumnsPatch::VER) - { + else if(columnId == ColumnsPatch::ST) + text = rowElement.transpose != 64 ? juce::String(rowElement.transpose - 64) : " "; + else if (columnId == ColumnsPatch::VER) { if(rowElement.model < ModelList.size()) text = ModelList[rowElement.model]; } - g.drawText(text, 2, 0, width - 4, 20, juce::Justification::centredLeft, true); // [6] + g.drawText(text, 2, 0, width - 4, height, juce::Justification::centredLeft, true); // [6] g.setColour(getLookAndFeel().findColour(juce::ListBox::backgroundColourId)); - g.fillRect(width - 1, 0, 1, 20); // [7] + g.fillRect(width - 1, 0, 1, height); // [7] } else if (m_modeIndex==0) { g.setColour(rowIsSelected ? juce::Colours::darkblue: getLookAndFeel().findColour(juce::ListBox::textColourId)); // [5] - juce::String text = ""; - - auto rowElement = m_romBankes[rowNumber]; - juce::String sBankName="ERR"; - text = "Bank: "; - - switch (virusLib::BankNumber(rowNumber+1)) - { - case virusLib::BankNumber::A: text += "A"; break; - case virusLib::BankNumber::B: text += "B"; break; - case virusLib::BankNumber::C: text += "C"; break; - case virusLib::BankNumber::D: text += "D"; break; - case virusLib::BankNumber::E: text += "E"; break; - case virusLib::BankNumber::F: text += "F"; break; - case virusLib::BankNumber::G: text += "G"; break; - case virusLib::BankNumber::H: text += "H"; break; - } - - g.drawText(text, 2, 0, width - 4, 20, juce::Justification::centredLeft, true); // [6] + g.drawText("Bank: " + getCurrentPartBankStr(virusLib::BankNumber(rowNumber+1)), 2, 0, width - 4, 20, juce::Justification::centredLeft, true); // [6] g.setColour(getLookAndFeel().findColour(juce::ListBox::backgroundColourId)); g.fillRect(width - 1, 0, 1, 20); // [7] } } + + + void PatchBrowser::selectedRowsChanged(int lastRowSelected) { auto idx = m_patchList.getSelectedRow(); - if (idx == -1) { return; } - - m_controller.setCurrentPartPreset(m_controller.getCurrentPart(),m_controller.getCurrentPartBank(m_controller.getCurrentPart()),lastRowSelected); - - /*uint8_t syxHeader[9] = {0xF0, 0x00, 0x20, 0x33, 0x01, 0x00, 0x10, 0x00, 0x00}; - syxHeader[8] = m_controller.isMultiMode() ? m_controller.getCurrentPart() : virusLib::ProgramType::SINGLE; // set edit buffer - const uint8_t syxEof = 0xF7; - uint8_t cs = syxHeader[5] + syxHeader[6] + syxHeader[7] + syxHeader[8]; - uint8_t data[256]; - for (int i = 0; i < 256; i++) - { - data[i] = m_patches[idx].data[i]; - cs += data[i]; - } - cs = cs & 0x7f; - Virus::SysEx syx; - for (auto i : syxHeader) + + if(m_modeIndex==1) { - syx.push_back(i); + uint8_t syxHeader[9] = {0xF0, 0x00, 0x20, 0x33, 0x01, 0x00, 0x10, 0x00, 0x00}; + syxHeader[8] = m_controller.isMultiMode() ? m_controller.getCurrentPart() : virusLib::ProgramType::SINGLE; // set edit buffer + const uint8_t syxEof = 0xF7; + uint8_t cs = syxHeader[5] + syxHeader[6] + syxHeader[7] + syxHeader[8]; + uint8_t data[256]; + for (int i = 0; i < 256; i++) + { + data[i] = m_filteredPatches[idx].data[i]; + cs += data[i]; + } + cs = cs & 0x7f; + Virus::SysEx syx; + for (auto i : syxHeader) + { + syx.push_back(i); + } + for (auto i : data) + { + syx.push_back(i); + } + syx.push_back(cs); + syx.push_back(syxEof); + m_controller.sendSysEx(syx); // send to edit buffer + m_controller.parseMessage(syx); // update ui + getParentComponent()->postCommandMessage(VirusEditor::Commands::UpdateParts); } - for (auto i : data) + else if (m_modeIndex==0) { - syx.push_back(i); - } - syx.push_back(cs); - syx.push_back(syxEof);*/ - //m_controller.sendSysEx(syx); // send to edit buffer - //m_controller.parseMessage(syx); // update ui + m_controller.setCurrentPartPreset(m_controller.getCurrentPart(),m_controller.getCurrentPartBank(m_controller.getCurrentPart()),lastRowSelected); + } + + + } void PatchBrowser::cellDoubleClicked(int rowNumber, int columnId, const juce::MouseEvent &) { - - if(m_modeIndex==1) + /* if(m_modeIndex==1) { - if(rowNumber == m_patchList.getSelectedRow()) - { - selectedRowsChanged(0); - } + selectedRowsChanged(0); } else if (m_modeIndex==0) { - if(rowNumber == m_romBankList.getSelectedRow()) - { - selectedRowsChanged(0); - } - } + m_controller.setCurrentPartPreset(m_controller.getCurrentPart(),m_controller.getCurrentPartBank(m_controller.getCurrentPart()),lastRowSelected); + }*/ } diff --git a/source/jucePlugin/ui2/Virus_Panel5_PatchBrowser.h b/source/jucePlugin/ui2/Virus_Panel5_PatchBrowser.h @@ -20,6 +20,7 @@ struct Patch uint8_t data[256]; virusLib::VirusModel model; uint8_t unison; + uint8_t transpose; }; struct RomBank @@ -27,17 +28,17 @@ struct RomBank virusLib::BankNumber m_RomNumber; }; -class PatchBrowser : public juce::Component, juce::FileBrowserListener, juce::TableListBoxModel, private juce::Timer +class PatchBrowser : public juce::Component, juce::FileBrowserListener, juce::TableListBoxModel { public: PatchBrowser(VirusParameterBinding &_parameterBinding, AudioPluginAudioProcessor &_processorRef); + ~PatchBrowser(); void loadFile(); void loadBankFileToRom(const juce::File &file); void savePreset(); private: - void timerCallback() override; bool bRunning; Virus::LookAndFeelPatchBrowser m_landf; @@ -57,10 +58,14 @@ private: juce::FileBrowserComponent m_bankList; juce::TableListBox m_patchList; juce::TableListBox m_romBankList; + juce::TextEditor m_search; juce::Array<RomBank> m_romBankes; juce::Array<Patch> m_patches; + juce::Array<Patch> m_filteredPatches; juce::PropertiesFile *m_properties; - + juce::HashMap<juce::String, bool> m_checksums; + int loadBankFile(const juce::File &file, const int _startIndex, const bool dedupe); + // Inherited via FileBrowserListener Buttons::OptionButtonLoadBank m_LoadBank; Buttons::OptionButtonSavePreset m_SavePreset; juce::ComboBox m_Mode; @@ -94,7 +99,8 @@ private: CAT2 = 4, ARP = 5, UNI = 6, - VER = 7 + ST = 7, + VER = 8, }; enum ColumnsRomBanks { @@ -108,12 +114,13 @@ private: class PatchBrowser::PatchBrowserSorter { public: - PatchBrowserSorter (int attributeToSortBy, bool forwards) : attributeToSort (attributeToSortBy), direction (forwards ? 1 : -1) + PatchBrowserSorter (int attributeToSortBy, bool forwards) + : attributeToSort (attributeToSortBy), + direction (forwards ? 1 : -1) {} int compareElements (Patch first, Patch second) const { - if(attributeToSort == ColumnsPatch::INDEX) { return direction * (first.progNumber - second.progNumber); } @@ -135,6 +142,9 @@ public: else if (attributeToSort == ColumnsPatch::VER) { return direction * (first.model - second.model); } + else if (attributeToSort == ColumnsPatch::ST) { + return direction * (first.transpose - second.transpose); + } return direction * (first.progNumber - second.progNumber); }