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.

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