xtController.cpp (23437B)
1 #include "xtController.h" 2 3 #include <fstream> 4 5 #include "PluginProcessor.h" 6 7 #include "xtLib/xtState.h" 8 9 #include "dsp56kEmu/logging.h" 10 11 #include "xtFrontPanel.h" 12 #include "xtWaveEditor.h" 13 14 namespace 15 { 16 constexpr const char* g_midiPacketNames[] = 17 { 18 "requestsingle", 19 "requestmulti", 20 "requestsinglebank", 21 "requestmultibank", 22 "requestglobal", 23 "requestmode", 24 "requestallsingles", 25 "singleparameterchange", 26 "multiparameterchange", 27 "globalparameterchange", 28 "singledump", 29 "multidump", 30 "globaldump", 31 "modedump", 32 "emuRequestLcd", 33 "emuRequestLeds", 34 "emuSendButton", 35 "emuSendRotary", 36 "requestWave", 37 "waveDump", 38 "requestTable", 39 "tableDump" 40 }; 41 42 static_assert(std::size(g_midiPacketNames) == static_cast<size_t>(xtJucePlugin::Controller::MidiPacketType::Count)); 43 44 const char* midiPacketName(xtJucePlugin::Controller::MidiPacketType _type) 45 { 46 return g_midiPacketNames[static_cast<uint32_t>(_type)]; 47 } 48 49 constexpr uint32_t g_pageMulti = 10; 50 constexpr uint32_t g_pageMultiInst0 = 11; 51 constexpr uint32_t g_pageMultiInst1 = 12; 52 constexpr uint32_t g_pageMultiInst2 = 13; 53 constexpr uint32_t g_pageMultiInst3 = 14; 54 constexpr uint32_t g_pageMultiInst4 = 15; 55 constexpr uint32_t g_pageMultiInst5 = 16; 56 constexpr uint32_t g_pageMultiInst6 = 17; 57 constexpr uint32_t g_pageMultiInst7 = 18; 58 constexpr uint32_t g_pageGlobal = 20; 59 constexpr uint32_t g_pageSoftKnobs = 30; 60 constexpr uint32_t g_pageControllers = 40; 61 } 62 63 namespace xtJucePlugin 64 { 65 Controller::Controller(AudioPluginAudioProcessor& p, const unsigned char _deviceId) : pluginLib::Controller(p, "parameterDescriptions_xt.json"), m_deviceId(_deviceId) 66 { 67 registerParams(p); 68 69 sendSysEx(RequestGlobal); 70 sendSysEx(RequestMode); 71 72 onPlayModeChanged.addListener([this](bool multiMode) 73 { 74 requestAllPatches(); 75 }); 76 77 // slow down edits of the wavetable, device gets overloaded quickly if we send too many changes 78 uint32_t idx; 79 getParameterDescriptions().getIndexByName(idx, "Wave"); 80 for(uint8_t i=0; i<m_singleEditBuffers.size(); ++i) 81 { 82 auto* p = getParameter(idx, i); 83 p->setRateLimitMilliseconds(250); 84 } 85 } 86 87 Controller::~Controller() = default; 88 89 bool Controller::sendSingle(const std::vector<uint8_t>& _sysex) 90 { 91 return sendSingle(_sysex, getCurrentPart()); 92 } 93 94 bool Controller::sendSingle(const std::vector<uint8_t>& _sysex, const uint8_t _part) 95 { 96 if(_sysex.size() == xt::Mw1::g_singleDumpLength) 97 { 98 // No program/bank bytes are part of the dump, send as-is and request the result 99 100 if(_part > 0) 101 return false; // we cannot support this as the hardware loads a MW1 to the "current" instrument, which is always the first one 102 103 pluginLib::Controller::sendSysEx(_sysex); 104 requestSingle(isMultiMode() ? xt::LocationH::SingleEditBufferMultiMode : xt::LocationH::SingleEditBufferSingleMode, 0); 105 return true; 106 } 107 108 auto data = _sysex; 109 110 if(_sysex.size() > std::tuple_size_v<xt::State::Single>) 111 { 112 // split a combined single into single, table, waves and send all of them 113 std::vector<xt::SysEx> splitResults; 114 xt::State::splitCombinedPatch(splitResults, _sysex); 115 116 if(!splitResults.empty()) 117 { 118 const auto& single = splitResults.front(); 119 120 if(m_waveEditor) 121 { 122 const auto& table = splitResults[1]; 123 m_waveEditor->getData().onReceiveTable(table, true); 124 125 for(size_t i=2; i<splitResults.size(); ++i) 126 { 127 const auto& wave = splitResults[i]; 128 m_waveEditor->getData().onReceiveWave(wave, true); 129 } 130 } 131 132 data = single; 133 } 134 } 135 136 data[wLib::IdxBuffer] = static_cast<uint8_t>(isMultiMode() ? xt::LocationH::SingleEditBufferMultiMode : xt::LocationH::SingleEditBufferSingleMode); 137 data[wLib::IdxLocation] = isMultiMode() ? _part : 0; 138 data[wLib::IdxDeviceId] = m_deviceId; 139 140 const auto* p = getMidiPacket(g_midiPacketNames[SingleDump]); 141 142 if (!p->updateChecksums(data)) 143 return false; 144 145 pluginLib::Controller::sendSysEx(data); 146 147 sendLockedParameters(_part); 148 149 requestSingle(isMultiMode() ? xt::LocationH::SingleEditBufferMultiMode : xt::LocationH::SingleEditBufferSingleMode, 0); 150 151 return true; 152 } 153 154 void Controller::onStateLoaded() 155 { 156 sendSysEx(RequestGlobal); 157 sendSysEx(RequestMode); 158 } 159 160 uint8_t Controller::getPartCount() const 161 { 162 return 8; 163 } 164 165 std::vector<uint8_t> Controller::getPartsForMidiChannel(const uint8_t _channel) 166 { 167 if (!isMultiMode()) 168 return {0}; 169 170 std::vector<uint8_t> parts; 171 172 for (uint8_t p=0; p<getPartCount(); ++p) 173 { 174 char paramName[16]; 175 (void)snprintf(paramName, std::size(paramName), "MI%dMidiChannel", static_cast<int>(p)); 176 auto* param = getParameter(paramName, 0); 177 assert(param && "parameter not found"); 178 const auto v = param->getUnnormalizedValue(); 179 if (v < 2 || v - 2 == _channel) // omni, global, 0, 1, .... 180 parts.push_back(p); 181 } 182 return parts; 183 } 184 185 std::string Controller::getSingleName(const pluginLib::MidiPacket::ParamValues& _values) const 186 { 187 std::string name; 188 for(uint32_t i=0; i<16; ++i) 189 { 190 char paramName[16]; 191 (void)snprintf(paramName, sizeof(paramName), "Name%02u", i); 192 const auto idx = getParameterIndexByName(paramName); 193 if(idx == InvalidParameterIndex) 194 break; 195 196 const auto it = _values.find(std::make_pair(pluginLib::MidiPacket::AnyPart, idx)); 197 if(it == _values.end()) 198 break; 199 200 name += static_cast<char>(it->second); 201 } 202 return name; 203 } 204 205 std::string Controller::getSingleName(const uint8_t _part) const 206 { 207 std::string name; 208 for(uint32_t i=0; i<16; ++i) 209 { 210 char paramName[16]; 211 (void)snprintf(paramName, sizeof(paramName), "Name%02u", i); 212 const auto idx = getParameterIndexByName(paramName); 213 if(idx == InvalidParameterIndex) 214 break; 215 216 const auto* p = getParameter(idx, _part); 217 if(!p) 218 break; 219 220 name += static_cast<char>(p->getUnnormalizedValue()); 221 } 222 return name; 223 } 224 225 std::string Controller::getSingleName(const pluginLib::MidiPacket::AnyPartParamValues& _values) const 226 { 227 return getString(_values, "Name", 16); 228 } 229 230 std::string Controller::getString(const pluginLib::MidiPacket::AnyPartParamValues& _values, const std::string& _prefix, const size_t _len) const 231 { 232 std::string name; 233 for(uint32_t i=0; i<_len; ++i) 234 { 235 char paramName[64]; 236 (void)snprintf(paramName, sizeof(paramName), "%s%02u", _prefix.c_str(), i); 237 238 const auto idx = getParameterIndexByName(paramName); 239 if(idx == InvalidParameterIndex) 240 break; 241 242 const auto it = _values[idx]; 243 if(!it) 244 break; 245 246 name += static_cast<char>(*it); 247 } 248 return name; 249 } 250 251 bool Controller::setSingleName(pluginLib::MidiPacket::AnyPartParamValues& _values, const std::string& _value) const 252 { 253 return setString(_values, "Name", 16, _value); 254 } 255 256 void Controller::parseSingle(const pluginLib::SysEx& _msg, const pluginLib::MidiPacket::Data& _data, const pluginLib::MidiPacket::ParamValues& _params) 257 { 258 Patch patch; 259 patch.data = _msg; 260 patch.name = getSingleName(_params); 261 262 const auto bank = _data.at(pluginLib::MidiDataType::Bank); 263 const auto prog = _data.at(pluginLib::MidiDataType::Program); 264 265 if(bank == static_cast<uint8_t>(xt::LocationH::SingleEditBufferSingleMode) && prog == 0) 266 { 267 m_singleEditBuffer = patch; 268 269 if(!isMultiMode()) 270 applyPatchParameters(_params, 0); 271 } 272 else if(bank == static_cast<uint8_t>(xt::LocationH::SingleEditBufferMultiMode)) 273 { 274 m_singleEditBuffers[prog] = patch; 275 276 if (isMultiMode()) 277 applyPatchParameters(_params, prog); 278 279 // if we switched to multi, all singles have to be requested. However, we cannot send all requests at once (device will miss some) 280 // so we chain them one after the other 281 if(prog + 1 < m_singleEditBuffers.size()) 282 requestSingle(xt::LocationH::SingleEditBufferMultiMode, prog + 1); 283 } 284 else 285 return; 286 287 // if the single that was received contains a user table, request it from the device as it might not match what we have in the editor 288 if (m_waveEditor) 289 { 290 const auto tableId = xt::TableId(xt::State::getWavetableFromSingleDump(patch.data)); 291 292 if (!xt::wave::isReadOnly(tableId)) 293 { 294 if (requestTable(tableId.rawId())) 295 m_requestWavesForTables.insert(tableId); 296 } 297 } 298 299 onProgramChanged(prog); 300 } 301 302 void Controller::parseMulti(const pluginLib::SysEx& _msg, const pluginLib::MidiPacket::Data& _data, const pluginLib::MidiPacket::ParamValues& _params) const 303 { 304 Patch patch; 305 patch.data = _msg; 306 patch.name = getSingleName(_params); 307 308 const auto bank = _data.at(pluginLib::MidiDataType::Bank); 309 // const auto prog = _data.at(pluginLib::MidiDataType::Program); 310 311 if(bank == static_cast<uint8_t>(xt::LocationH::MultiDumpMultiEditBuffer)) 312 { 313 applyPatchParameters(_params, 0); 314 315 if(isMultiMode()) 316 { 317 // requst first single. The other singles 1-7 are requested one after the other after a single has been received 318 requestSingle(xt::LocationH::SingleEditBufferMultiMode, 0); 319 } 320 } 321 } 322 323 void Controller::parseGlobal(const pluginLib::SysEx& _msg, const pluginLib::MidiPacket::Data& _data, const pluginLib::MidiPacket::ParamValues& _params) 324 { 325 memcpy(m_globalData.data(), &_msg[xt::IdxGlobalParamFirst], sizeof(m_globalData)); 326 327 applyPatchParameters(_params, 0); 328 } 329 330 bool Controller::parseSysexMessage(const pluginLib::SysEx& _msg, synthLib::MidiEventSource) 331 { 332 if(_msg.size() >= 5) 333 { 334 switch (const auto cmd = static_cast<xt::SysexCommand>(_msg[4])) 335 { 336 case xt::SysexCommand::EmuRotaries: 337 case xt::SysexCommand::EmuButtons: 338 case xt::SysexCommand::EmuLCD: 339 case xt::SysexCommand::EmuLEDs: 340 if(m_frontPanel) 341 m_frontPanel->processSysex(_msg); 342 return true; 343 default: 344 break; 345 } 346 } 347 348 LOG("Got sysex of size " << _msg.size()); 349 350 std::string name; 351 pluginLib::MidiPacket::Data data; 352 pluginLib::MidiPacket::ParamValues parameterValues; 353 354 if(!pluginLib::Controller::parseMidiPacket(name, data, parameterValues, _msg)) 355 return false; 356 357 if(name == midiPacketName(SingleDump)) 358 { 359 parseSingle(_msg, data, parameterValues); 360 } 361 else if (name == midiPacketName(MultiDump)) 362 { 363 parseMulti(_msg, data, parameterValues); 364 } 365 else if(name == midiPacketName(GlobalDump)) 366 { 367 parseGlobal(_msg, data, parameterValues); 368 } 369 else if(name == midiPacketName(ModeDump)) 370 { 371 const auto lastPlayMode = isMultiMode(); 372 memcpy(m_modeData.data(), &_msg[xt::IdxModeParamFirst], sizeof(m_modeData)); 373 const auto newPlayMode = isMultiMode(); 374 375 if(lastPlayMode != newPlayMode) 376 onPlayModeChanged(newPlayMode); 377 else 378 requestAllPatches(); 379 } 380 else if(name == midiPacketName(SingleParameterChange)) 381 { 382 const auto page = data[pluginLib::MidiDataType::Page]; 383 const auto index = data[pluginLib::MidiDataType::ParameterIndex]; 384 const auto part = data[pluginLib::MidiDataType::Part]; 385 const auto value = data[pluginLib::MidiDataType::ParameterValue]; 386 387 auto& params = findSynthParam(part, page, index); 388 389 for (auto& param : params) 390 param->setValueFromSynth(value, pluginLib::Parameter::Origin::Midi); 391 392 LOG("Single parameter " << static_cast<int>(index) << ", page " << static_cast<int>(page) << " for part " << static_cast<int>(part) << " changed to value " << static_cast<int>(value)); 393 } 394 else if(name == midiPacketName(GlobalParameterChange)) 395 { 396 const auto index = (static_cast<uint32_t>(data[pluginLib::MidiDataType::Page]) << 7) + static_cast<uint32_t>(data[pluginLib::MidiDataType::ParameterIndex]); 397 const auto value = data[pluginLib::MidiDataType::ParameterValue]; 398 399 if(m_globalData[index] != value) 400 { 401 LOG("Global parameter " << index << " changed to value " << static_cast<int>(value)); 402 m_globalData[index] = value; 403 } 404 } 405 else if(name == midiPacketName(WaveDump)) 406 { 407 if(m_waveEditor) 408 m_waveEditor->onReceiveWave(data, _msg); 409 } 410 else if(name == midiPacketName(TableDump)) 411 { 412 if(m_waveEditor) 413 m_waveEditor->onReceiveTable(data, _msg); 414 415 const auto tableId = xt::TableId(static_cast<uint16_t>(_msg[xt::SysexIndex::IdxWaveIndexH] << 7 | _msg[xt::SysexIndex::IdxWaveIndexL])); 416 417 if (m_requestWavesForTables.find(tableId) != m_requestWavesForTables.end()) 418 { 419 xt::TableData table; 420 421 if (xt::State::parseTableData(table, _msg)) 422 { 423 auto waves = xt::State::getWavesForTable(table); 424 for (const auto& wave : waves) 425 { 426 if (!xt::wave::isReadOnly(wave)) 427 requestWave(wave.rawId()); 428 } 429 } 430 m_requestWavesForTables.erase(tableId); 431 } 432 } 433 else 434 { 435 LOG("Received unknown sysex of size " << _msg.size()); 436 return false; 437 } 438 return true; 439 } 440 441 bool Controller::parseControllerMessage(const synthLib::SMidiEvent& _e) 442 { 443 const auto& cm = getParameterDescriptions().getControllerMap(); 444 const auto paramIndices = cm.getControlledParameters(_e); 445 446 if(paramIndices.empty()) 447 return false; 448 449 const auto origin = midiEventSourceToParameterOrigin(_e.source); 450 451 const auto parts = isMultiMode() ? getPartsForMidiEvent(_e) : std::vector<uint8_t>{0}; 452 453 if (parts.empty()) 454 return false; 455 456 for (const uint8_t part : parts) 457 { 458 for (const auto paramIndex : paramIndices) 459 { 460 auto* param = getParameter(paramIndex, part); 461 assert(param && "parameter not found for control change"); 462 param->setValueFromSynth(_e.c, origin); 463 } 464 } 465 466 return true; 467 } 468 469 bool Controller::parseMidiPacket(MidiPacketType _type, pluginLib::MidiPacket::Data& _data, pluginLib::MidiPacket::AnyPartParamValues& _params, const pluginLib::SysEx& _sysex) const 470 { 471 const auto* p = getMidiPacket(g_midiPacketNames[_type]); 472 assert(p && "midi packet not found"); 473 return pluginLib::Controller::parseMidiPacket(*p, _data, _params, _sysex); 474 } 475 476 bool Controller::sendSysEx(MidiPacketType _type) const 477 { 478 std::map<pluginLib::MidiDataType, uint8_t> params; 479 return sendSysEx(_type, params); 480 } 481 482 bool Controller::sendSysEx(const MidiPacketType _type, std::map<pluginLib::MidiDataType, uint8_t>& _params) const 483 { 484 _params.insert(std::make_pair(pluginLib::MidiDataType::DeviceId, m_deviceId)); 485 return pluginLib::Controller::sendSysEx(midiPacketName(_type), _params); 486 } 487 488 bool Controller::isMultiMode() const 489 { 490 return m_modeData.front() != 0; 491 } 492 493 void Controller::setPlayMode(const bool _multiMode) 494 { 495 if(isMultiMode() == _multiMode) 496 return; 497 498 m_modeData[0] = _multiMode ? 1 : 0; 499 500 sendModeDump(); 501 502 onPlayModeChanged(_multiMode); 503 } 504 505 void Controller::selectNextPreset() 506 { 507 selectPreset(+1); 508 } 509 510 void Controller::selectPrevPreset() 511 { 512 selectPreset(-1); 513 } 514 515 std::vector<uint8_t> Controller::createSingleDump(const xt::LocationH _buffer, const uint8_t _location, const uint8_t _part) const 516 { 517 pluginLib::MidiPacket::Data data; 518 519 data.insert(std::make_pair(pluginLib::MidiDataType::DeviceId, m_deviceId)); 520 data.insert(std::make_pair(pluginLib::MidiDataType::Bank, static_cast<uint8_t>(_buffer))); 521 data.insert(std::make_pair(pluginLib::MidiDataType::Program, _location)); 522 523 std::vector<uint8_t> dst; 524 525 if (!createMidiDataFromPacket(dst, midiPacketName(SingleDump), data, _part)) 526 return {}; 527 528 return dst; 529 } 530 531 std::vector<uint8_t> Controller::createSingleDump(xt::LocationH _buffer, const uint8_t _location, const pluginLib::MidiPacket::AnyPartParamValues& _values) const 532 { 533 pluginLib::MidiPacket::Data data; 534 535 data.insert(std::make_pair(pluginLib::MidiDataType::DeviceId, m_deviceId)); 536 data.insert(std::make_pair(pluginLib::MidiDataType::Bank, static_cast<uint8_t>(_buffer))); 537 data.insert(std::make_pair(pluginLib::MidiDataType::Program, _location)); 538 539 std::vector<uint8_t> dst; 540 541 if (!createMidiDataFromPacket(dst, midiPacketName(SingleDump), data, _values)) 542 return {}; 543 544 return dst; 545 } 546 547 bool Controller::parseSingle(pluginLib::MidiPacket::Data& _data, pluginLib::MidiPacket::AnyPartParamValues& _paramValues, const std::vector<uint8_t>& _sysex) const 548 { 549 return parseMidiPacket(SingleDump, _data, _paramValues, _sysex); 550 } 551 552 bool Controller::setString(pluginLib::MidiPacket::AnyPartParamValues& _values, const std::string& _prefix, size_t _len, const std::string& _value) const 553 { 554 for(uint32_t i=0; i<_len && i <_value.size(); ++i) 555 { 556 char paramName[64]; 557 (void)snprintf(paramName, sizeof(paramName), "%s%02u", _prefix.c_str(), i); 558 559 const auto idx = getParameterIndexByName(paramName); 560 if(idx == InvalidParameterIndex) 561 break; 562 563 _values[idx] = static_cast<uint8_t>(_value[i]); 564 } 565 return true; 566 } 567 568 void Controller::setFrontPanel(xtJucePlugin::FrontPanel* _frontPanel) 569 { 570 m_frontPanel = _frontPanel; 571 } 572 573 void Controller::setWaveEditor(xtJucePlugin::WaveEditor* _waveEditor) 574 { 575 m_waveEditor = _waveEditor; 576 } 577 578 void Controller::selectPreset(const int _offset) 579 { 580 auto& current = isMultiMode() ? m_currentSingles[getCurrentPart()] : m_currentSingle; 581 582 int index = static_cast<int>(current) + _offset; 583 584 if (index < 0) 585 index += 300; 586 587 if (index >= 300) 588 index -= 300; 589 590 current = static_cast<uint32_t>(index); 591 592 const int single = index % 100; 593 const int bank = index / 100; 594 595 if (isMultiMode()) 596 { 597 // TODO: modify multi 598 } 599 else 600 { 601 sendMidiEvent(synthLib::M_CONTROLCHANGE, synthLib::MC_BANKSELECTMSB, m_deviceId); 602 sendMidiEvent(synthLib::M_CONTROLCHANGE, synthLib::MC_BANKSELECTLSB, static_cast<uint8_t>(xt::LocationH::SingleBankA) + bank); 603 sendMidiEvent(synthLib::M_PROGRAMCHANGE, static_cast<uint8_t>(single), 0); 604 /* 605 sendGlobalParameterChange(xt::GlobalParameter::InstrumentABankNumber, static_cast<uint8_t>(bank)); 606 sendGlobalParameterChange(xt::GlobalParameter::InstrumentASingleNumber, static_cast<uint8_t>(single)); 607 */ } 608 } 609 610 void Controller::sendParameterChange(const pluginLib::Parameter& _parameter, const pluginLib::ParamValue _value) 611 { 612 const auto &desc = _parameter.getDescription(); 613 614 std::map<pluginLib::MidiDataType, uint8_t> data; 615 616 switch (desc.page) 617 { 618 case g_pageGlobal: 619 { 620 data.insert(std::make_pair(pluginLib::MidiDataType::ParameterIndex, _parameter.getDescription().index & 0x7f)); 621 data.insert(std::make_pair(pluginLib::MidiDataType::ParameterValue, _value)); 622 623 sendSysEx(GlobalParameterChange, data); 624 } 625 return; 626 case g_pageMulti: 627 case g_pageMultiInst0: 628 case g_pageMultiInst1: 629 case g_pageMultiInst2: 630 case g_pageMultiInst3: 631 case g_pageMultiInst4: 632 case g_pageMultiInst5: 633 case g_pageMultiInst6: 634 case g_pageMultiInst7: 635 { 636 uint8_t v; 637 638 if (!combineParameterChange(v, g_midiPacketNames[MultiDump], _parameter, _value)) 639 return; 640 641 uint8_t page; 642 643 if(desc.page > g_pageMulti) 644 page = desc.page - g_pageMultiInst0; 645 else 646 page = static_cast<uint8_t>(xt::LocationH::MultiDumpMultiEditBuffer); 647 648 data.insert(std::make_pair(pluginLib::MidiDataType::Part, _parameter.getPart())); 649 data.insert(std::make_pair(pluginLib::MidiDataType::Page, page)); 650 data.insert(std::make_pair(pluginLib::MidiDataType::ParameterIndex, desc.index)); 651 data.insert(std::make_pair(pluginLib::MidiDataType::ParameterValue, v)); 652 653 sendSysEx(MultiParameterChange, data); 654 } 655 return; 656 case g_pageSoftKnobs: 657 break; 658 case g_pageControllers: 659 break; 660 default: 661 { 662 uint8_t v; 663 if (!combineParameterChange(v, g_midiPacketNames[SingleDump], _parameter, _value)) 664 return; 665 666 data.insert(std::make_pair(pluginLib::MidiDataType::Part, _parameter.getPart())); 667 data.insert(std::make_pair(pluginLib::MidiDataType::Page, desc.page)); 668 data.insert(std::make_pair(pluginLib::MidiDataType::ParameterIndex, desc.index)); 669 data.insert(std::make_pair(pluginLib::MidiDataType::ParameterValue, v)); 670 671 sendSysEx(SingleParameterChange, data); 672 } 673 break; 674 } 675 } 676 677 bool Controller::sendGlobalParameterChange(xt::GlobalParameter _param, uint8_t _value) 678 { 679 const auto index = static_cast<uint32_t>(_param); 680 681 if(m_globalData[index] == _value) 682 return true; 683 684 std::map<pluginLib::MidiDataType, uint8_t> data; 685 686 data.insert(std::make_pair(pluginLib::MidiDataType::Page, index >> 7 )); 687 data.insert(std::make_pair(pluginLib::MidiDataType::ParameterIndex, index & 0x7f )); 688 data.insert(std::make_pair(pluginLib::MidiDataType::ParameterValue, _value)); 689 690 m_globalData[index] = _value; 691 692 return sendSysEx(GlobalParameterChange, data); 693 } 694 695 bool Controller::sendModeDump() const 696 { 697 std::vector<uint8_t> sysex; 698 std::map<pluginLib::MidiDataType, uint8_t> data; 699 data.insert({pluginLib::MidiDataType::DeviceId, m_deviceId}); 700 if(!createMidiDataFromPacket(sysex, midiPacketName(ModeDump), data, 0)) 701 return false; 702 sysex[xt::IdxModeParamFirst] = m_modeData.front(); 703 pluginLib::Controller::sendSysEx(sysex); 704 return true; 705 } 706 707 void Controller::requestSingle(xt::LocationH _buf, uint8_t _location) const 708 { 709 std::map<pluginLib::MidiDataType, uint8_t> params; 710 params[pluginLib::MidiDataType::Bank] = static_cast<uint8_t>(_buf); 711 params[pluginLib::MidiDataType::Program] = _location; 712 sendSysEx(RequestSingle, params); 713 } 714 715 void Controller::requestMulti(xt::LocationH _buf, uint8_t _location) const 716 { 717 std::map<pluginLib::MidiDataType, uint8_t> params; 718 params[pluginLib::MidiDataType::Bank] = static_cast<uint8_t>(_buf); 719 params[pluginLib::MidiDataType::Program] = _location; 720 sendSysEx(RequestMulti, params); 721 } 722 723 bool Controller::requestWave(const uint32_t _number) const 724 { 725 if(!xt::wave::isValidWaveIndex(_number)) 726 return false; 727 728 std::map<pluginLib::MidiDataType, uint8_t> params; 729 730 params[pluginLib::MidiDataType::Bank] = static_cast<uint8_t>(_number >> 7); 731 params[pluginLib::MidiDataType::Program] = _number & 0x7f; 732 733 return sendSysEx(RequestWave, params); 734 } 735 736 bool Controller::requestTable(const uint32_t _number) const 737 { 738 if(!xt::wave::isValidTableIndex(_number)) 739 return false; 740 741 std::map<pluginLib::MidiDataType, uint8_t> params; 742 743 params[pluginLib::MidiDataType::Bank] = static_cast<uint8_t>(_number >> 7); 744 params[pluginLib::MidiDataType::Program] = _number & 0x7f; 745 746 return sendSysEx(RequestTable, params); 747 } 748 749 uint8_t Controller::getGlobalParam(xt::GlobalParameter _type) const 750 { 751 return m_globalData[static_cast<uint32_t>(_type)]; 752 } 753 754 bool Controller::isDerivedParameter(pluginLib::Parameter& _derived, pluginLib::Parameter& _base) const 755 { 756 if(_derived.getDescription().page >= 100) 757 return false; 758 759 const auto& packetName = g_midiPacketNames[SingleDump]; 760 const auto* packet = getMidiPacket(packetName); 761 762 if (!packet) 763 { 764 LOG("Failed to find midi packet " << packetName); 765 return true; 766 } 767 768 const auto* defA = packet->getDefinitionByParameterName(_derived.getDescription().name); 769 const auto* defB = packet->getDefinitionByParameterName(_base.getDescription().name); 770 771 if (!defA || !defB) 772 return true; 773 774 return defA->doMasksOverlap(*defB); 775 } 776 777 void Controller::requestAllPatches() const 778 { 779 if (isMultiMode()) 780 { 781 requestMulti(xt::LocationH::MultiDumpMultiEditBuffer, 0); 782 } 783 else 784 { 785 requestSingle(xt::LocationH::SingleEditBufferSingleMode, 0); 786 } 787 } 788 }