| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2022 - Raw Material Software Limited
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    The code included in this file is provided under the terms of the ISC license
 -    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 -    To use, copy, modify, and/or distribute this software for any purpose with or
 -    without fee is hereby granted provided that the above copyright notice and
 -    this permission notice appear in all copies.
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace juce
 - {
 - 
 - namespace
 - {
 - 
 - #ifndef JUCE_ALSA_LOGGING
 -  #define JUCE_ALSA_LOGGING 0
 - #endif
 - 
 - #if JUCE_ALSA_LOGGING
 -  #define JUCE_ALSA_LOG(dbgtext)   { juce::String tempDbgBuf ("ALSA: "); tempDbgBuf << dbgtext; Logger::writeToLog (tempDbgBuf); DBG (tempDbgBuf); }
 -  #define JUCE_CHECKED_RESULT(x)   (logErrorMessage (x, __LINE__))
 - 
 -  static int logErrorMessage (int err, int lineNum)
 -  {
 -     if (err < 0)
 -         JUCE_ALSA_LOG ("Error: line " << lineNum << ": code " << err << " (" << snd_strerror (err) << ")");
 - 
 -     return err;
 -  }
 - #else
 -  #define JUCE_ALSA_LOG(x)         {}
 -  #define JUCE_CHECKED_RESULT(x)   (x)
 - #endif
 - 
 - #define JUCE_ALSA_FAILED(x)  failed (x)
 - 
 - static void getDeviceSampleRates (snd_pcm_t* handle, Array<double>& rates)
 - {
 -     snd_pcm_hw_params_t* hwParams;
 -     snd_pcm_hw_params_alloca (&hwParams);
 - 
 -     for (const auto rateToTry : SampleRateHelpers::getAllSampleRates())
 -     {
 -         if (snd_pcm_hw_params_any (handle, hwParams) >= 0
 -              && snd_pcm_hw_params_test_rate (handle, hwParams, (unsigned int) rateToTry, 0) == 0)
 -         {
 -             rates.addIfNotAlreadyThere (rateToTry);
 -         }
 -     }
 - }
 - 
 - static 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);
 - 
 -         JUCE_ALSA_LOG ("getDeviceNumChannels: " << (int) *minChans << " " << (int) *maxChans);
 - 
 -         // some virtual devices (dmix for example) report 10000 channels , we have to clamp these values
 -         *maxChans = jmin (*maxChans, 256u);
 -         *minChans = jmin (*minChans, *maxChans);
 -     }
 -     else
 -     {
 -         JUCE_ALSA_LOG ("getDeviceNumChannels failed");
 -     }
 - }
 - 
 - static void getDeviceProperties (const String& deviceID,
 -                                  unsigned int& minChansOut,
 -                                  unsigned int& maxChansOut,
 -                                  unsigned int& minChansIn,
 -                                  unsigned int& maxChansIn,
 -                                  Array<double>& rates,
 -                                  bool testOutput,
 -                                  bool testInput)
 - {
 -     minChansOut = maxChansOut = minChansIn = maxChansIn = 0;
 - 
 -     if (deviceID.isEmpty())
 -         return;
 - 
 -     JUCE_ALSA_LOG ("getDeviceProperties(" << deviceID.toUTF8().getAddress() << ")");
 - 
 -     snd_pcm_info_t* info;
 -     snd_pcm_info_alloca (&info);
 - 
 -     if (testOutput)
 -     {
 -         snd_pcm_t* pcmHandle;
 - 
 -         if (JUCE_CHECKED_RESULT (snd_pcm_open (&pcmHandle, deviceID.toUTF8().getAddress(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) >= 0)
 -         {
 -             getDeviceNumChannels (pcmHandle, &minChansOut, &maxChansOut);
 -             getDeviceSampleRates (pcmHandle, rates);
 - 
 -             snd_pcm_close (pcmHandle);
 -         }
 -     }
 - 
 -     if (testInput)
 -     {
 -         snd_pcm_t* pcmHandle;
 - 
 -         if (JUCE_CHECKED_RESULT (snd_pcm_open (&pcmHandle, deviceID.toUTF8(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) >= 0))
 -         {
 -             getDeviceNumChannels (pcmHandle, &minChansIn, &maxChansIn);
 - 
 -             if (rates.size() == 0)
 -                 getDeviceSampleRates (pcmHandle, rates);
 - 
 -             snd_pcm_close (pcmHandle);
 -         }
 -     }
 - }
 - 
 - static void ensureMinimumNumBitsSet (BigInteger& chans, int minNumChans)
 - {
 -     int i = 0;
 - 
 -     while (chans.countNumberOfSetBits() < minNumChans)
 -         chans.setBit (i++);
 - }
 - 
 - static void silentErrorHandler (const char*, int, const char*, int, const char*,...) {}
 - 
 - //==============================================================================
 - class ALSADevice
 - {
 - public:
 -     ALSADevice (const String& devID, bool forInput)
 -         : handle (nullptr),
 -           bitDepth (16),
 -           numChannelsRunning (0),
 -           latency (0),
 -           deviceID (devID),
 -           isInput (forInput),
 -           isInterleaved (true)
 -     {
 -         JUCE_ALSA_LOG ("snd_pcm_open (" << deviceID.toUTF8().getAddress() << ", forInput=" << (int) forInput << ")");
 - 
 -         int err = snd_pcm_open (&handle, deviceID.toUTF8(),
 -                                 forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
 -                                 SND_PCM_ASYNC);
 -         if (err < 0)
 -         {
 -             if (-err == EBUSY)
 -                 error << "The device \"" << deviceID << "\" is busy (another application is using it).";
 -             else if (-err == ENOENT)
 -                 error << "The device \"" << deviceID << "\" is not available.";
 -             else
 -                 error << "Could not open " << (forInput ? "input" : "output") << " device \"" << deviceID
 -                       << "\": " << snd_strerror(err) << " (" << err << ")";
 - 
 -             JUCE_ALSA_LOG ("snd_pcm_open failed; " << error);
 -         }
 -     }
 - 
 -     ~ALSADevice()
 -     {
 -         closeNow();
 -     }
 - 
 -     void closeNow()
 -     {
 -         if (handle != nullptr)
 -         {
 -             snd_pcm_close (handle);
 -             handle = nullptr;
 -         }
 -     }
 - 
 -     bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize)
 -     {
 -         if (handle == nullptr)
 -             return false;
 - 
 -         JUCE_ALSA_LOG ("ALSADevice::setParameters(" << deviceID << ", "
 -                          << (int) sampleRate << ", " << numChannels << ", " << bufferSize << ")");
 - 
 -         snd_pcm_hw_params_t* hwParams;
 -         snd_pcm_hw_params_alloca (&hwParams);
 - 
 -         if (snd_pcm_hw_params_any (handle, hwParams) < 0)
 -         {
 -             // this is the error message that aplay returns when an error happens here,
 -             // it is a bit more explicit that "Invalid parameter"
 -             error = "Broken configuration for this PCM: no configurations available";
 -             return false;
 -         }
 - 
 -         if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0) // works better for plughw..
 -             isInterleaved = true;
 -         else if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_NONINTERLEAVED) >= 0)
 -             isInterleaved = false;
 -         else
 -         {
 -             jassertfalse;
 -             return false;
 -         }
 - 
 -         enum { isFloatBit = 1 << 16, isLittleEndianBit = 1 << 17, onlyUseLower24Bits = 1 << 18 };
 - 
 -         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_S24_LE,     32 | isLittleEndianBit | onlyUseLower24Bits,
 -                                      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)
 -             {
 -                 const int type = formatsToTry [i + 1];
 -                 bitDepth = type & 255;
 - 
 -                 converter.reset (createConverter (isInput, bitDepth,
 -                                                   (type & isFloatBit) != 0,
 -                                                   (type & isLittleEndianBit) != 0,
 -                                                   (type & onlyUseLower24Bits) != 0,
 -                                                   numChannels,
 -                                                   isInterleaved));
 -                 break;
 -             }
 -         }
 - 
 -         if (bitDepth == 0)
 -         {
 -             error = "device doesn't support a compatible PCM format";
 -             JUCE_ALSA_LOG ("Error: " + error);
 -             return false;
 -         }
 - 
 -         int dir = 0;
 -         unsigned int periods = 4;
 -         snd_pcm_uframes_t samplesPerPeriod = (snd_pcm_uframes_t) bufferSize;
 - 
 -         if (JUCE_ALSA_FAILED (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, nullptr))
 -             || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_channels (handle, hwParams, (unsigned int ) numChannels))
 -             || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir))
 -             || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir))
 -             || JUCE_ALSA_FAILED (snd_pcm_hw_params (handle, hwParams)))
 -         {
 -             return false;
 -         }
 - 
 -         snd_pcm_uframes_t frames = 0;
 - 
 -         if (JUCE_ALSA_FAILED (snd_pcm_hw_params_get_period_size (hwParams, &frames, &dir))
 -              || JUCE_ALSA_FAILED (snd_pcm_hw_params_get_periods (hwParams, &periods, &dir)))
 -             latency = 0;
 -         else
 -             latency = (int) frames * ((int) periods - 1); // (this is the method JACK uses to guess the latency..)
 - 
 -         JUCE_ALSA_LOG ("frames: " << (int) frames << ", periods: " << (int) periods
 -                           << ", samplesPerPeriod: " << (int) samplesPerPeriod);
 - 
 -         snd_pcm_sw_params_t* swParams;
 -         snd_pcm_sw_params_alloca (&swParams);
 -         snd_pcm_uframes_t boundary;
 - 
 -         if (JUCE_ALSA_FAILED (snd_pcm_sw_params_current (handle, swParams))
 -             || JUCE_ALSA_FAILED (snd_pcm_sw_params_get_boundary (swParams, &boundary))
 -             || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_silence_threshold (handle, swParams, 0))
 -             || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_silence_size (handle, swParams, boundary))
 -             || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_start_threshold (handle, swParams, samplesPerPeriod))
 -             || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_stop_threshold (handle, swParams, boundary))
 -             || JUCE_ALSA_FAILED (snd_pcm_sw_params (handle, swParams)))
 -         {
 -             return false;
 -         }
 - 
 -        #if JUCE_ALSA_LOGGING
 -         // 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 (AudioBuffer<float>& outputChannelBuffer, const int numSamples)
 -     {
 -         jassert (numChannelsRunning <= outputChannelBuffer.getNumChannels());
 -         float* const* const data = outputChannelBuffer.getArrayOfWritePointers();
 -         snd_pcm_sframes_t numDone = 0;
 - 
 -         if (isInterleaved)
 -         {
 -             scratch.ensureSize ((size_t) ((int) 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(), (snd_pcm_uframes_t) numSamples);
 -         }
 -         else
 -         {
 -             for (int i = 0; i < numChannelsRunning; ++i)
 -                 converter->convertSamples (data[i], data[i], numSamples);
 - 
 -             numDone = snd_pcm_writen (handle, (void**) data, (snd_pcm_uframes_t) numSamples);
 -         }
 - 
 -         if (numDone < 0)
 -         {
 -             if (numDone == -(EPIPE))
 -                 underrunCount++;
 - 
 -             if (JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) numDone, 1 /* silent */)))
 -                 return false;
 -         }
 - 
 -         if (numDone < numSamples)
 -             JUCE_ALSA_LOG ("Did not write all samples: numDone: " << numDone << ", numSamples: " << numSamples);
 - 
 -         return true;
 -     }
 - 
 -     bool readFromInputDevice (AudioBuffer<float>& inputChannelBuffer, const int numSamples)
 -     {
 -         jassert (numChannelsRunning <= inputChannelBuffer.getNumChannels());
 -         float* const* const data = inputChannelBuffer.getArrayOfWritePointers();
 - 
 -         if (isInterleaved)
 -         {
 -             scratch.ensureSize ((size_t) ((int) sizeof (float) * numSamples * numChannelsRunning), false);
 -             scratch.fillWith (0); // (not clearing this data causes warnings in valgrind)
 - 
 -             auto num = snd_pcm_readi (handle, scratch.getData(), (snd_pcm_uframes_t) numSamples);
 - 
 -             if (num < 0)
 -             {
 -                 if (num == -(EPIPE))
 -                     overrunCount++;
 - 
 -                 if (JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) num, 1 /* silent */)))
 -                     return false;
 -             }
 - 
 - 
 -             if (num < numSamples)
 -                 JUCE_ALSA_LOG ("Did not read all samples: num: " << num << ", numSamples: " << numSamples);
 - 
 -             for (int i = 0; i < numChannelsRunning; ++i)
 -                 converter->convertSamples (data[i], 0, scratch.getData(), i, numSamples);
 -         }
 -         else
 -         {
 -             auto num = snd_pcm_readn (handle, (void**) data, (snd_pcm_uframes_t) numSamples);
 - 
 -             if (num < 0)
 -             {
 -                 if (num == -(EPIPE))
 -                     overrunCount++;
 - 
 -                 if (JUCE_ALSA_FAILED (snd_pcm_recover (handle, (int) num, 1 /* silent */)))
 -                     return false;
 -             }
 - 
 -             if (num < numSamples)
 -                 JUCE_ALSA_LOG ("Did not read all samples: num: " << num << ", numSamples: " << numSamples);
 - 
 -             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;
 -     int underrunCount = 0, overrunCount = 0;
 - 
 - private:
 -     //==============================================================================
 -     String deviceID;
 -     const bool isInput;
 -     bool isInterleaved;
 -     MemoryBlock scratch;
 -     std::unique_ptr<AudioData::Converter> converter;
 - 
 -     //==============================================================================
 -     template <class SampleType>
 -     struct ConverterHelper
 -     {
 -         static AudioData::Converter* createConverter (const bool forInput, const bool isLittleEndian, const int numInterleavedChannels, bool interleaved)
 -         {
 -             if (interleaved)
 -                 return create<AudioData::Interleaved> (forInput, isLittleEndian, numInterleavedChannels);
 - 
 -             return create<AudioData::NonInterleaved> (forInput, isLittleEndian, numInterleavedChannels);
 -         }
 - 
 -     private:
 -         template <class InterleavedType>
 -         static AudioData::Converter* create (const bool forInput, const bool isLittleEndian, const int numInterleavedChannels)
 -         {
 -             if (forInput)
 -             {
 -                 using DestType = AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>;
 - 
 -                 if (isLittleEndian)
 -                     return new AudioData::ConverterInstance <AudioData::Pointer <SampleType, AudioData::LittleEndian, InterleavedType, AudioData::Const>, DestType> (numInterleavedChannels, 1);
 - 
 -                 return new AudioData::ConverterInstance <AudioData::Pointer <SampleType, AudioData::BigEndian, InterleavedType, AudioData::Const>, DestType> (numInterleavedChannels, 1);
 -             }
 - 
 -             using SourceType = AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>;
 - 
 -             if (isLittleEndian)
 -                 return new AudioData::ConverterInstance <SourceType, AudioData::Pointer <SampleType, AudioData::LittleEndian, InterleavedType, AudioData::NonConst>> (1, numInterleavedChannels);
 - 
 -             return new AudioData::ConverterInstance <SourceType, AudioData::Pointer <SampleType, AudioData::BigEndian, InterleavedType, AudioData::NonConst>> (1, numInterleavedChannels);
 -         }
 -     };
 - 
 -     static AudioData::Converter* createConverter (bool forInput, int bitDepth,
 -                                                   bool isFloat, bool isLittleEndian, bool useOnlyLower24Bits,
 -                                                   int numInterleavedChannels,
 -                                                   bool interleaved)
 -     {
 -         JUCE_ALSA_LOG ("format: bitDepth=" << bitDepth << ", isFloat=" << (int) isFloat
 -                         << ", isLittleEndian=" << (int) isLittleEndian << ", numChannels=" << numInterleavedChannels);
 - 
 -         if (isFloat)         return ConverterHelper <AudioData::Float32>::createConverter (forInput, isLittleEndian, numInterleavedChannels, interleaved);
 -         if (bitDepth == 16)  return ConverterHelper <AudioData::Int16>  ::createConverter (forInput, isLittleEndian, numInterleavedChannels, interleaved);
 -         if (bitDepth == 24)  return ConverterHelper <AudioData::Int24>  ::createConverter (forInput, isLittleEndian, numInterleavedChannels, interleaved);
 - 
 -         jassert (bitDepth == 32);
 - 
 -         if (useOnlyLower24Bits)
 -             return ConverterHelper <AudioData::Int24in32>::createConverter (forInput, isLittleEndian, numInterleavedChannels, interleaved);
 - 
 -         return ConverterHelper <AudioData::Int32>::createConverter (forInput, isLittleEndian, numInterleavedChannels, interleaved);
 -     }
 - 
 -     //==============================================================================
 -     bool failed (const int errorNum)
 -     {
 -         if (errorNum >= 0)
 -             return false;
 - 
 -         error = snd_strerror (errorNum);
 -         JUCE_ALSA_LOG ("ALSA error: " << error);
 -         return true;
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ALSADevice)
 - };
 - 
 - //==============================================================================
 - class ALSAThread  : public Thread
 - {
 - public:
 -     ALSAThread (const String& inputDeviceID, const String& outputDeviceID)
 -         : Thread ("JUCE ALSA"),
 -           inputId (inputDeviceID),
 -           outputId (outputDeviceID)
 -     {
 -         initialiseRatesAndChannels();
 -     }
 - 
 -     ~ALSAThread() override
 -     {
 -         close();
 -     }
 - 
 -     void open (BigInteger inputChannels,
 -                BigInteger outputChannels,
 -                double newSampleRate,
 -                int newBufferSize)
 -     {
 -         close();
 - 
 -         error.clear();
 -         sampleRate = newSampleRate;
 -         bufferSize = newBufferSize;
 - 
 -         int maxInputsRequested = inputChannels.getHighestBit() + 1;
 -         maxInputsRequested = jmax ((int) minChansIn, jmin ((int) maxChansIn, maxInputsRequested));
 - 
 -         inputChannelBuffer.setSize (maxInputsRequested, bufferSize);
 -         inputChannelBuffer.clear();
 -         inputChannelDataForCallback.clear();
 -         currentInputChans.clear();
 - 
 -         if (inputChannels.getHighestBit() >= 0)
 -         {
 -             for (int i = 0; i < maxInputsRequested; ++i)
 -             {
 -                 if (inputChannels[i])
 -                 {
 -                     inputChannelDataForCallback.add (inputChannelBuffer.getReadPointer (i));
 -                     currentInputChans.setBit (i);
 -                 }
 -             }
 -         }
 - 
 -         ensureMinimumNumBitsSet (outputChannels, (int) minChansOut);
 - 
 -         int maxOutputsRequested = outputChannels.getHighestBit() + 1;
 -         maxOutputsRequested = jmax ((int) minChansOut, jmin ((int) maxChansOut, maxOutputsRequested));
 - 
 -         outputChannelBuffer.setSize (maxOutputsRequested, bufferSize);
 -         outputChannelBuffer.clear();
 -         outputChannelDataForCallback.clear();
 -         currentOutputChans.clear();
 - 
 -         // Note that the input device is opened before an output, because we've heard
 -         // of drivers where doing it in the reverse order mysteriously fails.. If this
 -         // order also causes problems, let us know and we'll see if we can find a compromise!
 - 
 -         if (inputChannelDataForCallback.size() > 0 && inputId.isNotEmpty())
 -         {
 -             inputDevice.reset (new ALSADevice (inputId, true));
 - 
 -             if (inputDevice->error.isNotEmpty())
 -             {
 -                 error = inputDevice->error;
 -                 inputDevice.reset();
 -                 return;
 -             }
 - 
 -             ensureMinimumNumBitsSet (currentInputChans, (int) minChansIn);
 - 
 -             if (! inputDevice->setParameters ((unsigned int) sampleRate,
 -                                               jlimit ((int) minChansIn, (int) maxChansIn, currentInputChans.getHighestBit() + 1),
 -                                               bufferSize))
 -             {
 -                 error = inputDevice->error;
 -                 inputDevice.reset();
 -                 return;
 -             }
 - 
 -             inputLatency = inputDevice->latency;
 -         }
 - 
 -         if (outputChannels.getHighestBit() >= 0)
 -         {
 -             for (int i = 0; i < maxOutputsRequested; ++i)
 -             {
 -                 if (outputChannels[i])
 -                 {
 -                     outputChannelDataForCallback.add (outputChannelBuffer.getWritePointer (i));
 -                     currentOutputChans.setBit (i);
 -                 }
 -             }
 -         }
 - 
 -         if (outputChannelDataForCallback.size() > 0 && outputId.isNotEmpty())
 -         {
 -             outputDevice.reset (new ALSADevice (outputId, false));
 - 
 -             if (outputDevice->error.isNotEmpty())
 -             {
 -                 error = outputDevice->error;
 -                 outputDevice.reset();
 -                 return;
 -             }
 - 
 -             if (! outputDevice->setParameters ((unsigned int) sampleRate,
 -                                                jlimit ((int) minChansOut, (int) maxChansOut,
 -                                                        currentOutputChans.getHighestBit() + 1),
 -                                                bufferSize))
 -             {
 -                 error = outputDevice->error;
 -                 outputDevice.reset();
 -                 return;
 -             }
 - 
 -             outputLatency = outputDevice->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 && JUCE_ALSA_FAILED (snd_pcm_prepare (inputDevice->handle)))
 -             return;
 - 
 -         if (outputDevice != nullptr && JUCE_ALSA_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()
 -     {
 -         if (isThreadRunning())
 -         {
 -             // problem: when pulseaudio is suspended (with pasuspend) , the ALSAThread::run is just stuck in
 -             // snd_pcm_writei -- no error, no nothing it just stays stuck. So the only way I found to exit "nicely"
 -             // (that is without the "killing thread by force" of stopThread) , is to just call snd_pcm_close from
 -             // here which will cause the thread to resume, and exit
 -             signalThreadShouldExit();
 - 
 -             const int callbacksToStop = numCallbacks;
 - 
 -             if ((! waitForThreadToExit (400)) && audioIoInProgress && numCallbacks == callbacksToStop)
 -             {
 -                 JUCE_ALSA_LOG ("Thread is stuck in i/o.. Is pulseaudio suspended?");
 - 
 -                 if (outputDevice != nullptr) outputDevice->closeNow();
 -                 if (inputDevice != nullptr) inputDevice->closeNow();
 -             }
 -         }
 - 
 -         stopThread (6000);
 - 
 -         inputDevice.reset();
 -         outputDevice.reset();
 - 
 -         inputChannelBuffer.setSize (1, 1);
 -         outputChannelBuffer.setSize (1, 1);
 - 
 -         numCallbacks = 0;
 -     }
 - 
 -     void setCallback (AudioIODeviceCallback* const newCallback) noexcept
 -     {
 -         const ScopedLock sl (callbackLock);
 -         callback = newCallback;
 -     }
 - 
 -     void run() override
 -     {
 -         while (! threadShouldExit())
 -         {
 -             if (inputDevice != nullptr && inputDevice->handle != nullptr)
 -             {
 -                 if (outputDevice == nullptr || outputDevice->handle == nullptr)
 -                 {
 -                     JUCE_ALSA_FAILED (snd_pcm_wait (inputDevice->handle, 2000));
 - 
 -                     if (threadShouldExit())
 -                         break;
 - 
 -                     auto avail = snd_pcm_avail_update (inputDevice->handle);
 - 
 -                     if (avail < 0)
 -                         JUCE_ALSA_FAILED (snd_pcm_recover (inputDevice->handle, (int) avail, 0));
 -                 }
 - 
 -                 audioIoInProgress = true;
 - 
 -                 if (! inputDevice->readFromInputDevice (inputChannelBuffer, bufferSize))
 -                 {
 -                     JUCE_ALSA_LOG ("Read failure");
 -                     break;
 -                 }
 - 
 -                 audioIoInProgress = false;
 -             }
 - 
 -             if (threadShouldExit())
 -                 break;
 - 
 -             {
 -                 const ScopedLock sl (callbackLock);
 -                 ++numCallbacks;
 - 
 -                 if (callback != nullptr)
 -                 {
 -                     callback->audioDeviceIOCallbackWithContext (inputChannelDataForCallback.getRawDataPointer(),
 -                                                                 inputChannelDataForCallback.size(),
 -                                                                 outputChannelDataForCallback.getRawDataPointer(),
 -                                                                 outputChannelDataForCallback.size(),
 -                                                                 bufferSize,
 -                                                                 {});
 -                 }
 -                 else
 -                 {
 -                     for (int i = 0; i < outputChannelDataForCallback.size(); ++i)
 -                         zeromem (outputChannelDataForCallback[i], (size_t) bufferSize * sizeof (float));
 -                 }
 -             }
 - 
 -             if (outputDevice != nullptr && outputDevice->handle != nullptr)
 -             {
 -                 JUCE_ALSA_FAILED (snd_pcm_wait (outputDevice->handle, 2000));
 - 
 -                 if (threadShouldExit())
 -                     break;
 - 
 -                 auto avail = snd_pcm_avail_update (outputDevice->handle);
 - 
 -                 if (avail < 0)
 -                     JUCE_ALSA_FAILED (snd_pcm_recover (outputDevice->handle, (int) avail, 0));
 - 
 -                 audioIoInProgress = true;
 - 
 -                 if (! outputDevice->writeToOutputDevice (outputChannelBuffer, bufferSize))
 -                 {
 -                     JUCE_ALSA_LOG ("write failure");
 -                     break;
 -                 }
 - 
 -                 audioIoInProgress = false;
 -             }
 -         }
 - 
 -         audioIoInProgress = false;
 -     }
 - 
 -     int getBitDepth() const noexcept
 -     {
 -         if (outputDevice != nullptr)
 -             return outputDevice->bitDepth;
 - 
 -         if (inputDevice != nullptr)
 -             return inputDevice->bitDepth;
 - 
 -         return 16;
 -     }
 - 
 -     int getXRunCount() const noexcept
 -     {
 -         int result = 0;
 - 
 -         if (outputDevice != nullptr)
 -             result += outputDevice->underrunCount;
 - 
 -         if (inputDevice != nullptr)
 -             result += inputDevice->overrunCount;
 - 
 -         return result;
 -     }
 - 
 -     //==============================================================================
 -     String error;
 -     double sampleRate = 0;
 -     int bufferSize = 0, outputLatency = 0, inputLatency = 0;
 -     BigInteger currentInputChans, currentOutputChans;
 - 
 -     Array<double> sampleRates;
 -     StringArray channelNamesOut, channelNamesIn;
 -     AudioIODeviceCallback* callback = nullptr;
 - 
 - private:
 -     //==============================================================================
 -     const String inputId, outputId;
 -     std::unique_ptr<ALSADevice> outputDevice, inputDevice;
 -     std::atomic<int> numCallbacks { 0 };
 -     std::atomic<bool> audioIoInProgress { false };
 - 
 -     CriticalSection callbackLock;
 - 
 -     AudioBuffer<float> inputChannelBuffer, outputChannelBuffer;
 -     Array<const float*> inputChannelDataForCallback;
 -     Array<float*> outputChannelDataForCallback;
 - 
 -     unsigned int minChansOut = 0, maxChansOut = 0;
 -     unsigned int minChansIn = 0, maxChansIn = 0;
 - 
 -     bool failed (const int errorNum)
 -     {
 -         if (errorNum >= 0)
 -             return false;
 - 
 -         error = snd_strerror (errorNum);
 -         JUCE_ALSA_LOG ("ALSA error: " << error);
 -         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, false, true);
 -         getDeviceProperties (outputId, minChansOut, maxChansOut, dummy, dummy, sampleRates, true, false);
 - 
 -         for (unsigned int i = 0; i < maxChansOut; ++i)
 -             channelNamesOut.add ("channel " + String ((int) i + 1));
 - 
 -         for (unsigned int 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& deviceTypeName,
 -                        const String& inputDeviceID,
 -                        const String& outputDeviceID)
 -         : AudioIODevice (deviceName, deviceTypeName),
 -           inputId (inputDeviceID),
 -           outputId (outputDeviceID),
 -           internal (inputDeviceID, outputDeviceID)
 -     {
 -     }
 - 
 -     ~ALSAAudioIODevice() override
 -     {
 -         close();
 -     }
 - 
 -     StringArray getOutputChannelNames() override            { return internal.channelNamesOut; }
 -     StringArray getInputChannelNames() override             { return internal.channelNamesIn; }
 - 
 -     Array<double> getAvailableSampleRates() override        { return internal.sampleRates; }
 - 
 -     Array<int> getAvailableBufferSizes() override
 -     {
 -         Array<int> r;
 -         int n = 16;
 - 
 -         for (int i = 0; i < 50; ++i)
 -         {
 -             r.add (n);
 -             n += n < 64 ? 16
 -                         : (n < 512 ? 32
 -                                    : (n < 1024 ? 64
 -                                                : (n < 2048 ? 128 : 256)));
 -         }
 - 
 -         return r;
 -     }
 - 
 -     int getDefaultBufferSize() override                      { return 512; }
 - 
 -     String open (const BigInteger& inputChannels,
 -                  const BigInteger& outputChannels,
 -                  double sampleRate,
 -                  int bufferSizeSamples) override
 -     {
 -         close();
 - 
 -         if (bufferSizeSamples <= 0)
 -             bufferSizeSamples = getDefaultBufferSize();
 - 
 -         if (sampleRate <= 0)
 -         {
 -             for (int i = 0; i < internal.sampleRates.size(); ++i)
 -             {
 -                 double rate = internal.sampleRates[i];
 - 
 -                 if (rate >= 44100)
 -                 {
 -                     sampleRate = rate;
 -                     break;
 -                 }
 -             }
 -         }
 - 
 -         internal.open (inputChannels, outputChannels,
 -                        sampleRate, bufferSizeSamples);
 - 
 -         isOpen_ = internal.error.isEmpty();
 -         return internal.error;
 -     }
 - 
 -     void close() override
 -     {
 -         stop();
 -         internal.close();
 -         isOpen_ = false;
 -     }
 - 
 -     bool isOpen() override                           { return isOpen_; }
 -     bool isPlaying() override                        { return isStarted && internal.error.isEmpty(); }
 -     String getLastError() override                   { return internal.error; }
 - 
 -     int getCurrentBufferSizeSamples() override       { return internal.bufferSize; }
 -     double getCurrentSampleRate() override           { return internal.sampleRate; }
 -     int getCurrentBitDepth() override                { return internal.getBitDepth(); }
 - 
 -     BigInteger getActiveOutputChannels() const override    { return internal.currentOutputChans; }
 -     BigInteger getActiveInputChannels() const override     { return internal.currentInputChans; }
 - 
 -     int getOutputLatencyInSamples() override         { return internal.outputLatency; }
 -     int getInputLatencyInSamples() override          { return internal.inputLatency; }
 - 
 -     int getXRunCount() const noexcept override       { return internal.getXRunCount(); }
 - 
 -     void start (AudioIODeviceCallback* callback) override
 -     {
 -         if (! isOpen_)
 -             callback = nullptr;
 - 
 -         if (callback != nullptr)
 -             callback->audioDeviceAboutToStart (this);
 - 
 -         internal.setCallback (callback);
 - 
 -         isStarted = (callback != nullptr);
 -     }
 - 
 -     void stop() override
 -     {
 -         auto oldCallback = internal.callback;
 - 
 -         start (nullptr);
 - 
 -         if (oldCallback != nullptr)
 -             oldCallback->audioDeviceStopped();
 -     }
 - 
 -     String inputId, outputId;
 - 
 - private:
 -     bool isOpen_ = false, isStarted = false;
 -     ALSAThread internal;
 - };
 - 
 - 
 - //==============================================================================
 - class ALSAAudioIODeviceType  : public AudioIODeviceType
 - {
 - public:
 -     ALSAAudioIODeviceType (bool onlySoundcards, const String& deviceTypeName)
 -         : AudioIODeviceType (deviceTypeName),
 -           listOnlySoundcards (onlySoundcards)
 -     {
 -        #if ! JUCE_ALSA_LOGGING
 -         snd_lib_error_set_handler (&silentErrorHandler);
 -        #endif
 -     }
 - 
 -     ~ALSAAudioIODeviceType()
 -     {
 -        #if ! JUCE_ALSA_LOGGING
 -         snd_lib_error_set_handler (nullptr);
 -        #endif
 - 
 -         snd_config_update_free_global(); // prevent valgrind from screaming about alsa leaks
 -     }
 - 
 -     //==============================================================================
 -     void scanForDevices()
 -     {
 -         if (hasScanned)
 -             return;
 - 
 -         hasScanned = true;
 -         inputNames.clear();
 -         inputIds.clear();
 -         outputNames.clear();
 -         outputIds.clear();
 - 
 -         JUCE_ALSA_LOG ("scanForDevices()");
 - 
 -         if (listOnlySoundcards)
 -             enumerateAlsaSoundcards();
 -         else
 -             enumerateAlsaPCMDevices();
 - 
 -         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
 - 
 -         auto idx = (forInput ? inputIds : outputIds).indexOf ("default");
 -         return idx >= 0 ? idx : 0;
 -     }
 - 
 -     bool hasSeparateInputsAndOutputs() const    { return true; }
 - 
 -     int getIndexOfDevice (AudioIODevice* device, bool asInput) const
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 - 
 -         if (auto* d = dynamic_cast<ALSAAudioIODevice*> (device))
 -             return asInput ? inputIds.indexOf (d->inputId)
 -                            : outputIds.indexOf (d->outputId);
 - 
 -         return -1;
 -     }
 - 
 -     AudioIODevice* createDevice (const String& outputDeviceName,
 -                                  const String& inputDeviceName)
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 - 
 -         auto inputIndex = inputNames.indexOf (inputDeviceName);
 -         auto outputIndex = outputNames.indexOf (outputDeviceName);
 - 
 -         String deviceName (outputIndex >= 0 ? outputDeviceName
 -                                             : inputDeviceName);
 - 
 -         if (inputIndex >= 0 || outputIndex >= 0)
 -             return new ALSAAudioIODevice (deviceName, getTypeName(),
 -                                           inputIds [inputIndex],
 -                                           outputIds [outputIndex]);
 - 
 -         return nullptr;
 -     }
 - 
 - private:
 -     //==============================================================================
 -     StringArray inputNames, outputNames, inputIds, outputIds;
 -     bool hasScanned = false;
 -     const bool listOnlySoundcards;
 - 
 -     bool testDevice (const String& id, const String& outputName, const String& inputName)
 -     {
 -         unsigned int minChansOut = 0, maxChansOut = 0;
 -         unsigned int minChansIn = 0, maxChansIn = 0;
 -         Array<double> rates;
 - 
 -         bool isInput = inputName.isNotEmpty(), isOutput = outputName.isNotEmpty();
 -         getDeviceProperties (id, minChansOut, maxChansOut, minChansIn, maxChansIn, rates, isOutput, isInput);
 - 
 -         isInput  = maxChansIn > 0;
 -         isOutput = maxChansOut > 0;
 - 
 -         if ((isInput || isOutput) && rates.size() > 0)
 -         {
 -             JUCE_ALSA_LOG ("testDevice: '" << id.toUTF8().getAddress() << "' -> isInput: "
 -                             << (int) isInput << ", isOutput: " << (int) isOutput);
 - 
 -             if (isInput)
 -             {
 -                 inputNames.add (inputName);
 -                 inputIds.add (id);
 -             }
 - 
 -             if (isOutput)
 -             {
 -                 outputNames.add (outputName);
 -                 outputIds.add (id);
 -             }
 - 
 -             return isInput || isOutput;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     void enumerateAlsaSoundcards()
 -     {
 -         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() <= 64)
 -         {
 -             snd_card_next (&cardNum);
 - 
 -             if (cardNum < 0)
 -                 break;
 - 
 -             if (JUCE_CHECKED_RESULT (snd_ctl_open (&handle, ("hw:" + String (cardNum)).toRawUTF8(), SND_CTL_NONBLOCK)) >= 0)
 -             {
 -                 if (JUCE_CHECKED_RESULT (snd_ctl_card_info (handle, info)) >= 0)
 -                 {
 -                     String cardId (snd_ctl_card_info_get_id (info));
 - 
 -                     if (cardId.removeCharacters ("0123456789").isEmpty())
 -                         cardId = String (cardNum);
 - 
 -                     String cardName = snd_ctl_card_info_get_name (info);
 - 
 -                     if (cardName.isEmpty())
 -                         cardName = cardId;
 - 
 -                     int device = -1;
 - 
 -                     snd_pcm_info_t* pcmInfo;
 -                     snd_pcm_info_alloca (&pcmInfo);
 - 
 -                     for (;;)
 -                     {
 -                         if (snd_ctl_pcm_next_device (handle, &device) < 0 || device < 0)
 -                             break;
 - 
 -                         snd_pcm_info_set_device (pcmInfo, (unsigned int) device);
 - 
 -                         for (unsigned int subDevice = 0, nbSubDevice = 1; subDevice < nbSubDevice; ++subDevice)
 -                         {
 -                             snd_pcm_info_set_subdevice (pcmInfo, subDevice);
 -                             snd_pcm_info_set_stream (pcmInfo, SND_PCM_STREAM_CAPTURE);
 -                             const bool isInput = (snd_ctl_pcm_info (handle, pcmInfo) >= 0);
 - 
 -                             snd_pcm_info_set_stream (pcmInfo, SND_PCM_STREAM_PLAYBACK);
 -                             const bool isOutput = (snd_ctl_pcm_info (handle, pcmInfo) >= 0);
 - 
 -                             if (! (isInput || isOutput))
 -                                 continue;
 - 
 -                             if (nbSubDevice == 1)
 -                                 nbSubDevice = snd_pcm_info_get_subdevices_count (pcmInfo);
 - 
 -                             String id, name;
 - 
 -                             if (nbSubDevice == 1)
 -                             {
 -                                 id << "hw:" << cardId << "," << device;
 -                                 name << cardName << ", " << snd_pcm_info_get_name (pcmInfo);
 -                             }
 -                             else
 -                             {
 -                                 id << "hw:" << cardId << "," << device << "," << (int) subDevice;
 -                                 name << cardName << ", " << snd_pcm_info_get_name (pcmInfo)
 -                                      << " {" <<  snd_pcm_info_get_subdevice_name (pcmInfo) << "}";
 -                             }
 - 
 -                             JUCE_ALSA_LOG ("Soundcard ID: " << id << ", name: '" << name
 -                                             << ", isInput:"  << (int) isInput
 -                                             << ", isOutput:" << (int) isOutput << "\n");
 - 
 -                             if (isInput)
 -                             {
 -                                 inputNames.add (name);
 -                                 inputIds.add (id);
 -                             }
 - 
 -                             if (isOutput)
 -                             {
 -                                 outputNames.add (name);
 -                                 outputIds.add (id);
 -                             }
 -                         }
 -                     }
 -                 }
 - 
 -                 JUCE_CHECKED_RESULT (snd_ctl_close (handle));
 -             }
 -         }
 -     }
 - 
 -     /* Enumerates all ALSA output devices (as output by the command aplay -L)
 -        Does not try to open the devices (with "testDevice" for example),
 -        so that it also finds devices that are busy and not yet available.
 -     */
 -     void enumerateAlsaPCMDevices()
 -     {
 -         void** hints = nullptr;
 - 
 -         if (JUCE_CHECKED_RESULT (snd_device_name_hint (-1, "pcm", &hints)) == 0)
 -         {
 -             for (char** h = (char**) hints; *h; ++h)
 -             {
 -                 const String id (hintToString (*h, "NAME"));
 -                 const String description (hintToString (*h, "DESC"));
 -                 const String ioid (hintToString (*h, "IOID"));
 - 
 -                 JUCE_ALSA_LOG ("ID: " << id << "; desc: " << description << "; ioid: " << ioid);
 - 
 -                 String ss = id.fromFirstOccurrenceOf ("=", false, false)
 -                               .upToFirstOccurrenceOf (",", false, false);
 - 
 -                 if (id.isEmpty()
 -                      || id.startsWith ("default:") || id.startsWith ("sysdefault:")
 -                      || id.startsWith ("plughw:") || id == "null")
 -                     continue;
 - 
 -                 String name (description.replace ("\n", "; "));
 - 
 -                 if (name.isEmpty())
 -                     name = id;
 - 
 -                 bool isOutput = (ioid != "Input");
 -                 bool isInput  = (ioid != "Output");
 - 
 -                 // alsa is stupid here, it advertises dmix and dsnoop as input/output devices, but
 -                 // opening dmix as input, or dsnoop as output will trigger errors..
 -                 isInput  = isInput  && ! id.startsWith ("dmix");
 -                 isOutput = isOutput && ! id.startsWith ("dsnoop");
 - 
 -                 if (isInput)
 -                 {
 -                     inputNames.add (name);
 -                     inputIds.add (id);
 -                 }
 - 
 -                 if (isOutput)
 -                 {
 -                     outputNames.add (name);
 -                     outputIds.add (id);
 -                 }
 -             }
 - 
 -             snd_device_name_free_hint (hints);
 -         }
 - 
 -         // sometimes the "default" device is not listed, but it is nice to see it explicitly in the list
 -         if (! outputIds.contains ("default"))
 -             testDevice ("default", "Default ALSA Output", "Default ALSA Input");
 - 
 -         // same for the pulseaudio plugin
 -         if (! outputIds.contains ("pulse"))
 -             testDevice ("pulse", "Pulseaudio output", "Pulseaudio input");
 - 
 -         // make sure the default device is listed first, and followed by the pulse device (if present)
 -         auto idx = outputIds.indexOf ("pulse");
 -         outputIds.move (idx, 0);
 -         outputNames.move (idx, 0);
 - 
 -         idx = inputIds.indexOf ("pulse");
 -         inputIds.move (idx, 0);
 -         inputNames.move (idx, 0);
 - 
 -         idx = outputIds.indexOf ("default");
 -         outputIds.move (idx, 0);
 -         outputNames.move (idx, 0);
 - 
 -         idx = inputIds.indexOf ("default");
 -         inputIds.move (idx, 0);
 -         inputNames.move (idx, 0);
 -     }
 - 
 -     static String hintToString (const void* hints, const char* type)
 -     {
 -         char* hint = snd_device_name_get_hint (hints, type);
 -         auto s = String::fromUTF8 (hint);
 -         ::free (hint);
 -         return s;
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ALSAAudioIODeviceType)
 - };
 - 
 - }
 - 
 - //==============================================================================
 - static inline AudioIODeviceType* createAudioIODeviceType_ALSA_Soundcards()
 - {
 -     return new ALSAAudioIODeviceType (true, "ALSA HW");
 - }
 - 
 - static inline AudioIODeviceType* createAudioIODeviceType_ALSA_PCMDevices()
 - {
 -     return new ALSAAudioIODeviceType (false, "ALSA");
 - }
 - 
 - } // namespace juce
 
 
  |