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.

592 lines
22KB

  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. const char* getJackErrorMessage (const jack_status_t status)
  71. {
  72. if (status & JackServerFailed
  73. || status & JackServerError) return "Unable to connect to JACK server";
  74. if (status & JackVersionError) return "Client's protocol version does not match";
  75. if (status & JackInvalidOption) return "The operation contained an invalid or unsupported option";
  76. if (status & JackNameNotUnique) return "The desired client name was not unique";
  77. if (status & JackNoSuchClient) return "Requested client does not exist";
  78. if (status & JackInitFailure) return "Unable to initialize client";
  79. return nullptr;
  80. }
  81. }
  82. #define JUCE_JACK_LOG_STATUS(x) { if (const char* m = getJackErrorMessage (x)) jack_Log (m); }
  83. #define JUCE_JACK_LOG(x) jack_Log(x)
  84. #else
  85. #define JUCE_JACK_LOG_STATUS(x) {}
  86. #define JUCE_JACK_LOG(x) {}
  87. #endif
  88. //==============================================================================
  89. #ifndef JUCE_JACK_CLIENT_NAME
  90. #define JUCE_JACK_CLIENT_NAME "JUCEJack"
  91. #endif
  92. struct JackPortIterator
  93. {
  94. JackPortIterator (jack_client_t* const client, const bool forInput)
  95. : ports (nullptr), index (-1)
  96. {
  97. if (client != nullptr)
  98. ports = juce::jack_get_ports (client, nullptr, nullptr,
  99. forInput ? JackPortIsOutput : JackPortIsInput);
  100. // (NB: This looks like it's the wrong way round, but it is correct!)
  101. }
  102. ~JackPortIterator()
  103. {
  104. ::free (ports);
  105. }
  106. bool next()
  107. {
  108. if (ports == nullptr || ports [index + 1] == nullptr)
  109. return false;
  110. name = CharPointer_UTF8 (ports[++index]);
  111. clientName = name.upToFirstOccurrenceOf (":", false, false);
  112. return true;
  113. }
  114. const char** ports;
  115. int index;
  116. String name;
  117. String clientName;
  118. };
  119. class JackAudioIODeviceType;
  120. static Array<JackAudioIODeviceType*> activeDeviceTypes;
  121. //==============================================================================
  122. class JackAudioIODevice : public AudioIODevice
  123. {
  124. public:
  125. JackAudioIODevice (const String& deviceName,
  126. const String& inId,
  127. const String& outId)
  128. : AudioIODevice (deviceName, "JACK"),
  129. inputId (inId),
  130. outputId (outId),
  131. deviceIsOpen (false),
  132. callback (nullptr),
  133. totalNumberOfInputChannels (0),
  134. totalNumberOfOutputChannels (0)
  135. {
  136. jassert (deviceName.isNotEmpty());
  137. jack_status_t status;
  138. client = juce::jack_client_open (JUCE_JACK_CLIENT_NAME, JackNoStartServer, &status);
  139. if (client == nullptr)
  140. {
  141. JUCE_JACK_LOG_STATUS (status);
  142. }
  143. else
  144. {
  145. juce::jack_set_error_function (errorCallback);
  146. // open input ports
  147. const StringArray inputChannels (getInputChannelNames());
  148. for (int i = 0; i < inputChannels.size(); ++i)
  149. {
  150. String inputName;
  151. inputName << "in_" << ++totalNumberOfInputChannels;
  152. inputPorts.add (juce::jack_port_register (client, inputName.toUTF8(),
  153. JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0));
  154. }
  155. // open output ports
  156. const StringArray outputChannels (getOutputChannelNames());
  157. for (int i = 0; i < outputChannels.size (); ++i)
  158. {
  159. String outputName;
  160. outputName << "out_" << ++totalNumberOfOutputChannels;
  161. outputPorts.add (juce::jack_port_register (client, outputName.toUTF8(),
  162. JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0));
  163. }
  164. inChans.calloc (totalNumberOfInputChannels + 2);
  165. outChans.calloc (totalNumberOfOutputChannels + 2);
  166. }
  167. }
  168. ~JackAudioIODevice()
  169. {
  170. close();
  171. if (client != nullptr)
  172. {
  173. juce::jack_client_close (client);
  174. client = nullptr;
  175. }
  176. }
  177. StringArray getChannelNames (bool forInput) const
  178. {
  179. StringArray names;
  180. for (JackPortIterator i (client, forInput); i.next();)
  181. if (i.clientName == getName())
  182. names.add (i.name.fromFirstOccurrenceOf (":", false, false));
  183. return names;
  184. }
  185. StringArray getOutputChannelNames() { return getChannelNames (false); }
  186. StringArray getInputChannelNames() { return getChannelNames (true); }
  187. int getNumSampleRates() { return client != nullptr ? 1 : 0; }
  188. double getSampleRate (int /*index*/) { return client != nullptr ? juce::jack_get_sample_rate (client) : 0; }
  189. int getNumBufferSizesAvailable() { return client != nullptr ? 1 : 0; }
  190. int getBufferSizeSamples (int /*index*/) { return getDefaultBufferSize(); }
  191. int getDefaultBufferSize() { return client != nullptr ? juce::jack_get_buffer_size (client) : 0; }
  192. String open (const BigInteger& inputChannels, const BigInteger& outputChannels,
  193. double /* sampleRate */, int /* bufferSizeSamples */)
  194. {
  195. if (client == nullptr)
  196. {
  197. lastError = "No JACK client running";
  198. return lastError;
  199. }
  200. lastError = String::empty;
  201. close();
  202. juce::jack_set_process_callback (client, processCallback, this);
  203. juce::jack_set_port_connect_callback (client, portConnectCallback, this);
  204. juce::jack_on_shutdown (client, shutdownCallback, this);
  205. juce::jack_activate (client);
  206. deviceIsOpen = true;
  207. if (! inputChannels.isZero())
  208. {
  209. for (JackPortIterator i (client, true); i.next();)
  210. {
  211. if (inputChannels [i.index] && i.clientName == getName())
  212. {
  213. int error = juce::jack_connect (client, i.ports[i.index], juce::jack_port_name ((jack_port_t*) inputPorts[i.index]));
  214. if (error != 0)
  215. JUCE_JACK_LOG ("Cannot connect input port " + String (i.index) + " (" + i.name + "), error " + String (error));
  216. }
  217. }
  218. }
  219. if (! outputChannels.isZero())
  220. {
  221. for (JackPortIterator i (client, false); i.next();)
  222. {
  223. if (outputChannels [i.index] && i.clientName == getName())
  224. {
  225. int error = juce::jack_connect (client, juce::jack_port_name ((jack_port_t*) outputPorts[i.index]), i.ports[i.index]);
  226. if (error != 0)
  227. JUCE_JACK_LOG ("Cannot connect output port " + String (i.index) + " (" + i.name + "), error " + String (error));
  228. }
  229. }
  230. }
  231. return lastError;
  232. }
  233. void close()
  234. {
  235. stop();
  236. if (client != nullptr)
  237. {
  238. juce::jack_deactivate (client);
  239. juce::jack_set_process_callback (client, processCallback, nullptr);
  240. juce::jack_set_port_connect_callback (client, portConnectCallback, nullptr);
  241. juce::jack_on_shutdown (client, shutdownCallback, nullptr);
  242. }
  243. deviceIsOpen = false;
  244. }
  245. void start (AudioIODeviceCallback* newCallback)
  246. {
  247. if (deviceIsOpen && newCallback != callback)
  248. {
  249. if (newCallback != nullptr)
  250. newCallback->audioDeviceAboutToStart (this);
  251. AudioIODeviceCallback* const oldCallback = callback;
  252. {
  253. const ScopedLock sl (callbackLock);
  254. callback = newCallback;
  255. }
  256. if (oldCallback != nullptr)
  257. oldCallback->audioDeviceStopped();
  258. }
  259. }
  260. void stop()
  261. {
  262. start (nullptr);
  263. }
  264. bool isOpen() { return deviceIsOpen; }
  265. bool isPlaying() { return callback != nullptr; }
  266. int getCurrentBufferSizeSamples() { return getBufferSizeSamples (0); }
  267. double getCurrentSampleRate() { return getSampleRate (0); }
  268. int getCurrentBitDepth() { return 32; }
  269. String getLastError() { return lastError; }
  270. BigInteger getActiveOutputChannels() const { return activeOutputChannels; }
  271. BigInteger getActiveInputChannels() const { return activeInputChannels; }
  272. int getOutputLatencyInSamples()
  273. {
  274. int latency = 0;
  275. for (int i = 0; i < outputPorts.size(); i++)
  276. latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, (jack_port_t*) outputPorts [i]));
  277. return latency;
  278. }
  279. int getInputLatencyInSamples()
  280. {
  281. int latency = 0;
  282. for (int i = 0; i < inputPorts.size(); i++)
  283. latency = jmax (latency, (int) juce::jack_port_get_total_latency (client, (jack_port_t*) inputPorts [i]));
  284. return latency;
  285. }
  286. String inputId, outputId;
  287. private:
  288. void process (const int numSamples)
  289. {
  290. int numActiveInChans = 0, numActiveOutChans = 0;
  291. for (int i = 0; i < totalNumberOfInputChannels; ++i)
  292. {
  293. if (activeInputChannels[i])
  294. if (jack_default_audio_sample_t* in
  295. = (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) inputPorts.getUnchecked(i), numSamples))
  296. inChans [numActiveInChans++] = (float*) in;
  297. }
  298. for (int i = 0; i < totalNumberOfOutputChannels; ++i)
  299. {
  300. if (activeOutputChannels[i])
  301. if (jack_default_audio_sample_t* out
  302. = (jack_default_audio_sample_t*) juce::jack_port_get_buffer ((jack_port_t*) outputPorts.getUnchecked(i), numSamples))
  303. outChans [numActiveOutChans++] = (float*) out;
  304. }
  305. const ScopedLock sl (callbackLock);
  306. if (callback != nullptr)
  307. {
  308. if ((numActiveInChans + numActiveOutChans) > 0)
  309. callback->audioDeviceIOCallback (const_cast <const float**> (inChans.getData()), numActiveInChans,
  310. outChans, numActiveOutChans, numSamples);
  311. }
  312. else
  313. {
  314. for (int i = 0; i < numActiveOutChans; ++i)
  315. zeromem (outChans[i], sizeof (float) * numSamples);
  316. }
  317. }
  318. static int processCallback (jack_nframes_t nframes, void* callbackArgument)
  319. {
  320. if (callbackArgument != nullptr)
  321. ((JackAudioIODevice*) callbackArgument)->process (nframes);
  322. return 0;
  323. }
  324. void updateActivePorts()
  325. {
  326. BigInteger newOutputChannels, newInputChannels;
  327. for (int i = 0; i < outputPorts.size(); ++i)
  328. if (juce::jack_port_connected ((jack_port_t*) outputPorts.getUnchecked(i)))
  329. newOutputChannels.setBit (i);
  330. for (int i = 0; i < inputPorts.size(); ++i)
  331. if (juce::jack_port_connected ((jack_port_t*) inputPorts.getUnchecked(i)))
  332. newInputChannels.setBit (i);
  333. if (newOutputChannels != activeOutputChannels
  334. || newInputChannels != activeInputChannels)
  335. {
  336. AudioIODeviceCallback* const oldCallback = callback;
  337. stop();
  338. activeOutputChannels = newOutputChannels;
  339. activeInputChannels = newInputChannels;
  340. if (oldCallback != nullptr)
  341. start (oldCallback);
  342. sendDeviceChangedCallback();
  343. }
  344. }
  345. static void portConnectCallback (jack_port_id_t, jack_port_id_t, int, void* arg)
  346. {
  347. if (JackAudioIODevice* device = static_cast <JackAudioIODevice*> (arg))
  348. device->updateActivePorts();
  349. }
  350. static void threadInitCallback (void* /* callbackArgument */)
  351. {
  352. JUCE_JACK_LOG ("JackAudioIODevice::initialise");
  353. }
  354. static void shutdownCallback (void* callbackArgument)
  355. {
  356. JUCE_JACK_LOG ("JackAudioIODevice::shutdown");
  357. if (JackAudioIODevice* device = (JackAudioIODevice*) callbackArgument)
  358. {
  359. device->client = nullptr;
  360. device->close();
  361. }
  362. }
  363. static void errorCallback (const char* msg)
  364. {
  365. JUCE_JACK_LOG ("JackAudioIODevice::errorCallback " + String (msg));
  366. }
  367. static void sendDeviceChangedCallback();
  368. bool deviceIsOpen;
  369. jack_client_t* client;
  370. String lastError;
  371. AudioIODeviceCallback* callback;
  372. CriticalSection callbackLock;
  373. HeapBlock <float*> inChans, outChans;
  374. int totalNumberOfInputChannels;
  375. int totalNumberOfOutputChannels;
  376. Array<void*> inputPorts, outputPorts;
  377. BigInteger activeInputChannels, activeOutputChannels;
  378. };
  379. //==============================================================================
  380. class JackAudioIODeviceType : public AudioIODeviceType
  381. {
  382. public:
  383. JackAudioIODeviceType()
  384. : AudioIODeviceType ("JACK"),
  385. hasScanned (false)
  386. {
  387. activeDeviceTypes.add (this);
  388. }
  389. ~JackAudioIODeviceType()
  390. {
  391. activeDeviceTypes.removeFirstMatchingValue (this);
  392. }
  393. void scanForDevices()
  394. {
  395. hasScanned = true;
  396. inputNames.clear();
  397. inputIds.clear();
  398. outputNames.clear();
  399. outputIds.clear();
  400. if (juce_libjackHandle == nullptr)
  401. {
  402. juce_libjackHandle = dlopen ("libjack.so", RTLD_LAZY);
  403. if (juce_libjackHandle == nullptr)
  404. return;
  405. }
  406. jack_status_t status;
  407. // open a dummy client
  408. if (jack_client_t* const client = juce::jack_client_open ("JuceJackDummy", JackNoStartServer, &status))
  409. {
  410. // scan for output devices
  411. for (JackPortIterator i (client, false); i.next();)
  412. {
  413. if (i.clientName != (JUCE_JACK_CLIENT_NAME) && ! inputNames.contains (i.clientName))
  414. {
  415. inputNames.add (i.clientName);
  416. inputIds.add (i.ports [i.index]);
  417. }
  418. }
  419. // scan for input devices
  420. for (JackPortIterator i (client, true); i.next();)
  421. {
  422. if (i.clientName != (JUCE_JACK_CLIENT_NAME) && ! outputNames.contains (i.clientName))
  423. {
  424. outputNames.add (i.clientName);
  425. outputIds.add (i.ports [i.index]);
  426. }
  427. }
  428. juce::jack_client_close (client);
  429. }
  430. else
  431. {
  432. JUCE_JACK_LOG_STATUS (status);
  433. }
  434. }
  435. StringArray getDeviceNames (bool wantInputNames) const
  436. {
  437. jassert (hasScanned); // need to call scanForDevices() before doing this
  438. return wantInputNames ? inputNames : outputNames;
  439. }
  440. int getDefaultDeviceIndex (bool /* forInput */) const
  441. {
  442. jassert (hasScanned); // need to call scanForDevices() before doing this
  443. return 0;
  444. }
  445. bool hasSeparateInputsAndOutputs() const { return true; }
  446. int getIndexOfDevice (AudioIODevice* device, bool asInput) const
  447. {
  448. jassert (hasScanned); // need to call scanForDevices() before doing this
  449. if (JackAudioIODevice* d = dynamic_cast <JackAudioIODevice*> (device))
  450. return asInput ? inputIds.indexOf (d->inputId)
  451. : outputIds.indexOf (d->outputId);
  452. return -1;
  453. }
  454. AudioIODevice* createDevice (const String& outputDeviceName,
  455. const String& inputDeviceName)
  456. {
  457. jassert (hasScanned); // need to call scanForDevices() before doing this
  458. const int inputIndex = inputNames.indexOf (inputDeviceName);
  459. const int outputIndex = outputNames.indexOf (outputDeviceName);
  460. if (inputIndex >= 0 || outputIndex >= 0)
  461. return new JackAudioIODevice (outputIndex >= 0 ? outputDeviceName
  462. : inputDeviceName,
  463. inputIds [inputIndex],
  464. outputIds [outputIndex]);
  465. return nullptr;
  466. }
  467. void portConnectionChange() { callDeviceChangeListeners(); }
  468. private:
  469. StringArray inputNames, outputNames, inputIds, outputIds;
  470. bool hasScanned;
  471. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JackAudioIODeviceType)
  472. };
  473. void JackAudioIODevice::sendDeviceChangedCallback()
  474. {
  475. for (int i = activeDeviceTypes.size(); --i >= 0;)
  476. if (JackAudioIODeviceType* d = activeDeviceTypes[i])
  477. d->portConnectionChange();
  478. }
  479. //==============================================================================
  480. AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_JACK()
  481. {
  482. return new JackAudioIODeviceType();
  483. }