1 /*
2  * $Id: pa_asio.cpp,v 1.1 2006/06/10 21:30:55 dmazzoni Exp $
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  *
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files
11  * (the "Software"), to deal in the Software without restriction,
12  * including without limitation the rights to use, copy, modify, merge,
13  * publish, distribute, sublicense, and/or sell copies of the Software,
14  * and to permit persons to whom the Software is furnished to do so,
15  * subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * Any person wishing to distribute modifications to the Software is
21  * requested to send the modifications to the original developer so that
22  * they can be incorporated into the canonical version.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
28  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31  */
32 
33 /* Modification History
34 
35         08-03-01 First version : Stephane Letz
36         08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk
37         08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz
38         08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz
39         08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil
40         08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when
41                  the stream is stopped : Stephane Letz
42         08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when
43                  the stream is stopped : Stephane Letz
44         10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that
45                  respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz
46         10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz
47         10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil
48         10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk
49         10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz
50         11-06-01 Rename functions : Stephane Letz
51         11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz
52         11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk
53         01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly :  Stephane Letz
54         02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz
55         19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz
56         09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz
57         12-04-02 Add Mac includes for <Devices.h> and <Timer.h> : Phil Burk
58         13-04-02 Removes another compiler warning : Stephane Letz
59         30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz
60         12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina
61         18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B.
62         21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina
63         ** NOTE  maintanance history is now stored in CVS **
64 */
65 
66 /** @file
67 
68     Note that specific support for paInputUnderflow, paOutputOverflow and
69     paNeverDropInput is not necessary or possible with this driver due to the
70     synchronous full duplex double-buffered architecture of ASIO.
71 
72     @todo check that CoInitialize()/CoUninitialize() are always correctly
73         paired, even in error cases.
74 
75     @todo implement host api specific extension to set i/o buffer sizes in frames
76 
77     @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
78 
79     @todo implement IsFormatSupported
80 
81     @todo work out how to implement stream stoppage from callback and
82             implement IsStreamActive properly. Stream stoppage could be implemented
83             using a high-priority thread blocked on an Event which is signalled
84             by the callback. Or, we could just call ASIO stop from the callback
85             and see what happens.
86 
87     @todo rigorously check asio return codes and convert to pa error codes
88 
89     @todo Different channels of a multichannel stream can have different sample
90             formats, but we assume that all are the same as the first channel for now.
91             Fixing this will require the block processor to maintain per-channel
92             conversion functions - could get nasty.
93 
94     @todo investigate whether the asio processNow flag needs to be honoured
95 
96     @todo handle asioMessages() callbacks in a useful way, or at least document
97             what cases we don't handle.
98 
99     @todo miscellaneous other FIXMEs
100 
101     @todo provide an asio-specific method for setting the systems specific
102         value (aka main window handle) - check that this matches the value
103         passed to PaAsio_ShowControlPanel, or remove it entirely from
104         PaAsio_ShowControlPanel. - this would allow PaAsio_ShowControlPanel
105         to be called for the currently open stream (at present all streams
106         must be closed).
107 */
108 
109 
110 
111 #include <stdio.h>
112 #include <assert.h>
113 #include <string.h>
114 //#include <values.h>
115 
116 #include <windows.h>
117 #include <mmsystem.h>
118 
119 #include "portaudio.h"
120 #include "pa_asio.h"
121 #include "pa_util.h"
122 #include "pa_allocation.h"
123 #include "pa_hostapi.h"
124 #include "pa_stream.h"
125 #include "pa_cpuload.h"
126 #include "pa_process.h"
127 
128 
129 /* This version of pa_asio.cpp is currently only targetted at Win32,
130    It would require a few tweaks to work with pre-OS X Macintosh.
131    To make configuration easier, we define WIN32 here to make sure
132    that the ASIO SDK knows this is Win32.
133 */
134 #ifndef WIN32
135 #define WIN32
136 #endif
137 
138 #include "asiosys.h"
139 #include "asio.h"
140 #include "asiodrivers.h"
141 #include "iasiothiscallresolver.h"
142 
143 /*
144 #if MAC
145 #include <Devices.h>
146 #include <Timer.h>
147 #include <Math64.h>
148 #else
149 */
150 /*
151 #include <math.h>
152 #include <windows.h>
153 #include <mmsystem.h>
154 */
155 /*
156 #endif
157 */
158 
159 /* external references */
160 extern AsioDrivers* asioDrivers ;
161 bool loadAsioDriver(char *name);
162 
163 
164 /* We are trying to be compatible with CARBON but this has not been thoroughly tested. */
165 /* not tested at all since new code was introduced. */
166 #define CARBON_COMPATIBLE  (0)
167 
168 
169 
170 
171 /* prototypes for functions declared in this file */
172 
173 extern "C" PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
174 static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
175 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
176                            PaStream** s,
177                            const PaStreamParameters *inputParameters,
178                            const PaStreamParameters *outputParameters,
179                            double sampleRate,
180                            unsigned long framesPerBuffer,
181                            PaStreamFlags streamFlags,
182                            PaStreamCallback *streamCallback,
183                            void *userData );
184 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
185                                   const PaStreamParameters *inputParameters,
186                                   const PaStreamParameters *outputParameters,
187                                   double sampleRate );
188 static PaError CloseStream( PaStream* stream );
189 static PaError StartStream( PaStream *stream );
190 static PaError StopStream( PaStream *stream );
191 static PaError AbortStream( PaStream *stream );
192 static PaError IsStreamStopped( PaStream *s );
193 static PaError IsStreamActive( PaStream *stream );
194 static PaTime GetStreamTime( PaStream *stream );
195 static double GetStreamCpuLoad( PaStream* stream );
196 static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
197 static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
198 static signed long GetStreamReadAvailable( PaStream* stream );
199 static signed long GetStreamWriteAvailable( PaStream* stream );
200 
201 /* our ASIO callback functions */
202 
203 static void bufferSwitch(long index, ASIOBool processNow);
204 static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
205 static void sampleRateChanged(ASIOSampleRate sRate);
206 static long asioMessages(long selector, long value, void* message, double* opt);
207 
208 static ASIOCallbacks asioCallbacks_ =
209     { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo };
210 
211 
212 #define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \
213     PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText )
214 
215 
PaAsio_SetLastSystemError(DWORD errorCode)216 static void PaAsio_SetLastSystemError( DWORD errorCode )
217 {
218     LPVOID lpMsgBuf;
219     FormatMessage(
220         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
221         NULL,
222         errorCode,
223         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
224         (LPTSTR) &lpMsgBuf,
225         0,
226         NULL
227     );
228     PaUtil_SetLastHostErrorInfo( paASIO, errorCode, (const char*)lpMsgBuf );
229     LocalFree( lpMsgBuf );
230 }
231 
232 #define PA_ASIO_SET_LAST_SYSTEM_ERROR( errorCode ) \
233     PaAsio_SetLastSystemError( errorCode )
234 
235 
PaAsio_GetAsioErrorText(ASIOError asioError)236 static const char* PaAsio_GetAsioErrorText( ASIOError asioError )
237 {
238     const char *result;
239 
240     switch( asioError ){
241         case ASE_OK:
242         case ASE_SUCCESS:           result = "Success"; break;
243         case ASE_NotPresent:        result = "Hardware input or output is not present or available"; break;
244         case ASE_HWMalfunction:     result = "Hardware is malfunctioning"; break;
245         case ASE_InvalidParameter:  result = "Input parameter invalid"; break;
246         case ASE_InvalidMode:       result = "Hardware is in a bad mode or used in a bad mode"; break;
247         case ASE_SPNotAdvancing:    result = "Hardware is not running when sample position is inquired"; break;
248         case ASE_NoClock:           result = "Sample clock or rate cannot be determined or is not present"; break;
249         case ASE_NoMemory:          result = "Not enough memory for completing the request"; break;
250         default:                    result = "Unknown ASIO error"; break;
251     }
252 
253     return result;
254 }
255 
256 
257 #define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \
258     PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) )
259 
260 
261 
262 
263 // Atomic increment and decrement operations
264 #if MAC
265 	/* need to be implemented on Mac */
PaAsio_AtomicIncrement(volatile long * v)266 	inline long PaAsio_AtomicIncrement(volatile long* v) {return ++(*const_cast<long*>(v));}
PaAsio_AtomicDecrement(volatile long * v)267 	inline long PaAsio_AtomicDecrement(volatile long* v) {return --(*const_cast<long*>(v));}
268 #elif WINDOWS
PaAsio_AtomicIncrement(volatile long * v)269 	inline long PaAsio_AtomicIncrement(volatile long* v) {return InterlockedIncrement(const_cast<long*>(v));}
PaAsio_AtomicDecrement(volatile long * v)270 	inline long PaAsio_AtomicDecrement(volatile long* v) {return InterlockedDecrement(const_cast<long*>(v));}
271 #endif
272 
273 
274 
275 typedef struct PaAsioDriverInfo
276 {
277     ASIODriverInfo asioDriverInfo;
278     long inputChannelCount, outputChannelCount;
279     long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity;
280     bool postOutput;
281 }
282 PaAsioDriverInfo;
283 
284 
285 /* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */
286 
287 typedef struct
288 {
289     PaUtilHostApiRepresentation inheritedHostApiRep;
290     PaUtilStreamInterface callbackStreamInterface;
291     PaUtilStreamInterface blockingStreamInterface;
292 
293     PaUtilAllocationGroup *allocations;
294 
295     void *systemSpecific;
296 
297     /* the ASIO C API only allows one ASIO driver to be open at a time,
298         so we keep track of whether we have the driver open here, and
299         use this information to return errors from OpenStream if the
300         driver is already open.
301 
302         openAsioDeviceIndex will be PaNoDevice if there is no device open
303         and a valid pa_asio (not global) device index otherwise.
304 
305         openAsioDriverInfo is populated with the driver info for the
306         currently open device (if any)
307     */
308     PaDeviceIndex openAsioDeviceIndex;
309     PaAsioDriverInfo openAsioDriverInfo;
310 }
311 PaAsioHostApiRepresentation;
312 
313 
314 /*
315     Retrieve <driverCount> driver names from ASIO, returned in a char**
316     allocated in <group>.
317 */
GetAsioDriverNames(PaUtilAllocationGroup * group,long driverCount)318 static char **GetAsioDriverNames( PaUtilAllocationGroup *group, long driverCount )
319 {
320     char **result = 0;
321     int i;
322 
323     result =(char**)PaUtil_GroupAllocateMemory(
324             group, sizeof(char*) * driverCount );
325     if( !result )
326         goto error;
327 
328     result[0] = (char*)PaUtil_GroupAllocateMemory(
329             group, 32 * driverCount );
330     if( !result[0] )
331         goto error;
332 
333     for( i=0; i<driverCount; ++i )
334         result[i] = result[0] + (32 * i);
335 
336     asioDrivers->getDriverNames( result, driverCount );
337 
338 error:
339     return result;
340 }
341 
342 
AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type)343 static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type)
344 {
345     switch (type) {
346         case ASIOSTInt16MSB:
347         case ASIOSTInt16LSB:
348                 return paInt16;
349 
350         case ASIOSTFloat32MSB:
351         case ASIOSTFloat32LSB:
352         case ASIOSTFloat64MSB:
353         case ASIOSTFloat64LSB:
354                 return paFloat32;
355 
356         case ASIOSTInt32MSB:
357         case ASIOSTInt32LSB:
358         case ASIOSTInt32MSB16:
359         case ASIOSTInt32LSB16:
360         case ASIOSTInt32MSB18:
361         case ASIOSTInt32MSB20:
362         case ASIOSTInt32MSB24:
363         case ASIOSTInt32LSB18:
364         case ASIOSTInt32LSB20:
365         case ASIOSTInt32LSB24:
366                 return paInt32;
367 
368         case ASIOSTInt24MSB:
369         case ASIOSTInt24LSB:
370                 return paInt24;
371 
372         default:
373                 return paCustomFormat;
374     }
375 }
376 
AsioSampleTypeLOG(ASIOSampleType type)377 void AsioSampleTypeLOG(ASIOSampleType type)
378 {
379     switch (type) {
380         case ASIOSTInt16MSB:  PA_DEBUG(("ASIOSTInt16MSB\n"));  break;
381         case ASIOSTInt16LSB:  PA_DEBUG(("ASIOSTInt16LSB\n"));  break;
382         case ASIOSTFloat32MSB:PA_DEBUG(("ASIOSTFloat32MSB\n"));break;
383         case ASIOSTFloat32LSB:PA_DEBUG(("ASIOSTFloat32LSB\n"));break;
384         case ASIOSTFloat64MSB:PA_DEBUG(("ASIOSTFloat64MSB\n"));break;
385         case ASIOSTFloat64LSB:PA_DEBUG(("ASIOSTFloat64LSB\n"));break;
386         case ASIOSTInt32MSB:  PA_DEBUG(("ASIOSTInt32MSB\n"));  break;
387         case ASIOSTInt32LSB:  PA_DEBUG(("ASIOSTInt32LSB\n"));  break;
388         case ASIOSTInt32MSB16:PA_DEBUG(("ASIOSTInt32MSB16\n"));break;
389         case ASIOSTInt32LSB16:PA_DEBUG(("ASIOSTInt32LSB16\n"));break;
390         case ASIOSTInt32MSB18:PA_DEBUG(("ASIOSTInt32MSB18\n"));break;
391         case ASIOSTInt32MSB20:PA_DEBUG(("ASIOSTInt32MSB20\n"));break;
392         case ASIOSTInt32MSB24:PA_DEBUG(("ASIOSTInt32MSB24\n"));break;
393         case ASIOSTInt32LSB18:PA_DEBUG(("ASIOSTInt32LSB18\n"));break;
394         case ASIOSTInt32LSB20:PA_DEBUG(("ASIOSTInt32LSB20\n"));break;
395         case ASIOSTInt32LSB24:PA_DEBUG(("ASIOSTInt32LSB24\n"));break;
396         case ASIOSTInt24MSB:  PA_DEBUG(("ASIOSTInt24MSB\n"));  break;
397         case ASIOSTInt24LSB:  PA_DEBUG(("ASIOSTInt24LSB\n"));  break;
398         default:              PA_DEBUG(("Custom Format%d\n",type));break;
399 
400     }
401 }
402 
BytesPerAsioSample(ASIOSampleType sampleType)403 static int BytesPerAsioSample( ASIOSampleType sampleType )
404 {
405     switch (sampleType) {
406         case ASIOSTInt16MSB:
407         case ASIOSTInt16LSB:
408             return 2;
409 
410         case ASIOSTFloat64MSB:
411         case ASIOSTFloat64LSB:
412             return 8;
413 
414         case ASIOSTFloat32MSB:
415         case ASIOSTFloat32LSB:
416         case ASIOSTInt32MSB:
417         case ASIOSTInt32LSB:
418         case ASIOSTInt32MSB16:
419         case ASIOSTInt32LSB16:
420         case ASIOSTInt32MSB18:
421         case ASIOSTInt32MSB20:
422         case ASIOSTInt32MSB24:
423         case ASIOSTInt32LSB18:
424         case ASIOSTInt32LSB20:
425         case ASIOSTInt32LSB24:
426             return 4;
427 
428         case ASIOSTInt24MSB:
429         case ASIOSTInt24LSB:
430             return 3;
431 
432         default:
433             return 0;
434     }
435 }
436 
437 
Swap16(void * buffer,long shift,long count)438 static void Swap16( void *buffer, long shift, long count )
439 {
440     unsigned short *p = (unsigned short*)buffer;
441     unsigned short temp;
442     (void) shift; /* unused parameter */
443 
444     while( count-- )
445     {
446         temp = *p;
447         *p++ = (unsigned short)((temp<<8) | (temp>>8));
448     }
449 }
450 
Swap24(void * buffer,long shift,long count)451 static void Swap24( void *buffer, long shift, long count )
452 {
453     unsigned char *p = (unsigned char*)buffer;
454     unsigned char temp;
455     (void) shift; /* unused parameter */
456 
457     while( count-- )
458     {
459         temp = *p;
460         *p = *(p+2);
461         *(p+2) = temp;
462         p += 3;
463     }
464 }
465 
466 #define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24));
467 
Swap32(void * buffer,long shift,long count)468 static void Swap32( void *buffer, long shift, long count )
469 {
470     unsigned long *p = (unsigned long*)buffer;
471     unsigned long temp;
472     (void) shift; /* unused parameter */
473 
474     while( count-- )
475     {
476         temp = *p;
477         *p++ = PA_SWAP32_( temp);
478     }
479 }
480 
SwapShiftLeft32(void * buffer,long shift,long count)481 static void SwapShiftLeft32( void *buffer, long shift, long count )
482 {
483     unsigned long *p = (unsigned long*)buffer;
484     unsigned long temp;
485 
486     while( count-- )
487     {
488         temp = *p;
489         temp = PA_SWAP32_( temp);
490         *p++ = temp << shift;
491     }
492 }
493 
ShiftRightSwap32(void * buffer,long shift,long count)494 static void ShiftRightSwap32( void *buffer, long shift, long count )
495 {
496     unsigned long *p = (unsigned long*)buffer;
497     unsigned long temp;
498 
499     while( count-- )
500     {
501         temp = *p >> shift;
502         *p++ = PA_SWAP32_( temp);
503     }
504 }
505 
ShiftLeft32(void * buffer,long shift,long count)506 static void ShiftLeft32( void *buffer, long shift, long count )
507 {
508     unsigned long *p = (unsigned long*)buffer;
509     unsigned long temp;
510 
511     while( count-- )
512     {
513         temp = *p;
514         *p++ = temp << shift;
515     }
516 }
517 
ShiftRight32(void * buffer,long shift,long count)518 static void ShiftRight32( void *buffer, long shift, long count )
519 {
520     unsigned long *p = (unsigned long*)buffer;
521     unsigned long temp;
522 
523     while( count-- )
524     {
525         temp = *p;
526         *p++ = temp >> shift;
527     }
528 }
529 
530 #define PA_SWAP_( x, y ) temp=x; x = y; y = temp;
531 
Swap64ConvertFloat64ToFloat32(void * buffer,long shift,long count)532 static void Swap64ConvertFloat64ToFloat32( void *buffer, long shift, long count )
533 {
534     double *in = (double*)buffer;
535     float *out = (float*)buffer;
536     unsigned char *p;
537     unsigned char temp;
538     (void) shift; /* unused parameter */
539 
540     while( count-- )
541     {
542         p = (unsigned char*)in;
543         PA_SWAP_( p[0], p[7] );
544         PA_SWAP_( p[1], p[6] );
545         PA_SWAP_( p[2], p[5] );
546         PA_SWAP_( p[3], p[4] );
547 
548         *out++ = (float) (*in++);
549     }
550 }
551 
ConvertFloat64ToFloat32(void * buffer,long shift,long count)552 static void ConvertFloat64ToFloat32( void *buffer, long shift, long count )
553 {
554     double *in = (double*)buffer;
555     float *out = (float*)buffer;
556     (void) shift; /* unused parameter */
557 
558     while( count-- )
559         *out++ = (float) (*in++);
560 }
561 
ConvertFloat32ToFloat64Swap64(void * buffer,long shift,long count)562 static void ConvertFloat32ToFloat64Swap64( void *buffer, long shift, long count )
563 {
564     float *in = ((float*)buffer) + (count-1);
565     double *out = ((double*)buffer) + (count-1);
566     unsigned char *p;
567     unsigned char temp;
568     (void) shift; /* unused parameter */
569 
570     while( count-- )
571     {
572         *out = *in--;
573 
574         p = (unsigned char*)out;
575         PA_SWAP_( p[0], p[7] );
576         PA_SWAP_( p[1], p[6] );
577         PA_SWAP_( p[2], p[5] );
578         PA_SWAP_( p[3], p[4] );
579 
580         out--;
581     }
582 }
583 
ConvertFloat32ToFloat64(void * buffer,long shift,long count)584 static void ConvertFloat32ToFloat64( void *buffer, long shift, long count )
585 {
586     float *in = ((float*)buffer) + (count-1);
587     double *out = ((double*)buffer) + (count-1);
588     (void) shift; /* unused parameter */
589 
590     while( count-- )
591         *out-- = *in--;
592 }
593 
594 #ifdef MAC
595 #define PA_MSB_IS_NATIVE_
596 #undef PA_LSB_IS_NATIVE_
597 #endif
598 
599 #ifdef WINDOWS
600 #undef PA_MSB_IS_NATIVE_
601 #define PA_LSB_IS_NATIVE_
602 #endif
603 
604 typedef void PaAsioBufferConverter( void *, long, long );
605 
SelectAsioToPaConverter(ASIOSampleType type,PaAsioBufferConverter ** converter,long * shift)606 static void SelectAsioToPaConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
607 {
608     *shift = 0;
609     *converter = 0;
610 
611     switch (type) {
612         case ASIOSTInt16MSB:
613             /* dest: paInt16, no conversion necessary, possible byte swap*/
614             #ifdef PA_LSB_IS_NATIVE_
615                 *converter = Swap16;
616             #endif
617             break;
618         case ASIOSTInt16LSB:
619             /* dest: paInt16, no conversion necessary, possible byte swap*/
620             #ifdef PA_MSB_IS_NATIVE_
621                 *converter = Swap16;
622             #endif
623             break;
624         case ASIOSTFloat32MSB:
625             /* dest: paFloat32, no conversion necessary, possible byte swap*/
626             #ifdef PA_LSB_IS_NATIVE_
627                 *converter = Swap32;
628             #endif
629             break;
630         case ASIOSTFloat32LSB:
631             /* dest: paFloat32, no conversion necessary, possible byte swap*/
632             #ifdef PA_MSB_IS_NATIVE_
633                 *converter = Swap32;
634             #endif
635             break;
636         case ASIOSTFloat64MSB:
637             /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
638             #ifdef PA_LSB_IS_NATIVE_
639                 *converter = Swap64ConvertFloat64ToFloat32;
640             #else
641                 *converter = ConvertFloat64ToFloat32;
642             #endif
643             break;
644         case ASIOSTFloat64LSB:
645             /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
646             #ifdef PA_MSB_IS_NATIVE_
647                 *converter = Swap64ConvertFloat64ToFloat32;
648             #else
649                 *converter = ConvertFloat64ToFloat32;
650             #endif
651             break;
652         case ASIOSTInt32MSB:
653             /* dest: paInt32, no conversion necessary, possible byte swap */
654             #ifdef PA_LSB_IS_NATIVE_
655                 *converter = Swap32;
656             #endif
657             break;
658         case ASIOSTInt32LSB:
659             /* dest: paInt32, no conversion necessary, possible byte swap */
660             #ifdef PA_MSB_IS_NATIVE_
661                 *converter = Swap32;
662             #endif
663             break;
664         case ASIOSTInt32MSB16:
665             /* dest: paInt32, 16 bit shift, possible byte swap */
666             #ifdef PA_LSB_IS_NATIVE_
667                 *converter = SwapShiftLeft32;
668             #else
669                 *converter = ShiftLeft32;
670             #endif
671             *shift = 16;
672             break;
673         case ASIOSTInt32MSB18:
674             /* dest: paInt32, 14 bit shift, possible byte swap */
675             #ifdef PA_LSB_IS_NATIVE_
676                 *converter = SwapShiftLeft32;
677             #else
678                 *converter = ShiftLeft32;
679             #endif
680             *shift = 14;
681             break;
682         case ASIOSTInt32MSB20:
683             /* dest: paInt32, 12 bit shift, possible byte swap */
684             #ifdef PA_LSB_IS_NATIVE_
685                 *converter = SwapShiftLeft32;
686             #else
687                 *converter = ShiftLeft32;
688             #endif
689             *shift = 12;
690             break;
691         case ASIOSTInt32MSB24:
692             /* dest: paInt32, 8 bit shift, possible byte swap */
693             #ifdef PA_LSB_IS_NATIVE_
694                 *converter = SwapShiftLeft32;
695             #else
696                 *converter = ShiftLeft32;
697             #endif
698             *shift = 8;
699             break;
700         case ASIOSTInt32LSB16:
701             /* dest: paInt32, 16 bit shift, possible byte swap */
702             #ifdef PA_MSB_IS_NATIVE_
703                 *converter = SwapShiftLeft32;
704             #else
705                 *converter = ShiftLeft32;
706             #endif
707             *shift = 16;
708             break;
709         case ASIOSTInt32LSB18:
710             /* dest: paInt32, 14 bit shift, possible byte swap */
711             #ifdef PA_MSB_IS_NATIVE_
712                 *converter = SwapShiftLeft32;
713             #else
714                 *converter = ShiftLeft32;
715             #endif
716             *shift = 14;
717             break;
718         case ASIOSTInt32LSB20:
719             /* dest: paInt32, 12 bit shift, possible byte swap */
720             #ifdef PA_MSB_IS_NATIVE_
721                 *converter = SwapShiftLeft32;
722             #else
723                 *converter = ShiftLeft32;
724             #endif
725             *shift = 12;
726             break;
727         case ASIOSTInt32LSB24:
728             /* dest: paInt32, 8 bit shift, possible byte swap */
729             #ifdef PA_MSB_IS_NATIVE_
730                 *converter = SwapShiftLeft32;
731             #else
732                 *converter = ShiftLeft32;
733             #endif
734             *shift = 8;
735             break;
736         case ASIOSTInt24MSB:
737             /* dest: paInt24, no conversion necessary, possible byte swap */
738             #ifdef PA_LSB_IS_NATIVE_
739                 *converter = Swap24;
740             #endif
741             break;
742         case ASIOSTInt24LSB:
743             /* dest: paInt24, no conversion necessary, possible byte swap */
744             #ifdef PA_MSB_IS_NATIVE_
745                 *converter = Swap24;
746             #endif
747             break;
748     }
749 }
750 
751 
SelectPaToAsioConverter(ASIOSampleType type,PaAsioBufferConverter ** converter,long * shift)752 static void SelectPaToAsioConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
753 {
754     *shift = 0;
755     *converter = 0;
756 
757     switch (type) {
758         case ASIOSTInt16MSB:
759             /* src: paInt16, no conversion necessary, possible byte swap*/
760             #ifdef PA_LSB_IS_NATIVE_
761                 *converter = Swap16;
762             #endif
763             break;
764         case ASIOSTInt16LSB:
765             /* src: paInt16, no conversion necessary, possible byte swap*/
766             #ifdef PA_MSB_IS_NATIVE_
767                 *converter = Swap16;
768             #endif
769             break;
770         case ASIOSTFloat32MSB:
771             /* src: paFloat32, no conversion necessary, possible byte swap*/
772             #ifdef PA_LSB_IS_NATIVE_
773                 *converter = Swap32;
774             #endif
775             break;
776         case ASIOSTFloat32LSB:
777             /* src: paFloat32, no conversion necessary, possible byte swap*/
778             #ifdef PA_MSB_IS_NATIVE_
779                 *converter = Swap32;
780             #endif
781             break;
782         case ASIOSTFloat64MSB:
783             /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
784             #ifdef PA_LSB_IS_NATIVE_
785                 *converter = ConvertFloat32ToFloat64Swap64;
786             #else
787                 *converter = ConvertFloat32ToFloat64;
788             #endif
789             break;
790         case ASIOSTFloat64LSB:
791             /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
792             #ifdef PA_MSB_IS_NATIVE_
793                 *converter = ConvertFloat32ToFloat64Swap64;
794             #else
795                 *converter = ConvertFloat32ToFloat64;
796             #endif
797             break;
798         case ASIOSTInt32MSB:
799             /* src: paInt32, no conversion necessary, possible byte swap */
800             #ifdef PA_LSB_IS_NATIVE_
801                 *converter = Swap32;
802             #endif
803             break;
804         case ASIOSTInt32LSB:
805             /* src: paInt32, no conversion necessary, possible byte swap */
806             #ifdef PA_MSB_IS_NATIVE_
807                 *converter = Swap32;
808             #endif
809             break;
810         case ASIOSTInt32MSB16:
811             /* src: paInt32, 16 bit shift, possible byte swap */
812             #ifdef PA_LSB_IS_NATIVE_
813                 *converter = ShiftRightSwap32;
814             #else
815                 *converter = ShiftRight32;
816             #endif
817             *shift = 16;
818             break;
819         case ASIOSTInt32MSB18:
820             /* src: paInt32, 14 bit shift, possible byte swap */
821             #ifdef PA_LSB_IS_NATIVE_
822                 *converter = ShiftRightSwap32;
823             #else
824                 *converter = ShiftRight32;
825             #endif
826             *shift = 14;
827             break;
828         case ASIOSTInt32MSB20:
829             /* src: paInt32, 12 bit shift, possible byte swap */
830             #ifdef PA_LSB_IS_NATIVE_
831                 *converter = ShiftRightSwap32;
832             #else
833                 *converter = ShiftRight32;
834             #endif
835             *shift = 12;
836             break;
837         case ASIOSTInt32MSB24:
838             /* src: paInt32, 8 bit shift, possible byte swap */
839             #ifdef PA_LSB_IS_NATIVE_
840                 *converter = ShiftRightSwap32;
841             #else
842                 *converter = ShiftRight32;
843             #endif
844             *shift = 8;
845             break;
846         case ASIOSTInt32LSB16:
847             /* src: paInt32, 16 bit shift, possible byte swap */
848             #ifdef PA_MSB_IS_NATIVE_
849                 *converter = ShiftRightSwap32;
850             #else
851                 *converter = ShiftRight32;
852             #endif
853             *shift = 16;
854             break;
855         case ASIOSTInt32LSB18:
856             /* src: paInt32, 14 bit shift, possible byte swap */
857             #ifdef PA_MSB_IS_NATIVE_
858                 *converter = ShiftRightSwap32;
859             #else
860                 *converter = ShiftRight32;
861             #endif
862             *shift = 14;
863             break;
864         case ASIOSTInt32LSB20:
865             /* src: paInt32, 12 bit shift, possible byte swap */
866             #ifdef PA_MSB_IS_NATIVE_
867                 *converter = ShiftRightSwap32;
868             #else
869                 *converter = ShiftRight32;
870             #endif
871             *shift = 12;
872             break;
873         case ASIOSTInt32LSB24:
874             /* src: paInt32, 8 bit shift, possible byte swap */
875             #ifdef PA_MSB_IS_NATIVE_
876                 *converter = ShiftRightSwap32;
877             #else
878                 *converter = ShiftRight32;
879             #endif
880             *shift = 8;
881             break;
882         case ASIOSTInt24MSB:
883             /* src: paInt24, no conversion necessary, possible byte swap */
884             #ifdef PA_LSB_IS_NATIVE_
885                 *converter = Swap24;
886             #endif
887             break;
888         case ASIOSTInt24LSB:
889             /* src: paInt24, no conversion necessary, possible byte swap */
890             #ifdef PA_MSB_IS_NATIVE_
891                 *converter = Swap24;
892             #endif
893             break;
894     }
895 }
896 
897 
898 typedef struct PaAsioDeviceInfo
899 {
900     PaDeviceInfo commonDeviceInfo;
901     long minBufferSize;
902     long maxBufferSize;
903     long preferredBufferSize;
904     long bufferGranularity;
905 
906     ASIOChannelInfo *asioChannelInfos;
907 }
908 PaAsioDeviceInfo;
909 
910 
PaAsio_GetAvailableLatencyValues(PaDeviceIndex device,long * minLatency,long * maxLatency,long * preferredLatency,long * granularity)911 PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device,
912 		long *minLatency, long *maxLatency, long *preferredLatency, long *granularity )
913 {
914     PaError result;
915     PaUtilHostApiRepresentation *hostApi;
916     PaDeviceIndex hostApiDevice;
917 
918     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
919 
920     if( result == paNoError )
921     {
922         result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
923 
924         if( result == paNoError )
925         {
926             PaAsioDeviceInfo *asioDeviceInfo =
927                     (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
928 
929             *minLatency = asioDeviceInfo->minBufferSize;
930             *maxLatency = asioDeviceInfo->maxBufferSize;
931             *preferredLatency = asioDeviceInfo->preferredBufferSize;
932             *granularity = asioDeviceInfo->bufferGranularity;
933         }
934     }
935 
936     return result;
937 }
938 
939 
940 
941 /*
942     load the asio driver named by <driverName> and return statistics about
943     the driver in info. If no error occurred, the driver will remain open
944     and must be closed by the called by calling ASIOExit() - if an error
945     is returned the driver will already be closed.
946 */
LoadAsioDriver(const char * driverName,PaAsioDriverInfo * driverInfo,void * systemSpecific)947 static PaError LoadAsioDriver( const char *driverName,
948         PaAsioDriverInfo *driverInfo, void *systemSpecific )
949 {
950     PaError result = paNoError;
951     ASIOError asioError;
952     int asioIsInitialized = 0;
953 
954     if( !loadAsioDriver( const_cast<char*>(driverName) ) )
955     {
956         result = paUnanticipatedHostError;
957         PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
958         goto error;
959     }
960 
961     memset( &driverInfo->asioDriverInfo, 0, sizeof(ASIODriverInfo) );
962     driverInfo->asioDriverInfo.asioVersion = 2;
963     driverInfo->asioDriverInfo.sysRef = systemSpecific;
964     if( (asioError = ASIOInit( &driverInfo->asioDriverInfo )) != ASE_OK )
965     {
966         result = paUnanticipatedHostError;
967         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
968         goto error;
969     }
970     else
971     {
972         asioIsInitialized = 1;
973     }
974 
975     if( (asioError = ASIOGetChannels(&driverInfo->inputChannelCount,
976             &driverInfo->outputChannelCount)) != ASE_OK )
977     {
978         result = paUnanticipatedHostError;
979         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
980         goto error;
981     }
982 
983     if( (asioError = ASIOGetBufferSize(&driverInfo->bufferMinSize,
984             &driverInfo->bufferMaxSize, &driverInfo->bufferPreferredSize,
985             &driverInfo->bufferGranularity)) != ASE_OK )
986     {
987         result = paUnanticipatedHostError;
988         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
989         goto error;
990     }
991 
992     if( ASIOOutputReady() == ASE_OK )
993         driverInfo->postOutput = true;
994     else
995         driverInfo->postOutput = false;
996 
997     return result;
998 
999 error:
1000     if( asioIsInitialized )
1001         ASIOExit();
1002 
1003     return result;
1004 }
1005 
1006 
1007 #define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_     13   /* must be the same number of elements as in the array below */
1008 static ASIOSampleRate defaultSampleRateSearchOrder_[]
1009      = {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0,
1010         192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
1011 
1012 
PaAsio_Initialize(PaUtilHostApiRepresentation ** hostApi,PaHostApiIndex hostApiIndex)1013 PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
1014 {
1015     PaError result = paNoError;
1016     int i, driverCount;
1017     PaAsioHostApiRepresentation *asioHostApi;
1018     PaAsioDeviceInfo *deviceInfoArray;
1019     char **names;
1020     PaAsioDriverInfo paAsioDriverInfo;
1021 
1022     asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
1023     if( !asioHostApi )
1024     {
1025         result = paInsufficientMemory;
1026         goto error;
1027     }
1028 
1029     asioHostApi->allocations = PaUtil_CreateAllocationGroup();
1030     if( !asioHostApi->allocations )
1031     {
1032         result = paInsufficientMemory;
1033         goto error;
1034     }
1035 
1036     asioHostApi->systemSpecific = 0;
1037     asioHostApi->openAsioDeviceIndex = paNoDevice;
1038 
1039     *hostApi = &asioHostApi->inheritedHostApiRep;
1040     (*hostApi)->info.structVersion = 1;
1041 
1042     (*hostApi)->info.type = paASIO;
1043     (*hostApi)->info.name = "ASIO";
1044     (*hostApi)->info.deviceCount = 0;
1045 
1046     #ifdef WINDOWS
1047         /* use desktop window as system specific ptr */
1048         asioHostApi->systemSpecific = GetDesktopWindow();
1049         CoInitialize(NULL);
1050     #endif
1051 
1052     /* MUST BE CHECKED : to force fragments loading on Mac */
1053     loadAsioDriver( "dummy" );
1054 
1055     /* driverCount is the number of installed drivers - not necessarily
1056         the number of installed physical devices. */
1057     #if MAC
1058         driverCount = asioDrivers->getNumFragments();
1059     #elif WINDOWS
1060         driverCount = asioDrivers->asioGetNumDev();
1061     #endif
1062 
1063     if( driverCount > 0 )
1064     {
1065         names = GetAsioDriverNames( asioHostApi->allocations, driverCount );
1066         if( !names )
1067         {
1068             result = paInsufficientMemory;
1069             goto error;
1070         }
1071 
1072 
1073         /* allocate enough space for all drivers, even if some aren't installed */
1074 
1075         (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
1076                 asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount );
1077         if( !(*hostApi)->deviceInfos )
1078         {
1079             result = paInsufficientMemory;
1080             goto error;
1081         }
1082 
1083         /* allocate all device info structs in a contiguous block */
1084         deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory(
1085                 asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount );
1086         if( !deviceInfoArray )
1087         {
1088             result = paInsufficientMemory;
1089             goto error;
1090         }
1091 
1092         for( i=0; i < driverCount; ++i )
1093         {
1094 
1095             PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i]));
1096 
1097             // Since portaudio opens ALL ASIO drivers, and no one else does that,
1098             // we face fact that some drivers were not meant for it, drivers which act
1099             // like shells on top of REAL drivers, for instance.
1100             // so we get duplicate handles, locks and other problems.
1101             // so lets NOT try to load any such wrappers.
1102             // The ones i [davidv] know of so far are:
1103 
1104             if (   strcmp (names[i],"ASIO DirectX Full Duplex Driver") == 0
1105                 || strcmp (names[i],"ASIO Multimedia Driver")          == 0
1106                 || strncmp(names[i],"Premiere",8)                      == 0   //"Premiere Elements Windows Sound 1.0"
1107                 || strncmp(names[i],"Adobe",5)                         == 0 ) //"Adobe Default Windows Sound 1.5"
1108             {
1109                 PA_DEBUG(("BLACKLISTED!!!\n"));
1110                 continue;
1111             }
1112 
1113 
1114             /* Attempt to load the asio driver... */
1115             if( LoadAsioDriver( names[i], &paAsioDriverInfo, asioHostApi->systemSpecific ) == paNoError )
1116             {
1117                 PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
1118                 PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
1119 
1120                 deviceInfo->structVersion = 2;
1121                 deviceInfo->hostApi = hostApiIndex;
1122 
1123                 deviceInfo->name = names[i];
1124                 PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n",  i,deviceInfo->name));
1125                 PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels       = %d\n", i, paAsioDriverInfo.inputChannelCount));
1126                 PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels      = %d\n", i, paAsioDriverInfo.outputChannelCount));
1127                 PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize       = %d\n", i, paAsioDriverInfo.bufferMinSize));
1128                 PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize       = %d\n", i, paAsioDriverInfo.bufferMaxSize));
1129                 PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriverInfo.bufferPreferredSize));
1130                 PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity   = %d\n", i, paAsioDriverInfo.bufferGranularity));
1131 
1132                 deviceInfo->maxInputChannels  = paAsioDriverInfo.inputChannelCount;
1133                 deviceInfo->maxOutputChannels = paAsioDriverInfo.outputChannelCount;
1134 
1135                 deviceInfo->defaultSampleRate = 0.;
1136                 bool foundDefaultSampleRate = false;
1137                 for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j )
1138                 {
1139                     ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
1140                     if( asioError != ASE_NoClock && asioError != ASE_NotPresent )
1141                     {
1142                         deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
1143                         foundDefaultSampleRate = true;
1144                         break;
1145                     }
1146                 }
1147 
1148                 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate));
1149 
1150                 if( foundDefaultSampleRate ){
1151 
1152                     /* calculate default latency values from bufferPreferredSize
1153                         for default low latency, and bufferPreferredSize * 3
1154                         for default high latency.
1155                         use the default sample rate to convert from samples to
1156                         seconds. Without knowing what sample rate the user will
1157                         use this is the best we can do.
1158                     */
1159 
1160                     double defaultLowLatency =
1161                             paAsioDriverInfo.bufferPreferredSize / deviceInfo->defaultSampleRate;
1162 
1163                     deviceInfo->defaultLowInputLatency = defaultLowLatency;
1164                     deviceInfo->defaultLowOutputLatency = defaultLowLatency;
1165 
1166                     long defaultHighLatencyBufferSize =
1167                             paAsioDriverInfo.bufferPreferredSize * 3;
1168 
1169                     if( defaultHighLatencyBufferSize > paAsioDriverInfo.bufferMaxSize )
1170                         defaultHighLatencyBufferSize = paAsioDriverInfo.bufferMaxSize;
1171 
1172                     double defaultHighLatency =
1173                             defaultHighLatencyBufferSize / deviceInfo->defaultSampleRate;
1174 
1175                     if( defaultHighLatency < defaultLowLatency )
1176                         defaultHighLatency = defaultLowLatency; /* just incase the driver returns something strange */
1177 
1178                     deviceInfo->defaultHighInputLatency = defaultHighLatency;
1179                     deviceInfo->defaultHighOutputLatency = defaultHighLatency;
1180 
1181                 }else{
1182 
1183                     deviceInfo->defaultLowInputLatency = 0.;
1184                     deviceInfo->defaultLowOutputLatency = 0.;
1185                     deviceInfo->defaultHighInputLatency = 0.;
1186                     deviceInfo->defaultHighOutputLatency = 0.;
1187                 }
1188 
1189                 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", i, deviceInfo->defaultLowInputLatency));
1190                 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", i, deviceInfo->defaultLowOutputLatency));
1191                 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i, deviceInfo->defaultHighInputLatency));
1192                 PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i, deviceInfo->defaultHighOutputLatency));
1193 
1194                 asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize;
1195                 asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize;
1196                 asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize;
1197                 asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity;
1198 
1199 
1200                 asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory(
1201                         asioHostApi->allocations,
1202                         sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels
1203                                 + deviceInfo->maxOutputChannels) );
1204                 if( !asioDeviceInfo->asioChannelInfos )
1205                 {
1206                     result = paInsufficientMemory;
1207                     goto error;
1208                 }
1209 
1210                 int a;
1211 
1212                 for( a=0; a < deviceInfo->maxInputChannels; ++a ){
1213                     asioDeviceInfo->asioChannelInfos[a].channel = a;
1214                     asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue;
1215                     ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] );
1216                     if( asioError != ASE_OK )
1217                     {
1218                         result = paUnanticipatedHostError;
1219                         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
1220                         goto error;
1221                     }
1222                 }
1223 
1224                 for( a=0; a < deviceInfo->maxOutputChannels; ++a ){
1225                     int b = deviceInfo->maxInputChannels + a;
1226                     asioDeviceInfo->asioChannelInfos[b].channel = a;
1227                     asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse;
1228                     ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] );
1229                     if( asioError != ASE_OK )
1230                     {
1231                         result = paUnanticipatedHostError;
1232                         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
1233                         goto error;
1234                     }
1235                 }
1236 
1237 
1238                 /* unload the driver */
1239                 ASIOExit();
1240 
1241                 (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
1242                 ++(*hostApi)->info.deviceCount;
1243             }
1244         }
1245     }
1246 
1247     if( (*hostApi)->info.deviceCount > 0 )
1248     {
1249         (*hostApi)->info.defaultInputDevice = 0;
1250         (*hostApi)->info.defaultOutputDevice = 0;
1251     }
1252     else
1253     {
1254         (*hostApi)->info.defaultInputDevice = paNoDevice;
1255         (*hostApi)->info.defaultOutputDevice = paNoDevice;
1256     }
1257 
1258 
1259     (*hostApi)->Terminate = Terminate;
1260     (*hostApi)->OpenStream = OpenStream;
1261     (*hostApi)->IsFormatSupported = IsFormatSupported;
1262 
1263     PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
1264                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
1265                                       GetStreamTime, GetStreamCpuLoad,
1266                                       PaUtil_DummyRead, PaUtil_DummyWrite,
1267                                       PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
1268 
1269     PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream,
1270                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
1271                                       GetStreamTime, PaUtil_DummyGetCpuLoad,
1272                                       ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
1273 
1274     return result;
1275 
1276 error:
1277     if( asioHostApi )
1278     {
1279         if( asioHostApi->allocations )
1280         {
1281             PaUtil_FreeAllAllocations( asioHostApi->allocations );
1282             PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
1283         }
1284 
1285         PaUtil_FreeMemory( asioHostApi );
1286     }
1287     return result;
1288 }
1289 
1290 
Terminate(struct PaUtilHostApiRepresentation * hostApi)1291 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
1292 {
1293     PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
1294 
1295     /*
1296         IMPLEMENT ME:
1297             - clean up any resources not handled by the allocation group
1298     */
1299 
1300     if( asioHostApi->allocations )
1301     {
1302         PaUtil_FreeAllAllocations( asioHostApi->allocations );
1303         PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
1304     }
1305 
1306     PaUtil_FreeMemory( asioHostApi );
1307 }
1308 
1309 
IsFormatSupported(struct PaUtilHostApiRepresentation * hostApi,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate)1310 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
1311                                   const PaStreamParameters *inputParameters,
1312                                   const PaStreamParameters *outputParameters,
1313                                   double sampleRate )
1314 {
1315     PaError result = paNoError;
1316     PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
1317     PaAsioDriverInfo *driverInfo = &asioHostApi->openAsioDriverInfo;
1318     int inputChannelCount, outputChannelCount;
1319     PaSampleFormat inputSampleFormat, outputSampleFormat;
1320     PaDeviceIndex asioDeviceIndex;
1321     ASIOError asioError;
1322 
1323     if( inputParameters && outputParameters )
1324     {
1325         /* full duplex ASIO stream must use the same device for input and output */
1326 
1327         if( inputParameters->device != outputParameters->device )
1328             return paBadIODeviceCombination;
1329     }
1330 
1331     if( inputParameters )
1332     {
1333         inputChannelCount = inputParameters->channelCount;
1334         inputSampleFormat = inputParameters->sampleFormat;
1335 
1336         /* all standard sample formats are supported by the buffer adapter,
1337             this implementation doesn't support any custom sample formats */
1338         if( inputSampleFormat & paCustomFormat )
1339             return paSampleFormatNotSupported;
1340 
1341         /* unless alternate device specification is supported, reject the use of
1342             paUseHostApiSpecificDeviceSpecification */
1343 
1344         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
1345             return paInvalidDevice;
1346 
1347         asioDeviceIndex = inputParameters->device;
1348 
1349         /* validate inputStreamInfo */
1350         /** @todo do more validation here */
1351         // if( inputParameters->hostApiSpecificStreamInfo )
1352         //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1353     }
1354     else
1355     {
1356         inputChannelCount = 0;
1357     }
1358 
1359     if( outputParameters )
1360     {
1361         outputChannelCount = outputParameters->channelCount;
1362         outputSampleFormat = outputParameters->sampleFormat;
1363 
1364         /* all standard sample formats are supported by the buffer adapter,
1365             this implementation doesn't support any custom sample formats */
1366         if( outputSampleFormat & paCustomFormat )
1367             return paSampleFormatNotSupported;
1368 
1369         /* unless alternate device specification is supported, reject the use of
1370             paUseHostApiSpecificDeviceSpecification */
1371 
1372         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
1373             return paInvalidDevice;
1374 
1375         asioDeviceIndex = outputParameters->device;
1376 
1377         /* validate outputStreamInfo */
1378         /** @todo do more validation here */
1379         // if( outputParameters->hostApiSpecificStreamInfo )
1380         //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1381     }
1382     else
1383     {
1384         outputChannelCount = 0;
1385     }
1386 
1387 
1388 
1389     /* if an ASIO device is open we can only get format information for the currently open device */
1390 
1391     if( asioHostApi->openAsioDeviceIndex != paNoDevice
1392 			&& asioHostApi->openAsioDeviceIndex != asioDeviceIndex )
1393     {
1394         return paDeviceUnavailable;
1395     }
1396 
1397 
1398     /* NOTE: we load the driver and use its current settings
1399         rather than the ones in our device info structure which may be stale */
1400 
1401     /* open the device if it's not already open */
1402     if( asioHostApi->openAsioDeviceIndex == paNoDevice )
1403     {
1404         result = LoadAsioDriver( asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
1405                 driverInfo, asioHostApi->systemSpecific );
1406         if( result != paNoError )
1407             return result;
1408     }
1409 
1410     /* check that input device can support inputChannelCount */
1411     if( inputChannelCount > 0 )
1412     {
1413         if( inputChannelCount > driverInfo->inputChannelCount )
1414         {
1415             result = paInvalidChannelCount;
1416             goto done;
1417         }
1418     }
1419 
1420     /* check that output device can support outputChannelCount */
1421     if( outputChannelCount )
1422     {
1423         if( outputChannelCount > driverInfo->outputChannelCount )
1424         {
1425             result = paInvalidChannelCount;
1426             goto done;
1427         }
1428     }
1429 
1430     /* query for sample rate support */
1431     asioError = ASIOCanSampleRate( sampleRate );
1432     if( asioError == ASE_NoClock || asioError == ASE_NotPresent )
1433     {
1434         result = paInvalidSampleRate;
1435         goto done;
1436     }
1437 
1438 done:
1439     /* close the device if it wasn't already open */
1440     if( asioHostApi->openAsioDeviceIndex == paNoDevice )
1441     {
1442         ASIOExit(); /* not sure if we should check for errors here */
1443     }
1444 
1445     if( result == paNoError )
1446         return paFormatIsSupported;
1447     else
1448         return result;
1449 }
1450 
1451 
1452 
1453 /* PaAsioStream - a stream data structure specifically for this implementation */
1454 
1455 typedef struct PaAsioStream
1456 {
1457     PaUtilStreamRepresentation streamRepresentation;
1458     PaUtilCpuLoadMeasurer cpuLoadMeasurer;
1459     PaUtilBufferProcessor bufferProcessor;
1460 
1461     PaAsioHostApiRepresentation *asioHostApi;
1462     unsigned long framesPerHostCallback;
1463 
1464     /* ASIO driver info  - these may not be needed for the life of the stream,
1465         but store them here until we work out how format conversion is going
1466         to work. */
1467 
1468     ASIOBufferInfo *asioBufferInfos;
1469     ASIOChannelInfo *asioChannelInfos;
1470     long inputLatency, outputLatency; // actual latencies returned by asio
1471 
1472     long inputChannelCount, outputChannelCount;
1473     bool postOutput;
1474 
1475     void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */
1476     void **inputBufferPtrs[2];
1477     void **outputBufferPtrs[2];
1478 
1479     PaAsioBufferConverter *inputBufferConverter;
1480     long inputShift;
1481     PaAsioBufferConverter *outputBufferConverter;
1482     long outputShift;
1483 
1484     volatile bool stopProcessing;
1485     int stopPlayoutCount;
1486     HANDLE completedBuffersPlayedEvent;
1487 
1488     bool streamFinishedCallbackCalled;
1489     volatile int isActive;
1490     volatile bool zeroOutput; /* all future calls to the callback will output silence */
1491 
1492     volatile long reenterCount;
1493     volatile long reenterError;
1494 
1495     PaStreamCallbackFlags callbackFlags;
1496 }
1497 PaAsioStream;
1498 
1499 static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */
1500 
1501 
ZeroOutputBuffers(PaAsioStream * stream,long index)1502 static void ZeroOutputBuffers( PaAsioStream *stream, long index )
1503 {
1504     int i;
1505 
1506     for( i=0; i < stream->outputChannelCount; ++i )
1507     {
1508         void *buffer = stream->asioBufferInfos[ i + stream->inputChannelCount ].buffers[index];
1509 
1510         int bytesPerSample = BytesPerAsioSample( stream->asioChannelInfos[ i + stream->inputChannelCount ].type );
1511 
1512         memset( buffer, 0, stream->framesPerHostCallback * bytesPerSample );
1513     }
1514 }
1515 
1516 
SelectHostBufferSize(unsigned long suggestedLatencyFrames,PaAsioDriverInfo * driverInfo)1517 static unsigned long SelectHostBufferSize( unsigned long suggestedLatencyFrames,
1518         PaAsioDriverInfo *driverInfo )
1519 {
1520     unsigned long result;
1521 
1522     if( suggestedLatencyFrames == 0 )
1523     {
1524         result = driverInfo->bufferPreferredSize;
1525     }
1526     else{
1527         if( suggestedLatencyFrames <= (unsigned long)driverInfo->bufferMinSize )
1528         {
1529             result = driverInfo->bufferMinSize;
1530         }
1531         else if( suggestedLatencyFrames >= (unsigned long)driverInfo->bufferMaxSize )
1532         {
1533             result = driverInfo->bufferMaxSize;
1534         }
1535         else
1536         {
1537             if( driverInfo->bufferGranularity == -1 )
1538             {
1539                 /* power-of-two */
1540                 result = 2;
1541 
1542                 while( result < suggestedLatencyFrames )
1543                     result *= 2;
1544 
1545                 if( result < (unsigned long)driverInfo->bufferMinSize )
1546                     result = driverInfo->bufferMinSize;
1547 
1548                 if( result > (unsigned long)driverInfo->bufferMaxSize )
1549                     result = driverInfo->bufferMaxSize;
1550             }
1551             else if( driverInfo->bufferGranularity == 0 )
1552             {
1553                 /* the documentation states that bufferGranularity should be
1554                     zero when bufferMinSize, bufferMaxSize and
1555                     bufferPreferredSize are the same. We assume that is the case.
1556                 */
1557 
1558                 result = driverInfo->bufferPreferredSize;
1559             }
1560             else
1561             {
1562                 /* modulo granularity */
1563 
1564                 unsigned long remainder =
1565                         suggestedLatencyFrames % driverInfo->bufferGranularity;
1566 
1567                 if( remainder == 0 )
1568                 {
1569                     result = suggestedLatencyFrames;
1570                 }
1571                 else
1572                 {
1573                     result = suggestedLatencyFrames
1574                             + (driverInfo->bufferGranularity - remainder);
1575 
1576                     if( result > (unsigned long)driverInfo->bufferMaxSize )
1577                         result = driverInfo->bufferMaxSize;
1578                 }
1579             }
1580         }
1581     }
1582 
1583     return result;
1584 }
1585 
1586 
1587 /* returns channelSelectors if present */
1588 
ValidateAsioSpecificStreamInfo(const PaStreamParameters * streamParameters,const PaAsioStreamInfo * streamInfo,int deviceChannelCount,int ** channelSelectors)1589 static PaError ValidateAsioSpecificStreamInfo(
1590         const PaStreamParameters *streamParameters,
1591         const PaAsioStreamInfo *streamInfo,
1592         int deviceChannelCount,
1593         int **channelSelectors )
1594 {
1595 	if( streamInfo )
1596 	{
1597 	    if( streamInfo->size != sizeof( PaAsioStreamInfo )
1598 	            || streamInfo->version != 1 )
1599 	    {
1600 	        return paIncompatibleHostApiSpecificStreamInfo;
1601 	    }
1602 
1603 	    if( streamInfo->flags & paAsioUseChannelSelectors )
1604             *channelSelectors = streamInfo->channelSelectors;
1605 
1606         if( !(*channelSelectors) )
1607             return paIncompatibleHostApiSpecificStreamInfo;
1608 
1609         for( int i=0; i < streamParameters->channelCount; ++i ){
1610              if( (*channelSelectors)[i] < 0
1611                     || (*channelSelectors)[i] >= deviceChannelCount ){
1612                 return paInvalidChannelCount;
1613              }
1614         }
1615 	}
1616 
1617 	return paNoError;
1618 }
1619 
1620 
1621 /* see pa_hostapi.h for a list of validity guarantees made about OpenStream  parameters */
1622 
OpenStream(struct PaUtilHostApiRepresentation * hostApi,PaStream ** s,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate,unsigned long framesPerBuffer,PaStreamFlags streamFlags,PaStreamCallback * streamCallback,void * userData)1623 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
1624                            PaStream** s,
1625                            const PaStreamParameters *inputParameters,
1626                            const PaStreamParameters *outputParameters,
1627                            double sampleRate,
1628                            unsigned long framesPerBuffer,
1629                            PaStreamFlags streamFlags,
1630                            PaStreamCallback *streamCallback,
1631                            void *userData )
1632 {
1633     PaError result = paNoError;
1634     PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
1635     PaAsioStream *stream = 0;
1636     PaAsioStreamInfo *inputStreamInfo, *outputStreamInfo;
1637     unsigned long framesPerHostBuffer;
1638     int inputChannelCount, outputChannelCount;
1639     PaSampleFormat inputSampleFormat, outputSampleFormat;
1640     PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
1641     unsigned long suggestedInputLatencyFrames;
1642     unsigned long suggestedOutputLatencyFrames;
1643     PaDeviceIndex asioDeviceIndex;
1644     ASIOError asioError;
1645     int asioIsInitialized = 0;
1646     int asioBuffersCreated = 0;
1647     int completedBuffersPlayedEventInited = 0;
1648     int i;
1649     PaAsioDriverInfo *driverInfo;
1650     int *inputChannelSelectors = 0;
1651     int *outputChannelSelectors = 0;
1652 
1653     /* unless we move to using lower level ASIO calls, we can only have
1654         one device open at a time */
1655     if( asioHostApi->openAsioDeviceIndex != paNoDevice ){
1656         PA_DEBUG(("OpenStream paDeviceUnavailable\n"));
1657         return paDeviceUnavailable;
1658     }
1659 
1660     if( inputParameters && outputParameters )
1661     {
1662         /* full duplex ASIO stream must use the same device for input and output */
1663 
1664         if( inputParameters->device != outputParameters->device ){
1665             PA_DEBUG(("OpenStream paBadIODeviceCombination\n"));
1666             return paBadIODeviceCombination;
1667     }
1668     }
1669 
1670     if( inputParameters )
1671     {
1672         inputChannelCount = inputParameters->channelCount;
1673         inputSampleFormat = inputParameters->sampleFormat;
1674         suggestedInputLatencyFrames = (unsigned long)((inputParameters->suggestedLatency * sampleRate)+0.5f);
1675 
1676         /* unless alternate device specification is supported, reject the use of
1677             paUseHostApiSpecificDeviceSpecification */
1678         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
1679             return paInvalidDevice;
1680 
1681         asioDeviceIndex = inputParameters->device;
1682 
1683         PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
1684 
1685         /* validate hostApiSpecificStreamInfo */
1686         inputStreamInfo = (PaAsioStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
1687         result = ValidateAsioSpecificStreamInfo( inputParameters, inputStreamInfo,
1688             asioDeviceInfo->commonDeviceInfo.maxInputChannels,
1689             &inputChannelSelectors
1690         );
1691         if( result != paNoError ) return result;
1692     }
1693     else
1694     {
1695         inputChannelCount = 0;
1696         inputSampleFormat = 0;
1697         suggestedInputLatencyFrames = 0;
1698     }
1699 
1700     if( outputParameters )
1701     {
1702         outputChannelCount = outputParameters->channelCount;
1703         outputSampleFormat = outputParameters->sampleFormat;
1704         suggestedOutputLatencyFrames = (unsigned long)((outputParameters->suggestedLatency * sampleRate)+0.5f);
1705 
1706         /* unless alternate device specification is supported, reject the use of
1707             paUseHostApiSpecificDeviceSpecification */
1708         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
1709             return paInvalidDevice;
1710 
1711         asioDeviceIndex = outputParameters->device;
1712 
1713         PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
1714 
1715         /* validate hostApiSpecificStreamInfo */
1716         outputStreamInfo = (PaAsioStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
1717         result = ValidateAsioSpecificStreamInfo( outputParameters, outputStreamInfo,
1718             asioDeviceInfo->commonDeviceInfo.maxOutputChannels,
1719             &outputChannelSelectors
1720         );
1721         if( result != paNoError ) return result;
1722     }
1723     else
1724     {
1725         outputChannelCount = 0;
1726         outputSampleFormat = 0;
1727         suggestedOutputLatencyFrames = 0;
1728     }
1729 
1730     driverInfo = &asioHostApi->openAsioDriverInfo;
1731 
1732     /* NOTE: we load the driver and use its current settings
1733         rather than the ones in our device info structure which may be stale */
1734 
1735     result = LoadAsioDriver( asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
1736             driverInfo, asioHostApi->systemSpecific );
1737     if( result == paNoError )
1738         asioIsInitialized = 1;
1739     else{
1740         PA_DEBUG(("OpenStream ERROR1\n"));
1741         goto error;
1742     }
1743 
1744     /* check that input device can support inputChannelCount */
1745     if( inputChannelCount > 0 )
1746     {
1747         if( inputChannelCount > driverInfo->inputChannelCount )
1748         {
1749             result = paInvalidChannelCount;
1750             PA_DEBUG(("OpenStream ERROR2\n"));
1751             goto error;
1752         }
1753     }
1754 
1755     /* check that output device can support outputChannelCount */
1756     if( outputChannelCount )
1757     {
1758         if( outputChannelCount > driverInfo->outputChannelCount )
1759         {
1760             result = paInvalidChannelCount;
1761             PA_DEBUG(("OpenStream ERROR3\n"));
1762             goto error;
1763         }
1764     }
1765 
1766 
1767     // check that the device supports the requested sample rate
1768 
1769     asioError = ASIOCanSampleRate( sampleRate );
1770     PA_DEBUG(("ASIOCanSampleRate(%f):%d\n",sampleRate, asioError ));
1771 
1772     if( asioError != ASE_OK )
1773     {
1774         result = paInvalidSampleRate;
1775         PA_DEBUG(("ERROR: ASIOCanSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
1776         goto error;
1777     }
1778 
1779 
1780     // retrieve the current sample rate, we only change to the requested
1781     // sample rate if the device is not already in that rate.
1782 
1783     ASIOSampleRate oldRate;
1784     asioError = ASIOGetSampleRate(&oldRate);
1785     if( asioError != ASE_OK )
1786     {
1787         result = paInvalidSampleRate;
1788         PA_DEBUG(("ERROR: ASIOGetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
1789         goto error;
1790     }
1791     PA_DEBUG(("ASIOGetSampleRate:%f\n",oldRate));
1792 
1793     if (oldRate != sampleRate){
1794 
1795         PA_DEBUG(("before ASIOSetSampleRate(%f)\n",sampleRate));
1796         asioError = ASIOSetSampleRate( sampleRate );
1797         /* Set sample rate */
1798         if( asioError != ASE_OK )
1799         {
1800             result = paInvalidSampleRate;
1801             PA_DEBUG(("ERROR: ASIOSetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
1802             goto error;
1803         }
1804         PA_DEBUG(("after ASIOSetSampleRate(%f)\n",sampleRate));
1805     }
1806     else
1807     {
1808         PA_DEBUG(("No Need to change SR\n"));
1809     }
1810 
1811 
1812     /*
1813         IMPLEMENT ME:
1814             - if a full duplex stream is requested, check that the combination
1815                 of input and output parameters is supported
1816     */
1817 
1818     /* validate platform specific flags */
1819     if( (streamFlags & paPlatformSpecificFlags) != 0 ){
1820         PA_DEBUG(("OpenStream invalid flags!!\n"));
1821         return paInvalidFlag; /* unexpected platform specific flag */
1822     }
1823 
1824 
1825     stream = (PaAsioStream*)PaUtil_AllocateMemory( sizeof(PaAsioStream) );
1826     if( !stream )
1827     {
1828         result = paInsufficientMemory;
1829         PA_DEBUG(("OpenStream ERROR5\n"));
1830         goto error;
1831     }
1832 
1833     stream->completedBuffersPlayedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
1834     if( stream->completedBuffersPlayedEvent == NULL )
1835     {
1836         result = paUnanticipatedHostError;
1837         PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
1838         PA_DEBUG(("OpenStream ERROR6\n"));
1839         goto error;
1840     }
1841     completedBuffersPlayedEventInited = 1;
1842 
1843 
1844     stream->asioBufferInfos = 0; /* for deallocation in error */
1845     stream->asioChannelInfos = 0; /* for deallocation in error */
1846     stream->bufferPtrs = 0; /* for deallocation in error */
1847 
1848     if( streamCallback )
1849     {
1850         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
1851                                                &asioHostApi->callbackStreamInterface, streamCallback, userData );
1852     }
1853     else
1854     {
1855         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
1856                                                &asioHostApi->blockingStreamInterface, streamCallback, userData );
1857     }
1858 
1859 
1860     PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
1861 
1862 
1863     stream->asioBufferInfos = (ASIOBufferInfo*)PaUtil_AllocateMemory(
1864             sizeof(ASIOBufferInfo) * (inputChannelCount + outputChannelCount) );
1865     if( !stream->asioBufferInfos )
1866     {
1867         result = paInsufficientMemory;
1868         PA_DEBUG(("OpenStream ERROR7\n"));
1869         goto error;
1870     }
1871 
1872 
1873     for( i=0; i < inputChannelCount; ++i )
1874     {
1875         ASIOBufferInfo *info = &stream->asioBufferInfos[i];
1876 
1877         info->isInput = ASIOTrue;
1878 
1879         if( inputChannelSelectors ){
1880             // inputChannelSelectors values have already been validated in
1881             // ValidateAsioSpecificStreamInfo() above
1882             info->channelNum = inputChannelSelectors[i];
1883         }else{
1884             info->channelNum = i;
1885         }
1886 
1887         info->buffers[0] = info->buffers[1] = 0;
1888     }
1889 
1890     for( i=0; i < outputChannelCount; ++i ){
1891         ASIOBufferInfo *info = &stream->asioBufferInfos[inputChannelCount+i];
1892 
1893         info->isInput = ASIOFalse;
1894 
1895         if( outputChannelSelectors ){
1896             // outputChannelSelectors values have already been validated in
1897             // ValidateAsioSpecificStreamInfo() above
1898             info->channelNum = outputChannelSelectors[i];
1899         }else{
1900             info->channelNum = i;
1901         }
1902 
1903         info->buffers[0] = info->buffers[1] = 0;
1904     }
1905 
1906 
1907     framesPerHostBuffer = SelectHostBufferSize(
1908             (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames )
1909                     ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames),
1910             driverInfo );
1911 
1912 
1913 	PA_DEBUG(("PaAsioOpenStream: framesPerHostBuffer :%d\n",  framesPerHostBuffer));
1914 
1915     asioError = ASIOCreateBuffers( stream->asioBufferInfos,
1916             inputChannelCount+outputChannelCount,
1917             framesPerHostBuffer, &asioCallbacks_ );
1918 
1919     if( asioError != ASE_OK
1920             && framesPerHostBuffer != (unsigned long)driverInfo->bufferPreferredSize )
1921     {
1922         PA_DEBUG(("ERROR: ASIOCreateBuffers: %s\n", PaAsio_GetAsioErrorText(asioError) ));
1923         /*
1924             Some buggy drivers (like the Hoontech DSP24) give incorrect
1925             [min, preferred, max] values They should work with the preferred size
1926             value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize
1927             computed in SelectHostBufferSize, we try again with the preferred size.
1928         */
1929 
1930         framesPerHostBuffer = driverInfo->bufferPreferredSize;
1931 
1932         PA_DEBUG(("PaAsioOpenStream: CORRECTED framesPerHostBuffer :%d\n",  framesPerHostBuffer));
1933 
1934         ASIOError asioError2 = ASIOCreateBuffers( stream->asioBufferInfos,
1935                 inputChannelCount+outputChannelCount,
1936                  framesPerHostBuffer, &asioCallbacks_ );
1937         if( asioError2 == ASE_OK )
1938             asioError = ASE_OK;
1939     }
1940 
1941     if( asioError != ASE_OK )
1942     {
1943         result = paUnanticipatedHostError;
1944         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
1945         PA_DEBUG(("OpenStream ERROR9\n"));
1946         goto error;
1947     }
1948 
1949     asioBuffersCreated = 1;
1950 
1951     stream->asioChannelInfos = (ASIOChannelInfo*)PaUtil_AllocateMemory(
1952             sizeof(ASIOChannelInfo) * (inputChannelCount + outputChannelCount) );
1953     if( !stream->asioChannelInfos )
1954     {
1955         result = paInsufficientMemory;
1956         PA_DEBUG(("OpenStream ERROR10\n"));
1957         goto error;
1958     }
1959 
1960     for( i=0; i < inputChannelCount + outputChannelCount; ++i )
1961     {
1962         stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum;
1963         stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput;
1964         asioError = ASIOGetChannelInfo( &stream->asioChannelInfos[i] );
1965         if( asioError != ASE_OK )
1966         {
1967             result = paUnanticipatedHostError;
1968             PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
1969             PA_DEBUG(("OpenStream ERROR11\n"));
1970             goto error;
1971         }
1972     }
1973 
1974     stream->bufferPtrs = (void**)PaUtil_AllocateMemory(
1975             2 * sizeof(void*) * (inputChannelCount + outputChannelCount) );
1976     if( !stream->bufferPtrs )
1977     {
1978         result = paInsufficientMemory;
1979         PA_DEBUG(("OpenStream ERROR12\n"));
1980         goto error;
1981     }
1982 
1983     if( inputChannelCount > 0 )
1984     {
1985         stream->inputBufferPtrs[0] = stream-> bufferPtrs;
1986         stream->inputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount];
1987 
1988         for( i=0; i<inputChannelCount; ++i )
1989         {
1990             stream->inputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0];
1991             stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1];
1992         }
1993     }
1994     else
1995     {
1996         stream->inputBufferPtrs[0] = 0;
1997         stream->inputBufferPtrs[1] = 0;
1998     }
1999 
2000     if( outputChannelCount > 0 )
2001     {
2002         stream->outputBufferPtrs[0] = &stream->bufferPtrs[inputChannelCount*2];
2003         stream->outputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount*2 + outputChannelCount];
2004 
2005         for( i=0; i<outputChannelCount; ++i )
2006         {
2007             stream->outputBufferPtrs[0][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[0];
2008             stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[1];
2009         }
2010     }
2011     else
2012     {
2013         stream->outputBufferPtrs[0] = 0;
2014         stream->outputBufferPtrs[1] = 0;
2015     }
2016 
2017     if( inputChannelCount > 0 )
2018     {
2019         /* FIXME: assume all channels use the same type for now */
2020         ASIOSampleType inputType = stream->asioChannelInfos[0].type;
2021 
2022         PA_DEBUG(("ASIO Input  type:%d",inputType));
2023         AsioSampleTypeLOG(inputType);
2024         hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( inputType );
2025 
2026         SelectAsioToPaConverter( inputType, &stream->inputBufferConverter, &stream->inputShift );
2027     }
2028     else
2029     {
2030         hostInputSampleFormat = 0;
2031         stream->inputBufferConverter = 0;
2032     }
2033 
2034     if( outputChannelCount > 0 )
2035     {
2036         /* FIXME: assume all channels use the same type for now */
2037         ASIOSampleType outputType = stream->asioChannelInfos[inputChannelCount].type;
2038 
2039         PA_DEBUG(("ASIO Output type:%d",outputType));
2040         AsioSampleTypeLOG(outputType);
2041         hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( outputType );
2042 
2043         SelectPaToAsioConverter( outputType, &stream->outputBufferConverter, &stream->outputShift );
2044     }
2045     else
2046     {
2047         hostOutputSampleFormat = 0;
2048         stream->outputBufferConverter = 0;
2049     }
2050 
2051     result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
2052                     inputChannelCount, inputSampleFormat, hostInputSampleFormat,
2053                     outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
2054                     sampleRate, streamFlags, framesPerBuffer,
2055                     framesPerHostBuffer, paUtilFixedHostBufferSize,
2056                     streamCallback, userData );
2057     if( result != paNoError ){
2058         PA_DEBUG(("OpenStream ERROR13\n"));
2059         goto error;
2060     }
2061 
2062 
2063     ASIOGetLatencies( &stream->inputLatency, &stream->outputLatency );
2064 
2065     stream->streamRepresentation.streamInfo.inputLatency =
2066             (double)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)
2067                 + stream->inputLatency) / sampleRate;   // seconds
2068     stream->streamRepresentation.streamInfo.outputLatency =
2069             (double)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)
2070                 + stream->outputLatency) / sampleRate; // seconds
2071     stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
2072 
2073     // the code below prints the ASIO latency which doesn't include the
2074     // buffer processor latency. it reports the added latency separately
2075     PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
2076             stream->inputLatency,
2077             (long)((stream->inputLatency*1000)/ sampleRate),
2078             PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor),
2079             (long)((PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)*1000)/ sampleRate)
2080             ));
2081 
2082     PA_DEBUG(("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
2083             stream->outputLatency,
2084             (long)((stream->outputLatency*1000)/ sampleRate),
2085             PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor),
2086             (long)((PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)*1000)/ sampleRate)
2087             ));
2088 
2089     stream->asioHostApi = asioHostApi;
2090     stream->framesPerHostCallback = framesPerHostBuffer;
2091 
2092     stream->inputChannelCount = inputChannelCount;
2093     stream->outputChannelCount = outputChannelCount;
2094     stream->postOutput = driverInfo->postOutput;
2095     stream->isActive = 0;
2096 
2097     asioHostApi->openAsioDeviceIndex = asioDeviceIndex;
2098 
2099     *s = (PaStream*)stream;
2100 
2101     return result;
2102 
2103 error:
2104     PA_DEBUG(("goto errored\n"));
2105     if( stream )
2106     {
2107         if( completedBuffersPlayedEventInited )
2108             CloseHandle( stream->completedBuffersPlayedEvent );
2109 
2110         if( stream->asioBufferInfos )
2111             PaUtil_FreeMemory( stream->asioBufferInfos );
2112 
2113         if( stream->asioChannelInfos )
2114             PaUtil_FreeMemory( stream->asioChannelInfos );
2115 
2116         if( stream->bufferPtrs )
2117             PaUtil_FreeMemory( stream->bufferPtrs );
2118 
2119         PaUtil_FreeMemory( stream );
2120     }
2121 
2122     if( asioBuffersCreated )
2123         ASIODisposeBuffers();
2124 
2125     if( asioIsInitialized )
2126         ASIOExit();
2127 
2128     return result;
2129 }
2130 
2131 
2132 /*
2133     When CloseStream() is called, the multi-api layer ensures that
2134     the stream has already been stopped or aborted.
2135 */
CloseStream(PaStream * s)2136 static PaError CloseStream( PaStream* s )
2137 {
2138     PaError result = paNoError;
2139     PaAsioStream *stream = (PaAsioStream*)s;
2140 
2141     /*
2142         IMPLEMENT ME:
2143             - additional stream closing + cleanup
2144     */
2145 
2146     PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
2147     PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
2148 
2149     stream->asioHostApi->openAsioDeviceIndex = paNoDevice;
2150 
2151     CloseHandle( stream->completedBuffersPlayedEvent );
2152 
2153     PaUtil_FreeMemory( stream->asioBufferInfos );
2154     PaUtil_FreeMemory( stream->asioChannelInfos );
2155     PaUtil_FreeMemory( stream->bufferPtrs );
2156     PaUtil_FreeMemory( stream );
2157 
2158     ASIODisposeBuffers();
2159     ASIOExit();
2160 
2161     return result;
2162 }
2163 
2164 
bufferSwitch(long index,ASIOBool directProcess)2165 static void bufferSwitch(long index, ASIOBool directProcess)
2166 {
2167 //TAKEN FROM THE ASIO SDK
2168 
2169     // the actual processing callback.
2170     // Beware that this is normally in a seperate thread, hence be sure that
2171     // you take care about thread synchronization. This is omitted here for
2172     // simplicity.
2173 
2174     // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
2175     // to be created though it will only set the timeInfo.samplePosition and
2176     // timeInfo.systemTime fields and the according flags
2177 
2178     ASIOTime  timeInfo;
2179     memset( &timeInfo, 0, sizeof (timeInfo) );
2180 
2181     // get the time stamp of the buffer, not necessary if no
2182     // synchronization to other media is required
2183     if( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
2184             timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
2185 
2186     // Call the real callback
2187     bufferSwitchTimeInfo( &timeInfo, index, directProcess );
2188 }
2189 
2190 
2191 // conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
2192 #if NATIVE_INT64
2193 	#define ASIO64toDouble(a)  (a)
2194 #else
2195 	const double twoRaisedTo32 = 4294967296.;
2196 	#define ASIO64toDouble(a)  ((a).lo + (a).hi * twoRaisedTo32)
2197 #endif
2198 
bufferSwitchTimeInfo(ASIOTime * timeInfo,long index,ASIOBool directProcess)2199 static ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool directProcess )
2200 {
2201     // the actual processing callback.
2202     // Beware that this is normally in a seperate thread, hence be sure that
2203     // you take care about thread synchronization.
2204 
2205 
2206     /* The SDK says the following about the directProcess flag:
2207         suggests to the host whether it should immediately start processing
2208         (directProcess == ASIOTrue), or whether its process should be deferred
2209         because the call comes from a very low level (for instance, a high level
2210         priority interrupt), and direct processing would cause timing instabilities for
2211         the rest of the system. If in doubt, directProcess should be set to ASIOFalse.
2212 
2213         We just ignore directProcess. This could cause incompatibilities with
2214         drivers which really don't want the audio processing to occur in this
2215         callback, but none have been identified yet.
2216     */
2217 
2218     (void) directProcess; /* suppress unused parameter warning */
2219 
2220 #if 0
2221     // store the timeInfo for later use
2222     asioDriverInfo.tInfo = *timeInfo;
2223 
2224     // get the time stamp of the buffer, not necessary if no
2225     // synchronization to other media is required
2226 
2227     if (timeInfo->timeInfo.flags & kSystemTimeValid)
2228             asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
2229     else
2230             asioDriverInfo.nanoSeconds = 0;
2231 
2232     if (timeInfo->timeInfo.flags & kSamplePositionValid)
2233             asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
2234     else
2235             asioDriverInfo.samples = 0;
2236 
2237     if (timeInfo->timeCode.flags & kTcValid)
2238             asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
2239     else
2240             asioDriverInfo.tcSamples = 0;
2241 
2242     // get the system reference time
2243     asioDriverInfo.sysRefTime = get_sys_reference_time();
2244 #endif
2245 
2246 #if 0
2247     // a few debug messages for the Windows device driver developer
2248     // tells you the time when driver got its interrupt and the delay until the app receives
2249     // the event notification.
2250     static double last_samples = 0;
2251     char tmp[128];
2252     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));
2253     OutputDebugString (tmp);
2254     last_samples = asioDriverInfo.samples;
2255 #endif
2256 
2257 
2258     if( !theAsioStream )
2259         return 0L;
2260 
2261     // Keep sample position
2262     // FIXME: asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
2263 
2264 
2265     // protect against reentrancy
2266     if( PaAsio_AtomicIncrement(&theAsioStream->reenterCount) )
2267     {
2268         theAsioStream->reenterError++;
2269         //DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError));
2270         return 0L;
2271     }
2272 
2273     int buffersDone = 0;
2274 
2275     do
2276     {
2277         if( buffersDone > 0 )
2278         {
2279             // this is a reentered buffer, we missed processing it on time
2280             // set the input overflow and output underflow flags as appropriate
2281 
2282             if( theAsioStream->inputChannelCount > 0 )
2283                 theAsioStream->callbackFlags |= paInputOverflow;
2284 
2285             if( theAsioStream->outputChannelCount > 0 )
2286                 theAsioStream->callbackFlags |= paOutputUnderflow;
2287         }
2288         else
2289         {
2290             if( theAsioStream->zeroOutput )
2291             {
2292                 ZeroOutputBuffers( theAsioStream, index );
2293 
2294                 // Finally if the driver supports the ASIOOutputReady() optimization,
2295                 // do it here, all data are in place
2296                 if( theAsioStream->postOutput )
2297                     ASIOOutputReady();
2298 
2299                 if( theAsioStream->stopProcessing )
2300                 {
2301                     if( theAsioStream->stopPlayoutCount < 2 )
2302                     {
2303                         ++theAsioStream->stopPlayoutCount;
2304                         if( theAsioStream->stopPlayoutCount == 2 )
2305                         {
2306                             theAsioStream->isActive = 0;
2307                             if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
2308                                 theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
2309                             theAsioStream->streamFinishedCallbackCalled = true;
2310                             SetEvent( theAsioStream->completedBuffersPlayedEvent );
2311                         }
2312                     }
2313                 }
2314             }
2315             else
2316             {
2317 
2318 #if 0
2319 // test code to try to detect slip conditions... these may work on some systems
2320 // but neither of them work on the RME Digi96
2321 
2322 // check that sample delta matches buffer size (otherwise we must have skipped
2323 // a buffer.
2324 static double last_samples = -512;
2325 double samples;
2326 //if( timeInfo->timeCode.flags & kTcValid )
2327 //    samples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
2328 //else
2329     samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
2330 int delta = samples - last_samples;
2331 //printf( "%d\n", delta);
2332 last_samples = samples;
2333 
2334 if( delta > theAsioStream->framesPerHostCallback )
2335 {
2336     if( theAsioStream->inputChannelCount > 0 )
2337         theAsioStream->callbackFlags |= paInputOverflow;
2338 
2339     if( theAsioStream->outputChannelCount > 0 )
2340         theAsioStream->callbackFlags |= paOutputUnderflow;
2341 }
2342 
2343 // check that the buffer index is not the previous index (which would indicate
2344 // that a buffer was skipped.
2345 static int previousIndex = 1;
2346 if( index == previousIndex )
2347 {
2348     if( theAsioStream->inputChannelCount > 0 )
2349         theAsioStream->callbackFlags |= paInputOverflow;
2350 
2351     if( theAsioStream->outputChannelCount > 0 )
2352         theAsioStream->callbackFlags |= paOutputUnderflow;
2353 }
2354 previousIndex = index;
2355 #endif
2356 
2357                 int i;
2358 
2359                 PaUtil_BeginCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer );
2360 
2361                 PaStreamCallbackTimeInfo paTimeInfo;
2362 
2363                 // asio systemTime is supposed to be measured according to the same
2364                 // clock as timeGetTime
2365                 paTimeInfo.currentTime = (ASIO64toDouble( timeInfo->timeInfo.systemTime ) * .000000001);
2366 
2367                 /* patch from Paul Boege */
2368                 paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime -
2369                     ((double)theAsioStream->inputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
2370 
2371                 paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime +
2372                     ((double)theAsioStream->outputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
2373 
2374                 /* old version is buggy because the buffer processor also adds in its latency to the time parameters
2375                 paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency;
2376                 paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency;
2377                 */
2378 #if 1
2379 // detect underflows by checking inter-callback time > 2 buffer period
2380 static double previousTime = -1;
2381 if( previousTime > 0 ){
2382 
2383     double delta = paTimeInfo.currentTime - previousTime;
2384 
2385     if( delta >= 2. * (theAsioStream->framesPerHostCallback / theAsioStream->streamRepresentation.streamInfo.sampleRate) ){
2386         if( theAsioStream->inputChannelCount > 0 )
2387             theAsioStream->callbackFlags |= paInputOverflow;
2388 
2389         if( theAsioStream->outputChannelCount > 0 )
2390             theAsioStream->callbackFlags |= paOutputUnderflow;
2391     }
2392 }
2393 previousTime = paTimeInfo.currentTime;
2394 #endif
2395 
2396                 // note that the above input and output times do not need to be
2397                 // adjusted for the latency of the buffer processor -- the buffer
2398                 // processor handles that.
2399 
2400                 if( theAsioStream->inputBufferConverter )
2401                 {
2402                     for( i=0; i<theAsioStream->inputChannelCount; i++ )
2403                     {
2404                         theAsioStream->inputBufferConverter( theAsioStream->inputBufferPtrs[index][i],
2405                                 theAsioStream->inputShift, theAsioStream->framesPerHostCallback );
2406                     }
2407                 }
2408 
2409                 PaUtil_BeginBufferProcessing( &theAsioStream->bufferProcessor, &paTimeInfo, theAsioStream->callbackFlags );
2410 
2411                 /* reset status flags once they've been passed to the callback */
2412                 theAsioStream->callbackFlags = 0;
2413 
2414                 PaUtil_SetInputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
2415                 for( i=0; i<theAsioStream->inputChannelCount; ++i )
2416                     PaUtil_SetNonInterleavedInputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i] );
2417 
2418                 PaUtil_SetOutputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
2419                 for( i=0; i<theAsioStream->outputChannelCount; ++i )
2420                     PaUtil_SetNonInterleavedOutputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i] );
2421 
2422                 int callbackResult;
2423                 if( theAsioStream->stopProcessing )
2424                     callbackResult = paComplete;
2425                 else
2426                     callbackResult = paContinue;
2427                 unsigned long framesProcessed = PaUtil_EndBufferProcessing( &theAsioStream->bufferProcessor, &callbackResult );
2428 
2429                 if( theAsioStream->outputBufferConverter )
2430                 {
2431                     for( i=0; i<theAsioStream->outputChannelCount; i++ )
2432                     {
2433                         theAsioStream->outputBufferConverter( theAsioStream->outputBufferPtrs[index][i],
2434                                 theAsioStream->outputShift, theAsioStream->framesPerHostCallback );
2435                     }
2436                 }
2437 
2438                 PaUtil_EndCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer, framesProcessed );
2439 
2440                 // Finally if the driver supports the ASIOOutputReady() optimization,
2441                 // do it here, all data are in place
2442                 if( theAsioStream->postOutput )
2443                     ASIOOutputReady();
2444 
2445                 if( callbackResult == paContinue )
2446                 {
2447                     /* nothing special to do */
2448                 }
2449                 else if( callbackResult == paAbort )
2450                 {
2451                     /* finish playback immediately  */
2452                     theAsioStream->isActive = 0;
2453                     if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
2454                         theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
2455                     theAsioStream->streamFinishedCallbackCalled = true;
2456                     SetEvent( theAsioStream->completedBuffersPlayedEvent );
2457                     theAsioStream->zeroOutput = true;
2458                 }
2459                 else /* paComplete or other non-zero value indicating complete */
2460                 {
2461                     /* Finish playback once currently queued audio has completed. */
2462                     theAsioStream->stopProcessing = true;
2463 
2464                     if( PaUtil_IsBufferProcessorOutputEmpty( &theAsioStream->bufferProcessor ) )
2465                     {
2466                         theAsioStream->zeroOutput = true;
2467                         theAsioStream->stopPlayoutCount = 0;
2468                     }
2469                 }
2470             }
2471         }
2472 
2473         ++buffersDone;
2474     }while( PaAsio_AtomicDecrement(&theAsioStream->reenterCount) >= 0 );
2475 
2476     return 0L;
2477 }
2478 
2479 
sampleRateChanged(ASIOSampleRate sRate)2480 static void sampleRateChanged(ASIOSampleRate sRate)
2481 {
2482     // TAKEN FROM THE ASIO SDK
2483     // do whatever you need to do if the sample rate changed
2484     // usually this only happens during external sync.
2485     // Audio processing is not stopped by the driver, actual sample rate
2486     // might not have even changed, maybe only the sample rate status of an
2487     // AES/EBU or S/PDIF digital input at the audio device.
2488     // You might have to update time/sample related conversion routines, etc.
2489 
2490     (void) sRate; /* unused parameter */
2491     PA_DEBUG( ("sampleRateChanged : %d \n", sRate));
2492 }
2493 
asioMessages(long selector,long value,void * message,double * opt)2494 static long asioMessages(long selector, long value, void* message, double* opt)
2495 {
2496 // TAKEN FROM THE ASIO SDK
2497     // currently the parameters "value", "message" and "opt" are not used.
2498     long ret = 0;
2499 
2500     (void) message; /* unused parameters */
2501     (void) opt;
2502 
2503     PA_DEBUG( ("asioMessages : %d , %d \n", selector, value));
2504 
2505     switch(selector)
2506     {
2507         case kAsioSelectorSupported:
2508             if(value == kAsioResetRequest
2509             || value == kAsioEngineVersion
2510             || value == kAsioResyncRequest
2511             || value == kAsioLatenciesChanged
2512             // the following three were added for ASIO 2.0, you don't necessarily have to support them
2513             || value == kAsioSupportsTimeInfo
2514             || value == kAsioSupportsTimeCode
2515             || value == kAsioSupportsInputMonitor)
2516                     ret = 1L;
2517             break;
2518 
2519         case kAsioBufferSizeChange:
2520             //printf("kAsioBufferSizeChange \n");
2521             break;
2522 
2523         case kAsioResetRequest:
2524             // defer the task and perform the reset of the driver during the next "safe" situation
2525             // You cannot reset the driver right now, as this code is called from the driver.
2526             // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
2527             // Afterwards you initialize the driver again.
2528 
2529             /*FIXME: commented the next line out */
2530             //asioDriverInfo.stopped;  // In this sample the processing will just stop
2531             ret = 1L;
2532             break;
2533 
2534         case kAsioResyncRequest:
2535             // This informs the application, that the driver encountered some non fatal data loss.
2536             // It is used for synchronization purposes of different media.
2537             // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
2538             // Windows Multimedia system, which could loose data because the Mutex was hold too long
2539             // by another thread.
2540             // However a driver can issue it in other situations, too.
2541             ret = 1L;
2542             break;
2543 
2544         case kAsioLatenciesChanged:
2545             // This will inform the host application that the drivers were latencies changed.
2546             // Beware, it this does not mean that the buffer sizes have changed!
2547             // You might need to update internal delay data.
2548             ret = 1L;
2549             //printf("kAsioLatenciesChanged \n");
2550             break;
2551 
2552         case kAsioEngineVersion:
2553             // return the supported ASIO version of the host application
2554             // If a host applications does not implement this selector, ASIO 1.0 is assumed
2555             // by the driver
2556             ret = 2L;
2557             break;
2558 
2559         case kAsioSupportsTimeInfo:
2560             // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
2561             // is supported.
2562             // For compatibility with ASIO 1.0 drivers the host application should always support
2563             // the "old" bufferSwitch method, too.
2564             ret = 1;
2565             break;
2566 
2567         case kAsioSupportsTimeCode:
2568             // informs the driver wether application is interested in time code info.
2569             // If an application does not need to know about time code, the driver has less work
2570             // to do.
2571             ret = 0;
2572             break;
2573     }
2574     return ret;
2575 }
2576 
2577 
StartStream(PaStream * s)2578 static PaError StartStream( PaStream *s )
2579 {
2580     PaError result = paNoError;
2581     PaAsioStream *stream = (PaAsioStream*)s;
2582     ASIOError asioError;
2583 
2584     if( stream->outputChannelCount > 0 )
2585     {
2586         ZeroOutputBuffers( stream, 0 );
2587         ZeroOutputBuffers( stream, 1 );
2588     }
2589 
2590     PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
2591     stream->stopProcessing = false;
2592     stream->zeroOutput = false;
2593 
2594     /* Reentrancy counter initialisation */
2595     stream->reenterCount = -1;
2596     stream->reenterError = 0;
2597 
2598     stream->callbackFlags = 0;
2599 
2600     if( ResetEvent( stream->completedBuffersPlayedEvent ) == 0 )
2601     {
2602         result = paUnanticipatedHostError;
2603         PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
2604     }
2605 
2606     if( result == paNoError )
2607     {
2608         theAsioStream = stream;
2609         asioError = ASIOStart();
2610         if( asioError == ASE_OK )
2611         {
2612             stream->isActive = 1;
2613             stream->streamFinishedCallbackCalled = false;
2614         }
2615         else
2616         {
2617             theAsioStream = 0;
2618             result = paUnanticipatedHostError;
2619             PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
2620         }
2621     }
2622 
2623     return result;
2624 }
2625 
2626 
StopStream(PaStream * s)2627 static PaError StopStream( PaStream *s )
2628 {
2629     PaError result = paNoError;
2630     PaAsioStream *stream = (PaAsioStream*)s;
2631     ASIOError asioError;
2632 
2633     if( stream->isActive )
2634     {
2635         stream->stopProcessing = true;
2636 
2637         /* wait for the stream to finish playing out enqueued buffers.
2638             timeout after four times the stream latency.
2639 
2640             @todo should use a better time out value - if the user buffer
2641             length is longer than the asio buffer size then that should
2642             be taken into account.
2643         */
2644         if( WaitForSingleObject( theAsioStream->completedBuffersPlayedEvent,
2645                 (DWORD)(stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.) )
2646                     == WAIT_TIMEOUT	 )
2647         {
2648             PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n" ));
2649         }
2650     }
2651 
2652     asioError = ASIOStop();
2653     if( asioError != ASE_OK )
2654     {
2655         result = paUnanticipatedHostError;
2656         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
2657     }
2658 
2659     theAsioStream = 0;
2660     stream->isActive = 0;
2661 
2662     if( !stream->streamFinishedCallbackCalled )
2663     {
2664         if( stream->streamRepresentation.streamFinishedCallback != 0 )
2665             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
2666     }
2667 
2668     return result;
2669 }
2670 
2671 
AbortStream(PaStream * s)2672 static PaError AbortStream( PaStream *s )
2673 {
2674     PaError result = paNoError;
2675     PaAsioStream *stream = (PaAsioStream*)s;
2676     ASIOError asioError;
2677 
2678     stream->zeroOutput = true;
2679 
2680     asioError = ASIOStop();
2681     if( asioError != ASE_OK )
2682     {
2683         result = paUnanticipatedHostError;
2684         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
2685     }
2686     else
2687     {
2688         // make sure that the callback is not still in-flight when ASIOStop()
2689         // returns. This has been observed to happen on the Hoontech DSP24 for
2690         // example.
2691         int count = 2000;  // only wait for 2 seconds, rather than hanging.
2692         while( theAsioStream->reenterCount != -1 && count > 0 )
2693         {
2694             Sleep(1);
2695             --count;
2696         }
2697     }
2698 
2699     /* it is questionable whether we should zero theAsioStream if ASIOStop()
2700         returns an error, because the callback could still be active. We assume
2701         not - this is based on the fact that ASIOStop is unlikely to fail
2702         if the callback is running - it's more likely to fail because the
2703         callback is not running. */
2704 
2705     theAsioStream = 0;
2706     stream->isActive = 0;
2707 
2708     if( !stream->streamFinishedCallbackCalled )
2709     {
2710         if( stream->streamRepresentation.streamFinishedCallback != 0 )
2711             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
2712     }
2713 
2714     return result;
2715 }
2716 
2717 
IsStreamStopped(PaStream * s)2718 static PaError IsStreamStopped( PaStream *s )
2719 {
2720     //PaAsioStream *stream = (PaAsioStream*)s;
2721     (void) s; /* unused parameter */
2722     return theAsioStream == 0;
2723 }
2724 
2725 
IsStreamActive(PaStream * s)2726 static PaError IsStreamActive( PaStream *s )
2727 {
2728     PaAsioStream *stream = (PaAsioStream*)s;
2729 
2730     return stream->isActive;
2731 }
2732 
2733 
GetStreamTime(PaStream * s)2734 static PaTime GetStreamTime( PaStream *s )
2735 {
2736     (void) s; /* unused parameter */
2737     return (double)timeGetTime() * .001;
2738 }
2739 
2740 
GetStreamCpuLoad(PaStream * s)2741 static double GetStreamCpuLoad( PaStream* s )
2742 {
2743     PaAsioStream *stream = (PaAsioStream*)s;
2744 
2745     return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
2746 }
2747 
2748 
2749 /*
2750     As separate stream interfaces are used for blocking and callback
2751     streams, the following functions can be guaranteed to only be called
2752     for blocking streams.
2753 */
2754 
ReadStream(PaStream * s,void * buffer,unsigned long frames)2755 static PaError ReadStream( PaStream* s,
2756                            void *buffer,
2757                            unsigned long frames )
2758 {
2759     PaAsioStream *stream = (PaAsioStream*)s;
2760 
2761     /* IMPLEMENT ME, see portaudio.h for required behavior*/
2762     (void) stream; /* unused parameters */
2763     (void) buffer;
2764     (void) frames;
2765 
2766     return paNoError;
2767 }
2768 
2769 
WriteStream(PaStream * s,const void * buffer,unsigned long frames)2770 static PaError WriteStream( PaStream* s,
2771                             const void *buffer,
2772                             unsigned long frames )
2773 {
2774     PaAsioStream *stream = (PaAsioStream*)s;
2775 
2776     /* IMPLEMENT ME, see portaudio.h for required behavior*/
2777     (void) stream; /* unused parameters */
2778     (void) buffer;
2779     (void) frames;
2780 
2781     return paNoError;
2782 }
2783 
2784 
GetStreamReadAvailable(PaStream * s)2785 static signed long GetStreamReadAvailable( PaStream* s )
2786 {
2787     PaAsioStream *stream = (PaAsioStream*)s;
2788 
2789     /* IMPLEMENT ME, see portaudio.h for required behavior*/
2790     (void) stream; /* unused parameter */
2791 
2792     return 0;
2793 }
2794 
2795 
GetStreamWriteAvailable(PaStream * s)2796 static signed long GetStreamWriteAvailable( PaStream* s )
2797 {
2798     PaAsioStream *stream = (PaAsioStream*)s;
2799 
2800     /* IMPLEMENT ME, see portaudio.h for required behavior*/
2801     (void) stream; /* unused parameter */
2802 
2803     return 0;
2804 }
2805 
2806 
PaAsio_ShowControlPanel(PaDeviceIndex device,void * systemSpecific)2807 PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific )
2808 {
2809 	PaError result = paNoError;
2810     PaUtilHostApiRepresentation *hostApi;
2811     PaDeviceIndex hostApiDevice;
2812     ASIODriverInfo asioDriverInfo;
2813 	ASIOError asioError;
2814     int asioIsInitialized = 0;
2815     PaAsioHostApiRepresentation *asioHostApi;
2816     PaAsioDeviceInfo *asioDeviceInfo;
2817 
2818 
2819     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
2820     if( result != paNoError )
2821         goto error;
2822 
2823     result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
2824     if( result != paNoError )
2825         goto error;
2826 
2827     /*
2828         In theory we could proceed if the currently open device was the same
2829         one for which the control panel was requested, however  because the
2830         window pointer is not available until this function is called we
2831         currently need to call ASIOInit() again here, which of course can't be
2832         done safely while a stream is open.
2833     */
2834 
2835     asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
2836     if( asioHostApi->openAsioDeviceIndex != paNoDevice )
2837     {
2838         result = paDeviceUnavailable;
2839         goto error;
2840     }
2841 
2842     asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
2843 
2844     if( !loadAsioDriver( const_cast<char*>(asioDeviceInfo->commonDeviceInfo.name) ) )
2845     {
2846         result = paUnanticipatedHostError;
2847         goto error;
2848     }
2849 
2850     /* CRUCIAL!!! */
2851     memset( &asioDriverInfo, 0, sizeof(ASIODriverInfo) );
2852     asioDriverInfo.asioVersion = 2;
2853     asioDriverInfo.sysRef = systemSpecific;
2854     asioError = ASIOInit( &asioDriverInfo );
2855     if( asioError != ASE_OK )
2856     {
2857         result = paUnanticipatedHostError;
2858         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
2859         goto error;
2860     }
2861     else
2862     {
2863         asioIsInitialized = 1;
2864     }
2865 
2866 PA_DEBUG(("PaAsio_ShowControlPanel: ASIOInit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
2867 PA_DEBUG(("asioVersion: ASIOInit(): %ld\n",   asioDriverInfo.asioVersion ));
2868 PA_DEBUG(("driverVersion: ASIOInit(): %ld\n", asioDriverInfo.driverVersion ));
2869 PA_DEBUG(("Name: ASIOInit(): %s\n",           asioDriverInfo.name ));
2870 PA_DEBUG(("ErrorMessage: ASIOInit(): %s\n",   asioDriverInfo.errorMessage ));
2871 
2872     asioError = ASIOControlPanel();
2873     if( asioError != ASE_OK )
2874     {
2875         PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
2876         result = paUnanticipatedHostError;
2877         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
2878         goto error;
2879     }
2880 
2881 PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
2882 
2883     asioError = ASIOExit();
2884     if( asioError != ASE_OK )
2885     {
2886         result = paUnanticipatedHostError;
2887         PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
2888         asioIsInitialized = 0;
2889         goto error;
2890     }
2891 
2892 PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
2893 
2894 	return result;
2895 
2896 error:
2897     if( asioIsInitialized )
2898         ASIOExit();
2899 
2900 	return result;
2901 }
2902 
2903 
PaAsio_GetInputChannelName(PaDeviceIndex device,int channelIndex,const char ** channelName)2904 PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex,
2905         const char** channelName )
2906 {
2907     PaError result = paNoError;
2908     PaUtilHostApiRepresentation *hostApi;
2909     PaDeviceIndex hostApiDevice;
2910     PaAsioDeviceInfo *asioDeviceInfo;
2911 
2912 
2913     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
2914     if( result != paNoError )
2915         goto error;
2916 
2917     result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
2918     if( result != paNoError )
2919         goto error;
2920 
2921     asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
2922 
2923     if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxInputChannels ){
2924         result = paInvalidChannelCount;
2925         goto error;
2926     }
2927 
2928     *channelName = asioDeviceInfo->asioChannelInfos[channelIndex].name;
2929 
2930     return paNoError;
2931 
2932 error:
2933     return result;
2934 }
2935 
2936 
PaAsio_GetOutputChannelName(PaDeviceIndex device,int channelIndex,const char ** channelName)2937 PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex,
2938         const char** channelName )
2939 {
2940     PaError result = paNoError;
2941     PaUtilHostApiRepresentation *hostApi;
2942     PaDeviceIndex hostApiDevice;
2943     PaAsioDeviceInfo *asioDeviceInfo;
2944 
2945 
2946     result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
2947     if( result != paNoError )
2948         goto error;
2949 
2950     result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
2951     if( result != paNoError )
2952         goto error;
2953 
2954     asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
2955 
2956     if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxOutputChannels ){
2957         result = paInvalidChannelCount;
2958         goto error;
2959     }
2960 
2961     *channelName = asioDeviceInfo->asioChannelInfos[
2962             asioDeviceInfo->commonDeviceInfo.maxInputChannels + channelIndex].name;
2963 
2964     return paNoError;
2965 
2966 error:
2967     return result;
2968 }
2969