Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

801 lines
19KB

  1. /*
  2. * Carla Plugin
  3. * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "CarlaPluginInternal.hpp"
  18. #include "CarlaEngine.hpp"
  19. #include "CarlaLibCounter.hpp"
  20. #include "CarlaMathUtils.hpp"
  21. #include <QtCore/QSettings>
  22. // -----------------------------------------------------------------------
  23. CARLA_BACKEND_START_NAMESPACE
  24. #if 0
  25. } // Fix editor indentation
  26. #endif
  27. // -------------------------------------------------------------------
  28. // Fallback data
  29. static const MidiProgramData kMidiProgramDataNull = { 0, 0, nullptr };
  30. // -----------------------------------------------------------------------
  31. // PluginAudioPort
  32. PluginAudioPort::PluginAudioPort() noexcept
  33. : rindex(0),
  34. port(nullptr) {}
  35. PluginAudioPort::~PluginAudioPort() noexcept
  36. {
  37. CARLA_ASSERT(port == nullptr);
  38. }
  39. // -----------------------------------------------------------------------
  40. // PluginAudioData
  41. PluginAudioData::PluginAudioData() noexcept
  42. : count(0),
  43. ports(nullptr) {}
  44. PluginAudioData::~PluginAudioData() noexcept
  45. {
  46. CARLA_ASSERT_INT(count == 0, count);
  47. CARLA_ASSERT(ports == nullptr);
  48. }
  49. void PluginAudioData::createNew(const uint32_t newCount)
  50. {
  51. CARLA_ASSERT_INT(count == 0, count);
  52. CARLA_SAFE_ASSERT_RETURN(ports == nullptr,);
  53. CARLA_SAFE_ASSERT_RETURN(newCount > 0,);
  54. ports = new PluginAudioPort[newCount];
  55. count = newCount;
  56. }
  57. void PluginAudioData::clear() noexcept
  58. {
  59. if (ports != nullptr)
  60. {
  61. for (uint32_t i=0; i < count; ++i)
  62. {
  63. if (ports[i].port != nullptr)
  64. {
  65. delete ports[i].port;
  66. ports[i].port = nullptr;
  67. }
  68. }
  69. delete[] ports;
  70. ports = nullptr;
  71. }
  72. count = 0;
  73. }
  74. void PluginAudioData::initBuffers() noexcept
  75. {
  76. for (uint32_t i=0; i < count; ++i)
  77. {
  78. if (ports[i].port != nullptr)
  79. ports[i].port->initBuffer();
  80. }
  81. }
  82. // -----------------------------------------------------------------------
  83. // PluginCVPort
  84. PluginCVPort::PluginCVPort() noexcept
  85. : rindex(0),
  86. param(0),
  87. port(nullptr) {}
  88. PluginCVPort::~PluginCVPort() noexcept
  89. {
  90. CARLA_ASSERT(port == nullptr);
  91. }
  92. // -----------------------------------------------------------------------
  93. // PluginCVData
  94. PluginCVData::PluginCVData() noexcept
  95. : count(0),
  96. ports(nullptr) {}
  97. PluginCVData::~PluginCVData() noexcept
  98. {
  99. CARLA_ASSERT_INT(count == 0, count);
  100. CARLA_ASSERT(ports == nullptr);
  101. }
  102. void PluginCVData::createNew(const uint32_t newCount)
  103. {
  104. CARLA_ASSERT_INT(count == 0, count);
  105. CARLA_SAFE_ASSERT_RETURN(ports == nullptr,);
  106. CARLA_SAFE_ASSERT_RETURN(newCount > 0,);
  107. ports = new PluginCVPort[newCount];
  108. count = newCount;
  109. }
  110. void PluginCVData::clear() noexcept
  111. {
  112. if (ports != nullptr)
  113. {
  114. for (uint32_t i=0; i < count; ++i)
  115. {
  116. if (ports[i].port != nullptr)
  117. {
  118. delete ports[i].port;
  119. ports[i].port = nullptr;
  120. }
  121. }
  122. delete[] ports;
  123. ports = nullptr;
  124. }
  125. count = 0;
  126. }
  127. void PluginCVData::initBuffers() noexcept
  128. {
  129. for (uint32_t i=0; i < count; ++i)
  130. {
  131. if (ports[i].port != nullptr)
  132. ports[i].port->initBuffer();
  133. }
  134. }
  135. // -----------------------------------------------------------------------
  136. // PluginEventData
  137. PluginEventData::PluginEventData() noexcept
  138. : portIn(nullptr),
  139. portOut(nullptr) {}
  140. PluginEventData::~PluginEventData() noexcept
  141. {
  142. CARLA_ASSERT(portIn == nullptr);
  143. CARLA_ASSERT(portOut == nullptr);
  144. }
  145. void PluginEventData::clear() noexcept
  146. {
  147. if (portIn != nullptr)
  148. {
  149. delete portIn;
  150. portIn = nullptr;
  151. }
  152. if (portOut != nullptr)
  153. {
  154. delete portOut;
  155. portOut = nullptr;
  156. }
  157. }
  158. void PluginEventData::initBuffers() noexcept
  159. {
  160. if (portIn != nullptr)
  161. portIn->initBuffer();
  162. if (portOut != nullptr)
  163. portOut->initBuffer();
  164. }
  165. // -----------------------------------------------------------------------
  166. // PluginParameterData
  167. PluginParameterData::PluginParameterData() noexcept
  168. : count(0),
  169. data(nullptr),
  170. ranges(nullptr),
  171. special(nullptr) {}
  172. PluginParameterData::~PluginParameterData() noexcept
  173. {
  174. CARLA_ASSERT_INT(count == 0, count);
  175. CARLA_ASSERT(data == nullptr);
  176. CARLA_ASSERT(ranges == nullptr);
  177. CARLA_ASSERT(special == nullptr);
  178. }
  179. void PluginParameterData::createNew(const uint32_t newCount, const bool withSpecial, const bool doReset)
  180. {
  181. CARLA_ASSERT_INT(count == 0, count);
  182. CARLA_SAFE_ASSERT_RETURN(data == nullptr,);
  183. CARLA_SAFE_ASSERT_RETURN(ranges == nullptr,);
  184. CARLA_SAFE_ASSERT_RETURN(special == nullptr,);
  185. CARLA_SAFE_ASSERT_RETURN(newCount > 0,);
  186. data = new ParameterData[newCount];
  187. ranges = new ParameterRanges[newCount];
  188. count = newCount;
  189. if (withSpecial)
  190. special = new SpecialParameterType[newCount];
  191. if (! doReset)
  192. return;
  193. for (uint32_t i=0; i < newCount; ++i)
  194. {
  195. data[i].type = PARAMETER_UNKNOWN;
  196. data[i].hints = 0x0;
  197. data[i].index = PARAMETER_NULL;
  198. data[i].rindex = PARAMETER_NULL;
  199. data[i].midiCC = -1;
  200. data[i].midiChannel = 0;
  201. ranges[i].def = 0.0f;
  202. ranges[i].min = 0.0f;
  203. ranges[i].max = 0.0f;
  204. ranges[i].step = 0.0f;
  205. ranges[i].stepSmall = 0.0f;
  206. ranges[i].stepLarge = 0.0f;
  207. if (withSpecial)
  208. special[i] = PARAMETER_SPECIAL_NULL;
  209. }
  210. }
  211. void PluginParameterData::clear() noexcept
  212. {
  213. if (data != nullptr)
  214. {
  215. delete[] data;
  216. data = nullptr;
  217. }
  218. if (ranges != nullptr)
  219. {
  220. delete[] ranges;
  221. ranges = nullptr;
  222. }
  223. if (special != nullptr)
  224. {
  225. delete[] special;
  226. special = nullptr;
  227. }
  228. count = 0;
  229. }
  230. float PluginParameterData::getFixedValue(const uint32_t parameterId, const float& value) const noexcept
  231. {
  232. CARLA_SAFE_ASSERT_RETURN(parameterId < count, 0.0f);
  233. return ranges[parameterId].getFixedValue(value);
  234. }
  235. // -----------------------------------------------------------------------
  236. // PluginProgramData
  237. PluginProgramData::PluginProgramData() noexcept
  238. : count(0),
  239. current(-1),
  240. names(nullptr) {}
  241. PluginProgramData::~PluginProgramData() noexcept
  242. {
  243. CARLA_ASSERT_INT(count == 0, count);
  244. CARLA_ASSERT_INT(current == -1, current);
  245. CARLA_ASSERT(names == nullptr);
  246. }
  247. void PluginProgramData::createNew(const uint32_t newCount)
  248. {
  249. CARLA_ASSERT_INT(count == 0, count);
  250. CARLA_ASSERT_INT(current == -1, current);
  251. CARLA_ASSERT(names == nullptr);
  252. CARLA_ASSERT_INT(newCount > 0, newCount);
  253. if (names != nullptr || newCount == 0)
  254. return;
  255. names = new ProgramName[newCount];
  256. count = newCount;
  257. for (uint32_t i=0; i < newCount; ++i)
  258. names[i] = nullptr;
  259. }
  260. void PluginProgramData::clear() noexcept
  261. {
  262. if (names != nullptr)
  263. {
  264. for (uint32_t i=0; i < count; ++i)
  265. {
  266. if (names[i] != nullptr)
  267. {
  268. delete[] names[i];
  269. names[i] = nullptr;
  270. }
  271. }
  272. delete[] names;
  273. names = nullptr;
  274. }
  275. count = 0;
  276. current = -1;
  277. }
  278. // -----------------------------------------------------------------------
  279. // PluginMidiProgramData
  280. PluginMidiProgramData::PluginMidiProgramData() noexcept
  281. : count(0),
  282. current(-1),
  283. data(nullptr) {}
  284. PluginMidiProgramData::~PluginMidiProgramData() noexcept
  285. {
  286. CARLA_ASSERT_INT(count == 0, count);
  287. CARLA_ASSERT_INT(current == -1, current);
  288. CARLA_ASSERT(data == nullptr);
  289. }
  290. void PluginMidiProgramData::createNew(const uint32_t newCount)
  291. {
  292. CARLA_ASSERT_INT(count == 0, count);
  293. CARLA_ASSERT_INT(current == -1, current);
  294. CARLA_ASSERT(data == nullptr);
  295. CARLA_ASSERT_INT(newCount > 0, newCount);
  296. if (data != nullptr || newCount == 0)
  297. return;
  298. data = new MidiProgramData[newCount];
  299. count = newCount;
  300. for (uint32_t i=0; i < count; ++i)
  301. {
  302. data[i].bank = 0;
  303. data[i].program = 0;
  304. data[i].name = nullptr;
  305. }
  306. }
  307. void PluginMidiProgramData::clear() noexcept
  308. {
  309. if (data != nullptr)
  310. {
  311. for (uint32_t i=0; i < count; ++i)
  312. {
  313. if (data[i].name != nullptr)
  314. {
  315. delete[] data[i].name;
  316. data[i].name = nullptr;
  317. }
  318. }
  319. delete[] data;
  320. data = nullptr;
  321. }
  322. count = 0;
  323. current = -1;
  324. }
  325. const MidiProgramData& PluginMidiProgramData::getCurrent() const noexcept
  326. {
  327. CARLA_SAFE_ASSERT_RETURN(current >= 0 && current < static_cast<int32_t>(count), kMidiProgramDataNull);
  328. return data[current];
  329. }
  330. // -----------------------------------------------------------------------
  331. CarlaPluginProtectedData::ExternalNotes::ExternalNotes()
  332. : dataPool(32, 152),
  333. data(dataPool) {}
  334. CarlaPluginProtectedData::ExternalNotes::~ExternalNotes()
  335. {
  336. mutex.lock();
  337. data.clear();
  338. mutex.unlock();
  339. }
  340. void CarlaPluginProtectedData::ExternalNotes::append(const ExternalMidiNote& note)
  341. {
  342. mutex.lock();
  343. data.append_sleepy(note);
  344. mutex.unlock();
  345. }
  346. // -----------------------------------------------------------------------
  347. CarlaPluginProtectedData::PostRtEvents::PostRtEvents()
  348. : dataPool(128, 128),
  349. data(dataPool),
  350. dataPendingRT(dataPool) {}
  351. CarlaPluginProtectedData::PostRtEvents::~PostRtEvents()
  352. {
  353. clear();
  354. }
  355. void CarlaPluginProtectedData::PostRtEvents::appendRT(const PluginPostRtEvent& e)
  356. {
  357. dataPendingRT.append(e);
  358. }
  359. void CarlaPluginProtectedData::PostRtEvents::trySplice()
  360. {
  361. if (mutex.tryLock())
  362. {
  363. dataPendingRT.spliceAppend(data);
  364. mutex.unlock();
  365. }
  366. }
  367. void CarlaPluginProtectedData::PostRtEvents::clear()
  368. {
  369. mutex.lock();
  370. data.clear();
  371. dataPendingRT.clear();
  372. mutex.unlock();
  373. }
  374. // -----------------------------------------------------------------------
  375. #ifndef BUILD_BRIDGE
  376. CarlaPluginProtectedData::PostProc::PostProc() noexcept
  377. : dryWet(1.0f),
  378. volume(1.0f),
  379. balanceLeft(-1.0f),
  380. balanceRight(1.0f),
  381. panning(0.0f) {}
  382. #endif
  383. // -----------------------------------------------------------------------
  384. CarlaPluginProtectedData::OSC::OSC(CarlaEngine* const eng, CarlaPlugin* const plug)
  385. : thread(eng, plug) {}
  386. // -----------------------------------------------------------------------
  387. CarlaPluginProtectedData::CarlaPluginProtectedData(CarlaEngine* const eng, const unsigned int idx, CarlaPlugin* const self)
  388. : engine(eng),
  389. client(nullptr),
  390. id(idx),
  391. hints(0x0),
  392. options(0x0),
  393. active(false),
  394. enabled(false),
  395. needsReset(false),
  396. lib(nullptr),
  397. uiLib(nullptr),
  398. ctrlChannel(0),
  399. extraHints(0x0),
  400. transientTryCounter(0),
  401. latency(0),
  402. latencyBuffers(nullptr),
  403. name(nullptr),
  404. filename(nullptr),
  405. iconName(nullptr),
  406. identifier(nullptr),
  407. osc(eng, self) {}
  408. CarlaPluginProtectedData::~CarlaPluginProtectedData()
  409. {
  410. CARLA_SAFE_ASSERT(! needsReset);
  411. CARLA_SAFE_ASSERT(transientTryCounter == 0);
  412. if (name != nullptr)
  413. {
  414. delete[] name;
  415. name = nullptr;
  416. }
  417. if (filename != nullptr)
  418. {
  419. delete[] filename;
  420. filename = nullptr;
  421. }
  422. if (iconName != nullptr)
  423. {
  424. delete[] iconName;
  425. iconName = nullptr;
  426. }
  427. if (identifier != nullptr)
  428. {
  429. delete[] identifier;
  430. identifier = nullptr;
  431. }
  432. {
  433. // mutex MUST have been locked before
  434. const bool lockMaster(masterMutex.tryLock());
  435. const bool lockSingle(singleMutex.tryLock());
  436. CARLA_SAFE_ASSERT(! lockMaster);
  437. CARLA_SAFE_ASSERT(! lockSingle);
  438. }
  439. if (client != nullptr)
  440. {
  441. if (client->isActive())
  442. {
  443. // must not happen
  444. carla_safe_assert("client->isActive()", __FILE__, __LINE__);
  445. client->deactivate();
  446. }
  447. clearBuffers();
  448. delete client;
  449. client = nullptr;
  450. }
  451. for (LinkedList<CustomData>::Itenerator it = custom.begin(); it.valid(); it.next())
  452. {
  453. CustomData& cData(it.getValue());
  454. if (cData.type != nullptr)
  455. {
  456. delete[] cData.type;
  457. cData.type = nullptr;
  458. }
  459. else
  460. carla_safe_assert("cData.type != nullptr", __FILE__, __LINE__);
  461. if (cData.key != nullptr)
  462. {
  463. delete[] cData.key;
  464. cData.key = nullptr;
  465. }
  466. else
  467. carla_safe_assert("cData.key != nullptr", __FILE__, __LINE__);
  468. if (cData.value != nullptr)
  469. {
  470. delete[] cData.value;
  471. cData.value = nullptr;
  472. }
  473. else
  474. carla_safe_assert("cData.value != nullptr", __FILE__, __LINE__);
  475. }
  476. prog.clear();
  477. midiprog.clear();
  478. custom.clear();
  479. // MUST have been locked before
  480. masterMutex.unlock();
  481. singleMutex.unlock();
  482. if (lib != nullptr)
  483. libClose();
  484. CARLA_SAFE_ASSERT(uiLib == nullptr);
  485. }
  486. // -----------------------------------------------------------------------
  487. // Buffer functions
  488. void CarlaPluginProtectedData::clearBuffers()
  489. {
  490. if (latencyBuffers != nullptr)
  491. {
  492. CARLA_SAFE_ASSERT(audioIn.count > 0);
  493. for (uint32_t i=0; i < audioIn.count; ++i)
  494. {
  495. CARLA_SAFE_ASSERT_CONTINUE(latencyBuffers[i] != nullptr);
  496. delete[] latencyBuffers[i];
  497. latencyBuffers[i] = nullptr;
  498. }
  499. delete[] latencyBuffers;
  500. latencyBuffers = nullptr;
  501. latency = 0;
  502. }
  503. else
  504. {
  505. CARLA_SAFE_ASSERT(latency == 0);
  506. }
  507. audioIn.clear();
  508. audioOut.clear();
  509. param.clear();
  510. event.clear();
  511. }
  512. void CarlaPluginProtectedData::recreateLatencyBuffers()
  513. {
  514. if (latencyBuffers != nullptr)
  515. {
  516. CARLA_ASSERT(audioIn.count > 0);
  517. for (uint32_t i=0; i < audioIn.count; ++i)
  518. {
  519. CARLA_SAFE_ASSERT_CONTINUE(latencyBuffers[i] != nullptr);
  520. delete[] latencyBuffers[i];
  521. latencyBuffers[i] = nullptr;
  522. }
  523. delete[] latencyBuffers;
  524. latencyBuffers = nullptr;
  525. }
  526. if (audioIn.count > 0 && latency > 0)
  527. {
  528. latencyBuffers = new float*[audioIn.count];
  529. for (uint32_t i=0; i < audioIn.count; ++i)
  530. {
  531. latencyBuffers[i] = new float[latency];
  532. FLOAT_CLEAR(latencyBuffers[i], latency);
  533. }
  534. }
  535. }
  536. // -----------------------------------------------------------------------
  537. // Post-poned events
  538. void CarlaPluginProtectedData::postponeRtEvent(const PluginPostRtEventType type, const int32_t value1, const int32_t value2, const float value3)
  539. {
  540. CARLA_SAFE_ASSERT_RETURN(type != kPluginPostRtEventNull,);
  541. PluginPostRtEvent rtEvent = { type, value1, value2, value3 };
  542. postRtEvents.appendRT(rtEvent);
  543. }
  544. // -----------------------------------------------------------------------
  545. // Library functions
  546. static LibCounter sLibCounter;
  547. const char* CarlaPluginProtectedData::libError(const char* const fname)
  548. {
  549. return lib_error(fname);
  550. }
  551. bool CarlaPluginProtectedData::libOpen(const char* const fname)
  552. {
  553. lib = sLibCounter.open(fname);
  554. return (lib != nullptr);
  555. }
  556. bool CarlaPluginProtectedData::libClose()
  557. {
  558. const bool ret = sLibCounter.close(lib);
  559. lib = nullptr;
  560. return ret;
  561. }
  562. void* CarlaPluginProtectedData::libSymbol(const char* const symbol)
  563. {
  564. return lib_symbol(lib, symbol);
  565. }
  566. bool CarlaPluginProtectedData::uiLibOpen(const char* const fname, const bool canDelete)
  567. {
  568. uiLib = sLibCounter.open(fname, canDelete);
  569. return (uiLib != nullptr);
  570. }
  571. bool CarlaPluginProtectedData::uiLibClose()
  572. {
  573. const bool ret = sLibCounter.close(uiLib);
  574. uiLib = nullptr;
  575. return ret;
  576. }
  577. void* CarlaPluginProtectedData::uiLibSymbol(const char* const symbol)
  578. {
  579. return lib_symbol(uiLib, symbol);
  580. }
  581. // -----------------------------------------------------------------------
  582. // Settings functions
  583. void CarlaPluginProtectedData::saveSetting(const uint option, const bool yesNo)
  584. {
  585. CARLA_SAFE_ASSERT_RETURN(identifier != nullptr && identifier[0] != '\0',);
  586. QSettings settings("falkTX", "CarlaPluginSettings");
  587. settings.beginGroup(identifier);
  588. switch (option)
  589. {
  590. case PLUGIN_OPTION_FIXED_BUFFERS:
  591. settings.setValue("FixedBuffers", yesNo);
  592. break;
  593. case PLUGIN_OPTION_FORCE_STEREO:
  594. settings.setValue("ForceStereo", yesNo);
  595. break;
  596. case PLUGIN_OPTION_MAP_PROGRAM_CHANGES:
  597. settings.setValue("MapProgramChanges", yesNo);
  598. break;
  599. case PLUGIN_OPTION_USE_CHUNKS:
  600. settings.setValue("UseChunks", yesNo);
  601. break;
  602. case PLUGIN_OPTION_SEND_CONTROL_CHANGES:
  603. settings.setValue("SendControlChanges", yesNo);
  604. break;
  605. case PLUGIN_OPTION_SEND_CHANNEL_PRESSURE:
  606. settings.setValue("SendChannelPressure", yesNo);
  607. break;
  608. case PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH:
  609. settings.setValue("SendNoteAftertouch", yesNo);
  610. break;
  611. case PLUGIN_OPTION_SEND_PITCHBEND:
  612. settings.setValue("SendPitchbend", yesNo);
  613. break;
  614. case PLUGIN_OPTION_SEND_ALL_SOUND_OFF:
  615. settings.setValue("SendAllSoundOff", yesNo);
  616. break;
  617. default:
  618. break;
  619. }
  620. settings.endGroup();
  621. }
  622. uint CarlaPluginProtectedData::loadSettings(const uint curOptions, const uint availOptions)
  623. {
  624. CARLA_SAFE_ASSERT_RETURN(identifier != nullptr && identifier[0] != '\0', 0x0);
  625. QSettings settings("falkTX", "CarlaPluginSettings");
  626. settings.beginGroup(identifier);
  627. unsigned int newOptions = 0x0;
  628. #define CHECK_AND_SET_OPTION(STR, BIT) \
  629. if ((availOptions & BIT) != 0 || BIT == PLUGIN_OPTION_FORCE_STEREO) \
  630. { \
  631. if (settings.contains(STR)) \
  632. { \
  633. if (settings.value(STR, (curOptions & BIT) != 0).toBool()) \
  634. newOptions |= BIT; \
  635. } \
  636. else if (curOptions & BIT) \
  637. newOptions |= BIT; \
  638. }
  639. CHECK_AND_SET_OPTION("FixedBuffers", PLUGIN_OPTION_FIXED_BUFFERS);
  640. CHECK_AND_SET_OPTION("ForceStereo", PLUGIN_OPTION_FORCE_STEREO);
  641. CHECK_AND_SET_OPTION("MapProgramChanges", PLUGIN_OPTION_MAP_PROGRAM_CHANGES);
  642. CHECK_AND_SET_OPTION("UseChunks", PLUGIN_OPTION_USE_CHUNKS);
  643. CHECK_AND_SET_OPTION("SendControlChanges", PLUGIN_OPTION_SEND_CONTROL_CHANGES);
  644. CHECK_AND_SET_OPTION("SendChannelPressure", PLUGIN_OPTION_SEND_CHANNEL_PRESSURE);
  645. CHECK_AND_SET_OPTION("SendNoteAftertouch", PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH);
  646. CHECK_AND_SET_OPTION("SendPitchbend", PLUGIN_OPTION_SEND_PITCHBEND);
  647. CHECK_AND_SET_OPTION("SendAllSoundOff", PLUGIN_OPTION_SEND_ALL_SOUND_OFF);
  648. #undef CHECK_AND_SET_OPTION
  649. settings.endGroup();
  650. return newOptions;
  651. }
  652. // -----------------------------------------------------------------------
  653. CARLA_BACKEND_END_NAMESPACE