Collection of tools useful for audio production
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.

608 lines
21KB

  1. /*
  2. * Carla Backend
  3. * Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * 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 COPYING file
  16. */
  17. #ifdef CARLA_ENGINE_JACK
  18. #include "carla_engine.h"
  19. #include "carla_plugin.h"
  20. #include <iostream>
  21. CARLA_BACKEND_START_NAMESPACE
  22. // -------------------------------------------------------------------------------------------------------------------
  23. // static JACK<->Engine calls
  24. static int carla_jack_srate_callback(jack_nframes_t newSampleRate, void* arg)
  25. {
  26. CarlaEngineJack* const engine = (CarlaEngineJack*)arg;
  27. engine->handleSampleRateCallback(newSampleRate);
  28. return 0;
  29. }
  30. static int carla_jack_bufsize_callback(jack_nframes_t newBufferSize, void* arg)
  31. {
  32. CarlaEngineJack* const engine = (CarlaEngineJack*)arg;
  33. engine->handleBufferSizeCallback(newBufferSize);
  34. return 0;
  35. }
  36. static void carla_jack_freewheel_callback(int starting, void* arg)
  37. {
  38. CarlaEngineJack* const engine = (CarlaEngineJack*)arg;
  39. engine->handleFreewheelCallback(bool(starting));
  40. }
  41. static int carla_jack_process_callback(jack_nframes_t nframes, void* arg)
  42. {
  43. CarlaEngineJack* const engine = (CarlaEngineJack*)arg;
  44. engine->handleProcessCallback(nframes);
  45. return 0;
  46. }
  47. static int carla_jack_process_callback_plugin(jack_nframes_t nframes, void* arg)
  48. {
  49. CarlaPlugin* const plugin = (CarlaPlugin*)arg;
  50. if (plugin && plugin->enabled())
  51. {
  52. plugin->engineProcessLock();
  53. plugin->initBuffers();
  54. plugin->process_jack(nframes);
  55. plugin->engineProcessUnlock();
  56. }
  57. return 0;
  58. }
  59. static void carla_jack_shutdown_callback(void* arg)
  60. {
  61. CarlaEngineJack* const engine = (CarlaEngineJack*)arg;
  62. engine->handleShutdownCallback();
  63. }
  64. // -------------------------------------------------------------------------------------------------------------------
  65. // Carla Engine (JACK)
  66. CarlaEngineJack::CarlaEngineJack()
  67. : CarlaEngine()
  68. #ifdef Q_COMPILER_INITIALIZER_LISTS
  69. , rackJackPorts{nullptr}
  70. #endif
  71. {
  72. qDebug("CarlaEngineJack::CarlaEngineJack()");
  73. type = CarlaEngineTypeJack;
  74. client = nullptr;
  75. state = JackTransportStopped;
  76. freewheel = false;
  77. procThread = nullptr;
  78. memset(&pos, 0, sizeof(jack_position_t));
  79. #ifndef Q_COMPILER_INITIALIZER_LISTS
  80. for (unsigned short i=0; i < rackPortCount; i++)
  81. rackJackPorts[i] = nullptr;
  82. #endif
  83. }
  84. CarlaEngineJack::~CarlaEngineJack()
  85. {
  86. qDebug("CarlaEngineJack::~CarlaEngineJack()");
  87. }
  88. // -------------------------------------------------------------------------------------------------------------------
  89. bool CarlaEngineJack::init(const char* const clientName)
  90. {
  91. qDebug("CarlaEngineJack::init(\"%s\")", clientName);
  92. client = jackbridge_client_open(clientName, JackNullOption, nullptr);
  93. state = JackTransportStopped;
  94. freewheel = false;
  95. procThread = nullptr;
  96. if (client)
  97. {
  98. sampleRate = jackbridge_get_sample_rate(client);
  99. bufferSize = jackbridge_get_buffer_size(client);
  100. jackbridge_set_sample_rate_callback(client, carla_jack_srate_callback, this);
  101. jackbridge_set_buffer_size_callback(client, carla_jack_bufsize_callback, this);
  102. jackbridge_set_freewheel_callback(client, carla_jack_freewheel_callback, this);
  103. jackbridge_set_process_callback(client, carla_jack_process_callback, this);
  104. jackbridge_on_shutdown(client, carla_jack_shutdown_callback, this);
  105. #ifndef BUILD_BRIDGE
  106. if (carlaOptions.processMode == PROCESS_MODE_CONTINUOUS_RACK)
  107. {
  108. rackJackPorts[rackPortAudioIn1] = jackbridge_port_register(client, "in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
  109. rackJackPorts[rackPortAudioIn2] = jackbridge_port_register(client, "in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
  110. rackJackPorts[rackPortAudioOut1] = jackbridge_port_register(client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  111. rackJackPorts[rackPortAudioOut2] = jackbridge_port_register(client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  112. rackJackPorts[rackPortControlIn] = jackbridge_port_register(client, "control-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
  113. rackJackPorts[rackPortControlOut] = jackbridge_port_register(client, "control-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
  114. rackJackPorts[rackPortMidiIn] = jackbridge_port_register(client, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
  115. rackJackPorts[rackPortMidiOut] = jackbridge_port_register(client, "midi-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
  116. }
  117. #endif
  118. if (jackbridge_activate(client) == 0)
  119. {
  120. // set client name, fixed for OSC usage
  121. // FIXME - put this in shared?
  122. char* fixedName = strdup(jackbridge_get_client_name(client));
  123. for (size_t i=0; i < strlen(fixedName); i++)
  124. {
  125. if (! (std::isalpha(fixedName[i]) || std::isdigit(fixedName[i])))
  126. fixedName[i] = '_';
  127. }
  128. name = strdup(fixedName);
  129. free((void*)fixedName);
  130. CarlaEngine::init(name);
  131. return true;
  132. }
  133. else
  134. {
  135. setLastError("Failed to activate the JACK client");
  136. client = nullptr;
  137. }
  138. }
  139. else
  140. setLastError("Failed to create new JACK client");
  141. return false;
  142. }
  143. bool CarlaEngineJack::close()
  144. {
  145. qDebug("CarlaEngineJack::close()");
  146. CarlaEngine::close();
  147. if (name)
  148. {
  149. free((void*)name);
  150. name = nullptr;
  151. }
  152. if (jackbridge_deactivate(client) == 0)
  153. {
  154. #ifndef BUILD_BRIDGE
  155. if (carlaOptions.processMode == PROCESS_MODE_CONTINUOUS_RACK)
  156. {
  157. jackbridge_port_unregister(client, rackJackPorts[rackPortAudioIn1]);
  158. jackbridge_port_unregister(client, rackJackPorts[rackPortAudioIn2]);
  159. jackbridge_port_unregister(client, rackJackPorts[rackPortAudioOut1]);
  160. jackbridge_port_unregister(client, rackJackPorts[rackPortAudioOut2]);
  161. jackbridge_port_unregister(client, rackJackPorts[rackPortControlIn]);
  162. jackbridge_port_unregister(client, rackJackPorts[rackPortControlOut]);
  163. jackbridge_port_unregister(client, rackJackPorts[rackPortMidiIn]);
  164. jackbridge_port_unregister(client, rackJackPorts[rackPortMidiOut]);
  165. }
  166. #endif
  167. if (jackbridge_client_close(client) == 0)
  168. {
  169. client = nullptr;
  170. return true;
  171. }
  172. else
  173. setLastError("Failed to close the JACK client");
  174. }
  175. else
  176. setLastError("Failed to deactivate the JACK client");
  177. client = nullptr;
  178. return false;
  179. }
  180. bool CarlaEngineJack::isOnAudioThread()
  181. {
  182. return (QThread::currentThread() == procThread);
  183. }
  184. bool CarlaEngineJack::isOffline()
  185. {
  186. return freewheel;
  187. }
  188. bool CarlaEngineJack::isRunning()
  189. {
  190. return bool(client);
  191. }
  192. CarlaEngineClient* CarlaEngineJack::addClient(CarlaPlugin* const plugin)
  193. {
  194. CarlaEngineClientNativeHandle handle;
  195. #ifndef BUILD_BRIDGE
  196. if (carlaOptions.processMode == PROCESS_MODE_SINGLE_CLIENT)
  197. {
  198. handle.jackClient = client;
  199. }
  200. else if (carlaOptions.processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
  201. #endif
  202. {
  203. handle.jackClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr);
  204. jackbridge_set_process_callback(handle.jackClient, carla_jack_process_callback_plugin, plugin);
  205. }
  206. //else if (carla_options.process_mode == PROCESS_MODE_CONTINUOUS_RACK)
  207. //{
  208. //}
  209. return new CarlaEngineClient(CarlaEngineTypeJack, handle);
  210. }
  211. // -------------------------------------------------------------------------------------------------------------------
  212. void CarlaEngineJack::handleSampleRateCallback(double newSampleRate)
  213. {
  214. sampleRate = newSampleRate;
  215. }
  216. void CarlaEngineJack::handleBufferSizeCallback(uint32_t newBufferSize)
  217. {
  218. #ifndef BUILD_BRIDGE
  219. if (carlaOptions.processHighPrecision)
  220. return;
  221. #endif
  222. bufferSizeChanged(newBufferSize);
  223. }
  224. void CarlaEngineJack::handleFreewheelCallback(bool isFreewheel)
  225. {
  226. freewheel = isFreewheel;
  227. }
  228. void CarlaEngineJack::handleProcessCallback(uint32_t nframes)
  229. {
  230. if (procThread == nullptr)
  231. procThread = QThread::currentThread();
  232. if (maxPluginNumber == 0)
  233. return;
  234. state = jackbridge_transport_query(client, &pos);
  235. timeInfo.playing = (state != JackTransportStopped);
  236. if (pos.unique_1 == pos.unique_2)
  237. {
  238. timeInfo.frame = pos.frame;
  239. timeInfo.time = pos.usecs;
  240. if (pos.valid & JackPositionBBT)
  241. {
  242. timeInfo.valid = CarlaEngineTimeBBT;
  243. timeInfo.bbt.bar = pos.bar;
  244. timeInfo.bbt.beat = pos.beat;
  245. timeInfo.bbt.tick = pos.tick;
  246. timeInfo.bbt.bar_start_tick = pos.bar_start_tick;
  247. timeInfo.bbt.beats_per_bar = pos.beats_per_bar;
  248. timeInfo.bbt.beat_type = pos.beat_type;
  249. timeInfo.bbt.ticks_per_beat = pos.ticks_per_beat;
  250. timeInfo.bbt.beats_per_minute = pos.beats_per_minute;
  251. }
  252. else
  253. timeInfo.valid = 0;
  254. }
  255. else
  256. {
  257. timeInfo.frame = 0;
  258. timeInfo.valid = 0;
  259. }
  260. #ifndef BUILD_BRIDGE
  261. if (carlaOptions.processMode == PROCESS_MODE_SINGLE_CLIENT)
  262. {
  263. for (unsigned short i=0; i < maxPluginNumber; i++)
  264. {
  265. CarlaPlugin* const plugin = getPluginUnchecked(i);
  266. if (plugin && plugin->enabled())
  267. {
  268. plugin->engineProcessLock();
  269. plugin->initBuffers();
  270. plugin->process_jack(nframes);
  271. plugin->engineProcessUnlock();
  272. }
  273. }
  274. }
  275. else if (carlaOptions.processMode == PROCESS_MODE_CONTINUOUS_RACK)
  276. {
  277. // get buffers from jack
  278. float* audioIn1 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioIn1], nframes);
  279. float* audioIn2 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioIn2], nframes);
  280. float* audioOut1 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioOut1], nframes);
  281. float* audioOut2 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioOut2], nframes);
  282. void* controlIn = jackbridge_port_get_buffer(rackJackPorts[rackPortControlIn], nframes);
  283. void* controlOut = jackbridge_port_get_buffer(rackJackPorts[rackPortControlOut], nframes);
  284. void* midiIn = jackbridge_port_get_buffer(rackJackPorts[rackPortMidiIn], nframes);
  285. void* midiOut = jackbridge_port_get_buffer(rackJackPorts[rackPortMidiOut], nframes);
  286. // assert buffers
  287. Q_ASSERT(audioIn1);
  288. Q_ASSERT(audioIn2);
  289. Q_ASSERT(audioOut1);
  290. Q_ASSERT(audioOut2);
  291. Q_ASSERT(controlIn);
  292. Q_ASSERT(controlOut);
  293. Q_ASSERT(midiIn);
  294. Q_ASSERT(midiOut);
  295. // create temporary audio buffers
  296. float ains_tmp_buf1[nframes];
  297. float ains_tmp_buf2[nframes];
  298. float aouts_tmp_buf1[nframes];
  299. float aouts_tmp_buf2[nframes];
  300. float* ains_tmp[2] = { ains_tmp_buf1, ains_tmp_buf2 };
  301. float* aouts_tmp[2] = { aouts_tmp_buf1, aouts_tmp_buf2 };
  302. // initialize audio input
  303. memcpy(ains_tmp_buf1, audioIn1, sizeof(float)*nframes);
  304. memcpy(ains_tmp_buf2, audioIn2, sizeof(float)*nframes);
  305. // initialize control input
  306. memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS);
  307. {
  308. jackbridge_midi_event_t jackEvent;
  309. const uint32_t jackEventCount = jackbridge_midi_get_event_count(controlIn);
  310. uint32_t carlaEventIndex = 0;
  311. for (uint32_t jackEventIndex=0; jackEventIndex < jackEventCount; jackEventIndex++)
  312. {
  313. if (jackbridge_midi_event_get(&jackEvent, controlIn, jackEventIndex) != 0)
  314. continue;
  315. CarlaEngineControlEvent* const carlaEvent = &rackControlEventsIn[carlaEventIndex++];
  316. uint8_t midiStatus = jackEvent.buffer[0];
  317. uint8_t midiChannel = midiStatus & 0x0F;
  318. carlaEvent->time = jackEvent.time;
  319. carlaEvent->channel = midiChannel;
  320. if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus))
  321. {
  322. uint8_t midiControl = jackEvent.buffer[1];
  323. if (MIDI_IS_CONTROL_BANK_SELECT(midiControl))
  324. {
  325. uint8_t midiBank = jackEvent.buffer[2];
  326. carlaEvent->type = CarlaEngineEventMidiBankChange;
  327. carlaEvent->value = midiBank;
  328. }
  329. else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF)
  330. {
  331. carlaEvent->type = CarlaEngineEventAllSoundOff;
  332. }
  333. else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF)
  334. {
  335. carlaEvent->type = CarlaEngineEventAllNotesOff;
  336. }
  337. else
  338. {
  339. uint8_t midiValue = jackEvent.buffer[2];
  340. carlaEvent->type = CarlaEngineEventControlChange;
  341. carlaEvent->controller = midiControl;
  342. carlaEvent->value = double(midiValue)/127;
  343. }
  344. }
  345. else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus))
  346. {
  347. uint8_t midiProgram = jackEvent.buffer[1];
  348. carlaEvent->type = CarlaEngineEventMidiProgramChange;
  349. carlaEvent->value = midiProgram;
  350. }
  351. }
  352. }
  353. // initialize midi input
  354. memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  355. {
  356. uint32_t i = 0, j = 0;
  357. jackbridge_midi_event_t jackEvent;
  358. while (jackbridge_midi_event_get(&jackEvent, midiIn, j++) == 0)
  359. {
  360. if (i == MAX_ENGINE_MIDI_EVENTS)
  361. break;
  362. if (jackEvent.size < 4)
  363. {
  364. rackMidiEventsIn[i].time = jackEvent.time;
  365. rackMidiEventsIn[i].size = jackEvent.size;
  366. memcpy(rackMidiEventsIn[i].data, jackEvent.buffer, jackEvent.size);
  367. i += 1;
  368. }
  369. }
  370. }
  371. // initialize outputs (zero)
  372. memset(aouts_tmp_buf1, 0, sizeof(float)*nframes);
  373. memset(aouts_tmp_buf2, 0, sizeof(float)*nframes);
  374. memset(rackControlEventsOut, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS);
  375. memset(rackMidiEventsOut, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  376. bool processed = false;
  377. // process plugins
  378. for (unsigned short i=0; i < maxPluginNumber; i++)
  379. {
  380. CarlaPlugin* const plugin = getPluginUnchecked(i);
  381. if (plugin && plugin->enabled())
  382. {
  383. if (processed)
  384. {
  385. // initialize inputs (from previous outputs)
  386. memcpy(ains_tmp_buf1, aouts_tmp_buf1, sizeof(float)*nframes);
  387. memcpy(ains_tmp_buf2, aouts_tmp_buf2, sizeof(float)*nframes);
  388. memcpy(rackMidiEventsIn, rackMidiEventsOut, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  389. // initialize outputs (zero)
  390. memset(aouts_tmp_buf1, 0, sizeof(float)*nframes);
  391. memset(aouts_tmp_buf2, 0, sizeof(float)*nframes);
  392. memset(rackMidiEventsOut, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  393. }
  394. // process
  395. plugin->engineProcessLock();
  396. plugin->initBuffers();
  397. if (carlaOptions.processHighPrecision)
  398. {
  399. float* ains_buffer2[2];
  400. float* aouts_buffer2[2];
  401. for (uint32_t j=0; j < nframes; j += 8)
  402. {
  403. ains_buffer2[0] = ains_tmp_buf1 + j;
  404. ains_buffer2[1] = ains_tmp_buf2 + j;
  405. aouts_buffer2[0] = aouts_tmp_buf1 + j;
  406. aouts_buffer2[1] = aouts_tmp_buf2 + j;
  407. plugin->process(ains_buffer2, aouts_buffer2, 8, j);
  408. }
  409. }
  410. else
  411. plugin->process(ains_tmp, aouts_tmp, nframes);
  412. plugin->engineProcessUnlock();
  413. // if plugin has no audio inputs, add previous buffers
  414. if (plugin->audioInCount() == 0)
  415. {
  416. for (uint32_t j=0; j < nframes; j++)
  417. {
  418. aouts_tmp_buf1[j] += ains_tmp_buf1[j];
  419. aouts_tmp_buf2[j] += ains_tmp_buf2[j];
  420. }
  421. }
  422. // if plugin has no midi output, add previous midi input
  423. if (plugin->midiOutCount() == 0)
  424. {
  425. memcpy(rackMidiEventsOut, rackMidiEventsIn, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  426. }
  427. processed = true;
  428. }
  429. }
  430. // if no plugins in the rack, copy inputs over outputs
  431. if (! processed)
  432. {
  433. memcpy(aouts_tmp_buf1, ains_tmp_buf1, sizeof(float)*nframes);
  434. memcpy(aouts_tmp_buf2, ains_tmp_buf2, sizeof(float)*nframes);
  435. memcpy(rackMidiEventsOut, rackMidiEventsIn, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  436. }
  437. // output audio
  438. memcpy(audioOut1, aouts_tmp_buf1, sizeof(float)*nframes);
  439. memcpy(audioOut2, aouts_tmp_buf2, sizeof(float)*nframes);
  440. // output control
  441. {
  442. jackbridge_midi_clear_buffer(controlOut);
  443. for (unsigned short i=0; i < MAX_ENGINE_CONTROL_EVENTS; i++)
  444. {
  445. CarlaEngineControlEvent* const event = &rackControlEventsOut[i];
  446. if (event->type == CarlaEngineEventControlChange && MIDI_IS_CONTROL_BANK_SELECT(event->controller))
  447. event->type = CarlaEngineEventMidiBankChange;
  448. uint8_t data[4] = { 0 };
  449. switch (event->type)
  450. {
  451. case CarlaEngineEventNull:
  452. break;
  453. case CarlaEngineEventControlChange:
  454. data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel;
  455. data[1] = event->controller;
  456. data[2] = event->value * 127;
  457. jackbridge_midi_event_write(controlOut, event->time, data, 3);
  458. break;
  459. case CarlaEngineEventMidiBankChange:
  460. data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel;
  461. data[1] = MIDI_CONTROL_BANK_SELECT;
  462. data[2] = event->value;
  463. jackbridge_midi_event_write(controlOut, event->time, data, 3);
  464. break;
  465. case CarlaEngineEventMidiProgramChange:
  466. data[0] = MIDI_STATUS_PROGRAM_CHANGE + event->channel;
  467. data[1] = event->value;
  468. jackbridge_midi_event_write(controlOut, event->time, data, 2);
  469. break;
  470. case CarlaEngineEventAllSoundOff:
  471. data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel;
  472. data[1] = MIDI_CONTROL_ALL_SOUND_OFF;
  473. jackbridge_midi_event_write(controlOut, event->time, data, 2);
  474. break;
  475. case CarlaEngineEventAllNotesOff:
  476. data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel;
  477. data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
  478. jackbridge_midi_event_write(controlOut, event->time, data, 2);
  479. break;
  480. }
  481. }
  482. }
  483. // output midi
  484. {
  485. jackbridge_midi_clear_buffer(midiOut);
  486. for (unsigned short i=0; i < MAX_ENGINE_MIDI_EVENTS; i++)
  487. {
  488. if (rackMidiEventsOut[i].size == 0)
  489. break;
  490. jackbridge_midi_event_write(midiOut, rackMidiEventsOut[i].time, rackMidiEventsOut[i].data, rackMidiEventsOut[i].size);
  491. }
  492. }
  493. }
  494. #else
  495. Q_UNUSED(nframes);
  496. #endif
  497. }
  498. void CarlaEngineJack::handleShutdownCallback()
  499. {
  500. //for (unsigned short i=0; i < maxPluginNumber; i++)
  501. //{
  502. //CarlaPlugin* const plugin = getPluginUnchecked(i);
  503. //plugin->x_client
  504. //}
  505. client = nullptr;
  506. procThread = nullptr;
  507. callback(CALLBACK_QUIT, 0, 0, 0, 0.0);
  508. }
  509. CARLA_BACKEND_END_NAMESPACE
  510. #endif // CARLA_ENGINE_JACK