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.

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