| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2013 - Raw Material Software Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found 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.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - } // (juce namespace)
 - 
 - extern "C"
 - {
 -     // Declare just the minimum number of interfaces for the DSound objects that we need..
 -     typedef struct typeDSBUFFERDESC
 -     {
 -         DWORD dwSize;
 -         DWORD dwFlags;
 -         DWORD dwBufferBytes;
 -         DWORD dwReserved;
 -         LPWAVEFORMATEX lpwfxFormat;
 -         GUID guid3DAlgorithm;
 -     } DSBUFFERDESC;
 - 
 -     struct IDirectSoundBuffer;
 - 
 -     #undef INTERFACE
 -     #define INTERFACE IDirectSound
 -     DECLARE_INTERFACE_(IDirectSound, IUnknown)
 -     {
 -         STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID*) PURE;
 -         STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
 -         STDMETHOD_(ULONG,Release)       (THIS) PURE;
 -         STDMETHOD(CreateSoundBuffer)    (THIS_ DSBUFFERDESC*, IDirectSoundBuffer**, LPUNKNOWN) PURE;
 -         STDMETHOD(GetCaps)              (THIS_ void*) PURE;
 -         STDMETHOD(DuplicateSoundBuffer) (THIS_ IDirectSoundBuffer*, IDirectSoundBuffer**) PURE;
 -         STDMETHOD(SetCooperativeLevel)  (THIS_ HWND, DWORD) PURE;
 -         STDMETHOD(Compact)              (THIS) PURE;
 -         STDMETHOD(GetSpeakerConfig)     (THIS_ LPDWORD) PURE;
 -         STDMETHOD(SetSpeakerConfig)     (THIS_ DWORD) PURE;
 -         STDMETHOD(Initialize)           (THIS_ const GUID*) PURE;
 -     };
 - 
 -     #undef INTERFACE
 -     #define INTERFACE IDirectSoundBuffer
 -     DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown)
 -     {
 -         STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID*) PURE;
 -         STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
 -         STDMETHOD_(ULONG,Release)       (THIS) PURE;
 -         STDMETHOD(GetCaps)              (THIS_ void*) PURE;
 -         STDMETHOD(GetCurrentPosition)   (THIS_ LPDWORD, LPDWORD) PURE;
 -         STDMETHOD(GetFormat)            (THIS_ LPWAVEFORMATEX, DWORD, LPDWORD) PURE;
 -         STDMETHOD(GetVolume)            (THIS_ LPLONG) PURE;
 -         STDMETHOD(GetPan)               (THIS_ LPLONG) PURE;
 -         STDMETHOD(GetFrequency)         (THIS_ LPDWORD) PURE;
 -         STDMETHOD(GetStatus)            (THIS_ LPDWORD) PURE;
 -         STDMETHOD(Initialize)           (THIS_ IDirectSound*, DSBUFFERDESC*) PURE;
 -         STDMETHOD(Lock)                 (THIS_ DWORD, DWORD, LPVOID*, LPDWORD, LPVOID*, LPDWORD, DWORD) PURE;
 -         STDMETHOD(Play)                 (THIS_ DWORD, DWORD, DWORD) PURE;
 -         STDMETHOD(SetCurrentPosition)   (THIS_ DWORD) PURE;
 -         STDMETHOD(SetFormat)            (THIS_ const WAVEFORMATEX*) PURE;
 -         STDMETHOD(SetVolume)            (THIS_ LONG) PURE;
 -         STDMETHOD(SetPan)               (THIS_ LONG) PURE;
 -         STDMETHOD(SetFrequency)         (THIS_ DWORD) PURE;
 -         STDMETHOD(Stop)                 (THIS) PURE;
 -         STDMETHOD(Unlock)               (THIS_ LPVOID, DWORD, LPVOID, DWORD) PURE;
 -         STDMETHOD(Restore)              (THIS) PURE;
 -     };
 - 
 -     //==============================================================================
 -     typedef struct typeDSCBUFFERDESC
 -     {
 -         DWORD dwSize;
 -         DWORD dwFlags;
 -         DWORD dwBufferBytes;
 -         DWORD dwReserved;
 -         LPWAVEFORMATEX lpwfxFormat;
 -     } DSCBUFFERDESC;
 - 
 -     struct IDirectSoundCaptureBuffer;
 - 
 -     #undef INTERFACE
 -     #define INTERFACE IDirectSoundCapture
 -     DECLARE_INTERFACE_(IDirectSoundCapture, IUnknown)
 -     {
 -         STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID*) PURE;
 -         STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
 -         STDMETHOD_(ULONG,Release)       (THIS) PURE;
 -         STDMETHOD(CreateCaptureBuffer)  (THIS_ DSCBUFFERDESC*, IDirectSoundCaptureBuffer**, LPUNKNOWN) PURE;
 -         STDMETHOD(GetCaps)              (THIS_ void*) PURE;
 -         STDMETHOD(Initialize)           (THIS_ const GUID*) PURE;
 -     };
 - 
 -     #undef INTERFACE
 -     #define INTERFACE IDirectSoundCaptureBuffer
 -     DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown)
 -     {
 -         STDMETHOD(QueryInterface)       (THIS_ REFIID, LPVOID*) PURE;
 -         STDMETHOD_(ULONG,AddRef)        (THIS) PURE;
 -         STDMETHOD_(ULONG,Release)       (THIS) PURE;
 -         STDMETHOD(GetCaps)              (THIS_ void*) PURE;
 -         STDMETHOD(GetCurrentPosition)   (THIS_ LPDWORD, LPDWORD) PURE;
 -         STDMETHOD(GetFormat)            (THIS_ LPWAVEFORMATEX, DWORD, LPDWORD) PURE;
 -         STDMETHOD(GetStatus)            (THIS_ LPDWORD) PURE;
 -         STDMETHOD(Initialize)           (THIS_ IDirectSoundCapture*, DSCBUFFERDESC*) PURE;
 -         STDMETHOD(Lock)                 (THIS_ DWORD, DWORD, LPVOID*, LPDWORD, LPVOID*, LPDWORD, DWORD) PURE;
 -         STDMETHOD(Start)                (THIS_ DWORD) PURE;
 -         STDMETHOD(Stop)                 (THIS) PURE;
 -         STDMETHOD(Unlock)               (THIS_ LPVOID, DWORD, LPVOID, DWORD) PURE;
 -     };
 - 
 -     #undef INTERFACE
 - }
 - 
 - namespace juce
 - {
 - 
 - //==============================================================================
 - namespace DSoundLogging
 - {
 -     String getErrorMessage (HRESULT hr)
 -     {
 -         const char* result = nullptr;
 - 
 -         switch (hr)
 -         {
 -             case MAKE_HRESULT(1, 0x878, 10):    result = "Device already allocated"; break;
 -             case MAKE_HRESULT(1, 0x878, 30):    result = "Control unavailable"; break;
 -             case E_INVALIDARG:                  result = "Invalid parameter"; break;
 -             case MAKE_HRESULT(1, 0x878, 50):    result = "Invalid call"; break;
 -             case E_FAIL:                        result = "Generic error"; break;
 -             case MAKE_HRESULT(1, 0x878, 70):    result = "Priority level error"; break;
 -             case E_OUTOFMEMORY:                 result = "Out of memory"; break;
 -             case MAKE_HRESULT(1, 0x878, 100):   result = "Bad format"; break;
 -             case E_NOTIMPL:                     result = "Unsupported function"; break;
 -             case MAKE_HRESULT(1, 0x878, 120):   result = "No driver"; break;
 -             case MAKE_HRESULT(1, 0x878, 130):   result = "Already initialised"; break;
 -             case CLASS_E_NOAGGREGATION:         result = "No aggregation"; break;
 -             case MAKE_HRESULT(1, 0x878, 150):   result = "Buffer lost"; break;
 -             case MAKE_HRESULT(1, 0x878, 160):   result = "Another app has priority"; break;
 -             case MAKE_HRESULT(1, 0x878, 170):   result = "Uninitialised"; break;
 -             case E_NOINTERFACE:                 result = "No interface"; break;
 -             case S_OK:                          result = "No error"; break;
 -             default:                            return "Unknown error: " + String ((int) hr);
 -         }
 - 
 -         return result;
 -     }
 - 
 -     //==============================================================================
 -    #if JUCE_DIRECTSOUND_LOGGING
 -     static void logMessage (String message)
 -     {
 -         message = "DSOUND: " + message;
 -         DBG (message);
 -         Logger::writeToLog (message);
 -     }
 - 
 -     static void logError (HRESULT hr, int lineNum)
 -     {
 -         if (FAILED (hr))
 -         {
 -             String error ("Error at line ");
 -             error << lineNum << ": " << getErrorMessage (hr);
 -             logMessage (error);
 -         }
 -     }
 - 
 -     #define CATCH JUCE_CATCH_EXCEPTION
 -     #define JUCE_DS_LOG(a)        DSoundLogging::logMessage(a);
 -     #define JUCE_DS_LOG_ERROR(a)  DSoundLogging::logError(a, __LINE__);
 -    #else
 -     #define CATCH JUCE_CATCH_ALL
 -     #define JUCE_DS_LOG(a)
 -     #define JUCE_DS_LOG_ERROR(a)
 -    #endif
 - }
 - 
 - //==============================================================================
 - namespace
 - {
 -     #define DSOUND_FUNCTION(functionName, params) \
 -         typedef HRESULT (WINAPI *type##functionName) params; \
 -         static type##functionName ds##functionName = nullptr;
 - 
 -     #define DSOUND_FUNCTION_LOAD(functionName) \
 -         ds##functionName = (type##functionName) GetProcAddress (h, #functionName);  \
 -         jassert (ds##functionName != nullptr);
 - 
 -     typedef BOOL (CALLBACK *LPDSENUMCALLBACKW) (LPGUID, LPCWSTR, LPCWSTR, LPVOID);
 -     typedef BOOL (CALLBACK *LPDSENUMCALLBACKA) (LPGUID, LPCSTR, LPCSTR, LPVOID);
 - 
 -     DSOUND_FUNCTION (DirectSoundCreate, (const GUID*, IDirectSound**, LPUNKNOWN))
 -     DSOUND_FUNCTION (DirectSoundCaptureCreate, (const GUID*, IDirectSoundCapture**, LPUNKNOWN))
 -     DSOUND_FUNCTION (DirectSoundEnumerateW, (LPDSENUMCALLBACKW, LPVOID))
 -     DSOUND_FUNCTION (DirectSoundCaptureEnumerateW, (LPDSENUMCALLBACKW, LPVOID))
 - 
 -     void initialiseDSoundFunctions()
 -     {
 -         if (dsDirectSoundCreate == nullptr)
 -         {
 -             HMODULE h = LoadLibraryA ("dsound.dll");
 - 
 -             DSOUND_FUNCTION_LOAD (DirectSoundCreate)
 -             DSOUND_FUNCTION_LOAD (DirectSoundCaptureCreate)
 -             DSOUND_FUNCTION_LOAD (DirectSoundEnumerateW)
 -             DSOUND_FUNCTION_LOAD (DirectSoundCaptureEnumerateW)
 -         }
 -     }
 - 
 -     // the overall size of buffer used is this value x the block size
 -     enum { blocksPerOverallBuffer = 16 };
 - }
 - 
 - //==============================================================================
 - class DSoundInternalOutChannel
 - {
 - public:
 -     DSoundInternalOutChannel (const String& name_, const GUID& guid_, int rate,
 -                               int bufferSize, float* left, float* right)
 -         : bitDepth (16), name (name_), guid (guid_), sampleRate (rate),
 -           bufferSizeSamples (bufferSize), leftBuffer (left), rightBuffer (right),
 -           pDirectSound (nullptr), pOutputBuffer (nullptr)
 -     {
 -     }
 - 
 -     ~DSoundInternalOutChannel()
 -     {
 -         close();
 -     }
 - 
 -     void close()
 -     {
 -         if (pOutputBuffer != nullptr)
 -         {
 -             JUCE_DS_LOG ("closing output: " + name);
 -             HRESULT hr = pOutputBuffer->Stop();
 -             JUCE_DS_LOG_ERROR (hr); (void) hr;
 - 
 -             pOutputBuffer->Release();
 -             pOutputBuffer = nullptr;
 -         }
 - 
 -         if (pDirectSound != nullptr)
 -         {
 -             pDirectSound->Release();
 -             pDirectSound = nullptr;
 -         }
 -     }
 - 
 -     String open()
 -     {
 -         JUCE_DS_LOG ("opening output: " + name + "  rate=" + String (sampleRate)
 -                        + " bits=" + String (bitDepth) + " buf=" + String (bufferSizeSamples));
 - 
 -         pDirectSound = nullptr;
 -         pOutputBuffer = nullptr;
 -         writeOffset = 0;
 - 
 -         String error;
 -         HRESULT hr = E_NOINTERFACE;
 - 
 -         if (dsDirectSoundCreate != nullptr)
 -             hr = dsDirectSoundCreate (&guid, &pDirectSound, nullptr);
 - 
 -         if (SUCCEEDED (hr))
 -         {
 -             bytesPerBuffer = (bufferSizeSamples * (bitDepth >> 2)) & ~15;
 -             totalBytesPerBuffer = (blocksPerOverallBuffer * bytesPerBuffer) & ~15;
 -             const int numChannels = 2;
 - 
 -             hr = pDirectSound->SetCooperativeLevel (GetDesktopWindow(), 2 /* DSSCL_PRIORITY */);
 -             JUCE_DS_LOG_ERROR (hr);
 - 
 -             if (SUCCEEDED (hr))
 -             {
 -                 IDirectSoundBuffer* pPrimaryBuffer;
 - 
 -                 DSBUFFERDESC primaryDesc = { 0 };
 -                 primaryDesc.dwSize = sizeof (DSBUFFERDESC);
 -                 primaryDesc.dwFlags = 1 /* DSBCAPS_PRIMARYBUFFER */;
 -                 primaryDesc.dwBufferBytes = 0;
 -                 primaryDesc.lpwfxFormat = 0;
 - 
 -                 JUCE_DS_LOG ("co-op level set");
 -                 hr = pDirectSound->CreateSoundBuffer (&primaryDesc, &pPrimaryBuffer, 0);
 -                 JUCE_DS_LOG_ERROR (hr);
 - 
 -                 if (SUCCEEDED (hr))
 -                 {
 -                     WAVEFORMATEX wfFormat;
 -                     wfFormat.wFormatTag       = WAVE_FORMAT_PCM;
 -                     wfFormat.nChannels        = (unsigned short) numChannels;
 -                     wfFormat.nSamplesPerSec   = (DWORD) sampleRate;
 -                     wfFormat.wBitsPerSample   = (unsigned short) bitDepth;
 -                     wfFormat.nBlockAlign      = (unsigned short) (wfFormat.nChannels * wfFormat.wBitsPerSample / 8);
 -                     wfFormat.nAvgBytesPerSec  = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
 -                     wfFormat.cbSize = 0;
 - 
 -                     hr = pPrimaryBuffer->SetFormat (&wfFormat);
 -                     JUCE_DS_LOG_ERROR (hr);
 - 
 -                     if (SUCCEEDED (hr))
 -                     {
 -                         DSBUFFERDESC secondaryDesc = { 0 };
 -                         secondaryDesc.dwSize = sizeof (DSBUFFERDESC);
 -                         secondaryDesc.dwFlags =  0x8000 /* DSBCAPS_GLOBALFOCUS */
 -                                                   | 0x10000 /* DSBCAPS_GETCURRENTPOSITION2 */;
 -                         secondaryDesc.dwBufferBytes = (DWORD) totalBytesPerBuffer;
 -                         secondaryDesc.lpwfxFormat = &wfFormat;
 - 
 -                         hr = pDirectSound->CreateSoundBuffer (&secondaryDesc, &pOutputBuffer, 0);
 -                         JUCE_DS_LOG_ERROR (hr);
 - 
 -                         if (SUCCEEDED (hr))
 -                         {
 -                             JUCE_DS_LOG ("buffer created");
 - 
 -                             DWORD dwDataLen;
 -                             unsigned char* pDSBuffData;
 - 
 -                             hr = pOutputBuffer->Lock (0, (DWORD) totalBytesPerBuffer,
 -                                                       (LPVOID*) &pDSBuffData, &dwDataLen, 0, 0, 0);
 -                             JUCE_DS_LOG_ERROR (hr);
 - 
 -                             if (SUCCEEDED (hr))
 -                             {
 -                                 zeromem (pDSBuffData, dwDataLen);
 - 
 -                                 hr = pOutputBuffer->Unlock (pDSBuffData, dwDataLen, 0, 0);
 - 
 -                                 if (SUCCEEDED (hr))
 -                                 {
 -                                     hr = pOutputBuffer->SetCurrentPosition (0);
 - 
 -                                     if (SUCCEEDED (hr))
 -                                     {
 -                                         hr = pOutputBuffer->Play (0, 0, 1 /* DSBPLAY_LOOPING */);
 - 
 -                                         if (SUCCEEDED (hr))
 -                                             return String::empty;
 -                                     }
 -                                 }
 -                             }
 -                         }
 -                     }
 -                 }
 -             }
 -         }
 - 
 -         error = DSoundLogging::getErrorMessage (hr);
 -         close();
 -         return error;
 -     }
 - 
 -     void synchronisePosition()
 -     {
 -         if (pOutputBuffer != nullptr)
 -         {
 -             DWORD playCursor;
 -             pOutputBuffer->GetCurrentPosition (&playCursor, &writeOffset);
 -         }
 -     }
 - 
 -     bool service()
 -     {
 -         if (pOutputBuffer == 0)
 -             return true;
 - 
 -         DWORD playCursor, writeCursor;
 - 
 -         for (;;)
 -         {
 -             HRESULT hr = pOutputBuffer->GetCurrentPosition (&playCursor, &writeCursor);
 - 
 -             if (hr == MAKE_HRESULT (1, 0x878, 150)) // DSERR_BUFFERLOST
 -             {
 -                 pOutputBuffer->Restore();
 -                 continue;
 -             }
 - 
 -             if (SUCCEEDED (hr))
 -                 break;
 - 
 -             JUCE_DS_LOG_ERROR (hr);
 -             jassertfalse;
 -             return true;
 -         }
 - 
 -         int playWriteGap = (int) (writeCursor - playCursor);
 -         if (playWriteGap < 0)
 -             playWriteGap += totalBytesPerBuffer;
 - 
 -         int bytesEmpty = (int) (playCursor - writeOffset);
 -         if (bytesEmpty < 0)
 -             bytesEmpty += totalBytesPerBuffer;
 - 
 -         if (bytesEmpty > (totalBytesPerBuffer - playWriteGap))
 -         {
 -             writeOffset = writeCursor;
 -             bytesEmpty = totalBytesPerBuffer - playWriteGap;
 -         }
 - 
 -         if (bytesEmpty >= bytesPerBuffer)
 -         {
 -             int* buf1 = nullptr;
 -             int* buf2 = nullptr;
 -             DWORD dwSize1 = 0;
 -             DWORD dwSize2 = 0;
 - 
 -             HRESULT hr = pOutputBuffer->Lock (writeOffset, (DWORD) bytesPerBuffer,
 -                                               (void**) &buf1, &dwSize1,
 -                                               (void**) &buf2, &dwSize2, 0);
 - 
 -             if (hr == MAKE_HRESULT (1, 0x878, 150)) // DSERR_BUFFERLOST
 -             {
 -                 pOutputBuffer->Restore();
 - 
 -                 hr = pOutputBuffer->Lock (writeOffset, (DWORD) bytesPerBuffer,
 -                                           (void**) &buf1, &dwSize1,
 -                                           (void**) &buf2, &dwSize2, 0);
 -             }
 - 
 -             if (SUCCEEDED (hr))
 -             {
 -                 if (bitDepth == 16)
 -                 {
 -                     const float* left = leftBuffer;
 -                     const float* right = rightBuffer;
 -                     int samples1 = (int) (dwSize1 >> 2);
 -                     int samples2 = (int) (dwSize2 >> 2);
 - 
 -                     if (left == nullptr)
 -                     {
 -                         for (int* dest = buf1; --samples1 >= 0;)  *dest++ = convertInputValues (0, *right++);
 -                         for (int* dest = buf2; --samples2 >= 0;)  *dest++ = convertInputValues (0, *right++);
 -                     }
 -                     else if (right == nullptr)
 -                     {
 -                         for (int* dest = buf1; --samples1 >= 0;)  *dest++ = convertInputValues (*left++, 0);
 -                         for (int* dest = buf2; --samples2 >= 0;)  *dest++ = convertInputValues (*left++, 0);
 -                     }
 -                     else
 -                     {
 -                         for (int* dest = buf1; --samples1 >= 0;)  *dest++ = convertInputValues (*left++, *right++);
 -                         for (int* dest = buf2; --samples2 >= 0;)  *dest++ = convertInputValues (*left++, *right++);
 -                     }
 -                 }
 -                 else
 -                 {
 -                     jassertfalse;
 -                 }
 - 
 -                 writeOffset = (writeOffset + dwSize1 + dwSize2) % totalBytesPerBuffer;
 - 
 -                 pOutputBuffer->Unlock (buf1, dwSize1, buf2, dwSize2);
 -             }
 -             else
 -             {
 -                 jassertfalse;
 -                 JUCE_DS_LOG_ERROR (hr);
 -             }
 - 
 -             bytesEmpty -= bytesPerBuffer;
 -             return true;
 -         }
 -         else
 -         {
 -             return false;
 -         }
 -     }
 - 
 -     int bitDepth;
 -     bool doneFlag;
 - 
 - private:
 -     String name;
 -     GUID guid;
 -     int sampleRate, bufferSizeSamples;
 -     float* leftBuffer;
 -     float* rightBuffer;
 - 
 -     IDirectSound* pDirectSound;
 -     IDirectSoundBuffer* pOutputBuffer;
 -     DWORD writeOffset;
 -     int totalBytesPerBuffer, bytesPerBuffer;
 -     unsigned int lastPlayCursor;
 - 
 -     static inline int convertInputValues (const float l, const float r) noexcept
 -     {
 -         return jlimit (-32768, 32767, roundToInt (32767.0f * r)) << 16
 -                 | (0xffff & jlimit (-32768, 32767, roundToInt (32767.0f * l)));
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE (DSoundInternalOutChannel)
 - };
 - 
 - //==============================================================================
 - struct DSoundInternalInChannel
 - {
 - public:
 -     DSoundInternalInChannel (const String& name_, const GUID& guid_, int rate,
 -                              int bufferSize, float* left, float* right)
 -         : bitDepth (16), name (name_), guid (guid_), sampleRate (rate),
 -           bufferSizeSamples (bufferSize), leftBuffer (left), rightBuffer (right),
 -           pDirectSound (nullptr), pDirectSoundCapture (nullptr), pInputBuffer (nullptr)
 -     {
 -     }
 - 
 -     ~DSoundInternalInChannel()
 -     {
 -         close();
 -     }
 - 
 -     void close()
 -     {
 -         if (pInputBuffer != nullptr)
 -         {
 -             JUCE_DS_LOG ("closing input: " + name);
 -             HRESULT hr = pInputBuffer->Stop();
 -             JUCE_DS_LOG_ERROR (hr); (void) hr;
 - 
 -             pInputBuffer->Release();
 -             pInputBuffer = nullptr;
 -         }
 - 
 -         if (pDirectSoundCapture != nullptr)
 -         {
 -             pDirectSoundCapture->Release();
 -             pDirectSoundCapture = nullptr;
 -         }
 - 
 -         if (pDirectSound != nullptr)
 -         {
 -             pDirectSound->Release();
 -             pDirectSound = nullptr;
 -         }
 -     }
 - 
 -     String open()
 -     {
 -         JUCE_DS_LOG ("opening input: " + name
 -                        + "  rate=" + String (sampleRate) + " bits=" + String (bitDepth) + " buf=" + String (bufferSizeSamples));
 - 
 -         pDirectSound = nullptr;
 -         pDirectSoundCapture = nullptr;
 -         pInputBuffer = nullptr;
 -         readOffset = 0;
 -         totalBytesPerBuffer = 0;
 - 
 -         HRESULT hr = dsDirectSoundCaptureCreate != nullptr
 -                         ? dsDirectSoundCaptureCreate (&guid, &pDirectSoundCapture, nullptr)
 -                         : E_NOINTERFACE;
 - 
 -         if (SUCCEEDED (hr))
 -         {
 -             const int numChannels = 2;
 -             bytesPerBuffer = (bufferSizeSamples * (bitDepth >> 2)) & ~15;
 -             totalBytesPerBuffer = (blocksPerOverallBuffer * bytesPerBuffer) & ~15;
 - 
 -             WAVEFORMATEX wfFormat;
 -             wfFormat.wFormatTag       = WAVE_FORMAT_PCM;
 -             wfFormat.nChannels        = (unsigned short)numChannels;
 -             wfFormat.nSamplesPerSec   = (DWORD) sampleRate;
 -             wfFormat.wBitsPerSample   = (unsigned short) bitDepth;
 -             wfFormat.nBlockAlign      = (unsigned short) (wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
 -             wfFormat.nAvgBytesPerSec  = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
 -             wfFormat.cbSize = 0;
 - 
 -             DSCBUFFERDESC captureDesc = { 0 };
 -             captureDesc.dwSize = sizeof (DSCBUFFERDESC);
 -             captureDesc.dwFlags = 0;
 -             captureDesc.dwBufferBytes = (DWORD) totalBytesPerBuffer;
 -             captureDesc.lpwfxFormat = &wfFormat;
 - 
 -             JUCE_DS_LOG ("object created");
 -             hr = pDirectSoundCapture->CreateCaptureBuffer (&captureDesc, &pInputBuffer, 0);
 - 
 -             if (SUCCEEDED (hr))
 -             {
 -                 hr = pInputBuffer->Start (1 /* DSCBSTART_LOOPING */);
 - 
 -                 if (SUCCEEDED (hr))
 -                     return String::empty;
 -             }
 -         }
 - 
 -         JUCE_DS_LOG_ERROR (hr);
 -         const String error (DSoundLogging::getErrorMessage (hr));
 -         close();
 - 
 -         return error;
 -     }
 - 
 -     void synchronisePosition()
 -     {
 -         if (pInputBuffer != nullptr)
 -         {
 -             DWORD capturePos;
 -             pInputBuffer->GetCurrentPosition (&capturePos, (DWORD*) &readOffset);
 -         }
 -     }
 - 
 -     bool service()
 -     {
 -         if (pInputBuffer == 0)
 -             return true;
 - 
 -         DWORD capturePos, readPos;
 -         HRESULT hr = pInputBuffer->GetCurrentPosition (&capturePos, &readPos);
 -         JUCE_DS_LOG_ERROR (hr);
 - 
 -         if (FAILED (hr))
 -             return true;
 - 
 -         int bytesFilled = (int) (readPos - readOffset);
 -         if (bytesFilled < 0)
 -             bytesFilled += totalBytesPerBuffer;
 - 
 -         if (bytesFilled >= bytesPerBuffer)
 -         {
 -             short* buf1 = nullptr;
 -             short* buf2 = nullptr;
 -             DWORD dwsize1 = 0;
 -             DWORD dwsize2 = 0;
 - 
 -             HRESULT hr = pInputBuffer->Lock ((DWORD) readOffset, (DWORD) bytesPerBuffer,
 -                                              (void**) &buf1, &dwsize1,
 -                                              (void**) &buf2, &dwsize2, 0);
 - 
 -             if (SUCCEEDED (hr))
 -             {
 -                 if (bitDepth == 16)
 -                 {
 -                     const float g = 1.0f / 32768.0f;
 - 
 -                     float* destL = leftBuffer;
 -                     float* destR = rightBuffer;
 -                     int samples1 = (int) (dwsize1 >> 2);
 -                     int samples2 = (int) (dwsize2 >> 2);
 - 
 -                     if (destL == nullptr)
 -                     {
 -                         for (const short* src = buf1; --samples1 >= 0;) { ++src; *destR++ = *src++ * g; }
 -                         for (const short* src = buf2; --samples2 >= 0;) { ++src; *destR++ = *src++ * g; }
 -                     }
 -                     else if (destR == nullptr)
 -                     {
 -                         for (const short* src = buf1; --samples1 >= 0;) { *destL++ = *src++ * g; ++src; }
 -                         for (const short* src = buf2; --samples2 >= 0;) { *destL++ = *src++ * g; ++src; }
 -                     }
 -                     else
 -                     {
 -                         for (const short* src = buf1; --samples1 >= 0;) { *destL++ = *src++ * g; *destR++ = *src++ * g; }
 -                         for (const short* src = buf2; --samples2 >= 0;) { *destL++ = *src++ * g; *destR++ = *src++ * g; }
 -                     }
 -                 }
 -                 else
 -                 {
 -                     jassertfalse;
 -                 }
 - 
 -                 readOffset = (readOffset + dwsize1 + dwsize2) % totalBytesPerBuffer;
 - 
 -                 pInputBuffer->Unlock (buf1, dwsize1, buf2, dwsize2);
 -             }
 -             else
 -             {
 -                 JUCE_DS_LOG_ERROR (hr);
 -                 jassertfalse;
 -             }
 - 
 -             bytesFilled -= bytesPerBuffer;
 - 
 -             return true;
 -         }
 -         else
 -         {
 -             return false;
 -         }
 -     }
 - 
 -     unsigned int readOffset;
 -     int bytesPerBuffer, totalBytesPerBuffer;
 -     int bitDepth;
 -     bool doneFlag;
 - 
 - private:
 -     String name;
 -     GUID guid;
 -     int sampleRate, bufferSizeSamples;
 -     float* leftBuffer;
 -     float* rightBuffer;
 - 
 -     IDirectSound* pDirectSound;
 -     IDirectSoundCapture* pDirectSoundCapture;
 -     IDirectSoundCaptureBuffer* pInputBuffer;
 - 
 -     JUCE_DECLARE_NON_COPYABLE (DSoundInternalInChannel)
 - };
 - 
 - //==============================================================================
 - class DSoundAudioIODevice  : public AudioIODevice,
 -                              public Thread
 - {
 - public:
 -     DSoundAudioIODevice (const String& deviceName,
 -                          const int outputDeviceIndex_,
 -                          const int inputDeviceIndex_)
 -         : AudioIODevice (deviceName, "DirectSound"),
 -           Thread ("Juce DSound"),
 -           outputDeviceIndex (outputDeviceIndex_),
 -           inputDeviceIndex (inputDeviceIndex_),
 -           isOpen_ (false),
 -           isStarted (false),
 -           bufferSizeSamples (0),
 -           sampleRate (0.0),
 -           inputBuffers (1, 1),
 -           outputBuffers (1, 1),
 -           callback (nullptr)
 -     {
 -         if (outputDeviceIndex_ >= 0)
 -         {
 -             outChannels.add (TRANS("Left"));
 -             outChannels.add (TRANS("Right"));
 -         }
 - 
 -         if (inputDeviceIndex_ >= 0)
 -         {
 -             inChannels.add (TRANS("Left"));
 -             inChannels.add (TRANS("Right"));
 -         }
 -     }
 - 
 -     ~DSoundAudioIODevice()
 -     {
 -         close();
 -     }
 - 
 -     String open (const BigInteger& inputChannels,
 -                  const BigInteger& outputChannels,
 -                  double sampleRate, int bufferSizeSamples)
 -     {
 -         lastError = openDevice (inputChannels, outputChannels, sampleRate, bufferSizeSamples);
 -         isOpen_ = lastError.isEmpty();
 - 
 -         return lastError;
 -     }
 - 
 -     void close()
 -     {
 -         stop();
 - 
 -         if (isOpen_)
 -         {
 -             closeDevice();
 -             isOpen_ = false;
 -         }
 -     }
 - 
 -     bool isOpen()                                       { return isOpen_ && isThreadRunning(); }
 -     int getCurrentBufferSizeSamples()                   { return bufferSizeSamples; }
 -     double getCurrentSampleRate()                       { return sampleRate; }
 -     BigInteger getActiveOutputChannels() const          { return enabledOutputs; }
 -     BigInteger getActiveInputChannels() const           { return enabledInputs; }
 -     int getOutputLatencyInSamples()                     { return (int) (getCurrentBufferSizeSamples() * 1.5); }
 -     int getInputLatencyInSamples()                      { return getOutputLatencyInSamples(); }
 -     StringArray getOutputChannelNames()                 { return outChannels; }
 -     StringArray getInputChannelNames()                  { return inChannels; }
 - 
 -     int getNumSampleRates()                             { return 4; }
 -     int getDefaultBufferSize()                          { return 2560; }
 -     int getNumBufferSizesAvailable()                    { return 50; }
 - 
 -     double getSampleRate (int index)
 -     {
 -         const double samps[] = { 44100.0, 48000.0, 88200.0, 96000.0 };
 -         return samps [jlimit (0, 3, index)];
 -     }
 - 
 -     int getBufferSizeSamples (int index)
 -     {
 -         int n = 64;
 -         for (int i = 0; i < index; ++i)
 -             n += (n < 512) ? 32
 -                            : ((n < 1024) ? 64
 -                                          : ((n < 2048) ? 128 : 256));
 - 
 -         return n;
 -     }
 - 
 -     int getCurrentBitDepth()
 -     {
 -         int bits = 256;
 - 
 -         for (int i = inChans.size(); --i >= 0;)
 -             bits = jmin (bits, inChans[i]->bitDepth);
 - 
 -         for (int i = outChans.size(); --i >= 0;)
 -             bits = jmin (bits, outChans[i]->bitDepth);
 - 
 -         if (bits > 32)
 -             bits = 16;
 - 
 -         return bits;
 -     }
 - 
 -     void start (AudioIODeviceCallback* call)
 -     {
 -         if (isOpen_ && call != nullptr && ! isStarted)
 -         {
 -             if (! isThreadRunning())
 -             {
 -                 // something gone wrong and the thread's stopped..
 -                 isOpen_ = false;
 -                 return;
 -             }
 - 
 -             call->audioDeviceAboutToStart (this);
 - 
 -             const ScopedLock sl (startStopLock);
 -             callback = call;
 -             isStarted = true;
 -         }
 -     }
 - 
 -     void stop()
 -     {
 -         if (isStarted)
 -         {
 -             AudioIODeviceCallback* const callbackLocal = callback;
 - 
 -             {
 -                 const ScopedLock sl (startStopLock);
 -                 isStarted = false;
 -             }
 - 
 -             if (callbackLocal != nullptr)
 -                 callbackLocal->audioDeviceStopped();
 -         }
 -     }
 - 
 -     bool isPlaying()                { return isStarted && isOpen_ && isThreadRunning(); }
 -     String getLastError()           { return lastError; }
 - 
 -     //==============================================================================
 -     StringArray inChannels, outChannels;
 -     int outputDeviceIndex, inputDeviceIndex;
 - 
 - private:
 -     bool isOpen_;
 -     bool isStarted;
 -     String lastError;
 - 
 -     OwnedArray <DSoundInternalInChannel> inChans;
 -     OwnedArray <DSoundInternalOutChannel> outChans;
 -     WaitableEvent startEvent;
 - 
 -     int bufferSizeSamples;
 -     double sampleRate;
 -     BigInteger enabledInputs, enabledOutputs;
 -     AudioSampleBuffer inputBuffers, outputBuffers;
 - 
 -     AudioIODeviceCallback* callback;
 -     CriticalSection startStopLock;
 - 
 -     String openDevice (const BigInteger& inputChannels,
 -                        const BigInteger& outputChannels,
 -                        double sampleRate_, int bufferSizeSamples_);
 - 
 -     void closeDevice()
 -     {
 -         isStarted = false;
 -         stopThread (5000);
 - 
 -         inChans.clear();
 -         outChans.clear();
 -         inputBuffers.setSize (1, 1);
 -         outputBuffers.setSize (1, 1);
 -     }
 - 
 -     void resync()
 -     {
 -         if (! threadShouldExit())
 -         {
 -             sleep (5);
 - 
 -             for (int i = 0; i < outChans.size(); ++i)
 -                 outChans.getUnchecked(i)->synchronisePosition();
 - 
 -             for (int i = 0; i < inChans.size(); ++i)
 -                 inChans.getUnchecked(i)->synchronisePosition();
 -         }
 -     }
 - 
 - public:
 -     void run()
 -     {
 -         while (! threadShouldExit())
 -         {
 -             if (wait (100))
 -                 break;
 -         }
 - 
 -         const int latencyMs = (int) (bufferSizeSamples * 1000.0 / sampleRate);
 -         const int maxTimeMS = jmax (5, 3 * latencyMs);
 - 
 -         while (! threadShouldExit())
 -         {
 -             int numToDo = 0;
 -             uint32 startTime = Time::getMillisecondCounter();
 - 
 -             for (int i = inChans.size(); --i >= 0;)
 -             {
 -                 inChans.getUnchecked(i)->doneFlag = false;
 -                 ++numToDo;
 -             }
 - 
 -             for (int i = outChans.size(); --i >= 0;)
 -             {
 -                 outChans.getUnchecked(i)->doneFlag = false;
 -                 ++numToDo;
 -             }
 - 
 -             if (numToDo > 0)
 -             {
 -                 const int maxCount = 3;
 -                 int count = maxCount;
 - 
 -                 for (;;)
 -                 {
 -                     for (int i = inChans.size(); --i >= 0;)
 -                     {
 -                         DSoundInternalInChannel* const in = inChans.getUnchecked(i);
 - 
 -                         if ((! in->doneFlag) && in->service())
 -                         {
 -                             in->doneFlag = true;
 -                             --numToDo;
 -                         }
 -                     }
 - 
 -                     for (int i = outChans.size(); --i >= 0;)
 -                     {
 -                         DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
 - 
 -                         if ((! out->doneFlag) && out->service())
 -                         {
 -                             out->doneFlag = true;
 -                             --numToDo;
 -                         }
 -                     }
 - 
 -                     if (numToDo <= 0)
 -                         break;
 - 
 -                     if (Time::getMillisecondCounter() > startTime + maxTimeMS)
 -                     {
 -                         resync();
 -                         break;
 -                     }
 - 
 -                     if (--count <= 0)
 -                     {
 -                         Sleep (1);
 -                         count = maxCount;
 -                     }
 - 
 -                     if (threadShouldExit())
 -                         return;
 -                 }
 -             }
 -             else
 -             {
 -                 sleep (1);
 -             }
 - 
 -             const ScopedLock sl (startStopLock);
 - 
 -             if (isStarted)
 -             {
 -                 callback->audioDeviceIOCallback (const_cast <const float**> (inputBuffers.getArrayOfChannels()),
 -                                                  inputBuffers.getNumChannels(),
 -                                                  outputBuffers.getArrayOfChannels(),
 -                                                  outputBuffers.getNumChannels(),
 -                                                  bufferSizeSamples);
 -             }
 -             else
 -             {
 -                 outputBuffers.clear();
 -                 sleep (1);
 -             }
 -         }
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODevice)
 - };
 - 
 - //==============================================================================
 - struct DSoundDeviceList
 - {
 -     StringArray outputDeviceNames, inputDeviceNames;
 -     Array<GUID> outputGuids, inputGuids;
 - 
 -     void scan()
 -     {
 -         outputDeviceNames.clear();
 -         inputDeviceNames.clear();
 -         outputGuids.clear();
 -         inputGuids.clear();
 - 
 -         if (dsDirectSoundEnumerateW != 0)
 -         {
 -             dsDirectSoundEnumerateW (outputEnumProcW, this);
 -             dsDirectSoundCaptureEnumerateW (inputEnumProcW, this);
 -         }
 -     }
 - 
 -     bool operator!= (const DSoundDeviceList& other) const noexcept
 -     {
 -         return outputDeviceNames != other.outputDeviceNames
 -             || inputDeviceNames != other.inputDeviceNames
 -             || outputGuids != other.outputGuids
 -             || inputGuids != other.inputGuids;
 -     }
 - 
 - private:
 -     static BOOL enumProc (LPGUID lpGUID, String desc, StringArray& names, Array<GUID>& guids)
 -     {
 -         desc = desc.trim();
 - 
 -         if (desc.isNotEmpty())
 -         {
 -             const String origDesc (desc);
 - 
 -             int n = 2;
 -             while (names.contains (desc))
 -                 desc = origDesc + " (" + String (n++) + ")";
 - 
 -             names.add (desc);
 -             guids.add (lpGUID != nullptr ? *lpGUID : GUID());
 -         }
 - 
 -         return TRUE;
 -     }
 - 
 -     BOOL outputEnumProc (LPGUID guid, LPCWSTR desc)  { return enumProc (guid, desc, outputDeviceNames, outputGuids); }
 -     BOOL inputEnumProc  (LPGUID guid, LPCWSTR desc)  { return enumProc (guid, desc, inputDeviceNames,  inputGuids); }
 - 
 -     static BOOL CALLBACK outputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object)
 -     {
 -         return static_cast<DSoundDeviceList*> (object)->outputEnumProc (lpGUID, description);
 -     }
 - 
 -     static BOOL CALLBACK inputEnumProcW (LPGUID lpGUID, LPCWSTR description, LPCWSTR, LPVOID object)
 -     {
 -         return static_cast<DSoundDeviceList*> (object)->inputEnumProc (lpGUID, description);
 -     }
 - };
 - 
 - //==============================================================================
 - String DSoundAudioIODevice::openDevice (const BigInteger& inputChannels,
 -                                         const BigInteger& outputChannels,
 -                                         double sampleRate_, int bufferSizeSamples_)
 - {
 -     closeDevice();
 - 
 -     sampleRate = sampleRate_;
 - 
 -     if (bufferSizeSamples_ <= 0)
 -         bufferSizeSamples_ = 960; // use as a default size if none is set.
 - 
 -     bufferSizeSamples = bufferSizeSamples_ & ~7;
 - 
 -     DSoundDeviceList dlh;
 -     dlh.scan();
 - 
 -     enabledInputs = inputChannels;
 -     enabledInputs.setRange (inChannels.size(),
 -                             enabledInputs.getHighestBit() + 1 - inChannels.size(),
 -                             false);
 - 
 -     inputBuffers.setSize (jmax (1, enabledInputs.countNumberOfSetBits()), bufferSizeSamples);
 -     inputBuffers.clear();
 -     int numIns = 0;
 - 
 -     for (int i = 0; i <= enabledInputs.getHighestBit(); i += 2)
 -     {
 -         float* left = nullptr;
 -         if (enabledInputs[i])
 -             left = inputBuffers.getSampleData (numIns++);
 - 
 -         float* right = nullptr;
 -         if (enabledInputs[i + 1])
 -             right = inputBuffers.getSampleData (numIns++);
 - 
 -         if (left != nullptr || right != nullptr)
 -             inChans.add (new DSoundInternalInChannel (dlh.inputDeviceNames [inputDeviceIndex],
 -                                                       dlh.inputGuids [inputDeviceIndex],
 -                                                       (int) sampleRate, bufferSizeSamples,
 -                                                       left, right));
 -     }
 - 
 -     enabledOutputs = outputChannels;
 -     enabledOutputs.setRange (outChannels.size(),
 -                              enabledOutputs.getHighestBit() + 1 - outChannels.size(),
 -                              false);
 - 
 -     outputBuffers.setSize (jmax (1, enabledOutputs.countNumberOfSetBits()), bufferSizeSamples);
 -     outputBuffers.clear();
 -     int numOuts = 0;
 - 
 -     for (int i = 0; i <= enabledOutputs.getHighestBit(); i += 2)
 -     {
 -         float* left = nullptr;
 -         if (enabledOutputs[i])
 -             left = outputBuffers.getSampleData (numOuts++);
 - 
 -         float* right = nullptr;
 -         if (enabledOutputs[i + 1])
 -             right = outputBuffers.getSampleData (numOuts++);
 - 
 -         if (left != nullptr || right != nullptr)
 -             outChans.add (new DSoundInternalOutChannel (dlh.outputDeviceNames[outputDeviceIndex],
 -                                                         dlh.outputGuids [outputDeviceIndex],
 -                                                         (int) sampleRate, bufferSizeSamples,
 -                                                         left, right));
 -     }
 - 
 -     String error;
 - 
 -     // boost our priority while opening the devices to try to get better sync between them
 -     const int oldThreadPri = GetThreadPriority (GetCurrentThread());
 -     const DWORD oldProcPri = GetPriorityClass (GetCurrentProcess());
 -     SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
 -     SetPriorityClass (GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
 - 
 -     for (int i = 0; i < outChans.size(); ++i)
 -     {
 -         error = outChans[i]->open();
 - 
 -         if (error.isNotEmpty())
 -         {
 -             error = "Error opening " + dlh.outputDeviceNames[i] + ": \"" + error + "\"";
 -             break;
 -         }
 -     }
 - 
 -     if (error.isEmpty())
 -     {
 -         for (int i = 0; i < inChans.size(); ++i)
 -         {
 -             error = inChans[i]->open();
 - 
 -             if (error.isNotEmpty())
 -             {
 -                 error = "Error opening " + dlh.inputDeviceNames[i] + ": \"" + error + "\"";
 -                 break;
 -             }
 -         }
 -     }
 - 
 -     if (error.isEmpty())
 -     {
 -         for (int i = 0; i < outChans.size(); ++i)
 -             outChans.getUnchecked(i)->synchronisePosition();
 - 
 -         for (int i = 0; i < inChans.size(); ++i)
 -             inChans.getUnchecked(i)->synchronisePosition();
 - 
 -         startThread (9);
 -         sleep (10);
 - 
 -         notify();
 -     }
 -     else
 -     {
 -         JUCE_DS_LOG ("Opening failed: " + error);
 -     }
 - 
 -     SetThreadPriority (GetCurrentThread(), oldThreadPri);
 -     SetPriorityClass (GetCurrentProcess(), oldProcPri);
 - 
 -     return error;
 - }
 - 
 - //==============================================================================
 - class DSoundAudioIODeviceType  : public AudioIODeviceType,
 -                                  private DeviceChangeDetector
 - {
 - public:
 -     DSoundAudioIODeviceType()
 -         : AudioIODeviceType ("DirectSound"),
 -           DeviceChangeDetector (L"DirectSound"),
 -           hasScanned (false)
 -     {
 -         initialiseDSoundFunctions();
 -     }
 - 
 -     void scanForDevices()
 -     {
 -         hasScanned = true;
 -         deviceList.scan();
 -     }
 - 
 -     StringArray getDeviceNames (bool wantInputNames) const
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 - 
 -         return wantInputNames ? deviceList.inputDeviceNames
 -                               : deviceList.outputDeviceNames;
 -     }
 - 
 -     int getDefaultDeviceIndex (bool /*forInput*/) const
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 -         return 0;
 -     }
 - 
 -     int getIndexOfDevice (AudioIODevice* device, bool asInput) const
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 - 
 -         if (DSoundAudioIODevice* const d = dynamic_cast <DSoundAudioIODevice*> (device))
 -             return asInput ? d->inputDeviceIndex
 -                            : d->outputDeviceIndex;
 - 
 -         return -1;
 -     }
 - 
 -     bool hasSeparateInputsAndOutputs() const    { return true; }
 - 
 -     AudioIODevice* createDevice (const String& outputDeviceName,
 -                                  const String& inputDeviceName)
 -     {
 -         jassert (hasScanned); // need to call scanForDevices() before doing this
 - 
 -         const int outputIndex = deviceList.outputDeviceNames.indexOf (outputDeviceName);
 -         const int inputIndex = deviceList.inputDeviceNames.indexOf (inputDeviceName);
 - 
 -         if (outputIndex >= 0 || inputIndex >= 0)
 -             return new DSoundAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
 -                                                                           : inputDeviceName,
 -                                             outputIndex, inputIndex);
 - 
 -         return nullptr;
 -     }
 - 
 - private:
 -     DSoundDeviceList deviceList;
 -     bool hasScanned;
 - 
 -     void systemDeviceChanged()
 -     {
 -         DSoundDeviceList newList;
 -         newList.scan();
 - 
 -         if (newList != deviceList)
 -         {
 -             deviceList = newList;
 -             callDeviceChangeListeners();
 -         }
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSoundAudioIODeviceType)
 - };
 - 
 - //==============================================================================
 - AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_DirectSound()
 - {
 -     return new DSoundAudioIODeviceType();
 - }
 
 
  |