gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

pa_asio.cpp (162638B)


      1 /*
      2  * $Id$
      3  * Portable Audio I/O Library for ASIO Drivers
      4  *
      5  * Author: Stephane Letz
      6  * Based on the Open Source API proposed by Ross Bencina
      7  * Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina
      8  * Blocking i/o implementation by Sven Fischer, Institute of Hearing
      9  * Technology and Audiology (www.hoertechnik-audiologie.de)
     10  *
     11  * Permission is hereby granted, free of charge, to any person obtaining
     12  * a copy of this software and associated documentation files
     13  * (the "Software"), to deal in the Software without restriction,
     14  * including without limitation the rights to use, copy, modify, merge,
     15  * publish, distribute, sublicense, and/or sell copies of the Software,
     16  * and to permit persons to whom the Software is furnished to do so,
     17  * subject to the following conditions:
     18  *
     19  * The above copyright notice and this permission notice shall be
     20  * included in all copies or substantial portions of the Software.
     21  *
     22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     25  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
     26  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     27  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     28  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     29  */
     30 
     31 /*
     32  * The text above constitutes the entire PortAudio license; however, 
     33  * the PortAudio community also makes the following non-binding requests:
     34  *
     35  * Any person wishing to distribute modifications to the Software is
     36  * requested to send the modifications to the original developer so that
     37  * they can be incorporated into the canonical version. It is also 
     38  * requested that these non-binding requests be included along with the 
     39  * license above.
     40  */
     41 
     42 /* Modification History
     43 
     44         08-03-01 First version : Stephane Letz
     45         08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk
     46         08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz
     47         08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz
     48         08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil
     49         08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when
     50                  the stream is stopped : Stephane Letz
     51         08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when
     52                  the stream is stopped : Stephane Letz
     53         10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that
     54                  respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz
     55         10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz
     56         10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil
     57         10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk
     58         10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz
     59         11-06-01 Rename functions : Stephane Letz
     60         11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz
     61         11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk
     62         01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly :  Stephane Letz
     63         02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz
     64         19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz
     65         09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz
     66         12-04-02 Add Mac includes for <Devices.h> and <Timer.h> : Phil Burk
     67         13-04-02 Removes another compiler warning : Stephane Letz
     68         30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz
     69         12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina
     70         18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B.
     71         21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina
     72         ** NOTE  maintanance history is now stored in CVS **
     73 */
     74 
     75 /** @file
     76     @ingroup hostapi_src
     77 
     78     Note that specific support for paInputUnderflow, paOutputOverflow and
     79     paNeverDropInput is not necessary or possible with this driver due to the
     80     synchronous full duplex double-buffered architecture of ASIO.
     81 */
     82 
     83 
     84 #include <stdio.h>
     85 #include <assert.h>
     86 #include <string.h>
     87 //#include <values.h>
     88 #include <new>
     89 
     90 #include <windows.h>
     91 #include <mmsystem.h>
     92 
     93 #include "portaudio.h"
     94 #include "pa_asio.h"
     95 #include "pa_util.h"
     96 #include "pa_allocation.h"
     97 #include "pa_hostapi.h"
     98 #include "pa_stream.h"
     99 #include "pa_cpuload.h"
    100 #include "pa_process.h"
    101 #include "pa_debugprint.h"
    102 #include "pa_ringbuffer.h"
    103 
    104 #include "pa_win_coinitialize.h"
    105 
    106 /* This version of pa_asio.cpp is currently only targetted at Win32,
    107    It would require a few tweaks to work with pre-OS X Macintosh.
    108    To make configuration easier, we define WIN32 here to make sure
    109    that the ASIO SDK knows this is Win32.
    110 */
    111 #ifndef WIN32
    112 #define WIN32
    113 #endif
    114 
    115 #include "asiosys.h"
    116 #include "asio.h"
    117 #include "asiodrivers.h"
    118 #include "iasiothiscallresolver.h"
    119 
    120 /*
    121 #if MAC
    122 #include <Devices.h>
    123 #include <Timer.h>
    124 #include <Math64.h>
    125 #else
    126 */
    127 /*
    128 #include <math.h>
    129 #include <windows.h>
    130 #include <mmsystem.h>
    131 */
    132 /*
    133 #endif
    134 */
    135 
    136 
    137 /* winmm.lib is needed for timeGetTime() (this is in winmm.a if you're using gcc) */
    138 #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
    139 #pragma comment(lib, "winmm.lib")
    140 #endif
    141 
    142 
    143 /* external reference to ASIO SDK's asioDrivers.
    144 
    145  This is a bit messy because we want to explicitly manage 
    146  allocation/deallocation of this structure, but some layers of the SDK 
    147  which we currently use (eg the implementation in asio.cpp) still
    148  use this global version.
    149 
    150  For now we keep it in sync with our local instance in the host
    151  API representation structure, but later we should be able to remove
    152  all dependence on it.
    153 */
    154 extern AsioDrivers* asioDrivers;
    155 
    156 
    157 /* We are trying to be compatible with CARBON but this has not been thoroughly tested. */
    158 /* not tested at all since new V19 code was introduced. */
    159 #define CARBON_COMPATIBLE  (0)
    160 
    161 
    162 /* prototypes for functions declared in this file */
    163 
    164 extern "C" PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
    165 static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
    166 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
    167                            PaStream** s,
    168                            const PaStreamParameters *inputParameters,
    169                            const PaStreamParameters *outputParameters,
    170                            double sampleRate,
    171                            unsigned long framesPerBuffer,
    172                            PaStreamFlags streamFlags,
    173                            PaStreamCallback *streamCallback,
    174                            void *userData );
    175 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
    176                                   const PaStreamParameters *inputParameters,
    177                                   const PaStreamParameters *outputParameters,
    178                                   double sampleRate );
    179 static PaError CloseStream( PaStream* stream );
    180 static PaError StartStream( PaStream *stream );
    181 static PaError StopStream( PaStream *stream );
    182 static PaError AbortStream( PaStream *stream );
    183 static PaError IsStreamStopped( PaStream *s );
    184 static PaError IsStreamActive( PaStream *stream );
    185 static PaTime GetStreamTime( PaStream *stream );
    186 static double GetStreamCpuLoad( PaStream* stream );
    187 static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
    188 static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
    189 static signed long GetStreamReadAvailable( PaStream* stream );
    190 static signed long GetStreamWriteAvailable( PaStream* stream );
    191 
    192 /* Blocking i/o callback function. */
    193 static int BlockingIoPaCallback(const void                     *inputBuffer    ,
    194                                       void                     *outputBuffer   ,
    195                                       unsigned long             framesPerBuffer,
    196                                 const PaStreamCallbackTimeInfo *timeInfo       ,
    197                                       PaStreamCallbackFlags     statusFlags    ,
    198                                       void                     *userData       );
    199 
    200 /* our ASIO callback functions */
    201 
    202 static void bufferSwitch(long index, ASIOBool processNow);
    203 static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
    204 static void sampleRateChanged(ASIOSampleRate sRate);
    205 static long asioMessages(long selector, long value, void* message, double* opt);
    206 
    207 static ASIOCallbacks asioCallbacks_ =
    208     { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo };
    209 
    210 
    211 #define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \
    212     PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText )
    213 
    214 
    215 static void PaAsio_SetLastSystemError( DWORD errorCode )
    216 {
    217     LPVOID lpMsgBuf;
    218     FormatMessage(
    219         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    220         NULL,
    221         errorCode,
    222         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    223         (LPTSTR) &lpMsgBuf,
    224         0,
    225         NULL
    226     );
    227     PaUtil_SetLastHostErrorInfo( paASIO, errorCode, (const char*)lpMsgBuf );
    228     LocalFree( lpMsgBuf );
    229 }
    230 
    231 #define PA_ASIO_SET_LAST_SYSTEM_ERROR( errorCode ) \
    232     PaAsio_SetLastSystemError( errorCode )
    233 
    234 
    235 static const char* PaAsio_GetAsioErrorText( ASIOError asioError )
    236 {
    237     const char *result;
    238 
    239     switch( asioError ){
    240         case ASE_OK:
    241         case ASE_SUCCESS:           result = "Success"; break;
    242         case ASE_NotPresent:        result = "Hardware input or output is not present or available"; break;
    243         case ASE_HWMalfunction:     result = "Hardware is malfunctioning"; break;
    244         case ASE_InvalidParameter:  result = "Input parameter invalid"; break;
    245         case ASE_InvalidMode:       result = "Hardware is in a bad mode or used in a bad mode"; break;
    246         case ASE_SPNotAdvancing:    result = "Hardware is not running when sample position is inquired"; break;
    247         case ASE_NoClock:           result = "Sample clock or rate cannot be determined or is not present"; break;
    248         case ASE_NoMemory:          result = "Not enough memory for completing the request"; break;
    249         default:                    result = "Unknown ASIO error"; break;
    250     }
    251 
    252     return result;
    253 }
    254 
    255 
    256 #define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \
    257     PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) )
    258 
    259 
    260 
    261 
    262 // Atomic increment and decrement operations
    263 #if MAC
    264     /* need to be implemented on Mac */
    265     inline long PaAsio_AtomicIncrement(volatile long* v) {return ++(*const_cast<long*>(v));}
    266     inline long PaAsio_AtomicDecrement(volatile long* v) {return --(*const_cast<long*>(v));}
    267 #elif WINDOWS
    268     inline long PaAsio_AtomicIncrement(volatile long* v) {return InterlockedIncrement(const_cast<long*>(v));}
    269     inline long PaAsio_AtomicDecrement(volatile long* v) {return InterlockedDecrement(const_cast<long*>(v));}
    270 #endif
    271 
    272 
    273 
    274 typedef struct PaAsioDriverInfo
    275 {
    276     ASIODriverInfo asioDriverInfo;
    277     long inputChannelCount, outputChannelCount;
    278     long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity;
    279     bool postOutput;
    280 }
    281 PaAsioDriverInfo;
    282 
    283 
    284 /* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */
    285 
    286 typedef struct
    287 {
    288     PaUtilHostApiRepresentation inheritedHostApiRep;
    289     PaUtilStreamInterface callbackStreamInterface;
    290     PaUtilStreamInterface blockingStreamInterface;
    291 
    292     PaUtilAllocationGroup *allocations;
    293 
    294     PaWinUtilComInitializationResult comInitializationResult;
    295 
    296     AsioDrivers *asioDrivers;
    297     void *systemSpecific;
    298     
    299     /* the ASIO C API only allows one ASIO driver to be open at a time,
    300         so we keep track of whether we have the driver open here, and
    301         use this information to return errors from OpenStream if the
    302         driver is already open.
    303 
    304         openAsioDeviceIndex will be PaNoDevice if there is no device open
    305         and a valid pa_asio (not global) device index otherwise.
    306 
    307         openAsioDriverInfo is populated with the driver info for the
    308         currently open device (if any)
    309     */
    310     PaDeviceIndex openAsioDeviceIndex;
    311     PaAsioDriverInfo openAsioDriverInfo;
    312 }
    313 PaAsioHostApiRepresentation;
    314 
    315 
    316 /*
    317     Retrieve <driverCount> driver names from ASIO, returned in a char**
    318     allocated in <group>.
    319 */
    320 static char **GetAsioDriverNames( PaAsioHostApiRepresentation *asioHostApi, PaUtilAllocationGroup *group, long driverCount )
    321 {
    322     char **result = 0;
    323     int i;
    324 
    325     result =(char**)PaUtil_GroupAllocateMemory(
    326             group, sizeof(char*) * driverCount );
    327     if( !result )
    328         goto error;
    329 
    330     result[0] = (char*)PaUtil_GroupAllocateMemory(
    331             group, 32 * driverCount );
    332     if( !result[0] )
    333         goto error;
    334 
    335     for( i=0; i<driverCount; ++i )
    336         result[i] = result[0] + (32 * i);
    337 
    338     asioHostApi->asioDrivers->getDriverNames( result, driverCount );
    339 
    340 error:
    341     return result;
    342 }
    343 
    344 
    345 static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type)
    346 {
    347     switch (type) {
    348         case ASIOSTInt16MSB:
    349         case ASIOSTInt16LSB:
    350                 return paInt16;
    351 
    352         case ASIOSTFloat32MSB:
    353         case ASIOSTFloat32LSB:
    354         case ASIOSTFloat64MSB:
    355         case ASIOSTFloat64LSB:
    356                 return paFloat32;
    357 
    358         case ASIOSTInt32MSB:
    359         case ASIOSTInt32LSB:
    360         case ASIOSTInt32MSB16:
    361         case ASIOSTInt32LSB16:
    362         case ASIOSTInt32MSB18:
    363         case ASIOSTInt32MSB20:
    364         case ASIOSTInt32MSB24:
    365         case ASIOSTInt32LSB18:
    366         case ASIOSTInt32LSB20:
    367         case ASIOSTInt32LSB24:
    368                 return paInt32;
    369 
    370         case ASIOSTInt24MSB:
    371         case ASIOSTInt24LSB:
    372                 return paInt24;
    373 
    374         default:
    375                 return paCustomFormat;
    376     }
    377 }
    378 
    379 void AsioSampleTypeLOG(ASIOSampleType type)
    380 {
    381     switch (type) {
    382         case ASIOSTInt16MSB:  PA_DEBUG(("ASIOSTInt16MSB\n"));  break;
    383         case ASIOSTInt16LSB:  PA_DEBUG(("ASIOSTInt16LSB\n"));  break;
    384         case ASIOSTFloat32MSB:PA_DEBUG(("ASIOSTFloat32MSB\n"));break;
    385         case ASIOSTFloat32LSB:PA_DEBUG(("ASIOSTFloat32LSB\n"));break;
    386         case ASIOSTFloat64MSB:PA_DEBUG(("ASIOSTFloat64MSB\n"));break;
    387         case ASIOSTFloat64LSB:PA_DEBUG(("ASIOSTFloat64LSB\n"));break;
    388         case ASIOSTInt32MSB:  PA_DEBUG(("ASIOSTInt32MSB\n"));  break;
    389         case ASIOSTInt32LSB:  PA_DEBUG(("ASIOSTInt32LSB\n"));  break;
    390         case ASIOSTInt32MSB16:PA_DEBUG(("ASIOSTInt32MSB16\n"));break;
    391         case ASIOSTInt32LSB16:PA_DEBUG(("ASIOSTInt32LSB16\n"));break;
    392         case ASIOSTInt32MSB18:PA_DEBUG(("ASIOSTInt32MSB18\n"));break;
    393         case ASIOSTInt32MSB20:PA_DEBUG(("ASIOSTInt32MSB20\n"));break;
    394         case ASIOSTInt32MSB24:PA_DEBUG(("ASIOSTInt32MSB24\n"));break;
    395         case ASIOSTInt32LSB18:PA_DEBUG(("ASIOSTInt32LSB18\n"));break;
    396         case ASIOSTInt32LSB20:PA_DEBUG(("ASIOSTInt32LSB20\n"));break;
    397         case ASIOSTInt32LSB24:PA_DEBUG(("ASIOSTInt32LSB24\n"));break;
    398         case ASIOSTInt24MSB:  PA_DEBUG(("ASIOSTInt24MSB\n"));  break;
    399         case ASIOSTInt24LSB:  PA_DEBUG(("ASIOSTInt24LSB\n"));  break;
    400         default:              PA_DEBUG(("Custom Format%d\n",type));break;
    401 
    402     }
    403 }
    404 
    405 static int BytesPerAsioSample( ASIOSampleType sampleType )
    406 {
    407     switch (sampleType) {
    408         case ASIOSTInt16MSB:
    409         case ASIOSTInt16LSB:
    410             return 2;
    411 
    412         case ASIOSTFloat64MSB:
    413         case ASIOSTFloat64LSB:
    414             return 8;
    415 
    416         case ASIOSTFloat32MSB:
    417         case ASIOSTFloat32LSB:
    418         case ASIOSTInt32MSB:
    419         case ASIOSTInt32LSB:
    420         case ASIOSTInt32MSB16:
    421         case ASIOSTInt32LSB16:
    422         case ASIOSTInt32MSB18:
    423         case ASIOSTInt32MSB20:
    424         case ASIOSTInt32MSB24:
    425         case ASIOSTInt32LSB18:
    426         case ASIOSTInt32LSB20:
    427         case ASIOSTInt32LSB24:
    428             return 4;
    429 
    430         case ASIOSTInt24MSB:
    431         case ASIOSTInt24LSB:
    432             return 3;
    433 
    434         default:
    435             return 0;
    436     }
    437 }
    438 
    439 
    440 static void Swap16( void *buffer, long shift, long count )
    441 {
    442     unsigned short *p = (unsigned short*)buffer;
    443     unsigned short temp;
    444     (void) shift; /* unused parameter */
    445 
    446     while( count-- )
    447     {
    448         temp = *p;
    449         *p++ = (unsigned short)((temp<<8) | (temp>>8));
    450     }
    451 }
    452 
    453 static void Swap24( void *buffer, long shift, long count )
    454 {
    455     unsigned char *p = (unsigned char*)buffer;
    456     unsigned char temp;
    457     (void) shift; /* unused parameter */
    458 
    459     while( count-- )
    460     {
    461         temp = *p;
    462         *p = *(p+2);
    463         *(p+2) = temp;
    464         p += 3;
    465     }
    466 }
    467 
    468 #define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24));
    469 
    470 static void Swap32( void *buffer, long shift, long count )
    471 {
    472     unsigned long *p = (unsigned long*)buffer;
    473     unsigned long temp;
    474     (void) shift; /* unused parameter */
    475 
    476     while( count-- )
    477     {
    478         temp = *p;
    479         *p++ = PA_SWAP32_( temp);
    480     }
    481 }
    482 
    483 static void SwapShiftLeft32( void *buffer, long shift, long count )
    484 {
    485     unsigned long *p = (unsigned long*)buffer;
    486     unsigned long temp;
    487 
    488     while( count-- )
    489     {
    490         temp = *p;
    491         temp = PA_SWAP32_( temp);
    492         *p++ = temp << shift;
    493     }
    494 }
    495 
    496 static void ShiftRightSwap32( void *buffer, long shift, long count )
    497 {
    498     unsigned long *p = (unsigned long*)buffer;
    499     unsigned long temp;
    500 
    501     while( count-- )
    502     {
    503         temp = *p >> shift;
    504         *p++ = PA_SWAP32_( temp);
    505     }
    506 }
    507 
    508 static void ShiftLeft32( void *buffer, long shift, long count )
    509 {
    510     unsigned long *p = (unsigned long*)buffer;
    511     unsigned long temp;
    512 
    513     while( count-- )
    514     {
    515         temp = *p;
    516         *p++ = temp << shift;
    517     }
    518 }
    519 
    520 static void ShiftRight32( void *buffer, long shift, long count )
    521 {
    522     unsigned long *p = (unsigned long*)buffer;
    523     unsigned long temp;
    524 
    525     while( count-- )
    526     {
    527         temp = *p;
    528         *p++ = temp >> shift;
    529     }
    530 }
    531 
    532 #define PA_SWAP_( x, y ) temp=x; x = y; y = temp;
    533 
    534 static void Swap64ConvertFloat64ToFloat32( void *buffer, long shift, long count )
    535 {
    536     double *in = (double*)buffer;
    537     float *out = (float*)buffer;
    538     unsigned char *p;
    539     unsigned char temp;
    540     (void) shift; /* unused parameter */
    541 
    542     while( count-- )
    543     {
    544         p = (unsigned char*)in;
    545         PA_SWAP_( p[0], p[7] );
    546         PA_SWAP_( p[1], p[6] );
    547         PA_SWAP_( p[2], p[5] );
    548         PA_SWAP_( p[3], p[4] );
    549 
    550         *out++ = (float) (*in++);
    551     }
    552 }
    553 
    554 static void ConvertFloat64ToFloat32( void *buffer, long shift, long count )
    555 {
    556     double *in = (double*)buffer;
    557     float *out = (float*)buffer;
    558     (void) shift; /* unused parameter */
    559 
    560     while( count-- )
    561         *out++ = (float) (*in++);
    562 }
    563 
    564 static void ConvertFloat32ToFloat64Swap64( void *buffer, long shift, long count )
    565 {
    566     float *in = ((float*)buffer) + (count-1);
    567     double *out = ((double*)buffer) + (count-1);
    568     unsigned char *p;
    569     unsigned char temp;
    570     (void) shift; /* unused parameter */
    571 
    572     while( count-- )
    573     {
    574         *out = *in--;
    575 
    576         p = (unsigned char*)out;
    577         PA_SWAP_( p[0], p[7] );
    578         PA_SWAP_( p[1], p[6] );
    579         PA_SWAP_( p[2], p[5] );
    580         PA_SWAP_( p[3], p[4] );
    581 
    582         out--;
    583     }
    584 }
    585 
    586 static void ConvertFloat32ToFloat64( void *buffer, long shift, long count )
    587 {
    588     float *in = ((float*)buffer) + (count-1);
    589     double *out = ((double*)buffer) + (count-1);
    590     (void) shift; /* unused parameter */
    591 
    592     while( count-- )
    593         *out-- = *in--;
    594 }
    595 
    596 #ifdef MAC
    597 #define PA_MSB_IS_NATIVE_
    598 #undef PA_LSB_IS_NATIVE_
    599 #endif
    600 
    601 #ifdef WINDOWS
    602 #undef PA_MSB_IS_NATIVE_
    603 #define PA_LSB_IS_NATIVE_
    604 #endif
    605 
    606 typedef void PaAsioBufferConverter( void *, long, long );
    607 
    608 static void SelectAsioToPaConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
    609 {
    610     *shift = 0;
    611     *converter = 0;
    612 
    613     switch (type) {
    614         case ASIOSTInt16MSB:
    615             /* dest: paInt16, no conversion necessary, possible byte swap*/
    616             #ifdef PA_LSB_IS_NATIVE_
    617                 *converter = Swap16;
    618             #endif
    619             break;
    620         case ASIOSTInt16LSB:
    621             /* dest: paInt16, no conversion necessary, possible byte swap*/
    622             #ifdef PA_MSB_IS_NATIVE_
    623                 *converter = Swap16;
    624             #endif
    625             break;
    626         case ASIOSTFloat32MSB:
    627             /* dest: paFloat32, no conversion necessary, possible byte swap*/
    628             #ifdef PA_LSB_IS_NATIVE_
    629                 *converter = Swap32;
    630             #endif
    631             break;
    632         case ASIOSTFloat32LSB:
    633             /* dest: paFloat32, no conversion necessary, possible byte swap*/
    634             #ifdef PA_MSB_IS_NATIVE_
    635                 *converter = Swap32;
    636             #endif
    637             break;
    638         case ASIOSTFloat64MSB:
    639             /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
    640             #ifdef PA_LSB_IS_NATIVE_
    641                 *converter = Swap64ConvertFloat64ToFloat32;
    642             #else
    643                 *converter = ConvertFloat64ToFloat32;
    644             #endif
    645             break;
    646         case ASIOSTFloat64LSB:
    647             /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
    648             #ifdef PA_MSB_IS_NATIVE_
    649                 *converter = Swap64ConvertFloat64ToFloat32;
    650             #else
    651                 *converter = ConvertFloat64ToFloat32;
    652             #endif
    653             break;
    654         case ASIOSTInt32MSB:
    655             /* dest: paInt32, no conversion necessary, possible byte swap */
    656             #ifdef PA_LSB_IS_NATIVE_
    657                 *converter = Swap32;
    658             #endif
    659             break;
    660         case ASIOSTInt32LSB:
    661             /* dest: paInt32, no conversion necessary, possible byte swap */
    662             #ifdef PA_MSB_IS_NATIVE_
    663                 *converter = Swap32;
    664             #endif
    665             break;
    666         case ASIOSTInt32MSB16:
    667             /* dest: paInt32, 16 bit shift, possible byte swap */
    668             #ifdef PA_LSB_IS_NATIVE_
    669                 *converter = SwapShiftLeft32;
    670             #else
    671                 *converter = ShiftLeft32;
    672             #endif
    673             *shift = 16;
    674             break;
    675         case ASIOSTInt32MSB18:
    676             /* dest: paInt32, 14 bit shift, possible byte swap */
    677             #ifdef PA_LSB_IS_NATIVE_
    678                 *converter = SwapShiftLeft32;
    679             #else
    680                 *converter = ShiftLeft32;
    681             #endif
    682             *shift = 14;
    683             break;
    684         case ASIOSTInt32MSB20:
    685             /* dest: paInt32, 12 bit shift, possible byte swap */
    686             #ifdef PA_LSB_IS_NATIVE_
    687                 *converter = SwapShiftLeft32;
    688             #else
    689                 *converter = ShiftLeft32;
    690             #endif
    691             *shift = 12;
    692             break;
    693         case ASIOSTInt32MSB24:
    694             /* dest: paInt32, 8 bit shift, possible byte swap */
    695             #ifdef PA_LSB_IS_NATIVE_
    696                 *converter = SwapShiftLeft32;
    697             #else
    698                 *converter = ShiftLeft32;
    699             #endif
    700             *shift = 8;
    701             break;
    702         case ASIOSTInt32LSB16:
    703             /* dest: paInt32, 16 bit shift, possible byte swap */
    704             #ifdef PA_MSB_IS_NATIVE_
    705                 *converter = SwapShiftLeft32;
    706             #else
    707                 *converter = ShiftLeft32;
    708             #endif
    709             *shift = 16;
    710             break;
    711         case ASIOSTInt32LSB18:
    712             /* dest: paInt32, 14 bit shift, possible byte swap */
    713             #ifdef PA_MSB_IS_NATIVE_
    714                 *converter = SwapShiftLeft32;
    715             #else
    716                 *converter = ShiftLeft32;
    717             #endif
    718             *shift = 14;
    719             break;
    720         case ASIOSTInt32LSB20:
    721             /* dest: paInt32, 12 bit shift, possible byte swap */
    722             #ifdef PA_MSB_IS_NATIVE_
    723                 *converter = SwapShiftLeft32;
    724             #else
    725                 *converter = ShiftLeft32;
    726             #endif
    727             *shift = 12;
    728             break;
    729         case ASIOSTInt32LSB24:
    730             /* dest: paInt32, 8 bit shift, possible byte swap */
    731             #ifdef PA_MSB_IS_NATIVE_
    732                 *converter = SwapShiftLeft32;
    733             #else
    734                 *converter = ShiftLeft32;
    735             #endif
    736             *shift = 8;
    737             break;
    738         case ASIOSTInt24MSB:
    739             /* dest: paInt24, no conversion necessary, possible byte swap */
    740             #ifdef PA_LSB_IS_NATIVE_
    741                 *converter = Swap24;
    742             #endif
    743             break;
    744         case ASIOSTInt24LSB:
    745             /* dest: paInt24, no conversion necessary, possible byte swap */
    746             #ifdef PA_MSB_IS_NATIVE_
    747                 *converter = Swap24;
    748             #endif
    749             break;
    750     }
    751 }
    752 
    753 
    754 static void SelectPaToAsioConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
    755 {
    756     *shift = 0;
    757     *converter = 0;
    758 
    759     switch (type) {
    760         case ASIOSTInt16MSB:
    761             /* src: paInt16, no conversion necessary, possible byte swap*/
    762             #ifdef PA_LSB_IS_NATIVE_
    763                 *converter = Swap16;
    764             #endif
    765             break;
    766         case ASIOSTInt16LSB:
    767             /* src: paInt16, no conversion necessary, possible byte swap*/
    768             #ifdef PA_MSB_IS_NATIVE_
    769                 *converter = Swap16;
    770             #endif
    771             break;
    772         case ASIOSTFloat32MSB:
    773             /* src: paFloat32, no conversion necessary, possible byte swap*/
    774             #ifdef PA_LSB_IS_NATIVE_
    775                 *converter = Swap32;
    776             #endif
    777             break;
    778         case ASIOSTFloat32LSB:
    779             /* src: paFloat32, no conversion necessary, possible byte swap*/
    780             #ifdef PA_MSB_IS_NATIVE_
    781                 *converter = Swap32;
    782             #endif
    783             break;
    784         case ASIOSTFloat64MSB:
    785             /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
    786             #ifdef PA_LSB_IS_NATIVE_
    787                 *converter = ConvertFloat32ToFloat64Swap64;
    788             #else
    789                 *converter = ConvertFloat32ToFloat64;
    790             #endif
    791             break;
    792         case ASIOSTFloat64LSB:
    793             /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
    794             #ifdef PA_MSB_IS_NATIVE_
    795                 *converter = ConvertFloat32ToFloat64Swap64;
    796             #else
    797                 *converter = ConvertFloat32ToFloat64;
    798             #endif
    799             break;
    800         case ASIOSTInt32MSB:
    801             /* src: paInt32, no conversion necessary, possible byte swap */
    802             #ifdef PA_LSB_IS_NATIVE_
    803                 *converter = Swap32;
    804             #endif
    805             break;
    806         case ASIOSTInt32LSB:
    807             /* src: paInt32, no conversion necessary, possible byte swap */
    808             #ifdef PA_MSB_IS_NATIVE_
    809                 *converter = Swap32;
    810             #endif
    811             break;
    812         case ASIOSTInt32MSB16:
    813             /* src: paInt32, 16 bit shift, possible byte swap */
    814             #ifdef PA_LSB_IS_NATIVE_
    815                 *converter = ShiftRightSwap32;
    816             #else
    817                 *converter = ShiftRight32;
    818             #endif
    819             *shift = 16;
    820             break;
    821         case ASIOSTInt32MSB18:
    822             /* src: paInt32, 14 bit shift, possible byte swap */
    823             #ifdef PA_LSB_IS_NATIVE_
    824                 *converter = ShiftRightSwap32;
    825             #else
    826                 *converter = ShiftRight32;
    827             #endif
    828             *shift = 14;
    829             break;
    830         case ASIOSTInt32MSB20:
    831             /* src: paInt32, 12 bit shift, possible byte swap */
    832             #ifdef PA_LSB_IS_NATIVE_
    833                 *converter = ShiftRightSwap32;
    834             #else
    835                 *converter = ShiftRight32;
    836             #endif
    837             *shift = 12;
    838             break;
    839         case ASIOSTInt32MSB24:
    840             /* src: paInt32, 8 bit shift, possible byte swap */
    841             #ifdef PA_LSB_IS_NATIVE_
    842                 *converter = ShiftRightSwap32;
    843             #else
    844                 *converter = ShiftRight32;
    845             #endif
    846             *shift = 8;
    847             break;
    848         case ASIOSTInt32LSB16:
    849             /* src: paInt32, 16 bit shift, possible byte swap */
    850             #ifdef PA_MSB_IS_NATIVE_
    851                 *converter = ShiftRightSwap32;
    852             #else
    853                 *converter = ShiftRight32;
    854             #endif
    855             *shift = 16;
    856             break;
    857         case ASIOSTInt32LSB18:
    858             /* src: paInt32, 14 bit shift, possible byte swap */
    859             #ifdef PA_MSB_IS_NATIVE_
    860                 *converter = ShiftRightSwap32;
    861             #else
    862                 *converter = ShiftRight32;
    863             #endif
    864             *shift = 14;
    865             break;
    866         case ASIOSTInt32LSB20:
    867             /* src: paInt32, 12 bit shift, possible byte swap */
    868             #ifdef PA_MSB_IS_NATIVE_
    869                 *converter = ShiftRightSwap32;
    870             #else
    871                 *converter = ShiftRight32;
    872             #endif
    873             *shift = 12;
    874             break;
    875         case ASIOSTInt32LSB24:
    876             /* src: paInt32, 8 bit shift, possible byte swap */
    877             #ifdef PA_MSB_IS_NATIVE_
    878                 *converter = ShiftRightSwap32;
    879             #else
    880                 *converter = ShiftRight32;
    881             #endif
    882             *shift = 8;
    883             break;
    884         case ASIOSTInt24MSB:
    885             /* src: paInt24, no conversion necessary, possible byte swap */
    886             #ifdef PA_LSB_IS_NATIVE_
    887                 *converter = Swap24;
    888             #endif
    889             break;
    890         case ASIOSTInt24LSB:
    891             /* src: paInt24, no conversion necessary, possible byte swap */
    892             #ifdef PA_MSB_IS_NATIVE_
    893                 *converter = Swap24;
    894             #endif
    895             break;
    896     }
    897 }
    898 
    899 
    900 typedef struct PaAsioDeviceInfo
    901 {
    902     PaDeviceInfo commonDeviceInfo;
    903     long minBufferSize;
    904     long maxBufferSize;
    905     long preferredBufferSize;
    906     long bufferGranularity;
    907 
    908     ASIOChannelInfo *asioChannelInfos;
    909 }
    910 PaAsioDeviceInfo;
    911 
    912 
    913 PaError PaAsio_GetAvailableBufferSizes( PaDeviceIndex device,
    914         long *minBufferSizeFrames, long *maxBufferSizeFrames, long *preferredBufferSizeFrames, long *granularity )
    915 {
    916     PaError result;
    917     PaUtilHostApiRepresentation *hostApi;
    918     PaDeviceIndex hostApiDevice;
    919 
    920     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
    921 
    922     if( result == paNoError )
    923     {
    924         result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
    925 
    926         if( result == paNoError )
    927         {
    928             PaAsioDeviceInfo *asioDeviceInfo =
    929                     (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
    930 
    931             *minBufferSizeFrames = asioDeviceInfo->minBufferSize;
    932             *maxBufferSizeFrames = asioDeviceInfo->maxBufferSize;
    933             *preferredBufferSizeFrames = asioDeviceInfo->preferredBufferSize;
    934             *granularity = asioDeviceInfo->bufferGranularity;
    935         }
    936     }
    937 
    938     return result;
    939 }
    940 
    941 /* Unload whatever we loaded in LoadAsioDriver().
    942 */
    943 static void UnloadAsioDriver( void )
    944 {
    945 	ASIOExit();
    946 }
    947 
    948 /*
    949     load the asio driver named by <driverName> and return statistics about
    950     the driver in info. If no error occurred, the driver will remain open
    951     and must be closed by the called by calling UnloadAsioDriver() - if an error
    952     is returned the driver will already be unloaded.
    953 */
    954 static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const char *driverName,
    955         PaAsioDriverInfo *driverInfo, void *systemSpecific )
    956 {
    957     PaError result = paNoError;
    958     ASIOError asioError;
    959     int asioIsInitialized = 0;
    960 
    961     if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(driverName) ) )
    962     {
    963         result = paUnanticipatedHostError;
    964         PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
    965         goto error;
    966     }
    967 
    968     memset( &driverInfo->asioDriverInfo, 0, sizeof(ASIODriverInfo) );
    969     driverInfo->asioDriverInfo.asioVersion = 2;
    970     driverInfo->asioDriverInfo.sysRef = systemSpecific;
    971     if( (asioError = ASIOInit( &driverInfo->asioDriverInfo )) != ASE_OK )
    972     {
    973         result = paUnanticipatedHostError;
    974         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
    975         goto error;
    976     }
    977     else
    978     {
    979         asioIsInitialized = 1;
    980     }
    981 
    982     if( (asioError = ASIOGetChannels(&driverInfo->inputChannelCount,
    983             &driverInfo->outputChannelCount)) != ASE_OK )
    984     {
    985         result = paUnanticipatedHostError;
    986         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
    987         goto error;
    988     }
    989 
    990     if( (asioError = ASIOGetBufferSize(&driverInfo->bufferMinSize,
    991             &driverInfo->bufferMaxSize, &driverInfo->bufferPreferredSize,
    992             &driverInfo->bufferGranularity)) != ASE_OK )
    993     {
    994         result = paUnanticipatedHostError;
    995         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
    996         goto error;
    997     }
    998 
    999     if( ASIOOutputReady() == ASE_OK )
   1000         driverInfo->postOutput = true;
   1001     else
   1002         driverInfo->postOutput = false;
   1003 
   1004     return result;
   1005 
   1006 error:
   1007     if( asioIsInitialized )
   1008 	{
   1009 		ASIOExit();
   1010 	}
   1011 
   1012     return result;
   1013 }
   1014 
   1015 
   1016 #define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_     13   /* must be the same number of elements as in the array below */
   1017 static ASIOSampleRate defaultSampleRateSearchOrder_[]
   1018      = {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0,
   1019         192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
   1020 
   1021 
   1022 static PaError InitPaDeviceInfoFromAsioDriver( PaAsioHostApiRepresentation *asioHostApi, 
   1023         const char *driverName, int driverIndex,
   1024         PaDeviceInfo *deviceInfo, PaAsioDeviceInfo *asioDeviceInfo )
   1025 {
   1026     PaError result = paNoError;
   1027 
   1028     /* Due to the headless design of the ASIO API, drivers are free to write over data given to them (like M-Audio
   1029        drivers f.i.). This is an attempt to overcome that. */
   1030     union _tag_local {
   1031         PaAsioDriverInfo info;
   1032         char _padding[4096];
   1033     } paAsioDriver;
   1034 
   1035     asioDeviceInfo->asioChannelInfos = 0; /* we check this below to handle error cleanup */
   1036 
   1037     result = LoadAsioDriver( asioHostApi, driverName, &paAsioDriver.info, asioHostApi->systemSpecific );
   1038     if( result == paNoError )
   1039     {
   1040         PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n",  driverIndex,deviceInfo->name));
   1041         PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels       = %d\n", driverIndex, paAsioDriver.info.inputChannelCount));
   1042         PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels      = %d\n", driverIndex, paAsioDriver.info.outputChannelCount));
   1043         PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize       = %d\n", driverIndex, paAsioDriver.info.bufferMinSize));
   1044         PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize       = %d\n", driverIndex, paAsioDriver.info.bufferMaxSize));
   1045         PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", driverIndex, paAsioDriver.info.bufferPreferredSize));
   1046         PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity   = %d\n", driverIndex, paAsioDriver.info.bufferGranularity));
   1047 
   1048         deviceInfo->maxInputChannels  = paAsioDriver.info.inputChannelCount;
   1049         deviceInfo->maxOutputChannels = paAsioDriver.info.outputChannelCount;
   1050 
   1051         deviceInfo->defaultSampleRate = 0.;
   1052         bool foundDefaultSampleRate = false;
   1053         for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j )
   1054         {
   1055             ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
   1056             if( asioError != ASE_NoClock && asioError != ASE_NotPresent )
   1057             {
   1058                 deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
   1059                 foundDefaultSampleRate = true;
   1060                 break;
   1061             }
   1062         }
   1063 
   1064         PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", driverIndex, deviceInfo->defaultSampleRate));
   1065 
   1066         if( foundDefaultSampleRate ){
   1067 
   1068             /* calculate default latency values from bufferPreferredSize
   1069                 for default low latency, and bufferMaxSize
   1070                 for default high latency.
   1071                 use the default sample rate to convert from samples to
   1072                 seconds. Without knowing what sample rate the user will
   1073                 use this is the best we can do.
   1074             */
   1075 
   1076             double defaultLowLatency =
   1077                     paAsioDriver.info.bufferPreferredSize / deviceInfo->defaultSampleRate;
   1078 
   1079             deviceInfo->defaultLowInputLatency = defaultLowLatency;
   1080             deviceInfo->defaultLowOutputLatency = defaultLowLatency;
   1081 
   1082             double defaultHighLatency =
   1083                     paAsioDriver.info.bufferMaxSize / deviceInfo->defaultSampleRate;
   1084 
   1085             if( defaultHighLatency < defaultLowLatency )
   1086                 defaultHighLatency = defaultLowLatency; /* just in case the driver returns something strange */ 
   1087                     
   1088             deviceInfo->defaultHighInputLatency = defaultHighLatency;
   1089             deviceInfo->defaultHighOutputLatency = defaultHighLatency;
   1090             
   1091         }else{
   1092 
   1093             deviceInfo->defaultLowInputLatency = 0.;
   1094             deviceInfo->defaultLowOutputLatency = 0.;
   1095             deviceInfo->defaultHighInputLatency = 0.;
   1096             deviceInfo->defaultHighOutputLatency = 0.;
   1097         }
   1098 
   1099         PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", driverIndex, deviceInfo->defaultLowInputLatency));
   1100         PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", driverIndex, deviceInfo->defaultLowOutputLatency));
   1101         PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", driverIndex, deviceInfo->defaultHighInputLatency));
   1102         PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", driverIndex, deviceInfo->defaultHighOutputLatency));
   1103 
   1104         asioDeviceInfo->minBufferSize = paAsioDriver.info.bufferMinSize;
   1105         asioDeviceInfo->maxBufferSize = paAsioDriver.info.bufferMaxSize;
   1106         asioDeviceInfo->preferredBufferSize = paAsioDriver.info.bufferPreferredSize;
   1107         asioDeviceInfo->bufferGranularity = paAsioDriver.info.bufferGranularity;
   1108 
   1109 
   1110         asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory(
   1111                 asioHostApi->allocations,
   1112                 sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels
   1113                         + deviceInfo->maxOutputChannels) );
   1114         if( !asioDeviceInfo->asioChannelInfos )
   1115         {
   1116             result = paInsufficientMemory;
   1117             goto error_unload;
   1118         }
   1119 
   1120         int a;
   1121 
   1122         for( a=0; a < deviceInfo->maxInputChannels; ++a ){
   1123             asioDeviceInfo->asioChannelInfos[a].channel = a;
   1124             asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue;
   1125             ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] );
   1126             if( asioError != ASE_OK )
   1127             {
   1128                 result = paUnanticipatedHostError;
   1129                 PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   1130                 goto error_unload;
   1131             }
   1132         }
   1133 
   1134         for( a=0; a < deviceInfo->maxOutputChannels; ++a ){
   1135             int b = deviceInfo->maxInputChannels + a;
   1136             asioDeviceInfo->asioChannelInfos[b].channel = a;
   1137             asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse;
   1138             ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] );
   1139             if( asioError != ASE_OK )
   1140             {
   1141                 result = paUnanticipatedHostError;
   1142                 PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   1143                 goto error_unload;
   1144             }
   1145         }
   1146 
   1147         /* unload the driver */
   1148         UnloadAsioDriver();
   1149     }
   1150 
   1151     return result;
   1152 
   1153 error_unload:
   1154     UnloadAsioDriver();
   1155 
   1156     if( asioDeviceInfo->asioChannelInfos ){
   1157         PaUtil_GroupFreeMemory( asioHostApi->allocations, asioDeviceInfo->asioChannelInfos );
   1158         asioDeviceInfo->asioChannelInfos = 0;
   1159     }
   1160 
   1161     return result;
   1162 }
   1163 
   1164 
   1165 /* we look up IsDebuggerPresent at runtime incase it isn't present (on Win95 for example) */
   1166 typedef BOOL (WINAPI *IsDebuggerPresentPtr)(VOID);
   1167 IsDebuggerPresentPtr IsDebuggerPresent_ = 0;
   1168 //FARPROC IsDebuggerPresent_ = 0; // this is the current way to do it apparently according to davidv
   1169 
   1170 PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
   1171 {
   1172     PaError result = paNoError;
   1173     int i, driverCount;
   1174     PaAsioHostApiRepresentation *asioHostApi;
   1175     PaAsioDeviceInfo *deviceInfoArray;
   1176     char **names;
   1177     asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
   1178     if( !asioHostApi )
   1179     {
   1180         result = paInsufficientMemory;
   1181         goto error;
   1182     }
   1183 
   1184     memset( asioHostApi, 0, sizeof(PaAsioHostApiRepresentation) ); /* ensure all fields are zeroed. especially asioHostApi->allocations */
   1185 
   1186     /*
   1187         We initialize COM ourselves here and uninitialize it in Terminate().
   1188         This should be the only COM initialization needed in this module.
   1189 
   1190         The ASIO SDK may also initialize COM but since we want to reduce dependency
   1191         on the ASIO SDK we manage COM initialization ourselves.
   1192 
   1193         There used to be code that initialized COM in other situations
   1194         such as when creating a Stream. This made PA work when calling Pa_CreateStream
   1195         from a non-main thread. However we currently consider initialization 
   1196         of COM in non-main threads to be the caller's responsibility.
   1197     */
   1198     result = PaWinUtil_CoInitialize( paASIO, &asioHostApi->comInitializationResult );
   1199     if( result != paNoError )
   1200     {
   1201         goto error;
   1202     }
   1203 
   1204     asioHostApi->asioDrivers = 0; /* avoid surprises in our error handler below */
   1205 
   1206     asioHostApi->allocations = PaUtil_CreateAllocationGroup();
   1207     if( !asioHostApi->allocations )
   1208     {
   1209         result = paInsufficientMemory;
   1210         goto error;
   1211     }
   1212 
   1213     /* Allocate the AsioDrivers() driver list (class from ASIO SDK) */
   1214     try
   1215     {
   1216         asioHostApi->asioDrivers = new AsioDrivers(); /* invokes CoInitialize(0) in AsioDriverList::AsioDriverList */
   1217     } 
   1218     catch (std::bad_alloc)
   1219     {
   1220         asioHostApi->asioDrivers = 0;
   1221     }
   1222     /* some implementations of new (ie MSVC, see http://support.microsoft.com/?kbid=167733)
   1223        don't throw std::bad_alloc, so we also explicitly test for a null return. */
   1224     if( asioHostApi->asioDrivers == 0 )
   1225     {
   1226         result = paInsufficientMemory;
   1227         goto error;
   1228     }
   1229 
   1230     asioDrivers = asioHostApi->asioDrivers; /* keep SDK global in sync until we stop depending on it */
   1231 
   1232     asioHostApi->systemSpecific = 0;
   1233     asioHostApi->openAsioDeviceIndex = paNoDevice;
   1234 
   1235     *hostApi = &asioHostApi->inheritedHostApiRep;
   1236     (*hostApi)->info.structVersion = 1;
   1237 
   1238     (*hostApi)->info.type = paASIO;
   1239     (*hostApi)->info.name = "ASIO";
   1240     (*hostApi)->info.deviceCount = 0;
   1241 
   1242     #ifdef WINDOWS
   1243         /* use desktop window as system specific ptr */
   1244         asioHostApi->systemSpecific = GetDesktopWindow();
   1245     #endif
   1246 
   1247     /* driverCount is the number of installed drivers - not necessarily
   1248         the number of installed physical devices. */
   1249     #if MAC
   1250         driverCount = asioHostApi->asioDrivers->getNumFragments();
   1251     #elif WINDOWS
   1252         driverCount = asioHostApi->asioDrivers->asioGetNumDev();
   1253     #endif
   1254 
   1255     if( driverCount > 0 )
   1256     {
   1257         names = GetAsioDriverNames( asioHostApi, asioHostApi->allocations, driverCount );
   1258         if( !names )
   1259         {
   1260             result = paInsufficientMemory;
   1261             goto error;
   1262         }
   1263 
   1264 
   1265         /* allocate enough space for all drivers, even if some aren't installed */
   1266 
   1267         (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
   1268                 asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount );
   1269         if( !(*hostApi)->deviceInfos )
   1270         {
   1271             result = paInsufficientMemory;
   1272             goto error;
   1273         }
   1274 
   1275         /* allocate all device info structs in a contiguous block */
   1276         deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory(
   1277                 asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount );
   1278         if( !deviceInfoArray )
   1279         {
   1280             result = paInsufficientMemory;
   1281             goto error;
   1282         }
   1283 
   1284         IsDebuggerPresent_ = (IsDebuggerPresentPtr)GetProcAddress( LoadLibraryA( "Kernel32.dll" ), "IsDebuggerPresent" );
   1285 
   1286         for( i=0; i < driverCount; ++i )
   1287         {
   1288             PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i]));
   1289 
   1290             // Since portaudio opens ALL ASIO drivers, and no one else does that,
   1291             // we face fact that some drivers were not meant for it, drivers which act
   1292             // like shells on top of REAL drivers, for instance.
   1293             // so we get duplicate handles, locks and other problems.
   1294             // so lets NOT try to load any such wrappers. 
   1295             // The ones i [davidv] know of so far are:
   1296 
   1297             if (   strcmp (names[i],"ASIO DirectX Full Duplex Driver") == 0
   1298                 || strcmp (names[i],"ASIO Multimedia Driver")          == 0
   1299                 || strncmp(names[i],"Premiere",8)                      == 0   //"Premiere Elements Windows Sound 1.0"
   1300                 || strncmp(names[i],"Adobe",5)                         == 0   //"Adobe Default Windows Sound 1.5"
   1301                )
   1302             {
   1303                 PA_DEBUG(("BLACKLISTED!!!\n"));
   1304                 continue;
   1305             }
   1306 
   1307 
   1308             if( IsDebuggerPresent_ && IsDebuggerPresent_() )  
   1309             {
   1310                 /* ASIO Digidesign Driver uses PACE copy protection which quits out
   1311                    if a debugger is running. So we don't load it if a debugger is running. */
   1312                 if( strcmp(names[i], "ASIO Digidesign Driver") == 0 )  
   1313                 {
   1314                     PA_DEBUG(("BLACKLISTED!!! ASIO Digidesign Driver would quit the debugger\n"));  
   1315                     continue;
   1316                 }  
   1317             }  
   1318 
   1319 
   1320             /* Attempt to init device info from the asio driver... */
   1321             {
   1322                 PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
   1323                 PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
   1324 
   1325                 deviceInfo->structVersion = 2;
   1326                 deviceInfo->hostApi = hostApiIndex;
   1327 
   1328                 deviceInfo->name = names[i];
   1329 
   1330                 if( InitPaDeviceInfoFromAsioDriver( asioHostApi, names[i], i, deviceInfo, asioDeviceInfo ) == paNoError )
   1331                 {
   1332                     (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
   1333                     ++(*hostApi)->info.deviceCount;
   1334                 }
   1335 				else
   1336 				{
   1337                     PA_DEBUG(("Skipping ASIO device:%s\n",names[i]));
   1338                     continue;
   1339                 }
   1340             }
   1341         }
   1342     }
   1343 
   1344     if( (*hostApi)->info.deviceCount > 0 )
   1345     {
   1346         (*hostApi)->info.defaultInputDevice = 0;
   1347         (*hostApi)->info.defaultOutputDevice = 0;
   1348     }
   1349     else
   1350     {
   1351         (*hostApi)->info.defaultInputDevice = paNoDevice;
   1352         (*hostApi)->info.defaultOutputDevice = paNoDevice;
   1353     }
   1354 
   1355 
   1356     (*hostApi)->Terminate = Terminate;
   1357     (*hostApi)->OpenStream = OpenStream;
   1358     (*hostApi)->IsFormatSupported = IsFormatSupported;
   1359 
   1360     PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
   1361                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
   1362                                       GetStreamTime, GetStreamCpuLoad,
   1363                                       PaUtil_DummyRead, PaUtil_DummyWrite,
   1364                                       PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
   1365 
   1366     PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream,
   1367                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
   1368                                       GetStreamTime, PaUtil_DummyGetCpuLoad,
   1369                                       ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
   1370 
   1371     return result;
   1372 
   1373 error:
   1374     if( asioHostApi )
   1375     {
   1376         if( asioHostApi->allocations )
   1377         {
   1378             PaUtil_FreeAllAllocations( asioHostApi->allocations );
   1379             PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
   1380         }
   1381 
   1382         delete asioHostApi->asioDrivers;
   1383         asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
   1384 
   1385         PaWinUtil_CoUninitialize( paASIO, &asioHostApi->comInitializationResult );
   1386 
   1387         PaUtil_FreeMemory( asioHostApi );
   1388     }
   1389 
   1390     return result;
   1391 }
   1392 
   1393 
   1394 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
   1395 {
   1396     PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
   1397 
   1398     /*
   1399         IMPLEMENT ME:
   1400             - clean up any resources not handled by the allocation group (need to review if there are any)
   1401     */
   1402 
   1403     if( asioHostApi->allocations )
   1404     {
   1405         PaUtil_FreeAllAllocations( asioHostApi->allocations );
   1406         PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
   1407     }
   1408 
   1409     delete asioHostApi->asioDrivers;
   1410     asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
   1411 
   1412     PaWinUtil_CoUninitialize( paASIO, &asioHostApi->comInitializationResult );
   1413 
   1414     PaUtil_FreeMemory( asioHostApi );
   1415 }
   1416 
   1417 
   1418 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
   1419                                   const PaStreamParameters *inputParameters,
   1420                                   const PaStreamParameters *outputParameters,
   1421                                   double sampleRate )
   1422 {
   1423     PaError result = paNoError;
   1424     PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
   1425     PaAsioDriverInfo *driverInfo = &asioHostApi->openAsioDriverInfo;
   1426     int inputChannelCount, outputChannelCount;
   1427     PaSampleFormat inputSampleFormat, outputSampleFormat;
   1428     PaDeviceIndex asioDeviceIndex;                                  
   1429     ASIOError asioError;
   1430     
   1431     if( inputParameters && outputParameters )
   1432     {
   1433         /* full duplex ASIO stream must use the same device for input and output */
   1434 
   1435         if( inputParameters->device != outputParameters->device )
   1436             return paBadIODeviceCombination;
   1437     }
   1438     
   1439     if( inputParameters )
   1440     {
   1441         inputChannelCount = inputParameters->channelCount;
   1442         inputSampleFormat = inputParameters->sampleFormat;
   1443 
   1444         /* all standard sample formats are supported by the buffer adapter,
   1445             this implementation doesn't support any custom sample formats */
   1446         if( inputSampleFormat & paCustomFormat )
   1447             return paSampleFormatNotSupported;
   1448             
   1449         /* unless alternate device specification is supported, reject the use of
   1450             paUseHostApiSpecificDeviceSpecification */
   1451 
   1452         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
   1453             return paInvalidDevice;
   1454 
   1455         asioDeviceIndex = inputParameters->device;
   1456 
   1457         /* validate inputStreamInfo */
   1458         /** @todo do more validation here */
   1459         // if( inputParameters->hostApiSpecificStreamInfo )
   1460         //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
   1461     }
   1462     else
   1463     {
   1464         inputChannelCount = 0;
   1465     }
   1466 
   1467     if( outputParameters )
   1468     {
   1469         outputChannelCount = outputParameters->channelCount;
   1470         outputSampleFormat = outputParameters->sampleFormat;
   1471 
   1472         /* all standard sample formats are supported by the buffer adapter,
   1473             this implementation doesn't support any custom sample formats */
   1474         if( outputSampleFormat & paCustomFormat )
   1475             return paSampleFormatNotSupported;
   1476             
   1477         /* unless alternate device specification is supported, reject the use of
   1478             paUseHostApiSpecificDeviceSpecification */
   1479 
   1480         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
   1481             return paInvalidDevice;
   1482 
   1483         asioDeviceIndex = outputParameters->device;
   1484 
   1485         /* validate outputStreamInfo */
   1486         /** @todo do more validation here */
   1487         // if( outputParameters->hostApiSpecificStreamInfo )
   1488         //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
   1489     }
   1490     else
   1491     {
   1492         outputChannelCount = 0;
   1493     }
   1494 
   1495 
   1496 
   1497     /* if an ASIO device is open we can only get format information for the currently open device */
   1498 
   1499     if( asioHostApi->openAsioDeviceIndex != paNoDevice 
   1500             && asioHostApi->openAsioDeviceIndex != asioDeviceIndex )
   1501     {
   1502         return paDeviceUnavailable;
   1503     }
   1504 
   1505 
   1506     /* NOTE: we load the driver and use its current settings
   1507         rather than the ones in our device info structure which may be stale */
   1508 
   1509     /* open the device if it's not already open */
   1510     if( asioHostApi->openAsioDeviceIndex == paNoDevice )
   1511     {
   1512         result = LoadAsioDriver( asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
   1513                 driverInfo, asioHostApi->systemSpecific );
   1514         if( result != paNoError )
   1515             return result;
   1516     }
   1517 
   1518     /* check that input device can support inputChannelCount */
   1519     if( inputChannelCount > 0 )
   1520     {
   1521         if( inputChannelCount > driverInfo->inputChannelCount )
   1522         {
   1523             result = paInvalidChannelCount;
   1524             goto done;
   1525         }
   1526     }
   1527 
   1528     /* check that output device can support outputChannelCount */
   1529     if( outputChannelCount )
   1530     {
   1531         if( outputChannelCount > driverInfo->outputChannelCount )
   1532         {
   1533             result = paInvalidChannelCount;
   1534             goto done;
   1535         }
   1536     }
   1537     
   1538     /* query for sample rate support */
   1539     asioError = ASIOCanSampleRate( sampleRate );
   1540     if( asioError == ASE_NoClock || asioError == ASE_NotPresent )
   1541     {
   1542         result = paInvalidSampleRate;
   1543         goto done;
   1544     }
   1545 
   1546 done:
   1547     /* close the device if it wasn't already open */
   1548     if( asioHostApi->openAsioDeviceIndex == paNoDevice )
   1549     {
   1550         UnloadAsioDriver(); /* not sure if we should check for errors here */
   1551     }
   1552 
   1553     if( result == paNoError )
   1554         return paFormatIsSupported;
   1555     else
   1556         return result;
   1557 }
   1558 
   1559 
   1560 
   1561 /** A data structure specifically for storing blocking i/o related data. */
   1562 typedef struct PaAsioStreamBlockingState
   1563 {
   1564     int stopFlag; /**< Flag indicating that block processing is to be stopped. */
   1565 
   1566     unsigned long writeBuffersRequested; /**< The number of available output buffers, requested by the #WriteStream() function. */
   1567     unsigned long readFramesRequested;   /**< The number of available input frames, requested by the #ReadStream() function. */
   1568 
   1569     int writeBuffersRequestedFlag; /**< Flag to indicate that #WriteStream() has requested more output buffers to be available. */
   1570     int readFramesRequestedFlag;   /**< Flag to indicate that #ReadStream() requires more input frames to be available. */
   1571 
   1572     HANDLE writeBuffersReadyEvent; /**< Event to signal that requested output buffers are available. */
   1573     HANDLE readFramesReadyEvent;   /**< Event to signal that requested input frames are available. */
   1574 
   1575     void *writeRingBufferData; /**< The actual ring buffer memory, used by the output ring buffer. */
   1576     void *readRingBufferData;  /**< The actual ring buffer memory, used by the input ring buffer. */
   1577 
   1578     PaUtilRingBuffer writeRingBuffer; /**< Frame-aligned blocking i/o ring buffer to store output data (interleaved user format). */
   1579     PaUtilRingBuffer readRingBuffer;  /**< Frame-aligned blocking i/o ring buffer to store input data (interleaved user format). */
   1580 
   1581     long writeRingBufferInitialFrames; /**< The initial number of silent frames within the output ring buffer. */
   1582 
   1583     const void **writeStreamBuffer; /**< Temp buffer, used by #WriteStream() for handling non-interleaved data. */
   1584     void **readStreamBuffer; /**< Temp buffer, used by #ReadStream() for handling non-interleaved data. */
   1585 
   1586     PaUtilBufferProcessor bufferProcessor; /**< Buffer processor, used to handle the blocking i/o ring buffers. */
   1587 
   1588     int outputUnderflowFlag; /**< Flag to signal an output underflow from within the callback function. */
   1589     int inputOverflowFlag; /**< Flag to signal an input overflow from within the callback function. */
   1590 }
   1591 PaAsioStreamBlockingState;
   1592 
   1593 
   1594 
   1595 /* PaAsioStream - a stream data structure specifically for this implementation */
   1596 
   1597 typedef struct PaAsioStream
   1598 {
   1599     PaUtilStreamRepresentation streamRepresentation;
   1600     PaUtilCpuLoadMeasurer cpuLoadMeasurer;
   1601     PaUtilBufferProcessor bufferProcessor;
   1602 
   1603     PaAsioHostApiRepresentation *asioHostApi;
   1604     unsigned long framesPerHostCallback;
   1605 
   1606     /* ASIO driver info  - these may not be needed for the life of the stream,
   1607         but store them here until we work out how format conversion is going
   1608         to work. */
   1609 
   1610     ASIOBufferInfo *asioBufferInfos;
   1611     ASIOChannelInfo *asioChannelInfos;
   1612     long asioInputLatencyFrames, asioOutputLatencyFrames; // actual latencies returned by asio
   1613 
   1614     long inputChannelCount, outputChannelCount;
   1615     bool postOutput;
   1616 
   1617     void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */
   1618     void **inputBufferPtrs[2];
   1619     void **outputBufferPtrs[2];
   1620 
   1621     PaAsioBufferConverter *inputBufferConverter;
   1622     long inputShift;
   1623     PaAsioBufferConverter *outputBufferConverter;
   1624     long outputShift;
   1625 
   1626     volatile bool stopProcessing;
   1627     int stopPlayoutCount;
   1628     HANDLE completedBuffersPlayedEvent;
   1629 
   1630     bool streamFinishedCallbackCalled;
   1631     int isStopped;
   1632     volatile int isActive;
   1633     volatile bool zeroOutput; /* all future calls to the callback will output silence */
   1634 
   1635     volatile long reenterCount;
   1636     volatile long reenterError;
   1637 
   1638     PaStreamCallbackFlags callbackFlags;
   1639 
   1640     PaAsioStreamBlockingState *blockingState; /**< Blocking i/o data struct, or NULL when using callback interface. */
   1641 }
   1642 PaAsioStream;
   1643 
   1644 static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */
   1645 
   1646 
   1647 static void ZeroOutputBuffers( PaAsioStream *stream, long index )
   1648 {
   1649     int i;
   1650 
   1651     for( i=0; i < stream->outputChannelCount; ++i )
   1652     {
   1653         void *buffer = stream->asioBufferInfos[ i + stream->inputChannelCount ].buffers[index];
   1654 
   1655         int bytesPerSample = BytesPerAsioSample( stream->asioChannelInfos[ i + stream->inputChannelCount ].type );
   1656 
   1657         memset( buffer, 0, stream->framesPerHostCallback * bytesPerSample );
   1658     }
   1659 }
   1660 
   1661 
   1662 /* return the next power of two >= x. 
   1663    Returns the input parameter if it is already a power of two. 
   1664    http://stackoverflow.com/questions/364985/algorithm-for-finding-the-smallest-power-of-two-thats-greater-or-equal-to-a-giv 
   1665 */
   1666 static unsigned long NextPowerOfTwo( unsigned long x )
   1667 {
   1668     --x;
   1669     x |= x >> 1;
   1670     x |= x >> 2;
   1671     x |= x >> 4;
   1672     x |= x >> 8;
   1673     x |= x >> 16;
   1674     /* If you needed to deal with numbers > 2^32 the following would be needed. 
   1675        For latencies, we don't deal with values this large. 
   1676      x |= x >> 16;
   1677     */
   1678 
   1679     return x + 1;
   1680 }
   1681 
   1682 
   1683 static unsigned long SelectHostBufferSizeForUnspecifiedUserFramesPerBuffer( 
   1684         unsigned long targetBufferingLatencyFrames, PaAsioDriverInfo *driverInfo )
   1685 {
   1686 	/* Choose a host buffer size based only on targetBufferingLatencyFrames and the 
   1687 	   device's supported buffer sizes. Always returns a valid value.
   1688 	*/
   1689 
   1690 	unsigned long result;
   1691 
   1692 	if( targetBufferingLatencyFrames <= (unsigned long)driverInfo->bufferMinSize )
   1693     {
   1694         result = driverInfo->bufferMinSize;
   1695     }
   1696     else if( targetBufferingLatencyFrames >= (unsigned long)driverInfo->bufferMaxSize )
   1697     {
   1698         result = driverInfo->bufferMaxSize;
   1699     }
   1700     else
   1701     {
   1702 		if( driverInfo->bufferGranularity == 0 ) /* single fixed host buffer size */
   1703         {
   1704             /* The documentation states that bufferGranularity should be zero 
   1705                when bufferMinSize, bufferMaxSize and bufferPreferredSize are the 
   1706                same. We assume that is the case.
   1707             */
   1708 
   1709             result = driverInfo->bufferPreferredSize;
   1710         }
   1711 		else if( driverInfo->bufferGranularity == -1 ) /* power-of-two */
   1712         {
   1713 		    /* We assume bufferMinSize and bufferMaxSize are powers of two. */
   1714 
   1715             result = NextPowerOfTwo( targetBufferingLatencyFrames );
   1716 
   1717             if( result < (unsigned long)driverInfo->bufferMinSize )
   1718                 result = driverInfo->bufferMinSize;
   1719 
   1720             if( result > (unsigned long)driverInfo->bufferMaxSize )
   1721                 result = driverInfo->bufferMaxSize;
   1722         }
   1723         else /* modulo bufferGranularity */
   1724         {
   1725             /* round up to the next multiple of granularity */
   1726             unsigned long n = (targetBufferingLatencyFrames + driverInfo->bufferGranularity - 1) 
   1727                     / driverInfo->bufferGranularity;
   1728             
   1729             result = n * driverInfo->bufferGranularity;
   1730 
   1731             if( result < (unsigned long)driverInfo->bufferMinSize )
   1732                 result = driverInfo->bufferMinSize;
   1733 
   1734             if( result > (unsigned long)driverInfo->bufferMaxSize )
   1735                 result = driverInfo->bufferMaxSize;
   1736         }
   1737     }
   1738 
   1739 	return result;
   1740 }
   1741 
   1742 
   1743 static unsigned long SelectHostBufferSizeForSpecifiedUserFramesPerBuffer( 
   1744         unsigned long targetBufferingLatencyFrames, unsigned long userFramesPerBuffer,
   1745         PaAsioDriverInfo *driverInfo )
   1746 {
   1747 	/* Select a host buffer size conforming to targetBufferingLatencyFrames 
   1748 	   and the device's supported buffer sizes.
   1749 	   The return value will always be a multiple of userFramesPerBuffer. 
   1750 	   If a valid buffer size can not be found the function returns 0.
   1751 
   1752 	   The current implementation uses a simple iterative search for clarity.
   1753 	   Feel free to suggest a closed form solution.
   1754 	*/
   1755 	unsigned long result = 0;
   1756 
   1757 	assert( userFramesPerBuffer != 0 );
   1758 	
   1759 	if( driverInfo->bufferGranularity == 0 ) /* single fixed host buffer size */
   1760     {
   1761         /* The documentation states that bufferGranularity should be zero 
   1762            when bufferMinSize, bufferMaxSize and bufferPreferredSize are the 
   1763            same. We assume that is the case.
   1764         */
   1765 
   1766 		if( (driverInfo->bufferPreferredSize % userFramesPerBuffer) == 0 )
   1767 			result = driverInfo->bufferPreferredSize;
   1768     }
   1769 	else if( driverInfo->bufferGranularity == -1 ) /* power-of-two */
   1770     {
   1771 		/* We assume bufferMinSize and bufferMaxSize are powers of two. */
   1772 
   1773         /* Search all powers of two in the range [bufferMinSize,bufferMaxSize] 
   1774            for multiples of userFramesPerBuffer. We prefer the first multiple
   1775            that is equal or greater than targetBufferingLatencyFrames, or  
   1776            failing that, the largest multiple less than 
   1777            targetBufferingLatencyFrames.
   1778         */
   1779         unsigned long x = (unsigned long)driverInfo->bufferMinSize; 
   1780 		do {
   1781 			if( (x % userFramesPerBuffer) == 0 )
   1782 			{
   1783                 /* any multiple of userFramesPerBuffer is acceptable */
   1784 				result = x;
   1785 				if( result >= targetBufferingLatencyFrames )
   1786 					break; /* stop. a value >= to targetBufferingLatencyFrames is ideal. */
   1787 			}
   1788 
   1789 			x *= 2;
   1790 		} while( x <= (unsigned long)driverInfo->bufferMaxSize );
   1791     }
   1792     else /* modulo granularity */
   1793     {
   1794 		/* We assume bufferMinSize is a multiple of bufferGranularity. */
   1795 
   1796         /* Search all multiples of bufferGranularity in the range 
   1797            [bufferMinSize,bufferMaxSize] for multiples of userFramesPerBuffer. 
   1798            We prefer the first multiple that is equal or greater than 
   1799            targetBufferingLatencyFrames, or failing that, the largest multiple  
   1800            less than targetBufferingLatencyFrames.
   1801         */
   1802 		unsigned long x = (unsigned long)driverInfo->bufferMinSize; 
   1803 		do {
   1804 			if( (x % userFramesPerBuffer) == 0 )
   1805 			{
   1806                 /* any multiple of userFramesPerBuffer is acceptable */
   1807 				result = x;
   1808 				if( result >= targetBufferingLatencyFrames )
   1809 					break; /* stop. a value >= to targetBufferingLatencyFrames is ideal. */
   1810 			}
   1811 
   1812 			x += driverInfo->bufferGranularity;
   1813 		} while( x <= (unsigned long)driverInfo->bufferMaxSize );
   1814     }
   1815 
   1816 	return result;
   1817 }
   1818 
   1819 
   1820 static unsigned long SelectHostBufferSize( 
   1821         unsigned long targetBufferingLatencyFrames, 
   1822         unsigned long userFramesPerBuffer, PaAsioDriverInfo *driverInfo )
   1823 {
   1824     unsigned long result = 0;
   1825 
   1826     /* We select a host buffer size based on the following requirements 
   1827        (in priority order):
   1828 
   1829         1. The host buffer size must be permissible according to the ASIO 
   1830            driverInfo buffer size constraints (min, max, granularity or 
   1831            powers-of-two).
   1832 
   1833         2. If the user specifies a non-zero framesPerBuffer parameter 
   1834            (userFramesPerBuffer here) the host buffer should be a multiple of 
   1835            this (subject to the constraints in (1) above).
   1836 
   1837            [NOTE: Where no permissible host buffer size is a multiple of 
   1838            userFramesPerBuffer, we choose a value as if userFramesPerBuffer were 
   1839            zero (i.e. we ignore it). This strategy is open for review ~ perhaps 
   1840            there are still "more optimal" buffer sizes related to 
   1841            userFramesPerBuffer that we could use.]
   1842 
   1843         3. The host buffer size should be greater than or equal to 
   1844            targetBufferingLatencyFrames, subject to (1) and (2) above. Where it 
   1845            is not possible to select a host buffer size equal or greater than 
   1846            targetBufferingLatencyFrames, the highest buffer size conforming to  
   1847            (1) and (2) should be chosen.
   1848     */
   1849 
   1850 	if( userFramesPerBuffer != 0 )
   1851 	{
   1852 		/* userFramesPerBuffer is specified, try to find a buffer size that's 
   1853            a multiple of it */
   1854 		result = SelectHostBufferSizeForSpecifiedUserFramesPerBuffer( 
   1855                 targetBufferingLatencyFrames, userFramesPerBuffer, driverInfo );
   1856 	}
   1857 
   1858 	if( result == 0 )
   1859 	{
   1860 		/* either userFramesPerBuffer was not specified, or we couldn't find a 
   1861            host buffer size that is a multiple of it. Select a host buffer size 
   1862            according to targetBufferingLatencyFrames and the ASIO driverInfo 
   1863            buffer size constraints.
   1864 	     */
   1865 		result = SelectHostBufferSizeForUnspecifiedUserFramesPerBuffer( 
   1866                 targetBufferingLatencyFrames, driverInfo );
   1867 	}
   1868 
   1869 	return result;
   1870 }
   1871 
   1872 
   1873 /* returns channelSelectors if present */
   1874 
   1875 static PaError ValidateAsioSpecificStreamInfo(
   1876         const PaStreamParameters *streamParameters,
   1877         const PaAsioStreamInfo *streamInfo,
   1878         int deviceChannelCount,
   1879         int **channelSelectors )
   1880 {
   1881     if( streamInfo )
   1882     {
   1883         if( streamInfo->size != sizeof( PaAsioStreamInfo )
   1884                 || streamInfo->version != 1 )
   1885         {
   1886             return paIncompatibleHostApiSpecificStreamInfo;
   1887         }
   1888 
   1889         if( streamInfo->flags & paAsioUseChannelSelectors )
   1890             *channelSelectors = streamInfo->channelSelectors;
   1891 
   1892         if( !(*channelSelectors) )
   1893             return paIncompatibleHostApiSpecificStreamInfo;
   1894 
   1895         for( int i=0; i < streamParameters->channelCount; ++i ){
   1896              if( (*channelSelectors)[i] < 0
   1897                     || (*channelSelectors)[i] >= deviceChannelCount ){
   1898                 return paInvalidChannelCount;
   1899              }           
   1900         }
   1901     }
   1902 
   1903     return paNoError;
   1904 }
   1905 
   1906 
   1907 static bool IsUsingExternalClockSource()
   1908 {
   1909     bool result = false;
   1910     ASIOError asioError;
   1911     ASIOClockSource clocks[32];
   1912     long numSources=32;
   1913 
   1914     /* davidv: listing ASIO Clock sources. there is an ongoing investigation by
   1915        me about whether or not to call ASIOSetSampleRate if an external Clock is
   1916        used. A few drivers expected different things here */
   1917     
   1918     asioError = ASIOGetClockSources(clocks, &numSources);
   1919     if( asioError != ASE_OK ){
   1920         PA_DEBUG(("ERROR: ASIOGetClockSources: %s\n", PaAsio_GetAsioErrorText(asioError) ));
   1921     }else{
   1922         PA_DEBUG(("INFO ASIOGetClockSources listing %d clocks\n", numSources ));
   1923         for (int i=0;i<numSources;++i){
   1924             PA_DEBUG(("ASIOClockSource%d %s current:%d\n", i, clocks[i].name, clocks[i].isCurrentSource ));
   1925            
   1926             if (clocks[i].isCurrentSource)
   1927                 result = true;
   1928         }
   1929     }
   1930 
   1931     return result;
   1932 }
   1933 
   1934 
   1935 static PaError ValidateAndSetSampleRate( double sampleRate )
   1936 {
   1937     PaError result = paNoError;
   1938     ASIOError asioError;
   1939 
   1940     // check that the device supports the requested sample rate 
   1941 
   1942     asioError = ASIOCanSampleRate( sampleRate );
   1943     PA_DEBUG(("ASIOCanSampleRate(%f):%d\n", sampleRate, asioError ));
   1944 
   1945     if( asioError != ASE_OK )
   1946     {
   1947         result = paInvalidSampleRate;
   1948         PA_DEBUG(("ERROR: ASIOCanSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
   1949         goto error;
   1950     }
   1951 
   1952     // retrieve the current sample rate, we only change to the requested
   1953     // sample rate if the device is not already in that rate.
   1954 
   1955     ASIOSampleRate oldRate;
   1956     asioError = ASIOGetSampleRate(&oldRate);
   1957     if( asioError != ASE_OK )
   1958     {
   1959         result = paInvalidSampleRate;
   1960         PA_DEBUG(("ERROR: ASIOGetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
   1961         goto error;
   1962     }
   1963     PA_DEBUG(("ASIOGetSampleRate:%f\n",oldRate));
   1964 
   1965     if (oldRate != sampleRate){
   1966         /* Set sample rate */
   1967 
   1968         PA_DEBUG(("before ASIOSetSampleRate(%f)\n",sampleRate));
   1969 
   1970         /*
   1971             If you have problems with some drivers when externally clocked, 
   1972             try switching on the following line and commenting out the one after it.
   1973             See IsUsingExternalClockSource() for more info.
   1974         */
   1975         //if( IsUsingExternalClockSource() ){
   1976         if( false ){
   1977             asioError = ASIOSetSampleRate( 0 );
   1978         }else{
   1979             asioError = ASIOSetSampleRate( sampleRate );
   1980         }
   1981         if( asioError != ASE_OK )
   1982         {
   1983             result = paInvalidSampleRate;
   1984             PA_DEBUG(("ERROR: ASIOSetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
   1985             goto error;
   1986         }
   1987         PA_DEBUG(("after ASIOSetSampleRate(%f)\n",sampleRate));
   1988     }
   1989     else
   1990     {
   1991         PA_DEBUG(("No Need to change SR\n"));
   1992     }
   1993 
   1994 error:
   1995     return result;
   1996 }
   1997 
   1998 
   1999 /* see pa_hostapi.h for a list of validity guarantees made about OpenStream  parameters */
   2000 
   2001 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
   2002                            PaStream** s,
   2003                            const PaStreamParameters *inputParameters,
   2004                            const PaStreamParameters *outputParameters,
   2005                            double sampleRate,
   2006                            unsigned long framesPerBuffer,
   2007                            PaStreamFlags streamFlags,
   2008                            PaStreamCallback *streamCallback,
   2009                            void *userData )
   2010 {
   2011     PaError result = paNoError;
   2012     PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
   2013     PaAsioStream *stream = 0;
   2014     PaAsioStreamInfo *inputStreamInfo, *outputStreamInfo;
   2015     unsigned long framesPerHostBuffer;
   2016     int inputChannelCount, outputChannelCount;
   2017     PaSampleFormat inputSampleFormat, outputSampleFormat;
   2018     PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
   2019     unsigned long suggestedInputLatencyFrames;
   2020     unsigned long suggestedOutputLatencyFrames;
   2021     PaDeviceIndex asioDeviceIndex;
   2022     ASIOError asioError;
   2023     int asioIsInitialized = 0;
   2024     int asioBuffersCreated = 0;
   2025     int completedBuffersPlayedEventInited = 0;
   2026     int i;
   2027     PaAsioDriverInfo *driverInfo;
   2028     int *inputChannelSelectors = 0;
   2029     int *outputChannelSelectors = 0;
   2030 
   2031     /* Are we using blocking i/o interface? */
   2032     int usingBlockingIo = ( !streamCallback ) ? TRUE : FALSE;
   2033     /* Blocking i/o stuff */
   2034     long lBlockingBufferSize     = 0; /* Desired ring buffer size in samples. */
   2035     long lBlockingBufferSizePow2 = 0; /* Power-of-2 rounded ring buffer size. */
   2036     long lBytesPerFrame          = 0; /* Number of bytes per input/output frame. */
   2037     int blockingWriteBuffersReadyEventInitialized = 0; /* Event init flag. */
   2038     int blockingReadFramesReadyEventInitialized   = 0; /* Event init flag. */
   2039 
   2040     int callbackBufferProcessorInited = FALSE;
   2041     int blockingBufferProcessorInited = FALSE;
   2042 
   2043     /* unless we move to using lower level ASIO calls, we can only have
   2044         one device open at a time */
   2045     if( asioHostApi->openAsioDeviceIndex != paNoDevice )
   2046     {
   2047         PA_DEBUG(("OpenStream paDeviceUnavailable\n"));
   2048         return paDeviceUnavailable;
   2049     }
   2050 
   2051     assert( theAsioStream == 0 );
   2052 
   2053     if( inputParameters && outputParameters )
   2054     {
   2055         /* full duplex ASIO stream must use the same device for input and output */
   2056 
   2057         if( inputParameters->device != outputParameters->device )
   2058         {
   2059             PA_DEBUG(("OpenStream paBadIODeviceCombination\n"));
   2060             return paBadIODeviceCombination;
   2061         }
   2062     }
   2063 
   2064     if( inputParameters )
   2065     {
   2066         inputChannelCount = inputParameters->channelCount;
   2067         inputSampleFormat = inputParameters->sampleFormat;
   2068         suggestedInputLatencyFrames = (unsigned long)((inputParameters->suggestedLatency * sampleRate)+0.5f);
   2069 
   2070         /* unless alternate device specification is supported, reject the use of
   2071             paUseHostApiSpecificDeviceSpecification */
   2072         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
   2073             return paInvalidDevice;
   2074 
   2075         asioDeviceIndex = inputParameters->device;
   2076 
   2077         PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
   2078 
   2079         /* validate hostApiSpecificStreamInfo */
   2080         inputStreamInfo = (PaAsioStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
   2081         result = ValidateAsioSpecificStreamInfo( inputParameters, inputStreamInfo,
   2082             asioDeviceInfo->commonDeviceInfo.maxInputChannels,
   2083             &inputChannelSelectors
   2084         );
   2085         if( result != paNoError ) return result;
   2086     }
   2087     else
   2088     {
   2089         inputChannelCount = 0;
   2090         inputSampleFormat = 0;
   2091         suggestedInputLatencyFrames = 0;
   2092     }
   2093 
   2094     if( outputParameters )
   2095     {
   2096         outputChannelCount = outputParameters->channelCount;
   2097         outputSampleFormat = outputParameters->sampleFormat;
   2098         suggestedOutputLatencyFrames = (unsigned long)((outputParameters->suggestedLatency * sampleRate)+0.5f);
   2099 
   2100         /* unless alternate device specification is supported, reject the use of
   2101             paUseHostApiSpecificDeviceSpecification */
   2102         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
   2103             return paInvalidDevice;
   2104 
   2105         asioDeviceIndex = outputParameters->device;
   2106 
   2107         PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
   2108 
   2109         /* validate hostApiSpecificStreamInfo */
   2110         outputStreamInfo = (PaAsioStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
   2111         result = ValidateAsioSpecificStreamInfo( outputParameters, outputStreamInfo,
   2112             asioDeviceInfo->commonDeviceInfo.maxOutputChannels,
   2113             &outputChannelSelectors
   2114         );
   2115         if( result != paNoError ) return result;
   2116     }
   2117     else
   2118     {
   2119         outputChannelCount = 0;
   2120         outputSampleFormat = 0;
   2121         suggestedOutputLatencyFrames = 0;
   2122     }
   2123 
   2124     driverInfo = &asioHostApi->openAsioDriverInfo;
   2125 
   2126     /* NOTE: we load the driver and use its current settings
   2127         rather than the ones in our device info structure which may be stale */
   2128 
   2129     result = LoadAsioDriver( asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
   2130             driverInfo, asioHostApi->systemSpecific );
   2131     if( result == paNoError )
   2132         asioIsInitialized = 1;
   2133     else{
   2134         PA_DEBUG(("OpenStream ERROR1 - LoadAsioDriver returned %d\n", result));
   2135         goto error;
   2136     }
   2137 
   2138     /* check that input device can support inputChannelCount */
   2139     if( inputChannelCount > 0 )
   2140     {
   2141         if( inputChannelCount > driverInfo->inputChannelCount )
   2142         {
   2143             result = paInvalidChannelCount;
   2144             PA_DEBUG(("OpenStream ERROR2\n"));
   2145             goto error;
   2146         }
   2147     }
   2148 
   2149     /* check that output device can support outputChannelCount */
   2150     if( outputChannelCount )
   2151     {
   2152         if( outputChannelCount > driverInfo->outputChannelCount )
   2153         {
   2154             result = paInvalidChannelCount;
   2155             PA_DEBUG(("OpenStream ERROR3\n"));
   2156             goto error;
   2157         }
   2158     }
   2159 
   2160     result = ValidateAndSetSampleRate( sampleRate );
   2161     if( result != paNoError )
   2162         goto error;
   2163 
   2164     /*
   2165         IMPLEMENT ME:
   2166             - if a full duplex stream is requested, check that the combination
   2167                 of input and output parameters is supported
   2168     */
   2169 
   2170     /* validate platform specific flags */
   2171     if( (streamFlags & paPlatformSpecificFlags) != 0 ){
   2172         PA_DEBUG(("OpenStream invalid flags!!\n"));
   2173         return paInvalidFlag; /* unexpected platform specific flag */
   2174     }
   2175 
   2176 
   2177     stream = (PaAsioStream*)PaUtil_AllocateMemory( sizeof(PaAsioStream) );
   2178     if( !stream )
   2179     {
   2180         result = paInsufficientMemory;
   2181         PA_DEBUG(("OpenStream ERROR5\n"));
   2182         goto error;
   2183     }
   2184     stream->blockingState = NULL; /* Blocking i/o not initialized, yet. */
   2185 
   2186 
   2187     stream->completedBuffersPlayedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
   2188     if( stream->completedBuffersPlayedEvent == NULL )
   2189     {
   2190         result = paUnanticipatedHostError;
   2191         PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
   2192         PA_DEBUG(("OpenStream ERROR6\n"));
   2193         goto error;
   2194     }
   2195     completedBuffersPlayedEventInited = 1;
   2196 
   2197 
   2198     stream->asioBufferInfos = 0; /* for deallocation in error */
   2199     stream->asioChannelInfos = 0; /* for deallocation in error */
   2200     stream->bufferPtrs = 0; /* for deallocation in error */
   2201 
   2202     /* Using blocking i/o interface... */
   2203     if( usingBlockingIo )
   2204     {
   2205         /* Blocking i/o is implemented by running callback mode, using a special blocking i/o callback. */
   2206         streamCallback = BlockingIoPaCallback; /* Setup PA to use the ASIO blocking i/o callback. */
   2207         userData       = &theAsioStream;       /* The callback user data will be the PA ASIO stream. */
   2208         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
   2209                                                &asioHostApi->blockingStreamInterface, streamCallback, userData );
   2210     }
   2211     else /* Using callback interface... */
   2212     {
   2213         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
   2214                                                &asioHostApi->callbackStreamInterface, streamCallback, userData );
   2215     }
   2216 
   2217 
   2218     PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
   2219 
   2220 
   2221     stream->asioBufferInfos = (ASIOBufferInfo*)PaUtil_AllocateMemory(
   2222             sizeof(ASIOBufferInfo) * (inputChannelCount + outputChannelCount) );
   2223     if( !stream->asioBufferInfos )
   2224     {
   2225         result = paInsufficientMemory;
   2226         PA_DEBUG(("OpenStream ERROR7\n"));
   2227         goto error;
   2228     }
   2229 
   2230 
   2231     for( i=0; i < inputChannelCount; ++i )
   2232     {
   2233         ASIOBufferInfo *info = &stream->asioBufferInfos[i];
   2234 
   2235         info->isInput = ASIOTrue;
   2236 
   2237         if( inputChannelSelectors ){
   2238             // inputChannelSelectors values have already been validated in
   2239             // ValidateAsioSpecificStreamInfo() above
   2240             info->channelNum = inputChannelSelectors[i];
   2241         }else{
   2242             info->channelNum = i;
   2243         }
   2244 
   2245         info->buffers[0] = info->buffers[1] = 0;
   2246     }
   2247 
   2248     for( i=0; i < outputChannelCount; ++i ){
   2249         ASIOBufferInfo *info = &stream->asioBufferInfos[inputChannelCount+i];
   2250 
   2251         info->isInput = ASIOFalse;
   2252 
   2253         if( outputChannelSelectors ){
   2254             // outputChannelSelectors values have already been validated in
   2255             // ValidateAsioSpecificStreamInfo() above
   2256             info->channelNum = outputChannelSelectors[i];
   2257         }else{
   2258             info->channelNum = i;
   2259         }
   2260         
   2261         info->buffers[0] = info->buffers[1] = 0;
   2262     }
   2263 
   2264 
   2265     /* Using blocking i/o interface... */
   2266     if( usingBlockingIo )
   2267     {
   2268 /** @todo REVIEW selection of host buffer size for blocking i/o */
   2269 
   2270         framesPerHostBuffer = SelectHostBufferSize( 0, framesPerBuffer, driverInfo );
   2271 
   2272     }
   2273     else /* Using callback interface... */
   2274     {
   2275         /* Select the host buffer size based on user framesPerBuffer and the
   2276            maximum of suggestedInputLatencyFrames and 
   2277            suggestedOutputLatencyFrames.
   2278 
   2279            We should subtract any fixed known driver latency from 
   2280            suggestedLatencyFrames before computing the host buffer size.
   2281            However, the ASIO API doesn't provide a method for determining fixed 
   2282            latencies independent of the host buffer size. ASIOGetLatencies()  
   2283            only returns latencies after the buffer size has been configured, so 
   2284            we can't reliably use it to determine fixed latencies here.
   2285 
   2286            We could set the preferred buffer size and then subtract it from
   2287            the values returned from ASIOGetLatencies, but this would not be 100%
   2288            reliable, so we don't do it.
   2289         */
   2290 
   2291         unsigned long targetBufferingLatencyFrames = 
   2292                 (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames )
   2293                 ? suggestedInputLatencyFrames 
   2294                 : suggestedOutputLatencyFrames);
   2295 
   2296         framesPerHostBuffer = SelectHostBufferSize( targetBufferingLatencyFrames, 
   2297                 framesPerBuffer, driverInfo );
   2298     }
   2299 
   2300 
   2301     PA_DEBUG(("PaAsioOpenStream: framesPerHostBuffer :%d\n",  framesPerHostBuffer));
   2302 
   2303     asioError = ASIOCreateBuffers( stream->asioBufferInfos,
   2304             inputChannelCount+outputChannelCount,
   2305             framesPerHostBuffer, &asioCallbacks_ );
   2306 
   2307     if( asioError != ASE_OK
   2308             && framesPerHostBuffer != (unsigned long)driverInfo->bufferPreferredSize )
   2309     {
   2310         PA_DEBUG(("ERROR: ASIOCreateBuffers: %s\n", PaAsio_GetAsioErrorText(asioError) ));
   2311         /*
   2312             Some buggy drivers (like the Hoontech DSP24) give incorrect
   2313             [min, preferred, max] values They should work with the preferred size
   2314             value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize
   2315             computed in SelectHostBufferSize, we try again with the preferred size.
   2316         */
   2317 
   2318         framesPerHostBuffer = driverInfo->bufferPreferredSize;
   2319 
   2320         PA_DEBUG(("PaAsioOpenStream: CORRECTED framesPerHostBuffer :%d\n",  framesPerHostBuffer));
   2321 
   2322         ASIOError asioError2 = ASIOCreateBuffers( stream->asioBufferInfos,
   2323                 inputChannelCount+outputChannelCount,
   2324                  framesPerHostBuffer, &asioCallbacks_ );
   2325         if( asioError2 == ASE_OK )
   2326             asioError = ASE_OK;
   2327     }
   2328 
   2329     if( asioError != ASE_OK )
   2330     {
   2331         result = paUnanticipatedHostError;
   2332         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   2333         PA_DEBUG(("OpenStream ERROR9\n"));
   2334         goto error;
   2335     }
   2336 
   2337     asioBuffersCreated = 1;
   2338 
   2339     stream->asioChannelInfos = (ASIOChannelInfo*)PaUtil_AllocateMemory(
   2340             sizeof(ASIOChannelInfo) * (inputChannelCount + outputChannelCount) );
   2341     if( !stream->asioChannelInfos )
   2342     {
   2343         result = paInsufficientMemory;
   2344         PA_DEBUG(("OpenStream ERROR10\n"));
   2345         goto error;
   2346     }
   2347 
   2348     for( i=0; i < inputChannelCount + outputChannelCount; ++i )
   2349     {
   2350         stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum;
   2351         stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput;
   2352         asioError = ASIOGetChannelInfo( &stream->asioChannelInfos[i] );
   2353         if( asioError != ASE_OK )
   2354         {
   2355             result = paUnanticipatedHostError;
   2356             PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   2357             PA_DEBUG(("OpenStream ERROR11\n"));
   2358             goto error;
   2359         }
   2360     }
   2361 
   2362     stream->bufferPtrs = (void**)PaUtil_AllocateMemory(
   2363             2 * sizeof(void*) * (inputChannelCount + outputChannelCount) );
   2364     if( !stream->bufferPtrs )
   2365     {
   2366         result = paInsufficientMemory;
   2367         PA_DEBUG(("OpenStream ERROR12\n"));
   2368         goto error;
   2369     }
   2370 
   2371     if( inputChannelCount > 0 )
   2372     {
   2373         stream->inputBufferPtrs[0] = stream-> bufferPtrs;
   2374         stream->inputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount];
   2375 
   2376         for( i=0; i<inputChannelCount; ++i )
   2377         {
   2378             stream->inputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0];
   2379             stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1];
   2380         }
   2381     }
   2382     else
   2383     {
   2384         stream->inputBufferPtrs[0] = 0;
   2385         stream->inputBufferPtrs[1] = 0;
   2386     }
   2387 
   2388     if( outputChannelCount > 0 )
   2389     {
   2390         stream->outputBufferPtrs[0] = &stream->bufferPtrs[inputChannelCount*2];
   2391         stream->outputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount*2 + outputChannelCount];
   2392 
   2393         for( i=0; i<outputChannelCount; ++i )
   2394         {
   2395             stream->outputBufferPtrs[0][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[0];
   2396             stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[1];
   2397         }
   2398     }
   2399     else
   2400     {
   2401         stream->outputBufferPtrs[0] = 0;
   2402         stream->outputBufferPtrs[1] = 0;
   2403     }
   2404 
   2405     if( inputChannelCount > 0 )
   2406     {
   2407         /* FIXME: assume all channels use the same type for now 
   2408         
   2409             see: "ASIO devices with multiple sample formats are unsupported"
   2410             http://www.portaudio.com/trac/ticket/106
   2411         */
   2412         ASIOSampleType inputType = stream->asioChannelInfos[0].type;
   2413 
   2414         PA_DEBUG(("ASIO Input  type:%d",inputType));
   2415         AsioSampleTypeLOG(inputType);
   2416         hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( inputType );
   2417 
   2418         SelectAsioToPaConverter( inputType, &stream->inputBufferConverter, &stream->inputShift );
   2419     }
   2420     else
   2421     {
   2422         hostInputSampleFormat = 0;
   2423         stream->inputBufferConverter = 0;
   2424     }
   2425 
   2426     if( outputChannelCount > 0 )
   2427     {
   2428         /* FIXME: assume all channels use the same type for now 
   2429         
   2430             see: "ASIO devices with multiple sample formats are unsupported"
   2431             http://www.portaudio.com/trac/ticket/106
   2432         */
   2433         ASIOSampleType outputType = stream->asioChannelInfos[inputChannelCount].type;
   2434 
   2435         PA_DEBUG(("ASIO Output type:%d",outputType));
   2436         AsioSampleTypeLOG(outputType);
   2437         hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( outputType );
   2438 
   2439         SelectPaToAsioConverter( outputType, &stream->outputBufferConverter, &stream->outputShift );
   2440     }
   2441     else
   2442     {
   2443         hostOutputSampleFormat = 0;
   2444         stream->outputBufferConverter = 0;
   2445     }
   2446 
   2447     /* Values returned by ASIOGetLatencies() include the latency introduced by 
   2448        the ASIO double buffer. */
   2449     ASIOGetLatencies( &stream->asioInputLatencyFrames, &stream->asioOutputLatencyFrames );
   2450 
   2451 
   2452     /* Using blocking i/o interface... */
   2453     if( usingBlockingIo )
   2454     {
   2455         /* Allocate the blocking i/o input ring buffer memory. */
   2456         stream->blockingState = (PaAsioStreamBlockingState*)PaUtil_AllocateMemory( sizeof(PaAsioStreamBlockingState) );
   2457         if( !stream->blockingState )
   2458         {
   2459             result = paInsufficientMemory;
   2460             PA_DEBUG(("ERROR! Blocking i/o interface struct allocation failed in OpenStream()\n"));
   2461             goto error;
   2462         }
   2463 
   2464         /* Initialize blocking i/o interface struct. */
   2465         stream->blockingState->readFramesReadyEvent   = NULL; /* Uninitialized, yet. */
   2466         stream->blockingState->writeBuffersReadyEvent = NULL; /* Uninitialized, yet. */
   2467         stream->blockingState->readRingBufferData     = NULL; /* Uninitialized, yet. */
   2468         stream->blockingState->writeRingBufferData    = NULL; /* Uninitialized, yet. */
   2469         stream->blockingState->readStreamBuffer       = NULL; /* Uninitialized, yet. */
   2470         stream->blockingState->writeStreamBuffer      = NULL; /* Uninitialized, yet. */
   2471         stream->blockingState->stopFlag               = TRUE; /* Not started, yet. */
   2472 
   2473 
   2474         /* If the user buffer is unspecified */
   2475         if( framesPerBuffer == paFramesPerBufferUnspecified )
   2476         {
   2477             /* Make the user buffer the same size as the host buffer. */
   2478             framesPerBuffer = framesPerHostBuffer;
   2479         }
   2480 
   2481 
   2482         /* Initialize callback buffer processor. */
   2483         result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor               ,
   2484                                                     inputChannelCount                     ,
   2485                                                     inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
   2486                                                     (hostInputSampleFormat | paNonInterleaved), /* Host format. */
   2487                                                     outputChannelCount                    ,
   2488                                                     outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
   2489                                                     (hostOutputSampleFormat | paNonInterleaved), /* Host format. */
   2490                                                     sampleRate                            ,
   2491                                                     streamFlags                           ,
   2492                                                     framesPerBuffer                       , /* Frames per ring buffer block. */
   2493                                                     framesPerHostBuffer                   , /* Frames per asio buffer. */
   2494                                                     paUtilFixedHostBufferSize             ,
   2495                                                     streamCallback                        ,
   2496                                                     userData                               );
   2497         if( result != paNoError ){
   2498             PA_DEBUG(("OpenStream ERROR13\n"));
   2499             goto error;
   2500         }
   2501         callbackBufferProcessorInited = TRUE;
   2502 
   2503         /* Initialize the blocking i/o buffer processor. */
   2504         result = PaUtil_InitializeBufferProcessor(&stream->blockingState->bufferProcessor,
   2505                                                    inputChannelCount                     ,
   2506                                                    inputSampleFormat                     , /* User format. */
   2507                                                    inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
   2508                                                    outputChannelCount                    ,
   2509                                                    outputSampleFormat                    , /* User format. */
   2510                                                    outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
   2511                                                    sampleRate                            ,
   2512                                                    paClipOff | paDitherOff               , /* Don't use dither nor clipping. */
   2513                                                    framesPerBuffer                       , /* Frames per user buffer. */
   2514                                                    framesPerBuffer                       , /* Frames per ring buffer block. */
   2515                                                    paUtilBoundedHostBufferSize           ,
   2516                                                    NULL, NULL                            );/* No callback! */
   2517         if( result != paNoError ){
   2518             PA_DEBUG(("ERROR! Blocking i/o buffer processor initialization failed in OpenStream()\n"));
   2519             goto error;
   2520         }
   2521         blockingBufferProcessorInited = TRUE;
   2522 
   2523         /* If input is requested. */
   2524         if( inputChannelCount )
   2525         {
   2526             /* Create the callback sync-event. */
   2527             stream->blockingState->readFramesReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   2528             if( stream->blockingState->readFramesReadyEvent == NULL )
   2529             {
   2530                 result = paUnanticipatedHostError;
   2531                 PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
   2532                 PA_DEBUG(("ERROR! Blocking i/o \"read frames ready\" event creation failed in OpenStream()\n"));
   2533                 goto error;
   2534             }
   2535             blockingReadFramesReadyEventInitialized = 1;
   2536 
   2537 
   2538             /* Create pointer buffer to access non-interleaved data in ReadStream() */
   2539             stream->blockingState->readStreamBuffer = (void**)PaUtil_AllocateMemory( sizeof(void*) * inputChannelCount );
   2540             if( !stream->blockingState->readStreamBuffer )
   2541             {
   2542                 result = paInsufficientMemory;
   2543                 PA_DEBUG(("ERROR! Blocking i/o read stream buffer allocation failed in OpenStream()\n"));
   2544                 goto error;
   2545             }
   2546 
   2547             /* The ring buffer should store as many data blocks as needed
   2548                to achieve the requested latency. Whereas it must be large
   2549                enough to store at least two complete data blocks.
   2550 
   2551                1) Determine the amount of latency to be added to the
   2552                   prefered ASIO latency.
   2553                2) Make sure we have at lest one additional latency frame.
   2554                3) Divide the number of frames by the desired block size to
   2555                   get the number (rounded up to pure integer) of blocks to
   2556                   be stored in the buffer.
   2557                4) Add one additional block for block processing and convert
   2558                   to samples frames.
   2559                5) Get the next larger (or equal) power-of-two buffer size.
   2560              */
   2561             lBlockingBufferSize = suggestedInputLatencyFrames - stream->asioInputLatencyFrames;
   2562             lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
   2563             lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
   2564             lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
   2565 
   2566             /* Get the next larger or equal power-of-two buffersize. */
   2567             lBlockingBufferSizePow2 = 1;
   2568             while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) );
   2569             lBlockingBufferSize = lBlockingBufferSizePow2;
   2570 
   2571             /* Compute total intput latency in seconds */
   2572             stream->streamRepresentation.streamInfo.inputLatency =
   2573                 (double)( PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor               )
   2574                         + PaUtil_GetBufferProcessorInputLatencyFrames(&stream->blockingState->bufferProcessor)
   2575                         + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer
   2576                         + stream->asioInputLatencyFrames )
   2577                 / sampleRate;
   2578 
   2579             /* The code below prints the ASIO latency which doesn't include
   2580                the buffer processor latency nor the blocking i/o latency. It
   2581                reports the added latency separately.
   2582             */
   2583             PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms),\n         added buffProc:%ld (%ld ms),\n         added blocking:%ld (%ld ms)\n",
   2584                 stream->asioInputLatencyFrames,
   2585                 (long)( stream->asioInputLatencyFrames * (1000.0 / sampleRate) ),
   2586                 PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor),
   2587                 (long)( PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) * (1000.0 / sampleRate) ),
   2588                 PaUtil_GetBufferProcessorInputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer,
   2589                 (long)( (PaUtil_GetBufferProcessorInputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) )
   2590                 ));
   2591 
   2592             /* Determine the size of ring buffer in bytes. */
   2593             lBytesPerFrame = inputChannelCount * Pa_GetSampleSize(inputSampleFormat );
   2594 
   2595             /* Allocate the blocking i/o input ring buffer memory. */
   2596             stream->blockingState->readRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame );
   2597             if( !stream->blockingState->readRingBufferData )
   2598             {
   2599                 result = paInsufficientMemory;
   2600                 PA_DEBUG(("ERROR! Blocking i/o input ring buffer allocation failed in OpenStream()\n"));
   2601                 goto error;
   2602             }
   2603 
   2604             /* Initialize the input ring buffer struct. */
   2605             PaUtil_InitializeRingBuffer( &stream->blockingState->readRingBuffer    ,
   2606                                           lBytesPerFrame                           ,
   2607                                           lBlockingBufferSize                      ,
   2608                                           stream->blockingState->readRingBufferData );
   2609         }
   2610 
   2611         /* If output is requested. */
   2612         if( outputChannelCount )
   2613         {
   2614             stream->blockingState->writeBuffersReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
   2615             if( stream->blockingState->writeBuffersReadyEvent == NULL )
   2616             {
   2617                 result = paUnanticipatedHostError;
   2618                 PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
   2619                 PA_DEBUG(("ERROR! Blocking i/o \"write buffers ready\" event creation failed in OpenStream()\n"));
   2620                 goto error;
   2621             }
   2622             blockingWriteBuffersReadyEventInitialized = 1;
   2623 
   2624             /* Create pointer buffer to access non-interleaved data in WriteStream() */
   2625             stream->blockingState->writeStreamBuffer = (const void**)PaUtil_AllocateMemory( sizeof(const void*) * outputChannelCount );
   2626             if( !stream->blockingState->writeStreamBuffer )
   2627             {
   2628                 result = paInsufficientMemory;
   2629                 PA_DEBUG(("ERROR! Blocking i/o write stream buffer allocation failed in OpenStream()\n"));
   2630                 goto error;
   2631             }
   2632 
   2633             /* The ring buffer should store as many data blocks as needed
   2634                to achieve the requested latency. Whereas it must be large
   2635                enough to store at least two complete data blocks.
   2636 
   2637                1) Determine the amount of latency to be added to the
   2638                   prefered ASIO latency.
   2639                2) Make sure we have at lest one additional latency frame.
   2640                3) Divide the number of frames by the desired block size to
   2641                   get the number (rounded up to pure integer) of blocks to
   2642                   be stored in the buffer.
   2643                4) Add one additional block for block processing and convert
   2644                   to samples frames.
   2645                5) Get the next larger (or equal) power-of-two buffer size.
   2646              */
   2647             lBlockingBufferSize = suggestedOutputLatencyFrames - stream->asioOutputLatencyFrames;
   2648             lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
   2649             lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
   2650             lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
   2651 
   2652             /* The buffer size (without the additional block) corresponds
   2653                to the initial number of silent samples in the output ring
   2654                buffer. */
   2655             stream->blockingState->writeRingBufferInitialFrames = lBlockingBufferSize - framesPerBuffer;
   2656 
   2657             /* Get the next larger or equal power-of-two buffersize. */
   2658             lBlockingBufferSizePow2 = 1;
   2659             while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) );
   2660             lBlockingBufferSize = lBlockingBufferSizePow2;
   2661 
   2662             /* Compute total output latency in seconds */
   2663             stream->streamRepresentation.streamInfo.outputLatency =
   2664                 (double)( PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)
   2665                         + PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->blockingState->bufferProcessor)
   2666                         + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer
   2667                         + stream->asioOutputLatencyFrames )
   2668                 / sampleRate;
   2669 
   2670             /* The code below prints the ASIO latency which doesn't include
   2671                the buffer processor latency nor the blocking i/o latency. It
   2672                reports the added latency separately.
   2673             */
   2674             PA_DEBUG(("PaAsio : ASIO OutputLatency = %ld (%ld ms),\n         added buffProc:%ld (%ld ms),\n         added blocking:%ld (%ld ms)\n",
   2675                 stream->asioOutputLatencyFrames,
   2676                 (long)( stream->asioOutputLatencyFrames * (1000.0 / sampleRate) ),
   2677                 PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor),
   2678                 (long)( PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) * (1000.0 / sampleRate) ),
   2679                 PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer,
   2680                 (long)( (PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) )
   2681                 ));
   2682 
   2683             /* Determine the size of ring buffer in bytes. */
   2684             lBytesPerFrame = outputChannelCount * Pa_GetSampleSize(outputSampleFormat);
   2685 
   2686             /* Allocate the blocking i/o output ring buffer memory. */
   2687             stream->blockingState->writeRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame );
   2688             if( !stream->blockingState->writeRingBufferData )
   2689             {
   2690                 result = paInsufficientMemory;
   2691                 PA_DEBUG(("ERROR! Blocking i/o output ring buffer allocation failed in OpenStream()\n"));
   2692                 goto error;
   2693             }
   2694 
   2695             /* Initialize the output ring buffer struct. */
   2696             PaUtil_InitializeRingBuffer( &stream->blockingState->writeRingBuffer    ,
   2697                                           lBytesPerFrame                            ,
   2698                                           lBlockingBufferSize                       ,
   2699                                           stream->blockingState->writeRingBufferData );
   2700         }
   2701 
   2702         stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
   2703 
   2704 
   2705     }
   2706     else /* Using callback interface... */
   2707     {
   2708         result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
   2709                         inputChannelCount, inputSampleFormat, (hostInputSampleFormat | paNonInterleaved),
   2710                         outputChannelCount, outputSampleFormat, (hostOutputSampleFormat | paNonInterleaved),
   2711                         sampleRate, streamFlags, framesPerBuffer,
   2712                         framesPerHostBuffer, paUtilFixedHostBufferSize,
   2713                         streamCallback, userData );
   2714         if( result != paNoError ){
   2715             PA_DEBUG(("OpenStream ERROR13\n"));
   2716             goto error;
   2717         }
   2718         callbackBufferProcessorInited = TRUE;
   2719 
   2720         stream->streamRepresentation.streamInfo.inputLatency =
   2721                 (double)( PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor)
   2722                     + stream->asioInputLatencyFrames) / sampleRate;   // seconds
   2723         stream->streamRepresentation.streamInfo.outputLatency =
   2724                 (double)( PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)
   2725                     + stream->asioOutputLatencyFrames) / sampleRate; // seconds
   2726         stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
   2727 
   2728         // the code below prints the ASIO latency which doesn't include the
   2729         // buffer processor latency. it reports the added latency separately
   2730         PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
   2731                 stream->asioInputLatencyFrames,
   2732                 (long)((stream->asioInputLatencyFrames*1000)/ sampleRate),  
   2733                 PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor),
   2734                 (long)((PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor)*1000)/ sampleRate)
   2735                 ));
   2736 
   2737         PA_DEBUG(("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
   2738                 stream->asioOutputLatencyFrames,
   2739                 (long)((stream->asioOutputLatencyFrames*1000)/ sampleRate), 
   2740                 PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor),
   2741                 (long)((PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)*1000)/ sampleRate)
   2742                 ));
   2743     }
   2744 
   2745     stream->asioHostApi = asioHostApi;
   2746     stream->framesPerHostCallback = framesPerHostBuffer;
   2747 
   2748     stream->inputChannelCount = inputChannelCount;
   2749     stream->outputChannelCount = outputChannelCount;
   2750     stream->postOutput = driverInfo->postOutput;
   2751     stream->isStopped = 1;
   2752     stream->isActive = 0;
   2753     
   2754     asioHostApi->openAsioDeviceIndex = asioDeviceIndex;
   2755 
   2756     theAsioStream = stream;
   2757     *s = (PaStream*)stream;
   2758 
   2759     return result;
   2760 
   2761 error:
   2762     PA_DEBUG(("goto errored\n"));
   2763     if( stream )
   2764     {
   2765         if( stream->blockingState )
   2766         {
   2767             if( blockingBufferProcessorInited )
   2768                 PaUtil_TerminateBufferProcessor( &stream->blockingState->bufferProcessor );
   2769 
   2770             if( stream->blockingState->writeRingBufferData )
   2771                 PaUtil_FreeMemory( stream->blockingState->writeRingBufferData );
   2772             if( stream->blockingState->writeStreamBuffer )
   2773                 PaUtil_FreeMemory( stream->blockingState->writeStreamBuffer );
   2774             if( blockingWriteBuffersReadyEventInitialized )
   2775                 CloseHandle( stream->blockingState->writeBuffersReadyEvent );
   2776 
   2777             if( stream->blockingState->readRingBufferData )
   2778                 PaUtil_FreeMemory( stream->blockingState->readRingBufferData );
   2779             if( stream->blockingState->readStreamBuffer )
   2780                 PaUtil_FreeMemory( stream->blockingState->readStreamBuffer );
   2781             if( blockingReadFramesReadyEventInitialized )
   2782                 CloseHandle( stream->blockingState->readFramesReadyEvent );
   2783 
   2784             PaUtil_FreeMemory( stream->blockingState );
   2785         }
   2786 
   2787         if( callbackBufferProcessorInited )
   2788             PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
   2789 
   2790         if( completedBuffersPlayedEventInited )
   2791             CloseHandle( stream->completedBuffersPlayedEvent );
   2792 
   2793         if( stream->asioBufferInfos )
   2794             PaUtil_FreeMemory( stream->asioBufferInfos );
   2795 
   2796         if( stream->asioChannelInfos )
   2797             PaUtil_FreeMemory( stream->asioChannelInfos );
   2798 
   2799         if( stream->bufferPtrs )
   2800             PaUtil_FreeMemory( stream->bufferPtrs );
   2801 
   2802         PaUtil_FreeMemory( stream );
   2803     }
   2804 
   2805     if( asioBuffersCreated )
   2806         ASIODisposeBuffers();
   2807 
   2808     if( asioIsInitialized )
   2809 	{
   2810 		UnloadAsioDriver();
   2811 	}
   2812     return result;
   2813 }
   2814 
   2815 
   2816 /*
   2817     When CloseStream() is called, the multi-api layer ensures that
   2818     the stream has already been stopped or aborted.
   2819 */
   2820 static PaError CloseStream( PaStream* s )
   2821 {
   2822     PaError result = paNoError;
   2823     PaAsioStream *stream = (PaAsioStream*)s;
   2824 
   2825     /*
   2826         IMPLEMENT ME:
   2827             - additional stream closing + cleanup
   2828     */
   2829 
   2830     PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
   2831     PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
   2832 
   2833     stream->asioHostApi->openAsioDeviceIndex = paNoDevice;
   2834 
   2835     CloseHandle( stream->completedBuffersPlayedEvent );
   2836 
   2837     /* Using blocking i/o interface... */
   2838     if( stream->blockingState )
   2839     {
   2840         PaUtil_TerminateBufferProcessor( &stream->blockingState->bufferProcessor );
   2841 
   2842         if( stream->inputChannelCount ) {
   2843             PaUtil_FreeMemory( stream->blockingState->readRingBufferData );
   2844             PaUtil_FreeMemory( stream->blockingState->readStreamBuffer  );
   2845             CloseHandle( stream->blockingState->readFramesReadyEvent );
   2846         }
   2847         if( stream->outputChannelCount ) {
   2848             PaUtil_FreeMemory( stream->blockingState->writeRingBufferData );
   2849             PaUtil_FreeMemory( stream->blockingState->writeStreamBuffer );
   2850             CloseHandle( stream->blockingState->writeBuffersReadyEvent );
   2851         }
   2852 
   2853         PaUtil_FreeMemory( stream->blockingState );
   2854     }
   2855 
   2856     PaUtil_FreeMemory( stream->asioBufferInfos );
   2857     PaUtil_FreeMemory( stream->asioChannelInfos );
   2858     PaUtil_FreeMemory( stream->bufferPtrs );
   2859     PaUtil_FreeMemory( stream );
   2860 
   2861     ASIODisposeBuffers();
   2862     UnloadAsioDriver();
   2863 
   2864     theAsioStream = 0;
   2865 
   2866     return result;
   2867 }
   2868 
   2869 
   2870 static void bufferSwitch(long index, ASIOBool directProcess)
   2871 {
   2872 //TAKEN FROM THE ASIO SDK
   2873 
   2874     // the actual processing callback.
   2875     // Beware that this is normally in a seperate thread, hence be sure that
   2876     // you take care about thread synchronization. This is omitted here for
   2877     // simplicity.
   2878 
   2879     // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
   2880     // to be created though it will only set the timeInfo.samplePosition and
   2881     // timeInfo.systemTime fields and the according flags
   2882 
   2883     ASIOTime  timeInfo;
   2884     memset( &timeInfo, 0, sizeof (timeInfo) );
   2885 
   2886     // get the time stamp of the buffer, not necessary if no
   2887     // synchronization to other media is required
   2888     if( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
   2889             timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
   2890 
   2891     // Call the real callback
   2892     bufferSwitchTimeInfo( &timeInfo, index, directProcess );
   2893 }
   2894 
   2895 
   2896 // conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
   2897 #if NATIVE_INT64
   2898     #define ASIO64toDouble(a)  (a)
   2899 #else
   2900     const double twoRaisedTo32 = 4294967296.;
   2901     #define ASIO64toDouble(a)  ((a).lo + (a).hi * twoRaisedTo32)
   2902 #endif
   2903 
   2904 static ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool directProcess )
   2905 {
   2906     // the actual processing callback.
   2907     // Beware that this is normally in a seperate thread, hence be sure that
   2908     // you take care about thread synchronization.
   2909 
   2910 
   2911     /* The SDK says the following about the directProcess flag:
   2912         suggests to the host whether it should immediately start processing
   2913         (directProcess == ASIOTrue), or whether its process should be deferred
   2914         because the call comes from a very low level (for instance, a high level
   2915         priority interrupt), and direct processing would cause timing instabilities for
   2916         the rest of the system. If in doubt, directProcess should be set to ASIOFalse.
   2917 
   2918         We just ignore directProcess. This could cause incompatibilities with
   2919         drivers which really don't want the audio processing to occur in this
   2920         callback, but none have been identified yet.
   2921     */
   2922 
   2923     (void) directProcess; /* suppress unused parameter warning */
   2924 
   2925 #if 0
   2926     // store the timeInfo for later use
   2927     asioDriverInfo.tInfo = *timeInfo;
   2928 
   2929     // get the time stamp of the buffer, not necessary if no
   2930     // synchronization to other media is required
   2931 
   2932     if (timeInfo->timeInfo.flags & kSystemTimeValid)
   2933             asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
   2934     else
   2935             asioDriverInfo.nanoSeconds = 0;
   2936 
   2937     if (timeInfo->timeInfo.flags & kSamplePositionValid)
   2938             asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
   2939     else
   2940             asioDriverInfo.samples = 0;
   2941 
   2942     if (timeInfo->timeCode.flags & kTcValid)
   2943             asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
   2944     else
   2945             asioDriverInfo.tcSamples = 0;
   2946 
   2947     // get the system reference time
   2948     asioDriverInfo.sysRefTime = get_sys_reference_time();
   2949 #endif
   2950 
   2951 #if 0
   2952     // a few debug messages for the Windows device driver developer
   2953     // tells you the time when driver got its interrupt and the delay until the app receives
   2954     // the event notification.
   2955     static double last_samples = 0;
   2956     char tmp[128];
   2957     sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples                 \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
   2958     OutputDebugString (tmp);
   2959     last_samples = asioDriverInfo.samples;
   2960 #endif
   2961 
   2962 
   2963     if( !theAsioStream )
   2964         return 0L;
   2965 
   2966     // protect against reentrancy
   2967     if( PaAsio_AtomicIncrement(&theAsioStream->reenterCount) )
   2968     {
   2969         theAsioStream->reenterError++;
   2970         //DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError));
   2971         return 0L;
   2972     }
   2973 
   2974     int buffersDone = 0;
   2975     
   2976     do
   2977     {
   2978         if( buffersDone > 0 )
   2979         {
   2980             // this is a reentered buffer, we missed processing it on time
   2981             // set the input overflow and output underflow flags as appropriate
   2982             
   2983             if( theAsioStream->inputChannelCount > 0 )
   2984                 theAsioStream->callbackFlags |= paInputOverflow;
   2985                 
   2986             if( theAsioStream->outputChannelCount > 0 )
   2987                 theAsioStream->callbackFlags |= paOutputUnderflow;
   2988         }
   2989         else
   2990         {
   2991             if( theAsioStream->zeroOutput )
   2992             {
   2993                 ZeroOutputBuffers( theAsioStream, index );
   2994 
   2995                 // Finally if the driver supports the ASIOOutputReady() optimization,
   2996                 // do it here, all data are in place
   2997                 if( theAsioStream->postOutput )
   2998                     ASIOOutputReady();
   2999 
   3000                 if( theAsioStream->stopProcessing )
   3001                 {
   3002                     if( theAsioStream->stopPlayoutCount < 2 )
   3003                     {
   3004                         ++theAsioStream->stopPlayoutCount;
   3005                         if( theAsioStream->stopPlayoutCount == 2 )
   3006                         {
   3007                             theAsioStream->isActive = 0;
   3008                             if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
   3009                                 theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
   3010                             theAsioStream->streamFinishedCallbackCalled = true;
   3011                             SetEvent( theAsioStream->completedBuffersPlayedEvent );
   3012                         }
   3013                     }
   3014                 }
   3015             }
   3016             else
   3017             {
   3018 
   3019 #if 0
   3020 /*
   3021     see: "ASIO callback underflow/overflow buffer slip detection doesn't work"
   3022     http://www.portaudio.com/trac/ticket/110
   3023 */
   3024 
   3025 // test code to try to detect slip conditions... these may work on some systems
   3026 // but neither of them work on the RME Digi96
   3027 
   3028 // check that sample delta matches buffer size (otherwise we must have skipped
   3029 // a buffer.
   3030 static double last_samples = -512;
   3031 double samples;
   3032 //if( timeInfo->timeCode.flags & kTcValid )
   3033 //    samples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
   3034 //else
   3035     samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
   3036 int delta = samples - last_samples;
   3037 //printf( "%d\n", delta);
   3038 last_samples = samples;
   3039 
   3040 if( delta > theAsioStream->framesPerHostCallback )
   3041 {
   3042     if( theAsioStream->inputChannelCount > 0 )
   3043         theAsioStream->callbackFlags |= paInputOverflow;
   3044 
   3045     if( theAsioStream->outputChannelCount > 0 )
   3046         theAsioStream->callbackFlags |= paOutputUnderflow;
   3047 }
   3048 
   3049 // check that the buffer index is not the previous index (which would indicate
   3050 // that a buffer was skipped.
   3051 static int previousIndex = 1;
   3052 if( index == previousIndex )
   3053 {
   3054     if( theAsioStream->inputChannelCount > 0 )
   3055         theAsioStream->callbackFlags |= paInputOverflow;
   3056 
   3057     if( theAsioStream->outputChannelCount > 0 )
   3058         theAsioStream->callbackFlags |= paOutputUnderflow;
   3059 }
   3060 previousIndex = index;
   3061 #endif
   3062 
   3063                 int i;
   3064 
   3065                 PaUtil_BeginCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer );
   3066 
   3067                 PaStreamCallbackTimeInfo paTimeInfo;
   3068 
   3069                 // asio systemTime is supposed to be measured according to the same
   3070                 // clock as timeGetTime
   3071                 paTimeInfo.currentTime = (ASIO64toDouble( timeInfo->timeInfo.systemTime ) * .000000001);
   3072 
   3073                 /* patch from Paul Boege */
   3074                 paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime -
   3075                     ((double)theAsioStream->asioInputLatencyFrames/theAsioStream->streamRepresentation.streamInfo.sampleRate);
   3076 
   3077                 paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime +
   3078                     ((double)theAsioStream->asioOutputLatencyFrames/theAsioStream->streamRepresentation.streamInfo.sampleRate);
   3079 
   3080                 /* old version is buggy because the buffer processor also adds in its latency to the time parameters
   3081                 paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency;
   3082                 paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency;
   3083                 */
   3084 
   3085 /* Disabled! Stopping and re-starting the stream causes an input overflow / output underflow. S.Fischer */
   3086 #if 0
   3087 // detect underflows by checking inter-callback time > 2 buffer period
   3088 static double previousTime = -1;
   3089 if( previousTime > 0 ){
   3090 
   3091     double delta = paTimeInfo.currentTime - previousTime;
   3092 
   3093     if( delta >= 2. * (theAsioStream->framesPerHostCallback / theAsioStream->streamRepresentation.streamInfo.sampleRate) ){
   3094         if( theAsioStream->inputChannelCount > 0 )
   3095             theAsioStream->callbackFlags |= paInputOverflow;
   3096 
   3097         if( theAsioStream->outputChannelCount > 0 )
   3098             theAsioStream->callbackFlags |= paOutputUnderflow;
   3099     }
   3100 }
   3101 previousTime = paTimeInfo.currentTime;
   3102 #endif
   3103 
   3104                 // note that the above input and output times do not need to be
   3105                 // adjusted for the latency of the buffer processor -- the buffer
   3106                 // processor handles that.
   3107 
   3108                 if( theAsioStream->inputBufferConverter )
   3109                 {
   3110                     for( i=0; i<theAsioStream->inputChannelCount; i++ )
   3111                     {
   3112                         theAsioStream->inputBufferConverter( theAsioStream->inputBufferPtrs[index][i],
   3113                                 theAsioStream->inputShift, theAsioStream->framesPerHostCallback );
   3114                     }
   3115                 }
   3116 
   3117                 PaUtil_BeginBufferProcessing( &theAsioStream->bufferProcessor, &paTimeInfo, theAsioStream->callbackFlags );
   3118 
   3119                 /* reset status flags once they've been passed to the callback */
   3120                 theAsioStream->callbackFlags = 0;
   3121 
   3122                 PaUtil_SetInputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
   3123                 for( i=0; i<theAsioStream->inputChannelCount; ++i )
   3124                     PaUtil_SetNonInterleavedInputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i] );
   3125 
   3126                 PaUtil_SetOutputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
   3127                 for( i=0; i<theAsioStream->outputChannelCount; ++i )
   3128                     PaUtil_SetNonInterleavedOutputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i] );
   3129 
   3130                 int callbackResult;
   3131                 if( theAsioStream->stopProcessing )
   3132                     callbackResult = paComplete;
   3133                 else
   3134                     callbackResult = paContinue;
   3135                 unsigned long framesProcessed = PaUtil_EndBufferProcessing( &theAsioStream->bufferProcessor, &callbackResult );
   3136 
   3137                 if( theAsioStream->outputBufferConverter )
   3138                 {
   3139                     for( i=0; i<theAsioStream->outputChannelCount; i++ )
   3140                     {
   3141                         theAsioStream->outputBufferConverter( theAsioStream->outputBufferPtrs[index][i],
   3142                                 theAsioStream->outputShift, theAsioStream->framesPerHostCallback );
   3143                     }
   3144                 }
   3145 
   3146                 PaUtil_EndCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer, framesProcessed );
   3147 
   3148                 // Finally if the driver supports the ASIOOutputReady() optimization,
   3149                 // do it here, all data are in place
   3150                 if( theAsioStream->postOutput )
   3151                     ASIOOutputReady();
   3152 
   3153                 if( callbackResult == paContinue )
   3154                 {
   3155                     /* nothing special to do */
   3156                 }
   3157                 else if( callbackResult == paAbort )
   3158                 {
   3159                     /* finish playback immediately  */
   3160                     theAsioStream->isActive = 0;
   3161                     if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
   3162                         theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
   3163                     theAsioStream->streamFinishedCallbackCalled = true;
   3164                     SetEvent( theAsioStream->completedBuffersPlayedEvent );
   3165                     theAsioStream->zeroOutput = true;
   3166                 }
   3167                 else /* paComplete or other non-zero value indicating complete */
   3168                 {
   3169                     /* Finish playback once currently queued audio has completed. */
   3170                     theAsioStream->stopProcessing = true;
   3171 
   3172                     if( PaUtil_IsBufferProcessorOutputEmpty( &theAsioStream->bufferProcessor ) )
   3173                     {
   3174                         theAsioStream->zeroOutput = true;
   3175                         theAsioStream->stopPlayoutCount = 0;
   3176                     }
   3177                 }
   3178             }
   3179         }
   3180         
   3181         ++buffersDone;
   3182     }while( PaAsio_AtomicDecrement(&theAsioStream->reenterCount) >= 0 );
   3183 
   3184     return 0L;
   3185 }
   3186 
   3187 
   3188 static void sampleRateChanged(ASIOSampleRate sRate)
   3189 {
   3190     // TAKEN FROM THE ASIO SDK
   3191     // do whatever you need to do if the sample rate changed
   3192     // usually this only happens during external sync.
   3193     // Audio processing is not stopped by the driver, actual sample rate
   3194     // might not have even changed, maybe only the sample rate status of an
   3195     // AES/EBU or S/PDIF digital input at the audio device.
   3196     // You might have to update time/sample related conversion routines, etc.
   3197 
   3198     (void) sRate; /* unused parameter */
   3199     PA_DEBUG( ("sampleRateChanged : %d \n", sRate));
   3200 }
   3201 
   3202 static long asioMessages(long selector, long value, void* message, double* opt)
   3203 {
   3204 // TAKEN FROM THE ASIO SDK
   3205     // currently the parameters "value", "message" and "opt" are not used.
   3206     long ret = 0;
   3207 
   3208     (void) message; /* unused parameters */
   3209     (void) opt;
   3210 
   3211     PA_DEBUG( ("asioMessages : %d , %d \n", selector, value));
   3212 
   3213     switch(selector)
   3214     {
   3215         case kAsioSelectorSupported:
   3216             if(value == kAsioResetRequest
   3217             || value == kAsioEngineVersion
   3218             || value == kAsioResyncRequest
   3219             || value == kAsioLatenciesChanged
   3220             // the following three were added for ASIO 2.0, you don't necessarily have to support them
   3221             || value == kAsioSupportsTimeInfo
   3222             || value == kAsioSupportsTimeCode
   3223             || value == kAsioSupportsInputMonitor)
   3224                     ret = 1L;
   3225             break;
   3226 
   3227         case kAsioBufferSizeChange:
   3228             //printf("kAsioBufferSizeChange \n");
   3229             break;
   3230 
   3231         case kAsioResetRequest:
   3232             // defer the task and perform the reset of the driver during the next "safe" situation
   3233             // You cannot reset the driver right now, as this code is called from the driver.
   3234             // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
   3235             // Afterwards you initialize the driver again.
   3236 
   3237             /*FIXME: commented the next line out
   3238 
   3239                 see: "PA/ASIO ignores some driver notifications it probably shouldn't"
   3240                 http://www.portaudio.com/trac/ticket/108
   3241             */
   3242             //asioDriverInfo.stopped;  // In this sample the processing will just stop
   3243             ret = 1L;
   3244             break;
   3245 
   3246         case kAsioResyncRequest:
   3247             // This informs the application, that the driver encountered some non fatal data loss.
   3248             // It is used for synchronization purposes of different media.
   3249             // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
   3250             // Windows Multimedia system, which could loose data because the Mutex was hold too long
   3251             // by another thread.
   3252             // However a driver can issue it in other situations, too.
   3253             ret = 1L;
   3254             break;
   3255 
   3256         case kAsioLatenciesChanged:
   3257             // This will inform the host application that the drivers were latencies changed.
   3258             // Beware, it this does not mean that the buffer sizes have changed!
   3259             // You might need to update internal delay data.
   3260             ret = 1L;
   3261             //printf("kAsioLatenciesChanged \n");
   3262             break;
   3263 
   3264         case kAsioEngineVersion:
   3265             // return the supported ASIO version of the host application
   3266             // If a host applications does not implement this selector, ASIO 1.0 is assumed
   3267             // by the driver
   3268             ret = 2L;
   3269             break;
   3270 
   3271         case kAsioSupportsTimeInfo:
   3272             // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
   3273             // is supported.
   3274             // For compatibility with ASIO 1.0 drivers the host application should always support
   3275             // the "old" bufferSwitch method, too.
   3276             ret = 1;
   3277             break;
   3278 
   3279         case kAsioSupportsTimeCode:
   3280             // informs the driver wether application is interested in time code info.
   3281             // If an application does not need to know about time code, the driver has less work
   3282             // to do.
   3283             ret = 0;
   3284             break;
   3285     }
   3286     return ret;
   3287 }
   3288 
   3289 
   3290 static PaError StartStream( PaStream *s )
   3291 {
   3292     PaError result = paNoError;
   3293     PaAsioStream *stream = (PaAsioStream*)s;
   3294     PaAsioStreamBlockingState *blockingState = stream->blockingState;
   3295     ASIOError asioError;
   3296 
   3297     if( stream->outputChannelCount > 0 )
   3298     {
   3299         ZeroOutputBuffers( stream, 0 );
   3300         ZeroOutputBuffers( stream, 1 );
   3301     }
   3302 
   3303     PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
   3304     stream->stopProcessing = false;
   3305     stream->zeroOutput = false;
   3306 
   3307     /* Reentrancy counter initialisation */
   3308     stream->reenterCount = -1;
   3309     stream->reenterError = 0;
   3310 
   3311     stream->callbackFlags = 0;
   3312 
   3313     if( ResetEvent( stream->completedBuffersPlayedEvent ) == 0 )
   3314     {
   3315         result = paUnanticipatedHostError;
   3316         PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
   3317     }
   3318 
   3319 
   3320     /* Using blocking i/o interface... */
   3321     if( blockingState )
   3322     {
   3323         /* Reset blocking i/o buffer processor. */
   3324         PaUtil_ResetBufferProcessor( &blockingState->bufferProcessor );
   3325 
   3326         /* If we're about to process some input data. */
   3327         if( stream->inputChannelCount )
   3328         {
   3329             /* Reset callback-ReadStream sync event. */
   3330             if( ResetEvent( blockingState->readFramesReadyEvent ) == 0 )
   3331             {
   3332                 result = paUnanticipatedHostError;
   3333                 PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
   3334             }
   3335 
   3336             /* Flush blocking i/o ring buffer. */
   3337             PaUtil_FlushRingBuffer( &blockingState->readRingBuffer );
   3338             (*blockingState->bufferProcessor.inputZeroer)( blockingState->readRingBuffer.buffer, 1, blockingState->bufferProcessor.inputChannelCount * blockingState->readRingBuffer.bufferSize );
   3339         }
   3340 
   3341         /* If we're about to process some output data. */
   3342         if( stream->outputChannelCount )
   3343         {
   3344             /* Reset callback-WriteStream sync event. */
   3345             if( ResetEvent( blockingState->writeBuffersReadyEvent ) == 0 )
   3346             {
   3347                 result = paUnanticipatedHostError;
   3348                 PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
   3349             }
   3350 
   3351             /* Flush blocking i/o ring buffer. */
   3352             PaUtil_FlushRingBuffer( &blockingState->writeRingBuffer );
   3353             (*blockingState->bufferProcessor.outputZeroer)( blockingState->writeRingBuffer.buffer, 1, blockingState->bufferProcessor.outputChannelCount * blockingState->writeRingBuffer.bufferSize );
   3354 
   3355             /* Initialize the output ring buffer to "silence". */
   3356             PaUtil_AdvanceRingBufferWriteIndex( &blockingState->writeRingBuffer, blockingState->writeRingBufferInitialFrames );
   3357         }
   3358 
   3359         /* Clear requested frames / buffers count. */
   3360         blockingState->writeBuffersRequested     = 0;
   3361         blockingState->readFramesRequested       = 0;
   3362         blockingState->writeBuffersRequestedFlag = FALSE;
   3363         blockingState->readFramesRequestedFlag   = FALSE;
   3364         blockingState->outputUnderflowFlag       = FALSE;
   3365         blockingState->inputOverflowFlag         = FALSE;
   3366         blockingState->stopFlag                  = FALSE;
   3367     }
   3368 
   3369 
   3370     if( result == paNoError )
   3371     {
   3372         assert( theAsioStream == stream ); /* theAsioStream should be set correctly in OpenStream */
   3373 
   3374         /* initialize these variables before the callback has a chance to be invoked */
   3375         stream->isStopped = 0;
   3376         stream->isActive = 1;
   3377         stream->streamFinishedCallbackCalled = false;
   3378 
   3379         asioError = ASIOStart();
   3380         if( asioError != ASE_OK )
   3381         {
   3382             stream->isStopped = 1;
   3383             stream->isActive = 0;
   3384 
   3385             result = paUnanticipatedHostError;
   3386             PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   3387         }
   3388     }
   3389 
   3390     return result;
   3391 }
   3392 
   3393 static void EnsureCallbackHasCompleted( PaAsioStream *stream )
   3394 {
   3395     // make sure that the callback is not still in-flight after ASIOStop()
   3396     // returns. This has been observed to happen on the Hoontech DSP24 for
   3397     // example.
   3398     int count = 2000;  // only wait for 2 seconds, rather than hanging.
   3399     while( stream->reenterCount != -1 && count > 0 )
   3400     {
   3401         Sleep(1);
   3402         --count;
   3403     }
   3404 }
   3405 
   3406 static PaError StopStream( PaStream *s )
   3407 {
   3408     PaError result = paNoError;
   3409     PaAsioStream *stream = (PaAsioStream*)s;
   3410     PaAsioStreamBlockingState *blockingState = stream->blockingState;
   3411     ASIOError asioError;
   3412 
   3413     if( stream->isActive )
   3414     {
   3415         /* If blocking i/o output is in use */
   3416         if( blockingState && stream->outputChannelCount )
   3417         {
   3418             /* Request the whole output buffer to be available. */
   3419             blockingState->writeBuffersRequested = blockingState->writeRingBuffer.bufferSize;
   3420             /* Signalize that additional buffers are need. */
   3421             blockingState->writeBuffersRequestedFlag = TRUE;
   3422             /* Set flag to indicate the playback is to be stopped. */
   3423             blockingState->stopFlag = TRUE;
   3424 
   3425             /* Wait until requested number of buffers has been freed. Time
   3426                out after twice the blocking i/o ouput buffer could have
   3427                been consumed. */
   3428             DWORD timeout = (DWORD)( 2 * blockingState->writeRingBuffer.bufferSize * 1000
   3429                                        / stream->streamRepresentation.streamInfo.sampleRate );
   3430             DWORD waitResult = WaitForSingleObject( blockingState->writeBuffersReadyEvent, timeout );
   3431 
   3432             /* If something seriously went wrong... */
   3433             if( waitResult == WAIT_FAILED )
   3434             {
   3435                 PA_DEBUG(("WaitForSingleObject() failed in StopStream()\n"));
   3436                 result = paUnanticipatedHostError;
   3437                 PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
   3438             }
   3439             else if( waitResult == WAIT_TIMEOUT )
   3440             {
   3441                 PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n"));
   3442                 result = paTimedOut;
   3443             }
   3444         }
   3445 
   3446         stream->stopProcessing = true;
   3447 
   3448         /* wait for the stream to finish playing out enqueued buffers.
   3449             timeout after four times the stream latency.
   3450 
   3451             @todo should use a better time out value - if the user buffer
   3452             length is longer than the asio buffer size then that should
   3453             be taken into account.
   3454         */
   3455         if( WaitForSingleObject( stream->completedBuffersPlayedEvent,
   3456                 (DWORD)(stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.) )
   3457                     == WAIT_TIMEOUT )
   3458         {
   3459             PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n" ));
   3460         }
   3461     }
   3462 
   3463     asioError = ASIOStop();
   3464     if( asioError == ASE_OK )
   3465     {
   3466         EnsureCallbackHasCompleted( stream );
   3467     }
   3468     else
   3469     {
   3470         result = paUnanticipatedHostError;
   3471         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   3472     }
   3473 
   3474     stream->isStopped = 1;
   3475     stream->isActive = 0;
   3476 
   3477     if( !stream->streamFinishedCallbackCalled )
   3478     {
   3479         if( stream->streamRepresentation.streamFinishedCallback != 0 )
   3480             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
   3481     }
   3482 
   3483     return result;
   3484 }
   3485 
   3486 static PaError AbortStream( PaStream *s )
   3487 {
   3488     PaError result = paNoError;
   3489     PaAsioStream *stream = (PaAsioStream*)s;
   3490     ASIOError asioError;
   3491 
   3492     stream->zeroOutput = true;
   3493 
   3494     asioError = ASIOStop();
   3495     if( asioError == ASE_OK )
   3496     {
   3497         EnsureCallbackHasCompleted( stream );
   3498     }
   3499     else
   3500     {
   3501         result = paUnanticipatedHostError;
   3502         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   3503     }
   3504 
   3505     stream->isStopped = 1;
   3506     stream->isActive = 0;
   3507 
   3508     if( !stream->streamFinishedCallbackCalled )
   3509     {
   3510         if( stream->streamRepresentation.streamFinishedCallback != 0 )
   3511             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
   3512     }
   3513 
   3514     return result;
   3515 }
   3516 
   3517 
   3518 static PaError IsStreamStopped( PaStream *s )
   3519 {
   3520     PaAsioStream *stream = (PaAsioStream*)s;
   3521     
   3522     return stream->isStopped;
   3523 }
   3524 
   3525 
   3526 static PaError IsStreamActive( PaStream *s )
   3527 {
   3528     PaAsioStream *stream = (PaAsioStream*)s;
   3529 
   3530     return stream->isActive;
   3531 }
   3532 
   3533 
   3534 static PaTime GetStreamTime( PaStream *s )
   3535 {
   3536     (void) s; /* unused parameter */
   3537 
   3538     return (double)timeGetTime() * .001;
   3539 }
   3540 
   3541 
   3542 static double GetStreamCpuLoad( PaStream* s )
   3543 {
   3544     PaAsioStream *stream = (PaAsioStream*)s;
   3545 
   3546     return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
   3547 }
   3548 
   3549 
   3550 /*
   3551     As separate stream interfaces are used for blocking and callback
   3552     streams, the following functions can be guaranteed to only be called
   3553     for blocking streams.
   3554 */
   3555 
   3556 static PaError ReadStream( PaStream      *s     ,
   3557                            void          *buffer,
   3558                            unsigned long  frames )
   3559 {
   3560     PaError result = paNoError; /* Initial return value. */
   3561     PaAsioStream *stream = (PaAsioStream*)s; /* The PA ASIO stream. */
   3562 
   3563     /* Pointer to the blocking i/o data struct. */
   3564     PaAsioStreamBlockingState *blockingState = stream->blockingState;
   3565 
   3566     /* Get blocking i/o buffer processor and ring buffer pointers. */
   3567     PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
   3568     PaUtilRingBuffer      *pRb = &blockingState->readRingBuffer;
   3569 
   3570     /* Ring buffer segment(s) used for writing. */
   3571     void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
   3572     void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
   3573 
   3574     /* Number of frames per ring buffer segment. */
   3575     long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
   3576     long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
   3577 
   3578     /* Get number of frames to be processed per data block. */
   3579     unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer;
   3580     /* Actual number of frames that has been copied into the ring buffer. */
   3581     unsigned long lFramesCopied = 0;
   3582     /* The number of remaining unprocessed dtat frames. */
   3583     unsigned long lFramesRemaining = frames;
   3584 
   3585     /* Copy the input argument to avoid pointer increment! */
   3586     const void *userBuffer;
   3587     unsigned int i; /* Just a counter. */
   3588 
   3589     /* About the time, needed to process 8 data blocks. */
   3590     DWORD timeout = (DWORD)( 8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate );
   3591     DWORD waitResult = 0;
   3592 
   3593 
   3594     /* Check if the stream is still available ready to gather new data. */
   3595     if( blockingState->stopFlag || !stream->isActive )
   3596     {
   3597         PA_DEBUG(("Warning! Stream no longer available for reading in ReadStream()\n"));
   3598         result = paStreamIsStopped;
   3599         return result;
   3600     }
   3601 
   3602     /* If the stream is a input stream. */
   3603     if( stream->inputChannelCount )
   3604     {
   3605         /* Prepare buffer access. */
   3606         if( !pBp->userOutputIsInterleaved )
   3607         {
   3608             userBuffer = blockingState->readStreamBuffer;
   3609             for( i = 0; i<pBp->inputChannelCount; ++i )
   3610             {
   3611                 ((void**)userBuffer)[i] = ((void**)buffer)[i];
   3612             }
   3613         } /* Use the unchanged buffer. */
   3614         else { userBuffer = buffer; }
   3615 
   3616         do /* Internal block processing for too large user data buffers. */
   3617         {
   3618             /* Get the size of the current data block to be processed. */
   3619             lFramesPerBlock =(lFramesPerBlock < lFramesRemaining)
   3620                             ? lFramesPerBlock : lFramesRemaining;
   3621             /* Use predefined block size for as long there are enough
   3622                buffers available, thereafter reduce the processing block
   3623                size to match the number of remaining buffers. So the final
   3624                data block is processed although it may be incomplete. */
   3625 
   3626             /* If the available amount of data frames is insufficient. */
   3627             if( PaUtil_GetRingBufferReadAvailable(pRb) < (long) lFramesPerBlock )
   3628             {
   3629                 /* Make sure, the event isn't already set! */
   3630                 /* ResetEvent( blockingState->readFramesReadyEvent ); */
   3631 
   3632                 /* Set the number of requested buffers. */
   3633                 blockingState->readFramesRequested = lFramesPerBlock;
   3634 
   3635                 /* Signalize that additional buffers are need. */
   3636                 blockingState->readFramesRequestedFlag = TRUE;
   3637 
   3638                 /* Wait until requested number of buffers has been freed. */
   3639                 waitResult = WaitForSingleObject( blockingState->readFramesReadyEvent, timeout );
   3640 
   3641                 /* If something seriously went wrong... */
   3642                 if( waitResult == WAIT_FAILED )
   3643                 {
   3644                     PA_DEBUG(("WaitForSingleObject() failed in ReadStream()\n"));
   3645                     result = paUnanticipatedHostError;
   3646                     PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
   3647                     return result;
   3648                 }
   3649                 else if( waitResult == WAIT_TIMEOUT )
   3650                 {
   3651                     PA_DEBUG(("WaitForSingleObject() timed out in ReadStream()\n"));
   3652 
   3653                     /* If block processing has stopped, abort! */
   3654                     if( blockingState->stopFlag ) { return result = paStreamIsStopped; }
   3655 
   3656                     /* If a timeout is encountered, give up eventually. */
   3657                     return result = paTimedOut;
   3658                 }
   3659             }
   3660             /* Now, the ring buffer contains the required amount of data
   3661                frames.
   3662                (Therefor we don't need to check the return argument of
   3663                PaUtil_GetRingBufferReadRegions(). ;-) )
   3664             */
   3665 
   3666             /* Retrieve pointer(s) to the ring buffer's current write
   3667                position(s). If the first buffer segment is too small to
   3668                store the requested number of bytes, an additional second
   3669                segment is returned. Otherwise, i.e. if the first segment
   3670                is large enough, the second segment's pointer will be NULL.
   3671             */
   3672             PaUtil_GetRingBufferReadRegions(pRb                ,
   3673                                             lFramesPerBlock    ,
   3674                                             &pRingBufferData1st,
   3675                                             &lRingBufferSize1st,
   3676                                             &pRingBufferData2nd,
   3677                                             &lRingBufferSize2nd);
   3678 
   3679             /* Set number of frames to be copied from the ring buffer. */
   3680             PaUtil_SetInputFrameCount( pBp, lRingBufferSize1st ); 
   3681             /* Setup ring buffer access. */
   3682             PaUtil_SetInterleavedInputChannels(pBp               ,  /* Buffer processor. */
   3683                                                0                 ,  /* The first channel's index. */
   3684                                                pRingBufferData1st,  /* First ring buffer segment. */
   3685                                                0                 ); /* Use all available channels. */
   3686 
   3687             /* If a second ring buffer segment is required. */
   3688             if( lRingBufferSize2nd ) {
   3689                 /* Set number of frames to be copied from the ring buffer. */
   3690                 PaUtil_Set2ndInputFrameCount( pBp, lRingBufferSize2nd );
   3691                 /* Setup ring buffer access. */
   3692                 PaUtil_Set2ndInterleavedInputChannels(pBp               ,  /* Buffer processor. */
   3693                                                       0                 ,  /* The first channel's index. */
   3694                                                       pRingBufferData2nd,  /* Second ring buffer segment. */
   3695                                                       0                 ); /* Use all available channels. */
   3696             }
   3697 
   3698             /* Let the buffer processor handle "copy and conversion" and
   3699                update the ring buffer indices manually. */
   3700             lFramesCopied = PaUtil_CopyInput( pBp, &buffer, lFramesPerBlock );
   3701             PaUtil_AdvanceRingBufferReadIndex( pRb, lFramesCopied );
   3702 
   3703             /* Decrease number of unprocessed frames. */
   3704             lFramesRemaining -= lFramesCopied;
   3705 
   3706         } /* Continue with the next data chunk. */
   3707         while( lFramesRemaining );
   3708 
   3709 
   3710         /* If there has been an input overflow within the callback */
   3711         if( blockingState->inputOverflowFlag )
   3712         {
   3713             blockingState->inputOverflowFlag = FALSE;
   3714 
   3715             /* Return the corresponding error code. */
   3716             result = paInputOverflowed;
   3717         }
   3718 
   3719     } /* If this is not an input stream. */
   3720     else {
   3721         result = paCanNotReadFromAnOutputOnlyStream;
   3722     }
   3723 
   3724     return result;
   3725 }
   3726 
   3727 static PaError WriteStream( PaStream      *s     ,
   3728                             const void    *buffer,
   3729                             unsigned long  frames )
   3730 {
   3731     PaError result = paNoError; /* Initial return value. */
   3732     PaAsioStream *stream = (PaAsioStream*)s; /* The PA ASIO stream. */
   3733 
   3734     /* Pointer to the blocking i/o data struct. */
   3735     PaAsioStreamBlockingState *blockingState = stream->blockingState;
   3736 
   3737     /* Get blocking i/o buffer processor and ring buffer pointers. */
   3738     PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
   3739     PaUtilRingBuffer      *pRb = &blockingState->writeRingBuffer;
   3740 
   3741     /* Ring buffer segment(s) used for writing. */
   3742     void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
   3743     void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
   3744 
   3745     /* Number of frames per ring buffer segment. */
   3746     long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
   3747     long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
   3748 
   3749     /* Get number of frames to be processed per data block. */
   3750     unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer;
   3751     /* Actual number of frames that has been copied into the ring buffer. */
   3752     unsigned long lFramesCopied = 0;
   3753     /* The number of remaining unprocessed dtat frames. */
   3754     unsigned long lFramesRemaining = frames;
   3755 
   3756     /* About the time, needed to process 8 data blocks. */
   3757     DWORD timeout = (DWORD)( 8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate );
   3758     DWORD waitResult = 0;
   3759 
   3760     /* Copy the input argument to avoid pointer increment! */
   3761     const void *userBuffer;
   3762     unsigned int i; /* Just a counter. */
   3763 
   3764 
   3765     /* Check if the stream ist still available ready to recieve new data. */
   3766     if( blockingState->stopFlag || !stream->isActive )
   3767     {
   3768         PA_DEBUG(("Warning! Stream no longer available for writing in WriteStream()\n"));
   3769         result = paStreamIsStopped;
   3770         return result;
   3771     }
   3772 
   3773     /* If the stream is a output stream. */
   3774     if( stream->outputChannelCount )
   3775     {
   3776         /* Prepare buffer access. */
   3777         if( !pBp->userOutputIsInterleaved )
   3778         {
   3779             userBuffer = blockingState->writeStreamBuffer;
   3780             for( i = 0; i<pBp->outputChannelCount; ++i )
   3781             {
   3782                 ((const void**)userBuffer)[i] = ((const void**)buffer)[i];
   3783             }
   3784         } /* Use the unchanged buffer. */
   3785         else { userBuffer = buffer; }
   3786 
   3787 
   3788         do /* Internal block processing for too large user data buffers. */
   3789         {
   3790             /* Get the size of the current data block to be processed. */
   3791             lFramesPerBlock =(lFramesPerBlock < lFramesRemaining)
   3792                             ? lFramesPerBlock : lFramesRemaining;
   3793             /* Use predefined block size for as long there are enough
   3794                frames available, thereafter reduce the processing block
   3795                size to match the number of remaining frames. So the final
   3796                data block is processed although it may be incomplete. */
   3797 
   3798             /* If the available amount of buffers is insufficient. */
   3799             if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) lFramesPerBlock )
   3800             {
   3801                 /* Make sure, the event isn't already set! */
   3802                 /* ResetEvent( blockingState->writeBuffersReadyEvent ); */
   3803 
   3804                 /* Set the number of requested buffers. */
   3805                 blockingState->writeBuffersRequested = lFramesPerBlock;
   3806 
   3807                 /* Signalize that additional buffers are need. */
   3808                 blockingState->writeBuffersRequestedFlag = TRUE;
   3809 
   3810                 /* Wait until requested number of buffers has been freed. */
   3811                 waitResult = WaitForSingleObject( blockingState->writeBuffersReadyEvent, timeout );
   3812 
   3813                 /* If something seriously went wrong... */
   3814                 if( waitResult == WAIT_FAILED )
   3815                 {
   3816                     PA_DEBUG(("WaitForSingleObject() failed in WriteStream()\n"));
   3817                     result = paUnanticipatedHostError;
   3818                     PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
   3819                     return result;
   3820                 }
   3821                 else if( waitResult == WAIT_TIMEOUT )
   3822                 {
   3823                     PA_DEBUG(("WaitForSingleObject() timed out in WriteStream()\n"));
   3824 
   3825                     /* If block processing has stopped, abort! */
   3826                     if( blockingState->stopFlag ) { return result = paStreamIsStopped; }
   3827                     
   3828                     /* If a timeout is encountered, give up eventually. */
   3829                     return result = paTimedOut;
   3830                 }
   3831             }
   3832             /* Now, the ring buffer contains the required amount of free
   3833                space to store the provided number of data frames.
   3834                (Therefor we don't need to check the return argument of
   3835                PaUtil_GetRingBufferWriteRegions(). ;-) )
   3836             */
   3837 
   3838             /* Retrieve pointer(s) to the ring buffer's current write
   3839                position(s). If the first buffer segment is too small to
   3840                store the requested number of bytes, an additional second
   3841                segment is returned. Otherwise, i.e. if the first segment
   3842                is large enough, the second segment's pointer will be NULL.
   3843             */
   3844             PaUtil_GetRingBufferWriteRegions(pRb                ,
   3845                                              lFramesPerBlock    ,
   3846                                              &pRingBufferData1st,
   3847                                              &lRingBufferSize1st,
   3848                                              &pRingBufferData2nd,
   3849                                              &lRingBufferSize2nd);
   3850 
   3851             /* Set number of frames to be copied to the ring buffer. */
   3852             PaUtil_SetOutputFrameCount( pBp, lRingBufferSize1st ); 
   3853             /* Setup ring buffer access. */
   3854             PaUtil_SetInterleavedOutputChannels(pBp               ,  /* Buffer processor. */
   3855                                                 0                 ,  /* The first channel's index. */
   3856                                                 pRingBufferData1st,  /* First ring buffer segment. */
   3857                                                 0                 ); /* Use all available channels. */
   3858 
   3859             /* If a second ring buffer segment is required. */
   3860             if( lRingBufferSize2nd ) {
   3861                 /* Set number of frames to be copied to the ring buffer. */
   3862                 PaUtil_Set2ndOutputFrameCount( pBp, lRingBufferSize2nd );
   3863                 /* Setup ring buffer access. */
   3864                 PaUtil_Set2ndInterleavedOutputChannels(pBp               ,  /* Buffer processor. */
   3865                                                        0                 ,  /* The first channel's index. */
   3866                                                        pRingBufferData2nd,  /* Second ring buffer segment. */
   3867                                                        0                 ); /* Use all available channels. */
   3868             }
   3869 
   3870             /* Let the buffer processor handle "copy and conversion" and
   3871                update the ring buffer indices manually. */
   3872             lFramesCopied = PaUtil_CopyOutput( pBp, &userBuffer, lFramesPerBlock );
   3873             PaUtil_AdvanceRingBufferWriteIndex( pRb, lFramesCopied );
   3874 
   3875             /* Decrease number of unprocessed frames. */
   3876             lFramesRemaining -= lFramesCopied;
   3877 
   3878         } /* Continue with the next data chunk. */
   3879         while( lFramesRemaining );
   3880 
   3881 
   3882         /* If there has been an output underflow within the callback */
   3883         if( blockingState->outputUnderflowFlag )
   3884         {
   3885             blockingState->outputUnderflowFlag = FALSE;
   3886 
   3887             /* Return the corresponding error code. */
   3888             result = paOutputUnderflowed;
   3889         }
   3890 
   3891     } /* If this is not an output stream. */
   3892     else
   3893     {
   3894         result = paCanNotWriteToAnInputOnlyStream;
   3895     }
   3896 
   3897     return result;
   3898 }
   3899 
   3900 
   3901 static signed long GetStreamReadAvailable( PaStream* s )
   3902 {
   3903     PaAsioStream *stream = (PaAsioStream*)s;
   3904 
   3905     /* Call buffer utility routine to get the number of available frames. */
   3906     return PaUtil_GetRingBufferReadAvailable( &stream->blockingState->readRingBuffer );
   3907 }
   3908 
   3909 
   3910 static signed long GetStreamWriteAvailable( PaStream* s )
   3911 {
   3912     PaAsioStream *stream = (PaAsioStream*)s;
   3913 
   3914     /* Call buffer utility routine to get the number of empty buffers. */
   3915     return PaUtil_GetRingBufferWriteAvailable( &stream->blockingState->writeRingBuffer );
   3916 }
   3917 
   3918 
   3919 /* This routine will be called by the PortAudio engine when audio is needed.
   3920 ** It may called at interrupt level on some machines so don't do anything
   3921 ** that could mess up the system like calling malloc() or free().
   3922 */
   3923 static int BlockingIoPaCallback(const void                     *inputBuffer    ,
   3924                                       void                     *outputBuffer   ,
   3925                                       unsigned long             framesPerBuffer,
   3926                                 const PaStreamCallbackTimeInfo *timeInfo       ,
   3927                                       PaStreamCallbackFlags     statusFlags    ,
   3928                                       void                     *userData       )
   3929 {
   3930     PaError result = paNoError; /* Initial return value. */
   3931     PaAsioStream *stream = *(PaAsioStream**)userData; /* The PA ASIO stream. */
   3932     PaAsioStreamBlockingState *blockingState = stream->blockingState; /* Persume blockingState is valid, otherwise the callback wouldn't be running. */
   3933 
   3934     /* Get a pointer to the stream's blocking i/o buffer processor. */
   3935     PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
   3936     PaUtilRingBuffer      *pRb = NULL;
   3937 
   3938     /* If output data has been requested. */
   3939     if( stream->outputChannelCount )
   3940     {
   3941         /* If the callback input argument signalizes a output underflow,
   3942            make sure the WriteStream() function knows about it, too! */
   3943         if( statusFlags & paOutputUnderflowed ) {
   3944             blockingState->outputUnderflowFlag = TRUE;
   3945         }
   3946 
   3947         /* Access the corresponding ring buffer. */
   3948         pRb = &blockingState->writeRingBuffer;
   3949 
   3950         /* If the blocking i/o buffer contains enough output data, */
   3951         if( PaUtil_GetRingBufferReadAvailable(pRb) >= (long) framesPerBuffer )
   3952         {
   3953             /* Extract the requested data from the ring buffer. */
   3954             PaUtil_ReadRingBuffer( pRb, outputBuffer, framesPerBuffer );
   3955         }
   3956         else /* If no output data is available :-( */
   3957         {
   3958             /* Signalize a write-buffer underflow. */
   3959             blockingState->outputUnderflowFlag = TRUE;
   3960 
   3961             /* Fill the output buffer with silence. */
   3962             (*pBp->outputZeroer)( outputBuffer, 1, pBp->outputChannelCount * framesPerBuffer );
   3963 
   3964             /* If playback is to be stopped */
   3965             if( blockingState->stopFlag && PaUtil_GetRingBufferReadAvailable(pRb) < (long) framesPerBuffer )
   3966             {
   3967                 /* Extract all the remaining data from the ring buffer,
   3968                    whether it is a complete data block or not. */
   3969                 PaUtil_ReadRingBuffer( pRb, outputBuffer, PaUtil_GetRingBufferReadAvailable(pRb) );
   3970             }
   3971         }
   3972 
   3973         /* Set blocking i/o event? */
   3974         if( blockingState->writeBuffersRequestedFlag && PaUtil_GetRingBufferWriteAvailable(pRb) >= (long) blockingState->writeBuffersRequested )
   3975         {
   3976             /* Reset buffer request. */
   3977             blockingState->writeBuffersRequestedFlag = FALSE;
   3978             blockingState->writeBuffersRequested     = 0;
   3979             /* Signalize that requested buffers are ready. */
   3980             SetEvent( blockingState->writeBuffersReadyEvent );
   3981             /* What do we do if SetEvent() returns zero, i.e. the event
   3982                could not be set? How to return errors from within the
   3983                callback? - S.Fischer */
   3984         }
   3985     }
   3986 
   3987     /* If input data has been supplied. */
   3988     if( stream->inputChannelCount )
   3989     {
   3990         /* If the callback input argument signalizes a input overflow,
   3991            make sure the ReadStream() function knows about it, too! */
   3992         if( statusFlags & paInputOverflowed ) {
   3993             blockingState->inputOverflowFlag = TRUE;
   3994         }
   3995 
   3996         /* Access the corresponding ring buffer. */
   3997         pRb = &blockingState->readRingBuffer;
   3998 
   3999         /* If the blocking i/o buffer contains not enough input buffers */
   4000         if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) framesPerBuffer )
   4001         {
   4002             /* Signalize a read-buffer overflow. */
   4003             blockingState->inputOverflowFlag = TRUE;
   4004 
   4005             /* Remove some old data frames from the buffer. */
   4006             PaUtil_AdvanceRingBufferReadIndex( pRb, framesPerBuffer );
   4007         }
   4008 
   4009         /* Insert the current input data into the ring buffer. */
   4010         PaUtil_WriteRingBuffer( pRb, inputBuffer, framesPerBuffer );
   4011 
   4012         /* Set blocking i/o event? */
   4013         if( blockingState->readFramesRequestedFlag && PaUtil_GetRingBufferReadAvailable(pRb) >= (long) blockingState->readFramesRequested )
   4014         {
   4015             /* Reset buffer request. */
   4016             blockingState->readFramesRequestedFlag = FALSE;
   4017             blockingState->readFramesRequested     = 0;
   4018             /* Signalize that requested buffers are ready. */
   4019             SetEvent( blockingState->readFramesReadyEvent );
   4020             /* What do we do if SetEvent() returns zero, i.e. the event
   4021                could not be set? How to return errors from within the
   4022                callback? - S.Fischer */
   4023             /** @todo report an error with PA_DEBUG */
   4024         }
   4025     }
   4026 
   4027     return paContinue;
   4028 }
   4029 
   4030 
   4031 PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific )
   4032 {
   4033     PaError result = paNoError;
   4034     PaUtilHostApiRepresentation *hostApi;
   4035     PaDeviceIndex hostApiDevice;
   4036     ASIODriverInfo asioDriverInfo;
   4037     ASIOError asioError;
   4038     int asioIsInitialized = 0;
   4039     PaAsioHostApiRepresentation *asioHostApi;
   4040     PaAsioDeviceInfo *asioDeviceInfo;
   4041     PaWinUtilComInitializationResult comInitializationResult;
   4042 
   4043     /* initialize COM again here, we might be in another thread */
   4044     result = PaWinUtil_CoInitialize( paASIO, &comInitializationResult );
   4045     if( result != paNoError )
   4046         return result;
   4047 
   4048     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
   4049     if( result != paNoError )
   4050         goto error;
   4051 
   4052     result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
   4053     if( result != paNoError )
   4054         goto error;
   4055 
   4056     /*
   4057         In theory we could proceed if the currently open device was the same
   4058         one for which the control panel was requested, however  because the
   4059         window pointer is not available until this function is called we
   4060         currently need to call ASIOInit() again here, which of course can't be
   4061         done safely while a stream is open.
   4062     */
   4063 
   4064     asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
   4065     if( asioHostApi->openAsioDeviceIndex != paNoDevice )
   4066     {
   4067         result = paDeviceUnavailable;
   4068         goto error;
   4069     }
   4070 
   4071     asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
   4072 
   4073     if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(asioDeviceInfo->commonDeviceInfo.name) ) )
   4074     {
   4075         result = paUnanticipatedHostError;
   4076         goto error;
   4077     }
   4078 
   4079     /* CRUCIAL!!! */
   4080     memset( &asioDriverInfo, 0, sizeof(ASIODriverInfo) );
   4081     asioDriverInfo.asioVersion = 2;
   4082     asioDriverInfo.sysRef = systemSpecific;
   4083     asioError = ASIOInit( &asioDriverInfo );
   4084     if( asioError != ASE_OK )
   4085     {
   4086         result = paUnanticipatedHostError;
   4087         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   4088         goto error;
   4089     }
   4090     else
   4091     {
   4092         asioIsInitialized = 1;
   4093     }
   4094 
   4095 PA_DEBUG(("PaAsio_ShowControlPanel: ASIOInit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
   4096 PA_DEBUG(("asioVersion: ASIOInit(): %ld\n",   asioDriverInfo.asioVersion )); 
   4097 PA_DEBUG(("driverVersion: ASIOInit(): %ld\n", asioDriverInfo.driverVersion )); 
   4098 PA_DEBUG(("Name: ASIOInit(): %s\n",           asioDriverInfo.name )); 
   4099 PA_DEBUG(("ErrorMessage: ASIOInit(): %s\n",   asioDriverInfo.errorMessage )); 
   4100 
   4101     asioError = ASIOControlPanel();
   4102     if( asioError != ASE_OK )
   4103     {
   4104         PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
   4105         result = paUnanticipatedHostError;
   4106         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   4107         goto error;
   4108     }
   4109 
   4110 PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
   4111 
   4112     asioError = ASIOExit();
   4113     if( asioError != ASE_OK )
   4114     {
   4115         result = paUnanticipatedHostError;
   4116         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
   4117         asioIsInitialized = 0;
   4118         goto error;
   4119     }
   4120 
   4121 PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
   4122 
   4123     return result;
   4124 
   4125 error:
   4126     if( asioIsInitialized )
   4127 	{
   4128 		ASIOExit();
   4129 	}
   4130 
   4131     PaWinUtil_CoUninitialize( paASIO, &comInitializationResult );
   4132 
   4133     return result;
   4134 }
   4135 
   4136 
   4137 PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex,
   4138         const char** channelName )
   4139 {
   4140     PaError result = paNoError;
   4141     PaUtilHostApiRepresentation *hostApi;
   4142     PaDeviceIndex hostApiDevice;
   4143     PaAsioDeviceInfo *asioDeviceInfo;
   4144 
   4145 
   4146     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
   4147     if( result != paNoError )
   4148         goto error;
   4149 
   4150     result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
   4151     if( result != paNoError )
   4152         goto error;
   4153 
   4154     asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
   4155 
   4156     if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxInputChannels ){
   4157         result = paInvalidChannelCount;
   4158         goto error;
   4159     }
   4160 
   4161     *channelName = asioDeviceInfo->asioChannelInfos[channelIndex].name;
   4162 
   4163     return paNoError;
   4164     
   4165 error:
   4166     return result;
   4167 }
   4168 
   4169 
   4170 PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex,
   4171         const char** channelName )
   4172 {
   4173     PaError result = paNoError;
   4174     PaUtilHostApiRepresentation *hostApi;
   4175     PaDeviceIndex hostApiDevice;
   4176     PaAsioDeviceInfo *asioDeviceInfo;
   4177 
   4178 
   4179     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
   4180     if( result != paNoError )
   4181         goto error;
   4182 
   4183     result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
   4184     if( result != paNoError )
   4185         goto error;
   4186 
   4187     asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
   4188 
   4189     if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxOutputChannels ){
   4190         result = paInvalidChannelCount;
   4191         goto error;
   4192     }
   4193 
   4194     *channelName = asioDeviceInfo->asioChannelInfos[
   4195             asioDeviceInfo->commonDeviceInfo.maxInputChannels + channelIndex].name;
   4196 
   4197     return paNoError;
   4198     
   4199 error:
   4200     return result;
   4201 }
   4202 
   4203 
   4204 /* NOTE: the following functions are ASIO-stream specific, and are called directly
   4205     by client code. We need to check for many more error conditions here because
   4206     we don't have the benefit of pa_front.c's parameter checking.
   4207 */
   4208 
   4209 static PaError GetAsioStreamPointer( PaAsioStream **stream, PaStream *s )
   4210 {
   4211     PaError result;
   4212     PaUtilHostApiRepresentation *hostApi;
   4213     PaAsioHostApiRepresentation *asioHostApi;
   4214     
   4215     result = PaUtil_ValidateStreamPointer( s );
   4216     if( result != paNoError )
   4217         return result;
   4218 
   4219     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
   4220     if( result != paNoError )
   4221         return result;
   4222 
   4223     asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
   4224     
   4225     if( PA_STREAM_REP( s )->streamInterface == &asioHostApi->callbackStreamInterface
   4226             || PA_STREAM_REP( s )->streamInterface == &asioHostApi->blockingStreamInterface )
   4227     {
   4228         /* s is an ASIO  stream */
   4229         *stream = (PaAsioStream *)s;
   4230         return paNoError;
   4231     }
   4232     else
   4233     {
   4234         return paIncompatibleStreamHostApi;
   4235     }
   4236 }
   4237 
   4238 
   4239 PaError PaAsio_SetStreamSampleRate( PaStream* s, double sampleRate )
   4240 {
   4241     PaAsioStream *stream;
   4242     PaError result = GetAsioStreamPointer( &stream, s );
   4243     if( result != paNoError )
   4244         return result;
   4245 
   4246     if( stream != theAsioStream )
   4247         return paBadStreamPtr;
   4248 
   4249     return ValidateAndSetSampleRate( sampleRate );
   4250 }
   4251