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.

963 lines
29KB

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