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.

1008 lines
31KB

  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. #include "../../../juce_Config.h"
  24. #if JUCE_BUILD_GUI_CLASSES
  25. #if JUCE_ALSA
  26. #include "linuxincludes.h"
  27. //==============================================================================
  28. /* Got an include error here? If so, you've either not got ALSA installed, or you've
  29. not got your paths set up correctly to find its header files.
  30. The package you need to install to get ASLA support is "libasound2-dev".
  31. If you don't have the ALSA library and don't want to build Juce with audio support,
  32. just disable the JUCE_ALSA flag in juce_Config.h
  33. */
  34. #include <alsa/asoundlib.h>
  35. //==============================================================================
  36. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  37. BEGIN_JUCE_NAMESPACE
  38. #include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
  39. #include "../../../src/juce_core/threads/juce_Thread.h"
  40. #include "../../../src/juce_core/threads/juce_ScopedLock.h"
  41. #include "../../../src/juce_core/basics/juce_Time.h"
  42. #include "../../../src/juce_core/io/files/juce_File.h"
  43. #include "../../../src/juce_core/io/files/juce_FileInputStream.h"
  44. #include "../../../src/juce_core/basics/juce_Singleton.h"
  45. #include "../../../src/juce_appframework/audio/dsp/juce_AudioDataConverters.h"
  46. static const int maxNumChans = 64;
  47. //==============================================================================
  48. static void getDeviceSampleRates (snd_pcm_t* handle, Array <int>& rates)
  49. {
  50. const int ratesToTry[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 };
  51. snd_pcm_hw_params_t* hwParams;
  52. snd_pcm_hw_params_alloca (&hwParams);
  53. for (int i = 0; ratesToTry[i] != 0; ++i)
  54. {
  55. if (snd_pcm_hw_params_any (handle, hwParams) >= 0
  56. && snd_pcm_hw_params_test_rate (handle, hwParams, ratesToTry[i], 0) == 0)
  57. {
  58. rates.add (ratesToTry[i]);
  59. }
  60. }
  61. }
  62. static void getDeviceNumChannels (snd_pcm_t* handle, unsigned int* minChans, unsigned int* maxChans)
  63. {
  64. snd_pcm_hw_params_t *params;
  65. snd_pcm_hw_params_alloca (&params);
  66. if (snd_pcm_hw_params_any (handle, params) >= 0)
  67. {
  68. snd_pcm_hw_params_get_channels_min (params, minChans);
  69. snd_pcm_hw_params_get_channels_max (params, maxChans);
  70. }
  71. }
  72. static void getDeviceProperties (const String& id,
  73. unsigned int& minChansOut,
  74. unsigned int& maxChansOut,
  75. unsigned int& minChansIn,
  76. unsigned int& maxChansIn,
  77. Array <int>& rates)
  78. {
  79. snd_ctl_t* handle;
  80. if (snd_ctl_open (&handle, id.upToLastOccurrenceOf (T(","), false, false), SND_CTL_NONBLOCK) >= 0)
  81. {
  82. snd_pcm_info_t* info;
  83. snd_pcm_info_alloca (&info);
  84. snd_pcm_info_set_stream (info, SND_PCM_STREAM_PLAYBACK);
  85. snd_pcm_info_set_device (info, id.fromLastOccurrenceOf (T(","), false, false).getIntValue());
  86. snd_pcm_info_set_subdevice (info, 0);
  87. if (snd_ctl_pcm_info (handle, info) >= 0)
  88. {
  89. snd_pcm_t* pcmHandle;
  90. if (snd_pcm_open (&pcmHandle, id, SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
  91. {
  92. getDeviceNumChannels (pcmHandle, &minChansOut, &maxChansOut);
  93. getDeviceSampleRates (pcmHandle, rates);
  94. snd_pcm_close (pcmHandle);
  95. }
  96. }
  97. snd_pcm_info_set_stream (info, SND_PCM_STREAM_CAPTURE);
  98. if (snd_ctl_pcm_info (handle, info) >= 0)
  99. {
  100. snd_pcm_t* pcmHandle;
  101. if (snd_pcm_open (&pcmHandle, id, SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
  102. {
  103. getDeviceNumChannels (pcmHandle, &minChansIn, &maxChansIn);
  104. if (rates.size() == 0)
  105. getDeviceSampleRates (pcmHandle, rates);
  106. snd_pcm_close (pcmHandle);
  107. }
  108. }
  109. snd_ctl_close (handle);
  110. }
  111. }
  112. //==============================================================================
  113. class ALSADevice
  114. {
  115. public:
  116. ALSADevice (const String& deviceName,
  117. const bool forInput)
  118. : handle (0),
  119. bitDepth (16),
  120. numChannelsRunning (0),
  121. isInput (forInput),
  122. sampleFormat (AudioDataConverters::int16LE)
  123. {
  124. failed (snd_pcm_open (&handle, deviceName,
  125. forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
  126. SND_PCM_ASYNC));
  127. }
  128. ~ALSADevice()
  129. {
  130. if (handle != 0)
  131. snd_pcm_close (handle);
  132. }
  133. bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize)
  134. {
  135. if (handle == 0)
  136. return false;
  137. snd_pcm_hw_params_t* hwParams;
  138. snd_pcm_hw_params_alloca (&hwParams);
  139. if (failed (snd_pcm_hw_params_any (handle, hwParams)))
  140. return false;
  141. if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_NONINTERLEAVED) >= 0)
  142. isInterleaved = false;
  143. else if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0)
  144. isInterleaved = true;
  145. else
  146. {
  147. jassertfalse
  148. return false;
  149. }
  150. const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE, 32, AudioDataConverters::float32LE,
  151. SND_PCM_FORMAT_FLOAT_BE, 32, AudioDataConverters::float32BE,
  152. SND_PCM_FORMAT_S32_LE, 32, AudioDataConverters::int32LE,
  153. SND_PCM_FORMAT_S32_BE, 32, AudioDataConverters::int32BE,
  154. SND_PCM_FORMAT_S24_LE, 24, AudioDataConverters::int24LE,
  155. SND_PCM_FORMAT_S24_BE, 24, AudioDataConverters::int24BE,
  156. SND_PCM_FORMAT_S16_LE, 16, AudioDataConverters::int16LE,
  157. SND_PCM_FORMAT_S16_BE, 16, AudioDataConverters::int16BE };
  158. bitDepth = 0;
  159. for (int i = 0; i < numElementsInArray (formatsToTry); i += 3)
  160. {
  161. if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0)
  162. {
  163. bitDepth = formatsToTry [i + 1];
  164. sampleFormat = (AudioDataConverters::DataFormat) formatsToTry [i + 2];
  165. break;
  166. }
  167. }
  168. if (bitDepth == 0)
  169. {
  170. error = "device doesn't support a compatible PCM format";
  171. DBG (T("ALSA error: ") + error + T("\n"));
  172. return false;
  173. }
  174. int dir = 0;
  175. unsigned int periods = 4;
  176. snd_pcm_uframes_t samplesPerPeriod = bufferSize;
  177. if (failed (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, 0))
  178. || failed (snd_pcm_hw_params_set_channels (handle, hwParams, numChannels))
  179. || failed (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir))
  180. || failed (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir))
  181. || failed (snd_pcm_hw_params (handle, hwParams)))
  182. {
  183. return false;
  184. }
  185. snd_pcm_sw_params_t* swParams;
  186. snd_pcm_sw_params_alloca (&swParams);
  187. if (failed (snd_pcm_sw_params_current (handle, swParams))
  188. || failed (snd_pcm_sw_params_set_silence_threshold (handle, swParams, 0))
  189. || failed (snd_pcm_sw_params_set_silence_size (handle, swParams, INT_MAX))
  190. || failed (snd_pcm_sw_params_set_start_threshold (handle, swParams, samplesPerPeriod))
  191. || failed (snd_pcm_sw_params_set_stop_threshold (handle, swParams, INT_MAX))
  192. || failed (snd_pcm_sw_params (handle, swParams)))
  193. {
  194. return false;
  195. }
  196. /*
  197. #ifdef JUCE_DEBUG
  198. // enable this to dump the config of the devices that get opened
  199. snd_output_t* out;
  200. snd_output_stdio_attach (&out, stderr, 0);
  201. snd_pcm_hw_params_dump (hwParams, out);
  202. snd_pcm_sw_params_dump (swParams, out);
  203. #endif
  204. */
  205. numChannelsRunning = numChannels;
  206. return true;
  207. }
  208. //==============================================================================
  209. bool write (float** const data, const int numSamples)
  210. {
  211. if (isInterleaved)
  212. {
  213. scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
  214. float* interleaved = (float*) scratch;
  215. AudioDataConverters::interleaveSamples ((const float**) data, interleaved, numSamples, numChannelsRunning);
  216. AudioDataConverters::convertFloatToFormat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
  217. snd_pcm_sframes_t num = snd_pcm_writei (handle, (void*) interleaved, numSamples);
  218. if (failed (num) && num != -EPIPE && num != -ESTRPIPE)
  219. return false;
  220. }
  221. else
  222. {
  223. for (int i = 0; i < numChannelsRunning; ++i)
  224. if (data[i] != 0)
  225. AudioDataConverters::convertFloatToFormat (sampleFormat, data[i], data[i], numSamples);
  226. snd_pcm_sframes_t num = snd_pcm_writen (handle, (void**) data, numSamples);
  227. if (failed (num))
  228. {
  229. if (num == -EPIPE)
  230. {
  231. if (failed (snd_pcm_prepare (handle)))
  232. return false;
  233. }
  234. else if (num != -ESTRPIPE)
  235. return false;
  236. }
  237. }
  238. return true;
  239. }
  240. bool read (float** const data, const int numSamples)
  241. {
  242. if (isInterleaved)
  243. {
  244. scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
  245. float* interleaved = (float*) scratch;
  246. snd_pcm_sframes_t num = snd_pcm_readi (handle, (void*) interleaved, numSamples);
  247. if (failed (num))
  248. {
  249. if (num == -EPIPE)
  250. {
  251. if (failed (snd_pcm_prepare (handle)))
  252. return false;
  253. }
  254. else if (num != -ESTRPIPE)
  255. return false;
  256. }
  257. AudioDataConverters::convertFormatToFloat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
  258. AudioDataConverters::deinterleaveSamples (interleaved, data, numSamples, numChannelsRunning);
  259. }
  260. else
  261. {
  262. snd_pcm_sframes_t num = snd_pcm_readn (handle, (void**) data, numSamples);
  263. if (failed (num) && num != -EPIPE && num != -ESTRPIPE)
  264. return false;
  265. for (int i = 0; i < numChannelsRunning; ++i)
  266. if (data[i] != 0)
  267. AudioDataConverters::convertFormatToFloat (sampleFormat, data[i], data[i], numSamples);
  268. }
  269. return true;
  270. }
  271. //==============================================================================
  272. juce_UseDebuggingNewOperator
  273. snd_pcm_t* handle;
  274. String error;
  275. int bitDepth, numChannelsRunning;
  276. //==============================================================================
  277. private:
  278. const bool isInput;
  279. bool isInterleaved;
  280. MemoryBlock scratch;
  281. AudioDataConverters::DataFormat sampleFormat;
  282. //==============================================================================
  283. bool failed (const int errorNum)
  284. {
  285. if (errorNum >= 0)
  286. return false;
  287. error = snd_strerror (errorNum);
  288. DBG (T("ALSA error: ") + error + T("\n"));
  289. return true;
  290. }
  291. };
  292. //==============================================================================
  293. class ALSAThread : public Thread
  294. {
  295. public:
  296. ALSAThread (const String& deviceName_)
  297. : Thread ("Juce ALSA"),
  298. sampleRate (0),
  299. bufferSize (0),
  300. callback (0),
  301. deviceName (deviceName_),
  302. outputDevice (0),
  303. inputDevice (0),
  304. numCallbacks (0),
  305. totalNumInputChannels (0),
  306. totalNumOutputChannels (0)
  307. {
  308. zeromem (outputChannelData, sizeof (outputChannelData));
  309. zeromem (outputChannelDataForCallback, sizeof (outputChannelDataForCallback));
  310. zeromem (inputChannelData, sizeof (inputChannelData));
  311. zeromem (inputChannelDataForCallback, sizeof (inputChannelDataForCallback));
  312. initialiseRatesAndChannels();
  313. }
  314. ~ALSAThread()
  315. {
  316. close();
  317. }
  318. void open (const BitArray& inputChannels,
  319. const BitArray& outputChannels,
  320. const double sampleRate_,
  321. const int bufferSize_)
  322. {
  323. close();
  324. error = String::empty;
  325. sampleRate = sampleRate_;
  326. bufferSize = bufferSize_;
  327. currentInputChans.clear();
  328. currentOutputChans.clear();
  329. numChannelsRunning = jmax (inputChannels.getHighestBit(),
  330. outputChannels.getHighestBit()) + 1;
  331. numChannelsRunning = jmin (maxNumChans, jlimit ((int) minChansIn,
  332. (int) maxChansIn,
  333. numChannelsRunning));
  334. if (inputChannels.getHighestBit() >= 0)
  335. {
  336. for (int i = 0; i < numChannelsRunning; ++i)
  337. {
  338. inputChannelData [i] = (float*) juce_calloc (sizeof (float) * bufferSize);
  339. if (inputChannels[i])
  340. {
  341. inputChannelDataForCallback [totalNumInputChannels++] = inputChannelData [i];
  342. currentInputChans.setBit (i);
  343. }
  344. }
  345. }
  346. if (outputChannels.getHighestBit() >= 0)
  347. {
  348. for (int i = 0; i < numChannelsRunning; ++i)
  349. {
  350. outputChannelData [i] = (float*) juce_calloc (sizeof (float) * bufferSize);
  351. if (outputChannels[i])
  352. {
  353. outputChannelDataForCallback [totalNumOutputChannels++] = outputChannelData [i];
  354. currentOutputChans.setBit (i);
  355. }
  356. }
  357. }
  358. if (totalNumOutputChannels > 0)
  359. {
  360. outputDevice = new ALSADevice (deviceName, false);
  361. if (outputDevice->error.isNotEmpty())
  362. {
  363. error = outputDevice->error;
  364. deleteAndZero (outputDevice);
  365. return;
  366. }
  367. if (! outputDevice->setParameters ((unsigned int) sampleRate, numChannelsRunning, bufferSize))
  368. {
  369. error = outputDevice->error;
  370. deleteAndZero (outputDevice);
  371. return;
  372. }
  373. }
  374. if (totalNumInputChannels > 0)
  375. {
  376. inputDevice = new ALSADevice (deviceName, true);
  377. if (inputDevice->error.isNotEmpty())
  378. {
  379. error = inputDevice->error;
  380. deleteAndZero (inputDevice);
  381. return;
  382. }
  383. if (! inputDevice->setParameters ((unsigned int) sampleRate, numChannelsRunning, bufferSize))
  384. {
  385. error = inputDevice->error;
  386. deleteAndZero (inputDevice);
  387. return;
  388. }
  389. }
  390. if (outputDevice == 0 && inputDevice == 0)
  391. {
  392. error = "no channels";
  393. return;
  394. }
  395. if (outputDevice != 0 && inputDevice != 0)
  396. {
  397. snd_pcm_link (outputDevice->handle, inputDevice->handle);
  398. }
  399. if (inputDevice != 0 && failed (snd_pcm_prepare (inputDevice->handle)))
  400. return;
  401. if (outputDevice != 0 && failed (snd_pcm_prepare (outputDevice->handle)))
  402. return;
  403. startThread (9);
  404. int count = 1000;
  405. while (numCallbacks == 0)
  406. {
  407. sleep (5);
  408. if (--count < 0 || ! isThreadRunning())
  409. {
  410. error = "device didn't start";
  411. break;
  412. }
  413. }
  414. }
  415. void close()
  416. {
  417. stopThread (6000);
  418. deleteAndZero (inputDevice);
  419. deleteAndZero (outputDevice);
  420. for (int i = 0; i < maxNumChans; ++i)
  421. {
  422. juce_free (inputChannelData [i]);
  423. juce_free (outputChannelData [i]);
  424. }
  425. zeromem (outputChannelData, sizeof (outputChannelData));
  426. zeromem (outputChannelDataForCallback, sizeof (outputChannelDataForCallback));
  427. zeromem (inputChannelData, sizeof (inputChannelData));
  428. zeromem (inputChannelDataForCallback, sizeof (inputChannelDataForCallback));
  429. totalNumOutputChannels = 0;
  430. totalNumInputChannels = 0;
  431. numChannelsRunning = 0;
  432. numCallbacks = 0;
  433. }
  434. void setCallback (AudioIODeviceCallback* const newCallback) throw()
  435. {
  436. const ScopedLock sl (callbackLock);
  437. callback = newCallback;
  438. }
  439. void run()
  440. {
  441. while (! threadShouldExit())
  442. {
  443. if (inputDevice != 0)
  444. {
  445. jassert (numChannelsRunning >= inputDevice->numChannelsRunning);
  446. if (! inputDevice->read (inputChannelData, bufferSize))
  447. {
  448. DBG ("ALSA: read failure");
  449. break;
  450. }
  451. }
  452. if (threadShouldExit())
  453. break;
  454. {
  455. const ScopedLock sl (callbackLock);
  456. ++numCallbacks;
  457. if (callback != 0)
  458. {
  459. callback->audioDeviceIOCallback ((const float**) inputChannelDataForCallback,
  460. totalNumInputChannels,
  461. outputChannelDataForCallback,
  462. totalNumOutputChannels,
  463. bufferSize);
  464. }
  465. else
  466. {
  467. for (int i = 0; i < totalNumOutputChannels; ++i)
  468. zeromem (outputChannelDataForCallback[i], sizeof (float) * bufferSize);
  469. }
  470. }
  471. if (outputDevice != 0)
  472. {
  473. failed (snd_pcm_wait (outputDevice->handle, 2000));
  474. if (threadShouldExit())
  475. break;
  476. failed (snd_pcm_avail_update (outputDevice->handle));
  477. jassert (numChannelsRunning >= outputDevice->numChannelsRunning);
  478. if (! outputDevice->write (outputChannelData, bufferSize))
  479. {
  480. DBG ("ALSA: write failure");
  481. break;
  482. }
  483. }
  484. }
  485. }
  486. int getBitDepth() const throw()
  487. {
  488. if (outputDevice != 0)
  489. return outputDevice->bitDepth;
  490. if (inputDevice != 0)
  491. return inputDevice->bitDepth;
  492. return 16;
  493. }
  494. //==============================================================================
  495. juce_UseDebuggingNewOperator
  496. String error;
  497. double sampleRate;
  498. int bufferSize;
  499. BitArray currentInputChans, currentOutputChans;
  500. Array <int> sampleRates;
  501. StringArray channelNamesOut, channelNamesIn;
  502. AudioIODeviceCallback* callback;
  503. private:
  504. //==============================================================================
  505. const String deviceName;
  506. ALSADevice* outputDevice;
  507. ALSADevice* inputDevice;
  508. int numCallbacks;
  509. CriticalSection callbackLock;
  510. float* outputChannelData [maxNumChans];
  511. float* outputChannelDataForCallback [maxNumChans];
  512. int totalNumInputChannels;
  513. float* inputChannelData [maxNumChans];
  514. float* inputChannelDataForCallback [maxNumChans];
  515. int totalNumOutputChannels;
  516. int numChannelsRunning;
  517. unsigned int minChansOut, maxChansOut;
  518. unsigned int minChansIn, maxChansIn;
  519. bool failed (const int errorNum) throw()
  520. {
  521. if (errorNum >= 0)
  522. return false;
  523. error = snd_strerror (errorNum);
  524. DBG (T("ALSA error: ") + error + T("\n"));
  525. return true;
  526. }
  527. void initialiseRatesAndChannels() throw()
  528. {
  529. sampleRates.clear();
  530. channelNamesOut.clear();
  531. channelNamesIn.clear();
  532. minChansOut = 0;
  533. maxChansOut = 0;
  534. minChansIn = 0;
  535. maxChansIn = 0;
  536. getDeviceProperties (deviceName, minChansOut, maxChansOut, minChansIn, maxChansIn, sampleRates);
  537. unsigned int i;
  538. for (i = 0; i < maxChansOut; ++i)
  539. channelNamesOut.add (T("channel ") + String ((int) i + 1));
  540. for (i = 0; i < maxChansIn; ++i)
  541. channelNamesIn.add (T("channel ") + String ((int) i + 1));
  542. }
  543. };
  544. //==============================================================================
  545. class ALSAAudioIODevice : public AudioIODevice
  546. {
  547. public:
  548. ALSAAudioIODevice (const String& deviceName,
  549. const String& deviceId)
  550. : AudioIODevice (deviceName, T("ALSA")),
  551. isOpen_ (false),
  552. isStarted (false),
  553. internal (0)
  554. {
  555. internal = new ALSAThread (deviceId);
  556. }
  557. ~ALSAAudioIODevice()
  558. {
  559. delete internal;
  560. }
  561. const StringArray getOutputChannelNames()
  562. {
  563. return internal->channelNamesOut;
  564. }
  565. const StringArray getInputChannelNames()
  566. {
  567. return internal->channelNamesIn;
  568. }
  569. int getNumSampleRates()
  570. {
  571. return internal->sampleRates.size();
  572. }
  573. double getSampleRate (int index)
  574. {
  575. return internal->sampleRates [index];
  576. }
  577. int getNumBufferSizesAvailable()
  578. {
  579. return 50;
  580. }
  581. int getBufferSizeSamples (int index)
  582. {
  583. int n = 16;
  584. for (int i = 0; i < index; ++i)
  585. n += n < 64 ? 16
  586. : (n < 512 ? 32
  587. : (n < 1024 ? 64
  588. : (n < 2048 ? 128 : 256)));
  589. return n;
  590. }
  591. int getDefaultBufferSize()
  592. {
  593. return 512;
  594. }
  595. const String open (const BitArray& inputChannels,
  596. const BitArray& outputChannels,
  597. double sampleRate,
  598. int bufferSizeSamples)
  599. {
  600. close();
  601. if (bufferSizeSamples <= 0)
  602. bufferSizeSamples = getDefaultBufferSize();
  603. if (sampleRate <= 0)
  604. {
  605. for (int i = 0; i < getNumSampleRates(); ++i)
  606. {
  607. if (getSampleRate (i) >= 44100)
  608. {
  609. sampleRate = getSampleRate (i);
  610. break;
  611. }
  612. }
  613. }
  614. internal->open (inputChannels, outputChannels,
  615. sampleRate, bufferSizeSamples);
  616. isOpen_ = internal->error.isEmpty();
  617. return internal->error;
  618. }
  619. void close()
  620. {
  621. stop();
  622. internal->close();
  623. isOpen_ = false;
  624. }
  625. bool isOpen()
  626. {
  627. return isOpen_;
  628. }
  629. int getCurrentBufferSizeSamples()
  630. {
  631. return internal->bufferSize;
  632. }
  633. double getCurrentSampleRate()
  634. {
  635. return internal->sampleRate;
  636. }
  637. int getCurrentBitDepth()
  638. {
  639. return internal->getBitDepth();
  640. }
  641. const BitArray getActiveOutputChannels() const
  642. {
  643. return internal->currentOutputChans;
  644. }
  645. const BitArray getActiveInputChannels() const
  646. {
  647. return internal->currentInputChans;
  648. }
  649. int getOutputLatencyInSamples()
  650. {
  651. return 0;
  652. }
  653. int getInputLatencyInSamples()
  654. {
  655. return 0;
  656. }
  657. void start (AudioIODeviceCallback* callback)
  658. {
  659. if (! isOpen_)
  660. callback = 0;
  661. internal->setCallback (callback);
  662. if (callback != 0)
  663. callback->audioDeviceAboutToStart (internal->sampleRate,
  664. internal->bufferSize);
  665. isStarted = (callback != 0);
  666. }
  667. void stop()
  668. {
  669. AudioIODeviceCallback* const oldCallback = internal->callback;
  670. start (0);
  671. if (oldCallback != 0)
  672. oldCallback->audioDeviceStopped();
  673. }
  674. bool isPlaying()
  675. {
  676. return isStarted && internal->error.isEmpty();
  677. }
  678. const String getLastError()
  679. {
  680. return internal->error;
  681. }
  682. private:
  683. bool isOpen_, isStarted;
  684. ALSAThread* internal;
  685. };
  686. //==============================================================================
  687. class ALSAAudioIODeviceType : public AudioIODeviceType
  688. {
  689. public:
  690. //==============================================================================
  691. ALSAAudioIODeviceType()
  692. : AudioIODeviceType (T("ALSA")),
  693. hasScanned (false)
  694. {
  695. }
  696. ~ALSAAudioIODeviceType()
  697. {
  698. }
  699. //==============================================================================
  700. void scanForDevices()
  701. {
  702. hasScanned = true;
  703. names.clear();
  704. ids.clear();
  705. snd_ctl_t* handle;
  706. snd_ctl_card_info_t* info;
  707. snd_ctl_card_info_alloca (&info);
  708. int cardNum = -1;
  709. while (ids.size() <= 24)
  710. {
  711. snd_card_next (&cardNum);
  712. if (cardNum < 0)
  713. break;
  714. if (snd_ctl_open (&handle, T("hw:") + String (cardNum), SND_CTL_NONBLOCK) >= 0)
  715. {
  716. if (snd_ctl_card_info (handle, info) >= 0)
  717. {
  718. String cardId (snd_ctl_card_info_get_id (info));
  719. if (cardId.removeCharacters (T("0123456789")).isEmpty())
  720. cardId = String (cardNum);
  721. int device = -1;
  722. for (;;)
  723. {
  724. if (snd_ctl_pcm_next_device (handle, &device) < 0 || device < 0)
  725. break;
  726. String id, name;
  727. id << "hw:" << cardId << ',' << device;
  728. if (testDevice (id))
  729. {
  730. name << snd_ctl_card_info_get_name (info);
  731. if (name.isEmpty())
  732. name = id;
  733. if (device > 0)
  734. name << " (" << (device + 1) << ')';
  735. ids.add (id);
  736. names.add (name);
  737. }
  738. }
  739. }
  740. snd_ctl_close (handle);
  741. }
  742. }
  743. }
  744. const StringArray getDeviceNames (const bool /*preferInputNames*/) const
  745. {
  746. jassert (hasScanned); // need to call scanForDevices() before doing this
  747. StringArray namesCopy (names);
  748. namesCopy.removeDuplicates (true);
  749. return namesCopy;
  750. }
  751. const String getDefaultDeviceName (const bool /*preferInputNames*/,
  752. const int /*numInputChannelsNeeded*/,
  753. const int /*numOutputChannelsNeeded*/) const
  754. {
  755. jassert (hasScanned); // need to call scanForDevices() before doing this
  756. return names[0];
  757. }
  758. AudioIODevice* createDevice (const String& deviceName)
  759. {
  760. jassert (hasScanned); // need to call scanForDevices() before doing this
  761. const int index = names.indexOf (deviceName);
  762. if (index >= 0)
  763. return new ALSAAudioIODevice (deviceName, ids [index]);
  764. return 0;
  765. }
  766. //==============================================================================
  767. juce_UseDebuggingNewOperator
  768. private:
  769. StringArray names, ids;
  770. bool hasScanned;
  771. static bool testDevice (const String& id)
  772. {
  773. unsigned int minChansOut = 0, maxChansOut = 0;
  774. unsigned int minChansIn = 0, maxChansIn = 0;
  775. Array <int> rates;
  776. getDeviceProperties (id, minChansOut, maxChansOut, minChansIn, maxChansIn, rates);
  777. DBG (T("ALSA device: ") + id
  778. + T(" outs=") + String ((int) minChansOut) + T("-") + String ((int) maxChansOut)
  779. + T(" ins=") + String ((int) minChansIn) + T("-") + String ((int) maxChansIn)
  780. + T(" rates=") + String (rates.size()));
  781. return (maxChansOut > 0 || maxChansIn > 0) && rates.size() > 0;
  782. }
  783. ALSAAudioIODeviceType (const ALSAAudioIODeviceType&);
  784. const ALSAAudioIODeviceType& operator= (const ALSAAudioIODeviceType&);
  785. };
  786. //==============================================================================
  787. AudioIODeviceType* juce_createDefaultAudioIODeviceType()
  788. {
  789. return new ALSAAudioIODeviceType();
  790. }
  791. END_JUCE_NAMESPACE
  792. //==============================================================================
  793. #else // if ALSA is turned off..
  794. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  795. BEGIN_JUCE_NAMESPACE
  796. #include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
  797. AudioIODeviceType* juce_createDefaultAudioIODeviceType() { return 0; }
  798. END_JUCE_NAMESPACE
  799. #endif
  800. #endif