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.

456 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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. // (This file gets included by juce_linux_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #ifdef JUCE_INCLUDED_FILE
  21. #if JUCE_ALSA
  22. //==============================================================================
  23. static snd_seq_t* iterateDevices (const bool forInput,
  24. StringArray& deviceNamesFound,
  25. const int deviceIndexToOpen)
  26. {
  27. snd_seq_t* returnedHandle = 0;
  28. snd_seq_t* seqHandle;
  29. if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT
  30. : SND_SEQ_OPEN_OUTPUT, 0) == 0)
  31. {
  32. snd_seq_system_info_t* systemInfo;
  33. snd_seq_client_info_t* clientInfo;
  34. if (snd_seq_system_info_malloc (&systemInfo) == 0)
  35. {
  36. if (snd_seq_system_info (seqHandle, systemInfo) == 0
  37. && snd_seq_client_info_malloc (&clientInfo) == 0)
  38. {
  39. int numClients = snd_seq_system_info_get_cur_clients (systemInfo);
  40. while (--numClients >= 0 && returnedHandle == 0)
  41. {
  42. if (snd_seq_query_next_client (seqHandle, clientInfo) == 0)
  43. {
  44. snd_seq_port_info_t* portInfo;
  45. if (snd_seq_port_info_malloc (&portInfo) == 0)
  46. {
  47. int numPorts = snd_seq_client_info_get_num_ports (clientInfo);
  48. const int client = snd_seq_client_info_get_client (clientInfo);
  49. snd_seq_port_info_set_client (portInfo, client);
  50. snd_seq_port_info_set_port (portInfo, -1);
  51. while (--numPorts >= 0)
  52. {
  53. if (snd_seq_query_next_port (seqHandle, portInfo) == 0
  54. && (snd_seq_port_info_get_capability (portInfo)
  55. & (forInput ? SND_SEQ_PORT_CAP_READ
  56. : SND_SEQ_PORT_CAP_WRITE)) != 0)
  57. {
  58. deviceNamesFound.add (snd_seq_client_info_get_name (clientInfo));
  59. if (deviceNamesFound.size() == deviceIndexToOpen + 1)
  60. {
  61. const int sourcePort = snd_seq_port_info_get_port (portInfo);
  62. const int sourceClient = snd_seq_client_info_get_client (clientInfo);
  63. if (sourcePort != -1)
  64. {
  65. snd_seq_set_client_name (seqHandle,
  66. forInput ? "Juce Midi Input"
  67. : "Juce Midi Output");
  68. const int portId
  69. = snd_seq_create_simple_port (seqHandle,
  70. forInput ? "Juce Midi In Port"
  71. : "Juce Midi Out Port",
  72. forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)
  73. : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ),
  74. SND_SEQ_PORT_TYPE_MIDI_GENERIC);
  75. snd_seq_connect_from (seqHandle, portId, sourceClient, sourcePort);
  76. returnedHandle = seqHandle;
  77. }
  78. }
  79. }
  80. }
  81. snd_seq_port_info_free (portInfo);
  82. }
  83. }
  84. }
  85. snd_seq_client_info_free (clientInfo);
  86. }
  87. snd_seq_system_info_free (systemInfo);
  88. }
  89. if (returnedHandle == 0)
  90. snd_seq_close (seqHandle);
  91. }
  92. deviceNamesFound.appendNumbersToDuplicates (true, true);
  93. return returnedHandle;
  94. }
  95. static snd_seq_t* createDevice (const bool forInput,
  96. const String& deviceNameToOpen)
  97. {
  98. snd_seq_t* seqHandle = 0;
  99. if (snd_seq_open (&seqHandle, "default", forInput ? SND_SEQ_OPEN_INPUT
  100. : SND_SEQ_OPEN_OUTPUT, 0) == 0)
  101. {
  102. snd_seq_set_client_name (seqHandle,
  103. (const char*) (forInput ? (deviceNameToOpen + T(" Input"))
  104. : (deviceNameToOpen + T(" Output"))));
  105. const int portId
  106. = snd_seq_create_simple_port (seqHandle,
  107. forInput ? "in"
  108. : "out",
  109. forInput ? (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE)
  110. : (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ),
  111. forInput ? SND_SEQ_PORT_TYPE_APPLICATION
  112. : SND_SEQ_PORT_TYPE_MIDI_GENERIC);
  113. if (portId < 0)
  114. {
  115. snd_seq_close (seqHandle);
  116. seqHandle = 0;
  117. }
  118. }
  119. return seqHandle;
  120. }
  121. //==============================================================================
  122. class MidiOutputDevice
  123. {
  124. public:
  125. MidiOutputDevice (MidiOutput* const midiOutput_,
  126. snd_seq_t* const seqHandle_)
  127. :
  128. midiOutput (midiOutput_),
  129. seqHandle (seqHandle_),
  130. maxEventSize (16 * 1024)
  131. {
  132. jassert (seqHandle != 0 && midiOutput != 0);
  133. snd_midi_event_new (maxEventSize, &midiParser);
  134. }
  135. ~MidiOutputDevice()
  136. {
  137. snd_midi_event_free (midiParser);
  138. snd_seq_close (seqHandle);
  139. }
  140. void sendMessageNow (const MidiMessage& message)
  141. {
  142. if (message.getRawDataSize() > maxEventSize)
  143. {
  144. maxEventSize = message.getRawDataSize();
  145. snd_midi_event_free (midiParser);
  146. snd_midi_event_new (maxEventSize, &midiParser);
  147. }
  148. snd_seq_event_t event;
  149. snd_seq_ev_clear (&event);
  150. snd_midi_event_encode (midiParser,
  151. message.getRawData(),
  152. message.getRawDataSize(),
  153. &event);
  154. snd_midi_event_reset_encode (midiParser);
  155. snd_seq_ev_set_source (&event, 0);
  156. snd_seq_ev_set_subs (&event);
  157. snd_seq_ev_set_direct (&event);
  158. snd_seq_event_output (seqHandle, &event);
  159. snd_seq_drain_output (seqHandle);
  160. }
  161. juce_UseDebuggingNewOperator
  162. private:
  163. MidiOutput* const midiOutput;
  164. snd_seq_t* const seqHandle;
  165. snd_midi_event_t* midiParser;
  166. int maxEventSize;
  167. };
  168. const StringArray MidiOutput::getDevices()
  169. {
  170. StringArray devices;
  171. iterateDevices (false, devices, -1);
  172. return devices;
  173. }
  174. int MidiOutput::getDefaultDeviceIndex()
  175. {
  176. return 0;
  177. }
  178. MidiOutput* MidiOutput::openDevice (int deviceIndex)
  179. {
  180. MidiOutput* newDevice = 0;
  181. StringArray devices;
  182. snd_seq_t* const handle = iterateDevices (false, devices, deviceIndex);
  183. if (handle != 0)
  184. {
  185. newDevice = new MidiOutput();
  186. newDevice->internal = new MidiOutputDevice (newDevice, handle);
  187. }
  188. return newDevice;
  189. }
  190. MidiOutput* MidiOutput::createNewDevice (const String& deviceName)
  191. {
  192. MidiOutput* newDevice = 0;
  193. snd_seq_t* const handle = createDevice (false, deviceName);
  194. if (handle != 0)
  195. {
  196. newDevice = new MidiOutput();
  197. newDevice->internal = new MidiOutputDevice (newDevice, handle);
  198. }
  199. return newDevice;
  200. }
  201. MidiOutput::~MidiOutput()
  202. {
  203. MidiOutputDevice* const device = (MidiOutputDevice*) internal;
  204. delete device;
  205. }
  206. void MidiOutput::reset()
  207. {
  208. }
  209. bool MidiOutput::getVolume (float& leftVol, float& rightVol)
  210. {
  211. return false;
  212. }
  213. void MidiOutput::setVolume (float leftVol, float rightVol)
  214. {
  215. }
  216. void MidiOutput::sendMessageNow (const MidiMessage& message)
  217. {
  218. ((MidiOutputDevice*) internal)->sendMessageNow (message);
  219. }
  220. //==============================================================================
  221. class MidiInputThread : public Thread
  222. {
  223. public:
  224. MidiInputThread (MidiInput* const midiInput_,
  225. snd_seq_t* const seqHandle_,
  226. MidiInputCallback* const callback_)
  227. : Thread (T("Juce MIDI Input")),
  228. midiInput (midiInput_),
  229. seqHandle (seqHandle_),
  230. callback (callback_)
  231. {
  232. jassert (seqHandle != 0 && callback != 0 && midiInput != 0);
  233. }
  234. ~MidiInputThread()
  235. {
  236. snd_seq_close (seqHandle);
  237. }
  238. void run()
  239. {
  240. const int maxEventSize = 16 * 1024;
  241. snd_midi_event_t* midiParser;
  242. if (snd_midi_event_new (maxEventSize, &midiParser) >= 0)
  243. {
  244. uint8* const buffer = (uint8*) juce_malloc (maxEventSize);
  245. const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN);
  246. struct pollfd* const pfd = (struct pollfd*) alloca (numPfds * sizeof (struct pollfd));
  247. snd_seq_poll_descriptors (seqHandle, pfd, numPfds, POLLIN);
  248. while (! threadShouldExit())
  249. {
  250. if (poll (pfd, numPfds, 500) > 0)
  251. {
  252. snd_seq_event_t* inputEvent = 0;
  253. snd_seq_nonblock (seqHandle, 1);
  254. do
  255. {
  256. if (snd_seq_event_input (seqHandle, &inputEvent) >= 0)
  257. {
  258. // xxx what about SYSEXes that are too big for the buffer?
  259. const int numBytes = snd_midi_event_decode (midiParser, buffer, maxEventSize, inputEvent);
  260. snd_midi_event_reset_decode (midiParser);
  261. if (numBytes > 0)
  262. {
  263. const MidiMessage message ((const uint8*) buffer,
  264. numBytes,
  265. Time::getMillisecondCounter() * 0.001);
  266. callback->handleIncomingMidiMessage (midiInput, message);
  267. }
  268. snd_seq_free_event (inputEvent);
  269. }
  270. }
  271. while (snd_seq_event_input_pending (seqHandle, 0) > 0);
  272. snd_seq_free_event (inputEvent);
  273. }
  274. }
  275. snd_midi_event_free (midiParser);
  276. juce_free (buffer);
  277. }
  278. };
  279. juce_UseDebuggingNewOperator
  280. private:
  281. MidiInput* const midiInput;
  282. snd_seq_t* const seqHandle;
  283. MidiInputCallback* const callback;
  284. };
  285. //==============================================================================
  286. MidiInput::MidiInput (const String& name_)
  287. : name (name_),
  288. internal (0)
  289. {
  290. }
  291. MidiInput::~MidiInput()
  292. {
  293. stop();
  294. MidiInputThread* const thread = (MidiInputThread*) internal;
  295. delete thread;
  296. }
  297. void MidiInput::start()
  298. {
  299. ((MidiInputThread*) internal)->startThread();
  300. }
  301. void MidiInput::stop()
  302. {
  303. ((MidiInputThread*) internal)->stopThread (3000);
  304. }
  305. int MidiInput::getDefaultDeviceIndex()
  306. {
  307. return 0;
  308. }
  309. const StringArray MidiInput::getDevices()
  310. {
  311. StringArray devices;
  312. iterateDevices (true, devices, -1);
  313. return devices;
  314. }
  315. MidiInput* MidiInput::openDevice (int deviceIndex, MidiInputCallback* callback)
  316. {
  317. MidiInput* newDevice = 0;
  318. StringArray devices;
  319. snd_seq_t* const handle = iterateDevices (true, devices, deviceIndex);
  320. if (handle != 0)
  321. {
  322. newDevice = new MidiInput (devices [deviceIndex]);
  323. newDevice->internal = new MidiInputThread (newDevice, handle, callback);
  324. }
  325. return newDevice;
  326. }
  327. MidiInput* MidiInput::createNewDevice (const String& deviceName, MidiInputCallback* callback)
  328. {
  329. MidiInput* newDevice = 0;
  330. snd_seq_t* const handle = createDevice (true, deviceName);
  331. if (handle != 0)
  332. {
  333. newDevice = new MidiInput (deviceName);
  334. newDevice->internal = new MidiInputThread (newDevice, handle, callback);
  335. }
  336. return newDevice;
  337. }
  338. //==============================================================================
  339. #else
  340. // (These are just stub functions if ALSA is unavailable...)
  341. const StringArray MidiOutput::getDevices() { return StringArray(); }
  342. int MidiOutput::getDefaultDeviceIndex() { return 0; }
  343. MidiOutput* MidiOutput::openDevice (int) { return 0; }
  344. MidiOutput* MidiOutput::createNewDevice (const String&) { return 0; }
  345. MidiOutput::~MidiOutput() {}
  346. void MidiOutput::reset() {}
  347. bool MidiOutput::getVolume (float&, float&) { return false; }
  348. void MidiOutput::setVolume (float, float) {}
  349. void MidiOutput::sendMessageNow (const MidiMessage&) {}
  350. MidiInput::MidiInput (const String& name_) : name (name_), internal (0) {}
  351. MidiInput::~MidiInput() {}
  352. void MidiInput::start() {}
  353. void MidiInput::stop() {}
  354. int MidiInput::getDefaultDeviceIndex() { return 0; }
  355. const StringArray MidiInput::getDevices() { return StringArray(); }
  356. MidiInput* MidiInput::openDevice (int, MidiInputCallback*) { return 0; }
  357. MidiInput* MidiInput::createNewDevice (const String&, MidiInputCallback*) { return 0; }
  358. #endif
  359. #endif