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 0b54ca49916c7338c17dc545aa9abc020d59641f
parent 86dbbba430c784f80664acc3b19233239e25c98e
Author: 790 <790@users.noreply.github.com>
Date:   Wed, 12 Jan 2022 19:17:31 +0000

add extra reverb params.

Diffstat:
Msource/jucePlugin/CMakeLists.txt | 2+-
Msource/jucePlugin/VirusController.cpp | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msource/jucePlugin/VirusParameterBinding.cpp | 2+-
Msource/jucePlugin/assets/bg_1377x800.png | 0
Asource/jucePlugin/assets/buttons/arphold_btn_36x36.png | 0
Msource/jucePlugin/assets/panels/bg_arp_1018x620.png | 0
Msource/jucePlugin/assets/panels/bg_fx_1018x620.png | 0
Msource/jucePlugin/ui/VirusEditor.cpp | 4++++
Msource/jucePlugin/ui/Virus_ArpEditor.cpp | 2+-
Msource/jucePlugin/ui/Virus_Buttons.cpp | 4++--
Msource/jucePlugin/ui/Virus_Buttons.h | 3+--
Msource/jucePlugin/ui/Virus_FxEditor.cpp | 26++++++++++++++++++--------
Msource/jucePlugin/ui/Virus_FxEditor.h | 2++
Msource/jucePlugin/ui/Virus_Parts.cpp | 3+--
Msource/jucePlugin/ui/Virus_Parts.h | 3+--
Msource/jucePlugin/ui/Virus_PatchBrowser.cpp | 58++++++++++++++++++++++++++++++++++++++--------------------
Msource/virusLib/microcontrollerTypes.h | 1+
17 files changed, 124 insertions(+), 45 deletions(-)

diff --git a/source/jucePlugin/CMakeLists.txt b/source/jucePlugin/CMakeLists.txt @@ -83,7 +83,7 @@ juce_add_binary_data(jucePlugin_BinaryData "assets/buttons/Handle_18x47.png" "assets/buttons/sync2_54x25.png" "assets/buttons/part_select_btn_36x36.png" - "assets/buttons/arphold_btn_28_22.png" + "assets/buttons/arphold_btn_36x36.png" "assets/knobs/Gen_70x70_100.png" "assets/knobs/Gen_pol_70x70_100.png" "assets/knobs/GenBlue_70x70_100.png" diff --git a/source/jucePlugin/VirusController.cpp b/source/jucePlugin/VirusController.cpp @@ -379,6 +379,9 @@ namespace Virus if (auto* p = findSynthParam(pt, virusLib::PAGE_B, virusLib::CLOCK_TEMPO)) { p->setValueFromSynth(patch.data[virusLib::MD_CLOCK_TEMPO], true); } + if (auto* p = findSynthParam(pt, virusLib::PAGE_A, virusLib::EFFECT_SEND)) { + p->setValueFromSynth(patch.data[virusLib::MD_PART_EFFECT_SEND], true); + } } } if (hasChecksum) @@ -662,7 +665,20 @@ namespace Virus default: return juce::String(idx); } } - + juce::String numToDelayLfoShape(float idx, Parameter::Description) + { + const auto ridx = juce::roundToInt(idx); + switch (ridx) + { + case 0: return "Sine"; + case 1: return "Triangle"; + case 2: return "Saw"; + case 3: return "Square"; + case 4: return "S&H"; + case 5: return "S&G"; + default: return juce::String(""); + } + } juce::String numToOsc3Mode(float idx, Parameter::Description) { const auto ridx = juce::roundToInt(idx); @@ -822,8 +838,28 @@ namespace Virus case 2: return "Reverb"; case 3: return "Reverb + Feedback 1"; case 4: return "Reverb + Feedback 2"; - case 5: return "Delay X:Y"; - case 6: return "Pattern X+Y"; + case 5: return "Delay2:1"; + case 6: return "Delay4:3"; + case 7: return "Delay4:1"; + case 8: return "Delay8:7"; + case 9: return "Pattern1+1"; + case 10: return "Pattern2+1"; + case 11: return "Pattern3+1"; + case 12: return "Pattern4+1"; + case 13: return "Pattern5+1"; + case 14: return "Pattern2+3"; + case 15: return "Pattern2+5"; + case 16: return "Pattern3+2"; + case 17: return "Pattern3+3"; + case 18: return "Pattern3+4"; + case 19: return "Pattern3+5"; + case 20: return "Pattern4+3"; + case 21: return "Pattern4+5"; + case 22: return "Pattern5+2"; + case 23: return "Pattern5+3"; + case 24: return "Pattern5+4"; + case 25: return "Pattern5+5"; + case 26: return "Pattern X+Y"; default: return juce::String(idx); } } @@ -1397,6 +1433,17 @@ namespace Virus default: return juce::String(""); } } + juce::String numToReverbRoomSize(float idx, Parameter::Description) { + const auto ridx = juce::roundToInt(idx); + + switch (ridx) { + case 0: return "Ambience"; + case 1: return "Small Room"; + case 2: return "Large Room"; + case 3: return "Hall"; + default: return juce::String(""); + } + } const std::initializer_list<Parameter::Description> Controller::m_paramsDescription = { @@ -1505,13 +1552,13 @@ namespace Virus {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 108, "Chorus Delay", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 109, "Chorus Feedback", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 110, "Chorus Lfo Shape", {0,67}, numToLfoShape, {}, true, true, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 112, "Delay/Reverb Mode", {0,6}, numToDelayReverbMode, {}, true, true, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 112, "Delay/Reverb Mode", {0,26}, numToDelayReverbMode, {}, true, true, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE, 113, "Effect Send", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 114, "Delay Time", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 115, "Delay Feedback", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 116, "Delay Rate / Reverb Decay Time", {0,127}, {},{}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 117, "Delay Depth / Reverb Room Size", {0,127}, {},{}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 118, "Delay Lfo Shape", {0,5}, numToLfoShape, {}, true, true, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 117, "Delay Depth / Reverb Room Size", {0,127}, numToReverbRoomSize,{}, true, true, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 118, "Delay Lfo Shape", {0,127}, numToDelayLfoShape, {}, true, true, false}, // {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 118, "Reverb Damping", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 119, "Delay Color", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 122, "Keyb Local", {0,1}, {},{}, false, false, true}, diff --git a/source/jucePlugin/VirusParameterBinding.cpp b/source/jucePlugin/VirusParameterBinding.cpp @@ -48,7 +48,7 @@ void VirusParameterBinding::bind(juce::ComboBox& _combo, Virus::ParameterType _p } void VirusParameterBinding::bind(juce::ComboBox& _combo, Virus::ParameterType _param, uint8_t _part) { - const auto v = m_processor.getController().getParameter(_param, m_processor.getController().getCurrentPart()); + const auto v = m_processor.getController().getParameter(_param, _part); if (!v) { assert(false && "Failed to find parameter"); diff --git a/source/jucePlugin/assets/bg_1377x800.png b/source/jucePlugin/assets/bg_1377x800.png Binary files differ. diff --git a/source/jucePlugin/assets/buttons/arphold_btn_36x36.png b/source/jucePlugin/assets/buttons/arphold_btn_36x36.png Binary files differ. diff --git a/source/jucePlugin/assets/panels/bg_arp_1018x620.png b/source/jucePlugin/assets/panels/bg_arp_1018x620.png Binary files differ. diff --git a/source/jucePlugin/assets/panels/bg_fx_1018x620.png b/source/jucePlugin/assets/panels/bg_fx_1018x620.png Binary files differ. diff --git a/source/jucePlugin/ui/VirusEditor.cpp b/source/jucePlugin/ui/VirusEditor.cpp @@ -150,6 +150,10 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu startTimerHz(5); setSize (kPanelWidth, kPanelHeight); + + // without this some combobox parameters are wrong on first load, no idea why. + m_controller.getParameter(Virus::Param_PlayMode)->setValue(virusLib::PlayModeSingle); + recreateControls(); } VirusEditor::~VirusEditor() { setLookAndFeel(nullptr); } diff --git a/source/jucePlugin/ui/Virus_ArpEditor.cpp b/source/jucePlugin/ui/Virus_ArpEditor.cpp @@ -90,7 +90,7 @@ ArpEditor::Arpeggiator::Arpeggiator(VirusParameterBinding &_parameterBinding) m_octaveRange.setBounds(m_pattern.getBounds().translated(0, comboBoxHeight + 18)); addAndMakeVisible(m_arpHold); - m_arpHold.setBounds(222, m_octaveRange.getY()+2, 28, 11); + m_arpHold.setBounds(218, m_octaveRange.getY()-2, 36, 18); _parameterBinding.bind(m_globalTempo, Virus::Param_ClockTempo, 0); _parameterBinding.bind(m_noteLength, Virus::Param_ArpNoteLength); diff --git a/source/jucePlugin/ui/Virus_Buttons.cpp b/source/jucePlugin/ui/Virus_Buttons.cpp @@ -29,12 +29,12 @@ namespace Buttons Buttons::ArpHoldButton::ArpHoldButton() : DrawableButton("ArpHoldButton", DrawableButton::ImageRaw) { - auto off = Drawable::createFromImageData(BinaryData::arphold_btn_28_22_png, BinaryData::arphold_btn_28_22_pngSize); + auto off = Drawable::createFromImageData(BinaryData::arphold_btn_36x36_png, BinaryData::arphold_btn_36x36_pngSize); auto on = off->createCopy(); setColour(DrawableButton::ColourIds::backgroundColourId, Colours::transparentBlack); setColour(DrawableButton::ColourIds::backgroundOnColourId, Colours::transparentBlack); setClickingTogglesState(true); - on->setOriginWithOriginalSize({0, -11}); + on->setOriginWithOriginalSize({0, -17}); setImages(off.get(), nullptr, on.get(), nullptr, on.get()); } diff --git a/source/jucePlugin/ui/Virus_Buttons.h b/source/jucePlugin/ui/Virus_Buttons.h @@ -65,4 +65,4 @@ namespace Buttons static constexpr auto kHeight = 36; PartSelectButton(); }; -} // namespace Buttons -\ No newline at end of file +} // namespace Buttons diff --git a/source/jucePlugin/ui/Virus_FxEditor.cpp b/source/jucePlugin/ui/Virus_FxEditor.cpp @@ -166,17 +166,18 @@ FxEditor::DelayAndReverb::DelayAndReverb(VirusParameterBinding &_parameterBindin m_sync.setBounds(0, 116 + 2, 481, 116); addAndMakeVisible(m_sync); - _parameterBinding.bind(m_time, Virus::Param_DelayTime); - _parameterBinding.bind(m_rate, Virus::Param_DelayRateReverbDecayTime); - _parameterBinding.bind(m_depth, Virus::Param_DelayDepthReverbRoomSize); - _parameterBinding.bind(m_color, Virus::Param_DelayColor); - _parameterBinding.bind(m_feedback, Virus::Param_DelayFeedback); - _parameterBinding.bind(m_fxMode, Virus::Param_DelayReverbMode); + _parameterBinding.bind(m_time, Virus::Param_DelayTime, 0); + _parameterBinding.bind(m_rate, Virus::Param_DelayRateReverbDecayTime, 0); + _parameterBinding.bind(m_depth, Virus::Param_DelayDepthReverbRoomSize, 0); + _parameterBinding.bind(m_color, Virus::Param_DelayColor, 0); + _parameterBinding.bind(m_feedback, Virus::Param_DelayFeedback, 0); + _parameterBinding.bind(m_fxMode, Virus::Param_DelayReverbMode, 0); } FxEditor::DelayAndReverb::Sync::Sync(VirusParameterBinding &_parameterBinding) { setupRotary(*this, m_mix); + setupRotary(*this, m_damping); m_mix.getProperties().set(Virus::LookAndFeel::KnobStyleProp, Virus::LookAndFeel::KnobStyle::GENERIC_RED); m_mix.setBounds(376, -2, knobSize, knobSize); @@ -185,9 +186,18 @@ FxEditor::DelayAndReverb::Sync::Sync(VirusParameterBinding &_parameterBinding) addAndMakeVisible(m_lfoShape); m_lfoShape.setBounds(m_clock.getBounds().getRight() + 26, 22, comboBoxWidth, comboBoxHeight); + addAndMakeVisible(m_reverbMode); + m_reverbMode.setBounds(m_lfoShape.getBounds().getRight() + 26, 22, comboBoxWidth, comboBoxHeight); + + m_damping.getProperties().set(Virus::LookAndFeel::KnobStyleProp, Virus::LookAndFeel::KnobStyle::GENERIC_RED); + m_damping.setBounds(m_reverbMode.getBounds().getRight() + 2, -2, knobSize, knobSize); + addAndMakeVisible(m_damping); + _parameterBinding.bind(m_mix, Virus::Param_EffectSend); - _parameterBinding.bind(m_clock, Virus::Param_DelayClock); - _parameterBinding.bind(m_lfoShape, Virus::Param_DelayLfoShape); + _parameterBinding.bind(m_clock, Virus::Param_DelayClock, 0); + _parameterBinding.bind(m_lfoShape, Virus::Param_DelayLfoShape, 0); + _parameterBinding.bind(m_damping, Virus::Param_DelayLfoShape, 0); + _parameterBinding.bind(m_reverbMode, Virus::Param_DelayDepthReverbRoomSize, 0); } FxEditor::Vocoder::Vocoder(VirusParameterBinding &_parameterBinding) : diff --git a/source/jucePlugin/ui/Virus_FxEditor.h b/source/jucePlugin/ui/Virus_FxEditor.h @@ -90,6 +90,8 @@ private: Sync(VirusParameterBinding &_parameterBinding); juce::Slider m_mix; juce::ComboBox m_clock, m_lfoShape; + juce::ComboBox m_reverbMode; + juce::Slider m_damping; } m_sync; } m_delayReverb; diff --git a/source/jucePlugin/ui/Virus_Parts.cpp b/source/jucePlugin/ui/Virus_Parts.cpp @@ -159,4 +159,4 @@ void Parts::timerCallback() m_presetNames[pt].setButtonText(m_controller.getCurrentPartPresetName(pt)); } -} -\ No newline at end of file +} diff --git a/source/jucePlugin/ui/Virus_Parts.h b/source/jucePlugin/ui/Virus_Parts.h @@ -28,4 +28,4 @@ class Parts : public juce::Component, private juce::Timer juce::TextButton m_btSingleMode; juce::TextButton m_btMultiSingleMode; juce::TextButton m_btMultiMode; -}; -\ No newline at end of file +}; diff --git a/source/jucePlugin/ui/Virus_PatchBrowser.cpp b/source/jucePlugin/ui/Virus_PatchBrowser.cpp @@ -50,6 +50,25 @@ PatchBrowser::PatchBrowser(VirusParameterBinding & _parameterBinding, Virus::Con void PatchBrowser::selectionChanged() {} +VirusModel guessVersion(uint8_t *data) { + if (data[51] > 3) { + // check extra filter modes + return VirusModel::C; + } + if(data[179] == 0x40 && data[180] == 0x40) // soft knobs don't exist on B so they have fixed value + return VirusModel::B; + /*if (data[232] != 0x03 || data[235] != 0x6c || data[238] != 0x01) { // extra mod slots + return VirusModel::C; + }*/ + /*if(data[173] != 0x00 || data[174] != 0x00) // EQ + return VirusModel::C;*/ + /*if (data[220] != 0x40 || data[221] != 0x54 || data[222] != 0x20 || data[223] != 0x40 || data[224] != 0x40) { + // eq controls + return VirusModel::C; + }*/ + return VirusModel::C; + +} void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e) { auto ext = file.getFileExtension().toLowerCase(); @@ -75,17 +94,17 @@ void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e { Patch patch; patch.progNumber = index; - if ((uint8_t)*(it + 266) != (uint8_t)0xf7) { - patch.model = VirusModel::TI; - } - else { - patch.model = VirusModel::B; - } data.copyTo(patch.data, 267*index + 9, 256); patch.name = parseAsciiText(patch.data, 128 + 112); patch.category1 = patch.data[251]; patch.category2 = patch.data[252]; patch.unison = patch.data[97]; + 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++; } @@ -123,17 +142,17 @@ void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e Patch patch; patch.progNumber = index; - if ((uint8_t)*(it + 266) != (uint8_t)0xf7) { - patch.model = VirusModel::TI; - } - else { - patch.model = VirusModel::B; - } std::copy(syx.begin() + 9, syx.end() - 2, patch.data); patch.name = parseAsciiText(patch.data, 128 + 112); patch.category1 = patch.data[251]; patch.category2 = patch.data[252]; patch.unison = patch.data[97]; + 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++; it += 266; @@ -154,18 +173,18 @@ void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e syx[266] = 0xf7; Patch patch; - if ((uint8_t)*(it + 2 + 266) != (uint8_t)0xf7) { // TI patches are 512 bytes - patch.model = VirusModel::TI; - } - else { - patch.model = VirusModel::B; - } std::memcpy(patch.data, syx.data()+9, 256); patch.progNumber = index; patch.name = parseAsciiText(patch.data, 128 + 112); patch.category1 = patch.data[251]; patch.category2 = patch.data[252]; patch.unison = patch.data[97]; + 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++; @@ -309,4 +328,4 @@ void PatchBrowser::sortOrderChanged(int newSortColumnId, bool isForwards) m_patches.sort(sorter); m_patchList.updateContent(); } -} -\ No newline at end of file +} diff --git a/source/virusLib/microcontrollerTypes.h b/source/virusLib/microcontrollerTypes.h @@ -83,6 +83,7 @@ namespace virusLib MIDI_ARPEGGIATOR_SEND = 96, MULTI_PROGRAM_CHANGE = 105, MIDI_CLOCK_RX = 106, + EFFECT_SEND = 113, // actually in bank A UNK6d = 109, PLAY_MODE = 122, PART_NUMBER = 123,