xtState.cpp (37058B)
1 #include "xtState.h" 2 3 #include <cassert> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 8 #include "xtMidiTypes.h" 9 #include "xt.h" 10 #include "xtWavePreview.h" 11 12 #include "synthLib/midiToSysex.h" 13 #include "synthLib/midiBufferParser.h" 14 15 #include "dsp56kEmu/logging.h" 16 17 namespace xt 18 { 19 static_assert(std::size(State::Dumps) == static_cast<uint32_t>(State::DumpType::Count), "data definition missing"); 20 21 State::State(Xt& _xt, WavePreview& _wavePreview) : m_xt(_xt), m_wavePreview(_wavePreview) 22 { 23 } 24 25 bool State::loadState(const SysEx& _sysex) 26 { 27 std::vector<std::vector<uint8_t>> messages; 28 synthLib::MidiToSysex::splitMultipleSysex(messages, _sysex); 29 30 if(messages.empty()) 31 return false; 32 33 Responses nop; 34 35 for (const auto& message : messages) 36 receive(nop, message, Origin::External); 37 38 return true; 39 } 40 41 bool State::getState(std::vector<uint8_t>& _state, synthLib::StateType _type) const 42 { 43 append(_state, m_mode, ~0u); 44 append(_state, m_global, wLib::IdxCommand); 45 46 // add all waves and tables that are used by the singles 47 std::set<TableId> tableIds; 48 49 auto addTableId = [&](TableId id) 50 { 51 if(wave::isReadOnly(id)) 52 return false; 53 54 const auto idx = id.rawId(); 55 if(idx >= m_tables.size()) 56 return false; 57 58 if(!isValid(m_tables[idx])) 59 return false; 60 tableIds.insert(id); 61 return true; 62 }; 63 64 for (const auto& s : m_currentInstrumentSingles) 65 { 66 const auto table = getWavetableFromSingleDump({s.begin(), s.end()}); 67 addTableId(table); 68 } 69 for (const auto& s : m_currentMultiSingles) 70 { 71 const auto table = getWavetableFromSingleDump({s.begin(), s.end()}); 72 addTableId(table); 73 } 74 75 std::set<WaveId> waveIds; 76 for (const TableId id : tableIds) 77 { 78 if(wave::isReadOnly(id)) 79 continue; 80 81 const auto idx = id.rawId(); 82 if(idx >= m_tables.size()) 83 continue; 84 85 const auto& t = m_tables[idx]; 86 if(!isValid(t)) 87 continue; 88 89 TableData table; 90 parseTableData(table, {t.begin(), t.end()}); 91 92 auto tableWaves = getWavesForTable(table); 93 94 for (const auto& waveId : tableWaves) 95 { 96 if(wave::isReadOnly(waveId)) 97 continue; 98 const auto waveIdx = waveId.rawId(); 99 if(waveIdx >= m_waves.size()) 100 continue; 101 const auto& wave = m_waves[waveIdx]; 102 if(!isValid(wave)) 103 continue; 104 waveIds.insert(waveId); 105 } 106 } 107 108 for (const auto& waveId : waveIds) 109 append(_state, m_waves[waveId.rawId()], 7); 110 111 for (const auto& tableId : tableIds) 112 append(_state, m_tables[tableId.rawId()], 7); 113 114 const auto multiMode = isMultiMode(); 115 116 // if we are in multimode, write multis last, otherwise, write singles last 117 // This causes the relevant things to be activated last when loading 118 if(multiMode) 119 { 120 for (const auto& s: m_currentInstrumentSingles) 121 append(_state, s, IdxSingleChecksumStart); 122 append(_state, m_currentMulti, IdxMultiChecksumStart); 123 for (const auto& s: m_currentMultiSingles) 124 append(_state, s, IdxSingleChecksumStart); 125 } 126 else 127 { 128 append(_state, m_currentMulti, IdxMultiChecksumStart); 129 for (const auto& s: m_currentMultiSingles) 130 append(_state, s, IdxSingleChecksumStart); 131 for (const auto& s: m_currentInstrumentSingles) 132 append(_state, s, IdxSingleChecksumStart); 133 } 134 135 return !_state.empty(); 136 } 137 138 bool State::receive(Responses& _responses, const synthLib::SMidiEvent& _data, Origin _sender) 139 { 140 if(!_data.sysex.empty()) 141 { 142 return receive(_responses, _data.sysex, _sender); 143 } 144 145 if (_sender == Origin::Device) 146 LOG("Recv: " << HEXN(_data.a, 2) << ' ' << HEXN(_data.b, 2) << ' ' << HEXN(_data.c, 2)); 147 148 switch(_data.a & 0xf0) 149 { 150 case synthLib::M_CONTROLCHANGE: 151 switch(_data.b) 152 { 153 case synthLib::MC_BANKSELECTMSB: 154 m_lastBankSelectMSB = _data; 155 break; 156 case synthLib::MC_BANKSELECTLSB: 157 m_lastBankSelectLSB = _data; 158 break; 159 default: 160 return false; 161 } 162 break; 163 case synthLib::M_PROGRAMCHANGE: 164 /* 165 switch(static_cast<BankSelectLSB>(m_lastBankSelectLSB.c)) 166 { 167 case BankSelectLSB::BsDeprecatedSingleBankA: 168 case BankSelectLSB::BsDeprecatedSingleBankB: 169 case BankSelectLSB::BsDeprecatedSingleBankC: 170 case BankSelectLSB::BsSingleBankA: 171 case BankSelectLSB::BsSingleBankB: 172 case BankSelectLSB::BsSingleBankC: 173 if(getGlobalParameter(GlobalParameter::SingleMultiMode) == 0) 174 requestSingle(LocationH::SingleEditBufferSingleMode, MidiSoundLocation::EditBufferCurrentSingle); 175 break; 176 case BankSelectLSB::BsMultiBank: 177 if(getGlobalParameter(GlobalParameter::SingleMultiMode) != 0) 178 requestMulti(LocationH::MultiEditBuffer, 0); 179 break; 180 default: 181 return false; 182 } 183 */ 184 break; 185 default: 186 return false; 187 } 188 return false; 189 } 190 191 bool State::receive(Responses& _responses, const SysEx& _data, const Origin _sender) 192 { 193 if(_data.size() == Mw1::g_singleDumpLength) 194 { 195 m_sender = _sender; 196 forwardToDevice(_data); 197 198 // MW1 dump doesn't contain any information about which part or bank it is loaded into, the first 199 // part is always the target 200 // Invalidate the currently cached single. We cannot do the conversion here, the hardware has to. 201 // The editor needs to request the single after sending a MW1 dump, which will fill our cache again 202 if(isMultiMode()) 203 m_currentMultiSingles[0].fill(0); 204 else 205 m_currentInstrumentSingles.front().fill(0); 206 return true; 207 } 208 209 const auto cmd = getCommand(_data); 210 211 if(cmd == SysexCommand::Invalid) 212 return false; 213 214 m_sender = _sender; 215 m_isEditBuffer = false; 216 217 switch (cmd) 218 { 219 case SysexCommand::SingleRequest: return getDump(DumpType::Single, _responses, _data); 220 case SysexCommand::MultiRequest: return getDump(DumpType::Multi,_responses, _data); 221 case SysexCommand::GlobalRequest: return getDump(DumpType::Global, _responses, _data); 222 case SysexCommand::ModeRequest: return getDump(DumpType::Mode, _responses, _data); 223 case SysexCommand::WaveRequest: return getDump(DumpType::Wave, _responses, _data); 224 case SysexCommand::WaveCtlRequest: return getDump(DumpType::Table, _responses, _data); 225 226 case SysexCommand::SingleDump: return parseDump(DumpType::Single, _data); 227 case SysexCommand::MultiDump: return parseDump(DumpType::Multi, _data); 228 case SysexCommand::GlobalDump: return parseDump(DumpType::Global, _data); 229 case SysexCommand::ModeDump: return parseDump(DumpType::Mode, _data); 230 case SysexCommand::WaveDump: return parseDump(DumpType::Wave, _data); 231 case SysexCommand::WaveCtlDump: return parseDump(DumpType::Table, _data); 232 233 case SysexCommand::SingleParameterChange: return modifyDump(DumpType::Single, _data); 234 case SysexCommand::MultiParameterChange: return modifyDump(DumpType::Multi, _data); 235 case SysexCommand::GlobalParameterChange: return modifyDump(DumpType::Global, _data); 236 case SysexCommand::ModeParameterChange: return modifyDump(DumpType::Mode, _data); 237 238 case SysexCommand::WaveDumpP: return m_wavePreview.receiveWave(_data); 239 case SysexCommand::WaveCtlDumpP: return m_wavePreview.receiveWaveControlTable(_data); 240 case SysexCommand::WavePreviewMode: return m_wavePreview.receiveWavePreviewMode(_data); 241 242 /* case SysexCommand::EmuLCD: 243 case SysexCommand::EmuLEDs: 244 case SysexCommand::EmuButtons: 245 case SysexCommand::EmuRotaries: 246 return false; 247 */ default: 248 return false; 249 } 250 } 251 252 void State::createInitState() 253 { 254 // request global settings and wait for them. Once they are valid, send init state 255 requestGlobal(); 256 requestMode(); 257 258 synthLib::MidiBufferParser parser; 259 Responses unused; 260 std::vector<uint8_t> midi; 261 std::vector<synthLib::SMidiEvent> events; 262 263 while(!isValid(m_global) || !isValid(m_mode)) 264 { 265 m_xt.process(8); 266 midi.clear(); 267 m_xt.receiveMidi(midi); 268 parser.write(midi); 269 270 events.clear(); 271 parser.getEvents(events); 272 273 for (const auto & event : events) 274 { 275 if(!event.sysex.empty()) 276 { 277 if(!receive(unused, event.sysex, Origin::Device)) 278 assert(false); 279 } 280 } 281 } 282 283 auto setParam = [&](const GlobalParameter _param, const uint8_t _value) 284 { 285 sendGlobalParameter(_param, _value); 286 }; 287 288 setParam(GlobalParameter::StartupSoundbank, 0); // First bank 289 setParam(GlobalParameter::StartupSoundNum, 0); // First sound 290 setParam(GlobalParameter::StartupMultiNumber, 0); // First Multi 291 292 setParam(GlobalParameter::ProgramChangeMode, 0); // single 293 setParam(GlobalParameter::MasterTune, 64); // 440 Hz 294 setParam(GlobalParameter::Transpose, 64); // +/- 0 295 setParam(GlobalParameter::ParameterSend, 2); // SysEx 296 setParam(GlobalParameter::ParameterReceive, 1); // on 297 setParam(GlobalParameter::ArpNoteOutChannel, 0); // off 298 setParam(GlobalParameter::MidiClockOutput, 0); // off 299 setParam(GlobalParameter::MidiChannel, 1); // omni 300 setParam(GlobalParameter::DeviceId, 0); // 0 301 setParam(GlobalParameter::InputGain, 3); // 4 302 303 receive(unused, convertTo(m_global), Origin::External); 304 } 305 306 bool State::setState(const std::vector<uint8_t>& _state, synthLib::StateType _type) 307 { 308 return loadState(_state); 309 } 310 311 void State::process(const uint32_t _numSamples) 312 { 313 for (auto it = m_delayedCalls.begin(); it != m_delayedCalls.end();) 314 { 315 auto& delay = it->first; 316 auto& call = it->second; 317 318 delay -= static_cast<int32_t>(_numSamples); 319 320 if (delay <= 0) 321 { 322 call(); 323 it = m_delayedCalls.erase(it); 324 } 325 else 326 { 327 ++it; 328 } 329 } 330 } 331 332 bool State::setSingleName(std::vector<uint8_t>& _sysex, const std::string& _name) 333 { 334 if (_sysex.size() != std::tuple_size_v<Single>) 335 return false; 336 337 if (getCommand(_sysex) != SysexCommand::SingleDump) 338 return false; 339 340 for (size_t i=0; i<mw2::g_singleNameLength; ++i) 341 _sysex[i + mw2::g_singleNamePosition] = i >= _name.size() ? ' ' : _name[i]; 342 return true; 343 } 344 345 TableId State::getWavetableFromSingleDump(const SysEx& _single) 346 { 347 constexpr auto wavetableIndex = IdxSingleParamFirst + static_cast<uint32_t>(SingleParameter::Wavetable); 348 349 if(wavetableIndex >= _single.size()) 350 return TableId::invalid(); 351 352 return TableId(_single[wavetableIndex]); 353 } 354 355 bool State::parseSingleDump(const SysEx& _data) 356 { 357 Single single; 358 359 if(!convertTo(single, _data)) 360 return false; 361 362 const auto buf = static_cast<LocationH>(_data[wLib::IdxBuffer]); 363 const auto loc = _data[wLib::IdxLocation]; 364 365 Single* dst = getSingle(buf, loc); 366 367 if(!dst) 368 return false; 369 *dst = single; 370 return true; 371 } 372 373 bool State::parseMultiDump(const SysEx& _data) 374 { 375 Multi multi; 376 377 if(!convertTo(multi, _data)) 378 return false; 379 380 const auto buf = static_cast<LocationH>(_data[wLib::IdxBuffer]); 381 const auto loc = _data[wLib::IdxLocation]; 382 383 auto* m = getMulti(buf, loc); 384 if(!m) 385 return false; 386 *m = multi; 387 return true; 388 } 389 390 bool State::parseGlobalDump(const SysEx& _data) 391 { 392 return convertTo(m_global, _data); 393 } 394 395 bool State::parseModeDump(const SysEx& _data) 396 { 397 if(!convertTo(m_mode, _data)) 398 return false; 399 onPlayModeChanged(); 400 return true; 401 } 402 403 bool State::parseWaveDump(const SysEx& _data) 404 { 405 const auto idx = getWaveId(_data).rawId(); 406 407 if(idx >= m_waves.size()) 408 return false; 409 410 const auto old = m_waves[idx]; 411 412 if(!convertTo(m_waves[idx], _data)) 413 return false; 414 415 if (m_waves[idx] == old) 416 return true; 417 418 forwardToDevice(_data); 419 420 return true; 421 } 422 423 bool State::parseTableDump(const SysEx& _data) 424 { 425 const auto idx = getTableId(_data).rawId(); 426 427 if(idx >= m_tables.size()) 428 return false; 429 430 if(!convertTo(m_tables[idx], _data)) 431 return false; 432 433 return true; 434 } 435 436 bool State::modifySingle(const SysEx& _data) 437 { 438 auto* p = getSingleParameter(_data); 439 if(!p) 440 return false; 441 *p = _data[IdxSingleParamValue]; 442 return true; 443 } 444 445 bool State::modifyMulti(const SysEx& _data) 446 { 447 auto* p = getMultiParameter(_data); 448 if(!p) 449 return false; 450 451 *p = _data[IdxMultiParamValue]; 452 return true; 453 } 454 455 bool State::modifyGlobal(const SysEx& _data) 456 { 457 auto* p = getGlobalParameter(_data); 458 if(!p) 459 return false; 460 461 if(*p == _data[IdxGlobalParamValue]) 462 return true; 463 464 *p = _data[IdxGlobalParamValue]; 465 466 return true; 467 } 468 469 bool State::modifyMode(const SysEx& _data) 470 { 471 auto* p = getModeParameter(_data); 472 if(!p) 473 return false; 474 475 *p = _data[IdxModeParamValue]; 476 477 onPlayModeChanged(); 478 479 return true; 480 } 481 482 namespace 483 { 484 template<size_t Size> 485 uint8_t* getParameter(std::array<uint8_t, Size>& _dump, const SysEx& _data, State::DumpType _type) 486 { 487 const auto& dump = State::Dumps[static_cast<uint32_t>(_type)]; 488 489 if(dump.idxParamIndexH >= _data.size() || dump.idxParamIndexL >= _data.size()) 490 return nullptr; 491 492 auto i = dump.firstParamIndex; 493 if (dump.idxParamIndexH != dump.idxParamIndexL) 494 i += static_cast<uint32_t>(_data[dump.idxParamIndexH]) << 7; 495 i += static_cast<uint32_t>(_data[dump.idxParamIndexL]); 496 497 if(i > _dump.size()) 498 return nullptr; 499 return &_dump[i]; 500 } 501 } 502 503 uint8_t* State::getSingleParameter(const SysEx& _data) 504 { 505 const auto loc = _data[wLib::IdxBuffer]; 506 507 Single* s = getSingle(isMultiMode() ? LocationH::SingleEditBufferMultiMode : LocationH::SingleEditBufferSingleMode, loc); 508 if(!s) 509 return nullptr; 510 return getParameter(*s, _data, DumpType::Single); 511 } 512 513 uint8_t* State::getMultiParameter(const SysEx& _data) 514 { 515 const auto& dump = Dumps[static_cast<uint8_t>(DumpType::Multi)]; 516 517 const auto idxH = _data[dump.idxParamIndexH]; 518 const auto idxL = _data[dump.idxParamIndexL]; 519 // const auto val = _data[dump.idxParamValue]; 520 521 if(idxH == 0x20) 522 return &m_currentMulti[dump.firstParamIndex + idxL]; 523 524 constexpr auto inst0 = static_cast<uint8_t>(MultiParameter::Inst0First); 525 constexpr auto inst1 = static_cast<uint8_t>(MultiParameter::Inst1First); 526 527 const auto idx = dump.firstParamIndex + inst0 + idxH * (inst1 - inst0) + idxL; 528 529 return &m_currentMulti[idx]; 530 } 531 532 uint8_t* State::getGlobalParameter(const SysEx& _data) 533 { 534 return getParameter(m_global, _data, DumpType::Global); 535 } 536 537 uint8_t* State::getModeParameter(const SysEx& _data) 538 { 539 return getParameter(m_mode, _data, DumpType::Mode); 540 } 541 542 bool State::getSingle(Responses& _responses, const SysEx& _data) 543 { 544 const auto buf = static_cast<LocationH>(_data[wLib::IdxBuffer]); 545 const auto loc = _data[wLib::IdxLocation]; 546 547 const auto* s = getSingle(buf, loc); 548 if(!s || !isValid(*s)) 549 return false; 550 _responses.push_back(convertTo(*s)); 551 return true; 552 } 553 554 State::Single* State::getSingle(LocationH _buf, uint8_t _loc) 555 { 556 switch (_buf) 557 { 558 case LocationH::SingleBankA: 559 if(_loc >= 128) 560 return nullptr; 561 return &m_romSingles[_loc]; 562 case LocationH::SingleBankB: 563 if(_loc >= 128) 564 return nullptr; 565 return &m_romSingles[_loc + 100]; 566 case LocationH::SingleEditBufferSingleMode: 567 m_isEditBuffer = true; 568 return m_currentInstrumentSingles.data(); 569 case LocationH::SingleEditBufferMultiMode: 570 { 571 m_isEditBuffer = true; 572 if(_loc >= m_currentMultiSingles.size()) 573 return nullptr; 574 return &m_currentMultiSingles[_loc]; 575 } 576 default: 577 return nullptr; 578 } 579 } 580 581 bool State::getMulti(Responses& _responses, const SysEx& _data) 582 { 583 const auto buf = static_cast<LocationH>(_data[wLib::IdxBuffer]); 584 const auto loc = _data[wLib::IdxLocation]; 585 586 const auto* m = getMulti(buf, loc); 587 if(!m || !isValid(*m)) 588 return false; 589 _responses.push_back(convertTo(*m)); 590 return true; 591 } 592 593 State::Multi* State::getMulti(LocationH buf, uint8_t loc) 594 { 595 switch (buf) 596 { 597 case LocationH::MultiDumpMultiEditBuffer: 598 m_isEditBuffer = true; 599 return &m_currentMulti; 600 case LocationH::MultiBankA: 601 if(loc >= m_romMultis.size()) 602 return nullptr; 603 return &m_romMultis[loc]; 604 default: 605 return nullptr; 606 } 607 } 608 609 bool State::getGlobal(Responses& _responses) 610 { 611 const auto* g = getGlobal(); 612 if(g == nullptr) 613 return false; 614 _responses.push_back(convertTo(*g)); 615 return true; 616 } 617 618 State::Global* State::getGlobal() 619 { 620 if(isValid(m_global)) 621 { 622 m_isEditBuffer = true; 623 return &m_global; 624 } 625 return nullptr; 626 } 627 628 bool State::getMode(Responses& _responses) 629 { 630 const auto* m = getMode(); 631 if(m == nullptr) 632 return false; 633 _responses.push_back(convertTo(*m)); 634 return true; 635 } 636 637 State::Mode* State::getMode() 638 { 639 if(isValid(m_mode)) 640 { 641 m_isEditBuffer = true; 642 return &m_mode; 643 } 644 return nullptr; 645 } 646 647 bool State::getWave(Responses& _responses, const SysEx& _data) 648 { 649 const auto idx = getWaveId(_data); 650 651 auto* w = getWave(idx); 652 if(!w || !isValid(*w)) 653 return false; 654 _responses.emplace_back(w->begin(), w->end()); 655 return true; 656 } 657 658 State::Wave* State::getWave(const WaveId _id) 659 { 660 const auto idx = _id.rawId(); 661 if(idx >= m_waves.size()) 662 return nullptr; 663 return &m_waves[idx]; 664 } 665 666 bool State::getTable(Responses& _responses, const SysEx& _data) 667 { 668 const auto idx = getTableId(_data); 669 670 auto* t = getTable(idx); 671 if(!t || !isValid(*t)) 672 return false; 673 _responses.emplace_back(t->begin(), t->end()); 674 return true; 675 } 676 677 State::Table* State::getTable(const TableId _id) 678 { 679 const auto idx = _id.rawId(); 680 if(idx >= m_tables.size()) 681 return nullptr; 682 return &m_tables[idx]; 683 } 684 685 bool State::getDump(const DumpType _type, Responses& _responses, const SysEx& _data) 686 { 687 bool res; 688 689 switch (_type) 690 { 691 case DumpType::Single: res = getSingle(_responses, _data); break; 692 case DumpType::Multi: res = getMulti(_responses, _data); break; 693 case DumpType::Global: res = getGlobal(_responses); break; 694 case DumpType::Mode: res = getMode(_responses); break; 695 case DumpType::Wave: res = getWave(_responses, _data); break; 696 case DumpType::Table: res = getTable(_responses, _data); break; 697 default: 698 return false; 699 } 700 701 if(!res) 702 forwardToDevice(_data); 703 return true; 704 } 705 706 bool State::parseDump(DumpType _type, const SysEx& _data) 707 { 708 bool res; 709 switch (_type) 710 { 711 case DumpType::Single: res = parseSingleDump(_data); break; 712 case DumpType::Multi: res = parseMultiDump(_data); break; 713 case DumpType::Global: res = parseGlobalDump(_data); break; 714 case DumpType::Mode: res = parseModeDump(_data); break; 715 case DumpType::Wave: res = parseWaveDump(_data); break; 716 case DumpType::Table: res = parseTableDump(_data); break; 717 default: 718 return false; 719 } 720 721 if(res && _type != DumpType::Wave) 722 forwardToDevice(_data); 723 return res; 724 } 725 726 bool State::modifyDump(DumpType _type, const SysEx& _data) 727 { 728 bool res; 729 switch (_type) 730 { 731 case DumpType::Single: res = modifySingle(_data); break; 732 case DumpType::Multi: res = modifyMulti(_data); break; 733 case DumpType::Global: res = modifyGlobal(_data); break; 734 case DumpType::Mode: res = modifyMode(_data); break; 735 default: 736 return false; 737 } 738 if(res) 739 forwardToDevice(_data); 740 return res; 741 } 742 743 uint8_t State::getGlobalParameter(const GlobalParameter _parameter) const 744 { 745 return m_global[static_cast<uint32_t>(_parameter) + IdxGlobalParamFirst]; 746 } 747 748 void State::setGlobalParameter(GlobalParameter _parameter, uint8_t _value) 749 { 750 m_global[static_cast<uint32_t>(_parameter) + IdxGlobalParamFirst] = _value; 751 } 752 753 uint8_t State::getModeParameter(const ModeParameter _parameter) const 754 { 755 return m_mode[static_cast<uint32_t>(_parameter) + IdxModeParamFirst]; 756 } 757 758 SysexCommand State::getCommand(const SysEx& _data) 759 { 760 if (_data.size() < 5) 761 return SysexCommand::Invalid; 762 763 if (_data.front() != 0xf0 || _data.back() != 0xf7) 764 return SysexCommand::Invalid; 765 766 if (_data[wLib::IdxIdWaldorf] != wLib::IdWaldorf || _data[wLib::IdxIdMachine] != IdMw2) 767 return SysexCommand::Invalid; 768 769 return static_cast<SysexCommand>(_data[wLib::IdxCommand]); 770 } 771 772 TableId State::getTableId(const SysEx& _data) 773 { 774 if (_data.size() == Mw1::g_tableDumpLength) 775 return TableId(_data[5] + wave::g_firstRamTableIndex - Mw1::g_firstRamTableIndex); 776 return TableId(static_cast<uint16_t>((_data[IdxWaveIndexH] << 7) | _data[IdxWaveIndexL])); 777 } 778 779 WaveId State::getWaveId(const SysEx& _data) 780 { 781 if (_data.size() == Mw1::g_waveDumpLength) 782 { 783 const uint16_t id = 784 static_cast<uint16_t>(_data[5] << 12) | 785 static_cast<uint16_t>(_data[6] << 8) | 786 static_cast<uint16_t>(_data[7] << 4) | 787 static_cast<uint16_t>(_data[8]); 788 789 return WaveId(static_cast<uint16_t>(id + wave::g_firstRamWaveIndex - Mw1::g_firstRamWaveIndex)); 790 } 791 return WaveId(static_cast<uint16_t>((_data[IdxWaveIndexH] << 7) | _data[IdxWaveIndexL])); 792 } 793 794 bool State::isSpeech(const TableData& _table) 795 { 796 return _table[0].rawId() == 0xdead && _table[1].rawId() == 0xbeef; 797 } 798 799 bool State::isUpaw(const TableData& _table) 800 { 801 return _table[0].rawId() == 0x12de && _table[1].rawId() == 0xc0de; 802 } 803 804 void State::forwardToDevice(const SysEx& _data) 805 { 806 if(m_sender != Origin::External) 807 return; 808 809 sendSysex(_data); 810 811 switch (getCommand(_data)) 812 { 813 case SysexCommand::WaveDump: 814 // there is an annoying bug in the XT 815 // A wave that is edited that is part of a table that is used in one of the current singles is not updated 816 // The workaround is to send a table dump with different waves and then the one with the correct waves 817 { 818 const auto waveId = getWaveId(_data); 819 820 std::set<TableId> dirtyTables; 821 822 auto checkTable = [&](const TableId _id) 823 { 824 if (wave::isReadOnly(_id)) 825 return false; 826 const auto idx = _id.rawId(); 827 if (idx >= m_tables.size()) 828 return false; 829 if (dirtyTables.find(_id) != dirtyTables.end()) 830 return true; 831 const auto& t = m_tables[idx]; 832 if (!isValid(t)) 833 return false; 834 TableData table; 835 if (!parseTableData(table, { t.begin(), t.end() })) 836 return false; 837 auto waves = getWavesForTable(table); 838 const auto it = std::find(waves.begin(), waves.end(), waveId); 839 if (it == waves.end()) 840 return false; 841 dirtyTables.insert(_id); 842 return true; 843 }; 844 845 if (isMultiMode()) 846 { 847 for (auto& s : m_currentMultiSingles) 848 { 849 const auto tableId = getWavetableFromSingleDump({ s.begin(), s.end() }); 850 checkTable(tableId); 851 } 852 } 853 else 854 { 855 const auto tableId = getWavetableFromSingleDump({m_currentInstrumentSingles.front().begin(), m_currentInstrumentSingles.front().end()}); 856 checkTable(tableId); 857 } 858 859 for (const auto& tableId : dirtyTables) 860 { 861 const auto& originalTable = m_tables[tableId.rawId()]; 862 SysEx originalTableSysex = SysEx(originalTable.begin(), originalTable.end()); 863 864 TableData table; 865 parseTableData(table, originalTableSysex); 866 auto waves = getWavesForTable(table); 867 868 // modify table to use a different wave 869 for (auto& idx : waves) 870 { 871 if (idx == waveId) 872 idx = WaveId(waveId.rawId() > 1000 ? 1000 : 1001); 873 } 874 875 // send the modified table to the device 876 auto modifiedTableSysex = createTableData(table, tableId.rawId(), false); 877 878 sendSysex(std::move(modifiedTableSysex)); 879 880 // after a delay, send the original table again 881 constexpr auto delaySamples = static_cast<uint32_t>(40000 * 0.8f); 882 883 m_delayedCalls.emplace_back(delaySamples, [this, tableId] 884 { 885 const auto& t = m_tables[tableId.rawId()]; 886 SysEx s = SysEx(t.begin(), t.end()); 887 sendSysex(std::move(s)); 888 }); 889 } 890 } 891 break; 892 default:; 893 } 894 } 895 896 void State::requestGlobal() const 897 { 898 sendSysex({0xf0, wLib::IdWaldorf, IdMw2, wLib::IdDeviceOmni, static_cast<uint8_t>(SysexCommand::GlobalRequest), 0xf7}); 899 } 900 901 void State::requestMode() const 902 { 903 sendSysex({0xf0, wLib::IdWaldorf, IdMw2, wLib::IdDeviceOmni, static_cast<uint8_t>(SysexCommand::ModeRequest), 0xf7}); 904 } 905 906 void State::requestSingle(LocationH _buf, uint8_t _location) const 907 { 908 sendSysex({0xf0, wLib::IdWaldorf, IdMw2, wLib::IdDeviceOmni, static_cast<uint8_t>(SysexCommand::SingleRequest), static_cast<uint8_t>(_buf), static_cast<uint8_t>(_location), 0xf7}); 909 } 910 911 void State::requestMulti(LocationH _buf, uint8_t _location) const 912 { 913 sendSysex({0xf0, wLib::IdWaldorf, IdMw2, wLib::IdDeviceOmni, static_cast<uint8_t>(SysexCommand::MultiRequest), static_cast<uint8_t>(_buf), _location, 0xf7}); 914 } 915 916 void State::sendMulti(const std::vector<uint8_t>& _multiData) const 917 { 918 std::vector<uint8_t> data = { 0xf0, wLib::IdWaldorf, IdMw2, wLib::IdDeviceOmni, static_cast<uint8_t>(SysexCommand::MultiDump), static_cast<uint8_t>(LocationH::MultiBankA), 0}; 919 data.insert(data.end(), _multiData.begin(), _multiData.end()); 920 data.push_back(0x00); 921 data.push_back(0xf7); 922 updateChecksum(data, IdxMultiChecksumStart); 923 sendSysex(std::move(data)); 924 } 925 926 void State::sendGlobalParameter(GlobalParameter _param, uint8_t _value) 927 { 928 setGlobalParameter(_param, _value); 929 930 const auto p = static_cast<uint8_t>(_param); 931 932 sendSysex({0xf0, wLib::IdWaldorf, IdMw2, wLib::IdDeviceOmni, static_cast<uint8_t>(SysexCommand::GlobalParameterChange), 933 static_cast<uint8_t>(p >> 7), static_cast<uint8_t>(p & 0x7f), _value, 0xf7}); 934 } 935 936 void State::sendMultiParameter(const uint8_t _instrument, MultiParameter _param, const uint8_t _value) 937 { 938 const SysEx sysex{0xf0, wLib::IdWaldorf, IdMw2, wLib::IdDeviceOmni, static_cast<uint8_t>(SysexCommand::MultiParameterChange), 939 _instrument, static_cast<uint8_t>(static_cast<uint8_t>(_param) - static_cast<uint8_t>(MultiParameter::Inst0First)), _value, 0xf7}; 940 941 Responses responses; 942 receive(responses, sysex, Origin::External); 943 } 944 945 void State::sendSysex(const std::initializer_list<uint8_t>& _data) const 946 { 947 synthLib::SMidiEvent e(synthLib::MidiEventSource::Internal); 948 e.sysex = _data; 949 m_xt.sendMidiEvent(e); 950 } 951 952 void State::sendSysex(const SysEx& _data) const 953 { 954 synthLib::SMidiEvent e(synthLib::MidiEventSource::Internal); 955 e.sysex = _data; 956 m_xt.sendMidiEvent(e); 957 } 958 959 void State::sendSysex(SysEx&& _data) const 960 { 961 synthLib::SMidiEvent e(synthLib::MidiEventSource::Internal); 962 e.sysex = std::move(_data); 963 m_xt.sendMidiEvent(e); 964 } 965 966 void State::createSequencerMultiData(std::vector<uint8_t>& _data) 967 { 968 assert(false); 969 /* 970 static_assert( 971 (static_cast<uint32_t>(MultiParameter::Inst15) - static_cast<uint32_t>(MultiParameter::Inst0)) == 972 (static_cast<uint32_t>(MultiParameter::Inst1) - static_cast<uint32_t>(MultiParameter::Inst0)) * 15, 973 "we need a consecutive offset"); 974 975 _data.assign(static_cast<uint32_t>(xt::MultiParameter::Count), 0); 976 977 constexpr char name[] = "From TUS with <3"; 978 static_assert(std::size(name) == 17, "wrong name length"); 979 memcpy(&_data[static_cast<uint32_t>(MultiParameter::Name00)], name, sizeof(name) - 1); 980 981 auto setParam = [&](MultiParameter _param, const uint8_t _value) 982 { 983 _data[static_cast<uint32_t>(_param)] = _value; 984 }; 985 986 auto setInstParam = [&](const uint8_t _instIndex, const MultiParameter _param, const uint8_t _value) 987 { 988 auto index = static_cast<uint32_t>(MultiParameter::Inst0) + (static_cast<uint32_t>(MultiParameter::Inst1) - static_cast<uint32_t>(MultiParameter::Inst0)) * _instIndex; 989 index += static_cast<uint32_t>(_param) - static_cast<uint32_t>(MultiParameter::Inst0); 990 _data[index] = _value; 991 }; 992 993 setParam(MultiParameter::Volume, 127); // max volume 994 995 setParam(MultiParameter::ControlW, 121); // global 996 setParam(MultiParameter::ControlX, 121); // global 997 setParam(MultiParameter::ControlY, 121); // global 998 setParam(MultiParameter::ControlZ, 121); // global 999 1000 for (uint8_t i = 0; i < 16; ++i) 1001 { 1002 setInstParam(i, MultiParameter::Inst0SoundBank, 0); // bank A 1003 setInstParam(i, MultiParameter::Inst0SoundNumber, i); // sound number i 1004 setInstParam(i, MultiParameter::Inst0MidiChannel, 2+i); // midi channel i 1005 setInstParam(i, MultiParameter::Inst0Volume, 127); // max volume 1006 setInstParam(i, MultiParameter::Inst0Transpose, 64); // no transpose 1007 setInstParam(i, MultiParameter::Inst0Detune, 64); // no detune 1008 setInstParam(i, MultiParameter::Inst0Output, 0); // main out 1009 setInstParam(i, MultiParameter::Inst0Flags, 3); // RX = Local+MIDI / TX = off / Engine = Play 1010 setInstParam(i, MultiParameter::Inst0Pan, 64); // center 1011 setInstParam(i, MultiParameter::Inst0Pattern, 0); // no pattern 1012 setInstParam(i, MultiParameter::Inst0VeloLow, 1); // full velocity range 1013 setInstParam(i, MultiParameter::Inst0VeloHigh, 127); 1014 setInstParam(i, MultiParameter::Inst0KeyLow, 0); // full key range 1015 setInstParam(i, MultiParameter::Inst0KeyHigh, 127); 1016 setInstParam(i, MultiParameter::Inst0MidiRxFlags, 63); // enable Pitchbend, Modwheel, Aftertouch, Sustain, Button 1/2, Program Change 1017 } 1018 */ 1019 } 1020 1021 namespace 1022 { 1023 void extractWaveDataFromSysEx(WaveData& _wave, const SysEx& _sysex, const uint32_t _off) 1024 { 1025 /* 1026 mw2_sysex.pdf: 1027 1028 "A Wave consists of 128 eight Bit samples, but only the first 64 of them are 1029 stored/transmitted, the second half is same as first except the values are 1030 negated and the order is reversed: 1031 1032 Wave[64+n] = -Wave[63-n] for n=0..63 1033 1034 Note that samples are not two's complement format, to get a signed byte, 1035 the most significant bit must be flipped: 1036 1037 signed char s = Wave[n] ^ 0x80" 1038 */ 1039 1040 for(uint32_t i=0; i<_wave.size()>>1; ++i) 1041 { 1042 const auto idx = _off + (i<<1); 1043 auto sample = (_sysex[idx]) << 4 | _sysex[idx+1]; 1044 sample = sample ^ 0x80; 1045 1046 _wave[i] = static_cast<int8_t>(sample); 1047 _wave[127-i] = static_cast<int8_t>(-sample); 1048 } 1049 } 1050 } 1051 1052 bool State::parseWaveData(WaveData& _wave, const SysEx& _sysex) 1053 { 1054 if(_sysex.size() != std::tuple_size_v<Wave>) 1055 return parseMw1WaveData(_wave, _sysex); 1056 1057 if(_sysex.front() != 0xf0 || _sysex[1] != wLib::IdWaldorf || _sysex[2] != IdMw2) 1058 return false; 1059 1060 if(_sysex[4] != static_cast<uint8_t>(SysexCommand::WaveDump) && _sysex[4] != static_cast<uint8_t>(SysexCommand::WaveDumpP)) 1061 return false; 1062 1063 constexpr auto off = 7; 1064 1065 extractWaveDataFromSysEx(_wave, _sysex, off); 1066 1067 return true; 1068 } 1069 1070 bool State::parseMw1WaveData(WaveData& _wave, const SysEx& _sysex) 1071 { 1072 if (_sysex.size() != Mw1::g_waveDumpLength) 1073 return false; 1074 1075 if(_sysex.front() != 0xf0 || _sysex[1] != wLib::IdWaldorf || _sysex[2] != IdMw1) 1076 return false; 1077 1078 if(_sysex[4] != Mw1::g_idmWave) 1079 return false; 1080 1081 constexpr auto off = 9; 1082 1083 extractWaveDataFromSysEx(_wave, _sysex, off); 1084 1085 return true; 1086 } 1087 1088 SysEx State::createWaveData(const WaveData& _wave, const uint16_t _waveIndex, const bool _preview) 1089 { 1090 const auto hh = static_cast<uint8_t>(_waveIndex >> 7); 1091 const auto ll = static_cast<uint8_t>(_waveIndex & 0x7f); 1092 1093 const std::initializer_list<uint8_t> header{0xf0, wLib::IdWaldorf, IdMw2, wLib::IdDeviceOmni, static_cast<uint8_t>(_preview ? SysexCommand::WaveDumpP : SysexCommand::WaveDump), hh, ll}; 1094 SysEx sysex{header}; 1095 sysex.reserve(sysex.size() + _wave.size()); 1096 1097 for(uint32_t i=0; i<_wave.size()>>1; ++i) 1098 { 1099 const int sample = static_cast<uint8_t>(_wave[i] ^ 0x80); 1100 1101 sysex.push_back(static_cast<uint8_t>(sample >> 4)); 1102 sysex.push_back(static_cast<uint8_t>(sample & 0xf)); 1103 } 1104 1105 sysex.push_back(0); 1106 sysex.push_back(0xf7); 1107 1108 updateChecksum(sysex, static_cast<uint32_t>(std::size(header))); 1109 1110 return sysex; 1111 } 1112 1113 WaveData State::createinterpolatedTable(const WaveData& _a, const WaveData& _b, uint16_t _indexA, uint16_t _indexB, uint16_t _indexTarget) 1114 { 1115 assert(_indexB > _indexA); 1116 assert(_indexTarget >= _indexA && _indexTarget <= _indexB); 1117 1118 xt::WaveData result; 1119 1120 const auto indexDelta = _indexB - _indexA; 1121 const auto targetDelta = _indexTarget - _indexA; 1122 1123 for(size_t i=0; i<_a.size(); ++i) 1124 { 1125 auto d = _b[i] - _a[i]; 1126 d *= targetDelta; 1127 d /= indexDelta; 1128 d += _a[i]; 1129 result[i] = static_cast<int8_t>(d); 1130 } 1131 return result; 1132 } 1133 1134 namespace 1135 { 1136 void extractTableDataFromSysEx(TableData& _table, const SysEx& _sysex, const uint32_t _off) 1137 { 1138 for(uint32_t i=0; i<_table.size(); ++i) 1139 { 1140 const auto i4 = i<<2; 1141 1142 auto waveIdx = _sysex[i4+_off] << 12; 1143 waveIdx |= _sysex[i4+_off+1] << 8; 1144 waveIdx |= _sysex[i4+_off+2] << 4; 1145 waveIdx |= _sysex[i4+_off+3]; 1146 1147 _table[i] = WaveId(static_cast<uint16_t>(waveIdx)); 1148 } 1149 } 1150 } 1151 1152 bool State::parseTableData(TableData& _table, const SysEx& _sysex) 1153 { 1154 if(_sysex.size() != std::tuple_size_v<Table>) 1155 return parseMw1TableData(_table, _sysex); 1156 1157 if(_sysex[0] != 0xf0 || _sysex[1] != wLib::IdWaldorf || _sysex[2] != IdMw2) 1158 return false; 1159 1160 if(_sysex[4] != static_cast<uint8_t>(SysexCommand::WaveCtlDump) && _sysex[4] != static_cast<uint8_t>(SysexCommand::WaveCtlDumpP)) 1161 return false; 1162 1163 constexpr uint32_t off = 7; 1164 1165 extractTableDataFromSysEx(_table, _sysex, off); 1166 1167 return true; 1168 } 1169 1170 bool State::parseMw1TableData(TableData& _table, const SysEx& _sysex) 1171 { 1172 if (_sysex.size() != Mw1::g_tableDumpLength) 1173 return false; 1174 1175 if(_sysex[0] != 0xf0 || _sysex[1] != wLib::IdWaldorf || _sysex[2] != IdMw1) 1176 return false; 1177 1178 extractTableDataFromSysEx(_table, _sysex, 6); 1179 1180 if (isSpeech(_table)) 1181 { 1182 _table[2] = WaveId(_table[2].rawId() + wave::g_firstRamWaveIndex - Mw1::g_firstRamWaveIndex); 1183 } 1184 else 1185 { 1186 for(auto & t : _table) 1187 t = WaveId(t.rawId() + wave::g_firstRamWaveIndex - Mw1::g_firstRamWaveIndex); 1188 } 1189 return true; 1190 } 1191 1192 std::vector<WaveId> State::getWavesForTable(const TableData& _table) 1193 { 1194 std::vector<WaveId> waves; 1195 1196 if (isSpeech(_table)) 1197 { 1198 const auto startWaveId = _table[2]; 1199 1200 waves.reserve(8); 1201 for (uint16_t i=0; i<8; ++i) 1202 waves.emplace_back(startWaveId.rawId() + i); 1203 } 1204 else if (isUpaw(_table)) 1205 { 1206 assert(false && "add support"); 1207 } 1208 else 1209 { 1210 waves.reserve(_table.size()); 1211 for (const auto& w : _table) 1212 waves.push_back(w); 1213 } 1214 1215 return waves; 1216 } 1217 1218 SysEx State::createTableData(const TableData& _table, const uint32_t _tableIndex, const bool _preview) 1219 { 1220 const auto hh = static_cast<uint8_t>(_tableIndex >> 7); 1221 const auto ll = static_cast<uint8_t>(_tableIndex & 0x7f); 1222 1223 const std::initializer_list<uint8_t> header{0xf0, wLib::IdWaldorf, IdMw2, wLib::IdDeviceOmni, static_cast<uint8_t>(_preview ? SysexCommand::WaveCtlDumpP : SysexCommand::WaveCtlDump), hh, ll}; 1224 SysEx sysex{header}; 1225 sysex.reserve(sysex.size() + _table.size() * 4 + 2); 1226 1227 for (const auto& e : _table) 1228 { 1229 const auto waveId = e.rawId(); 1230 1231 sysex.push_back((waveId >> 12) & 0xf); 1232 sysex.push_back((waveId >> 8 ) & 0xf); 1233 sysex.push_back((waveId >> 4 ) & 0xf); 1234 sysex.push_back((waveId ) & 0xf); 1235 } 1236 1237 sysex.push_back(0); 1238 sysex.push_back(0xf7); 1239 1240 updateChecksum(sysex, static_cast<uint32_t>(std::size(header))); 1241 1242 return sysex; 1243 } 1244 1245 bool State::splitCombinedPatch(std::vector<SysEx>& _dumps, const SysEx& _combinedSingle) 1246 { 1247 if(getCommand(_combinedSingle) != SysexCommand::SingleDump) 1248 return false; 1249 1250 constexpr auto singleSize = std::tuple_size_v<Single>; 1251 constexpr auto tableSize = std::tuple_size_v<Table>; 1252 constexpr auto waveSize = std::tuple_size_v<Wave>; 1253 1254 if(_combinedSingle.size() == singleSize) 1255 return false; 1256 1257 if(_combinedSingle.size() < singleSize + tableSize - 2) 1258 return false; 1259 1260 auto& single = _dumps.emplace_back(); 1261 size_t offBegin = 0; 1262 size_t offEnd = offBegin + singleSize - 1; 1263 single.assign(_combinedSingle.begin() + static_cast<ptrdiff_t>(offBegin), _combinedSingle.begin() + static_cast<ptrdiff_t>(offEnd)); 1264 single.push_back(0xf7); 1265 1266 auto& table = _dumps.emplace_back(); 1267 1268 offBegin = offEnd; 1269 offEnd += tableSize - 2; 1270 table.push_back(0xf0); 1271 table.insert(table.end(), _combinedSingle.begin() + static_cast<ptrdiff_t>(offBegin), _combinedSingle.begin() + static_cast<ptrdiff_t>(offEnd)); 1272 table.push_back(0xf7); 1273 1274 while(_combinedSingle.size() - offEnd >= waveSize - 2) 1275 { 1276 offBegin = offEnd; 1277 offEnd += waveSize - 2; 1278 1279 auto& wave = _dumps.emplace_back(); 1280 wave.push_back(0xf0); 1281 wave.insert(wave.end(), _combinedSingle.begin() + static_cast<ptrdiff_t>(offBegin), _combinedSingle.begin() + static_cast<ptrdiff_t>(offEnd)); 1282 wave.push_back(0xf7); 1283 } 1284 1285 return true; 1286 } 1287 1288 SysEx State::createCombinedPatch(const std::vector<SysEx>& _dumps) 1289 { 1290 uint32_t singleCount = 0; 1291 uint32_t tableCount = 0; 1292 1293 std::vector<SysEx> waves; 1294 1295 SysEx single; 1296 SysEx table; 1297 1298 for (auto& dump : _dumps) 1299 { 1300 switch(getCommand(dump)) 1301 { 1302 case SysexCommand::SingleDump: 1303 ++singleCount; 1304 single = dump; 1305 break; 1306 case SysexCommand::WaveCtlDump: 1307 ++tableCount; 1308 table = dump; 1309 break; 1310 case SysexCommand::WaveDump: 1311 waves.push_back(dump); 1312 break; 1313 default:; 1314 } 1315 } 1316 1317 if(!tableCount && waves.empty()) 1318 return single; 1319 1320 if(tableCount > 1) 1321 return {}; 1322 1323 // a combined single is a single dump + a table dump + an arbitrary number of wave dumps in one sysex, i.e. f0/f7 are stripped from the individual dumps 1324 single.pop_back(); 1325 1326 single.insert(single.end(), table.begin()+1, table.end()-1); 1327 1328 for (const auto& wave : waves) 1329 single.insert(single.end(), wave.begin()+1, wave.end()-1); 1330 1331 single.push_back(0xf7); 1332 1333 return single; 1334 } 1335 1336 void State::onPlayModeChanged() 1337 { 1338 // if the play mode is changed, force a re-request of the edit buffer for the first single again, because on the device, that edit buffer is shared between multi & single 1339 m_currentMultiSingles[0][0] = 0; 1340 m_currentInstrumentSingles[0][0] = 0; 1341 1342 // also, as the multi is not valid if the machine is not in multi mode, invalidate the existing data to force a re-request from the device 1343 if(isMultiMode()) 1344 m_currentMulti[0] = 0; 1345 } 1346 }