controller.cpp (17930B)
1 #include "controller.h" 2 3 #include <cassert> 4 #include <fstream> 5 6 #include "parameter.h" 7 #include "processor.h" 8 9 #include "dsp56kEmu/logging.h" 10 11 #include "juceUiLib/messageBox.h" 12 13 #include "synthLib/os.h" 14 15 namespace pluginLib 16 { 17 uint8_t getParameterValue(const Parameter* _p) 18 { 19 return static_cast<uint8_t>(_p->getUnnormalizedValue()); 20 } 21 22 Controller::Controller(Processor& _processor, const std::string& _parameterDescJsonFilename) 23 : m_processor(_processor) 24 , m_descriptions(loadParameterDescriptions(_parameterDescJsonFilename)) 25 , m_locking(*this) 26 , m_parameterLinks(*this) 27 { 28 if(!m_descriptions.isValid()) 29 { 30 genericUI::MessageBox::showOk(juce::MessageBoxIconType::WarningIcon, 31 _processor.getProperties().name + " - Failed to parse Parameter Descriptions json", 32 "Encountered errors while parsing parameter descriptions:\n\n" + m_descriptions.getErrors()); 33 } 34 } 35 36 Controller::~Controller() 37 { 38 stopTimer(); 39 m_softKnobs.clear(); 40 } 41 42 void Controller::registerParams(juce::AudioProcessor& _processor, Parameter::PartFormatter _partFormatter/* = nullptr*/) 43 { 44 auto globalParams = std::make_unique<juce::AudioProcessorParameterGroup>("global", "Global", "|"); 45 46 if(!_partFormatter) 47 { 48 _partFormatter = [](const uint8_t& _part, bool) 49 { 50 return juce::String("Ch ") + juce::String(_part + 1); 51 }; 52 } 53 std::map<ParamIndex, int> knownParameterIndices; 54 55 for (uint8_t part = 0; part < getPartCount(); part++) 56 { 57 m_paramsByParamType[part].reserve(m_descriptions.getDescriptions().size()); 58 59 const auto partNumber = juce::String(part + 1); 60 auto group = std::make_unique<juce::AudioProcessorParameterGroup>("ch" + partNumber, _partFormatter(part, false), "|"); 61 62 for (const auto& desc : m_descriptions.getDescriptions()) 63 { 64 const ParamIndex idx = {static_cast<uint8_t>(desc.page), part, desc.index}; 65 66 int uid = 0; 67 68 auto itKnownParamIdx = knownParameterIndices.find(idx); 69 70 if(itKnownParamIdx == knownParameterIndices.end()) 71 knownParameterIndices.insert(std::make_pair(idx, 0)); 72 else 73 uid = ++itKnownParamIdx->second; 74 75 std::unique_ptr<Parameter> p; 76 p.reset(createParameter(*this, desc, part, uid, _partFormatter)); 77 78 if(uid > 0) 79 { 80 const auto& existingParams = findSynthParam(idx); 81 82 for (auto& existingParam : existingParams) 83 { 84 if(isDerivedParameter(*existingParam, *p)) 85 existingParam->addDerivedParameter(p.get()); 86 } 87 } 88 89 const bool isNonPartExclusive = desc.isNonPartSensitive(); 90 91 if (isNonPartExclusive && part != 0) 92 { 93 // only register on first part! 94 m_paramsByParamType[part].push_back(m_paramsByParamType[0][m_paramsByParamType[part].size()]); 95 continue; 96 } 97 98 m_paramsByParamType[part].push_back(p.get()); 99 100 if (p->getDescription().isPublic) 101 { 102 // lifecycle managed by Juce 103 104 auto itExisting = m_synthParams.find(idx); 105 if (itExisting != m_synthParams.end()) 106 { 107 itExisting->second.push_back(p.get()); 108 } 109 else 110 { 111 ParameterList params; 112 params.emplace_back(p.get()); 113 m_synthParams.insert(std::make_pair(idx, std::move(params))); 114 } 115 116 if (isNonPartExclusive) 117 { 118 jassert(part == 0); 119 globalParams->addChild(std::move(p)); 120 } 121 else 122 group->addChild(std::move(p)); 123 } 124 else 125 { 126 // lifecycle handled by us 127 128 auto itExisting = m_synthInternalParams.find(idx); 129 if (itExisting != m_synthInternalParams.end()) 130 { 131 itExisting->second.push_back(p.get()); 132 } 133 else 134 { 135 ParameterList params; 136 params.emplace_back(p.get()); 137 m_synthInternalParams.insert(std::make_pair(idx, std::move(params))); 138 } 139 m_synthInternalParamList.emplace_back(std::move(p)); 140 } 141 } 142 _processor.addParameterGroup(std::move(group)); 143 } 144 145 _processor.addParameterGroup(std::move(globalParams)); 146 147 // initialize all soft knobs for all parts 148 std::vector<size_t> softKnobs; 149 150 for (size_t i=0; i<m_descriptions.getDescriptions().size(); ++i) 151 { 152 const auto& desc = m_descriptions.getDescriptions()[i]; 153 if(!desc.isSoftKnob()) 154 continue; 155 softKnobs.push_back(i); 156 } 157 158 for(size_t part = 0; part<getPartCount(); ++part) 159 { 160 for (const auto& softKnobParam : softKnobs) 161 { 162 auto* sk = new SoftKnob(*this, static_cast<uint8_t>(part), static_cast<uint32_t>(softKnobParam)); 163 m_softKnobs.insert({sk->getParameter(), std::unique_ptr<SoftKnob>(sk)}); 164 } 165 } 166 } 167 168 void Controller::sendSysEx(const pluginLib::SysEx& _msg) const 169 { 170 synthLib::SMidiEvent ev(synthLib::MidiEventSource::Editor); 171 ev.sysex = _msg; 172 sendMidiEvent(ev); 173 } 174 175 void Controller::sendMidiEvent(const synthLib::SMidiEvent& _ev) const 176 { 177 m_processor.addMidiEvent(_ev); 178 } 179 180 void Controller::sendMidiEvent(const uint8_t _a, const uint8_t _b, const uint8_t _c, const uint32_t _offset/* = 0*/, const synthLib::MidiEventSource _source/* = synthLib::MidiEventSource::Editor*/) const 181 { 182 m_processor.addMidiEvent(synthLib::SMidiEvent(_source, _a, _b, _c, _offset)); 183 } 184 185 bool Controller::combineParameterChange(uint8_t& _result, const std::string& _midiPacket, const Parameter& _parameter, ParamValue _value) const 186 { 187 const auto &desc = _parameter.getDescription(); 188 189 std::map<MidiDataType, uint8_t> data; 190 191 const auto *packet = getMidiPacket(_midiPacket); 192 193 if (!packet) 194 { 195 LOG("Failed to find midi packet " << _midiPacket); 196 return false; 197 } 198 199 const ParamIndex idx = {static_cast<uint8_t>(desc.page), _parameter.getPart(), desc.index}; 200 201 const auto params = findSynthParam(idx); 202 203 uint32_t byte = MidiPacket::InvalidIndex; 204 205 for (auto param : params) 206 { 207 byte = packet->getByteIndexForParameterName(param->getDescription().name); 208 if (byte != MidiPacket::InvalidIndex) 209 break; 210 } 211 212 if (byte == MidiPacket::InvalidIndex) 213 { 214 LOG("Failed to find byte index for parameter " << desc.name); 215 return false; 216 } 217 218 std::vector<const MidiPacket::MidiDataDefinition*> definitions; 219 220 if(!packet->getDefinitionsForByteIndex(definitions, byte)) 221 return false; 222 223 if (definitions.size() == 1) 224 { 225 _result = static_cast<uint8_t>(_value); 226 return true; 227 } 228 229 _result = 0; 230 231 for (const auto& it : definitions) 232 { 233 uint32_t i = 0; 234 235 if(!m_descriptions.getIndexByName(i, it->paramName)) 236 { 237 LOG("Failed to find index for parameter " << it->paramName); 238 return false; 239 } 240 241 auto* p = getParameter(i, _parameter.getPart()); 242 const auto v = p == &_parameter ? _value : getParameterValue(p); 243 _result |= it->packValue(v); 244 } 245 246 return true; 247 } 248 249 void Controller::applyPatchParameters(const MidiPacket::ParamValues& _params, const uint8_t _part) const 250 { 251 for (const auto& it : _params) 252 { 253 auto* p = getParameter(it.first.second, _part); 254 p->setValueFromSynth(it.second, pluginLib::Parameter::Origin::PresetChange); 255 256 for (const auto& derivedParam : p->getDerivedParameters()) 257 derivedParam->setValueFromSynth(it.second, pluginLib::Parameter::Origin::PresetChange); 258 } 259 260 getProcessor().updateHostDisplay(juce::AudioProcessorListener::ChangeDetails().withProgramChanged(true)); 261 } 262 263 void Controller::timerCallback() 264 { 265 processMidiMessages(); 266 } 267 268 bool Controller::sendSysEx(const std::string& _packetName) const 269 { 270 return sendSysEx(_packetName, {}); 271 } 272 273 bool Controller::sendSysEx(const std::string& _packetName, const std::map<MidiDataType, uint8_t>& _params) const 274 { 275 std::vector<uint8_t> sysex; 276 277 if(!createMidiDataFromPacket(sysex, _packetName, _params, 0)) 278 return false; 279 280 sendSysEx(sysex); 281 return true; 282 } 283 284 const Controller::ParameterList& Controller::findSynthParam(const uint8_t _part, const uint8_t _page, const uint8_t _paramIndex) const 285 { 286 const ParamIndex paramIndex{ _page, _part, _paramIndex }; 287 288 return findSynthParam(paramIndex); 289 } 290 291 const Controller::ParameterList& Controller::findSynthParam(const ParamIndex& _paramIndex) const 292 { 293 const auto it = m_synthParams.find(_paramIndex); 294 295 if (it != m_synthParams.end()) 296 return it->second; 297 298 const auto iti = m_synthInternalParams.find(_paramIndex); 299 300 if (iti == m_synthInternalParams.end()) 301 { 302 static ParameterList empty; 303 return empty; 304 } 305 306 return iti->second; 307 } 308 309 void Controller::sendLockedParameters(const uint8_t _part) 310 { 311 const auto lockedParameters = m_locking.getLockedParameters(_part); 312 313 for (const auto& p : lockedParameters) 314 { 315 const auto v = p->getUnnormalizedValue(); 316 sendParameterChange(*p, static_cast<uint8_t>(v)); 317 } 318 } 319 320 juce::Value* Controller::getParamValueObject(const uint32_t _index, const uint8_t _part) const 321 { 322 const auto res = getParameter(_index, _part); 323 return res ? &res->getValueObject() : nullptr; 324 } 325 326 Parameter* Controller::getParameter(const uint32_t _index) const 327 { 328 return getParameter(_index, 0); 329 } 330 331 Parameter* Controller::getParameter(const uint32_t _index, const uint8_t _part) const 332 { 333 if (_part >= m_paramsByParamType.size()) 334 return nullptr; 335 336 if (_index >= m_paramsByParamType[_part].size()) 337 return nullptr; 338 339 return m_paramsByParamType[_part][_index]; 340 } 341 342 Parameter* Controller::getParameter(const std::string& _name, const uint8_t _part) const 343 { 344 const auto idx = getParameterIndexByName(_name); 345 if(idx == InvalidParameterIndex) 346 return nullptr; 347 return getParameter(idx, _part); 348 } 349 350 uint32_t Controller::getParameterIndexByName(const std::string& _name) const 351 { 352 uint32_t index; 353 return m_descriptions.getIndexByName(index, _name) ? index : InvalidParameterIndex; 354 } 355 356 bool Controller::setParameters(const std::map<std::string, ParamValue>& _values, const uint8_t _part, const Parameter::Origin _changedBy) const 357 { 358 bool res = false; 359 360 for (const auto& it : _values) 361 { 362 const auto& name = it.first; 363 const auto& value = it.second; 364 365 if(auto* param = getParameter(name, _part)) 366 { 367 res = true; 368 param->setUnnormalizedValueNotifyingHost(value, _changedBy); 369 } 370 } 371 372 return res; 373 } 374 375 const MidiPacket* Controller::getMidiPacket(const std::string& _name) const 376 { 377 return m_descriptions.getMidiPacket(_name); 378 } 379 380 bool Controller::createNamedParamValues(MidiPacket::NamedParamValues& _params, const std::string& _packetName, const uint8_t _part) const 381 { 382 const auto* m = getMidiPacket(_packetName); 383 assert(m && "midi packet not found"); 384 if(!m) 385 return false; 386 387 MidiPacket::ParamIndices indices; 388 m->getParameterIndices(indices, m_descriptions); 389 390 if(indices.empty()) 391 return true; 392 393 for (const auto& index : indices) 394 { 395 auto* p = getParameter(index.second, _part); 396 if(!p) 397 return false; 398 const auto* largestP = p; 399 // we might have more than 1 parameter per index, use the one with the largest range 400 const auto& derived = p->getDerivedParameters(); 401 for (const auto& parameter : derived) 402 { 403 if(parameter->getDescription().range.getLength() > p->getDescription().range.getLength()) 404 largestP = parameter; 405 } 406 const auto v = getParameterValue(largestP); 407 _params.insert(std::make_pair(std::make_pair(index.first, p->getDescription().name), v)); 408 } 409 410 return true; 411 } 412 413 bool Controller::createNamedParamValues(MidiPacket::NamedParamValues& _dest, const MidiPacket::AnyPartParamValues& _source) const 414 { 415 for(uint32_t i=0; i<_source.size(); ++i) 416 { 417 const auto& v = _source[i]; 418 if(!v) 419 continue; 420 const auto* p = getParameter(i); 421 assert(p); 422 if(!p) 423 return false; 424 const auto key = std::make_pair(MidiPacket::AnyPart, p->getDescription().name); 425 _dest.insert(std::make_pair(key, *v)); 426 } 427 return true; 428 } 429 430 bool Controller::createMidiDataFromPacket(std::vector<uint8_t>& _sysex, const std::string& _packetName, const std::map<MidiDataType, uint8_t>& _data, uint8_t _part) const 431 { 432 MidiPacket::NamedParamValues paramValues; 433 434 if(!createNamedParamValues(paramValues, _packetName, _part)) 435 return false; 436 437 return createMidiDataFromPacket(_sysex, _packetName, _data, paramValues); 438 } 439 440 bool Controller::createMidiDataFromPacket(std::vector<uint8_t>& _sysex, const std::string& _packetName, const std::map<MidiDataType, uint8_t>& _data, const MidiPacket::NamedParamValues& _values) const 441 { 442 const auto* m = getMidiPacket(_packetName); 443 444 if(!m->create(_sysex, _data, _values)) 445 { 446 assert(false && "failed to create midi packet"); 447 _sysex.clear(); 448 return false; 449 } 450 return true; 451 } 452 453 bool Controller::createMidiDataFromPacket(std::vector<uint8_t>& _sysex, const std::string& _packetName, const std::map<MidiDataType, uint8_t>& _data, const MidiPacket::AnyPartParamValues& _values) const 454 { 455 MidiPacket::NamedParamValues namedParams; 456 if(!createNamedParamValues(namedParams, _values)) 457 return false; 458 return createMidiDataFromPacket(_sysex, _packetName, _data, namedParams); 459 } 460 461 bool Controller::parseMidiPacket(const MidiPacket& _packet, MidiPacket::Data& _data, MidiPacket::ParamValues& _parameterValues, const std::vector<uint8_t>& _src) const 462 { 463 _data.clear(); 464 _parameterValues.clear(); 465 return _packet.parse(_data, _parameterValues, m_descriptions, _src); 466 } 467 468 bool Controller::parseMidiPacket(const MidiPacket& _packet, MidiPacket::Data& _data, MidiPacket::AnyPartParamValues& _parameterValues, const std::vector<uint8_t>& _src) const 469 { 470 _data.clear(); 471 _parameterValues.clear(); 472 return _packet.parse(_data, _parameterValues, m_descriptions, _src); 473 } 474 475 bool Controller::parseMidiPacket(const MidiPacket& _packet, MidiPacket::Data& _data, const std::function<void(MidiPacket::ParamIndex, ParamValue)>& _parameterValues, const std::vector<uint8_t>& _src) const 476 { 477 _data.clear(); 478 return _packet.parse(_data, _parameterValues, m_descriptions, _src); 479 } 480 481 bool Controller::parseMidiPacket(const std::string& _name, MidiPacket::Data& _data, MidiPacket::ParamValues& _parameterValues, const std::vector<uint8_t>& _src) const 482 { 483 auto* m = getMidiPacket(_name); 484 assert(m); 485 if(!m) 486 return false; 487 return parseMidiPacket(*m, _data, _parameterValues, _src); 488 } 489 490 bool Controller::parseMidiPacket(std::string& _name, MidiPacket::Data& _data, MidiPacket::ParamValues& _parameterValues, const std::vector<uint8_t>& _src) const 491 { 492 const auto& packets = m_descriptions.getMidiPackets(); 493 494 for (const auto& packet : packets) 495 { 496 if(!parseMidiPacket(packet.second, _data, _parameterValues, _src)) 497 continue; 498 499 _name = packet.first; 500 return true; 501 } 502 return false; 503 } 504 505 bool Controller::setCurrentPart(const uint8_t _part) 506 { 507 if(_part == m_currentPart) 508 return false; 509 m_currentPart = _part; 510 onCurrentPartChanged(m_currentPart); 511 return true; 512 } 513 514 bool Controller::parseMidiMessage(const synthLib::SMidiEvent& _e) 515 { 516 if(_e.sysex.empty()) 517 return parseControllerMessage(_e); 518 return parseSysexMessage(_e.sysex, _e.source); 519 } 520 521 void Controller::enqueueMidiMessages(const std::vector<synthLib::SMidiEvent>& _events) 522 { 523 if(_events.empty()) 524 return; 525 526 const std::lock_guard l(m_midiMessagesLock); 527 m_midiMessages.insert(m_midiMessages.end(), _events.begin(), _events.end()); 528 if(!isTimerRunning()) 529 startTimer(1); 530 } 531 532 void Controller::loadChunkData(baseLib::ChunkReader& _cr) 533 { 534 m_parameterLinks.loadChunkData(_cr); 535 } 536 537 void Controller::saveChunkData(baseLib::BinaryStream& _s) const 538 { 539 m_parameterLinks.saveChunkData(_s); 540 } 541 542 Parameter::Origin Controller::midiEventSourceToParameterOrigin(const synthLib::MidiEventSource _source) 543 { 544 switch (_source) 545 { 546 case synthLib::MidiEventSource::Unknown: 547 return Parameter::Origin::Unknown; 548 case synthLib::MidiEventSource::Editor: 549 return Parameter::Origin::Ui; 550 case synthLib::MidiEventSource::Host: 551 return Parameter::Origin::HostAutomation; 552 case synthLib::MidiEventSource::PhysicalInput: 553 case synthLib::MidiEventSource::Plugin: 554 return Parameter::Origin::Midi; 555 case synthLib::MidiEventSource::Internal: 556 return Parameter::Origin::Unknown; 557 default: 558 assert(false && "implement new midi event source type"); 559 return Parameter::Origin::Unknown; 560 } 561 } 562 563 void Controller::getMidiMessages(std::vector<synthLib::SMidiEvent>& _events) 564 { 565 const std::lock_guard l(m_midiMessagesLock); 566 std::swap(m_midiMessages, _events); 567 m_midiMessages.clear(); 568 stopTimer(); 569 } 570 571 void Controller::processMidiMessages() 572 { 573 std::vector<synthLib::SMidiEvent> events; 574 getMidiMessages(events); 575 576 for (const auto& e : events) 577 parseMidiMessage(e); 578 } 579 580 std::string Controller::loadParameterDescriptions(const std::string& _filename) const 581 { 582 const auto path = synthLib::getModulePath() + _filename; 583 584 const std::ifstream f(path.c_str(), std::ios::in); 585 if(f.is_open()) 586 { 587 std::stringstream buf; 588 buf << f.rdbuf(); 589 return buf.str(); 590 } 591 592 const auto res = m_processor.findResource(_filename); 593 if(res) 594 return {res->first, res->second}; 595 return {}; 596 } 597 598 std::set<std::string> Controller::getRegionIdsForParameter(const Parameter* _param) const 599 { 600 if(!_param) 601 return {}; 602 return getRegionIdsForParameter(_param->getDescription().name); 603 } 604 605 std::set<std::string> Controller::getRegionIdsForParameter(const std::string& _name) const 606 { 607 const auto& regions = getParameterDescriptions().getRegions(); 608 609 std::set<std::string> result; 610 for (const auto& region : regions) 611 { 612 if(region.second.containsParameter(_name)) 613 result.insert(region.first); 614 } 615 return result; 616 } 617 618 Parameter* Controller::createParameter(Controller& _controller, const Description& _desc, const uint8_t _part, const int _uid, const Parameter::PartFormatter& _partFormatter) 619 { 620 return new Parameter(_controller, _desc, _part, _uid, _partFormatter); 621 } 622 }