microcontroller.cpp (44905B)
1 #include <vector> 2 #include <thread> 3 #include <cstring> // memcpy 4 #include <cmath> // floor/abs 5 6 #include "microcontroller.h" 7 8 #include "dspSingle.h" 9 #include "frontpanelState.h" 10 #include "synthLib/midiTypes.h" 11 12 using namespace dsp56k; 13 using namespace synthLib; 14 15 namespace virusLib 16 { 17 18 constexpr virusLib::PlayMode g_defaultPlayMode = virusLib::PlayModeSingle; 19 20 constexpr uint32_t g_sysexPresetHeaderSize = 9; 21 constexpr uint32_t g_sysexPresetFooterSize = 2; // checksum, f7 22 23 constexpr uint32_t g_singleRamBankCount = 2; 24 25 const std::set<uint8_t> g_pageA = {0x05, 0x0A, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 26 0x1E, 0x1F, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 27 0x2E, 0x2F, 0x30, 0x31, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 28 0x3E, 0x3F, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 29 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5D, 0x5E, 0x61, 30 0x62, 0x63, 0x64, 0x65, 0x66, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x7B}; 31 32 const std::set<uint8_t> g_pageB = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x11, 33 0x12, 0x13, 0x15, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 34 0x26, 0x27, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x36, 0x37, 35 0x38, 0x39, 0x3A, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 36 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x54, 0x55, 37 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 38 0x64, 0x65, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x7B, 0x7C}; 39 40 constexpr uint8_t g_pageC_global[] = {45, 63, 64, 65, 66, 67, 68, 69, 70, 85, 86, 87, 90, 91, 41 92, 93, 94, 95, 96, 97, 98, 99, 105, 106, 110, 111, 112, 113, 42 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 127}; 43 44 Microcontroller::Microcontroller(DspSingle& _dsp, const ROMFile& _romFile, bool _useEsaiBasedMidiTiming) : m_rom(_romFile) 45 { 46 if(!_romFile.isValid()) 47 return; 48 49 m_hdi08TxParsers.reserve(2); 50 m_midiQueues.reserve(2); 51 52 addDSP(_dsp, _useEsaiBasedMidiTiming); 53 54 m_globalSettings.fill(0xffffffff); 55 56 for(size_t i=0; i<m_multis.size(); ++i) 57 m_rom.getMulti(0, m_multis[i]); 58 59 m_multiEditBuffer = m_multis.front(); 60 61 bool failed = false; 62 63 // read all singles from ROM and copy first ROM banks to RAM banks 64 for(uint32_t b=0; b<128 && !failed; ++b) 65 { 66 std::vector<TPreset> singles; 67 68 const auto bank = b >= g_singleRamBankCount ? b - g_singleRamBankCount : b; 69 70 for(uint32_t p=0; p<m_rom.getPresetsPerBank(); ++p) 71 { 72 TPreset single; 73 if(!m_rom.getSingle(bank, p, single)) 74 break; 75 76 if(ROMFile::getSingleName(single).size() != 10) 77 { 78 failed = true; 79 break; 80 } 81 82 singles.emplace_back(single); 83 } 84 85 if(!singles.empty()) 86 m_singles.emplace_back(std::move(singles)); 87 } 88 89 if(!m_singles.empty()) 90 { 91 const auto& singles = m_singles[0]; 92 93 if(!singles.empty()) 94 { 95 m_singleEditBuffer = singles[0]; 96 97 for(auto i=0; i<static_cast<int>(std::min(singles.size(), m_singleEditBuffers.size())); ++i) 98 m_singleEditBuffers[i] = singles[i]; 99 } 100 } 101 102 m_pendingSysexInput.reserve(64); 103 } 104 105 void Microcontroller::sendInitControlCommands(uint8_t _masterVolume) 106 { 107 writeHostBitsWithWait(0, 1); 108 // const std::vector<TWord> magic = { 0xf4f473, 0xf4f46e, 0xf4f46f, 0xf4f477 }; // snow 109 // const std::vector<TWord> magic = { 0xf4f453, 0xf4f44e, 0xf4f44f, 0xf4f457 }; // SNOW 110 // const std::vector<TWord> magic = { 0xf4f454, 0xf4f449, 0xf4f453, 0xf4f44e, 0xf4f44f, 0xf4f457 }; // TISNOW 111 // const std::vector<TWord> magic = { 0xf4f473, 0x407f01, 0xf4f473, 0x401000, 0xf4f46e, 0x407f01, 0xf4f46e, 0x401000, 0xf4f46f, 0x407f01, 0xf4f46f, 0x401000, 0xf4f477, 0x407f01, 0xf4f477, 0x401000 }; 112 // const std::vector<TWord> magic = { 0xf4f473, 0x407f00, 0xf4f46e, 0x407f01, 0xf4f46f, 0x407f02, 0xf4f477, 0x407f03 }; 113 // m_hdi08.writeRX(magic); 114 115 LOG("Sending Init Control Commands"); 116 117 if(m_rom.isTIFamily()) 118 { 119 const std::vector<TWord> initCodeDS = 120 { 121 0xF4F473, 0x407F00, 122 0xF4F473, 0x401000, // Samplerate 44100 Hz 123 // 0xF47555, 0x104000, 0x0C0104, 0x000319, 0x007F00, 0x00407F, 0x000000, 0x00007E, 0x003728, 0x607F62, 0x3E3420, 0x190040, 0x406000, 0x663100, 0x402300, 0x401509, 0x2F233E, 0x286B6A, 0x400600, 0x010200, 0x384719, 0x137F00, 0x7F7F40, 0x150000, 0x006501, 0x010057, 0x000040, 0x404040, 0x4B5402, 0x010040, 0x000040, 0x404040, 0x407B01, 0x400400, 0x000269, 0x7F4000, 0x01017F, 0x001060, 0x126801, 0x00011B, 0x7F5010, 0x0C0140, 0x000000, 0x010000, 0x000040, 0x000000, 0x004000, 0x610100, 0x000100, 0x4B0000, 0x390400, 0x000000, 0x7F0000, 0x01423E, 0x010001, 0x000124, 0x000040, 0x000000, 0x000040, 0x40282B, 0x554040, 0x404049, 0x2C4060, 0x4D4040, 0x004040, 0x401603, 0x03107F, 0x144900, 0x004002, 0x490F19, 0x2B186A, 0x184814, 0x010000, 0x410000, 0x7F607F, 0x004864, 0x334040, 0x282000, 0x000000, 0x056556, 0x071845, 0x023C00, 0x202054, 0x202049, 0x202042, 0x430001, 0x000100, 0x010001, 0x440354, 0x373062, 0x000000, 0x400304, 0x020000, 0x000000, 0x7F4040, 0x7F7F40, 0x000005, 0x000200, 0x000000, 0x010000, 0x000000, 0x004000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x400000, 0x000000, 0x000000, 0x007F7F, 0x400000, 0x000000, 0x144600, 0x404614, 0x460040, 0x460135, 0x004000, 0x400040, 0x004000, 0x400040, 0x0B2903, 0x400000, 0x000000, 0x000000, 0x010002, 0x000000, 0x010000, 0x00001F, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x02697F, 0x400001, 0x000006, 124 0xF4F473, 0x401000, // Samplerate 44100 Hz 125 0xF00020, 0x330110, 0x734000, 0x00F700, 126 0xF00020, 0x330110, 0x734009, 0x02F702, // USB Mode = 3 out 1 in 127 0xF00020, 0x330110, 0x73400E, 0x00F700, // Set DSP clock base to $0 = 133 Mhz ($1 = 153 MHz) 128 0xF00020, 0x330110, 0x73406D, 0x64F764, // DSP clock adjustment in percent (roughly), default $64 = 100%, max $79 = 121% 129 0xF00020, 0x330110, 0x73400D, 0x00F700, // ?? 130 0xF00020, 0x330110, 0x734010, 0x00F700, // Samplerate = 44100 Hz 131 0xF00020, 0x330110, 0x734019, 0x01F701, // EQ = Enable 132 0xF00020, 0x330110, 0x73401A, 0x01F701, // Arp = Enable 133 0xF00020, 0x330110, 0x73401B, 0x01F701, // Delay = Enable 134 0xF00020, 0x330110, 0x73401C, 0x01F701, // Reverb = Enable 135 0xF00020, 0x330110, 0x73401D, 0x00F700, // Analog Input Phono Mode = off 136 0xF00020, 0x330110, 0x73402D, 0x00F700, // Second Output Select = 0 137 0xF00020, 0x330110, 0x734032, 0x6EF76E, // BPM LED Brightness Ratio = $6e 138 0xF00020, 0x330110, 0x734033, 0x50F750, // LED Brightness = $50 139 0xF00020, 0x330110, 0x734034, 0x7fF77f, // Logo Groove = $7f 140 0xF00020, 0x330110, 0x734035, 0x40F740, // Random Patch Generator Depth = $40 141 0xF00020, 0x330110, 0x734036, 0x0CF70C, // Random Patch Generator Amount = $54 142 0xF00020, 0x330110, 0x73403B, 0x01F701, // USB Output Midi Data Cable Number = 1 143 0xF00020, 0x330110, 0x73403C, 0x01F701, // USB Output Panel Data Cable Number = 1 144 0xF00020, 0x330110, 0x73403E, 0x40F740, // Keyboard Param Velocity Curve = $40 145 0xF00020, 0x330110, 0x734040, 0x01F701, // Keyboard Param Local On = On 146 0xF00020, 0x330110, 0x734041, 0x00F700, // Keyboard Param Channel Mode = 0 147 0xF00020, 0x330110, 0x734042, 0x40F740, // Keyboard Param Transpose = $40 148 0xF00020, 0x330110, 0x734043, 0x01F701, // Keyboard Param Modwheel = 1 149 0xF00020, 0x330110, 0x734044, 0x40F740, // Keyboard Param Hold Pedal = $40 150 0xF00020, 0x330110, 0x734045, 0x00F700, // Keyboard Param Pedal 2 Mode = 0 151 0xF00020, 0x330110, 0x734046, 0x40F740, // Keyboard Param Pressure Sensitivity = $40 152 0xF00020, 0x330110, 0x73404C, 0x00F700, // Pure Tuning = 0 153 0xF00020, 0x330110, 0x734057, 0x01F701, // Midi Volume Enable = On 154 0xF00020, 0x330110, 0x73405A, 0x00F700, // Input Thru Level = 0 155 0xF00020, 0x330110, 0x73405B, 0x00F700, // Input Boost = 0 156 0xF00020, 0x330110, 0x73405C, 0x40F740, // Master Tune = +/- 0 157 0xF00020, 0x330110, 0x73405D, 0x10F710, // device ID $10 = omni 158 0xF00020, 0x330110, 0x73405E, 0x01F701, // Midi Control Low Page = 1 = allow midi CC 159 0xF00020, 0x330110, 0x73405F, 0x00F700, // Midi Control High Page = 0 = Do NOT allow Poly Pressure 160 0xF00020, 0x330110, 0x734060, 0x00F700, // Midi Arp Send = 0 = off 161 0xF00020, 0x330110, 0x73406A, 0x01F701, // Midi Clock RX = 1 = enabled 162 0xF00020, 0x330110, 0x73406E, 0x00F700, // Soft Knob Config Mode 1 = 0 163 0xF00020, 0x330110, 0x73406F, 0x00F700, // Soft Knob Config Mode 2 = 0 164 0xF00020, 0x330110, 0x734070, 0x00F700, // Soft Knob Config Dest 1 = 0 165 0xF00020, 0x330110, 0x734071, 0x00F700, // Soft Knob Config Dest 2 = 0 166 0xF00020, 0x330110, 0x734072, 0x00F700, // Soft Knob Config Mode 3 = 0 167 // 0xF0FFFF, 0x00FFFF, 0x20FFFF, 0x33FFFF, 0x01FFFF, 0x10FFFF, 0x73FFFF, 0x01FFFF, 0x10FFFF, 0x00FFFF, 0xF7FFFF, // parameter $10 for Part 1 = 0 168 0xF00020, 0x330110, 0x734073, 0x00F700, // Soft Knob Config Dest 3 = 0 169 0xF00020, 0x330110, 0x734079, 0x01F701, // Panel Destination = 1 170 0xF00020, 0x330110, 0x73407C, 0x00F700, // Global Channel = 0 171 0xF00020, 0x330110, 0x73407D, 0x02F702, // LED Mode = 2 172 0xF00020, 0x330110, 0x73407F, 0x63F763, // Master Volume = 99 173 // 0xF47555, 0x104000, 0x0C0104, 0x000319, 0x007F00, 0x00407F, 0x000000, 0x00007E, 0x003728, 0x607F62, 0x3E3420, 0x190040, 0x406000, 0x663100, 0x402300, 0x401509, 0x2F233E, 0x286B6A, 0x400600, 0x010200, 0x384719, 0x137F00, 0x7F7F40, 0x150000, 0x006501, 0x010057, 0x000040, 0x404040, 0x4B5402, 0x010040, 0x000040, 0x404040, 0x407B01, 0x400400, 0x000269, 0x7F4000, 0x01017F, 0x001060, 0x126801, 0x00011B, 0x7F5010, 0x0C0140, 0x000000, 0x010000, 0x000040, 0x000000, 0x004000, 0x610100, 0x000100, 0x4B0000, 0x390400, 0x000000, 0x7F0000, 0x01423E, 0x010001, 0x000124, 0x000040, 0x000000, 0x000040, 0x40282B, 0x554040, 0x404049, 0x2C4060, 0x4D4040, 0x004040, 0x401603, 0x03107F, 0x144900, 0x004002, 0x490F19, 0x2B186A, 0x184814, 0x010000, 0x410000, 0x7F607F, 0x004864, 0x334040, 0x282000, 0x000000, 0x056556, 0x071845, 0x023C00, 0x202054, 0x202049, 0x202042, 0x430001, 0x000100, 0x010001, 0x440354, 0x373062, 0x000000, 0x400304, 0x020000, 0x000000, 0x7F4040, 0x7F7F40, 0x000005, 0x000200, 0x000000, 0x010000, 0x000000, 0x004000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x400000, 0x000000, 0x000000, 0x007F7F, 0x400000, 0x000000, 0x144600, 0x404614, 0x460040, 0x460135, 0x004000, 0x400040, 0x004000, 0x400040, 0x0B2903, 0x400000, 0x000000, 0x000000, 0x010002, 0x000000, 0x010000, 0x00001F, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x406401, 0x406400, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x02697F, 0x400001, 0x000006, 174 0xF4F473, 0x401000, // Samplerate 44100 Hz 175 // 0xF4F473, 0x401001, // Samplerate 48000 Hz 176 }; 177 178 m_hdi08.writeRX(initCodeDS); 179 180 #if 0 181 constexpr uint8_t prts = 0x4f; 182 183 enum class Output : uint8_t 184 { 185 Out1L, Out1, Out1R, 186 Out2L, Out2, Out2R, 187 Out3L, Out3, Out3R, 188 Usb1L, Usb1, Usb1R, 189 Usb2L, Usb2, Usb2R, 190 Usb3L, Usb3, Usb3R 191 }; 192 193 constexpr auto oa = static_cast<uint8_t>(Output::Usb1); 194 constexpr auto ob = static_cast<uint8_t>(Output::Usb2); 195 constexpr auto oc = static_cast<uint8_t>(Output::Usb3); 196 197 constexpr uint8_t multi[] = 198 { 199 0x02,0x01,0x00,0x01,0x49,0x6e,0x69,0x74,0x20,0x4d,0x75,0x6c,0x74,0x69,0x00,0x39, // Internal/"Init Multi"/Clock Tempo 200 0x01,0x3c,0x00,0x10,0x00,0x01,0x01,0x00,0x40,0x40,0x40,0x40,0x40,0x00,0x40,0x40, // Delay/Internal 201 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Bank Number 202 0x00,0x00,0x00,0x00,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, // Program Number 203 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, // Midi Channel 204 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Low Key 205 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, // High Key 206 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, // Transpose 207 0x40,0x42,0x43,0x41,0x47,0x42,0x46,0x41,0x48,0x46,0x44,0x40,0x40,0x40,0x40,0x40, // Detune 208 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, // Part Volume 209 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Midi Volume Init 210 oa ,oa ,ob ,ob ,oc ,oc ,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, // Output Select 211 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Effect Send 212 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Internal 213 0x41,0x46,0x40,0x48,0x41,0x49,0x47,0x41,0x42,0x47,0x40,0x45,0x41,0x49,0x47,0x46, // Internal 214 prts,prts,prts,prts,prts,prts,prts,prts,prts,prts,prts,prts,prts,prts,prts,prts // Part State 215 }; 216 217 TPreset data; 218 memcpy(&data[0], multi, std::size(multi)); 219 220 sendControlCommand(PLAY_MODE, PlayModeMulti); 221 222 const auto words = presetToDSPWords(data, true); 223 224 sendPreset(0, words, true); 225 #endif 226 } 227 // else 228 { 229 sendControlCommand(MIDI_CLOCK_RX, 0x1); // Enable MIDI clock receive 230 sendControlCommand(GLOBAL_CHANNEL, 0x0); // Set global midi channel to 0 231 sendControlCommand(MIDI_CONTROL_LOW_PAGE, 0x1); // Enable midi CC to edit parameters on page A 232 sendControlCommand(MIDI_CONTROL_HIGH_PAGE, 0x0); // Disable poly pressure to edit parameters on page B 233 sendControlCommand(MASTER_VOLUME, _masterVolume <= 127 ? _masterVolume : 92); // Set master volume to 92, this matches the Virus TI in USB mode 234 sendControlCommand(MASTER_TUNE, 64); // Set master tune to 0 235 sendControlCommand(DEVICE_ID, OMNI_DEVICE_ID); // Set device ID to Omni 236 } 237 } 238 239 void Microcontroller::createDefaultState() 240 { 241 sendControlCommand(PLAY_MODE, g_defaultPlayMode); 242 243 if constexpr (g_defaultPlayMode == PlayModeSingle) 244 writeSingle(BankNumber::EditBuffer, SINGLE, m_singleEditBuffer); 245 else 246 loadMulti(0, m_multiEditBuffer); 247 } 248 249 void Microcontroller::writeHostBitsWithWait(const uint8_t flag0, const uint8_t flag1) 250 { 251 m_hdi08.writeHostFlags(flag0, flag1); 252 } 253 254 bool Microcontroller::sendPreset(const uint8_t program, const TPreset& preset, const bool isMulti) 255 { 256 if(!isMulti && !isValid(preset)) 257 return false; 258 259 std::lock_guard lock(m_mutex); 260 261 if(m_loadingState || waitingForPresetReceiveConfirmation()) 262 { 263 // if we write a multi or a multi mode single, remove a pending single for single mode 264 // If we write a single-mode single, remove all multi-related pending writes 265 const auto multiRelated = isMulti || program != SINGLE; 266 267 for (auto it = m_pendingPresetWrites.begin(); it != m_pendingPresetWrites.end();) 268 { 269 const auto& pendingPreset = *it; 270 271 const auto pendingIsMultiRelated = pendingPreset.isMulti || pendingPreset.program != SINGLE; 272 273 if (multiRelated != pendingIsMultiRelated) 274 it = m_pendingPresetWrites.erase(it); 275 else 276 ++it; 277 } 278 279 for(auto it = m_pendingPresetWrites.begin(); it != m_pendingPresetWrites.end();) 280 { 281 const auto& pendingPreset = *it; 282 if (pendingPreset.isMulti == isMulti && pendingPreset.program == program) 283 it = m_pendingPresetWrites.erase(it); 284 else 285 ++it; 286 } 287 288 m_pendingPresetWrites.emplace_back(SPendingPresetWrite{program, isMulti, preset}); 289 290 return true; 291 } 292 293 receiveUpgradedPreset(); 294 295 if(isMulti) 296 { 297 m_multiEditBuffer = preset; 298 299 m_globalSettings[PLAY_MODE] = PlayModeMulti; 300 } 301 else 302 { 303 if(program == SINGLE) 304 { 305 m_globalSettings[PLAY_MODE] = PlayModeSingle; 306 m_singleEditBuffer = preset; 307 } 308 else if(program < m_singleEditBuffers.size()) 309 { 310 if(program >= getPartCount()) 311 return false; 312 313 m_singleEditBuffers[program] = preset; 314 } 315 } 316 317 writeHostBitsWithWait(0,1); 318 // Send header 319 TWord buf[] = {0xf47555, static_cast<TWord>(isMulti ? 0x110000 : 0x100000)}; 320 buf[1] = buf[1] | (program << 8); 321 m_hdi08.writeRX(buf, 2); 322 323 m_hdi08.writeRX(presetToDSPWords(preset, isMulti)); 324 325 LOG("Send to DSP: " << (isMulti ? "Multi" : "Single") << " to program " << static_cast<int>(program)); 326 327 for (auto& parser : m_hdi08TxParsers) 328 parser.waitForPreset(isMulti ? m_rom.getMultiPresetSize() : m_rom.getSinglePresetSize()); 329 330 m_sentPresetProgram = program; 331 m_sentPresetIsMulti = isMulti; 332 333 return true; 334 } 335 336 void Microcontroller::sendControlCommand(const ControlCommand _command, const uint8_t _value) 337 { 338 send(globalSettingsPage(), 0x0, _command, _value); 339 } 340 341 void Microcontroller::setSamplerate(const float _samplerate) 342 { 343 const auto sr = static_cast<int>(std::floor(_samplerate + 0.5f)); 344 345 /* 346 0 = 44100 Hz @ EXTAL 11289600 Hz (44100 * 256) 347 1 = 48000 Hz @ EXTAL 12288000 Hz (48000 * 256) 348 2 = 44100 Hz @ ^^ 349 3 = 32000 Hz @ ^^ 350 4 = 96000 Hz @ ^^ 351 5 = 88200 Hz @ ^^ 352 6 = 64000 Hz @ ^^ 353 */ 354 355 TWord v; 356 357 switch (sr) 358 { 359 default: 360 case 44100: v = 0; break; 361 case 48000: v = 1; break; 362 case 32000: v = 3; break; 363 case 96000: v = 4; break; 364 case 88200: v = 5; break; 365 case 64000: v = 6; break; 366 } 367 368 std::lock_guard lock(m_mutex); 369 m_hdi08.writeRX({0xF4F473, 0x401000 + v}); 370 } 371 372 uint32_t Microcontroller::getPartCount() const 373 { 374 if(m_rom.getModel() == DeviceModel::Snow) 375 return 4; 376 return 16; 377 } 378 379 uint8_t Microcontroller::getPartMidiChannel(const uint8_t _part) const 380 { 381 return m_multiEditBuffer[MD_PART_MIDI_CHANNEL + _part]; 382 } 383 384 bool Microcontroller::isPolyPressureForPageBEnabled() const 385 { 386 return m_globalSettings[MIDI_CONTROL_HIGH_PAGE] == 1; 387 } 388 389 bool Microcontroller::send(const Page _page, const uint8_t _part, const uint8_t _param, const uint8_t _value) 390 { 391 std::lock_guard lock(m_mutex); 392 393 if(_page == globalSettingsPage()) 394 { 395 if(m_globalSettings[_param] == _value) 396 return true; 397 m_globalSettings[_param] = _value; 398 } 399 400 writeHostBitsWithWait(0,1); 401 402 TWord buf[] = {0xf4f400, 0x0}; 403 buf[0] = buf[0] | _page; 404 buf[1] = (_part << 16) | (_param << 8) | _value; 405 m_hdi08.writeRX(buf, 2); 406 407 // LOG("Send command, page " << (int)_page << ", part " << (int)_part << ", param " << (int)_param << ", value " << (int)_value); 408 409 return true; 410 } 411 412 bool Microcontroller::sendMIDI(const SMidiEvent& _ev, FrontpanelState* _fpState/* = nullptr*/) 413 { 414 const uint8_t channel = _ev.a & 0x0f; 415 const uint8_t status = _ev.a & 0xf0; 416 417 const auto singleMode = m_globalSettings[PLAY_MODE] == PlayModeSingle; 418 419 if(status != 0xf0 && singleMode && channel != m_globalSettings[GLOBAL_CHANNEL]) 420 return true; 421 422 switch (status) 423 { 424 case M_PROGRAMCHANGE: 425 if(singleMode) 426 return partProgramChange(SINGLE, _ev.b); 427 428 for(uint32_t p=0; p<getPartCount(); ++p) 429 { 430 if(channel == getPartMidiChannel(static_cast<uint8_t>(p))) 431 partProgramChange(static_cast<uint8_t>(p), _ev.b); 432 } 433 return true; 434 case M_CONTROLCHANGE: 435 switch(_ev.b) 436 { 437 case MC_BANKSELECTLSB: 438 { 439 if(singleMode) 440 { 441 partBankSelect(SINGLE, _ev.c, false); 442 } 443 else 444 { 445 for(uint32_t p=0; p<getPartCount(); ++p) 446 { 447 if(channel == getPartMidiChannel(static_cast<uint8_t>(p))) 448 partBankSelect(static_cast<uint8_t>(p), _ev.c, false); 449 } 450 } 451 } 452 return true; 453 default: 454 if(g_pageA.find(_ev.b) != g_pageA.end()) 455 applyToSingleEditBuffer(PAGE_A, singleMode ? SINGLE : channel, _ev.b, _ev.c); 456 break; 457 } 458 break; 459 case M_POLYPRESSURE: 460 if(isPolyPressureForPageBEnabled()) 461 { 462 if(g_pageB.find(_ev.b) != g_pageB.end()) 463 { 464 applyToSingleEditBuffer(PAGE_B, singleMode ? SINGLE : channel, _ev.b, _ev.c); 465 auto e = _ev; 466 e.source = MidiEventSource::Plugin; 467 m_midiOutput.push_back(e); 468 } 469 } 470 break; 471 default: 472 break; 473 } 474 475 for (auto& midiQueue : m_midiQueues) 476 midiQueue.add(_ev); 477 478 if(status < 0xf0 && _fpState) 479 { 480 for(uint32_t p=0; p<getPartCount(); ++p) 481 { 482 if(channel == getPartMidiChannel(static_cast<uint8_t>(p))) 483 _fpState->m_midiEventReceived[p] = true; 484 } 485 } 486 487 return true; 488 } 489 490 bool Microcontroller::sendSysex(const std::vector<uint8_t>& _data, std::vector<SMidiEvent>& _responses, const MidiEventSource _source) 491 { 492 if (_data.size() < 7) 493 return true; // invalid sysex or not directed to us 494 495 const auto manufacturerA = _data[1]; 496 const auto manufacturerB = _data[2]; 497 const auto manufacturerC = _data[3]; 498 const auto productId = _data[4]; 499 const auto deviceId = _data[5]; 500 const auto cmd = _data[6]; 501 502 if (deviceId != m_globalSettings[DEVICE_ID] && deviceId != OMNI_DEVICE_ID && m_globalSettings[DEVICE_ID] != OMNI_DEVICE_ID) 503 { 504 // ignore messages intended for a different device but allow omni requests 505 return true; 506 } 507 508 auto buildResponseHeader = [&](SMidiEvent& _ev) 509 { 510 auto& response = _ev.sysex; 511 512 response.reserve(1024); 513 514 response.push_back(M_STARTOFSYSEX); 515 response.push_back(manufacturerA); 516 response.push_back(manufacturerB); 517 response.push_back(manufacturerC); 518 response.push_back(productId); 519 response.push_back(deviceId); 520 }; 521 522 auto buildPresetResponse = [&](const uint8_t _type, const BankNumber _bank, const uint8_t _program, const TPreset& _dump) 523 { 524 if(!isValid(_dump)) 525 return; 526 527 SMidiEvent ev(_source); 528 529 auto& response = ev.sysex; 530 531 buildResponseHeader(ev); 532 533 response.push_back(_type); 534 response.push_back(toMidiByte(_bank)); 535 response.push_back(_program); 536 537 const auto size = _type == DUMP_SINGLE ? m_rom.getSinglePresetSize() : m_rom.getMultiPresetSize(); 538 539 const auto modelABCsize = ROMFile::getSinglePresetSize(DeviceModel::ABC); 540 541 for(size_t i=0; i<modelABCsize; ++i) 542 response.push_back(_dump[i]); 543 544 // checksum for ABC models comes after 256 bytes of preset data 545 response.push_back(calcChecksum(response)); 546 547 if (size > modelABCsize) 548 { 549 for (size_t i = modelABCsize; i < size; ++i) 550 response.push_back(_dump[i]); 551 552 // Second checksum for D model: That checksum is to be calculated over the whole preset data, including the ABC checksum 553 response.push_back(calcChecksum(response)); 554 } 555 556 response.push_back(M_ENDOFSYSEX); 557 558 _responses.emplace_back(std::move(ev)); 559 }; 560 561 auto buildSingleResponse = [&](const BankNumber _bank, const uint8_t _program) 562 { 563 TPreset dump; 564 const auto res = requestSingle(_bank, _program, dump); 565 if(res) 566 buildPresetResponse(DUMP_SINGLE, _bank, _program, dump); 567 }; 568 569 auto buildMultiResponse = [&](const BankNumber _bank, const uint8_t _program) 570 { 571 TPreset dump; 572 const auto res = requestMulti(_bank, _program, dump); 573 if(res) 574 buildPresetResponse(DUMP_MULTI, _bank, _program, dump); 575 }; 576 577 auto buildSingleBankResponse = [&](const BankNumber _bank) 578 { 579 if (_bank == BankNumber::EditBuffer) 580 return; 581 582 const auto bankIndex = toArrayIndex(_bank); 583 584 if(bankIndex < m_singles.size()) 585 { 586 // eat this, host, whoever you are. 128 single packets 587 for(uint8_t i=0; i<m_singles[bankIndex].size(); ++i) 588 { 589 TPreset data; 590 const auto res = requestSingle(_bank, i, data); 591 buildPresetResponse(DUMP_SINGLE, _bank, i, data); 592 } 593 } 594 }; 595 596 auto buildMultiBankResponse = [&](const BankNumber _bank) 597 { 598 if(_bank == BankNumber::A) 599 { 600 // eat this, host, whoever you are. 128 multi packets 601 for(uint8_t i=0; i<m_rom.getPresetsPerBank(); ++i) 602 { 603 TPreset data; 604 const auto res = requestMulti(_bank, i, data); 605 buildPresetResponse(DUMP_MULTI, _bank, i, data); 606 } 607 } 608 }; 609 610 auto buildGlobalResponse = [&](const uint8_t _param) 611 { 612 SMidiEvent ev(_source); 613 auto& response = ev.sysex; 614 615 buildResponseHeader(ev); 616 617 response.push_back(globalSettingsPage()); 618 response.push_back(0); // part = 0 619 response.push_back(_param); 620 response.push_back(static_cast<uint8_t>(m_globalSettings[_param])); 621 response.push_back(M_ENDOFSYSEX); 622 623 _responses.emplace_back(std::move(ev)); 624 }; 625 626 auto buildGlobalResponses = [&]() 627 { 628 for (uint32_t i=0; i<m_globalSettings.size(); ++i) 629 { 630 if(m_globalSettings[i] <= 0xff) 631 buildGlobalResponse(static_cast<uint8_t>(i)); 632 } 633 }; 634 635 auto buildTotalResponse = [&]() 636 { 637 buildGlobalResponses(); 638 buildSingleBankResponse(BankNumber::A); 639 buildSingleBankResponse(BankNumber::B); 640 buildMultiBankResponse(BankNumber::A); 641 }; 642 643 auto buildArrangementResponse = [&]() 644 { 645 // If we are in multi mode, we return the Single mode single first. If in single mode, it is returned last. 646 // The reason is that we want to backup everything but the last loaded multi/single defines the play mode when restoring 647 const bool isMultiMode = m_globalSettings[PLAY_MODE] == PlayModeMulti; 648 649 if(isMultiMode) 650 buildSingleResponse(BankNumber::EditBuffer, SINGLE); 651 652 buildMultiResponse(BankNumber::EditBuffer, 0); 653 654 for(uint8_t p=0; p<16; ++p) 655 buildPresetResponse(DUMP_SINGLE, BankNumber::EditBuffer, p, m_singleEditBuffers[p]); 656 657 if(!isMultiMode) 658 buildSingleResponse(BankNumber::EditBuffer, SINGLE); 659 }; 660 661 auto buildControllerDumpResponse = [&](const uint8_t _part) 662 { 663 TPreset single; 664 665 requestSingle(BankNumber::EditBuffer, _part, single); 666 667 const uint8_t channel = _part == SINGLE ? 0 : _part; 668 669 for (const auto cc : g_pageA) _responses.emplace_back(_source, M_CONTROLCHANGE + channel, cc, single[cc], 0); 670 for (const auto cc : g_pageB) _responses.emplace_back(_source, M_POLYPRESSURE, cc, single[cc + 128], 0); 671 }; 672 673 auto enqueue = [&] 674 { 675 m_pendingSysexInput.emplace_back(_source, _data); 676 return false; 677 }; 678 679 switch (cmd) 680 { 681 case DUMP_SINGLE: 682 { 683 const auto bank = fromMidiByte(_data[7]); 684 const uint8_t program = _data[8]; 685 LOG("Received Single dump, Bank " << (int)toMidiByte(bank) << ", program " << (int)program); 686 TPreset preset; 687 preset.fill(0); 688 if(_data.size() == 524 && m_rom.isTIFamily()) 689 { 690 // D preset 691 auto data(_data); 692 693 data.erase(data.begin() + 0x100 + g_sysexPresetHeaderSize); // A/B/C checksum, not needed on D 694 std::copy_n(data.data() + g_sysexPresetHeaderSize, std::min(preset.size(), _data.size() - g_sysexPresetHeaderSize - g_sysexPresetFooterSize), preset.begin()); 695 } 696 else 697 { 698 std::copy_n(_data.data() + g_sysexPresetHeaderSize, std::min(preset.size(), _data.size() - g_sysexPresetHeaderSize - g_sysexPresetFooterSize), preset.begin()); 699 } 700 return writeSingle(bank, program, preset); 701 } 702 case DUMP_MULTI: 703 { 704 const auto bank = fromMidiByte(_data[7]); 705 const uint8_t program = _data[8]; 706 LOG("Received Multi dump, Bank " << (int)toMidiByte(bank) << ", program " << (int)program); 707 TPreset preset; 708 std::copy_n(_data.data() + g_sysexPresetHeaderSize, std::min(preset.size(), _data.size() - g_sysexPresetHeaderSize - g_sysexPresetFooterSize), preset.begin()); 709 return writeMulti(bank, program, preset); 710 } 711 case REQUEST_SINGLE: 712 { 713 const auto bank = fromMidiByte(_data[7]); 714 if(!m_pendingPresetWrites.empty() || bank == BankNumber::EditBuffer && waitingForPresetReceiveConfirmation()) 715 return enqueue(); 716 const uint8_t program = _data[8]; 717 LOG("Request Single, Bank " << (int)toMidiByte(bank) << ", program " << (int)program); 718 buildSingleResponse(bank, program); 719 break; 720 } 721 case REQUEST_MULTI: 722 { 723 const auto bank = fromMidiByte(_data[7]); 724 if(!m_pendingPresetWrites.empty() || bank == BankNumber::EditBuffer && waitingForPresetReceiveConfirmation()) 725 return enqueue(); 726 const uint8_t program = _data[8]; 727 LOG("Request Multi, Bank " << (int)bank << ", program " << (int)program); 728 buildMultiResponse(bank, program); 729 break; 730 } 731 case REQUEST_BANK_SINGLE: 732 { 733 const auto bank = fromMidiByte(_data[7]); 734 buildSingleBankResponse(bank); 735 break; 736 } 737 case REQUEST_BANK_MULTI: 738 { 739 const auto bank = fromMidiByte(_data[7]); 740 buildMultiBankResponse(bank); 741 break; 742 } 743 case REQUEST_CONTROLLER_DUMP: 744 { 745 const auto part = _data[8]; 746 if (part < 16 || part == SINGLE) 747 buildControllerDumpResponse(part); 748 break; 749 } 750 case REQUEST_GLOBAL: 751 buildGlobalResponses(); 752 break; 753 case REQUEST_TOTAL: 754 if(!m_pendingPresetWrites.empty() || waitingForPresetReceiveConfirmation()) 755 return enqueue(); 756 buildTotalResponse(); 757 break; 758 case REQUEST_ARRANGEMENT: 759 if(!m_pendingPresetWrites.empty() || waitingForPresetReceiveConfirmation()) 760 return enqueue(); 761 buildArrangementResponse(); 762 break; 763 case PAGE_6E: 764 case PAGE_6F: 765 case PAGE_A: 766 case PAGE_B: 767 case PAGE_C: 768 case PAGE_D: 769 { 770 const auto page = static_cast<Page>(cmd); 771 772 if(!isPageSupported(page)) 773 break; 774 775 auto part = _data[7]; 776 const auto param = _data[8]; 777 const auto value = _data[9]; 778 779 if(page == globalSettingsPage() && param == PLAY_MODE) 780 { 781 const auto playMode = value; 782 783 send(page, part, param, value); 784 785 switch(playMode) 786 { 787 case PlayModeSingle: 788 { 789 LOG("Switch to Single mode"); 790 return writeSingle(BankNumber::EditBuffer, SINGLE, m_singleEditBuffer); 791 } 792 case PlayModeMultiSingle: 793 case PlayModeMulti: 794 { 795 writeMulti(BankNumber::EditBuffer, 0, m_multiEditBuffer); 796 for(uint8_t i=0; i<16; ++i) 797 writeSingle(BankNumber::EditBuffer, i, m_singleEditBuffers[i]); 798 return true; 799 } 800 default: 801 return true; 802 } 803 } 804 805 if(!m_rom.isTIFamily() && page == PAGE_A && m_globalSettings[PLAY_MODE] != PlayModeSingle) 806 { 807 applyToMultiEditBuffer(page, part, param, value); 808 } 809 810 if(page == PAGE_C || (page == PAGE_B && param == CLOCK_TEMPO)) 811 { 812 applyToMultiEditBuffer(page, part, param, value); 813 814 const auto command = static_cast<ControlCommand>(param); 815 816 switch(command) 817 { 818 case PART_BANK_SELECT: 819 return partBankSelect(part, value, false); 820 case PART_BANK_CHANGE: 821 return partBankSelect(part, value, true); 822 case PART_PROGRAM_CHANGE: 823 return partProgramChange(part, value); 824 case MULTI_PROGRAM_CHANGE: 825 if(part == 0) 826 { 827 return multiProgramChange(value); 828 } 829 return true; 830 } 831 } 832 else 833 { 834 if (m_globalSettings[PLAY_MODE] != PlayModeSingle || part == SINGLE) 835 { 836 // virus only applies sysex changes to other parts while in multi mode. 837 applyToSingleEditBuffer(page, part, param, value); 838 } 839 if (m_globalSettings[PLAY_MODE] == PlayModeSingle && part == 0) 840 { 841 // accept parameter changes in single mode even if sent for part 0, this is how the editor does it right now 842 applyToSingleEditBuffer(page, SINGLE, param, value); 843 } 844 } 845 846 return send(page, part, param, value); 847 } 848 default: 849 LOG("Unknown sysex command " << HEXN(cmd, 2)); 850 } 851 852 return true; 853 } 854 855 std::vector<TWord> Microcontroller::presetToDSPWords(const TPreset& _preset, const bool _isMulti) const 856 { 857 const auto presetVersion = getPresetVersion(_preset); 858 const auto presetModel = presetVersion <= C ? DeviceModel::ABC : DeviceModel::Snow; 859 860 const auto targetByteSize = _isMulti ? m_rom.getMultiPresetSize() : m_rom.getSinglePresetSize(); 861 const auto sourceByteSize = _isMulti ? ROMFile::getMultiPresetSize(presetModel) : ROMFile::getSinglePresetSize(presetModel); 862 863 const auto sourceWordSize = (sourceByteSize + 2) / 3; 864 const auto targetWordSize = (targetByteSize + 2) / 3; 865 866 std::vector<TWord> preset; 867 preset.resize(targetWordSize, 0); 868 869 size_t idx = 0; 870 for (size_t i = 0; i < sourceWordSize && i < targetWordSize; i++) 871 { 872 if (i == (sourceWordSize - 1)) 873 { 874 if (idx < sourceByteSize) 875 preset[i] = _preset[idx] << 16; 876 if ((idx + 1) < sourceByteSize) 877 preset[i] |= _preset[idx + 1] << 8; 878 if ((idx + 2) < sourceByteSize) 879 preset[i] |= _preset[idx + 2]; 880 } 881 else if (i < sourceWordSize) 882 { 883 preset[i] = ((_preset[idx] << 16) | (_preset[idx + 1] << 8) | _preset[idx + 2]); 884 } 885 886 idx += 3; 887 } 888 889 return preset; 890 } 891 892 bool Microcontroller::getSingle(BankNumber _bank, uint32_t _preset, TPreset& _result) const 893 { 894 _result[0] = 0; 895 896 if (_bank == BankNumber::EditBuffer) 897 return false; 898 899 const auto bank = toArrayIndex(_bank); 900 901 if(bank >= m_singles.size()) 902 return false; 903 904 const auto& s = m_singles[bank]; 905 906 if(_preset >= s.size()) 907 return false; 908 909 _result = s[_preset]; 910 return true; 911 } 912 913 bool Microcontroller::requestMulti(BankNumber _bank, uint8_t _program, TPreset& _data) 914 { 915 _data[0] = 0; 916 917 if (_bank == BankNumber::EditBuffer) 918 { 919 receiveUpgradedPreset(); 920 921 // Use multi-edit buffer 922 _data = m_multiEditBuffer; 923 return true; 924 } 925 926 if (_bank != BankNumber::A || _program >= m_multis.size()) 927 return false; 928 929 // Load from flash 930 _data = m_multis[_program]; 931 return true; 932 } 933 934 bool Microcontroller::requestSingle(BankNumber _bank, uint8_t _program, TPreset& _data) 935 { 936 if (_bank == BankNumber::EditBuffer) 937 { 938 receiveUpgradedPreset(); 939 940 // Use single-edit buffer 941 if(_program == SINGLE) 942 _data = m_singleEditBuffer; 943 else 944 _data = m_singleEditBuffers[_program % m_singleEditBuffers.size()]; 945 946 return true; 947 } 948 949 // Load from flash 950 return getSingle(_bank, _program, _data); 951 } 952 953 bool Microcontroller::writeSingle(BankNumber _bank, uint8_t _program, const TPreset& _data) 954 { 955 if (_bank != BankNumber::EditBuffer) 956 { 957 const auto bank = toArrayIndex(_bank); 958 959 if(bank >= m_singles.size() || bank >= g_singleRamBankCount) 960 return true; // out of range 961 962 if(_program >= m_singles[bank].size()) 963 return true; // out of range 964 965 m_singles[bank][_program] = _data; 966 967 return true; 968 } 969 970 if(_program >= m_singleEditBuffers.size() && _program != SINGLE) 971 return false; 972 973 LOG("Loading Single " << ROMFile::getSingleName(_data) << " to part " << static_cast<int>(_program)); 974 975 // Send to DSP 976 return sendPreset(_program, _data, false); 977 } 978 979 bool Microcontroller::writeMulti(BankNumber _bank, uint8_t _program, const TPreset& _data) 980 { 981 if(_bank == BankNumber::A && _program < m_multis.size()) 982 { 983 m_multis[_program] = _data; 984 return true; 985 } 986 987 if (_bank != BankNumber::EditBuffer) 988 { 989 LOG("We do not support writing to RAM or ROM, attempt to write multi to bank " << static_cast<int>(toMidiByte(_bank)) << ", program " << static_cast<int>(_program)); 990 return true; 991 } 992 993 LOG("Loading Multi " << ROMFile::getMultiName(_data)); 994 995 // Convert array of uint8_t to vector of 24bit TWord 996 return sendPreset(_program, _data, true); 997 } 998 999 bool Microcontroller::partBankSelect(const uint8_t _part, const uint8_t _value, const bool _immediatelySelectSingle) 1000 { 1001 if(_part == SINGLE) 1002 { 1003 const auto bankIndex = static_cast<uint8_t>(toArrayIndex(fromMidiByte(_value)) % m_singles.size()); 1004 m_currentBank = bankIndex; 1005 return true; 1006 } 1007 1008 m_multiEditBuffer[MD_PART_BANK_NUMBER + _part] = _value; 1009 1010 if(_immediatelySelectSingle) 1011 return partProgramChange(_part, m_multiEditBuffer[MD_PART_PROGRAM_NUMBER + _part]); 1012 1013 return true; 1014 } 1015 1016 bool Microcontroller::partProgramChange(const uint8_t _part, const uint8_t _value) 1017 { 1018 TPreset single; 1019 1020 if(_part == SINGLE) 1021 { 1022 if (getSingle(fromArrayIndex(m_currentBank), _value, single)) 1023 { 1024 m_currentSingle = _value; 1025 return writeSingle(BankNumber::EditBuffer, SINGLE, single); 1026 } 1027 return false; 1028 } 1029 1030 const auto bank = fromArrayIndex(m_multiEditBuffer[MD_PART_BANK_NUMBER + _part]); 1031 1032 if(getSingle(bank, _value, single)) 1033 { 1034 m_multiEditBuffer[MD_PART_PROGRAM_NUMBER + _part] = _value; 1035 return writeSingle(BankNumber::EditBuffer, _part, single); 1036 } 1037 1038 return true; 1039 } 1040 1041 bool Microcontroller::multiProgramChange(uint8_t _value) 1042 { 1043 if(_value >= m_multis.size()) 1044 return true; 1045 1046 return loadMulti(_value, m_multis[_value]); 1047 } 1048 1049 bool Microcontroller::loadMulti(uint8_t _program, const TPreset& _multi) 1050 { 1051 if(!writeMulti(BankNumber::EditBuffer, _program, _multi)) 1052 return false; 1053 1054 for (uint8_t p = 0; p < 16; ++p) 1055 loadMultiSingle(p, _multi); 1056 1057 return true; 1058 } 1059 1060 bool Microcontroller::loadMultiSingle(uint8_t _part) 1061 { 1062 return loadMultiSingle(_part, m_multiEditBuffer); 1063 } 1064 1065 bool Microcontroller::loadMultiSingle(uint8_t _part, const TPreset& _multi) 1066 { 1067 const auto partBank = _multi[MD_PART_BANK_NUMBER + _part]; 1068 const auto partSingle = _multi[MD_PART_PROGRAM_NUMBER + _part]; 1069 1070 partBankSelect(_part, partBank, false); 1071 return partProgramChange(_part, partSingle); 1072 } 1073 1074 void Microcontroller::process() 1075 { 1076 m_hdi08.exec(); 1077 1078 std::lock_guard lock(m_mutex); 1079 1080 if(m_loadingState || m_pendingPresetWrites.empty() || !m_hdi08.rxEmpty() || waitingForPresetReceiveConfirmation()) 1081 return; 1082 1083 const auto preset = m_pendingPresetWrites.front(); 1084 m_pendingPresetWrites.pop_front(); 1085 1086 sendPreset(preset.program, preset.data, preset.isMulti); 1087 } 1088 1089 #if !SYNTHLIB_DEMO_MODE 1090 bool Microcontroller::getState(std::vector<unsigned char>& _state, const StateType _type) 1091 { 1092 const auto deviceId = static_cast<uint8_t>(m_globalSettings[DEVICE_ID]); 1093 1094 std::vector<SMidiEvent> responses; 1095 1096 if(_type == StateTypeGlobal) 1097 sendSysex({M_STARTOFSYSEX, 0x00, 0x20, 0x33, 0x01, deviceId, REQUEST_TOTAL, M_ENDOFSYSEX}, responses, MidiEventSource::Internal); 1098 1099 sendSysex({M_STARTOFSYSEX, 0x00, 0x20, 0x33, 0x01, deviceId, REQUEST_ARRANGEMENT, M_ENDOFSYSEX}, responses, MidiEventSource::Internal); 1100 1101 if(responses.empty()) 1102 return false; 1103 1104 for (const auto& response : responses) 1105 { 1106 assert(!response.sysex.empty()); 1107 _state.insert(_state.end(), response.sysex.begin(), response.sysex.end()); 1108 } 1109 1110 return true; 1111 } 1112 1113 bool Microcontroller::setState(const std::vector<unsigned char>& _state, const StateType _type) 1114 { 1115 std::vector<SMidiEvent> events; 1116 1117 for(size_t i=0; i<_state.size(); ++i) 1118 { 1119 if(_state[i] == 0xf0) 1120 { 1121 const auto begin = i; 1122 1123 for(++i; i<_state.size(); ++i) 1124 { 1125 if(_state[i] == 0xf7) 1126 { 1127 SMidiEvent ev(MidiEventSource::Internal); 1128 ev.sysex.resize(i + 1 - begin); 1129 memcpy(ev.sysex.data(), &_state[begin], ev.sysex.size()); 1130 events.emplace_back(ev); 1131 break; 1132 } 1133 } 1134 } 1135 } 1136 1137 return setState(events); 1138 } 1139 1140 bool Microcontroller::setState(const std::vector<synthLib::SMidiEvent>& _events) 1141 { 1142 if(_events.empty()) 1143 return false; 1144 1145 // delay all preset loads until everything is loaded 1146 m_loadingState = true; 1147 1148 std::vector<SMidiEvent> unusedResponses; 1149 1150 for (const auto& event : _events) 1151 { 1152 if(!event.sysex.empty()) 1153 { 1154 sendSysex(event.sysex, unusedResponses, MidiEventSource::Internal); 1155 unusedResponses.clear(); 1156 } 1157 else 1158 { 1159 sendMIDI(event); 1160 } 1161 } 1162 1163 m_loadingState = false; 1164 1165 return true; 1166 } 1167 #endif 1168 1169 void Microcontroller::addDSP(DspSingle& _dsp, bool _useEsaiBasedMidiTiming) 1170 { 1171 m_hdi08.addHDI08(_dsp.getHDI08()); 1172 m_hdi08TxParsers.emplace_back(*this); 1173 m_midiQueues.emplace_back(_dsp, m_hdi08.getQueue(m_hdi08.size()-1), _useEsaiBasedMidiTiming, m_rom.isTIFamily()); 1174 } 1175 1176 void Microcontroller::processHdi08Tx(std::vector<synthLib::SMidiEvent>& _midiEvents) 1177 { 1178 for(size_t i=0; i<m_hdi08.size(); ++i) 1179 { 1180 auto& hdi08 = m_hdi08.getHDI08(i); 1181 auto& parser = m_hdi08TxParsers[i]; 1182 1183 while(hdi08.hasTX()) 1184 { 1185 if(parser.append(hdi08.readTX())) 1186 { 1187 const auto midi = parser.getMidiData(); 1188 if(i == 0) 1189 _midiEvents.insert(_midiEvents.end(), midi.begin(), midi.end()); 1190 parser.clearMidiData(); 1191 } 1192 } 1193 } 1194 } 1195 1196 void Microcontroller::readMidiOut(std::vector<synthLib::SMidiEvent>& _midiOut) 1197 { 1198 std::lock_guard lock(m_mutex); 1199 processHdi08Tx(_midiOut); 1200 1201 if (!m_pendingSysexInput.empty()) 1202 { 1203 uint32_t eraseCount = 0; 1204 1205 for (const auto& input : m_pendingSysexInput) 1206 { 1207 if(!m_pendingPresetWrites.empty() || waitingForPresetReceiveConfirmation()) 1208 break; 1209 1210 sendSysex(input.second, _midiOut, input.first); 1211 ++eraseCount; 1212 } 1213 1214 if(eraseCount == m_pendingSysexInput.size()) 1215 m_pendingSysexInput.clear(); 1216 else if(eraseCount > 0) 1217 m_pendingSysexInput.erase(m_pendingSysexInput.begin(), m_pendingSysexInput.begin() + eraseCount); 1218 } 1219 1220 if(!m_midiOutput.empty()) 1221 { 1222 _midiOut.insert(_midiOut.end(), m_midiOutput.begin(), m_midiOutput.end()); 1223 m_midiOutput.clear(); 1224 } 1225 } 1226 1227 void Microcontroller::sendPendingMidiEvents(const uint32_t _maxOffset) 1228 { 1229 for (auto& midiQueue : m_midiQueues) 1230 midiQueue.sendPendingMidiEvents(_maxOffset); 1231 } 1232 1233 PresetVersion Microcontroller::getPresetVersion(const TPreset& _preset) 1234 { 1235 return getPresetVersion(_preset[0]); 1236 } 1237 1238 PresetVersion Microcontroller::getPresetVersion(const uint8_t v) 1239 { 1240 if(v >= D2) return D2; 1241 if(v >= D) return D; 1242 if(v >= C) return C; 1243 if(v >= B) return B; 1244 return A; 1245 } 1246 1247 uint8_t Microcontroller::calcChecksum(const std::vector<uint8_t>& _data, const size_t _offset, const size_t _count/* = std::numeric_limits<size_t>::max()*/) 1248 { 1249 uint8_t cs = 0; 1250 1251 for (size_t i = _offset; i < std::min(_data.size(), _count); ++i) 1252 cs += _data[i]; 1253 1254 return cs & 0x7f; 1255 } 1256 1257 bool Microcontroller::dspHasBooted() const 1258 { 1259 for (const auto &p : m_hdi08TxParsers) 1260 { 1261 if(!p.hasDspBooted()) 1262 return false; 1263 } 1264 return true; 1265 } 1266 1267 void Microcontroller::applyToSingleEditBuffer(const Page _page, const uint8_t _part, const uint8_t _param, const uint8_t _value) 1268 { 1269 if(_part == SINGLE) 1270 applyToSingleEditBuffer(m_singleEditBuffer, _page, _param, _value); 1271 else 1272 applyToSingleEditBuffer(m_singleEditBuffers[_part], _page, _param, _value); 1273 } 1274 1275 void Microcontroller::applyToSingleEditBuffer(TPreset& _single, const Page _page, const uint8_t _param, const uint8_t _value) 1276 { 1277 constexpr uint32_t paramsPerPage = 128; 1278 1279 uint32_t offset; 1280 switch(_page) 1281 { 1282 case PAGE_A: 1283 // prevent that someone attempts to modify the preset version 1284 if(_param == 0) 1285 return; 1286 offset = 0; break; 1287 case PAGE_B: offset = 1; break; 1288 case PAGE_6E: offset = 2; break; 1289 case PAGE_6F: offset = 3; break; 1290 default: 1291 return; 1292 } 1293 1294 offset *= paramsPerPage; 1295 offset += _param; 1296 1297 if(offset >= _single.size()) 1298 return; 1299 1300 _single[offset] = _value; 1301 } 1302 1303 void Microcontroller::applyToMultiEditBuffer(const Page _page, const uint8_t _part, const uint8_t _param, const uint8_t _value) 1304 { 1305 // multi edit buffer duplicates parameters of a single, apply them to the multi edit buffer 1306 switch (_page) 1307 { 1308 case PAGE_A: 1309 switch (_param) 1310 { 1311 case EFFECT_SEND: m_multiEditBuffer[MD_PART_EFFECT_SEND + _part] = _value; break; 1312 case DELAY_REVERB_MODE: m_multiEditBuffer[MD_DELAY_MODE] = _value; break; 1313 case DELAY_TIME: m_multiEditBuffer[MD_DELAY_TIME] = _value; break; 1314 case DELAY_FEEDBACK: m_multiEditBuffer[MD_DELAY_FEEDBACK] = _value; break; 1315 case DELAY_RATE: m_multiEditBuffer[MD_DELAY_RATE] = _value; break; 1316 case DELAY_DEPTH: m_multiEditBuffer[MD_DELAY_DEPTH] = _value; break; 1317 case DELAY_LFO_SHAPE: m_multiEditBuffer[MD_DELAY_SHAPE] = _value; break; 1318 case DELAY_COLOR: m_multiEditBuffer[MD_DELAY_COLOR] = _value; break; 1319 } 1320 break; 1321 case PAGE_B: 1322 if (_param == CLOCK_TEMPO) 1323 { 1324 m_multiEditBuffer[MD_CLOCK_TEMPO] = _value; 1325 } 1326 break; 1327 case PAGE_C: 1328 if (_param >= PART_MIDI_CHANNEL && _param <= PART_OUTPUT_SELECT) 1329 { 1330 const auto idx = MD_PART_MIDI_CHANNEL + ((_param-PART_MIDI_CHANNEL)*16) + _part; 1331 m_multiEditBuffer[idx] = _value; 1332 } 1333 break; 1334 } 1335 } 1336 1337 Page Microcontroller::globalSettingsPage() const 1338 { 1339 return m_rom.isTIFamily() ? PAGE_D : PAGE_C; 1340 } 1341 1342 bool Microcontroller::isPageSupported(Page _page) const 1343 { 1344 switch (_page) 1345 { 1346 case PAGE_6E: 1347 case PAGE_6F: 1348 case PAGE_D: 1349 return m_rom.isTIFamily(); 1350 case PAGE_A: 1351 case PAGE_B: 1352 case PAGE_C: 1353 return true; 1354 default: 1355 return false; 1356 } 1357 } 1358 1359 bool Microcontroller::waitingForPresetReceiveConfirmation() const 1360 { 1361 for (const auto& parser : m_hdi08TxParsers) 1362 { 1363 if(parser.waitingForPreset()) 1364 return true; 1365 } 1366 return false; 1367 } 1368 1369 void Microcontroller::receiveUpgradedPreset() 1370 { 1371 const auto waitingForPresetConfirmation = waitingForPresetReceiveConfirmation(); 1372 1373 if(waitingForPresetConfirmation) 1374 return; 1375 1376 std::vector<uint8_t> upgradedPreset; 1377 m_hdi08TxParsers.front().getPresetData(upgradedPreset); 1378 1379 if(upgradedPreset.empty()) 1380 return; 1381 1382 LOG("Replacing edit buffer for " << (m_sentPresetIsMulti ? "multi" : "single") << " program " << static_cast<int>(m_sentPresetProgram) << " with upgraded preset"); 1383 1384 auto copyTo = [&upgradedPreset, this](TPreset& _preset) 1385 { 1386 std::copy(upgradedPreset.begin(), upgradedPreset.end(), _preset.begin()); 1387 }; 1388 1389 if(m_sentPresetIsMulti) 1390 { 1391 copyTo(m_multiEditBuffer); 1392 } 1393 else if(m_sentPresetProgram == SINGLE) 1394 { 1395 copyTo(m_singleEditBuffer); 1396 } 1397 else if(m_sentPresetProgram < m_singleEditBuffers.size()) 1398 { 1399 copyTo(m_singleEditBuffers[m_sentPresetProgram]); 1400 } 1401 } 1402 1403 bool Microcontroller::isValid(const TPreset& _preset) 1404 { 1405 return _preset[240] >= 32 && _preset[240] <= 127; 1406 } 1407 }