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.

1045 lines
32KB

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