Audio plugin host https://kx.studio/carla
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.

644 lines
20KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2016 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of the ISC license
  6. http://www.isc.org/downloads/software-support-policy/isc-license/
  7. Permission to use, copy, modify, and/or distribute this software for any
  8. purpose with or without fee is hereby granted, provided that the above
  9. copyright notice and this permission notice appear in all copies.
  10. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
  11. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  12. FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
  13. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  14. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  16. OF THIS SOFTWARE.
  17. -----------------------------------------------------------------------------
  18. To release a closed-source product which uses other parts of JUCE not
  19. licensed under the ISC terms, commercial licenses are available: visit
  20. www.juce.com for more information.
  21. ==============================================================================
  22. */
  23. #if JUCE_ALSA
  24. // You can define these strings in your app if you want to override the default names:
  25. #ifndef JUCE_ALSA_MIDI_INPUT_NAME
  26. #define JUCE_ALSA_MIDI_INPUT_NAME "Juce Midi Input"
  27. #endif
  28. #ifndef JUCE_ALSA_MIDI_OUTPUT_NAME
  29. #define JUCE_ALSA_MIDI_OUTPUT_NAME "Juce Midi Output"
  30. #endif
  31. //==============================================================================
  32. namespace
  33. {
  34. class AlsaPortAndCallback;
  35. //==============================================================================
  36. class AlsaClient : public ReferenceCountedObject
  37. {
  38. public:
  39. typedef ReferenceCountedObjectPtr<AlsaClient> Ptr;
  40. static Ptr getInstance (bool forInput)
  41. {
  42. AlsaClient*& instance = (forInput ? inInstance : outInstance);
  43. if (instance == nullptr)
  44. instance = new AlsaClient (forInput);
  45. return instance;
  46. }
  47. bool isInput() const noexcept { return input; }
  48. void registerCallback (AlsaPortAndCallback* cb)
  49. {
  50. if (cb != nullptr)
  51. {
  52. {
  53. const ScopedLock sl (callbackLock);
  54. activeCallbacks.add (cb);
  55. if (inputThread == nullptr)
  56. inputThread = new MidiInputThread (*this);
  57. }
  58. inputThread->startThread();
  59. }
  60. }
  61. void unregisterCallback (AlsaPortAndCallback* cb)
  62. {
  63. const ScopedLock sl (callbackLock);
  64. jassert (activeCallbacks.contains (cb));
  65. activeCallbacks.removeAllInstancesOf (cb);
  66. if (activeCallbacks.size() == 0 && inputThread->isThreadRunning())
  67. inputThread->signalThreadShouldExit();
  68. }
  69. void handleIncomingMidiMessage (snd_seq_event*, const MidiMessage&);
  70. void handlePartialSysexMessage (snd_seq_event*, const uint8*, int, double);
  71. snd_seq_t* get() const noexcept { return handle; }
  72. private:
  73. bool input;
  74. snd_seq_t* handle;
  75. Array<AlsaPortAndCallback*> activeCallbacks;
  76. CriticalSection callbackLock;
  77. static AlsaClient* inInstance;
  78. static AlsaClient* outInstance;
  79. //==============================================================================
  80. friend class ReferenceCountedObjectPtr<AlsaClient>;
  81. friend struct ContainerDeletePolicy<AlsaClient>;
  82. AlsaClient (bool forInput)
  83. : input (forInput), handle (nullptr)
  84. {
  85. AlsaClient*& instance = (input ? inInstance : outInstance);
  86. jassert (instance == nullptr);
  87. instance = this;
  88. snd_seq_open (&handle, "default", forInput ? SND_SEQ_OPEN_INPUT
  89. : SND_SEQ_OPEN_OUTPUT, 0);
  90. snd_seq_set_client_name (handle, forInput ? JUCE_ALSA_MIDI_INPUT_NAME
  91. : JUCE_ALSA_MIDI_OUTPUT_NAME);
  92. }
  93. ~AlsaClient()
  94. {
  95. AlsaClient*& instance = (input ? inInstance : outInstance);
  96. jassert (instance != nullptr);
  97. instance = nullptr;
  98. if (handle != nullptr)
  99. {
  100. snd_seq_close (handle);
  101. handle = nullptr;
  102. }
  103. jassert (activeCallbacks.size() == 0);
  104. if (inputThread)
  105. {
  106. inputThread->stopThread (3000);
  107. inputThread = nullptr;
  108. }
  109. }
  110. //==============================================================================
  111. class MidiInputThread : public Thread
  112. {
  113. public:
  114. MidiInputThread (AlsaClient& c)
  115. : Thread ("Juce MIDI Input"), client (c), concatenator (2048)
  116. {
  117. jassert (client.input && client.get() != nullptr);
  118. }
  119. void run() override
  120. {
  121. const int maxEventSize = 16 * 1024;
  122. snd_midi_event_t* midiParser;
  123. snd_seq_t* seqHandle = client.get();
  124. if (snd_midi_event_new (maxEventSize, &midiParser) >= 0)
  125. {
  126. const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN);
  127. HeapBlock<pollfd> pfd ((size_t) numPfds);
  128. snd_seq_poll_descriptors (seqHandle, pfd, (unsigned int) numPfds, POLLIN);
  129. HeapBlock<uint8> buffer (maxEventSize);
  130. while (! threadShouldExit())
  131. {
  132. if (poll (pfd, (nfds_t) numPfds, 100) > 0) // there was a "500" here which is a bit long when we exit the program and have to wait for a timeout on this poll call
  133. {
  134. if (threadShouldExit())
  135. break;
  136. snd_seq_nonblock (seqHandle, 1);
  137. do
  138. {
  139. snd_seq_event_t* inputEvent = nullptr;
  140. if (snd_seq_event_input (seqHandle, &inputEvent) >= 0)
  141. {
  142. // xxx what about SYSEXes that are too big for the buffer?
  143. const long numBytes = snd_midi_event_decode (midiParser, buffer,
  144. maxEventSize, inputEvent);
  145. snd_midi_event_reset_decode (midiParser);
  146. concatenator.pushMidiData (buffer, (int) numBytes,
  147. Time::getMillisecondCounter() * 0.001,
  148. inputEvent, client);
  149. snd_seq_free_event (inputEvent);
  150. }
  151. }
  152. while (snd_seq_event_input_pending (seqHandle, 0) > 0);
  153. }
  154. }
  155. snd_midi_event_free (midiParser);
  156. }
  157. };
  158. private:
  159. AlsaClient& client;
  160. MidiDataConcatenator concatenator;
  161. };
  162. ScopedPointer<MidiInputThread> inputThread;
  163. };
  164. AlsaClient* AlsaClient::inInstance = nullptr;
  165. AlsaClient* AlsaClient::outInstance = nullptr;
  166. //==============================================================================
  167. // represents an input or output port of the supplied AlsaClient
  168. class AlsaPort
  169. {
  170. public:
  171. AlsaPort() noexcept : portId (-1) {}
  172. AlsaPort (const AlsaClient::Ptr& c, int port) noexcept : client (c), portId (port) {}
  173. void createPort (const AlsaClient::Ptr& c, const String& name, bool forInput)
  174. {
  175. client = c;
  176. if (snd_seq_t* handle = client->get())
  177. portId = snd_seq_create_simple_port (handle, name.toUTF8(),
  178. forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)
  179. : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ),
  180. SND_SEQ_PORT_TYPE_MIDI_GENERIC);
  181. }
  182. void deletePort()
  183. {
  184. if (isValid())
  185. {
  186. snd_seq_delete_simple_port (client->get(), portId);
  187. portId = -1;
  188. }
  189. }
  190. void connectWith (int sourceClient, int sourcePort)
  191. {
  192. if (client->isInput())
  193. snd_seq_connect_from (client->get(), portId, sourceClient, sourcePort);
  194. else
  195. snd_seq_connect_to (client->get(), portId, sourceClient, sourcePort);
  196. }
  197. bool isValid() const noexcept
  198. {
  199. return client != nullptr && client->get() != nullptr && portId >= 0;
  200. }
  201. AlsaClient::Ptr client;
  202. int portId;
  203. };
  204. //==============================================================================
  205. class AlsaPortAndCallback
  206. {
  207. public:
  208. AlsaPortAndCallback (AlsaPort p, MidiInput* in, MidiInputCallback* cb)
  209. : port (p), midiInput (in), callback (cb), callbackEnabled (false)
  210. {
  211. }
  212. ~AlsaPortAndCallback()
  213. {
  214. enableCallback (false);
  215. port.deletePort();
  216. }
  217. void enableCallback (bool enable)
  218. {
  219. if (callbackEnabled != enable)
  220. {
  221. callbackEnabled = enable;
  222. if (enable)
  223. port.client->registerCallback (this);
  224. else
  225. port.client->unregisterCallback (this);
  226. }
  227. }
  228. void handleIncomingMidiMessage (const MidiMessage& message) const
  229. {
  230. callback->handleIncomingMidiMessage (midiInput, message);
  231. }
  232. void handlePartialSysexMessage (const uint8* messageData, int numBytesSoFar, double timeStamp)
  233. {
  234. callback->handlePartialSysexMessage (midiInput, messageData, numBytesSoFar, timeStamp);
  235. }
  236. private:
  237. AlsaPort port;
  238. MidiInput* midiInput;
  239. MidiInputCallback* callback;
  240. bool callbackEnabled;
  241. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AlsaPortAndCallback)
  242. };
  243. void AlsaClient::handleIncomingMidiMessage (snd_seq_event_t* event, const MidiMessage& message)
  244. {
  245. const ScopedLock sl (callbackLock);
  246. if (AlsaPortAndCallback* const cb = activeCallbacks[event->dest.port])
  247. cb->handleIncomingMidiMessage (message);
  248. }
  249. void AlsaClient::handlePartialSysexMessage (snd_seq_event* event, const uint8* messageData, int numBytesSoFar, double timeStamp)
  250. {
  251. const ScopedLock sl (callbackLock);
  252. if (AlsaPortAndCallback* const cb = activeCallbacks[event->dest.port])
  253. cb->handlePartialSysexMessage (messageData, numBytesSoFar, timeStamp);
  254. }
  255. //==============================================================================
  256. static AlsaPort iterateMidiClient (const AlsaClient::Ptr& seq,
  257. snd_seq_client_info_t* clientInfo,
  258. const bool forInput,
  259. StringArray& deviceNamesFound,
  260. const int deviceIndexToOpen)
  261. {
  262. AlsaPort port;
  263. snd_seq_t* seqHandle = seq->get();
  264. snd_seq_port_info_t* portInfo = nullptr;
  265. if (snd_seq_port_info_malloc (&portInfo) == 0)
  266. {
  267. int numPorts = snd_seq_client_info_get_num_ports (clientInfo);
  268. const int client = snd_seq_client_info_get_client (clientInfo);
  269. snd_seq_port_info_set_client (portInfo, client);
  270. snd_seq_port_info_set_port (portInfo, -1);
  271. while (--numPorts >= 0)
  272. {
  273. if (snd_seq_query_next_port (seqHandle, portInfo) == 0
  274. && (snd_seq_port_info_get_capability (portInfo) & (forInput ? SND_SEQ_PORT_CAP_READ
  275. : SND_SEQ_PORT_CAP_WRITE)) != 0)
  276. {
  277. const String clientName = snd_seq_client_info_get_name (clientInfo);
  278. const String portName = snd_seq_port_info_get_name(portInfo);
  279. if (clientName == portName)
  280. deviceNamesFound.add (clientName);
  281. else
  282. deviceNamesFound.add (clientName + ": " + portName);
  283. if (deviceNamesFound.size() == deviceIndexToOpen + 1)
  284. {
  285. const int sourcePort = snd_seq_port_info_get_port (portInfo);
  286. if (sourcePort != -1)
  287. {
  288. const int sourceClient = snd_seq_client_info_get_client (clientInfo);
  289. port.createPort (seq, portName, forInput);
  290. port.connectWith (sourceClient, sourcePort);
  291. }
  292. }
  293. }
  294. }
  295. snd_seq_port_info_free (portInfo);
  296. }
  297. return port;
  298. }
  299. static AlsaPort iterateMidiDevices (const bool forInput,
  300. StringArray& deviceNamesFound,
  301. const int deviceIndexToOpen)
  302. {
  303. AlsaPort port;
  304. const AlsaClient::Ptr client (AlsaClient::getInstance (forInput));
  305. if (snd_seq_t* const seqHandle = client->get())
  306. {
  307. snd_seq_system_info_t* systemInfo = nullptr;
  308. snd_seq_client_info_t* clientInfo = nullptr;
  309. if (snd_seq_system_info_malloc (&systemInfo) == 0)
  310. {
  311. if (snd_seq_system_info (seqHandle, systemInfo) == 0
  312. && snd_seq_client_info_malloc (&clientInfo) == 0)
  313. {
  314. int numClients = snd_seq_system_info_get_cur_clients (systemInfo);
  315. while (--numClients >= 0 && ! port.isValid())
  316. if (snd_seq_query_next_client (seqHandle, clientInfo) == 0)
  317. port = iterateMidiClient (client, clientInfo, forInput,
  318. deviceNamesFound, deviceIndexToOpen);
  319. snd_seq_client_info_free (clientInfo);
  320. }
  321. snd_seq_system_info_free (systemInfo);
  322. }
  323. }
  324. deviceNamesFound.appendNumbersToDuplicates (true, true);
  325. return port;
  326. }
  327. //==============================================================================
  328. class MidiOutputDevice
  329. {
  330. public:
  331. MidiOutputDevice (MidiOutput* const output, const AlsaPort& p)
  332. : midiOutput (output), port (p),
  333. maxEventSize (16 * 1024)
  334. {
  335. jassert (port.isValid() && midiOutput != nullptr);
  336. snd_midi_event_new ((size_t) maxEventSize, &midiParser);
  337. }
  338. ~MidiOutputDevice()
  339. {
  340. snd_midi_event_free (midiParser);
  341. port.deletePort();
  342. }
  343. bool sendMessageNow (const MidiMessage& message)
  344. {
  345. if (message.getRawDataSize() > maxEventSize)
  346. {
  347. maxEventSize = message.getRawDataSize();
  348. snd_midi_event_free (midiParser);
  349. snd_midi_event_new ((size_t) maxEventSize, &midiParser);
  350. }
  351. snd_seq_event_t event;
  352. snd_seq_ev_clear (&event);
  353. long numBytes = (long) message.getRawDataSize();
  354. const uint8* data = message.getRawData();
  355. snd_seq_t* seqHandle = port.client->get();
  356. bool success = true;
  357. while (numBytes > 0)
  358. {
  359. const long numSent = snd_midi_event_encode (midiParser, data, numBytes, &event);
  360. if (numSent <= 0)
  361. {
  362. success = numSent == 0;
  363. break;
  364. }
  365. numBytes -= numSent;
  366. data += numSent;
  367. snd_seq_ev_set_source (&event, port.portId);
  368. snd_seq_ev_set_subs (&event);
  369. snd_seq_ev_set_direct (&event);
  370. if (snd_seq_event_output_direct (seqHandle, &event) < 0)
  371. {
  372. success = false;
  373. break;
  374. }
  375. }
  376. snd_midi_event_reset_encode (midiParser);
  377. return success;
  378. }
  379. private:
  380. MidiOutput* const midiOutput;
  381. AlsaPort port;
  382. snd_midi_event_t* midiParser;
  383. int maxEventSize;
  384. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutputDevice)
  385. };
  386. } // namespace
  387. StringArray MidiOutput::getDevices()
  388. {
  389. StringArray devices;
  390. iterateMidiDevices (false, devices, -1);
  391. return devices;
  392. }
  393. int MidiOutput::getDefaultDeviceIndex()
  394. {
  395. return 0;
  396. }
  397. MidiOutput* MidiOutput::openDevice (int deviceIndex)
  398. {
  399. MidiOutput* newDevice = nullptr;
  400. StringArray devices;
  401. AlsaPort port (iterateMidiDevices (false, devices, deviceIndex));
  402. if (port.isValid())
  403. {
  404. newDevice = new MidiOutput (devices [deviceIndex]);
  405. newDevice->internal = new MidiOutputDevice (newDevice, port);
  406. }
  407. return newDevice;
  408. }
  409. MidiOutput* MidiOutput::createNewDevice (const String& deviceName)
  410. {
  411. MidiOutput* newDevice = nullptr;
  412. AlsaPort port;
  413. const AlsaClient::Ptr client (AlsaClient::getInstance (false));
  414. port.createPort (client, deviceName, false);
  415. if (port.isValid())
  416. {
  417. newDevice = new MidiOutput (deviceName);
  418. newDevice->internal = new MidiOutputDevice (newDevice, port);
  419. }
  420. return newDevice;
  421. }
  422. MidiOutput::~MidiOutput()
  423. {
  424. stopBackgroundThread();
  425. delete static_cast<MidiOutputDevice*> (internal);
  426. }
  427. void MidiOutput::sendMessageNow (const MidiMessage& message)
  428. {
  429. static_cast<MidiOutputDevice*> (internal)->sendMessageNow (message);
  430. }
  431. //==============================================================================
  432. MidiInput::MidiInput (const String& nm)
  433. : name (nm), internal (nullptr)
  434. {
  435. }
  436. MidiInput::~MidiInput()
  437. {
  438. stop();
  439. delete static_cast<AlsaPortAndCallback*> (internal);
  440. }
  441. void MidiInput::start()
  442. {
  443. static_cast<AlsaPortAndCallback*> (internal)->enableCallback (true);
  444. }
  445. void MidiInput::stop()
  446. {
  447. static_cast<AlsaPortAndCallback*> (internal)->enableCallback (false);
  448. }
  449. int MidiInput::getDefaultDeviceIndex()
  450. {
  451. return 0;
  452. }
  453. StringArray MidiInput::getDevices()
  454. {
  455. StringArray devices;
  456. iterateMidiDevices (true, devices, -1);
  457. return devices;
  458. }
  459. MidiInput* MidiInput::openDevice (int deviceIndex, MidiInputCallback* callback)
  460. {
  461. MidiInput* newDevice = nullptr;
  462. StringArray devices;
  463. AlsaPort port (iterateMidiDevices (true, devices, deviceIndex));
  464. if (port.isValid())
  465. {
  466. newDevice = new MidiInput (devices [deviceIndex]);
  467. newDevice->internal = new AlsaPortAndCallback (port, newDevice, callback);
  468. }
  469. return newDevice;
  470. }
  471. MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback)
  472. {
  473. MidiInput* newDevice = nullptr;
  474. AlsaPort port;
  475. const AlsaClient::Ptr client (AlsaClient::getInstance (true));
  476. port.createPort (client, deviceName, true);
  477. if (port.isValid())
  478. {
  479. newDevice = new MidiInput (deviceName);
  480. newDevice->internal = new AlsaPortAndCallback (port, newDevice, callback);
  481. }
  482. return newDevice;
  483. }
  484. //==============================================================================
  485. #else
  486. // (These are just stub functions if ALSA is unavailable...)
  487. StringArray MidiOutput::getDevices() { return StringArray(); }
  488. int MidiOutput::getDefaultDeviceIndex() { return 0; }
  489. MidiOutput* MidiOutput::openDevice (int) { return nullptr; }
  490. MidiOutput* MidiOutput::createNewDevice (const String&) { return nullptr; }
  491. MidiOutput::~MidiOutput() {}
  492. void MidiOutput::sendMessageNow (const MidiMessage&) {}
  493. MidiInput::MidiInput (const String& nm) : name (nm), internal (nullptr) {}
  494. MidiInput::~MidiInput() {}
  495. void MidiInput::start() {}
  496. void MidiInput::stop() {}
  497. int MidiInput::getDefaultDeviceIndex() { return 0; }
  498. StringArray MidiInput::getDevices() { return StringArray(); }
  499. MidiInput* MidiInput::openDevice (int, MidiInputCallback*) { return nullptr; }
  500. MidiInput* MidiInput::createNewDevice (const String&, MidiInputCallback*) { return nullptr; }
  501. #endif