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.

462 lines
15KB

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