The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

607 lines
23KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. //==============================================================================
  19. static void* juce_libjackHandle = nullptr;
  20. static void* juce_loadJackFunction (const char* const name)
  21. {
  22. if (juce_libjackHandle == nullptr)
  23. return nullptr;
  24. return dlsym (juce_libjackHandle, name);
  25. }
  26. #define JUCE_DECL_JACK_FUNCTION(return_type, fn_name, argument_types, arguments) \
  27. return_type fn_name argument_types \
  28. { \
  29. typedef return_type (*fn_type) argument_types; \
  30. static fn_type fn = (fn_type) juce_loadJackFunction (#fn_name); \
  31. return (fn != nullptr) ? ((*fn) arguments) : (return_type) 0; \
  32. }
  33. #define JUCE_DECL_VOID_JACK_FUNCTION(fn_name, argument_types, arguments) \
  34. void fn_name argument_types \
  35. { \
  36. typedef void (*fn_type) argument_types; \
  37. static fn_type fn = (fn_type) juce_loadJackFunction (#fn_name); \
  38. if (fn != nullptr) (*fn) arguments; \
  39. }
  40. //==============================================================================
  41. JUCE_DECL_JACK_FUNCTION (jack_client_t*, jack_client_open, (const char* client_name, jack_options_t options, jack_status_t* status, ...), (client_name, options, status));
  42. JUCE_DECL_JACK_FUNCTION (int, jack_client_close, (jack_client_t *client), (client));
  43. JUCE_DECL_JACK_FUNCTION (int, jack_activate, (jack_client_t* client), (client));
  44. JUCE_DECL_JACK_FUNCTION (int, jack_deactivate, (jack_client_t* client), (client));
  45. JUCE_DECL_JACK_FUNCTION (jack_nframes_t, jack_get_buffer_size, (jack_client_t* client), (client));
  46. JUCE_DECL_JACK_FUNCTION (jack_nframes_t, jack_get_sample_rate, (jack_client_t* client), (client));
  47. JUCE_DECL_VOID_JACK_FUNCTION (jack_on_shutdown, (jack_client_t* client, void (*function)(void* arg), void* arg), (client, function, arg));
  48. JUCE_DECL_JACK_FUNCTION (void* , jack_port_get_buffer, (jack_port_t* port, jack_nframes_t nframes), (port, nframes));
  49. JUCE_DECL_JACK_FUNCTION (jack_nframes_t, jack_port_get_total_latency, (jack_client_t* client, jack_port_t* port), (client, port));
  50. JUCE_DECL_JACK_FUNCTION (jack_port_t* , jack_port_register, (jack_client_t* client, const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size), (client, port_name, port_type, flags, buffer_size));
  51. JUCE_DECL_VOID_JACK_FUNCTION (jack_set_error_function, (void (*func)(const char*)), (func));
  52. JUCE_DECL_JACK_FUNCTION (int, jack_set_process_callback, (jack_client_t* client, JackProcessCallback process_callback, void* arg), (client, process_callback, arg));
  53. JUCE_DECL_JACK_FUNCTION (const char**, jack_get_ports, (jack_client_t* client, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags), (client, port_name_pattern, type_name_pattern, flags));
  54. JUCE_DECL_JACK_FUNCTION (int, jack_connect, (jack_client_t* client, const char* source_port, const char* destination_port), (client, source_port, destination_port));
  55. JUCE_DECL_JACK_FUNCTION (const char*, jack_port_name, (const jack_port_t* port), (port));
  56. JUCE_DECL_JACK_FUNCTION (void*, jack_set_port_connect_callback, (jack_client_t* client, JackPortConnectCallback connect_callback, void* arg), (client, connect_callback, arg));
  57. JUCE_DECL_JACK_FUNCTION (jack_port_t* , jack_port_by_id, (jack_client_t* client, jack_port_id_t port_id), (client, port_id));
  58. JUCE_DECL_JACK_FUNCTION (int, jack_port_connected, (const jack_port_t* port), (port));
  59. JUCE_DECL_JACK_FUNCTION (int, jack_port_connected_to, (const jack_port_t* port, const char* port_name), (port, port_name));
  60. #if JUCE_DEBUG
  61. #define JACK_LOGGING_ENABLED 1
  62. #endif
  63. #if JACK_LOGGING_ENABLED
  64. namespace
  65. {
  66. void jack_Log (const String& s)
  67. {
  68. std::cerr << s << std::endl;
  69. }
  70. void dumpJackErrorMessage (const jack_status_t status)
  71. {
  72. if (status & JackServerFailed || status & JackServerError) jack_Log ("Unable to connect to JACK server");
  73. if (status & JackVersionError) jack_Log ("Client's protocol version does not match");
  74. if (status & JackInvalidOption) jack_Log ("The operation contained an invalid or unsupported option");
  75. if (status & JackNameNotUnique) jack_Log ("The desired client name was not unique");
  76. if (status & JackNoSuchClient) jack_Log ("Requested client does not exist");
  77. if (status & JackInitFailure) jack_Log ("Unable to initialize client");
  78. }
  79. }
  80. #else
  81. #define dumpJackErrorMessage(a) {}
  82. #define jack_Log(...) {}
  83. #endif
  84. //==============================================================================
  85. #ifndef JUCE_JACK_CLIENT_NAME
  86. #define JUCE_JACK_CLIENT_NAME "JUCEJack"
  87. #endif
  88. static const char** getJackPorts (jack_client_t* const client, const bool forInput)
  89. {
  90. if (client != nullptr)
  91. return juce::jack_get_ports (client, nullptr, nullptr,
  92. forInput ? JackPortIsOutput : JackPortIsInput);
  93. // (NB: This looks like it's the wrong way round, but it is correct!)
  94. return nullptr;
  95. }
  96. class JackAudioIODeviceType;
  97. static Array<JackAudioIODeviceType*> activeDeviceTypes;
  98. //==============================================================================
  99. class JackAudioIODevice : public AudioIODevice
  100. {
  101. public:
  102. JackAudioIODevice (const String& deviceName,
  103. const String& inId,
  104. const String& outId)
  105. : AudioIODevice (deviceName, "JACK"),
  106. inputId (inId),
  107. outputId (outId),
  108. isOpen_ (false),
  109. callback (nullptr),
  110. totalNumberOfInputChannels (0),
  111. totalNumberOfOutputChannels (0)
  112. {
  113. jassert (deviceName.isNotEmpty());
  114. jack_status_t status;
  115. client = juce::jack_client_open (JUCE_JACK_CLIENT_NAME, JackNoStartServer, &status);
  116. if (client == nullptr)
  117. {
  118. dumpJackErrorMessage (status);
  119. }
  120. else
  121. {
  122. juce::jack_set_error_function (errorCallback);
  123. // open input ports
  124. const StringArray inputChannels (getInputChannelNames());
  125. for (int i = 0; i < inputChannels.size(); ++i)
  126. {
  127. String inputName;
  128. inputName << "in_" << ++totalNumberOfInputChannels;
  129. inputPorts.add (juce::jack_port_register (client, inputName.toUTF8(),
  130. JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0));
  131. }
  132. // open output ports
  133. const StringArray outputChannels (getOutputChannelNames());
  134. for (int i = 0; i < outputChannels.size (); ++i)
  135. {
  136. String outputName;
  137. outputName << "out_" << ++totalNumberOfOutputChannels;
  138. outputPorts.add (juce::jack_port_register (client, outputName.toUTF8(),
  139. JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0));
  140. }
  141. inChans.calloc (totalNumberOfInputChannels + 2);
  142. outChans.calloc (totalNumberOfOutputChannels + 2);
  143. }
  144. }
  145. ~JackAudioIODevice()
  146. {
  147. close();
  148. if (client != nullptr)
  149. {
  150. juce::jack_client_close (client);
  151. client = nullptr;
  152. }
  153. }
  154. StringArray getChannelNames (bool forInput) const
  155. {
  156. StringArray names;
  157. if (const char** const ports = getJackPorts (client, forInput))
  158. {
  159. for (int j = 0; ports[j] != nullptr; ++j)
  160. {
  161. const String portName (ports [j]);
  162. if (portName.upToFirstOccurrenceOf (":", false, false) == getName())
  163. names.add (portName.fromFirstOccurrenceOf (":", false, false));
  164. }
  165. free (ports);
  166. }
  167. return names;
  168. }
  169. StringArray getOutputChannelNames() { return getChannelNames (false); }
  170. StringArray getInputChannelNames() { return getChannelNames (true); }
  171. int getNumSampleRates() { return client != nullptr ? 1 : 0; }
  172. double getSampleRate (int /*index*/) { return client != nullptr ? juce::jack_get_sample_rate (client) : 0; }
  173. int getNumBufferSizesAvailable() { return client != nullptr ? 1 : 0; }
  174. int getBufferSizeSamples (int /*index*/) { return getDefaultBufferSize(); }
  175. int getDefaultBufferSize() { return client != nullptr ? juce::jack_get_buffer_size (client) : 0; }
  176. String open (const BigInteger& inputChannels, const BigInteger& outputChannels,
  177. double /* sampleRate */, int /* bufferSizeSamples */)
  178. {
  179. if (client == nullptr)
  180. {
  181. lastError = "No JACK client running";
  182. return lastError;
  183. }
  184. lastError = String::empty;
  185. close();
  186. juce::jack_set_process_callback (client, processCallback, this);
  187. juce::jack_set_port_connect_callback (client, portConnectCallback, this);
  188. juce::jack_on_shutdown (client, shutdownCallback, this);
  189. juce::jack_activate (client);
  190. isOpen_ = true;
  191. if (! inputChannels.isZero())
  192. {
  193. if (const char** const ports = getJackPorts (client, true))
  194. {
  195. const int numInputChannels = inputChannels.getHighestBit() + 1;
  196. for (int i = 0; i < numInputChannels; ++i)
  197. {
  198. const String portName (ports[i]);
  199. if (inputChannels[i] && portName.upToFirstOccurrenceOf (":", false, false) == getName())
  200. {
  201. int error = juce::jack_connect (client, ports[i], juce::jack_port_name ((jack_port_t*) inputPorts[i]));
  202. if (error != 0)
  203. jack_Log ("Cannot connect input port " + String (i) + " (" + String (ports[i]) + "), error " + String (error));
  204. }
  205. }
  206. free (ports);
  207. }
  208. }
  209. if (! outputChannels.isZero())
  210. {
  211. if (const char** const ports = getJackPorts (client, false))
  212. {
  213. const int numOutputChannels = outputChannels.getHighestBit() + 1;
  214. for (int i = 0; i < numOutputChannels; ++i)
  215. {
  216. const String portName (ports[i]);
  217. if (outputChannels[i] && portName.upToFirstOccurrenceOf (":", false, false) == getName())
  218. {
  219. int error = juce::jack_connect (client, juce::jack_port_name ((jack_port_t*) outputPorts[i]), ports[i]);
  220. if (error != 0)
  221. jack_Log ("Cannot connect output port " + String (i) + " (" + String (ports[i]) + "), error " + String (error));
  222. }
  223. }
  224. free (ports);
  225. }
  226. }
  227. return lastError;
  228. }
  229. void close()
  230. {
  231. stop();
  232. if (client != nullptr)
  233. {
  234. juce::jack_deactivate (client);
  235. juce::jack_set_process_callback (client, processCallback, nullptr);
  236. juce::jack_set_port_connect_callback (client, portConnectCallback, nullptr);
  237. juce::jack_on_shutdown (client, shutdownCallback, nullptr);
  238. }
  239. isOpen_ = false;
  240. }
  241. void start (AudioIODeviceCallback* newCallback)
  242. {
  243. if (isOpen_ && newCallback != callback)
  244. {
  245. if (newCallback != nullptr)
  246. newCallback->audioDeviceAboutToStart (this);
  247. AudioIODeviceCallback* const oldCallback = callback;
  248. {
  249. const ScopedLock sl (callbackLock);
  250. callback = newCallback;
  251. }
  252. if (oldCallback != nullptr)
  253. oldCallback->audioDeviceStopped();
  254. }
  255. }
  256. void stop()
  257. {
  258. start (nullptr);
  259. }
  260. bool isOpen() { return isOpen_; }
  261. bool isPlaying() { return callback != nullptr; }
  262. int getCurrentBufferSizeSamples() { return getBufferSizeSamples (0); }
  263. double getCurrentSampleRate() { return getSampleRate (0); }
  264. int getCurrentBitDepth() { return 32; }
  265. String getLastError() { return lastError; }
  266. BigInteger getActiveOutputChannels() const { return activeOutputChannels; }
  267. BigInteger getActiveInputChannels() const { return activeInputChannels; }
  268. int getOutputLatencyInSamples()
  269. {
  270. int latency = 0;
  271. for (int i = 0; i < outputPorts.size(); i++)
  272. latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, (jack_port_t*) outputPorts [i]));
  273. return latency;
  274. }
  275. int getInputLatencyInSamples()
  276. {
  277. int latency = 0;
  278. for (int i = 0; i < inputPorts.size(); i++)
  279. latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, (jack_port_t*) inputPorts [i]));
  280. return latency;
  281. }
  282. String inputId, outputId;
  283. private:
  284. void process (const int numSamples)
  285. {
  286. int numActiveInChans = 0, numActiveOutChans = 0;
  287. for (int i = 0; i < totalNumberOfInputChannels; ++i)
  288. {
  289. if (activeInputChannels[i])
  290. if (jack_default_audio_sample_t* in
  291. = (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) inputPorts.getUnchecked(i), numSamples))
  292. inChans [numActiveInChans++] = (float*) in;
  293. }
  294. for (int i = 0; i < totalNumberOfOutputChannels; ++i)
  295. {
  296. if (activeOutputChannels[i])
  297. if (jack_default_audio_sample_t* out
  298. = (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) outputPorts.getUnchecked(i), numSamples))
  299. outChans [numActiveOutChans++] = (float*) out;
  300. }
  301. const ScopedLock sl (callbackLock);
  302. if (callback != nullptr)
  303. {
  304. if ((numActiveInChans + numActiveOutChans) > 0)
  305. callback->audioDeviceIOCallback (const_cast <const float**> (inChans.getData()), numActiveInChans,
  306. outChans, numActiveOutChans, numSamples);
  307. }
  308. else
  309. {
  310. for (int i = 0; i < numActiveOutChans; ++i)
  311. zeromem (outChans[i], sizeof (float) * numSamples);
  312. }
  313. }
  314. static int processCallback (jack_nframes_t nframes, void* callbackArgument)
  315. {
  316. if (callbackArgument != nullptr)
  317. ((JackAudioIODevice*) callbackArgument)->process (nframes);
  318. return 0;
  319. }
  320. void updateActivePorts()
  321. {
  322. BigInteger newOutputChannels, newInputChannels;
  323. for (int i = 0; i < outputPorts.size(); ++i)
  324. if (juce::jack_port_connected ((jack_port_t*) outputPorts.getUnchecked(i)))
  325. newOutputChannels.setBit (i);
  326. for (int i = 0; i < inputPorts.size(); ++i)
  327. if (juce::jack_port_connected ((jack_port_t*) inputPorts.getUnchecked(i)))
  328. newInputChannels.setBit (i);
  329. if (newOutputChannels != activeOutputChannels
  330. || newInputChannels != activeInputChannels)
  331. {
  332. AudioIODeviceCallback* const oldCallback = callback;
  333. stop();
  334. activeOutputChannels = newOutputChannels;
  335. activeInputChannels = newInputChannels;
  336. if (oldCallback != nullptr)
  337. start (oldCallback);
  338. sendDeviceChangedCallback();
  339. }
  340. }
  341. static void portConnectCallback (jack_port_id_t, jack_port_id_t, int, void* arg)
  342. {
  343. if (JackAudioIODevice* device = static_cast <JackAudioIODevice*> (arg))
  344. device->updateActivePorts();
  345. }
  346. static void threadInitCallback (void* /* callbackArgument */)
  347. {
  348. jack_Log ("JackAudioIODevice::initialise");
  349. }
  350. static void shutdownCallback (void* callbackArgument)
  351. {
  352. jack_Log ("JackAudioIODevice::shutdown");
  353. if (JackAudioIODevice* device = (JackAudioIODevice*) callbackArgument)
  354. {
  355. device->client = nullptr;
  356. device->close();
  357. }
  358. }
  359. static void errorCallback (const char* msg)
  360. {
  361. jack_Log ("JackAudioIODevice::errorCallback " + String (msg));
  362. }
  363. static void sendDeviceChangedCallback();
  364. bool isOpen_;
  365. jack_client_t* client;
  366. String lastError;
  367. AudioIODeviceCallback* callback;
  368. CriticalSection callbackLock;
  369. HeapBlock <float*> inChans, outChans;
  370. int totalNumberOfInputChannels;
  371. int totalNumberOfOutputChannels;
  372. Array<void*> inputPorts, outputPorts;
  373. BigInteger activeInputChannels, activeOutputChannels;
  374. };
  375. //==============================================================================
  376. class JackAudioIODeviceType : public AudioIODeviceType
  377. {
  378. public:
  379. JackAudioIODeviceType()
  380. : AudioIODeviceType ("JACK"),
  381. hasScanned (false)
  382. {
  383. activeDeviceTypes.add (this);
  384. }
  385. ~JackAudioIODeviceType()
  386. {
  387. activeDeviceTypes.removeFirstMatchingValue (this);
  388. }
  389. void scanForDevices()
  390. {
  391. hasScanned = true;
  392. inputNames.clear();
  393. inputIds.clear();
  394. outputNames.clear();
  395. outputIds.clear();
  396. if (juce_libjackHandle == nullptr)
  397. {
  398. juce_libjackHandle = dlopen ("libjack.so", RTLD_LAZY);
  399. if (juce_libjackHandle == nullptr)
  400. return;
  401. }
  402. jack_status_t status;
  403. // open a dummy client
  404. if (jack_client_t* const client = juce::jack_client_open ("JuceJackDummy", JackNoStartServer, &status))
  405. {
  406. // scan for output devices
  407. if (const char** const ports = getJackPorts (client, false))
  408. {
  409. for (int j = 0; ports[j] != nullptr; ++j)
  410. {
  411. String clientName (ports[j]);
  412. clientName = clientName.upToFirstOccurrenceOf (":", false, false);
  413. if (clientName != (JUCE_JACK_CLIENT_NAME) && ! inputNames.contains (clientName))
  414. {
  415. inputNames.add (clientName);
  416. inputIds.add (ports [j]);
  417. }
  418. }
  419. free (ports);
  420. }
  421. // scan for input devices
  422. if (const char** const ports = getJackPorts (client, true))
  423. {
  424. for (int j = 0; ports[j] != nullptr; ++j)
  425. {
  426. String clientName (ports[j]);
  427. clientName = clientName.upToFirstOccurrenceOf (":", false, false);
  428. if (clientName != (JUCE_JACK_CLIENT_NAME) && ! outputNames.contains (clientName))
  429. {
  430. outputNames.add (clientName);
  431. outputIds.add (ports [j]);
  432. }
  433. }
  434. free (ports);
  435. }
  436. juce::jack_client_close (client);
  437. }
  438. else
  439. {
  440. dumpJackErrorMessage (status);
  441. }
  442. }
  443. StringArray getDeviceNames (bool wantInputNames) const
  444. {
  445. jassert (hasScanned); // need to call scanForDevices() before doing this
  446. return wantInputNames ? inputNames : outputNames;
  447. }
  448. int getDefaultDeviceIndex (bool /* forInput */) const
  449. {
  450. jassert (hasScanned); // need to call scanForDevices() before doing this
  451. return 0;
  452. }
  453. bool hasSeparateInputsAndOutputs() const { return true; }
  454. int getIndexOfDevice (AudioIODevice* device, bool asInput) const
  455. {
  456. jassert (hasScanned); // need to call scanForDevices() before doing this
  457. if (JackAudioIODevice* d = dynamic_cast <JackAudioIODevice*> (device))
  458. return asInput ? inputIds.indexOf (d->inputId)
  459. : outputIds.indexOf (d->outputId);
  460. return -1;
  461. }
  462. AudioIODevice* createDevice (const String& outputDeviceName,
  463. const String& inputDeviceName)
  464. {
  465. jassert (hasScanned); // need to call scanForDevices() before doing this
  466. const int inputIndex = inputNames.indexOf (inputDeviceName);
  467. const int outputIndex = outputNames.indexOf (outputDeviceName);
  468. if (inputIndex >= 0 || outputIndex >= 0)
  469. return new JackAudioIODevice (outputIndex >= 0 ? outputDeviceName
  470. : inputDeviceName,
  471. inputIds [inputIndex],
  472. outputIds [outputIndex]);
  473. return nullptr;
  474. }
  475. void portConnectionChange() { callDeviceChangeListeners(); }
  476. private:
  477. StringArray inputNames, outputNames, inputIds, outputIds;
  478. bool hasScanned;
  479. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JackAudioIODeviceType)
  480. };
  481. void JackAudioIODevice::sendDeviceChangedCallback()
  482. {
  483. for (int i = activeDeviceTypes.size(); --i >= 0;)
  484. if (JackAudioIODeviceType* d = activeDeviceTypes[i])
  485. d->portConnectionChange();
  486. }
  487. //==============================================================================
  488. AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_JACK()
  489. {
  490. return new JackAudioIODeviceType();
  491. }