commit 69a035101fada3d50b2176d3156d521477a5f046 parent 6c74c9ee4044d28de9b12fbab26e31f37790ccc2 Author: 790 <790@users.noreply.github.com> Date: Tue, 11 Jan 2022 15:17:45 +0000 bug fixing Diffstat:
25 files changed, 410 insertions(+), 143 deletions(-)
diff --git a/source/jucePlugin/CMakeLists.txt b/source/jucePlugin/CMakeLists.txt @@ -41,6 +41,7 @@ PRIVATE ui/Virus_LfoEditor.cpp ui/Virus_OscEditor.cpp ui/Virus_PatchBrowser.cpp + ui/Virus_Parts.cpp ui/Virus_Buttons.h ui/Virus_LookAndFeel.h ui/VirusEditor.h @@ -49,6 +50,7 @@ PRIVATE ui/Virus_LfoEditor.h ui/Virus_OscEditor.h ui/Virus_PatchBrowser.h + ui/Virus_Parts.h ui/Ui_Utils.h VirusController.cpp VirusController.h @@ -80,7 +82,7 @@ juce_add_binary_data(jucePlugin_BinaryData "assets/buttons/presets_btn_43_15.png" "assets/buttons/Handle_18x47.png" "assets/buttons/sync2_54x25.png" - "assets/buttons/part_select_btn_39x72.png" + "assets/buttons/part_select_btn_36x36.png" "assets/buttons/arphold_btn_28_22.png" "assets/knobs/Gen_70x70_100.png" "assets/knobs/Gen_pol_70x70_100.png" diff --git a/source/jucePlugin/VirusController.cpp b/source/jucePlugin/VirusController.cpp @@ -20,6 +20,7 @@ namespace Virus (findSynthParam(0, 0x72, 0x7a))->onValueChanged = [this] { const uint8_t prg = isMultiMode() ? 0x0 : 0x40; sendSysEx(constructMessage({MessageType::REQUEST_SINGLE, 0x0, prg})); + sendSysEx(constructMessage({MessageType::REQUEST_MULTI, 0x0, prg})); }; sendSysEx(constructMessage({MessageType::REQUEST_TOTAL})); sendSysEx(constructMessage({MessageType::REQUEST_ARRANGEMENT})); @@ -256,7 +257,13 @@ namespace Virus bankNames.add(parseAsciiText(m_multis[i].data, 0)); return bankNames; } - + void Controller::setSinglePresetName(uint8_t part, juce::String _name) { + constexpr uint8_t asciiStart = 112; + _name = _name.substring(0,kNameLength).paddedRight(' ', kNameLength); + for (int i = 0; i < kNameLength; i++) { + getParamValue(part, 1, asciiStart+i)->setValue((uint8_t)_name[i]); + } + } juce::String Controller::getCurrentPartPresetName(uint8_t part) { // expensive but fresh! @@ -290,7 +297,8 @@ namespace Virus for (auto i = 0; i < kDataSizeInBytes; ++i) patch.push_back(preset.data[i]); sendSysEx(constructMessage(patch)); - sendSysEx(constructMessage({MessageType::REQUEST_ARRANGEMENT})); + //sendSysEx(constructMessage({MessageType::REQUEST_ARRANGEMENT})); + sendSysEx(constructMessage({MessageType::REQUEST_SINGLE, 0x0, pt})); m_currentBank[part] = _bank; m_currentProgram[part] = prg; } @@ -360,6 +368,17 @@ namespace Virus patch.progNumber = msg[startPos + 1]; auto progName = parseAsciiText(msg, startPos + 2 + 3); [[maybe_unused]] auto dataSum = copyData(msg, startPos + 2, patch.data); + + /* If it's a multi edit buffer, set the part page C single parameters to their multi equivalents */ + if (patch.bankNumber == 0) { + for (auto pt = 0; pt < 16; pt++) { + for(int i = 0; i < 8; i++) { + if (auto* p = findSynthParam(pt, virusLib::PAGE_C, virusLib::PART_MIDI_CHANNEL+i)) { + p->setValueFromSynth(patch.data[virusLib::MD_PART_MIDI_CHANNEL + (i*16) + pt], true); + } + } + } + } if (hasChecksum) { const int expectedChecksum = msg[msg.size() - 2]; @@ -367,7 +386,11 @@ namespace Virus const int checksum = (msgDeviceId + 0x11 + patch.bankNumber + patch.progNumber + dataSum) & 0x7f; assert(checksum == expectedChecksum); } - m_multis[patch.progNumber] = patch; + if (patch.bankNumber == 0) { + m_currentMulti = patch; + } else { + m_multis[patch.progNumber] = patch; + } } void Controller::parseControllerDump(synthLib::SMidiEvent &m) @@ -763,7 +786,7 @@ namespace Virus } } - juce::String numToOutputDelaySelect(float idx, Parameter::Description) + juce::String numToOutputSelect(float idx, Parameter::Description) { const auto ridx = juce::roundToInt(idx); switch (ridx) @@ -771,19 +794,19 @@ namespace Virus case 0: return "OUT 1 L"; case 1: return "OUT 1 L+R"; case 2: return "OUT 1 R"; - case 3: return "OUT 2 L"; +/* case 3: return "OUT 2 L"; case 4: return "OUT 2 L+R"; case 5: return "OUT 2 R"; case 6: return "OUT 3 L"; case 7: return "OUT 3 L+R"; - case 8: return "OUT 3 R"; + case 8: return "OUT 3 R";*/ case 9: return "AUX 1 L"; case 10: return "AUX 1 L+R"; case 11: return "AUX 1 R"; case 12: return "AUX 2 L"; case 13: return "AUX 2 L+R"; case 14: return "AUX 2 R"; - default: return juce::String(idx); + default: return juce::String(""); } } @@ -1168,6 +1191,25 @@ namespace Virus } } + juce::String numToSoftKnobName(float idx, Parameter::Description) { + const char *softKnobNames[] = {"~Para","+3rds","+4ths","+5ths", + "+7ths","+Octave","Access","ArpMode","ArpOct","Attack", + "Balance","Chorus","Cutoff","Decay","Delay","Depth", + "Destroy","Detune","Disolve","Distort","Dive","Effects", + "Elevate","Energy","EqHigh","EqLow","EqMid","Fast","Fear", + "Filter","FM","Glide","Hold","Hype","Infect","Length","Mix", + "Morph","Mutate","Noise","Open","Orbit","Pan","Phaser","Phatter", + "Pitch","Pulsate","Push","PWM","Rate","Release","Reso","Reverb", + "Scream","Shape","Sharpen","Slow","Soften","Speed","SubOsc", + "Sustain","Sweep","Swing","Tempo","Thinner","Tone","Tremolo", + "Vibrato","WahWah","Warmth","Warp","Width"}; + const auto ridx = juce::roundToInt(idx); + if (ridx < sizeof(softKnobNames)-1) { + return softKnobNames[ridx]; + } + return juce::String(idx); + } + juce::String numToUnisonMode(float v, Parameter::Description) { const auto ridx = juce::roundToInt(v); @@ -1292,7 +1334,7 @@ namespace Virus const auto ridx = juce::roundToInt(v); switch (ridx) { - case 0: return "Off"; +// case 0: return "Off"; case 1: return "1 Stage"; case 2: return "2 Stages"; case 3: return "3 Stages"; @@ -1315,6 +1357,45 @@ namespace Virus } } + juce::String numToCategory(float idx, Parameter::Description) + { + const juce::Array<juce::String> categories = {"--", "Lead", "Bass", "Pad", "Decay", "Pluck", + "Acid", "Classic", "Arpeggiator", "Effects", "Drums", "Percussion", + "Input", "Vocoder", "Favourite 1", "Favourite 2", "Favourite 3"}; + + const auto ridx = juce::roundToInt(idx); + if(ridx < categories.size()) + return categories[ridx]; + return "Undefined"; + } + + juce::String numToBendRange(float idx, Parameter::Description) { + const auto ridx = juce::roundToInt(idx); + switch (ridx) + { + case 40: return "-2oct"; + case 52: return "-1oct"; + case 57: return "-7st"; + case 58: return "-6st"; + case 59: return "-5st"; + case 60: return "-4st"; + case 61: return "-3st"; + case 62: return "-2st"; + case 63: return "-1st"; + case 64: return "None"; + case 65: return "+1st"; + case 66: return "+2st"; + case 67: return "+3st"; + case 68: return "+4st"; + case 69: return "+5st"; + case 70: return "+6st"; + case 71: return "+7st"; + case 76: return "+1oct"; + case 88: return "+2oct"; + default: return juce::String(""); + } + } + const std::initializer_list<Parameter::Description> Controller::m_paramsDescription = { {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 0, "Bank Select", {0, 3 + 26}, numToBank, {}, false, true, false}, // The Virus TI contains 4 banks of RAM, followed by 26 banks of ROM @@ -1327,45 +1408,45 @@ namespace Virus {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 7, "Channel Volume", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 8, "Balance", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 9, "Contr 9", {0,127}, {},{}, false, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 10, "Panorama", {0,127}, numToPan,{}, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 10, "Panorama", {0,127}, numToPan,{}, true, false, false, true}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 11, "Expression", {0,127}, {},{}, false, false, false}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 12, "Contr 12", {0,127}, {},{}, false, false, false}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 13, "Contr 13", {0,127}, {},{}, false, false, false}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 14, "Contr 14", {0,127}, {},{}, false, false, false}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 15, "Contr 15", {0,127}, {},{}, false, false, false}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 16, "Contr 16", {0,127}, {},{}, false, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 17, "Osc1 Shape", {0,127}, numToOscShape,{}, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 17, "Osc1 Shape", {0,127}, numToOscShape,{}, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 18, "Osc1 Pulsewidth", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 19, "Osc1 Wave Select", {0,64}, numToOscWaveSelect, {}, true, true, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 20, "Osc1 Semitone", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 21, "Osc1 Keyfollow", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 22, "Osc2 Shape", {0,127}, numToOscShape, {}, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 20, "Osc1 Semitone", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 21, "Osc1 Keyfollow", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 22, "Osc2 Shape", {0,127}, numToOscShape, {}, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 23, "Osc2 Pulsewidth", {0,127}, {}, {}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 24, "Osc2 Wave Select", {0,64}, numToOscWaveSelect,{}, true, true, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 25, "Osc2 Semitone", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 25, "Osc2 Semitone", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 26, "Osc2 Detune", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 27, "Osc2 FM Amount", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 28, "Osc2 Sync", {0,1}, {},{}, true, false, true}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 29, "Osc2 Filt Env Amt", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 30, "FM Filt Env Amt", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 31, "Osc2 Keyfollow", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 29, "Osc2 Filt Env Amt", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 30, "FM Filt Env Amt", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 31, "Osc2 Keyfollow", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 32, "Bank Select", {0, 3 + 26}, numToBank,{}, false, true, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 33, "Osc Balance", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 33, "Osc Balance", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 34, "Suboscillator Volume", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 35, "Suboscillator Shape", {0,1}, [](float v, Parameter::Description){ return juce::roundToInt(v) == 0 ? "Square" : "Triangle"; },{}, true, true, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 36, "Osc Mainvolume", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 37, "Noise Volume", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 38, "Ringmodulator Volume", {0,127}, {},{}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::VIRUS_C, 39, "Noise Color", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::VIRUS_C, 39, "Noise Color", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 40, "Cutoff", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 41, "Cutoff2", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 42, "Filter1 Resonance", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 43, "Filter2 Resonance", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 44, "Filter1 Env Amt", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 45, "Filter2 Env Amt", {0,127}, {},{}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 46, "Filter1 Keyfollow", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 47, "Filter2 Keyfollow", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 48, "Filter Balance", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 46, "Filter1 Keyfollow", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 47, "Filter2 Keyfollow", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 48, "Filter Balance", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 49, "Saturation Curve", {0,14}, numToSatCurv, {}, true, true, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 51, "Filter1 Mode", {0,7}, numToFilterMode, {}, true, true, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 52, "Filter2 Mode", {0,3}, numToFilter2Mode, {}, true, true, false}, @@ -1373,12 +1454,12 @@ namespace Virus {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 54, "Filter Env Attack", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 55, "Filter Env Decay", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 56, "Filter Env Sustain", {0,127}, {},{}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 57, "Filter Env Sustain Time", {0,127}, numToEnvSusTime, {}, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 57, "Filter Env Sustain Time", {0,127}, numToEnvSusTime, {}, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 58, "Filter Env Release", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 59, "Amp Env Attack", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 60, "Amp Env Decay", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 61, "Amp Env Sustain", {0,127}, {},{}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 62, "Amp Env Sustain Time", {0,127}, numToEnvSusTime, {}, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 62, "Amp Env Sustain Time", {0,127}, numToEnvSusTime, {}, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 63, "Amp Env Release", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 64, "Hold Pedal", {0,127}, {},{}, false, false, false}, {Parameter::Page::A, Parameter::Class::PERFORMANCE_CONTROLLER, 65, "Portamento Pedal", {0,127}, {},{}, false, false, false}, @@ -1387,40 +1468,40 @@ namespace Virus {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 68, "Lfo1 Shape", {0,67}, numToLfoShape, {}, true, true, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 69, "Lfo1 Env Mode", {0,1}, {},{}, true, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 70, "Lfo1 Mode", {0,1}, numToLfoMode, {}, true, false, true}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 71, "Lfo1 Symmetry", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 71, "Lfo1 Symmetry", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 72, "Lfo1 Keyfollow", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 73, "Lfo1 Keytrigger", {0,127}, {}, {}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 74, "Osc1 Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 75, "Osc2 Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 76, "PW Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 77, "Reso Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 78, "FiltGain Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 74, "Osc1 Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 75, "Osc2 Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 76, "PW Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 77, "Reso Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 78, "FiltGain Lfo1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 79, "Lfo2 Rate", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 80, "Lfo2 Shape", {0,67}, numToLfoShape,{}, true, true, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 81, "Lfo2 Env Mode", {0,1}, {},{}, true, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 82, "Lfo2 Mode", {0,1}, numToLfoMode, {}, true, false, true}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 83, "Lfo2 Symmetry", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 83, "Lfo2 Symmetry", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 84, "Lfo2 Keyfollow", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 85, "Lfo2 Keytrigger", {0,127}, {},{}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 86, "OscShape Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 87, "FmAmount Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 88, "Cutoff1 Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 89, "Cutoff2 Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 90, "Panorama Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 86, "OscShape Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 87, "FmAmount Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 88, "Cutoff1 Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 89, "Cutoff2 Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 90, "Panorama Lfo2 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 91, "Patch Volume", {0,127}, {},{}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 93, "Transpose", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 93, "Transpose", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 94, "Key Mode", {0,5}, numToKeyMode, {}, true, true, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 97, "Unison Mode", {0,15}, numToUnisonMode, {}, true, true, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 98, "Unison Detune", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 99, "Unison Panorama Spread", {0,127}, {},{}, true, false, false}, - {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 100, "Unison Lfo Phase", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 100, "Unison Lfo Phase", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 101, "Input Mode", {0,3}, numToInputMode, {}, true, true, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 102, "Input Select", {0,8}, numToInputSelect,{}, true, true, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 105, "Chorus Mix", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 106, "Chorus Rate", {0,127}, {},{}, true, false, false}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A, 107, "Chorus Depth", {0,127}, {},{}, true, false, false}, {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}, + {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|Parameter::Class::MULTI_OR_SINGLE, 113, "Effect Send", {0,127}, {},{}, true, false, false}, @@ -1430,7 +1511,7 @@ namespace Virus {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, 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}, + {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}, {Parameter::Page::A, Parameter::Class::SOUNDBANK_A|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 123, "All Notes Off", {0,127}, {},{}, false, false, false}, @@ -1438,7 +1519,7 @@ namespace Virus {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 2, "Arp Pattern Selct", {0,63}, numToNumPlusOne, {}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 3, "Arp Octave Range", {0,3}, numToNumPlusOne,{}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 4, "Arp Hold Enable", {0,1}, {},{}, true, false, true}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 5, "Arp Note Length", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 5, "Arp Note Length", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 6, "Arp Swing", {0,127}, numToArpSwing, {}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 7, "Lfo3 Rate", {0,127}, {},{}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 8, "Lfo3 Shape", {0,67}, numToLfoShape, {}, true, true, false}, @@ -1454,9 +1535,9 @@ namespace Virus {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::MULTI_OR_SINGLE|Parameter::Class::NON_PART_SENSITIVE, 20, "Delay Clock", {0,16}, numToMusicDivision, {}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 21, "Lfo3 Clock", {0,21}, numToMusicDivision, {}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 25, "Control Smooth Mode", {0,3}, numToControlSmoothMode,{}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 26, "Bender Range Up", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 27, "Bender Range Down", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 28, "Bender Scale", {0,1}, numToLinExp, {}, true, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 26, "Bender Range Up", {0,127}, numToBendRange, {}, true, true, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 27, "Bender Range Down", {0,127}, numToBendRange, {}, true, true, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 28, "Bender Scale", {0,1}, numToLinExp, {}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 30, "Filter1 Env Polarity", {0,1}, numToNegPos, {}, true, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 31, "Filter1 Env Polarity", {0,1}, numToNegPos, {}, true, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 32, "Filter2 Cutoff Link", {0,1}, {},{}, true, false, true}, @@ -1468,50 +1549,50 @@ namespace Virus {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 39, "Vocoder Mode", {0,12}, numToVocoderMode,{}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 41, "Osc3 Mode", {0,67}, numToOsc3Mode,{}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 42, "Osc3 Volume", {0,127}, {},{}, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 43, "Osc3 Semitone", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 43, "Osc3 Semitone", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 44, "Osc3 Detune", {0,127}, {},{}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 45, "LowEQ Frequency", {0,127}, {},{}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 46, "HighEQ Frequency", {0,127}, {},{}, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 47, "Osc1 Shape Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 48, "Osc2 Shape Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 49, "PulseWidth Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 50, "Fm Amount Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 51, "Soft Knob1 ShortName", {0,127}, {},{}, false, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 52, "Soft Knob2 ShortName", {0,127}, {},{}, false, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 54, "Filter1 EnvAmt Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 55, "Filter2 EnvAmt Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 56, "Resonance1 Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 57, "Resonance2 Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 47, "Osc1 Shape Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 48, "Osc2 Shape Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 49, "PulseWidth Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 50, "Fm Amount Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 51, "Soft Knob1 ShortName", {0,71}, numToSoftKnobName,{}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 52, "Soft Knob2 ShortName", {0,71}, numToSoftKnobName,{}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 54, "Filter1 EnvAmt Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 55, "Filter2 EnvAmt Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 56, "Resonance1 Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 57, "Resonance2 Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 58, "Second Output Balance", {0,127}, {},{}, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 60, "Amp Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 61, "Panorama Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 60, "Amp Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 61, "Panorama Velocity", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 62, "Soft Knob-1 Single", {0,117}, numToSoftKnobDest, {}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 63, "Soft Knob-2 Single", {0,117}, numToSoftKnobDest, {}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 64, "Assign1 Source", {0,27}, numToModMatrixSource, {}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 65, "Assign1 Destination", {0,122}, numToModMatrixDest, {}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 66, "Assign1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 66, "Assign1 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 67, "Assign2 Source", {0,27}, numToModMatrixSource,{}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 68, "Assign2 Destination1", {0,122}, numToModMatrixDest,{}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 69, "Assign2 Amount1", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 69, "Assign2 Amount1", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 70, "Assign2 Destination2", {0,122}, numToModMatrixDest, {}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 71, "Assign2 Amount2", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 71, "Assign2 Amount2", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 72, "Assign3 Source", {0,27}, numToModMatrixSource, {}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 73, "Assign3 Destination1", {0,122}, numToModMatrixDest,{}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 74, "Assign3 Amount1", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 74, "Assign3 Amount1", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 75, "Assign3 Destination2", {0,122}, numToModMatrixDest,{}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 76, "Assign3 Amount2", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 76, "Assign3 Amount2", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 77, "Assign2 Destination3", {0,122}, numToModMatrixDest,{}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 78, "Assign2 Amount3", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 78, "Assign2 Amount3", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 79, "LFO1 Assign Dest", {0,122}, numToModMatrixDest, {}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 80, "LFO1 Assign Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 80, "LFO1 Assign Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 81, "LFO2 Assign Dest", {0,122}, numToModMatrixDest, {}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 82, "LFO2 Assign Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 82, "LFO2 Assign Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 84, "Phaser Mode", {0,6}, numToPhaserMode, {}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 85, "Phaser Mix", {0,127}, {},{}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 86, "Phaser Rate", {0,127}, {},{}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 87, "Phaser Depth", {0,127}, {},{}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 88, "Phaser Frequency", {0,127}, {},{}, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 89, "Phaser Feedback", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 89, "Phaser Feedback", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 90, "Phaser Spread", {0,127}, {},{}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 92, "MidEQ Gain", {0,127}, {},{}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 93, "MidEQ Frequency", {0,127}, {},{}, true, false, false}, @@ -1523,34 +1604,35 @@ namespace Virus {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 99, "Input Ringmodulator", {0,127}, {},{}, true, false, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 100, "Distortion Curve", {0,11}, numToDistortionCurv,{}, true, true, false}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 101, "Distortion Intensity", {0,127}, {},{}, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 102, "Assign 4 Source", {0,27}, numToModMatrixSource,{}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 103, "Assign 4 Destination", {0,122}, numToModMatrixDest, {}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C,104, "Assign 4 Amount", {0,127}, {},{}, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 105, "Assign 5 Source", {0,27}, numToModMatrixSource, {}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 106, "Assign 5 Destination", {0,122}, numToModMatrixDest, {}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 107, "Assign 5 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 108, "Assign 6 Source", {0,27}, numToModMatrixSource, {}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 109, "Assign 6 Destination", {0,122}, numToModMatrixDest, {}, true, true, false}, - {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 110, "Assign 6 Amount", {0,127}, paramTo7bitSigned, {}, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 103, "Assign 4 Source", {0,27}, numToModMatrixSource,{}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 104, "Assign 4 Destination", {0,122}, numToModMatrixDest, {}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 105, "Assign 4 Amount", {0,127}, {},{}, true, false, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 106, "Assign 5 Source", {0,27}, numToModMatrixSource, {}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 107, "Assign 5 Destination", {0,122}, numToModMatrixDest, {}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 108, "Assign 5 Amount", {0,127}, paramTo7bitSigned, textTo7bitSigned, true, false, false, true}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 109, "Assign 6 Source", {0,27}, numToModMatrixSource, {}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 110, "Assign 6 Destination", {0,122}, numToModMatrixDest, {}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 111, "Assign 6 Amount", {0,127}, paramTo7bitSigned, {}, true, false, false, true}, {Parameter::Page::B, Parameter::Class::SOUNDBANK_B|Parameter::Class::VIRUS_C, 122, "Filter Select", {0,2}, numToFilterSelect, {}, true, true, false}, - - {Parameter::Page::C, Parameter::Class::MULTI_PARAM|Parameter::Class::NON_PART_SENSITIVE, 22, "Delay Output Select", {0,14}, numToOutputDelaySelect, {}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 123, "Category1", {0,16}, numToCategory, {}, true, true, false}, + {Parameter::Page::B, Parameter::Class::SOUNDBANK_B, 124, "Category2", {0,16}, numToCategory, {}, true, true, false}, + {Parameter::Page::C, Parameter::Class::MULTI_PARAM|Parameter::Class::NON_PART_SENSITIVE, 22, "Delay Output Select", {0,14}, numToOutputSelect, {}, false, true, false}, {Parameter::Page::C, Parameter::Class::MULTI_PARAM|Parameter::Class::BANK_PROGRAM_CHANGE_PARAM_BANK_SELECT, 31, "Part Bank Select", {0, 3 + 26}, {},{}, false, true, false}, {Parameter::Page::C, Parameter::Class::MULTI_PARAM|Parameter::Class::BANK_PROGRAM_CHANGE_PARAM_BANK_SELECT, 32, "Part Bank Change", {0, 3 + 26}, {},{}, false, true, false}, {Parameter::Page::C, Parameter::Class::MULTI_PARAM|Parameter::Class::BANK_PROGRAM_CHANGE_PARAM_BANK_SELECT, 33, "Part Program Change", {0,127}, {},{}, false, false, false}, {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 34, "Part Midi Channel", {0,15}, {},{}, false, true, false}, {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 35, "Part Low Key", {0,127}, {},{}, false, true, false}, {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 36, "Part High Key", {0,127}, {},{}, false, true, false}, - {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 37, "Part Transpose", {0,127}, paramTo7bitSigned, textTo7bitSigned, false, false, false}, - {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 38, "Part Detune", {0,127}, paramTo7bitSigned, textTo7bitSigned, false, false, false}, - {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 39, "Part Volume", {0,127}, {},{}, true, false, false}, + {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 37, "Part Transpose", {0,127}, paramTo7bitSigned, textTo7bitSigned, false, false, false, true}, + {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 38, "Part Detune", {0,127}, paramTo7bitSigned, textTo7bitSigned, false, false, false, true}, + {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 39, "Part Volume", {0,127}, paramTo7bitSigned,textTo7bitSigned, true, false, false, true}, {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 40, "Part Midi Volume Init", {0,127}, {},{}, false, true, false}, - {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 41, "Part Output Select", {0,14}, {},{}, false, true, false}, + {Parameter::Page::C, Parameter::Class::MULTI_PARAM, 41, "Part Output Select", {0,14}, numToOutputSelect,{}, false, true, false}, {Parameter::Page::C, Parameter::Class::GLOBAL, 45, "Second Output Select", {0,15}, {},{}, false, true, false}, {Parameter::Page::C, Parameter::Class::GLOBAL, 63, "Keyb Transpose Buttons", {0,1}, {},{}, false, false, true}, {Parameter::Page::C, Parameter::Class::GLOBAL, 64, "Keyb Local", {0,1}, {},{}, false, false, true}, {Parameter::Page::C, Parameter::Class::GLOBAL, 65, "Keyb Mode", {0,1}, {},{}, false, false, true}, - {Parameter::Page::C, Parameter::Class::GLOBAL, 66, "Keyb Transpose", {0,127}, paramTo7bitSigned, textTo7bitSigned, false, false, false}, + {Parameter::Page::C, Parameter::Class::GLOBAL, 66, "Keyb Transpose", {0,127}, paramTo7bitSigned, textTo7bitSigned, false, false, false, true}, {Parameter::Page::C, Parameter::Class::GLOBAL, 67, "Keyb ModWheel Contr", {0,127}, {},{}, false, false, false}, {Parameter::Page::C, Parameter::Class::GLOBAL, 68, "Keyb Pedal 1 Contr", {0,127}, {},{}, false, false, false}, {Parameter::Page::C, Parameter::Class::GLOBAL, 69, "Keyb Pedal 2 Contr", {0,127}, {},{}, false, false, false}, @@ -1566,7 +1648,7 @@ namespace Virus {Parameter::Page::C, Parameter::Class::GLOBAL, 87, "Glob Midi Volume Enable", {0,1}, {},{}, false, false, true}, {Parameter::Page::C, Parameter::Class::GLOBAL, 90, "Input Thru Level", {0,127}, {},{}, false, false, false}, {Parameter::Page::C, Parameter::Class::GLOBAL, 91, "Input Boost", {0,127}, {},{}, false, false, false}, - {Parameter::Page::C, Parameter::Class::GLOBAL, 92, "Master Tune", {0,127}, paramTo7bitSigned, textTo7bitSigned, false, false, false}, + {Parameter::Page::C, Parameter::Class::GLOBAL, 92, "Master Tune", {0,127}, paramTo7bitSigned, textTo7bitSigned, false, false, false, true}, {Parameter::Page::C, Parameter::Class::GLOBAL, 93, "Device ID", {0,16}, {},{}, true, true, false}, {Parameter::Page::C, Parameter::Class::GLOBAL, 94, "Midi Control Low Page", {0,1}, {},{}, false, false, true}, {Parameter::Page::C, Parameter::Class::GLOBAL, 95, "Midi Control High Page", {0,1}, {},{}, false, false, true}, diff --git a/source/jucePlugin/VirusController.h b/source/jucePlugin/VirusController.h @@ -231,7 +231,8 @@ namespace Virus Param_Assign6Destination, Param_Assign6Amount, Param_FilterSelect, - + Param_Category1, + Param_Category2, Param_DelayOutputSelect, Param_PartBankSelect, Param_PartBankChange, @@ -412,6 +413,7 @@ namespace Virus // bank - 0-1 (AB) juce::StringArray getSinglePresetNames(virusLib::BankNumber bank) const; juce::StringArray getMultiPresetsName() const; + void setSinglePresetName(uint8_t part, juce::String _name); bool isMultiMode() { return getParamValue(0, 2, 0x7a)->getValue(); } // part 0 - 15 (ignored when single! 0x40...) void setCurrentPartPreset(uint8_t part, virusLib::BankNumber bank, uint8_t prg); @@ -419,6 +421,8 @@ namespace Virus uint8_t getCurrentPartProgram(uint8_t part); juce::String getCurrentPartPresetName(uint8_t part); uint32_t getBankCount() const { return static_cast<uint32_t>(m_singles.size()); } + uint8_t getCurrentPart() const { return m_currentPart; } + void setCurrentPart(uint8_t _part) { m_currentPart = _part; } void parseMessage(const SysEx &); void sendSysEx(const SysEx &); void onStateLoaded(); @@ -442,7 +446,7 @@ namespace Virus MultiPatch m_multis[128]; // RAM has 128 Multi 'snapshots' std::array<std::array<SinglePatch, 128>, 8> m_singles; - + MultiPatch m_currentMulti; static const std::initializer_list<Parameter::Description> m_paramsDescription; struct ParamIndex @@ -489,5 +493,6 @@ namespace Virus unsigned char m_deviceId; virusLib::BankNumber m_currentBank[16]; uint8_t m_currentProgram[16]; + uint8_t m_currentPart; }; }; // namespace Virus diff --git a/source/jucePlugin/VirusParameter.h b/source/jucePlugin/VirusParameter.h @@ -42,6 +42,7 @@ namespace Virus bool isPublic; bool isDiscrete; bool isBool; + bool isBipolar; }; Parameter(Controller &, const Description desc, uint8_t partNum = 0x40); @@ -56,9 +57,10 @@ namespace Virus float getValue() const override { return convertTo0to1(m_value.getValue()); } void setValue(float newValue) override { return m_value.setValue(convertFrom0to1(newValue)); }; void setValueFromSynth(int newValue, bool notifyHost = true); - float getDefaultValue() const override { return 0; /* maybe return from ROM state? */ } + float getDefaultValue() const override { return m_desc.isBipolar ? 64.0f : 0.0f; /* maybe return from ROM state? */ } bool isDiscrete() const override { return m_desc.isDiscrete; } bool isBoolean() const override { return m_desc.isBool; } + bool isBipolar() const { return m_desc.isBipolar; } float getValueForText(const juce::String &text) const override { diff --git a/source/jucePlugin/VirusParameterBinding.cpp b/source/jucePlugin/VirusParameterBinding.cpp @@ -2,53 +2,78 @@ #include "VirusParameter.h" #include "PluginProcessor.h" -void VirusParameterBinding::setPart(uint8_t _part) { - m_part = _part; +VirusParameterBinding::~VirusParameterBinding() +{ + clearBindings(); +} +void VirusParameterBinding::clearBindings() { for (const auto b : m_bindings) { b->onValueChanged = nullptr; } m_bindings.clear(); - +} +void VirusParameterBinding::setPart(uint8_t _part) +{ + clearBindings(); + m_processor.getController().setCurrentPart(_part); } void VirusParameterBinding::bind(juce::Slider &_slider, Virus::ParameterType _param) { - const auto v = m_processor.getController().getParameter(_param, m_part); + bind(_slider, _param, m_processor.getController().getCurrentPart()); +} +void VirusParameterBinding::bind(juce::Slider &_slider, Virus::ParameterType _param, uint8_t part) +{ + const auto v = m_processor.getController().getParameter(_param, part); if (!v) { assert(false && "Failed to find parameter"); return; } const auto range = v->getNormalisableRange(); + _slider.setRange(range.start, range.end, range.interval); _slider.setDoubleClickReturnValue(true, v->getDefaultValue()); _slider.getValueObject().referTo(v->getValueObject()); + _slider.getProperties().set("type", "slider"); + _slider.getProperties().set("name", v->name); + if (v->isBipolar()) { + _slider.getProperties().set("bipolar", true); + } } -void VirusParameterBinding::bind(juce::ComboBox& _combo, Virus::ParameterType _param) +void VirusParameterBinding::bind(juce::ComboBox& _combo, Virus::ParameterType _param) { + bind(_combo, _param, m_processor.getController().getCurrentPart()); +} +void VirusParameterBinding::bind(juce::ComboBox& _combo, Virus::ParameterType _param, uint8_t _part) { - const auto v = m_processor.getController().getParameter(_param, m_part); + const auto v = m_processor.getController().getParameter(_param, m_processor.getController().getCurrentPart()); if (!v) { assert(false && "Failed to find parameter"); return; } _combo.setTextWhenNothingSelected("--"); - _combo.addItemList(v->getAllValueStrings(), 1); - _combo.setSelectedItemIndex(v->getValueObject().getValueSource().getValue()); + int idx = 1; + for (auto vs : v->getAllValueStrings()) { + if(vs.isNotEmpty()) + _combo.addItem(vs, idx); + idx++; + } + //_combo.addItemList(v->getAllValueStrings(), 1); + _combo.setSelectedId((int)v->getValueObject().getValueSource().getValue() + 1, juce::dontSendNotification); _combo.onChange = [this, &_combo, v]() { - //v->setValue(_combo.getSelectedId() - 1); - v->getValueObject().getValueSource().setValue(_combo.getSelectedItemIndex()); + v->getValueObject().getValueSource().setValue(_combo.getSelectedId() - 1); }; - v->onValueChanged = [this, &_combo, v]() { _combo.setSelectedItemIndex(v->getValueObject().getValueSource().getValue(), juce::NotificationType::dontSendNotification); }; + v->onValueChanged = [this, &_combo, v]() { _combo.setSelectedId((int)v->getValueObject().getValueSource().getValue() + 1, juce::NotificationType::dontSendNotification); }; m_bindings.add(v); } void VirusParameterBinding::bind(juce::DrawableButton &_btn, Virus::ParameterType _param) { - const auto v = m_processor.getController().getParameter(_param, m_part); + const auto v = m_processor.getController().getParameter(_param, m_processor.getController().getCurrentPart()); if (!v) { assert(false && "Failed to find parameter"); @@ -59,7 +84,7 @@ void VirusParameterBinding::bind(juce::DrawableButton &_btn, Virus::ParameterTyp void VirusParameterBinding::bind(juce::Component &_btn, Virus::ParameterType _param) { - const auto v = m_processor.getController().getParameter(_param, m_part); + const auto v = m_processor.getController().getParameter(_param, m_processor.getController().getCurrentPart()); if (!v) { assert(false && "Failed to find parameter"); diff --git a/source/jucePlugin/VirusParameterBinding.h b/source/jucePlugin/VirusParameterBinding.h @@ -1,6 +1,7 @@ #pragma once #include "VirusController.h" #include "VirusParameter.h" +#include "ui/Virus_Buttons.h" namespace juce { class Value; } @@ -10,16 +11,19 @@ class AudioPluginAudioProcessor; class VirusParameterBinding { public: - VirusParameterBinding(AudioPluginAudioProcessor& _processor, uint8_t _part = 0) : m_processor(_processor) + VirusParameterBinding(AudioPluginAudioProcessor& _processor) : m_processor(_processor) { - m_part = _part; + } + ~VirusParameterBinding(); + void clearBindings(); void setPart(uint8_t _part); void bind(juce::Slider& _control, Virus::ParameterType _param); + void bind(juce::Slider& _control, Virus::ParameterType _param, uint8_t _part); void bind(juce::ComboBox &_control, Virus::ParameterType _param); + void bind(juce::ComboBox &_control, Virus::ParameterType _param, uint8_t _part); 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/assets/buttons/part_select_btc_18x36.png b/source/jucePlugin/assets/buttons/part_select_btc_18x36.png Binary files differ. diff --git a/source/jucePlugin/assets/buttons/part_select_btn_36x36.png b/source/jucePlugin/assets/buttons/part_select_btn_36x36.png Binary files differ. diff --git a/source/jucePlugin/ui/VirusEditor.cpp b/source/jucePlugin/ui/VirusEditor.cpp @@ -15,7 +15,8 @@ constexpr auto kPanelWidth = 1377; constexpr auto kPanelHeight = 800; VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAudioProcessor &_processorRef) : - m_parameterBinding(_parameterBinding), processorRef(_processorRef), m_controller(processorRef.getController()), m_btSingleMode("Single Mode"), m_btMultiMode("Multi Mode") + m_parameterBinding(_parameterBinding), processorRef(_processorRef), m_controller(processorRef.getController()), m_btSingleMode("Single\nMode"), m_btMultiSingleMode("Multi\nSingle"), m_btMultiMode("Multi\nMode"), + m_controlLabel("ctrlLabel", "") { setLookAndFeel(&m_lookAndFeel); @@ -56,7 +57,7 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu m_partLabels[pt].setJustificationType(Justification::centred); addAndMakeVisible(m_partLabels[pt]); - m_partSelect[pt].setBounds(34, 161 + pt*(36), 39, 36); + m_partSelect[pt].setBounds(35, 161 + pt*(36), 36, 36); m_partSelect[pt].setButtonText(juce::String(pt)); m_partSelect[pt].setRadioGroupId(kPartGroupId); m_partSelect[pt].setClickingTogglesState(true); @@ -69,7 +70,6 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu m_presetNames[pt].setButtonText(m_controller.getCurrentPartPresetName(pt)); m_presetNames[pt].setColour(juce::TextButton::ColourIds::textColourOnId, juce::Colour(255,113,128)); m_presetNames[pt].setColour(juce::TextButton::ColourIds::textColourOffId, juce::Colour(255, 113, 128)); - //m_presetNames[pt].setColour(0, juce::Colours::white); m_presetNames[pt].onClick = [this, pt]() { juce::PopupMenu selector; @@ -115,31 +115,53 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu }; addAndMakeVisible(m_prevPatch[pt]); addAndMakeVisible(m_nextPatch[pt]); + + m_partVolumes[pt].setSliderStyle(juce::Slider::RotaryHorizontalVerticalDrag); + m_partVolumes[pt].setTextBoxStyle(juce::Slider::NoTextBox, false, 0, 0); + m_partVolumes[pt].setBounds(m_nextPatch[pt].getBounds().translated(m_nextPatch[pt].getWidth()+8, 0)); + m_partVolumes[pt].setSize(18,18); + m_partVolumes[pt].getProperties().set(Virus::LookAndFeel::KnobStyleProp, Virus::LookAndFeel::KnobStyle::GENERIC_MULTI); + _parameterBinding.bind(m_partVolumes[pt], Virus::Param_PartVolume, pt); + addAndMakeVisible(m_partVolumes[pt]); + + m_partPans[pt].setSliderStyle(juce::Slider::RotaryHorizontalVerticalDrag); + m_partPans[pt].setTextBoxStyle(juce::Slider::NoTextBox, false, 0, 0); + m_partPans[pt].setBounds(m_partVolumes[pt].getBounds().translated(m_partVolumes[pt].getWidth()+4, 0)); + m_partPans[pt].setSize(18,18); + m_partPans[pt].getProperties().set(Virus::LookAndFeel::KnobStyleProp, Virus::LookAndFeel::KnobStyle::GENERIC_MULTI); + _parameterBinding.bind(m_partPans[pt], Virus::Param_Panorama, pt); + addAndMakeVisible(m_partPans[pt]); } - m_partSelect[0].setToggleState(true, NotificationType::sendNotification); + m_partSelect[m_controller.getCurrentPart()].setToggleState(true, NotificationType::sendNotification); m_btSingleMode.setRadioGroupId(0x3cf); m_btMultiMode.setRadioGroupId(0x3cf); + m_btMultiSingleMode.setRadioGroupId(0x3cf); addAndMakeVisible(m_btSingleMode); addAndMakeVisible(m_btMultiMode); + addAndMakeVisible(m_btMultiSingleMode); m_btSingleMode.setTopLeftPosition(102, 756); - m_btSingleMode.setSize(100, 30); + m_btSingleMode.setSize(70, 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); + const auto isMulti = m_controller.getParamValue(Virus::Param_PlayMode)>0; m_btSingleMode.setClickingTogglesState(true); m_btMultiMode.setClickingTogglesState(true); + m_btMultiSingleMode.setClickingTogglesState(true); + m_btSingleMode.setToggleState(true, juce::sendNotificationAsync); + //m_btMultiMode.setToggleState(isMulti, juce::dontSendNotification); + //m_btMultiSingleMode.setToggleState(isMulti, juce::dontSendNotification); m_btSingleMode.setColour(TextButton::ColourIds::textColourOnId, juce::Colours::white); m_btSingleMode.setColour(TextButton::ColourIds::textColourOffId, juce::Colours::grey); m_btMultiMode.setColour(TextButton::ColourIds::textColourOnId, juce::Colours::white); m_btMultiMode.setColour(TextButton::ColourIds::textColourOffId, juce::Colours::grey); - m_btSingleMode.onClick = [this]() { setPlayMode(0); }; - m_btMultiMode.onClick = [this]() { setPlayMode(1); }; + m_btMultiSingleMode.setColour(TextButton::ColourIds::textColourOnId, juce::Colours::white); + m_btMultiSingleMode.setColour(TextButton::ColourIds::textColourOffId, juce::Colours::grey); + m_btSingleMode.onClick = [this]() { setPlayMode(virusLib::PlayMode::PlayModeSingle); }; + m_btMultiSingleMode.onClick = [this]() { setPlayMode(virusLib::PlayMode::PlayModeMultiSingle); }; + m_btMultiMode.onClick = [this]() { setPlayMode(virusLib::PlayMode::PlayModeMulti); }; - m_btMultiMode.setTopLeftPosition(m_btSingleMode.getPosition().x + m_btSingleMode.getWidth() + 10, - m_btSingleMode.getY()); - m_btMultiMode.setSize(100, 30); + m_btMultiSingleMode.setBounds(m_btSingleMode.getBounds().translated(m_btSingleMode.getWidth()+4, 0)); + m_btMultiMode.setBounds(m_btMultiSingleMode.getBounds().translated(m_btMultiSingleMode.getWidth()+4, 0)); juce::PropertiesFile::Options opts; opts.applicationName = "DSP56300 Emulator"; @@ -215,8 +237,26 @@ VirusEditor::VirusEditor(VirusParameterBinding &_parameterBinding, AudioPluginAu m_patchName.setJustificationType(Justification::left); m_patchName.setFont(juce::Font(32.0f, juce::Font::bold)); m_patchName.setColour(juce::Label::textColourId, juce::Colour(255, 113, 128)); + m_patchName.setEditable(false, true, true); + m_patchName.onTextChange = [this]() { + auto text = m_patchName.getText(); + if(text.trim().length() > 0) { + m_controller.setSinglePresetName(m_controller.getCurrentPart(), text); + } + }; addAndMakeVisible(m_patchName); + m_controlLabel.setBounds(650, 48, 262, 36); + m_controlLabel.setJustificationType(Justification::right); + m_controlLabel.setColour(juce::Label::textColourId, juce::Colour(255, 113, 128)); + m_controlLabel.setFont(juce::Font(16.0f, juce::Font::bold)); + //m_controlLabel.setColour(juce::Label::ColourIds::backgroundColourId, juce::Colours::black); + //m_controlLabel.setColour(juce::Label::ColourIds::outlineColourId, juce::Colours::white); + + addAndMakeVisible(m_controlLabel); + + addMouseListener(this, true); + startTimerHz(5); setSize (kPanelWidth, kPanelHeight); } @@ -235,11 +275,14 @@ void VirusEditor::timerCallback() m_nextPatch[pt].setVisible(singlePartOrInMulti); if (singlePartOrInMulti) m_presetNames[pt].setButtonText(m_controller.getCurrentPartPresetName(pt)); - if (pt == m_parameterBinding.m_part) + if (pt == m_controller.getCurrentPart()) { - m_patchName.setText(m_controller.getCurrentPartPresetName(pt), - NotificationType::dontSendNotification); + const auto patchName = m_controller.getCurrentPartPresetName(pt); + if(m_patchName.getText() != patchName) { + m_patchName.setText(patchName, NotificationType::dontSendNotification); + } } + //m_partVolumes[pt].setValue(m_controller.getParameter(Virus::Param_PartVolume, pt)->getValue(), juce::dontSendNotification); } } @@ -319,6 +362,39 @@ void VirusEditor::applyToSections(std::function<void(Component *)> action) } } +void VirusEditor::mouseDrag(const juce::MouseEvent & event) +{ + const bool paramLocal = false; + auto props = event.eventComponent->getProperties(); + if(props.contains("type") && props["type"] == "slider") { + m_controlLabel.setVisible(true); + auto comp = dynamic_cast<juce::Slider*>(event.eventComponent); + if(comp) { + auto name = props["name"]; + + if(paramLocal) { + m_controlLabel.setTopLeftPosition(getTopLevelComponent()->getLocalPoint(comp->getParentComponent(), comp->getPosition().translated(0, -16))); + m_controlLabel.setSize(comp->getWidth(), 20); + } + else { + m_controlLabel.setBounds(m_patchName.getBounds().translated(m_controlLabel.getWidth(), 0)); + m_controlLabel.setSize(m_patchName.getWidth()/2, m_patchName.getHeight()); + } + if (props.contains("bipolar") && props["bipolar"]) { + m_controlLabel.setText(name.toString() + "\n" + juce::String(juce::roundToInt(comp->getValue())-64), juce::dontSendNotification); + } else { + m_controlLabel.setText(name.toString() + "\n" + juce::String(juce::roundToInt(comp->getValue())), juce::dontSendNotification); + } + } + } +} + +void VirusEditor::mouseUp(const juce::MouseEvent & event) +{ + m_controlLabel.setText("", juce::dontSendNotification); + m_controlLabel.setVisible(false); +} + void VirusEditor::resized() { m_background->setBounds (getLocalBounds()); @@ -501,14 +577,13 @@ void VirusEditor::saveFile() { const auto result = chooser.getResult(); m_previousPath = result.getParentDirectory().getFullPathName(); const auto ext = result.getFileExtension().toLowerCase(); - const uint8_t syxHeader[9] = {0xF0, 0x00, 0x20, 0x33, 0x01, 0x00, 0x10, 0x01, 0x00}; const uint8_t syxEof[1] = {0xF7}; uint8_t cs = syxHeader[5] + syxHeader[6] + syxHeader[7] + syxHeader[8]; uint8_t data[256]; for (int i = 0; i < 256; i++) { - auto param = m_controller.getParamValue(m_parameterBinding.m_part, i < 128 ? 0 : 1, i % 128); + auto param = m_controller.getParamValue(m_controller.getCurrentPart(), i < 128 ? 0 : 1, i % 128); data[i] = param ? (int)param->getValue() : 0; cs += data[i]; diff --git a/source/jucePlugin/ui/VirusEditor.h b/source/jucePlugin/ui/VirusEditor.h @@ -12,6 +12,7 @@ class LfoEditor; class FxEditor; class ArpEditor; class PatchBrowser; +class Parts; class VirusEditor : public juce::Component, private juce::Timer { @@ -32,12 +33,16 @@ private: juce::Label m_version; juce::Label m_patchName; + juce::Label m_controlLabel; 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::Slider m_partVolumes[16]; + juce::Slider m_partPans[16]; juce::TextButton m_btSingleMode; + juce::TextButton m_btMultiSingleMode; juce::TextButton m_btMultiMode; juce::ComboBox m_cmbMidiInput; juce::ComboBox m_cmbMidiOutput; @@ -81,9 +86,13 @@ private: std::unique_ptr<ArpEditor> m_arpEditor; std::unique_ptr<PatchBrowser> m_patchBrowser; + std::unique_ptr<Parts> m_partList; std::unique_ptr<juce::Drawable> m_background; Virus::LookAndFeel m_lookAndFeel; juce::String m_previousPath; + + void mouseDrag (const juce::MouseEvent &event) override; + void mouseUp (const juce::MouseEvent &event) override; }; diff --git a/source/jucePlugin/ui/Virus_ArpEditor.cpp b/source/jucePlugin/ui/Virus_ArpEditor.cpp @@ -83,7 +83,8 @@ ArpEditor::Arpeggiator::Arpeggiator(VirusParameterBinding &_parameterBinding) constexpr auto comboBoxHeight = 15; constexpr auto comboTopY = 35; - m_mode.setBounds(35, 40, 100, 18); + m_mode.setBounds(35, 40, 90, 15); + m_mode.setJustificationType(Justification::topLeft); m_pattern.setBounds(114, comboTopY, comboBoxWidth, comboBoxHeight); m_resolution.setBounds(220, comboTopY, comboBoxWidth, comboBoxHeight); m_octaveRange.setBounds(m_pattern.getBounds().translated(0, comboBoxHeight + 18)); @@ -111,6 +112,11 @@ ArpEditor::SoftKnobs::SoftKnobs(VirusParameterBinding &_parameterBinding) addAndMakeVisible(m_name[i]); m_name[i].setBounds(m_funcAs[i].getX() + distance, 42, comboBoxWidth, comboBoxHeight); } + _parameterBinding.bind(m_name[0], Virus::Param_SoftKnob1ShortName); + _parameterBinding.bind(m_name[1], Virus::Param_SoftKnob2ShortName); + + _parameterBinding.bind(m_funcAs[0], Virus::Param_SoftKnob1Single); + _parameterBinding.bind(m_funcAs[1], Virus::Param_SoftKnob2Single); } ArpEditor::PatchSettings::PatchSettings(VirusParameterBinding &_parameterBinding) @@ -125,9 +131,11 @@ ArpEditor::PatchSettings::PatchSettings(VirusParameterBinding &_parameterBinding m_transpose.setBounds(m_panning.getX(), y2, knobSize, knobSize); for (auto *cb : - {&m_keyMode, &m_secondaryOutput, &m_bendUp, &m_bendDown, &m_bendScale, &m_smoothMode, &m_cat1, &m_cat2}) + {&m_keyMode, &m_secondaryOutput, &m_bendScale, &m_smoothMode, &m_cat1, &m_cat2}) addAndMakeVisible(cb); - + + addAndMakeVisible(m_bendUp); + addAndMakeVisible(m_bendDown); constexpr auto yDist = 50; m_keyMode.setBounds(18, 42, comboBoxWidth, comboBoxHeight); @@ -146,9 +154,12 @@ ArpEditor::PatchSettings::PatchSettings(VirusParameterBinding &_parameterBinding //_parameterBinding.bind(m_outputBalance, Virus::Param_SecondOutputBalance); _parameterBinding.bind(m_transpose, Virus::Param_Transpose); _parameterBinding.bind(m_keyMode, Virus::Param_KeyMode); - //_parameterBinding.bind(m_secondaryOutput, Virus::Param_KeyMode); _parameterBinding.bind(m_bendUp, Virus::Param_BenderRangeUp); _parameterBinding.bind(m_bendDown, Virus::Param_BenderRangeDown); _parameterBinding.bind(m_bendScale, Virus::Param_BenderScale); _parameterBinding.bind(m_smoothMode, Virus::Param_ControlSmoothMode); + _parameterBinding.bind(m_cat1, Virus::Param_Category1); + _parameterBinding.bind(m_cat2, Virus::Param_Category2); + + _parameterBinding.bind(m_secondaryOutput, Virus::Param_PartOutputSelect); } diff --git a/source/jucePlugin/ui/Virus_ArpEditor.h b/source/jucePlugin/ui/Virus_ArpEditor.h @@ -56,7 +56,8 @@ private: juce::Slider m_outputBalance; juce::Slider m_transpose; juce::ComboBox m_keyMode, m_secondaryOutput; - juce::ComboBox m_bendUp, m_bendDown, m_bendScale, m_smoothMode, m_cat1, m_cat2; + juce::ComboBox m_bendScale, m_smoothMode, m_cat1, m_cat2; + juce::ComboBox m_bendUp, m_bendDown; } m_patchSettings; std::unique_ptr<juce::Drawable> m_background; diff --git a/source/jucePlugin/ui/Virus_Buttons.cpp b/source/jucePlugin/ui/Virus_Buttons.cpp @@ -106,12 +106,10 @@ namespace Buttons Buttons::PartSelectButton::PartSelectButton() : DrawableButton("PartSelectButton", DrawableButton::ButtonStyle::ImageRaw) { - auto normal = - Drawable::createFromImageData(BinaryData::part_select_btn_39x72_png, BinaryData::part_select_btn_39x72_pngSize); - auto pressed = normal->createCopy(); - pressed->setOriginWithOriginalSize({0, -36}); + auto on = + Drawable::createFromImageData(BinaryData::part_select_btn_36x36_png, BinaryData::part_select_btn_36x36_pngSize); setColour(DrawableButton::ColourIds::backgroundColourId, Colours::transparentBlack); setColour(DrawableButton::ColourIds::backgroundOnColourId, Colours::transparentBlack); - setImages(normal.get(), nullptr, pressed.get(), nullptr, pressed.get(), nullptr, normal.get()); + setImages(nullptr, nullptr, on.get(), nullptr, on.get(), nullptr, nullptr); } }; // namespace Buttons 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 +} // namespace Buttons +\ No newline at end of file diff --git a/source/jucePlugin/ui/Virus_FxEditor.cpp b/source/jucePlugin/ui/Virus_FxEditor.cpp @@ -135,6 +135,10 @@ FxEditor::EnvelopeFollower::EnvelopeFollower(VirusParameterBinding &_parameterBi addAndMakeVisible(m_input); m_input.setBounds(17, 37, comboBoxWidth, comboBoxHeight); + _parameterBinding.bind(m_input, Virus::Param_InputFollowMode); + _parameterBinding.bind(m_attack, Virus::Param_FilterEnvAttack); + _parameterBinding.bind(m_release, Virus::Param_FilterEnvDecay); + _parameterBinding.bind(m_gain, Virus::Param_FilterEnvSustain); } FxEditor::Punch::Punch(VirusParameterBinding &_parameterBinding) diff --git a/source/jucePlugin/ui/Virus_LfoEditor.cpp b/source/jucePlugin/ui/Virus_LfoEditor.cpp @@ -70,14 +70,9 @@ LfoEditor::LfoTwoOneShared::LfoTwoOneShared(VirusParameterBinding& _parameterBin m_link.setBounds(293, 8, 36, 12); m_assignDest.setBounds(393, 122, comboBoxWidth, comboBoxHeight); - //_parameterBinding.bind(m_rate, Virus::Param_Lfo1Rate); - //_parameterBinding.bind(m_keytrack, Virus::Param_Lfo1Keyfollow); _parameterBinding.bind(m_contour, _lfoIndex == 0 ? Virus::Param_Lfo1Symmetry : Virus::Param_Lfo2Symmetry); _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_assignDest, Virus::Param_Lfo1AssignDest); } LfoEditor::LfoOne::LfoOne(VirusParameterBinding& _parameterBinding) : LfoTwoOneShared(_parameterBinding, 0) diff --git a/source/jucePlugin/ui/Virus_LookAndFeel.cpp b/source/jucePlugin/ui/Virus_LookAndFeel.cpp @@ -39,6 +39,9 @@ namespace Virus case KnobStyle::GENERIC_BLUE: knob = m_genBlue.get(); break; + case KnobStyle::GENERIC_MULTI: + knob = m_multi.get(); + break; case KnobStyle::GENERIC: default: knob = m_genKnob.get(); @@ -49,7 +52,13 @@ namespace Virus // g.fillAll (Colours::pink.withAlpha (0.4f)); const auto step = roundToInt(m_knobImageSteps.convertFrom0to1(sliderPosProportional)); // take relevant pos - knob->setOriginWithOriginalSize({0.0f, -70.0f * step}); + if (knob == m_multi.get()) { + knob->setOriginWithOriginalSize({0.0f, -18.0f * step}); + } + else { + knob->setOriginWithOriginalSize({0.0f, -70.0f * step}); + } + } // this won't support scaling! knob->drawAt(g, x, y, 1.0f); diff --git a/source/jucePlugin/ui/Virus_LookAndFeel.h b/source/jucePlugin/ui/Virus_LookAndFeel.h @@ -16,7 +16,8 @@ namespace Virus GENERIC, GENERIC_POL, GENERIC_BLUE, - GENERIC_RED + GENERIC_RED, + GENERIC_MULTI }; static const char *KnobStyleProp; diff --git a/source/jucePlugin/ui/Virus_OscEditor.cpp b/source/jucePlugin/ui/Virus_OscEditor.cpp @@ -26,6 +26,8 @@ OscEditor::OscEditor(VirusParameterBinding& _parameterBinding) addAndMakeVisible(m_filterEnv); addAndMakeVisible(m_ampEnv); addAndMakeVisible(m_oscSync); + + _parameterBinding.bind(m_oscSync, Virus::Param_Osc2Sync); } void OscEditor::resized() diff --git a/source/jucePlugin/ui/Virus_Parts.cpp b/source/jucePlugin/ui/Virus_Parts.cpp @@ -0,0 +1,11 @@ +#include "Virus_Parts.h" +#include "BinaryData.h" +#include "Ui_Utils.h" +#include "../VirusParameterBinding.h" + +using namespace juce; + +Parts::Parts(VirusParameterBinding & _parameterBinding, Virus::Controller& _controller) : m_parameterBinding(_parameterBinding), m_controller(_controller) +{ + +} +\ No newline at end of file diff --git a/source/jucePlugin/ui/Virus_Parts.h b/source/jucePlugin/ui/Virus_Parts.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../PluginProcessor.h" +#include "Virus_Buttons.h" +#include <juce_gui_extra/juce_gui_extra.h> +#include "../VirusController.h" +class VirusParameterBinding; + +class Parts : public juce::Component +{ + public: + Parts(VirusParameterBinding& _parameterBinding, Virus::Controller& _controller); + private: + Virus::Controller &m_controller; + VirusParameterBinding &m_parameterBinding; +}; +\ No newline at end of file diff --git a/source/jucePlugin/ui/Virus_PatchBrowser.cpp b/source/jucePlugin/ui/Virus_PatchBrowser.cpp @@ -75,6 +75,7 @@ void PatchBrowser::fileClicked(const juce::File &file, const juce::MouseEvent &e } } m_patchList.updateContent(); + m_patchList.deselectAllRows(); m_patchList.repaint(); // force repaint since row number doesn't often change } else if (ext == ".mid" || ext == ".midi") @@ -181,7 +182,7 @@ void PatchBrowser::paintCell(Graphics &g, int rowNumber, int columnId, int width void PatchBrowser::selectedRowsChanged(int lastRowSelected) { auto idx = m_patchList.getSelectedRow(); uint8_t syxHeader[9] = {0xF0, 0x00, 0x20, 0x33, 0x01, 0x00, 0x10, 0x00, 0x00}; - syxHeader[8] = m_controller.isMultiMode() ? m_parameterBinding.m_part : virusLib::ProgramType::SINGLE; // set edit buffer + 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]; @@ -205,3 +206,10 @@ void PatchBrowser::selectedRowsChanged(int lastRowSelected) { m_controller.sendSysEx(syx); // send to edit buffer m_controller.parseMessage(syx); // update ui } + +void PatchBrowser::cellDoubleClicked(int rowNumber, int columnId, const juce::MouseEvent &) +{ + if(rowNumber == m_patchList.getSelectedRow()) { + selectedRowsChanged(0); + } +} diff --git a/source/jucePlugin/ui/Virus_PatchBrowser.h b/source/jucePlugin/ui/Virus_PatchBrowser.h @@ -52,4 +52,5 @@ private: bool rowIsSelected) override; virtual void selectedRowsChanged(int lastRowSelected) override; + virtual void cellDoubleClicked (int rowNumber, int columnId, const juce::MouseEvent &) override; }; diff --git a/source/jucePlugin/version.h b/source/jucePlugin/version.h @@ -1,4 +1,4 @@ #pragma once -static constexpr const char* const g_pluginVersionString = "1.2.1"; -static constexpr uint32_t g_pluginVersion = 121; +static constexpr const char* const g_pluginVersionString = "1.2.2"; +static constexpr uint32_t g_pluginVersion = 122; diff --git a/source/virusLib/microcontroller.cpp b/source/virusLib/microcontroller.cpp @@ -903,7 +903,10 @@ void Microcontroller::applyToSingleEditBuffer(TPreset& _single, const Page _page void Microcontroller::applyToMultiEditBuffer(const uint8_t _part, const uint8_t _param, const uint8_t _value) { - // TODO: This is horrible. We need to remap everything + // remap page C parameters into the multi edit buffer + if (_param >= PART_MIDI_CHANNEL && _param <= PART_OUTPUT_SELECT) { + m_multiEditBuffer[MD_PART_MIDI_CHANNEL + ((_param-PART_MIDI_CHANNEL)*16) + _part] = _value; + } } }