| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library - "Jules' Utility Class Extensions"
 -    Copyright 2004-11 by Raw Material Software Ltd.
 - 
 -   ------------------------------------------------------------------------------
 - 
 -    JUCE can be redistributed and/or modified under the terms of the GNU General
 -    Public License (Version 2), as published by the Free Software Foundation.
 -    A copy of the license is included in the JUCE distribution, or can be found
 -    online at www.gnu.org/licenses.
 - 
 -    JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
 -    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 -    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 - 
 -   ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.rawmaterialsoftware.com/juce for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace
 - {
 -     void getDeviceSampleRates (snd_pcm_t* handle, Array <int>& rates)
 -     {
 -         const int ratesToTry[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 };
 - 
 -         snd_pcm_hw_params_t* hwParams;
 -         snd_pcm_hw_params_alloca (&hwParams);
 - 
 -         for (int i = 0; ratesToTry[i] != 0; ++i)
 -         {
 -             if (snd_pcm_hw_params_any (handle, hwParams) >= 0
 -                  && snd_pcm_hw_params_test_rate (handle, hwParams, ratesToTry[i], 0) == 0)
 -             {
 -                 rates.addIfNotAlreadyThere (ratesToTry[i]);
 -             }
 -         }
 -     }
 - 
 -     void getDeviceNumChannels (snd_pcm_t* handle, unsigned int* minChans, unsigned int* maxChans)
 -     {
 -         snd_pcm_hw_params_t *params;
 -         snd_pcm_hw_params_alloca (¶ms);
 - 
 -         if (snd_pcm_hw_params_any (handle, params) >= 0)
 -         {
 -             snd_pcm_hw_params_get_channels_min (params, minChans);
 -             snd_pcm_hw_params_get_channels_max (params, maxChans);
 -         }
 -     }
 - 
 -     void getDeviceProperties (const String& deviceID,
 -                               unsigned int& minChansOut,
 -                               unsigned int& maxChansOut,
 -                               unsigned int& minChansIn,
 -                               unsigned int& maxChansIn,
 -                               Array <int>& rates)
 -     {
 -         if (deviceID.isEmpty())
 -             return;
 - 
 -         snd_ctl_t* handle;
 - 
 -         if (snd_ctl_open (&handle, deviceID.upToLastOccurrenceOf (",", false, false).toUTF8(), SND_CTL_NONBLOCK) >= 0)
 -         {
 -             snd_pcm_info_t* info;
 -             snd_pcm_info_alloca (&info);
 - 
 -             snd_pcm_info_set_stream (info, SND_PCM_STREAM_PLAYBACK);
 -             snd_pcm_info_set_device (info, deviceID.fromLastOccurrenceOf (",", false, false).getIntValue());
 -             snd_pcm_info_set_subdevice (info, 0);
 - 
 -             if (snd_ctl_pcm_info (handle, info) >= 0)
 -             {
 -                 snd_pcm_t* pcmHandle;
 -                 if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC | SND_PCM_NONBLOCK) >= 0)
 -                 {
 -                     getDeviceNumChannels (pcmHandle, &minChansOut, &maxChansOut);
 -                     getDeviceSampleRates (pcmHandle, rates);
 - 
 -                     snd_pcm_close (pcmHandle);
 -                 }
 -             }
 - 
 -             snd_pcm_info_set_stream (info, SND_PCM_STREAM_CAPTURE);
 - 
 -             if (snd_ctl_pcm_info (handle, info) >= 0)
 -             {
 -                 snd_pcm_t* pcmHandle;
 -                 if (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC | SND_PCM_NONBLOCK) >= 0)
 -                 {
 -                     getDeviceNumChannels (pcmHandle, &minChansIn, &maxChansIn);
 - 
 -                     if (rates.size() == 0)
 -                         getDeviceSampleRates (pcmHandle, rates);
 - 
 -                     snd_pcm_close (pcmHandle);
 -                 }
 -             }
 - 
 -             snd_ctl_close (handle);
 -         }
 -     }
 - }
 - 
 - //==============================================================================
 - class ALSADevice
 - {
 - public:
 -     ALSADevice (const String& deviceID, bool forInput)
 -         : handle (0),
 -           bitDepth (16),
 -           numChannelsRunning (0),
 -           latency (0),
 -           isInput (forInput),
 -           isInterleaved (true)
 -     {
 -         failed (snd_pcm_open (&handle, deviceID.toUTF8(),
 -                               forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
 -                               SND_PCM_ASYNC));
 -     }
 - 
 -     ~ALSADevice()
 -     {
 -         if (handle != 0)
 -             snd_pcm_close (handle);
 -     }
 - 
 -     bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize)
 -     {
 -         if (handle == 0)
 -             return false;
 - 
 -         snd_pcm_hw_params_t* hwParams;
 -         snd_pcm_hw_params_alloca (&hwParams);
 - 
 -         if (failed (snd_pcm_hw_params_any (handle, hwParams)))
 -             return false;
 - 
 -         if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_NONINTERLEAVED) >= 0)
 -             isInterleaved = false;
 -         else if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0)
 -             isInterleaved = true;
 -         else
 -         {
 -             jassertfalse;
 -             return false;
 -         }
 - 
 -         enum { isFloatBit = 1 << 16, isLittleEndianBit = 1 << 17 };
 - 
 -         const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE,   32 | isFloatBit | isLittleEndianBit,
 -                                      SND_PCM_FORMAT_FLOAT_BE,   32 | isFloatBit,
 -                                      SND_PCM_FORMAT_S32_LE,     32 | isLittleEndianBit,
 -                                      SND_PCM_FORMAT_S32_BE,     32,
 -                                      SND_PCM_FORMAT_S24_3LE,    24 | isLittleEndianBit,
 -                                      SND_PCM_FORMAT_S24_3BE,    24,
 -                                      SND_PCM_FORMAT_S16_LE,     16 | isLittleEndianBit,
 -                                      SND_PCM_FORMAT_S16_BE,     16 };
 -         bitDepth = 0;
 - 
 -         for (int i = 0; i < numElementsInArray (formatsToTry); i += 2)
 -         {
 -             if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0)
 -             {
 -                 bitDepth = formatsToTry [i + 1] & 255;
 -                 const bool isFloat = (formatsToTry [i + 1] & isFloatBit) != 0;
 -                 const bool isLittleEndian = (formatsToTry [i + 1] & isLittleEndianBit) != 0;
 -                 converter = createConverter (isInput, bitDepth, isFloat, isLittleEndian, numChannels);
 -                 break;
 -             }
 -         }
 - 
 -         if (bitDepth == 0)
 -         {
 -             error = "device doesn't support a compatible PCM format";
 -             DBG ("ALSA error: " + error + "\n");
 -             return false;
 -         }
 - 
 -         int dir = 0;
 -         unsigned int periods = 4;
 -         snd_pcm_uframes_t samplesPerPeriod = bufferSize;
 - 
 -         if (failed (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, 0))
 -             || failed (snd_pcm_hw_params_set_channels (handle, hwParams, numChannels))
 -             || failed (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir))
 -             || failed (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir))
 -             || failed (snd_pcm_hw_params (handle, hwParams)))
 -         {
 -             return false;
 -         }
 - 
 -         snd_pcm_uframes_t frames = 0;
 - 
 -         if (failed (snd_pcm_hw_params_get_period_size (hwParams, &frames, &dir))
 -              || failed (snd_pcm_hw_params_get_periods (hwParams, &periods, &dir)))
 -             latency = 0;
 -         else
 -             latency = frames * (periods - 1); // (this is the method JACK uses to guess the latency..)
 - 
 -         snd_pcm_sw_params_t* swParams;
 -         snd_pcm_sw_params_alloca (&swParams);
 -         snd_pcm_uframes_t boundary;
 - 
 -         if (failed (snd_pcm_sw_params_current (handle, swParams))
 -             || failed (snd_pcm_sw_params_get_boundary (swParams, &boundary))
 -             || failed (snd_pcm_sw_params_set_silence_threshold (handle, swParams, 0))
 -             || failed (snd_pcm_sw_params_set_silence_size (handle, swParams, boundary))
 -             || failed (snd_pcm_sw_params_set_start_threshold (handle, swParams, samplesPerPeriod))
 -             || failed (snd_pcm_sw_params_set_stop_threshold (handle, swParams, boundary))
 -             || failed (snd_pcm_sw_params (handle, swParams)))
 -         {
 -             return false;
 -         }
 - 
 -       #if 0
 -         // enable this to dump the config of the devices that get opened
 -         snd_output_t* out;
 -         snd_output_stdio_attach (&out, stderr, 0);
 -         snd_pcm_hw_params_dump (hwParams, out);
 -         snd_pcm_sw_params_dump (swParams, out);
 -       #endif
 - 
 -         numChannelsRunning = numChannels;
 - 
 -         return true;
 -     }
 - 
 -     //==============================================================================
 -     bool writeToOutputDevice (AudioSampleBuffer& outputChannelBuffer, const int numSamples)
 -     {
 -         jassert (numChannelsRunning <= outputChannelBuffer.getNumChannels());
 -         float** const data = outputChannelBuffer.getArrayOfChannels();
 -         snd_pcm_sframes_t numDone = 0;
 - 
 -         if (isInterleaved)
 -         {
 -             scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
 - 
 -             for (int i = 0; i < numChannelsRunning; ++i)
 -                 converter->convertSamples (scratch.getData(), i, data[i], 0, numSamples);
 - 
 -             numDone = snd_pcm_writei (handle, scratch.getData(), numSamples);
 -         }
 -         else
 -         {
 -             for (int i = 0; i < numChannelsRunning; ++i)
 -                 converter->convertSamples (data[i], data[i], numSamples);
 - 
 -             numDone = snd_pcm_writen (handle, (void**) data, numSamples);
 -         }
 - 
 -         if (failed (numDone))
 -         {
 -             if (numDone == -EPIPE)
 -             {
 -                 if (failed (snd_pcm_prepare (handle)))
 -                     return false;
 -             }
 -             else if (numDone != -ESTRPIPE)
 -                 return false;
 -         }
 - 
 -         return true;
 -     }
 - 
 -     bool readFromInputDevice (AudioSampleBuffer& inputChannelBuffer, const int numSamples)
 -     {
 -         jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels());
 -         float** const data = inputChannelBuffer.getArrayOfChannels();
 - 
 -         if (isInterleaved)
 -         {
 -             scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
 -             scratch.fillWith (0); // (not clearing this data causes warnings in valgrind)
 - 
 -             snd_pcm_sframes_t num = snd_pcm_readi (handle, scratch.getData(), numSamples);
 - 
 -             if (failed (num))
 -             {
 -                 if (num == -EPIPE)
 -                 {
 -                     if (failed (snd_pcm_prepare (handle)))
 -                         return false;
 -                 }
 -                 else if (num != -ESTRPIPE)
 -                     return false;
 -             }
 - 
 -             for (int i = 0; i < numChannelsRunning; ++i)
 -                 converter->convertSamples (data[i], 0, scratch.getData(), i, numSamples);
 -         }
 -         else
 -         {
 -             snd_pcm_sframes_t num = snd_pcm_readn (handle, (void**) data, numSamples);
 - 
 -             if (failed (num) && num != -EPIPE && num != -ESTRPIPE)
 -                 return false;
 - 
 -             for (int i = 0; i < numChannelsRunning; ++i)
 -                 converter->convertSamples (data[i], data[i], numSamples);
 -         }
 - 
 -         return true;
 -     }
 - 
 -     //==============================================================================
 -     snd_pcm_t* handle;
 -     String error;
 -     int bitDepth, numChannelsRunning, latency;
 - 
 -     //==============================================================================
 - private:
 -     const bool isInput;
 -     bool isInterleaved;
 -     MemoryBlock scratch;
 -     ScopedPointer<AudioData::Converter> converter;
 - 
 -     //==============================================================================
 -     template <class SampleType>
 -     struct ConverterHelper
 -     {
 -         static AudioData::Converter* createConverter (const bool forInput, const bool isLittleEndian, const int numInterleavedChannels)
 -         {
 -             if (forInput)
 -             {
 -                 typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestType;
 - 
 -                 if (isLittleEndian)
 -                     return new AudioData::ConverterInstance <AudioData::Pointer <SampleType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const>, DestType> (numInterleavedChannels, 1);
 -                 else
 -                     return new AudioData::ConverterInstance <AudioData::Pointer <SampleType, AudioData::BigEndian, AudioData::Interleaved, AudioData::Const>, DestType> (numInterleavedChannels, 1);
 -             }
 -             else
 -             {
 -                 typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceType;
 - 
 -                 if (isLittleEndian)
 -                     return new AudioData::ConverterInstance <SourceType, AudioData::Pointer <SampleType, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> > (1, numInterleavedChannels);
 -                 else
 -                     return new AudioData::ConverterInstance <SourceType, AudioData::Pointer <SampleType, AudioData::BigEndian, AudioData::Interleaved, AudioData::NonConst> > (1, numInterleavedChannels);
 -             }
 -         }
 -     };
 - 
 -     static AudioData::Converter* createConverter (const bool forInput, const int bitDepth, const bool isFloat, const bool isLittleEndian, const int numInterleavedChannels)
 -     {
 -         switch (bitDepth)
 -         {
 -             case 16:    return ConverterHelper <AudioData::Int16>::createConverter (forInput, isLittleEndian,  numInterleavedChannels);
 -             case 24:    return ConverterHelper <AudioData::Int24>::createConverter (forInput, isLittleEndian,  numInterleavedChannels);
 -             case 32:    return isFloat ? ConverterHelper <AudioData::Float32>::createConverter (forInput, isLittleEndian,  numInterleavedChannels)
 -                                        : ConverterHelper <AudioData::Int32>::createConverter (forInput, isLittleEndian,  numInterleavedChannels);
 -             default:    jassertfalse; break; // unsupported format!
 -         }
 - 
 -         return nullptr;
 -     }
 - 
 -     //==============================================================================
 -     bool failed (const int errorNum)
 -     {
 -         if (errorNum >= 0)
 -             return false;
 - 
 -         error = snd_strerror (errorNum);
 -         DBG ("ALSA error: " + error + "\n");
 -         return true;
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ALSADevice);
 - };
 - 
 - //==============================================================================
 - class ALSAThread  : public Thread
 - {
 - public:
 -     ALSAThread (const String& inputId_,
 -                 const String& outputId_)
 -         : Thread ("Juce ALSA"),
 -           sampleRate (0),
 -           bufferSize (0),
 -           outputLatency (0),
 -           inputLatency (0),
 -           callback (0),
 -           inputId (inputId_),
 -           outputId (outputId_),
 -           numCallbacks (0),
 -           inputChannelBuffer (1, 1),
 -           outputChannelBuffer (1, 1)
 -     {
 -         initialiseRatesAndChannels();
 -     }
 - 
 -     ~ALSAThread()
 -     {
 -         close();
 -     }
 - 
 -     void open (BigInteger inputChannels,
 -                BigInteger outputChannels,
 -                const double sampleRate_,
 -                const int bufferSize_)
 -     {
 -         close();
 - 
 -         error = String::empty;
 -         sampleRate = sampleRate_;
 -         bufferSize = bufferSize_;
 - 
 -         inputChannelBuffer.setSize (jmax ((int) minChansIn, inputChannels.getHighestBit()) + 1, bufferSize);
 -         inputChannelBuffer.clear();
 -         inputChannelDataForCallback.clear();
 -         currentInputChans.clear();
 - 
 -         if (inputChannels.getHighestBit() >= 0)
 -         {
 -             for (int i = 0; i <= jmax (inputChannels.getHighestBit(), (int) minChansIn); ++i)
 -             {
 -                 if (inputChannels[i])
 -                 {
 -                     inputChannelDataForCallback.add (inputChannelBuffer.getSampleData (i));
 -                     currentInputChans.setBit (i);
 -                 }
 -             }
 -         }
 - 
 -         outputChannelBuffer.setSize (jmax ((int) minChansOut, outputChannels.getHighestBit()) + 1, bufferSize);
 -         outputChannelBuffer.clear();
 -         outputChannelDataForCallback.clear();
 -         currentOutputChans.clear();
 - 
 -         if (outputChannels.getHighestBit() >= 0)
 -         {
 -             for (int i = 0; i <= jmax (outputChannels.getHighestBit(), (int) minChansOut); ++i)
 -             {
 -                 if (outputChannels[i])
 -                 {
 -                     outputChannelDataForCallback.add (outputChannelBuffer.getSampleData (i));
 -                     currentOutputChans.setBit (i);
 -                 }
 -             }
 -         }
 - 
 -         if (outputChannelDataForCallback.size() > 0 && outputId.isNotEmpty())
 -         {
 -             outputDevice = new ALSADevice (outputId, false);
 - 
 -             if (outputDevice->error.isNotEmpty())
 -             {
 -                 error = outputDevice->error;
 -                 outputDevice = nullptr;
 -                 return;
 -             }
 - 
 -             currentOutputChans.setRange (0, minChansOut, true);
 - 
 -             if (! outputDevice->setParameters ((unsigned int) sampleRate,
 -                                                jlimit ((int) minChansOut, (int) maxChansOut, currentOutputChans.getHighestBit() + 1),
 -                                                bufferSize))
 -             {
 -                 error = outputDevice->error;
 -                 outputDevice = nullptr;
 -                 return;
 -             }
 - 
 -             outputLatency = outputDevice->latency;
 -         }
 - 
 -         if (inputChannelDataForCallback.size() > 0 && inputId.isNotEmpty())
 -         {
 -             inputDevice = new ALSADevice (inputId, true);
 - 
 -             if (inputDevice->error.isNotEmpty())
 -             {
 -                 error = inputDevice->error;
 -                 inputDevice = nullptr;
 -                 return;
 -             }
 - 
 -             currentInputChans.setRange (0, minChansIn, true);
 - 
 -             if (! inputDevice->setParameters ((unsigned int) sampleRate,
 -                                               jlimit ((int) minChansIn, (int) maxChansIn, currentInputChans.getHighestBit() + 1),
 -                                               bufferSize))
 -             {
 -                 error = inputDevice->error;
 -                 inputDevice = nullptr;
 -                 return;
 -             }
 - 
 -             inputLatency = inputDevice->latency;
 -         }
 - 
 -         if (outputDevice == nullptr && inputDevice == nullptr)
 -         {
 -             error = "no channels";
 -             return;
 -         }
 - 
 -         if (outputDevice != nullptr && inputDevice != nullptr)
 -         {
 -             snd_pcm_link (outputDevice->handle, inputDevice->handle);
 -         }
 - 
 -         if (inputDevice != nullptr && failed (snd_pcm_prepare (inputDevice->handle)))
 -             return;
 - 
 -         if (outputDevice != nullptr && failed (snd_pcm_prepare (outputDevice->handle)))
 -             return;
 - 
 -         startThread (9);
 - 
 -         int count = 1000;
 - 
 -         while (numCallbacks == 0)
 -         {
 -             sleep (5);
 - 
 -             if (--count < 0 || ! isThreadRunning())
 -             {
 -                 error = "device didn't start";
 -                 break;
 -             }
 -         }
 -     }
 - 
 -     void close()
 -     {
 -         stopThread (6000);
 - 
 -         inputDevice = nullptr;
 -         outputDevice = nullptr;
 - 
 -         inputChannelBuffer.setSize (1, 1);
 -         outputChannelBuffer.setSize (1, 1);
 - 
 -         numCallbacks = 0;
 -     }
 - 
 -     void setCallback (AudioIODeviceCallback* const newCallback) noexcept
 -     {
 -         const ScopedLock sl (callbackLock);
 -         callback = newCallback;
 -     }
 - 
 -     void run()
 -     {
 -         while (! threadShouldExit())
 -         {
 -             if (inputDevice != nullptr)
 -             {
 -                 if (! inputDevice->readFromInputDevice (inputChannelBuffer, bufferSize))
 -                 {
 -                     DBG ("ALSA: read failure");
 -                     break;
 -                 }
 -             }
 - 
 -             if (threadShouldExit())
 -                 break;
 - 
 -             {
 -                 const ScopedLock sl (callbackLock);
 -                 ++numCallbacks;
 - 
 -                 if (callback != nullptr)
 -                 {
 -                     callback->audioDeviceIOCallback ((const float**) inputChannelDataForCallback.getRawDataPointer(),
 -                                                      inputChannelDataForCallback.size(),
 -                                                      outputChannelDataForCallback.getRawDataPointer(),
 -                                                      outputChannelDataForCallback.size(),
 -                                                      bufferSize);
 -                 }
 -                 else
 -                 {
 -                     for (int i = 0; i < outputChannelDataForCallback.size(); ++i)
 -                         zeromem (outputChannelDataForCallback[i], sizeof (float) * bufferSize);
 -                 }
 -             }
 - 
 -             if (outputDevice != nullptr)
 -             {
 -                 failed (snd_pcm_wait (outputDevice->handle, 2000));
 - 
 -                 if (threadShouldExit())
 -                     break;
 - 
 -                 failed (snd_pcm_avail_update (outputDevice->handle));
 - 
 -                 if (! outputDevice->writeToOutputDevice (outputChannelBuffer, bufferSize))
 -                 {
 -                     DBG ("ALSA: write failure");
 -                     break;
 -                 }
 -             }
 -         }
 -     }
 - 
 -     int getBitDepth() const noexcept
 -     {
 -         if (outputDevice != nullptr)
 -             return outputDevice->bitDepth;
 - 
 -         if (inputDevice != nullptr)
 -             return inputDevice->bitDepth;
 - 
 -         return 16;
 -     }
 - 
 -     //==============================================================================
 -     String error;
 -     double sampleRate;
 -     int bufferSize, outputLatency, inputLatency;
 -     BigInteger currentInputChans, currentOutputChans;
 - 
 -     Array <int> sampleRates;
 -     StringArray channelNamesOut, channelNamesIn;
 -     AudioIODeviceCallback* callback;
 - 
 - private:
 -     //==============================================================================
 -     const String inputId, outputId;
 -     ScopedPointer<ALSADevice> outputDevice, inputDevice;
 -     int numCallbacks;
 - 
 -     CriticalSection callbackLock;
 - 
 -     AudioSampleBuffer inputChannelBuffer, outputChannelBuffer;
 -     Array<float*> inputChannelDataForCallback, outputChannelDataForCallback;
 - 
 -     unsigned int minChansOut, maxChansOut;
 -     unsigned int minChansIn, maxChansIn;
 - 
 -     bool failed (const int errorNum)
 -     {
 -         if (errorNum >= 0)
 -             return false;
 - 
 -         error = snd_strerror (errorNum);
 -         DBG ("ALSA error: " + error + "\n");
 -         return true;
 -     }
 - 
 -     void initialiseRatesAndChannels()
 -     {
 -         sampleRates.clear();
 -         channelNamesOut.clear();
 -         channelNamesIn.clear();
 -         minChansOut = 0;
 -         maxChansOut = 0;
 -         minChansIn = 0;
 -         maxChansIn = 0;
 -         unsigned int dummy = 0;
 - 
 -         getDeviceProperties (inputId, dummy, dummy, minChansIn, maxChansIn, sampleRates);
 -         getDeviceProperties (outputId, minChansOut, maxChansOut, dummy, dummy, sampleRates);
 - 
 -         unsigned int i;
 -         for (i = 0; i < maxChansOut; ++i)
 -             channelNamesOut.add ("channel " + String ((int) i + 1));
 - 
 -         for (i = 0; i < maxChansIn; ++i)
 -             channelNamesIn.add ("channel " + String ((int) i + 1));
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ALSAThread);
 - };
 - 
 - 
 - //==============================================================================
 - class ALSAAudioIODevice   : public AudioIODevice
 - {
 - public:
 -     ALSAAudioIODevice (const String& deviceName,
 -                        const String& inputId_,
 -                        const String& outputId_)
 -         : AudioIODevice (deviceName, "ALSA"),
 -           inputId (inputId_),
 -           outputId (outputId_),
 -           isOpen_ (false),
 -           isStarted (false),
 -           internal (inputId_, outputId_)
 -     {
 -     }
 - 
 -     ~ALSAAudioIODevice()
 -     {
 -         close();
 -     }
 - 
 -     StringArray getOutputChannelNames()             { return internal.channelNamesOut; }
 -     StringArray getInputChannelNames()              { return internal.channelNamesIn; }
 - 
 -     int getNumSampleRates()                         { return internal.sampleRates.size(); }
 -     double getSampleRate (int index)                { return internal.sampleRates [index]; }
 - 
 -     int getDefaultBufferSize()                      { return 512; }
 -     int getNumBufferSizesAvailable()                { return 50; }
 - 
 -     int getBufferSizeSamples (int index)
 -     {
 -         int n = 16;
 -         for (int i = 0; i < index; ++i)
 -             n += n < 64 ? 16
 -                         : (n < 512 ? 32
 -                                    : (n < 1024 ? 64
 -                                                : (n < 2048 ? 128 : 256)));
 - 
 -         return n;
 -     }
 - 
 -     String open (const BigInteger& inputChannels,
 -                  const BigInteger& outputChannels,
 -                  double sampleRate,
 -                  int bufferSizeSamples)
 -     {
 -         close();
 - 
 -         if (bufferSizeSamples <= 0)
 -             bufferSizeSamples = getDefaultBufferSize();
 - 
 -         if (sampleRate <= 0)
 -         {
 -             for (int i = 0; i < getNumSampleRates(); ++i)
 -             {
 -                 if (getSampleRate (i) >= 44100)
 -                 {
 -                     sampleRate = getSampleRate (i);
 -                     break;
 -                 }
 -             }
 -         }
 - 
 -         internal.open (inputChannels, outputChannels,
 -                        sampleRate, bufferSizeSamples);
 - 
 -         isOpen_ = internal.error.isEmpty();
 -         return internal.error;
 -     }
 - 
 -     void close()
 -     {
 -         stop();
 -         internal.close();
 -         isOpen_ = false;
 -     }
 - 
 -     bool isOpen()                           { return isOpen_; }
 -     bool isPlaying()                        { return isStarted && internal.error.isEmpty(); }
 -     String getLastError()                   { return internal.error; }
 - 
 -     int getCurrentBufferSizeSamples()       { return internal.bufferSize; }
 -     double getCurrentSampleRate()           { return internal.sampleRate; }
 -     int getCurrentBitDepth()                { return internal.getBitDepth(); }
 - 
 -     BigInteger getActiveOutputChannels() const    { return internal.currentOutputChans; }
 -     BigInteger getActiveInputChannels() const     { return internal.currentInputChans; }
 - 
 -     int getOutputLatencyInSamples()         { return internal.outputLatency; }
 -     int getInputLatencyInSamples()          { return internal.inputLatency; }
 - 
 -     void start (AudioIODeviceCallback* callback)
 -     {
 -         if (! isOpen_)
 -             callback = nullptr;
 - 
 -         if (callback != nullptr)
 -             callback->audioDeviceAboutToStart (this);
 - 
 -         internal.setCallback (callback);
 - 
 -         isStarted = (callback != nullptr);
 -     }
 - 
 -     void stop()
 -     {
 -         AudioIODeviceCallback* const oldCallback = internal.callback;
 - 
 -         start (0);
 - 
 -         if (oldCallback != nullptr)
 -             oldCallback->audioDeviceStopped();
 -     }
 - 
 -     String inputId, outputId;
 - 
 - private:
 -     bool isOpen_, isStarted;
 -     ALSAThread internal;
 - };
 - 
 - 
 - //==============================================================================
 - class ALSAAudioIODeviceType  : public AudioIODeviceType
 - {
 - public:
 -     //==============================================================================
 -     ALSAAudioIODeviceType()
 -         : AudioIODeviceType ("ALSA"),
 -           hasScanned (false)
 -     {
 -     }
 - 
 -     ~ALSAAudioIODeviceType()
 -     {
 -     }
 - 
 -     //==============================================================================
 -     void scanForDevices()
 -     {
 -         if (hasScanned)
 -             return;
 - 
 -         hasScanned = true;
 -         inputNames.clear();
 -         inputIds.clear();
 -         outputNames.clear();
 -         outputIds.clear();
 - 
 - /*        void** hints = 0;
 -         if (snd_device_name_hint (-1, "pcm", &hints) >= 0)
 -         {
 -             for (void** hint = hints; *hint != 0; ++hint)
 -             {
 -                 const String name (getHint (*hint, "NAME"));
 - 
 -                 if (name.isNotEmpty())
 -                 {
 -                     const String ioid (getHint (*hint, "IOID"));
 - 
 -                     String desc (getHint (*hint, "DESC"));
 -                     if (desc.isEmpty())
 -                         desc = name;
 - 
 -                     desc = desc.replaceCharacters ("\n\r", "  ");
 - 
 -                     DBG ("name: " << name << "\ndesc: " << desc << "\nIO: " << ioid);
 - 
 -                     if (ioid.isEmpty() || ioid == "Input")
 -                     {
 -                         inputNames.add (desc);
 -                         inputIds.add (name);
 -                     }
 - 
 -                     if (ioid.isEmpty() || ioid == "Output")
 -                     {
 -                         outputNames.add (desc);
 -                         outputIds.add (name);
 -                     }
 -                 }
 -             }
 - 
 -             snd_device_name_free_hint (hints);
 -         }
 - */
 -         snd_ctl_t* handle = nullptr;
 -         snd_ctl_card_info_t* info = nullptr;
 -         snd_ctl_card_info_alloca (&info);
 - 
 -         int cardNum = -1;
 - 
 -         while (outputIds.size() + inputIds.size() <= 32)
 -         {
 -             snd_card_next (&cardNum);
 - 
 -             if (cardNum < 0)
 -                 break;
 - 
 -             if (snd_ctl_open (&handle, ("hw:" + String (cardNum)).toUTF8(), SND_CTL_NONBLOCK) >= 0)
 -             {
 -                 if (snd_ctl_card_info (handle, info) >= 0)
 -                 {
 -                     String cardId (snd_ctl_card_info_get_id (info));
 - 
 -                     if (cardId.removeCharacters ("0123456789").isEmpty())
 -                         cardId = String (cardNum);
 - 
 -                     int device = -1;
 - 
 -                     for (;;)
 -                     {
 -                         if (snd_ctl_pcm_next_device (handle, &device) < 0 || device < 0)
 -                             break;
 - 
 -                         String id, name;
 -                         id << "hw:" << cardId << ',' << device;
 - 
 -                         bool isInput, isOutput;
 - 
 -                         if (testDevice (id, isInput, isOutput))
 -                         {
 -                             name << snd_ctl_card_info_get_name (info);
 - 
 -                             if (name.isEmpty())
 -                                 name = id;
 - 
 -                             if (isInput)
 -                             {
 -                                 inputNames.add (name);
 -                                 inputIds.add (id);
 -                             }
 - 
 -                             if (isOutput)
 -                             {
 -                                 outputNames.add (name);
 -                                 outputIds.add (id);
 -                             }
 -                         }
 -                     }
 -                 }
 - 
 -                 snd_ctl_close (handle);
 -             }
 -         }
 - 
 -         inputNames.appendNumbersToDuplicates (false, true);
 -         outputNames.appendNumbersToDuplicates (false, true);
 -     }
 - 
 -     StringArray getDeviceNames (bool wantInputNames) const
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 - 
 -         return wantInputNames ? inputNames : outputNames;
 -     }
 - 
 -     int getDefaultDeviceIndex (bool forInput) const
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 -         return 0;
 -     }
 - 
 -     bool hasSeparateInputsAndOutputs() const    { return true; }
 - 
 -     int getIndexOfDevice (AudioIODevice* device, bool asInput) const
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 - 
 -         ALSAAudioIODevice* d = dynamic_cast <ALSAAudioIODevice*> (device);
 -         if (d == nullptr)
 -             return -1;
 - 
 -         return asInput ? inputIds.indexOf (d->inputId)
 -                        : outputIds.indexOf (d->outputId);
 -     }
 - 
 -     AudioIODevice* createDevice (const String& outputDeviceName,
 -                                  const String& inputDeviceName)
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 - 
 -         const int inputIndex = inputNames.indexOf (inputDeviceName);
 -         const int outputIndex = outputNames.indexOf (outputDeviceName);
 - 
 -         String deviceName (outputIndex >= 0 ? outputDeviceName
 -                                             : inputDeviceName);
 - 
 -         if (inputIndex >= 0 || outputIndex >= 0)
 -             return new ALSAAudioIODevice (deviceName,
 -                                           inputIds [inputIndex],
 -                                           outputIds [outputIndex]);
 - 
 -         return nullptr;
 -     }
 - 
 -     //==============================================================================
 - private:
 -     StringArray inputNames, outputNames, inputIds, outputIds;
 -     bool hasScanned;
 - 
 -     static bool testDevice (const String& id, bool& isInput, bool& isOutput)
 -     {
 -         unsigned int minChansOut = 0, maxChansOut = 0;
 -         unsigned int minChansIn = 0, maxChansIn = 0;
 -         Array <int> rates;
 - 
 -         getDeviceProperties (id, minChansOut, maxChansOut, minChansIn, maxChansIn, rates);
 - 
 -         DBG ("ALSA device: " + id
 -               + " outs=" + String ((int) minChansOut) + "-" + String ((int) maxChansOut)
 -               + " ins=" + String ((int) minChansIn) + "-" + String ((int) maxChansIn)
 -               + " rates=" + String (rates.size()));
 - 
 -         isInput = maxChansIn > 0;
 -         isOutput = maxChansOut > 0;
 - 
 -         return (isInput || isOutput) && rates.size() > 0;
 -     }
 - 
 -     /*static String getHint (void* hint, const char* type)
 -     {
 -         char* const n = snd_device_name_get_hint (hint, type);
 -         const String s ((const char*) n);
 -         free (n);
 -         return s;
 -     }*/
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ALSAAudioIODeviceType);
 - };
 - 
 - //==============================================================================
 - AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_ALSA()
 - {
 -     return new ALSAAudioIODeviceType();
 - }
 
 
  |