2
* $Id: pa_asio.cpp 1416 2009-06-16 16:12:41Z rossb $
3
* Portable Audio I/O Library for ASIO Drivers
5
* Author: Stephane Letz
6
* Based on the Open Source API proposed by Ross Bencina
7
* Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina
8
* Blocking i/o implementation by Sven Fischer, Institute of Hearing
9
* Technology and Audiology (www.hoertechnik-audiologie.de)
11
* Permission is hereby granted, free of charge, to any person obtaining
12
* a copy of this software and associated documentation files
13
* (the "Software"), to deal in the Software without restriction,
14
* including without limitation the rights to use, copy, modify, merge,
15
* publish, distribute, sublicense, and/or sell copies of the Software,
16
* and to permit persons to whom the Software is furnished to do so,
17
* subject to the following conditions:
19
* The above copyright notice and this permission notice shall be
20
* included in all copies or substantial portions of the Software.
22
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
26
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
* The text above constitutes the entire PortAudio license; however,
33
* the PortAudio community also makes the following non-binding requests:
35
* Any person wishing to distribute modifications to the Software is
36
* requested to send the modifications to the original developer so that
37
* they can be incorporated into the canonical version. It is also
38
* requested that these non-binding requests be included along with the
42
/* Modification History
44
08-03-01 First version : Stephane Letz
45
08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk
46
08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz
47
08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz
48
08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil
49
08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when
50
the stream is stopped : Stephane Letz
51
08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when
52
the stream is stopped : Stephane Letz
53
10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that
54
respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz
55
10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz
56
10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil
57
10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk
58
10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz
59
11-06-01 Rename functions : Stephane Letz
60
11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz
61
11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk
62
01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz
63
02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz
64
19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz
65
09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz
66
12-04-02 Add Mac includes for <Devices.h> and <Timer.h> : Phil Burk
67
13-04-02 Removes another compiler warning : Stephane Letz
68
30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz
69
12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina
70
18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B.
71
21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina
72
** NOTE maintanance history is now stored in CVS **
78
Note that specific support for paInputUnderflow, paOutputOverflow and
79
paNeverDropInput is not necessary or possible with this driver due to the
80
synchronous full duplex double-buffered architecture of ASIO.
82
@todo implement host api specific extension to set i/o buffer sizes in frames
84
@todo review ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
86
@todo review Blocking i/o latency computations in OpenStream(), changing ring
87
buffer to a non-power-of-two structure could reduce blocking i/o latency.
89
@todo implement IsFormatSupported
91
@todo work out how to implement stream stoppage from callback and
92
implement IsStreamActive properly. Stream stoppage could be implemented
93
using a high-priority thread blocked on an Event which is signalled
94
by the callback. Or, we could just call ASIO stop from the callback
97
@todo rigorously check asio return codes and convert to pa error codes
99
@todo Different channels of a multichannel stream can have different sample
100
formats, but we assume that all are the same as the first channel for now.
101
Fixing this will require the block processor to maintain per-channel
102
conversion functions - could get nasty.
104
@todo investigate whether the asio processNow flag needs to be honoured
106
@todo handle asioMessages() callbacks in a useful way, or at least document
107
what cases we don't handle.
109
@todo miscellaneous other FIXMEs
111
@todo provide an asio-specific method for setting the systems specific
112
value (aka main window handle) - check that this matches the value
113
passed to PaAsio_ShowControlPanel, or remove it entirely from
114
PaAsio_ShowControlPanel. - this would allow PaAsio_ShowControlPanel
115
to be called for the currently open stream (at present all streams
124
//#include <values.h>
128
#include <mmsystem.h>
130
#include "portaudio.h"
133
#include "pa_allocation.h"
134
#include "pa_hostapi.h"
135
#include "pa_stream.h"
136
#include "pa_cpuload.h"
137
#include "pa_process.h"
138
#include "pa_debugprint.h"
139
#include "pa_ringbuffer.h"
141
/* This version of pa_asio.cpp is currently only targetted at Win32,
142
It would require a few tweaks to work with pre-OS X Macintosh.
143
To make configuration easier, we define WIN32 here to make sure
144
that the ASIO SDK knows this is Win32.
152
#include "asiodrivers.h"
153
#include "iasiothiscallresolver.h"
165
#include <mmsystem.h>
172
/* external reference to ASIO SDK's asioDrivers.
174
This is a bit messy because we want to explicitly manage
175
allocation/deallocation of this structure, but some layers of the SDK
176
which we currently use (eg the implementation in asio.cpp) still
177
use this global version.
179
For now we keep it in sync with our local instance in the host
180
API representation structure, but later we should be able to remove
181
all dependence on it.
183
extern AsioDrivers* asioDrivers;
186
/* We are trying to be compatible with CARBON but this has not been thoroughly tested. */
187
/* not tested at all since new V19 code was introduced. */
188
#define CARBON_COMPATIBLE (0)
191
/* prototypes for functions declared in this file */
193
extern "C" PaError PaAsio_Initialize (PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex);
194
static void Terminate (struct PaUtilHostApiRepresentation *hostApi);
195
static PaError OpenStream (struct PaUtilHostApiRepresentation *hostApi,
197
const PaStreamParameters *inputParameters,
198
const PaStreamParameters *outputParameters,
200
unsigned long framesPerBuffer,
201
PaStreamFlags streamFlags,
202
PaStreamCallback *streamCallback,
204
static PaError IsFormatSupported (struct PaUtilHostApiRepresentation *hostApi,
205
const PaStreamParameters *inputParameters,
206
const PaStreamParameters *outputParameters,
208
static PaError CloseStream (PaStream* stream);
209
static PaError StartStream (PaStream *stream);
210
static PaError StopStream (PaStream *stream);
211
static PaError AbortStream (PaStream *stream);
212
static PaError IsStreamStopped (PaStream *s);
213
static PaError IsStreamActive (PaStream *stream);
214
static PaTime GetStreamTime (PaStream *stream);
215
static double GetStreamCpuLoad (PaStream* stream);
216
static PaError ReadStream (PaStream* stream, void *buffer, unsigned long frames);
217
static PaError WriteStream (PaStream* stream, const void *buffer, unsigned long frames);
218
static signed long GetStreamReadAvailable (PaStream* stream);
219
static signed long GetStreamWriteAvailable (PaStream* stream);
221
/* Blocking i/o callback function. */
222
static int BlockingIoPaCallback (const void *inputBuffer ,
224
unsigned long framesPerBuffer,
225
const PaStreamCallbackTimeInfo *timeInfo ,
226
PaStreamCallbackFlags statusFlags ,
229
/* our ASIO callback functions */
231
static void bufferSwitch (long index, ASIOBool processNow);
232
static ASIOTime *bufferSwitchTimeInfo (ASIOTime *timeInfo, long index, ASIOBool processNow);
233
static void sampleRateChanged (ASIOSampleRate sRate);
234
static long asioMessages (long selector, long value, void* message, double* opt);
236
static ASIOCallbacks asioCallbacks_ = { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo };
239
#define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \
240
PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText )
243
static void PaAsio_SetLastSystemError (DWORD errorCode)
247
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
250
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
255
PaUtil_SetLastHostErrorInfo (paASIO, errorCode, (const char*) lpMsgBuf);
256
LocalFree (lpMsgBuf);
259
#define PA_ASIO_SET_LAST_SYSTEM_ERROR( errorCode ) \
260
PaAsio_SetLastSystemError( errorCode )
263
static const char* PaAsio_GetAsioErrorText (ASIOError asioError)
273
result = "Hardware input or output is not present or available";
275
case ASE_HWMalfunction:
276
result = "Hardware is malfunctioning";
278
case ASE_InvalidParameter:
279
result = "Input parameter invalid";
281
case ASE_InvalidMode:
282
result = "Hardware is in a bad mode or used in a bad mode";
284
case ASE_SPNotAdvancing:
285
result = "Hardware is not running when sample position is inquired";
288
result = "Sample clock or rate cannot be determined or is not present";
291
result = "Not enough memory for completing the request";
294
result = "Unknown ASIO error";
302
#define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \
303
PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) )
308
// Atomic increment and decrement operations
310
/* need to be implemented on Mac */
311
inline long PaAsio_AtomicIncrement (volatile long* v)
313
return ++ (*const_cast<long*> (v));
315
inline long PaAsio_AtomicDecrement (volatile long* v)
317
return -- (*const_cast<long*> (v));
320
inline long PaAsio_AtomicIncrement (volatile long* v)
322
return InterlockedIncrement (const_cast<long*> (v));
324
inline long PaAsio_AtomicDecrement (volatile long* v)
326
return InterlockedDecrement (const_cast<long*> (v));
332
typedef struct PaAsioDriverInfo {
333
ASIODriverInfo asioDriverInfo;
334
long inputChannelCount, outputChannelCount;
335
long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity;
341
/* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */
344
PaUtilHostApiRepresentation inheritedHostApiRep;
345
PaUtilStreamInterface callbackStreamInterface;
346
PaUtilStreamInterface blockingStreamInterface;
348
PaUtilAllocationGroup *allocations;
350
AsioDrivers *asioDrivers;
351
void *systemSpecific;
353
/* the ASIO C API only allows one ASIO driver to be open at a time,
354
so we keep track of whether we have the driver open here, and
355
use this information to return errors from OpenStream if the
356
driver is already open.
358
openAsioDeviceIndex will be PaNoDevice if there is no device open
359
and a valid pa_asio (not global) device index otherwise.
361
openAsioDriverInfo is populated with the driver info for the
362
currently open device (if any)
364
PaDeviceIndex openAsioDeviceIndex;
365
PaAsioDriverInfo openAsioDriverInfo;
367
PaAsioHostApiRepresentation;
371
Retrieve <driverCount> driver names from ASIO, returned in a char**
372
allocated in <group>.
374
static char **GetAsioDriverNames (PaAsioHostApiRepresentation *asioHostApi, PaUtilAllocationGroup *group, long driverCount)
379
result = (char**) PaUtil_GroupAllocateMemory (
380
group, sizeof (char*) * driverCount);
385
result[0] = (char*) PaUtil_GroupAllocateMemory (
386
group, 32 * driverCount);
391
for (i=0; i<driverCount; ++i)
392
result[i] = result[0] + (32 * i);
394
asioHostApi->asioDrivers->getDriverNames (result, driverCount);
401
static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat (ASIOSampleType type)
408
case ASIOSTFloat32MSB:
409
case ASIOSTFloat32LSB:
410
case ASIOSTFloat64MSB:
411
case ASIOSTFloat64LSB:
416
case ASIOSTInt32MSB16:
417
case ASIOSTInt32LSB16:
418
case ASIOSTInt32MSB18:
419
case ASIOSTInt32MSB20:
420
case ASIOSTInt32MSB24:
421
case ASIOSTInt32LSB18:
422
case ASIOSTInt32LSB20:
423
case ASIOSTInt32LSB24:
431
return paCustomFormat;
435
void AsioSampleTypeLOG (ASIOSampleType type)
439
PA_DEBUG ( ("ASIOSTInt16MSB\n"));
442
PA_DEBUG ( ("ASIOSTInt16LSB\n"));
444
case ASIOSTFloat32MSB:
445
PA_DEBUG ( ("ASIOSTFloat32MSB\n"));
447
case ASIOSTFloat32LSB:
448
PA_DEBUG ( ("ASIOSTFloat32LSB\n"));
450
case ASIOSTFloat64MSB:
451
PA_DEBUG ( ("ASIOSTFloat64MSB\n"));
453
case ASIOSTFloat64LSB:
454
PA_DEBUG ( ("ASIOSTFloat64LSB\n"));
457
PA_DEBUG ( ("ASIOSTInt32MSB\n"));
460
PA_DEBUG ( ("ASIOSTInt32LSB\n"));
462
case ASIOSTInt32MSB16:
463
PA_DEBUG ( ("ASIOSTInt32MSB16\n"));
465
case ASIOSTInt32LSB16:
466
PA_DEBUG ( ("ASIOSTInt32LSB16\n"));
468
case ASIOSTInt32MSB18:
469
PA_DEBUG ( ("ASIOSTInt32MSB18\n"));
471
case ASIOSTInt32MSB20:
472
PA_DEBUG ( ("ASIOSTInt32MSB20\n"));
474
case ASIOSTInt32MSB24:
475
PA_DEBUG ( ("ASIOSTInt32MSB24\n"));
477
case ASIOSTInt32LSB18:
478
PA_DEBUG ( ("ASIOSTInt32LSB18\n"));
480
case ASIOSTInt32LSB20:
481
PA_DEBUG ( ("ASIOSTInt32LSB20\n"));
483
case ASIOSTInt32LSB24:
484
PA_DEBUG ( ("ASIOSTInt32LSB24\n"));
487
PA_DEBUG ( ("ASIOSTInt24MSB\n"));
490
PA_DEBUG ( ("ASIOSTInt24LSB\n"));
493
PA_DEBUG ( ("Custom Format%d\n",type));
499
static int BytesPerAsioSample (ASIOSampleType sampleType)
501
switch (sampleType) {
506
case ASIOSTFloat64MSB:
507
case ASIOSTFloat64LSB:
510
case ASIOSTFloat32MSB:
511
case ASIOSTFloat32LSB:
514
case ASIOSTInt32MSB16:
515
case ASIOSTInt32LSB16:
516
case ASIOSTInt32MSB18:
517
case ASIOSTInt32MSB20:
518
case ASIOSTInt32MSB24:
519
case ASIOSTInt32LSB18:
520
case ASIOSTInt32LSB20:
521
case ASIOSTInt32LSB24:
534
static void Swap16 (void *buffer, long shift, long count)
536
unsigned short *p = (unsigned short*) buffer;
538
(void) shift; /* unused parameter */
542
*p++ = (unsigned short) ( (temp<<8) | (temp>>8));
546
static void Swap24 (void *buffer, long shift, long count)
548
unsigned char *p = (unsigned char*) buffer;
550
(void) shift; /* unused parameter */
560
#define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24));
562
static void Swap32 (void *buffer, long shift, long count)
564
unsigned long *p = (unsigned long*) buffer;
566
(void) shift; /* unused parameter */
570
*p++ = PA_SWAP32_ (temp);
574
static void SwapShiftLeft32 (void *buffer, long shift, long count)
576
unsigned long *p = (unsigned long*) buffer;
581
temp = PA_SWAP32_ (temp);
582
*p++ = temp << shift;
586
static void ShiftRightSwap32 (void *buffer, long shift, long count)
588
unsigned long *p = (unsigned long*) buffer;
593
*p++ = PA_SWAP32_ (temp);
597
static void ShiftLeft32 (void *buffer, long shift, long count)
599
unsigned long *p = (unsigned long*) buffer;
604
*p++ = temp << shift;
608
static void ShiftRight32 (void *buffer, long shift, long count)
610
unsigned long *p = (unsigned long*) buffer;
615
*p++ = temp >> shift;
619
#define PA_SWAP_( x, y ) temp=x; x = y; y = temp;
621
static void Swap64ConvertFloat64ToFloat32 (void *buffer, long shift, long count)
623
double *in = (double*) buffer;
624
float *out = (float*) buffer;
627
(void) shift; /* unused parameter */
630
p = (unsigned char*) in;
631
PA_SWAP_ (p[0], p[7]);
632
PA_SWAP_ (p[1], p[6]);
633
PA_SWAP_ (p[2], p[5]);
634
PA_SWAP_ (p[3], p[4]);
636
*out++ = (float) (*in++);
640
static void ConvertFloat64ToFloat32 (void *buffer, long shift, long count)
642
double *in = (double*) buffer;
643
float *out = (float*) buffer;
644
(void) shift; /* unused parameter */
647
*out++ = (float) (*in++);
650
static void ConvertFloat32ToFloat64Swap64 (void *buffer, long shift, long count)
652
float *in = ( (float*) buffer) + (count-1);
653
double *out = ( (double*) buffer) + (count-1);
656
(void) shift; /* unused parameter */
661
p = (unsigned char*) out;
662
PA_SWAP_ (p[0], p[7]);
663
PA_SWAP_ (p[1], p[6]);
664
PA_SWAP_ (p[2], p[5]);
665
PA_SWAP_ (p[3], p[4]);
671
static void ConvertFloat32ToFloat64 (void *buffer, long shift, long count)
673
float *in = ( (float*) buffer) + (count-1);
674
double *out = ( (double*) buffer) + (count-1);
675
(void) shift; /* unused parameter */
682
#define PA_MSB_IS_NATIVE_
683
#undef PA_LSB_IS_NATIVE_
687
#undef PA_MSB_IS_NATIVE_
688
#define PA_LSB_IS_NATIVE_
691
typedef void PaAsioBufferConverter (void *, long, long);
693
static void SelectAsioToPaConverter (ASIOSampleType type, PaAsioBufferConverter **converter, long *shift)
700
/* dest: paInt16, no conversion necessary, possible byte swap*/
701
#ifdef PA_LSB_IS_NATIVE_
706
/* dest: paInt16, no conversion necessary, possible byte swap*/
707
#ifdef PA_MSB_IS_NATIVE_
711
case ASIOSTFloat32MSB:
712
/* dest: paFloat32, no conversion necessary, possible byte swap*/
713
#ifdef PA_LSB_IS_NATIVE_
717
case ASIOSTFloat32LSB:
718
/* dest: paFloat32, no conversion necessary, possible byte swap*/
719
#ifdef PA_MSB_IS_NATIVE_
723
case ASIOSTFloat64MSB:
724
/* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
725
#ifdef PA_LSB_IS_NATIVE_
726
*converter = Swap64ConvertFloat64ToFloat32;
728
*converter = ConvertFloat64ToFloat32;
731
case ASIOSTFloat64LSB:
732
/* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
733
#ifdef PA_MSB_IS_NATIVE_
734
*converter = Swap64ConvertFloat64ToFloat32;
736
*converter = ConvertFloat64ToFloat32;
740
/* dest: paInt32, no conversion necessary, possible byte swap */
741
#ifdef PA_LSB_IS_NATIVE_
746
/* dest: paInt32, no conversion necessary, possible byte swap */
747
#ifdef PA_MSB_IS_NATIVE_
751
case ASIOSTInt32MSB16:
752
/* dest: paInt32, 16 bit shift, possible byte swap */
753
#ifdef PA_LSB_IS_NATIVE_
754
*converter = SwapShiftLeft32;
756
*converter = ShiftLeft32;
760
case ASIOSTInt32MSB18:
761
/* dest: paInt32, 14 bit shift, possible byte swap */
762
#ifdef PA_LSB_IS_NATIVE_
763
*converter = SwapShiftLeft32;
765
*converter = ShiftLeft32;
769
case ASIOSTInt32MSB20:
770
/* dest: paInt32, 12 bit shift, possible byte swap */
771
#ifdef PA_LSB_IS_NATIVE_
772
*converter = SwapShiftLeft32;
774
*converter = ShiftLeft32;
778
case ASIOSTInt32MSB24:
779
/* dest: paInt32, 8 bit shift, possible byte swap */
780
#ifdef PA_LSB_IS_NATIVE_
781
*converter = SwapShiftLeft32;
783
*converter = ShiftLeft32;
787
case ASIOSTInt32LSB16:
788
/* dest: paInt32, 16 bit shift, possible byte swap */
789
#ifdef PA_MSB_IS_NATIVE_
790
*converter = SwapShiftLeft32;
792
*converter = ShiftLeft32;
796
case ASIOSTInt32LSB18:
797
/* dest: paInt32, 14 bit shift, possible byte swap */
798
#ifdef PA_MSB_IS_NATIVE_
799
*converter = SwapShiftLeft32;
801
*converter = ShiftLeft32;
805
case ASIOSTInt32LSB20:
806
/* dest: paInt32, 12 bit shift, possible byte swap */
807
#ifdef PA_MSB_IS_NATIVE_
808
*converter = SwapShiftLeft32;
810
*converter = ShiftLeft32;
814
case ASIOSTInt32LSB24:
815
/* dest: paInt32, 8 bit shift, possible byte swap */
816
#ifdef PA_MSB_IS_NATIVE_
817
*converter = SwapShiftLeft32;
819
*converter = ShiftLeft32;
824
/* dest: paInt24, no conversion necessary, possible byte swap */
825
#ifdef PA_LSB_IS_NATIVE_
830
/* dest: paInt24, no conversion necessary, possible byte swap */
831
#ifdef PA_MSB_IS_NATIVE_
839
static void SelectPaToAsioConverter (ASIOSampleType type, PaAsioBufferConverter **converter, long *shift)
846
/* src: paInt16, no conversion necessary, possible byte swap*/
847
#ifdef PA_LSB_IS_NATIVE_
852
/* src: paInt16, no conversion necessary, possible byte swap*/
853
#ifdef PA_MSB_IS_NATIVE_
857
case ASIOSTFloat32MSB:
858
/* src: paFloat32, no conversion necessary, possible byte swap*/
859
#ifdef PA_LSB_IS_NATIVE_
863
case ASIOSTFloat32LSB:
864
/* src: paFloat32, no conversion necessary, possible byte swap*/
865
#ifdef PA_MSB_IS_NATIVE_
869
case ASIOSTFloat64MSB:
870
/* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
871
#ifdef PA_LSB_IS_NATIVE_
872
*converter = ConvertFloat32ToFloat64Swap64;
874
*converter = ConvertFloat32ToFloat64;
877
case ASIOSTFloat64LSB:
878
/* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
879
#ifdef PA_MSB_IS_NATIVE_
880
*converter = ConvertFloat32ToFloat64Swap64;
882
*converter = ConvertFloat32ToFloat64;
886
/* src: paInt32, no conversion necessary, possible byte swap */
887
#ifdef PA_LSB_IS_NATIVE_
892
/* src: paInt32, no conversion necessary, possible byte swap */
893
#ifdef PA_MSB_IS_NATIVE_
897
case ASIOSTInt32MSB16:
898
/* src: paInt32, 16 bit shift, possible byte swap */
899
#ifdef PA_LSB_IS_NATIVE_
900
*converter = ShiftRightSwap32;
902
*converter = ShiftRight32;
906
case ASIOSTInt32MSB18:
907
/* src: paInt32, 14 bit shift, possible byte swap */
908
#ifdef PA_LSB_IS_NATIVE_
909
*converter = ShiftRightSwap32;
911
*converter = ShiftRight32;
915
case ASIOSTInt32MSB20:
916
/* src: paInt32, 12 bit shift, possible byte swap */
917
#ifdef PA_LSB_IS_NATIVE_
918
*converter = ShiftRightSwap32;
920
*converter = ShiftRight32;
924
case ASIOSTInt32MSB24:
925
/* src: paInt32, 8 bit shift, possible byte swap */
926
#ifdef PA_LSB_IS_NATIVE_
927
*converter = ShiftRightSwap32;
929
*converter = ShiftRight32;
933
case ASIOSTInt32LSB16:
934
/* src: paInt32, 16 bit shift, possible byte swap */
935
#ifdef PA_MSB_IS_NATIVE_
936
*converter = ShiftRightSwap32;
938
*converter = ShiftRight32;
942
case ASIOSTInt32LSB18:
943
/* src: paInt32, 14 bit shift, possible byte swap */
944
#ifdef PA_MSB_IS_NATIVE_
945
*converter = ShiftRightSwap32;
947
*converter = ShiftRight32;
951
case ASIOSTInt32LSB20:
952
/* src: paInt32, 12 bit shift, possible byte swap */
953
#ifdef PA_MSB_IS_NATIVE_
954
*converter = ShiftRightSwap32;
956
*converter = ShiftRight32;
960
case ASIOSTInt32LSB24:
961
/* src: paInt32, 8 bit shift, possible byte swap */
962
#ifdef PA_MSB_IS_NATIVE_
963
*converter = ShiftRightSwap32;
965
*converter = ShiftRight32;
970
/* src: paInt24, no conversion necessary, possible byte swap */
971
#ifdef PA_LSB_IS_NATIVE_
976
/* src: paInt24, no conversion necessary, possible byte swap */
977
#ifdef PA_MSB_IS_NATIVE_
985
typedef struct PaAsioDeviceInfo {
986
PaDeviceInfo commonDeviceInfo;
989
long preferredBufferSize;
990
long bufferGranularity;
992
ASIOChannelInfo *asioChannelInfos;
997
PaError PaAsio_GetAvailableLatencyValues (PaDeviceIndex device,
998
long *minLatency, long *maxLatency, long *preferredLatency, long *granularity)
1001
PaUtilHostApiRepresentation *hostApi;
1002
PaDeviceIndex hostApiDevice;
1004
result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
1006
if (result == paNoError) {
1007
result = PaUtil_DeviceIndexToHostApiDeviceIndex (&hostApiDevice, device, hostApi);
1009
if (result == paNoError) {
1010
PaAsioDeviceInfo *asioDeviceInfo =
1011
(PaAsioDeviceInfo*) hostApi->deviceInfos[hostApiDevice];
1013
*minLatency = asioDeviceInfo->minBufferSize;
1014
*maxLatency = asioDeviceInfo->maxBufferSize;
1015
*preferredLatency = asioDeviceInfo->preferredBufferSize;
1016
*granularity = asioDeviceInfo->bufferGranularity;
1023
/* Unload whatever we loaded in LoadAsioDriver().
1024
Also balance the call to CoInitialize(0).
1026
static void UnloadAsioDriver (void)
1033
load the asio driver named by <driverName> and return statistics about
1034
the driver in info. If no error occurred, the driver will remain open
1035
and must be closed by the called by calling UnloadAsioDriver() - if an error
1036
is returned the driver will already be unloaded.
1038
static PaError LoadAsioDriver (PaAsioHostApiRepresentation *asioHostApi, const char *driverName,
1039
PaAsioDriverInfo *driverInfo, void *systemSpecific)
1041
PaError result = paNoError;
1042
ASIOError asioError;
1043
int asioIsInitialized = 0;
1046
ASIO uses CoCreateInstance() to load a driver. That requires that
1047
CoInitialize(0) be called for every thread that loads a driver.
1048
It is OK to call CoInitialize(0) multiple times form one thread as long
1049
as it is balanced by a call to CoUninitialize(). See UnloadAsioDriver().
1051
The V18 version called CoInitialize() starting on 2/19/02.
1052
That was removed from PA V19 for unknown reasons.
1053
Phil Burk added it back on 6/27/08 so that JSyn would work.
1057
if (!asioHostApi->asioDrivers->loadDriver (const_cast<char*> (driverName))) {
1058
/* If this returns an error then it might be because CoInitialize(0) was removed.
1059
It should be called right before this.
1061
result = paUnanticipatedHostError;
1062
PA_ASIO_SET_LAST_HOST_ERROR (0, "Failed to load ASIO driver");
1066
memset (&driverInfo->asioDriverInfo, 0, sizeof (ASIODriverInfo));
1067
driverInfo->asioDriverInfo.asioVersion = 2;
1068
driverInfo->asioDriverInfo.sysRef = systemSpecific;
1070
if ( (asioError = ASIOInit (&driverInfo->asioDriverInfo)) != ASE_OK) {
1071
result = paUnanticipatedHostError;
1072
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
1075
asioIsInitialized = 1;
1078
if ( (asioError = ASIOGetChannels (&driverInfo->inputChannelCount,
1079
&driverInfo->outputChannelCount)) != ASE_OK) {
1080
result = paUnanticipatedHostError;
1081
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
1085
if ( (asioError = ASIOGetBufferSize (&driverInfo->bufferMinSize,
1086
&driverInfo->bufferMaxSize, &driverInfo->bufferPreferredSize,
1087
&driverInfo->bufferGranularity)) != ASE_OK) {
1088
result = paUnanticipatedHostError;
1089
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
1093
if (ASIOOutputReady() == ASE_OK)
1094
driverInfo->postOutput = true;
1096
driverInfo->postOutput = false;
1102
if (asioIsInitialized) {
1111
#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ 13 /* must be the same number of elements as in the array below */
1112
static ASIOSampleRate defaultSampleRateSearchOrder_[]
1113
= {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0,
1114
192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0
1118
/* we look up IsDebuggerPresent at runtime incase it isn't present (on Win95 for example) */
1119
typedef BOOL (WINAPI *IsDebuggerPresentPtr) (VOID);
1120
IsDebuggerPresentPtr IsDebuggerPresent_ = 0;
1121
//FARPROC IsDebuggerPresent_ = 0; // this is the current way to do it apparently according to davidv
1123
PaError PaAsio_Initialize (PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex)
1125
PaError result = paNoError;
1127
PaAsioHostApiRepresentation *asioHostApi;
1128
PaAsioDeviceInfo *deviceInfoArray;
1130
PaAsioDriverInfo paAsioDriverInfo;
1132
asioHostApi = (PaAsioHostApiRepresentation*) PaUtil_AllocateMemory (sizeof (PaAsioHostApiRepresentation));
1135
result = paInsufficientMemory;
1139
asioHostApi->asioDrivers = 0; /* avoid surprises in our error handler below */
1141
asioHostApi->allocations = PaUtil_CreateAllocationGroup();
1143
if (!asioHostApi->allocations) {
1144
result = paInsufficientMemory;
1148
/* Allocate the AsioDrivers() driver list (class from ASIO SDK) */
1150
asioHostApi->asioDrivers = new AsioDrivers(); /* calls CoInitialize(0) */
1151
} catch (std::bad_alloc) {
1152
asioHostApi->asioDrivers = 0;
1155
/* some implementations of new (ie MSVC, see http://support.microsoft.com/?kbid=167733)
1156
don't throw std::bad_alloc, so we also explicitly test for a null return. */
1157
if (asioHostApi->asioDrivers == 0) {
1158
result = paInsufficientMemory;
1162
asioDrivers = asioHostApi->asioDrivers; /* keep SDK global in sync until we stop depending on it */
1164
asioHostApi->systemSpecific = 0;
1165
asioHostApi->openAsioDeviceIndex = paNoDevice;
1167
*hostApi = &asioHostApi->inheritedHostApiRep;
1168
(*hostApi)->info.structVersion = 1;
1170
(*hostApi)->info.type = paASIO;
1171
(*hostApi)->info.name = "ASIO";
1172
(*hostApi)->info.deviceCount = 0;
1175
/* use desktop window as system specific ptr */
1176
asioHostApi->systemSpecific = GetDesktopWindow();
1179
/* driverCount is the number of installed drivers - not necessarily
1180
the number of installed physical devices. */
1182
driverCount = asioHostApi->asioDrivers->getNumFragments();
1184
driverCount = asioHostApi->asioDrivers->asioGetNumDev();
1187
if (driverCount > 0) {
1188
names = GetAsioDriverNames (asioHostApi, asioHostApi->allocations, driverCount);
1191
result = paInsufficientMemory;
1196
/* allocate enough space for all drivers, even if some aren't installed */
1198
(*hostApi)->deviceInfos = (PaDeviceInfo**) PaUtil_GroupAllocateMemory (
1199
asioHostApi->allocations, sizeof (PaDeviceInfo*) * driverCount);
1201
if (! (*hostApi)->deviceInfos) {
1202
result = paInsufficientMemory;
1206
/* allocate all device info structs in a contiguous block */
1207
deviceInfoArray = (PaAsioDeviceInfo*) PaUtil_GroupAllocateMemory (
1208
asioHostApi->allocations, sizeof (PaAsioDeviceInfo) * driverCount);
1210
if (!deviceInfoArray) {
1211
result = paInsufficientMemory;
1215
IsDebuggerPresent_ = GetProcAddress (LoadLibrary ("Kernel32.dll"), "IsDebuggerPresent");
1217
for (i=0; i < driverCount; ++i) {
1219
PA_DEBUG ( ("ASIO names[%d]:%s\n",i,names[i]));
1221
// Since portaudio opens ALL ASIO drivers, and no one else does that,
1222
// we face fact that some drivers were not meant for it, drivers which act
1223
// like shells on top of REAL drivers, for instance.
1224
// so we get duplicate handles, locks and other problems.
1225
// so lets NOT try to load any such wrappers.
1226
// The ones i [davidv] know of so far are:
1228
if (strcmp (names[i],"ASIO DirectX Full Duplex Driver") == 0
1229
|| strcmp (names[i],"ASIO Multimedia Driver") == 0
1230
|| strncmp (names[i],"Premiere",8) == 0 //"Premiere Elements Windows Sound 1.0"
1231
|| strncmp (names[i],"Adobe",5) == 0 //"Adobe Default Windows Sound 1.5"
1233
PA_DEBUG ( ("BLACKLISTED!!!\n"));
1238
if (IsDebuggerPresent_ && IsDebuggerPresent_()) {
1239
/* ASIO Digidesign Driver uses PACE copy protection which quits out
1240
if a debugger is running. So we don't load it if a debugger is running. */
1241
if (strcmp (names[i], "ASIO Digidesign Driver") == 0) {
1242
PA_DEBUG ( ("BLACKLISTED!!! ASIO Digidesign Driver would quit the debugger\n"));
1248
/* Attempt to load the asio driver... */
1249
if (LoadAsioDriver (asioHostApi, names[i], &paAsioDriverInfo, asioHostApi->systemSpecific) == paNoError) {
1250
PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
1251
PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
1253
deviceInfo->structVersion = 2;
1254
deviceInfo->hostApi = hostApiIndex;
1256
deviceInfo->name = names[i];
1257
PA_DEBUG ( ("PaAsio_Initialize: drv:%d name = %s\n", i,deviceInfo->name));
1258
PA_DEBUG ( ("PaAsio_Initialize: drv:%d inputChannels = %d\n", i, paAsioDriverInfo.inputChannelCount));
1259
PA_DEBUG ( ("PaAsio_Initialize: drv:%d outputChannels = %d\n", i, paAsioDriverInfo.outputChannelCount));
1260
PA_DEBUG ( ("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", i, paAsioDriverInfo.bufferMinSize));
1261
PA_DEBUG ( ("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", i, paAsioDriverInfo.bufferMaxSize));
1262
PA_DEBUG ( ("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriverInfo.bufferPreferredSize));
1263
PA_DEBUG ( ("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", i, paAsioDriverInfo.bufferGranularity));
1265
deviceInfo->maxInputChannels = paAsioDriverInfo.inputChannelCount;
1266
deviceInfo->maxOutputChannels = paAsioDriverInfo.outputChannelCount;
1268
deviceInfo->defaultSampleRate = 0.;
1269
bool foundDefaultSampleRate = false;
1271
for (int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j) {
1272
ASIOError asioError = ASIOCanSampleRate (defaultSampleRateSearchOrder_[j]);
1274
if (asioError != ASE_NoClock && asioError != ASE_NotPresent) {
1275
deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
1276
foundDefaultSampleRate = true;
1281
PA_DEBUG ( ("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate));
1283
if (foundDefaultSampleRate) {
1285
/* calculate default latency values from bufferPreferredSize
1286
for default low latency, and bufferPreferredSize * 3
1287
for default high latency.
1288
use the default sample rate to convert from samples to
1289
seconds. Without knowing what sample rate the user will
1290
use this is the best we can do.
1293
double defaultLowLatency =
1294
paAsioDriverInfo.bufferPreferredSize / deviceInfo->defaultSampleRate;
1296
deviceInfo->defaultLowInputLatency = defaultLowLatency;
1297
deviceInfo->defaultLowOutputLatency = defaultLowLatency;
1299
long defaultHighLatencyBufferSize =
1300
paAsioDriverInfo.bufferPreferredSize * 3;
1302
if (defaultHighLatencyBufferSize > paAsioDriverInfo.bufferMaxSize)
1303
defaultHighLatencyBufferSize = paAsioDriverInfo.bufferMaxSize;
1305
double defaultHighLatency =
1306
defaultHighLatencyBufferSize / deviceInfo->defaultSampleRate;
1308
if (defaultHighLatency < defaultLowLatency)
1309
defaultHighLatency = defaultLowLatency; /* just incase the driver returns something strange */
1311
deviceInfo->defaultHighInputLatency = defaultHighLatency;
1312
deviceInfo->defaultHighOutputLatency = defaultHighLatency;
1316
deviceInfo->defaultLowInputLatency = 0.;
1317
deviceInfo->defaultLowOutputLatency = 0.;
1318
deviceInfo->defaultHighInputLatency = 0.;
1319
deviceInfo->defaultHighOutputLatency = 0.;
1322
PA_DEBUG ( ("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", i, deviceInfo->defaultLowInputLatency));
1323
PA_DEBUG ( ("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", i, deviceInfo->defaultLowOutputLatency));
1324
PA_DEBUG ( ("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i, deviceInfo->defaultHighInputLatency));
1325
PA_DEBUG ( ("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i, deviceInfo->defaultHighOutputLatency));
1327
asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize;
1328
asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize;
1329
asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize;
1330
asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity;
1333
asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*) PaUtil_GroupAllocateMemory (
1334
asioHostApi->allocations,
1335
sizeof (ASIOChannelInfo) * (deviceInfo->maxInputChannels
1336
+ deviceInfo->maxOutputChannels));
1338
if (!asioDeviceInfo->asioChannelInfos) {
1339
result = paInsufficientMemory;
1345
for (a=0; a < deviceInfo->maxInputChannels; ++a) {
1346
asioDeviceInfo->asioChannelInfos[a].channel = a;
1347
asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue;
1348
ASIOError asioError = ASIOGetChannelInfo (&asioDeviceInfo->asioChannelInfos[a]);
1350
if (asioError != ASE_OK) {
1351
result = paUnanticipatedHostError;
1352
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
1357
for (a=0; a < deviceInfo->maxOutputChannels; ++a) {
1358
int b = deviceInfo->maxInputChannels + a;
1359
asioDeviceInfo->asioChannelInfos[b].channel = a;
1360
asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse;
1361
ASIOError asioError = ASIOGetChannelInfo (&asioDeviceInfo->asioChannelInfos[b]);
1363
if (asioError != ASE_OK) {
1364
result = paUnanticipatedHostError;
1365
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
1371
/* unload the driver */
1374
(*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
1375
++ (*hostApi)->info.deviceCount;
1380
if ( (*hostApi)->info.deviceCount > 0) {
1381
(*hostApi)->info.defaultInputDevice = 0;
1382
(*hostApi)->info.defaultOutputDevice = 0;
1384
(*hostApi)->info.defaultInputDevice = paNoDevice;
1385
(*hostApi)->info.defaultOutputDevice = paNoDevice;
1389
(*hostApi)->Terminate = Terminate;
1390
(*hostApi)->OpenStream = OpenStream;
1391
(*hostApi)->IsFormatSupported = IsFormatSupported;
1393
PaUtil_InitializeStreamInterface (&asioHostApi->callbackStreamInterface, CloseStream, StartStream,
1394
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
1395
GetStreamTime, GetStreamCpuLoad,
1396
PaUtil_DummyRead, PaUtil_DummyWrite,
1397
PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable);
1399
PaUtil_InitializeStreamInterface (&asioHostApi->blockingStreamInterface, CloseStream, StartStream,
1400
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
1401
GetStreamTime, PaUtil_DummyGetCpuLoad,
1402
ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable);
1412
if (asioHostApi->allocations) {
1413
PaUtil_FreeAllAllocations (asioHostApi->allocations);
1414
PaUtil_DestroyAllocationGroup (asioHostApi->allocations);
1417
delete asioHostApi->asioDrivers;
1418
asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
1420
PaUtil_FreeMemory (asioHostApi);
1427
static void Terminate (struct PaUtilHostApiRepresentation *hostApi)
1429
PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*) hostApi;
1433
- clean up any resources not handled by the allocation group (need to review if there are any)
1436
if (asioHostApi->allocations) {
1437
PaUtil_FreeAllAllocations (asioHostApi->allocations);
1438
PaUtil_DestroyAllocationGroup (asioHostApi->allocations);
1441
delete asioHostApi->asioDrivers; /* calls CoUninitialize() */
1442
asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
1444
PaUtil_FreeMemory (asioHostApi);
1448
static PaError IsFormatSupported (struct PaUtilHostApiRepresentation *hostApi,
1449
const PaStreamParameters *inputParameters,
1450
const PaStreamParameters *outputParameters,
1453
PaError result = paNoError;
1454
PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*) hostApi;
1455
PaAsioDriverInfo *driverInfo = &asioHostApi->openAsioDriverInfo;
1456
int inputChannelCount, outputChannelCount;
1457
PaSampleFormat inputSampleFormat, outputSampleFormat;
1458
PaDeviceIndex asioDeviceIndex;
1459
ASIOError asioError;
1461
if (inputParameters && outputParameters) {
1462
/* full duplex ASIO stream must use the same device for input and output */
1464
if (inputParameters->device != outputParameters->device)
1465
return paBadIODeviceCombination;
1468
if (inputParameters) {
1469
inputChannelCount = inputParameters->channelCount;
1470
inputSampleFormat = inputParameters->sampleFormat;
1472
/* all standard sample formats are supported by the buffer adapter,
1473
this implementation doesn't support any custom sample formats */
1474
if (inputSampleFormat & paCustomFormat)
1475
return paSampleFormatNotSupported;
1477
/* unless alternate device specification is supported, reject the use of
1478
paUseHostApiSpecificDeviceSpecification */
1480
if (inputParameters->device == paUseHostApiSpecificDeviceSpecification)
1481
return paInvalidDevice;
1483
asioDeviceIndex = inputParameters->device;
1485
/* validate inputStreamInfo */
1486
/** @todo do more validation here */
1487
// if( inputParameters->hostApiSpecificStreamInfo )
1488
// return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1490
inputChannelCount = 0;
1493
if (outputParameters) {
1494
outputChannelCount = outputParameters->channelCount;
1495
outputSampleFormat = outputParameters->sampleFormat;
1497
/* all standard sample formats are supported by the buffer adapter,
1498
this implementation doesn't support any custom sample formats */
1499
if (outputSampleFormat & paCustomFormat)
1500
return paSampleFormatNotSupported;
1502
/* unless alternate device specification is supported, reject the use of
1503
paUseHostApiSpecificDeviceSpecification */
1505
if (outputParameters->device == paUseHostApiSpecificDeviceSpecification)
1506
return paInvalidDevice;
1508
asioDeviceIndex = outputParameters->device;
1510
/* validate outputStreamInfo */
1511
/** @todo do more validation here */
1512
// if( outputParameters->hostApiSpecificStreamInfo )
1513
// return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1515
outputChannelCount = 0;
1520
/* if an ASIO device is open we can only get format information for the currently open device */
1522
if (asioHostApi->openAsioDeviceIndex != paNoDevice
1523
&& asioHostApi->openAsioDeviceIndex != asioDeviceIndex) {
1524
return paDeviceUnavailable;
1528
/* NOTE: we load the driver and use its current settings
1529
rather than the ones in our device info structure which may be stale */
1531
/* open the device if it's not already open */
1532
if (asioHostApi->openAsioDeviceIndex == paNoDevice) {
1533
result = LoadAsioDriver (asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
1534
driverInfo, asioHostApi->systemSpecific);
1536
if (result != paNoError)
1540
/* check that input device can support inputChannelCount */
1541
if (inputChannelCount > 0) {
1542
if (inputChannelCount > driverInfo->inputChannelCount) {
1543
result = paInvalidChannelCount;
1548
/* check that output device can support outputChannelCount */
1549
if (outputChannelCount) {
1550
if (outputChannelCount > driverInfo->outputChannelCount) {
1551
result = paInvalidChannelCount;
1556
/* query for sample rate support */
1557
asioError = ASIOCanSampleRate (sampleRate);
1559
if (asioError == ASE_NoClock || asioError == ASE_NotPresent) {
1560
result = paInvalidSampleRate;
1566
/* close the device if it wasn't already open */
1567
if (asioHostApi->openAsioDeviceIndex == paNoDevice) {
1568
UnloadAsioDriver(); /* not sure if we should check for errors here */
1571
if (result == paNoError)
1572
return paFormatIsSupported;
1579
/** A data structure specifically for storing blocking i/o related data. */
1580
typedef struct PaAsioStreamBlockingState {
1581
int stopFlag; /**< Flag indicating that block processing is to be stopped. */
1583
unsigned long writeBuffersRequested; /**< The number of available output buffers, requested by the #WriteStream() function. */
1584
unsigned long readFramesRequested; /**< The number of available input frames, requested by the #ReadStream() function. */
1586
int writeBuffersRequestedFlag; /**< Flag to indicate that #WriteStream() has requested more output buffers to be available. */
1587
int readFramesRequestedFlag; /**< Flag to indicate that #ReadStream() requires more input frames to be available. */
1589
HANDLE writeBuffersReadyEvent; /**< Event to signal that requested output buffers are available. */
1590
HANDLE readFramesReadyEvent; /**< Event to signal that requested input frames are available. */
1592
void *writeRingBufferData; /**< The actual ring buffer memory, used by the output ring buffer. */
1593
void *readRingBufferData; /**< The actual ring buffer memory, used by the input ring buffer. */
1595
PaUtilRingBuffer writeRingBuffer; /**< Frame-aligned blocking i/o ring buffer to store output data (interleaved user format). */
1596
PaUtilRingBuffer readRingBuffer; /**< Frame-aligned blocking i/o ring buffer to store input data (interleaved user format). */
1598
long writeRingBufferInitialFrames; /**< The initial number of silent frames within the output ring buffer. */
1600
const void **writeStreamBuffer; /**< Temp buffer, used by #WriteStream() for handling non-interleaved data. */
1601
void **readStreamBuffer; /**< Temp buffer, used by #ReadStream() for handling non-interleaved data. */
1603
PaUtilBufferProcessor bufferProcessor; /**< Buffer processor, used to handle the blocking i/o ring buffers. */
1605
int outputUnderflowFlag; /**< Flag to signal an output underflow from within the callback function. */
1606
int inputOverflowFlag; /**< Flag to signal an input overflow from within the callback function. */
1608
PaAsioStreamBlockingState;
1612
/* PaAsioStream - a stream data structure specifically for this implementation */
1614
typedef struct PaAsioStream {
1615
PaUtilStreamRepresentation streamRepresentation;
1616
PaUtilCpuLoadMeasurer cpuLoadMeasurer;
1617
PaUtilBufferProcessor bufferProcessor;
1619
PaAsioHostApiRepresentation *asioHostApi;
1620
unsigned long framesPerHostCallback;
1622
/* ASIO driver info - these may not be needed for the life of the stream,
1623
but store them here until we work out how format conversion is going
1626
ASIOBufferInfo *asioBufferInfos;
1627
ASIOChannelInfo *asioChannelInfos;
1628
long inputLatency, outputLatency; // actual latencies returned by asio
1630
long inputChannelCount, outputChannelCount;
1633
void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */
1634
void **inputBufferPtrs[2];
1635
void **outputBufferPtrs[2];
1637
PaAsioBufferConverter *inputBufferConverter;
1639
PaAsioBufferConverter *outputBufferConverter;
1642
volatile bool stopProcessing;
1643
int stopPlayoutCount;
1644
HANDLE completedBuffersPlayedEvent;
1646
bool streamFinishedCallbackCalled;
1648
volatile int isActive;
1649
volatile bool zeroOutput; /* all future calls to the callback will output silence */
1651
volatile long reenterCount;
1652
volatile long reenterError;
1654
PaStreamCallbackFlags callbackFlags;
1656
PaAsioStreamBlockingState *blockingState; /**< Blocking i/o data struct, or NULL when using callback interface. */
1660
static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */
1663
static void ZeroOutputBuffers (PaAsioStream *stream, long index)
1667
for (i=0; i < stream->outputChannelCount; ++i) {
1668
void *buffer = stream->asioBufferInfos[ i + stream->inputChannelCount ].buffers[index];
1670
int bytesPerSample = BytesPerAsioSample (stream->asioChannelInfos[ i + stream->inputChannelCount ].type);
1672
memset (buffer, 0, stream->framesPerHostCallback * bytesPerSample);
1677
static unsigned long SelectHostBufferSize (unsigned long suggestedLatencyFrames,
1678
PaAsioDriverInfo *driverInfo)
1680
unsigned long result;
1682
if (suggestedLatencyFrames == 0) {
1683
result = driverInfo->bufferPreferredSize;
1685
if (suggestedLatencyFrames <= (unsigned long) driverInfo->bufferMinSize) {
1686
result = driverInfo->bufferMinSize;
1687
} else if (suggestedLatencyFrames >= (unsigned long) driverInfo->bufferMaxSize) {
1688
result = driverInfo->bufferMaxSize;
1690
if (driverInfo->bufferGranularity == -1) {
1694
while (result < suggestedLatencyFrames)
1697
if (result < (unsigned long) driverInfo->bufferMinSize)
1698
result = driverInfo->bufferMinSize;
1700
if (result > (unsigned long) driverInfo->bufferMaxSize)
1701
result = driverInfo->bufferMaxSize;
1702
} else if (driverInfo->bufferGranularity == 0) {
1703
/* the documentation states that bufferGranularity should be
1704
zero when bufferMinSize, bufferMaxSize and
1705
bufferPreferredSize are the same. We assume that is the case.
1708
result = driverInfo->bufferPreferredSize;
1710
/* modulo granularity */
1712
unsigned long remainder =
1713
suggestedLatencyFrames % driverInfo->bufferGranularity;
1715
if (remainder == 0) {
1716
result = suggestedLatencyFrames;
1718
result = suggestedLatencyFrames
1719
+ (driverInfo->bufferGranularity - remainder);
1721
if (result > (unsigned long) driverInfo->bufferMaxSize)
1722
result = driverInfo->bufferMaxSize;
1732
/* returns channelSelectors if present */
1734
static PaError ValidateAsioSpecificStreamInfo (
1735
const PaStreamParameters *streamParameters,
1736
const PaAsioStreamInfo *streamInfo,
1737
int deviceChannelCount,
1738
int **channelSelectors)
1741
if (streamInfo->size != sizeof (PaAsioStreamInfo)
1742
|| streamInfo->version != 1) {
1743
return paIncompatibleHostApiSpecificStreamInfo;
1746
if (streamInfo->flags & paAsioUseChannelSelectors)
1747
*channelSelectors = streamInfo->channelSelectors;
1749
if (! (*channelSelectors))
1750
return paIncompatibleHostApiSpecificStreamInfo;
1752
for (int i=0; i < streamParameters->channelCount; ++i) {
1753
if ( (*channelSelectors) [i] < 0
1754
|| (*channelSelectors) [i] >= deviceChannelCount) {
1755
return paInvalidChannelCount;
1764
static bool IsUsingExternalClockSource()
1766
bool result = false;
1767
ASIOError asioError;
1768
ASIOClockSource clocks[32];
1771
/* davidv: listing ASIO Clock sources. there is an ongoing investigation by
1772
me about whether or not to call ASIOSetSampleRate if an external Clock is
1773
used. A few drivers expected different things here */
1775
asioError = ASIOGetClockSources (clocks, &numSources);
1777
if (asioError != ASE_OK) {
1778
PA_DEBUG ( ("ERROR: ASIOGetClockSources: %s\n", PaAsio_GetAsioErrorText (asioError)));
1780
PA_DEBUG ( ("INFO ASIOGetClockSources listing %d clocks\n", numSources));
1782
for (int i=0; i<numSources; ++i) {
1783
PA_DEBUG ( ("ASIOClockSource%d %s current:%d\n", i, clocks[i].name, clocks[i].isCurrentSource));
1785
if (clocks[i].isCurrentSource)
1794
static PaError ValidateAndSetSampleRate (double sampleRate)
1796
PaError result = paNoError;
1797
ASIOError asioError;
1799
// check that the device supports the requested sample rate
1801
asioError = ASIOCanSampleRate (sampleRate);
1802
PA_DEBUG ( ("ASIOCanSampleRate(%f):%d\n", sampleRate, asioError));
1804
if (asioError != ASE_OK) {
1805
result = paInvalidSampleRate;
1806
PA_DEBUG ( ("ERROR: ASIOCanSampleRate: %s\n", PaAsio_GetAsioErrorText (asioError)));
1810
// retrieve the current sample rate, we only change to the requested
1811
// sample rate if the device is not already in that rate.
1813
ASIOSampleRate oldRate;
1814
asioError = ASIOGetSampleRate (&oldRate);
1816
if (asioError != ASE_OK) {
1817
result = paInvalidSampleRate;
1818
PA_DEBUG ( ("ERROR: ASIOGetSampleRate: %s\n", PaAsio_GetAsioErrorText (asioError)));
1822
PA_DEBUG ( ("ASIOGetSampleRate:%f\n",oldRate));
1824
if (oldRate != sampleRate) {
1825
/* Set sample rate */
1827
PA_DEBUG ( ("before ASIOSetSampleRate(%f)\n",sampleRate));
1830
If you have problems with some drivers when externally clocked,
1831
try switching on the following line and commenting out the one after it.
1832
See IsUsingExternalClockSource() for more info.
1835
//if( IsUsingExternalClockSource() ){
1837
asioError = ASIOSetSampleRate (0);
1839
asioError = ASIOSetSampleRate (sampleRate);
1842
if (asioError != ASE_OK) {
1843
result = paInvalidSampleRate;
1844
PA_DEBUG ( ("ERROR: ASIOSetSampleRate: %s\n", PaAsio_GetAsioErrorText (asioError)));
1848
PA_DEBUG ( ("after ASIOSetSampleRate(%f)\n",sampleRate));
1850
PA_DEBUG ( ("No Need to change SR\n"));
1858
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
1860
static PaError OpenStream (struct PaUtilHostApiRepresentation *hostApi,
1862
const PaStreamParameters *inputParameters,
1863
const PaStreamParameters *outputParameters,
1865
unsigned long framesPerBuffer,
1866
PaStreamFlags streamFlags,
1867
PaStreamCallback *streamCallback,
1870
PaError result = paNoError;
1871
PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*) hostApi;
1872
PaAsioStream *stream = 0;
1873
PaAsioStreamInfo *inputStreamInfo, *outputStreamInfo;
1874
unsigned long framesPerHostBuffer;
1875
int inputChannelCount, outputChannelCount;
1876
PaSampleFormat inputSampleFormat, outputSampleFormat;
1877
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
1878
unsigned long suggestedInputLatencyFrames;
1879
unsigned long suggestedOutputLatencyFrames;
1880
PaDeviceIndex asioDeviceIndex;
1881
ASIOError asioError;
1882
int asioIsInitialized = 0;
1883
int asioBuffersCreated = 0;
1884
int completedBuffersPlayedEventInited = 0;
1886
PaAsioDriverInfo *driverInfo;
1887
int *inputChannelSelectors = 0;
1888
int *outputChannelSelectors = 0;
1890
/* Are we using blocking i/o interface? */
1891
int usingBlockingIo = (!streamCallback) ? TRUE : FALSE;
1892
/* Blocking i/o stuff */
1893
long lBlockingBufferSize = 0; /* Desired ring buffer size in samples. */
1894
long lBlockingBufferSizePow2 = 0; /* Power-of-2 rounded ring buffer size. */
1895
long lBytesPerFrame = 0; /* Number of bytes per input/output frame. */
1896
int blockingWriteBuffersReadyEventInitialized = 0; /* Event init flag. */
1897
int blockingReadFramesReadyEventInitialized = 0; /* Event init flag. */
1899
int callbackBufferProcessorInited = FALSE;
1900
int blockingBufferProcessorInited = FALSE;
1902
/* unless we move to using lower level ASIO calls, we can only have
1903
one device open at a time */
1904
if (asioHostApi->openAsioDeviceIndex != paNoDevice) {
1905
PA_DEBUG ( ("OpenStream paDeviceUnavailable\n"));
1906
return paDeviceUnavailable;
1909
assert (theAsioStream == 0);
1911
if (inputParameters && outputParameters) {
1912
/* full duplex ASIO stream must use the same device for input and output */
1914
if (inputParameters->device != outputParameters->device) {
1915
PA_DEBUG ( ("OpenStream paBadIODeviceCombination\n"));
1916
return paBadIODeviceCombination;
1920
if (inputParameters) {
1921
inputChannelCount = inputParameters->channelCount;
1922
inputSampleFormat = inputParameters->sampleFormat;
1923
suggestedInputLatencyFrames = (unsigned long) ( (inputParameters->suggestedLatency * sampleRate) +0.5f);
1925
/* unless alternate device specification is supported, reject the use of
1926
paUseHostApiSpecificDeviceSpecification */
1927
if (inputParameters->device == paUseHostApiSpecificDeviceSpecification)
1928
return paInvalidDevice;
1930
asioDeviceIndex = inputParameters->device;
1932
PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[asioDeviceIndex];
1934
/* validate hostApiSpecificStreamInfo */
1935
inputStreamInfo = (PaAsioStreamInfo*) inputParameters->hostApiSpecificStreamInfo;
1936
result = ValidateAsioSpecificStreamInfo (inputParameters, inputStreamInfo,
1937
asioDeviceInfo->commonDeviceInfo.maxInputChannels,
1938
&inputChannelSelectors
1941
if (result != paNoError) return result;
1943
inputChannelCount = 0;
1944
inputSampleFormat = 0;
1945
suggestedInputLatencyFrames = 0;
1948
if (outputParameters) {
1949
outputChannelCount = outputParameters->channelCount;
1950
outputSampleFormat = outputParameters->sampleFormat;
1951
suggestedOutputLatencyFrames = (unsigned long) ( (outputParameters->suggestedLatency * sampleRate) +0.5f);
1953
/* unless alternate device specification is supported, reject the use of
1954
paUseHostApiSpecificDeviceSpecification */
1955
if (outputParameters->device == paUseHostApiSpecificDeviceSpecification)
1956
return paInvalidDevice;
1958
asioDeviceIndex = outputParameters->device;
1960
PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[asioDeviceIndex];
1962
/* validate hostApiSpecificStreamInfo */
1963
outputStreamInfo = (PaAsioStreamInfo*) outputParameters->hostApiSpecificStreamInfo;
1964
result = ValidateAsioSpecificStreamInfo (outputParameters, outputStreamInfo,
1965
asioDeviceInfo->commonDeviceInfo.maxOutputChannels,
1966
&outputChannelSelectors
1969
if (result != paNoError) return result;
1971
outputChannelCount = 0;
1972
outputSampleFormat = 0;
1973
suggestedOutputLatencyFrames = 0;
1976
driverInfo = &asioHostApi->openAsioDriverInfo;
1978
/* NOTE: we load the driver and use its current settings
1979
rather than the ones in our device info structure which may be stale */
1981
result = LoadAsioDriver (asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
1982
driverInfo, asioHostApi->systemSpecific);
1984
if (result == paNoError)
1985
asioIsInitialized = 1;
1987
PA_DEBUG ( ("OpenStream ERROR1 - LoadAsioDriver returned %d\n", result));
1991
/* check that input device can support inputChannelCount */
1992
if (inputChannelCount > 0) {
1993
if (inputChannelCount > driverInfo->inputChannelCount) {
1994
result = paInvalidChannelCount;
1995
PA_DEBUG ( ("OpenStream ERROR2\n"));
2000
/* check that output device can support outputChannelCount */
2001
if (outputChannelCount) {
2002
if (outputChannelCount > driverInfo->outputChannelCount) {
2003
result = paInvalidChannelCount;
2004
PA_DEBUG ( ("OpenStream ERROR3\n"));
2009
result = ValidateAndSetSampleRate (sampleRate);
2011
if (result != paNoError)
2016
- if a full duplex stream is requested, check that the combination
2017
of input and output parameters is supported
2020
/* validate platform specific flags */
2021
if ( (streamFlags & paPlatformSpecificFlags) != 0) {
2022
PA_DEBUG ( ("OpenStream invalid flags!!\n"));
2023
return paInvalidFlag; /* unexpected platform specific flag */
2027
stream = (PaAsioStream*) PaUtil_AllocateMemory (sizeof (PaAsioStream));
2030
result = paInsufficientMemory;
2031
PA_DEBUG ( ("OpenStream ERROR5\n"));
2035
stream->blockingState = NULL; /* Blocking i/o not initialized, yet. */
2038
stream->completedBuffersPlayedEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
2040
if (stream->completedBuffersPlayedEvent == NULL) {
2041
result = paUnanticipatedHostError;
2042
PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
2043
PA_DEBUG ( ("OpenStream ERROR6\n"));
2047
completedBuffersPlayedEventInited = 1;
2050
stream->asioBufferInfos = 0; /* for deallocation in error */
2051
stream->asioChannelInfos = 0; /* for deallocation in error */
2052
stream->bufferPtrs = 0; /* for deallocation in error */
2054
/* Using blocking i/o interface... */
2055
if (usingBlockingIo) {
2056
/* Blocking i/o is implemented by running callback mode, using a special blocking i/o callback. */
2057
streamCallback = BlockingIoPaCallback; /* Setup PA to use the ASIO blocking i/o callback. */
2058
userData = &theAsioStream; /* The callback user data will be the PA ASIO stream. */
2059
PaUtil_InitializeStreamRepresentation (&stream->streamRepresentation,
2060
&asioHostApi->blockingStreamInterface, streamCallback, userData);
2061
} else { /* Using callback interface... */
2062
PaUtil_InitializeStreamRepresentation (&stream->streamRepresentation,
2063
&asioHostApi->callbackStreamInterface, streamCallback, userData);
2067
PaUtil_InitializeCpuLoadMeasurer (&stream->cpuLoadMeasurer, sampleRate);
2070
stream->asioBufferInfos = (ASIOBufferInfo*) PaUtil_AllocateMemory (
2071
sizeof (ASIOBufferInfo) * (inputChannelCount + outputChannelCount));
2073
if (!stream->asioBufferInfos) {
2074
result = paInsufficientMemory;
2075
PA_DEBUG ( ("OpenStream ERROR7\n"));
2080
for (i=0; i < inputChannelCount; ++i) {
2081
ASIOBufferInfo *info = &stream->asioBufferInfos[i];
2083
info->isInput = ASIOTrue;
2085
if (inputChannelSelectors) {
2086
// inputChannelSelectors values have already been validated in
2087
// ValidateAsioSpecificStreamInfo() above
2088
info->channelNum = inputChannelSelectors[i];
2090
info->channelNum = i;
2093
info->buffers[0] = info->buffers[1] = 0;
2096
for (i=0; i < outputChannelCount; ++i) {
2097
ASIOBufferInfo *info = &stream->asioBufferInfos[inputChannelCount+i];
2099
info->isInput = ASIOFalse;
2101
if (outputChannelSelectors) {
2102
// outputChannelSelectors values have already been validated in
2103
// ValidateAsioSpecificStreamInfo() above
2104
info->channelNum = outputChannelSelectors[i];
2106
info->channelNum = i;
2109
info->buffers[0] = info->buffers[1] = 0;
2113
/* Using blocking i/o interface... */
2114
if (usingBlockingIo) {
2115
/** @todo REVIEW selection of host buffer size for blocking i/o */
2116
/* Use default host latency for blocking i/o. */
2117
framesPerHostBuffer = SelectHostBufferSize (0, driverInfo);
2119
} else { /* Using callback interface... */
2120
framesPerHostBuffer = SelectHostBufferSize (
2121
( (suggestedInputLatencyFrames > suggestedOutputLatencyFrames)
2122
? suggestedInputLatencyFrames : suggestedOutputLatencyFrames),
2127
PA_DEBUG ( ("PaAsioOpenStream: framesPerHostBuffer :%d\n", framesPerHostBuffer));
2129
asioError = ASIOCreateBuffers (stream->asioBufferInfos,
2130
inputChannelCount+outputChannelCount,
2131
framesPerHostBuffer, &asioCallbacks_);
2133
if (asioError != ASE_OK
2134
&& framesPerHostBuffer != (unsigned long) driverInfo->bufferPreferredSize) {
2135
PA_DEBUG ( ("ERROR: ASIOCreateBuffers: %s\n", PaAsio_GetAsioErrorText (asioError)));
2137
Some buggy drivers (like the Hoontech DSP24) give incorrect
2138
[min, preferred, max] values They should work with the preferred size
2139
value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize
2140
computed in SelectHostBufferSize, we try again with the preferred size.
2143
framesPerHostBuffer = driverInfo->bufferPreferredSize;
2145
PA_DEBUG ( ("PaAsioOpenStream: CORRECTED framesPerHostBuffer :%d\n", framesPerHostBuffer));
2147
ASIOError asioError2 = ASIOCreateBuffers (stream->asioBufferInfos,
2148
inputChannelCount+outputChannelCount,
2149
framesPerHostBuffer, &asioCallbacks_);
2151
if (asioError2 == ASE_OK)
2155
if (asioError != ASE_OK) {
2156
result = paUnanticipatedHostError;
2157
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
2158
PA_DEBUG ( ("OpenStream ERROR9\n"));
2162
asioBuffersCreated = 1;
2164
stream->asioChannelInfos = (ASIOChannelInfo*) PaUtil_AllocateMemory (
2165
sizeof (ASIOChannelInfo) * (inputChannelCount + outputChannelCount));
2167
if (!stream->asioChannelInfos) {
2168
result = paInsufficientMemory;
2169
PA_DEBUG ( ("OpenStream ERROR10\n"));
2173
for (i=0; i < inputChannelCount + outputChannelCount; ++i) {
2174
stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum;
2175
stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput;
2176
asioError = ASIOGetChannelInfo (&stream->asioChannelInfos[i]);
2178
if (asioError != ASE_OK) {
2179
result = paUnanticipatedHostError;
2180
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
2181
PA_DEBUG ( ("OpenStream ERROR11\n"));
2186
stream->bufferPtrs = (void**) PaUtil_AllocateMemory (
2187
2 * sizeof (void*) * (inputChannelCount + outputChannelCount));
2189
if (!stream->bufferPtrs) {
2190
result = paInsufficientMemory;
2191
PA_DEBUG ( ("OpenStream ERROR12\n"));
2195
if (inputChannelCount > 0) {
2196
stream->inputBufferPtrs[0] = stream-> bufferPtrs;
2197
stream->inputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount];
2199
for (i=0; i<inputChannelCount; ++i) {
2200
stream->inputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0];
2201
stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1];
2204
stream->inputBufferPtrs[0] = 0;
2205
stream->inputBufferPtrs[1] = 0;
2208
if (outputChannelCount > 0) {
2209
stream->outputBufferPtrs[0] = &stream->bufferPtrs[inputChannelCount*2];
2210
stream->outputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount*2 + outputChannelCount];
2212
for (i=0; i<outputChannelCount; ++i) {
2213
stream->outputBufferPtrs[0][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[0];
2214
stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[1];
2217
stream->outputBufferPtrs[0] = 0;
2218
stream->outputBufferPtrs[1] = 0;
2221
if (inputChannelCount > 0) {
2222
/* FIXME: assume all channels use the same type for now */
2223
ASIOSampleType inputType = stream->asioChannelInfos[0].type;
2225
PA_DEBUG ( ("ASIO Input type:%d",inputType));
2226
AsioSampleTypeLOG (inputType);
2227
hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat (inputType);
2229
SelectAsioToPaConverter (inputType, &stream->inputBufferConverter, &stream->inputShift);
2231
hostInputSampleFormat = 0;
2232
stream->inputBufferConverter = 0;
2235
if (outputChannelCount > 0) {
2236
/* FIXME: assume all channels use the same type for now */
2237
ASIOSampleType outputType = stream->asioChannelInfos[inputChannelCount].type;
2239
PA_DEBUG ( ("ASIO Output type:%d",outputType));
2240
AsioSampleTypeLOG (outputType);
2241
hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat (outputType);
2243
SelectPaToAsioConverter (outputType, &stream->outputBufferConverter, &stream->outputShift);
2245
hostOutputSampleFormat = 0;
2246
stream->outputBufferConverter = 0;
2250
ASIOGetLatencies (&stream->inputLatency, &stream->outputLatency);
2253
/* Using blocking i/o interface... */
2254
if (usingBlockingIo) {
2255
/* Allocate the blocking i/o input ring buffer memory. */
2256
stream->blockingState = (PaAsioStreamBlockingState*) PaUtil_AllocateMemory (sizeof (PaAsioStreamBlockingState));
2258
if (!stream->blockingState) {
2259
result = paInsufficientMemory;
2260
PA_DEBUG ( ("ERROR! Blocking i/o interface struct allocation failed in OpenStream()\n"));
2264
/* Initialize blocking i/o interface struct. */
2265
stream->blockingState->readFramesReadyEvent = NULL; /* Uninitialized, yet. */
2266
stream->blockingState->writeBuffersReadyEvent = NULL; /* Uninitialized, yet. */
2267
stream->blockingState->readRingBufferData = NULL; /* Uninitialized, yet. */
2268
stream->blockingState->writeRingBufferData = NULL; /* Uninitialized, yet. */
2269
stream->blockingState->readStreamBuffer = NULL; /* Uninitialized, yet. */
2270
stream->blockingState->writeStreamBuffer = NULL; /* Uninitialized, yet. */
2271
stream->blockingState->stopFlag = TRUE; /* Not started, yet. */
2274
/* If the user buffer is unspecified */
2275
if (framesPerBuffer == paFramesPerBufferUnspecified) {
2276
/* Make the user buffer the same size as the host buffer. */
2277
framesPerBuffer = framesPerHostBuffer;
2281
/* Initialize callback buffer processor. */
2282
result = PaUtil_InitializeBufferProcessor (&stream->bufferProcessor ,
2284
inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
2285
hostInputSampleFormat , /* Host format. */
2286
outputChannelCount ,
2287
outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
2288
hostOutputSampleFormat , /* Host format. */
2291
framesPerBuffer , /* Frames per ring buffer block. */
2292
framesPerHostBuffer , /* Frames per asio buffer. */
2293
paUtilFixedHostBufferSize ,
2297
if (result != paNoError) {
2298
PA_DEBUG ( ("OpenStream ERROR13\n"));
2302
callbackBufferProcessorInited = TRUE;
2304
/* Initialize the blocking i/o buffer processor. */
2305
result = PaUtil_InitializeBufferProcessor (&stream->blockingState->bufferProcessor,
2307
inputSampleFormat , /* User format. */
2308
inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
2309
outputChannelCount ,
2310
outputSampleFormat , /* User format. */
2311
outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
2313
paClipOff | paDitherOff , /* Don't use dither nor clipping. */
2314
framesPerBuffer , /* Frames per user buffer. */
2315
framesPerBuffer , /* Frames per ring buffer block. */
2316
paUtilBoundedHostBufferSize ,
2317
NULL, NULL); /* No callback! */
2319
if (result != paNoError) {
2320
PA_DEBUG ( ("ERROR! Blocking i/o buffer processor initialization failed in OpenStream()\n"));
2324
blockingBufferProcessorInited = TRUE;
2326
/* If input is requested. */
2327
if (inputChannelCount) {
2328
/* Create the callback sync-event. */
2329
stream->blockingState->readFramesReadyEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2331
if (stream->blockingState->readFramesReadyEvent == NULL) {
2332
result = paUnanticipatedHostError;
2333
PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
2334
PA_DEBUG ( ("ERROR! Blocking i/o \"read frames ready\" event creation failed in OpenStream()\n"));
2338
blockingReadFramesReadyEventInitialized = 1;
2341
/* Create pointer buffer to access non-interleaved data in ReadStream() */
2342
stream->blockingState->readStreamBuffer = (void**) PaUtil_AllocateMemory (sizeof (void*) * inputChannelCount);
2344
if (!stream->blockingState->readStreamBuffer) {
2345
result = paInsufficientMemory;
2346
PA_DEBUG ( ("ERROR! Blocking i/o read stream buffer allocation failed in OpenStream()\n"));
2350
/* The ring buffer should store as many data blocks as needed
2351
to achieve the requested latency. Whereas it must be large
2352
enough to store at least two complete data blocks.
2354
1) Determine the amount of latency to be added to the
2355
prefered ASIO latency.
2356
2) Make sure we have at lest one additional latency frame.
2357
3) Divide the number of frames by the desired block size to
2358
get the number (rounded up to pure integer) of blocks to
2359
be stored in the buffer.
2360
4) Add one additional block for block processing and convert
2362
5) Get the next larger (or equal) power-of-two buffer size.
2364
lBlockingBufferSize = suggestedInputLatencyFrames - stream->inputLatency;
2365
lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
2366
lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
2367
lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
2369
/* Get the next larger or equal power-of-two buffersize. */
2370
lBlockingBufferSizePow2 = 1;
2372
while (lBlockingBufferSize > (lBlockingBufferSizePow2<<=1));
2374
lBlockingBufferSize = lBlockingBufferSizePow2;
2376
/* Compute total intput latency in seconds */
2377
stream->streamRepresentation.streamInfo.inputLatency =
2378
(double) (PaUtil_GetBufferProcessorInputLatency (&stream->bufferProcessor)
2379
+ PaUtil_GetBufferProcessorInputLatency (&stream->blockingState->bufferProcessor)
2380
+ (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer
2381
+ stream->inputLatency)
2384
/* The code below prints the ASIO latency which doesn't include
2385
the buffer processor latency nor the blocking i/o latency. It
2386
reports the added latency separately.
2388
PA_DEBUG ( ("PaAsio : ASIO InputLatency = %ld (%ld ms),\n added buffProc:%ld (%ld ms),\n added blocking:%ld (%ld ms)\n",
2389
stream->inputLatency,
2390
(long) (stream->inputLatency * (1000.0 / sampleRate)),
2391
PaUtil_GetBufferProcessorInputLatency (&stream->bufferProcessor),
2392
(long) (PaUtil_GetBufferProcessorInputLatency (&stream->bufferProcessor) * (1000.0 / sampleRate)),
2393
PaUtil_GetBufferProcessorInputLatency (&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer,
2394
(long) ( (PaUtil_GetBufferProcessorInputLatency (&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate))
2397
/* Determine the size of ring buffer in bytes. */
2398
lBytesPerFrame = inputChannelCount * Pa_GetSampleSize (inputSampleFormat);
2400
/* Allocate the blocking i/o input ring buffer memory. */
2401
stream->blockingState->readRingBufferData = (void*) PaUtil_AllocateMemory (lBlockingBufferSize * lBytesPerFrame);
2403
if (!stream->blockingState->readRingBufferData) {
2404
result = paInsufficientMemory;
2405
PA_DEBUG ( ("ERROR! Blocking i/o input ring buffer allocation failed in OpenStream()\n"));
2409
/* Initialize the input ring buffer struct. */
2410
PaUtil_InitializeRingBuffer (&stream->blockingState->readRingBuffer ,
2412
lBlockingBufferSize ,
2413
stream->blockingState->readRingBufferData);
2416
/* If output is requested. */
2417
if (outputChannelCount) {
2418
stream->blockingState->writeBuffersReadyEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2420
if (stream->blockingState->writeBuffersReadyEvent == NULL) {
2421
result = paUnanticipatedHostError;
2422
PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
2423
PA_DEBUG ( ("ERROR! Blocking i/o \"write buffers ready\" event creation failed in OpenStream()\n"));
2427
blockingWriteBuffersReadyEventInitialized = 1;
2429
/* Create pointer buffer to access non-interleaved data in WriteStream() */
2430
stream->blockingState->writeStreamBuffer = (const void**) PaUtil_AllocateMemory (sizeof (const void*) * outputChannelCount);
2432
if (!stream->blockingState->writeStreamBuffer) {
2433
result = paInsufficientMemory;
2434
PA_DEBUG ( ("ERROR! Blocking i/o write stream buffer allocation failed in OpenStream()\n"));
2438
/* The ring buffer should store as many data blocks as needed
2439
to achieve the requested latency. Whereas it must be large
2440
enough to store at least two complete data blocks.
2442
1) Determine the amount of latency to be added to the
2443
prefered ASIO latency.
2444
2) Make sure we have at lest one additional latency frame.
2445
3) Divide the number of frames by the desired block size to
2446
get the number (rounded up to pure integer) of blocks to
2447
be stored in the buffer.
2448
4) Add one additional block for block processing and convert
2450
5) Get the next larger (or equal) power-of-two buffer size.
2452
lBlockingBufferSize = suggestedOutputLatencyFrames - stream->outputLatency;
2453
lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
2454
lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
2455
lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
2457
/* The buffer size (without the additional block) corresponds
2458
to the initial number of silent samples in the output ring
2460
stream->blockingState->writeRingBufferInitialFrames = lBlockingBufferSize - framesPerBuffer;
2462
/* Get the next larger or equal power-of-two buffersize. */
2463
lBlockingBufferSizePow2 = 1;
2465
while (lBlockingBufferSize > (lBlockingBufferSizePow2<<=1));
2467
lBlockingBufferSize = lBlockingBufferSizePow2;
2469
/* Compute total output latency in seconds */
2470
stream->streamRepresentation.streamInfo.outputLatency =
2471
(double) (PaUtil_GetBufferProcessorOutputLatency (&stream->bufferProcessor)
2472
+ PaUtil_GetBufferProcessorOutputLatency (&stream->blockingState->bufferProcessor)
2473
+ (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer
2474
+ stream->outputLatency)
2477
/* The code below prints the ASIO latency which doesn't include
2478
the buffer processor latency nor the blocking i/o latency. It
2479
reports the added latency separately.
2481
PA_DEBUG ( ("PaAsio : ASIO OutputLatency = %ld (%ld ms),\n added buffProc:%ld (%ld ms),\n added blocking:%ld (%ld ms)\n",
2482
stream->outputLatency,
2483
(long) (stream->inputLatency * (1000.0 / sampleRate)),
2484
PaUtil_GetBufferProcessorOutputLatency (&stream->bufferProcessor),
2485
(long) (PaUtil_GetBufferProcessorOutputLatency (&stream->bufferProcessor) * (1000.0 / sampleRate)),
2486
PaUtil_GetBufferProcessorOutputLatency (&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer,
2487
(long) ( (PaUtil_GetBufferProcessorOutputLatency (&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate))
2490
/* Determine the size of ring buffer in bytes. */
2491
lBytesPerFrame = outputChannelCount * Pa_GetSampleSize (outputSampleFormat);
2493
/* Allocate the blocking i/o output ring buffer memory. */
2494
stream->blockingState->writeRingBufferData = (void*) PaUtil_AllocateMemory (lBlockingBufferSize * lBytesPerFrame);
2496
if (!stream->blockingState->writeRingBufferData) {
2497
result = paInsufficientMemory;
2498
PA_DEBUG ( ("ERROR! Blocking i/o output ring buffer allocation failed in OpenStream()\n"));
2502
/* Initialize the output ring buffer struct. */
2503
PaUtil_InitializeRingBuffer (&stream->blockingState->writeRingBuffer ,
2505
lBlockingBufferSize ,
2506
stream->blockingState->writeRingBufferData);
2509
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
2512
} else { /* Using callback interface... */
2513
result = PaUtil_InitializeBufferProcessor (&stream->bufferProcessor,
2514
inputChannelCount, inputSampleFormat, hostInputSampleFormat,
2515
outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
2516
sampleRate, streamFlags, framesPerBuffer,
2517
framesPerHostBuffer, paUtilFixedHostBufferSize,
2518
streamCallback, userData);
2520
if (result != paNoError) {
2521
PA_DEBUG ( ("OpenStream ERROR13\n"));
2525
callbackBufferProcessorInited = TRUE;
2527
stream->streamRepresentation.streamInfo.inputLatency =
2528
(double) (PaUtil_GetBufferProcessorInputLatency (&stream->bufferProcessor)
2529
+ stream->inputLatency) / sampleRate; // seconds
2530
stream->streamRepresentation.streamInfo.outputLatency =
2531
(double) (PaUtil_GetBufferProcessorOutputLatency (&stream->bufferProcessor)
2532
+ stream->outputLatency) / sampleRate; // seconds
2533
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
2535
// the code below prints the ASIO latency which doesn't include the
2536
// buffer processor latency. it reports the added latency separately
2537
PA_DEBUG ( ("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
2538
stream->inputLatency,
2539
(long) ( (stream->inputLatency*1000) / sampleRate),
2540
PaUtil_GetBufferProcessorInputLatency (&stream->bufferProcessor),
2541
(long) ( (PaUtil_GetBufferProcessorInputLatency (&stream->bufferProcessor) *1000) / sampleRate)
2544
PA_DEBUG ( ("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
2545
stream->outputLatency,
2546
(long) ( (stream->outputLatency*1000) / sampleRate),
2547
PaUtil_GetBufferProcessorOutputLatency (&stream->bufferProcessor),
2548
(long) ( (PaUtil_GetBufferProcessorOutputLatency (&stream->bufferProcessor) *1000) / sampleRate)
2552
stream->asioHostApi = asioHostApi;
2553
stream->framesPerHostCallback = framesPerHostBuffer;
2555
stream->inputChannelCount = inputChannelCount;
2556
stream->outputChannelCount = outputChannelCount;
2557
stream->postOutput = driverInfo->postOutput;
2558
stream->isStopped = 1;
2559
stream->isActive = 0;
2561
asioHostApi->openAsioDeviceIndex = asioDeviceIndex;
2563
theAsioStream = stream;
2564
*s = (PaStream*) stream;
2569
PA_DEBUG ( ("goto errored\n"));
2572
if (stream->blockingState) {
2573
if (blockingBufferProcessorInited)
2574
PaUtil_TerminateBufferProcessor (&stream->blockingState->bufferProcessor);
2576
if (stream->blockingState->writeRingBufferData)
2577
PaUtil_FreeMemory (stream->blockingState->writeRingBufferData);
2579
if (stream->blockingState->writeStreamBuffer)
2580
PaUtil_FreeMemory (stream->blockingState->writeStreamBuffer);
2582
if (blockingWriteBuffersReadyEventInitialized)
2583
CloseHandle (stream->blockingState->writeBuffersReadyEvent);
2585
if (stream->blockingState->readRingBufferData)
2586
PaUtil_FreeMemory (stream->blockingState->readRingBufferData);
2588
if (stream->blockingState->readStreamBuffer)
2589
PaUtil_FreeMemory (stream->blockingState->readStreamBuffer);
2591
if (blockingReadFramesReadyEventInitialized)
2592
CloseHandle (stream->blockingState->readFramesReadyEvent);
2594
PaUtil_FreeMemory (stream->blockingState);
2597
if (callbackBufferProcessorInited)
2598
PaUtil_TerminateBufferProcessor (&stream->bufferProcessor);
2600
if (completedBuffersPlayedEventInited)
2601
CloseHandle (stream->completedBuffersPlayedEvent);
2603
if (stream->asioBufferInfos)
2604
PaUtil_FreeMemory (stream->asioBufferInfos);
2606
if (stream->asioChannelInfos)
2607
PaUtil_FreeMemory (stream->asioChannelInfos);
2609
if (stream->bufferPtrs)
2610
PaUtil_FreeMemory (stream->bufferPtrs);
2612
PaUtil_FreeMemory (stream);
2615
if (asioBuffersCreated)
2616
ASIODisposeBuffers();
2618
if (asioIsInitialized) {
2627
When CloseStream() is called, the multi-api layer ensures that
2628
the stream has already been stopped or aborted.
2630
static PaError CloseStream (PaStream* s)
2632
PaError result = paNoError;
2633
PaAsioStream *stream = (PaAsioStream*) s;
2637
- additional stream closing + cleanup
2640
PaUtil_TerminateBufferProcessor (&stream->bufferProcessor);
2641
PaUtil_TerminateStreamRepresentation (&stream->streamRepresentation);
2643
stream->asioHostApi->openAsioDeviceIndex = paNoDevice;
2645
CloseHandle (stream->completedBuffersPlayedEvent);
2647
/* Using blocking i/o interface... */
2648
if (stream->blockingState) {
2649
PaUtil_TerminateBufferProcessor (&stream->blockingState->bufferProcessor);
2651
if (stream->inputChannelCount) {
2652
PaUtil_FreeMemory (stream->blockingState->readRingBufferData);
2653
PaUtil_FreeMemory (stream->blockingState->readStreamBuffer);
2654
CloseHandle (stream->blockingState->readFramesReadyEvent);
2657
if (stream->outputChannelCount) {
2658
PaUtil_FreeMemory (stream->blockingState->writeRingBufferData);
2659
PaUtil_FreeMemory (stream->blockingState->writeStreamBuffer);
2660
CloseHandle (stream->blockingState->writeBuffersReadyEvent);
2663
PaUtil_FreeMemory (stream->blockingState);
2666
PaUtil_FreeMemory (stream->asioBufferInfos);
2667
PaUtil_FreeMemory (stream->asioChannelInfos);
2668
PaUtil_FreeMemory (stream->bufferPtrs);
2669
PaUtil_FreeMemory (stream);
2671
ASIODisposeBuffers();
2680
static void bufferSwitch (long index, ASIOBool directProcess)
2682
//TAKEN FROM THE ASIO SDK
2684
// the actual processing callback.
2685
// Beware that this is normally in a seperate thread, hence be sure that
2686
// you take care about thread synchronization. This is omitted here for
2689
// as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
2690
// to be created though it will only set the timeInfo.samplePosition and
2691
// timeInfo.systemTime fields and the according flags
2694
memset (&timeInfo, 0, sizeof (timeInfo));
2696
// get the time stamp of the buffer, not necessary if no
2697
// synchronization to other media is required
2698
if (ASIOGetSamplePosition (&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
2699
timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
2701
// Call the real callback
2702
bufferSwitchTimeInfo (&timeInfo, index, directProcess);
2706
// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
2708
#define ASIO64toDouble(a) (a)
2710
const double twoRaisedTo32 = 4294967296.;
2711
#define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
2714
static ASIOTime *bufferSwitchTimeInfo (ASIOTime *timeInfo, long index, ASIOBool directProcess)
2716
// the actual processing callback.
2717
// Beware that this is normally in a seperate thread, hence be sure that
2718
// you take care about thread synchronization.
2721
/* The SDK says the following about the directProcess flag:
2722
suggests to the host whether it should immediately start processing
2723
(directProcess == ASIOTrue), or whether its process should be deferred
2724
because the call comes from a very low level (for instance, a high level
2725
priority interrupt), and direct processing would cause timing instabilities for
2726
the rest of the system. If in doubt, directProcess should be set to ASIOFalse.
2728
We just ignore directProcess. This could cause incompatibilities with
2729
drivers which really don't want the audio processing to occur in this
2730
callback, but none have been identified yet.
2733
(void) directProcess; /* suppress unused parameter warning */
2736
// store the timeInfo for later use
2737
asioDriverInfo.tInfo = *timeInfo;
2739
// get the time stamp of the buffer, not necessary if no
2740
// synchronization to other media is required
2742
if (timeInfo->timeInfo.flags & kSystemTimeValid)
2743
asioDriverInfo.nanoSeconds = ASIO64toDouble (timeInfo->timeInfo.systemTime);
2745
asioDriverInfo.nanoSeconds = 0;
2747
if (timeInfo->timeInfo.flags & kSamplePositionValid)
2748
asioDriverInfo.samples = ASIO64toDouble (timeInfo->timeInfo.samplePosition);
2750
asioDriverInfo.samples = 0;
2752
if (timeInfo->timeCode.flags & kTcValid)
2753
asioDriverInfo.tcSamples = ASIO64toDouble (timeInfo->timeCode.timeCodeSamples);
2755
asioDriverInfo.tcSamples = 0;
2757
// get the system reference time
2758
asioDriverInfo.sysRefTime = get_sys_reference_time();
2762
// a few debug messages for the Windows device driver developer
2763
// tells you the time when driver got its interrupt and the delay until the app receives
2764
// the event notification.
2765
static double last_samples = 0;
2767
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));
2768
OutputDebugString (tmp);
2769
last_samples = asioDriverInfo.samples;
2776
// Keep sample position
2777
// FIXME: asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
2780
// protect against reentrancy
2781
if (PaAsio_AtomicIncrement (&theAsioStream->reenterCount)) {
2782
theAsioStream->reenterError++;
2783
//DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError));
2787
int buffersDone = 0;
2790
if (buffersDone > 0) {
2791
// this is a reentered buffer, we missed processing it on time
2792
// set the input overflow and output underflow flags as appropriate
2794
if (theAsioStream->inputChannelCount > 0)
2795
theAsioStream->callbackFlags |= paInputOverflow;
2797
if (theAsioStream->outputChannelCount > 0)
2798
theAsioStream->callbackFlags |= paOutputUnderflow;
2800
if (theAsioStream->zeroOutput) {
2801
ZeroOutputBuffers (theAsioStream, index);
2803
// Finally if the driver supports the ASIOOutputReady() optimization,
2804
// do it here, all data are in place
2805
if (theAsioStream->postOutput)
2808
if (theAsioStream->stopProcessing) {
2809
if (theAsioStream->stopPlayoutCount < 2) {
2810
++theAsioStream->stopPlayoutCount;
2812
if (theAsioStream->stopPlayoutCount == 2) {
2813
theAsioStream->isActive = 0;
2815
if (theAsioStream->streamRepresentation.streamFinishedCallback != 0)
2816
theAsioStream->streamRepresentation.streamFinishedCallback (theAsioStream->streamRepresentation.userData);
2818
theAsioStream->streamFinishedCallbackCalled = true;
2819
SetEvent (theAsioStream->completedBuffersPlayedEvent);
2826
// test code to try to detect slip conditions... these may work on some systems
2827
// but neither of them work on the RME Digi96
2829
// check that sample delta matches buffer size (otherwise we must have skipped
2831
static double last_samples = -512;
2833
//if( timeInfo->timeCode.flags & kTcValid )
2834
// samples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
2836
samples = ASIO64toDouble (timeInfo->timeInfo.samplePosition);
2837
int delta = samples - last_samples;
2838
//printf( "%d\n", delta);
2839
last_samples = samples;
2841
if (delta > theAsioStream->framesPerHostCallback) {
2842
if (theAsioStream->inputChannelCount > 0)
2843
theAsioStream->callbackFlags |= paInputOverflow;
2845
if (theAsioStream->outputChannelCount > 0)
2846
theAsioStream->callbackFlags |= paOutputUnderflow;
2849
// check that the buffer index is not the previous index (which would indicate
2850
// that a buffer was skipped.
2851
static int previousIndex = 1;
2853
if (index == previousIndex) {
2854
if (theAsioStream->inputChannelCount > 0)
2855
theAsioStream->callbackFlags |= paInputOverflow;
2857
if (theAsioStream->outputChannelCount > 0)
2858
theAsioStream->callbackFlags |= paOutputUnderflow;
2861
previousIndex = index;
2866
PaUtil_BeginCpuLoadMeasurement (&theAsioStream->cpuLoadMeasurer);
2868
PaStreamCallbackTimeInfo paTimeInfo;
2870
// asio systemTime is supposed to be measured according to the same
2871
// clock as timeGetTime
2872
paTimeInfo.currentTime = (ASIO64toDouble (timeInfo->timeInfo.systemTime) * .000000001);
2874
/* patch from Paul Boege */
2875
paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime -
2876
( (double) theAsioStream->inputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
2878
paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime +
2879
( (double) theAsioStream->outputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
2881
/* old version is buggy because the buffer processor also adds in its latency to the time parameters
2882
paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency;
2883
paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency;
2886
/* Disabled! Stopping and re-starting the stream causes an input overflow / output undeflow. S.Fischer */
2888
// detect underflows by checking inter-callback time > 2 buffer period
2889
static double previousTime = -1;
2891
if (previousTime > 0) {
2893
double delta = paTimeInfo.currentTime - previousTime;
2895
if (delta >= 2. * (theAsioStream->framesPerHostCallback / theAsioStream->streamRepresentation.streamInfo.sampleRate)) {
2896
if (theAsioStream->inputChannelCount > 0)
2897
theAsioStream->callbackFlags |= paInputOverflow;
2899
if (theAsioStream->outputChannelCount > 0)
2900
theAsioStream->callbackFlags |= paOutputUnderflow;
2904
previousTime = paTimeInfo.currentTime;
2907
// note that the above input and output times do not need to be
2908
// adjusted for the latency of the buffer processor -- the buffer
2909
// processor handles that.
2911
if (theAsioStream->inputBufferConverter) {
2912
for (i=0; i<theAsioStream->inputChannelCount; i++) {
2913
theAsioStream->inputBufferConverter (theAsioStream->inputBufferPtrs[index][i],
2914
theAsioStream->inputShift, theAsioStream->framesPerHostCallback);
2918
PaUtil_BeginBufferProcessing (&theAsioStream->bufferProcessor, &paTimeInfo, theAsioStream->callbackFlags);
2920
/* reset status flags once they've been passed to the callback */
2921
theAsioStream->callbackFlags = 0;
2923
PaUtil_SetInputFrameCount (&theAsioStream->bufferProcessor, 0 /* default to host buffer size */);
2925
for (i=0; i<theAsioStream->inputChannelCount; ++i)
2926
PaUtil_SetNonInterleavedInputChannel (&theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i]);
2928
PaUtil_SetOutputFrameCount (&theAsioStream->bufferProcessor, 0 /* default to host buffer size */);
2930
for (i=0; i<theAsioStream->outputChannelCount; ++i)
2931
PaUtil_SetNonInterleavedOutputChannel (&theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i]);
2935
if (theAsioStream->stopProcessing)
2936
callbackResult = paComplete;
2938
callbackResult = paContinue;
2940
unsigned long framesProcessed = PaUtil_EndBufferProcessing (&theAsioStream->bufferProcessor, &callbackResult);
2942
if (theAsioStream->outputBufferConverter) {
2943
for (i=0; i<theAsioStream->outputChannelCount; i++) {
2944
theAsioStream->outputBufferConverter (theAsioStream->outputBufferPtrs[index][i],
2945
theAsioStream->outputShift, theAsioStream->framesPerHostCallback);
2949
PaUtil_EndCpuLoadMeasurement (&theAsioStream->cpuLoadMeasurer, framesProcessed);
2951
// Finally if the driver supports the ASIOOutputReady() optimization,
2952
// do it here, all data are in place
2953
if (theAsioStream->postOutput)
2956
if (callbackResult == paContinue) {
2957
/* nothing special to do */
2958
} else if (callbackResult == paAbort) {
2959
/* finish playback immediately */
2960
theAsioStream->isActive = 0;
2962
if (theAsioStream->streamRepresentation.streamFinishedCallback != 0)
2963
theAsioStream->streamRepresentation.streamFinishedCallback (theAsioStream->streamRepresentation.userData);
2965
theAsioStream->streamFinishedCallbackCalled = true;
2966
SetEvent (theAsioStream->completedBuffersPlayedEvent);
2967
theAsioStream->zeroOutput = true;
2968
} else { /* paComplete or other non-zero value indicating complete */
2969
/* Finish playback once currently queued audio has completed. */
2970
theAsioStream->stopProcessing = true;
2972
if (PaUtil_IsBufferProcessorOutputEmpty (&theAsioStream->bufferProcessor)) {
2973
theAsioStream->zeroOutput = true;
2974
theAsioStream->stopPlayoutCount = 0;
2981
} while (PaAsio_AtomicDecrement (&theAsioStream->reenterCount) >= 0);
2987
static void sampleRateChanged (ASIOSampleRate sRate)
2989
// TAKEN FROM THE ASIO SDK
2990
// do whatever you need to do if the sample rate changed
2991
// usually this only happens during external sync.
2992
// Audio processing is not stopped by the driver, actual sample rate
2993
// might not have even changed, maybe only the sample rate status of an
2994
// AES/EBU or S/PDIF digital input at the audio device.
2995
// You might have to update time/sample related conversion routines, etc.
2997
(void) sRate; /* unused parameter */
2998
PA_DEBUG ( ("sampleRateChanged : %d \n", sRate));
3001
static long asioMessages (long selector, long value, void* message, double* opt)
3003
// TAKEN FROM THE ASIO SDK
3004
// currently the parameters "value", "message" and "opt" are not used.
3007
(void) message; /* unused parameters */
3010
PA_DEBUG ( ("asioMessages : %d , %d \n", selector, value));
3013
case kAsioSelectorSupported:
3015
if (value == kAsioResetRequest
3016
|| value == kAsioEngineVersion
3017
|| value == kAsioResyncRequest
3018
|| value == kAsioLatenciesChanged
3019
// the following three were added for ASIO 2.0, you don't necessarily have to support them
3020
|| value == kAsioSupportsTimeInfo
3021
|| value == kAsioSupportsTimeCode
3022
|| value == kAsioSupportsInputMonitor)
3027
case kAsioBufferSizeChange:
3028
//printf("kAsioBufferSizeChange \n");
3031
case kAsioResetRequest:
3032
// defer the task and perform the reset of the driver during the next "safe" situation
3033
// You cannot reset the driver right now, as this code is called from the driver.
3034
// Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
3035
// Afterwards you initialize the driver again.
3037
/*FIXME: commented the next line out */
3038
//asioDriverInfo.stopped; // In this sample the processing will just stop
3042
case kAsioResyncRequest:
3043
// This informs the application, that the driver encountered some non fatal data loss.
3044
// It is used for synchronization purposes of different media.
3045
// Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
3046
// Windows Multimedia system, which could loose data because the Mutex was hold too long
3047
// by another thread.
3048
// However a driver can issue it in other situations, too.
3052
case kAsioLatenciesChanged:
3053
// This will inform the host application that the drivers were latencies changed.
3054
// Beware, it this does not mean that the buffer sizes have changed!
3055
// You might need to update internal delay data.
3057
//printf("kAsioLatenciesChanged \n");
3060
case kAsioEngineVersion:
3061
// return the supported ASIO version of the host application
3062
// If a host applications does not implement this selector, ASIO 1.0 is assumed
3067
case kAsioSupportsTimeInfo:
3068
// informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
3070
// For compatibility with ASIO 1.0 drivers the host application should always support
3071
// the "old" bufferSwitch method, too.
3075
case kAsioSupportsTimeCode:
3076
// informs the driver wether application is interested in time code info.
3077
// If an application does not need to know about time code, the driver has less work
3087
static PaError StartStream (PaStream *s)
3089
PaError result = paNoError;
3090
PaAsioStream *stream = (PaAsioStream*) s;
3091
PaAsioStreamBlockingState *blockingState = stream->blockingState;
3092
ASIOError asioError;
3094
if (stream->outputChannelCount > 0) {
3095
ZeroOutputBuffers (stream, 0);
3096
ZeroOutputBuffers (stream, 1);
3099
PaUtil_ResetBufferProcessor (&stream->bufferProcessor);
3100
stream->stopProcessing = false;
3101
stream->zeroOutput = false;
3103
/* Reentrancy counter initialisation */
3104
stream->reenterCount = -1;
3105
stream->reenterError = 0;
3107
stream->callbackFlags = 0;
3109
if (ResetEvent (stream->completedBuffersPlayedEvent) == 0) {
3110
result = paUnanticipatedHostError;
3111
PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
3115
/* Using blocking i/o interface... */
3116
if (blockingState) {
3117
/* Reset blocking i/o buffer processor. */
3118
PaUtil_ResetBufferProcessor (&blockingState->bufferProcessor);
3120
/* If we're about to process some input data. */
3121
if (stream->inputChannelCount) {
3122
/* Reset callback-ReadStream sync event. */
3123
if (ResetEvent (blockingState->readFramesReadyEvent) == 0) {
3124
result = paUnanticipatedHostError;
3125
PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
3128
/* Flush blocking i/o ring buffer. */
3129
PaUtil_FlushRingBuffer (&blockingState->readRingBuffer);
3130
(*blockingState->bufferProcessor.inputZeroer) (blockingState->readRingBuffer.buffer, 1, blockingState->bufferProcessor.inputChannelCount * blockingState->readRingBuffer.bufferSize);
3133
/* If we're about to process some output data. */
3134
if (stream->outputChannelCount) {
3135
/* Reset callback-WriteStream sync event. */
3136
if (ResetEvent (blockingState->writeBuffersReadyEvent) == 0) {
3137
result = paUnanticipatedHostError;
3138
PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
3141
/* Flush blocking i/o ring buffer. */
3142
PaUtil_FlushRingBuffer (&blockingState->writeRingBuffer);
3143
(*blockingState->bufferProcessor.outputZeroer) (blockingState->writeRingBuffer.buffer, 1, blockingState->bufferProcessor.outputChannelCount * blockingState->writeRingBuffer.bufferSize);
3145
/* Initialize the output ring buffer to "silence". */
3146
PaUtil_AdvanceRingBufferWriteIndex (&blockingState->writeRingBuffer, blockingState->writeRingBufferInitialFrames);
3149
/* Clear requested frames / buffers count. */
3150
blockingState->writeBuffersRequested = 0;
3151
blockingState->readFramesRequested = 0;
3152
blockingState->writeBuffersRequestedFlag = FALSE;
3153
blockingState->readFramesRequestedFlag = FALSE;
3154
blockingState->outputUnderflowFlag = FALSE;
3155
blockingState->inputOverflowFlag = FALSE;
3156
blockingState->stopFlag = FALSE;
3160
if (result == paNoError) {
3161
assert (theAsioStream == stream); /* theAsioStream should be set correctly in OpenStream */
3163
/* initialize these variables before the callback has a chance to be invoked */
3164
stream->isStopped = 0;
3165
stream->isActive = 1;
3166
stream->streamFinishedCallbackCalled = false;
3168
asioError = ASIOStart();
3170
if (asioError != ASE_OK) {
3171
stream->isStopped = 1;
3172
stream->isActive = 0;
3174
result = paUnanticipatedHostError;
3175
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3182
static void EnsureCallbackHasCompleted (PaAsioStream *stream)
3184
// make sure that the callback is not still in-flight after ASIOStop()
3185
// returns. This has been observed to happen on the Hoontech DSP24 for
3187
int count = 2000; // only wait for 2 seconds, rather than hanging.
3189
while (stream->reenterCount != -1 && count > 0) {
3195
static PaError StopStream (PaStream *s)
3197
PaError result = paNoError;
3198
PaAsioStream *stream = (PaAsioStream*) s;
3199
PaAsioStreamBlockingState *blockingState = stream->blockingState;
3200
ASIOError asioError;
3202
if (stream->isActive) {
3203
/* If blocking i/o output is in use */
3204
if (blockingState && stream->outputChannelCount) {
3205
/* Request the whole output buffer to be available. */
3206
blockingState->writeBuffersRequested = blockingState->writeRingBuffer.bufferSize;
3207
/* Signalize that additional buffers are need. */
3208
blockingState->writeBuffersRequestedFlag = TRUE;
3209
/* Set flag to indicate the playback is to be stopped. */
3210
blockingState->stopFlag = TRUE;
3212
/* Wait until requested number of buffers has been freed. Time
3213
out after twice the blocking i/o ouput buffer could have
3215
DWORD timeout = (DWORD) (2 * blockingState->writeRingBuffer.bufferSize * 1000
3216
/ stream->streamRepresentation.streamInfo.sampleRate);
3217
DWORD waitResult = WaitForSingleObject (blockingState->writeBuffersReadyEvent, timeout);
3219
/* If something seriously went wrong... */
3220
if (waitResult == WAIT_FAILED) {
3221
PA_DEBUG ( ("WaitForSingleObject() failed in StopStream()\n"));
3222
result = paUnanticipatedHostError;
3223
PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
3224
} else if (waitResult == WAIT_TIMEOUT) {
3225
PA_DEBUG ( ("WaitForSingleObject() timed out in StopStream()\n"));
3226
result = paTimedOut;
3230
stream->stopProcessing = true;
3232
/* wait for the stream to finish playing out enqueued buffers.
3233
timeout after four times the stream latency.
3235
@todo should use a better time out value - if the user buffer
3236
length is longer than the asio buffer size then that should
3237
be taken into account.
3239
if (WaitForSingleObject (stream->completedBuffersPlayedEvent,
3240
(DWORD) (stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.))
3242
PA_DEBUG ( ("WaitForSingleObject() timed out in StopStream()\n"));
3246
asioError = ASIOStop();
3248
if (asioError == ASE_OK) {
3249
EnsureCallbackHasCompleted (stream);
3251
result = paUnanticipatedHostError;
3252
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3255
stream->isStopped = 1;
3256
stream->isActive = 0;
3258
if (!stream->streamFinishedCallbackCalled) {
3259
if (stream->streamRepresentation.streamFinishedCallback != 0)
3260
stream->streamRepresentation.streamFinishedCallback (stream->streamRepresentation.userData);
3266
static PaError AbortStream (PaStream *s)
3268
PaError result = paNoError;
3269
PaAsioStream *stream = (PaAsioStream*) s;
3270
ASIOError asioError;
3272
stream->zeroOutput = true;
3274
asioError = ASIOStop();
3276
if (asioError == ASE_OK) {
3277
EnsureCallbackHasCompleted (stream);
3279
result = paUnanticipatedHostError;
3280
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3283
stream->isStopped = 1;
3284
stream->isActive = 0;
3286
if (!stream->streamFinishedCallbackCalled) {
3287
if (stream->streamRepresentation.streamFinishedCallback != 0)
3288
stream->streamRepresentation.streamFinishedCallback (stream->streamRepresentation.userData);
3295
static PaError IsStreamStopped (PaStream *s)
3297
PaAsioStream *stream = (PaAsioStream*) s;
3299
return stream->isStopped;
3303
static PaError IsStreamActive (PaStream *s)
3305
PaAsioStream *stream = (PaAsioStream*) s;
3307
return stream->isActive;
3311
static PaTime GetStreamTime (PaStream *s)
3313
(void) s; /* unused parameter */
3314
return (double) timeGetTime() * .001;
3318
static double GetStreamCpuLoad (PaStream* s)
3320
PaAsioStream *stream = (PaAsioStream*) s;
3322
return PaUtil_GetCpuLoad (&stream->cpuLoadMeasurer);
3327
As separate stream interfaces are used for blocking and callback
3328
streams, the following functions can be guaranteed to only be called
3329
for blocking streams.
3332
static PaError ReadStream (PaStream *s ,
3334
unsigned long frames)
3336
PaError result = paNoError; /* Initial return value. */
3337
PaAsioStream *stream = (PaAsioStream*) s; /* The PA ASIO stream. */
3339
/* Pointer to the blocking i/o data struct. */
3340
PaAsioStreamBlockingState *blockingState = stream->blockingState;
3342
/* Get blocking i/o buffer processor and ring buffer pointers. */
3343
PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
3344
PaUtilRingBuffer *pRb = &blockingState->readRingBuffer;
3346
/* Ring buffer segment(s) used for writing. */
3347
void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
3348
void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
3350
/* Number of frames per ring buffer segment. */
3351
long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
3352
long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
3354
/* Get number of frames to be processed per data block. */
3355
unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer;
3356
/* Actual number of frames that has been copied into the ring buffer. */
3357
unsigned long lFramesCopied = 0;
3358
/* The number of remaining unprocessed dtat frames. */
3359
unsigned long lFramesRemaining = frames;
3361
/* Copy the input argument to avoid pointer increment! */
3362
const void *userBuffer;
3363
unsigned int i; /* Just a counter. */
3365
/* About the time, needed to process 8 data blocks. */
3366
DWORD timeout = (DWORD) (8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate);
3367
DWORD waitResult = 0;
3370
/* Check if the stream is still available ready to gather new data. */
3371
if (blockingState->stopFlag || !stream->isActive) {
3372
PA_DEBUG ( ("Warning! Stream no longer available for reading in ReadStream()\n"));
3373
result = paStreamIsStopped;
3377
/* If the stream is a input stream. */
3378
if (stream->inputChannelCount) {
3379
/* Prepare buffer access. */
3380
if (!pBp->userOutputIsInterleaved) {
3381
userBuffer = blockingState->readStreamBuffer;
3383
for (i = 0; i<pBp->inputChannelCount; ++i) {
3384
( (void**) userBuffer) [i] = ( (void**) buffer) [i];
3386
} /* Use the unchanged buffer. */
3388
userBuffer = buffer;
3391
do { /* Internal block processing for too large user data buffers. */
3392
/* Get the size of the current data block to be processed. */
3393
lFramesPerBlock = (lFramesPerBlock < lFramesRemaining)
3394
? lFramesPerBlock : lFramesRemaining;
3395
/* Use predefined block size for as long there are enough
3396
buffers available, thereafter reduce the processing block
3397
size to match the number of remaining buffers. So the final
3398
data block is processed although it may be incomplete. */
3400
/* If the available amount of data frames is insufficient. */
3401
if (PaUtil_GetRingBufferReadAvailable (pRb) < (long) lFramesPerBlock) {
3402
/* Make sure, the event isn't already set! */
3403
/* ResetEvent( blockingState->readFramesReadyEvent ); */
3405
/* Set the number of requested buffers. */
3406
blockingState->readFramesRequested = lFramesPerBlock;
3408
/* Signalize that additional buffers are need. */
3409
blockingState->readFramesRequestedFlag = TRUE;
3411
/* Wait until requested number of buffers has been freed. */
3412
waitResult = WaitForSingleObject (blockingState->readFramesReadyEvent, timeout);
3414
/* If something seriously went wrong... */
3415
if (waitResult == WAIT_FAILED) {
3416
PA_DEBUG ( ("WaitForSingleObject() failed in ReadStream()\n"));
3417
result = paUnanticipatedHostError;
3418
PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
3420
} else if (waitResult == WAIT_TIMEOUT) {
3421
PA_DEBUG ( ("WaitForSingleObject() timed out in ReadStream()\n"));
3423
/* If block processing has stopped, abort! */
3424
if (blockingState->stopFlag) {
3425
return result = paStreamIsStopped;
3428
/* If a timeout is encountered, give up eventually. */
3429
return result = paTimedOut;
3433
/* Now, the ring buffer contains the required amount of data
3435
(Therefor we don't need to check the return argument of
3436
PaUtil_GetRingBufferReadRegions(). ;-) )
3439
/* Retrieve pointer(s) to the ring buffer's current write
3440
position(s). If the first buffer segment is too small to
3441
store the requested number of bytes, an additional second
3442
segment is returned. Otherwise, i.e. if the first segment
3443
is large enough, the second segment's pointer will be NULL.
3445
PaUtil_GetRingBufferReadRegions (pRb ,
3447
&pRingBufferData1st,
3448
&lRingBufferSize1st,
3449
&pRingBufferData2nd,
3450
&lRingBufferSize2nd);
3452
/* Set number of frames to be copied from the ring buffer. */
3453
PaUtil_SetInputFrameCount (pBp, lRingBufferSize1st);
3454
/* Setup ring buffer access. */
3455
PaUtil_SetInterleavedInputChannels (pBp , /* Buffer processor. */
3456
0 , /* The first channel's index. */
3457
pRingBufferData1st, /* First ring buffer segment. */
3458
0); /* Use all available channels. */
3460
/* If a second ring buffer segment is required. */
3461
if (lRingBufferSize2nd) {
3462
/* Set number of frames to be copied from the ring buffer. */
3463
PaUtil_Set2ndInputFrameCount (pBp, lRingBufferSize2nd);
3464
/* Setup ring buffer access. */
3465
PaUtil_Set2ndInterleavedInputChannels (pBp , /* Buffer processor. */
3466
0 , /* The first channel's index. */
3467
pRingBufferData2nd, /* Second ring buffer segment. */
3468
0); /* Use all available channels. */
3471
/* Let the buffer processor handle "copy and conversion" and
3472
update the ring buffer indices manually. */
3473
lFramesCopied = PaUtil_CopyInput (pBp, &buffer, lFramesPerBlock);
3474
PaUtil_AdvanceRingBufferReadIndex (pRb, lFramesCopied);
3476
/* Decrease number of unprocessed frames. */
3477
lFramesRemaining -= lFramesCopied;
3479
} /* Continue with the next data chunk. */
3481
while (lFramesRemaining);
3484
/* If there has been an input overflow within the callback */
3485
if (blockingState->inputOverflowFlag) {
3486
blockingState->inputOverflowFlag = FALSE;
3488
/* Return the corresponding error code. */
3489
result = paInputOverflowed;
3492
} /* If this is not an input stream. */
3494
result = paCanNotReadFromAnOutputOnlyStream;
3500
static PaError WriteStream (PaStream *s ,
3502
unsigned long frames)
3504
PaError result = paNoError; /* Initial return value. */
3505
PaAsioStream *stream = (PaAsioStream*) s; /* The PA ASIO stream. */
3507
/* Pointer to the blocking i/o data struct. */
3508
PaAsioStreamBlockingState *blockingState = stream->blockingState;
3510
/* Get blocking i/o buffer processor and ring buffer pointers. */
3511
PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
3512
PaUtilRingBuffer *pRb = &blockingState->writeRingBuffer;
3514
/* Ring buffer segment(s) used for writing. */
3515
void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
3516
void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
3518
/* Number of frames per ring buffer segment. */
3519
long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
3520
long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
3522
/* Get number of frames to be processed per data block. */
3523
unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer;
3524
/* Actual number of frames that has been copied into the ring buffer. */
3525
unsigned long lFramesCopied = 0;
3526
/* The number of remaining unprocessed dtat frames. */
3527
unsigned long lFramesRemaining = frames;
3529
/* About the time, needed to process 8 data blocks. */
3530
DWORD timeout = (DWORD) (8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate);
3531
DWORD waitResult = 0;
3533
/* Copy the input argument to avoid pointer increment! */
3534
const void *userBuffer;
3535
unsigned int i; /* Just a counter. */
3538
/* Check if the stream ist still available ready to recieve new data. */
3539
if (blockingState->stopFlag || !stream->isActive) {
3540
PA_DEBUG ( ("Warning! Stream no longer available for writing in WriteStream()\n"));
3541
result = paStreamIsStopped;
3545
/* If the stream is a output stream. */
3546
if (stream->outputChannelCount) {
3547
/* Prepare buffer access. */
3548
if (!pBp->userOutputIsInterleaved) {
3549
userBuffer = blockingState->writeStreamBuffer;
3551
for (i = 0; i<pBp->outputChannelCount; ++i) {
3552
( (const void**) userBuffer) [i] = ( (const void**) buffer) [i];
3554
} /* Use the unchanged buffer. */
3556
userBuffer = buffer;
3560
do { /* Internal block processing for too large user data buffers. */
3561
/* Get the size of the current data block to be processed. */
3562
lFramesPerBlock = (lFramesPerBlock < lFramesRemaining)
3563
? lFramesPerBlock : lFramesRemaining;
3564
/* Use predefined block size for as long there are enough
3565
frames available, thereafter reduce the processing block
3566
size to match the number of remaining frames. So the final
3567
data block is processed although it may be incomplete. */
3569
/* If the available amount of buffers is insufficient. */
3570
if (PaUtil_GetRingBufferWriteAvailable (pRb) < (long) lFramesPerBlock) {
3571
/* Make sure, the event isn't already set! */
3572
/* ResetEvent( blockingState->writeBuffersReadyEvent ); */
3574
/* Set the number of requested buffers. */
3575
blockingState->writeBuffersRequested = lFramesPerBlock;
3577
/* Signalize that additional buffers are need. */
3578
blockingState->writeBuffersRequestedFlag = TRUE;
3580
/* Wait until requested number of buffers has been freed. */
3581
waitResult = WaitForSingleObject (blockingState->writeBuffersReadyEvent, timeout);
3583
/* If something seriously went wrong... */
3584
if (waitResult == WAIT_FAILED) {
3585
PA_DEBUG ( ("WaitForSingleObject() failed in WriteStream()\n"));
3586
result = paUnanticipatedHostError;
3587
PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
3589
} else if (waitResult == WAIT_TIMEOUT) {
3590
PA_DEBUG ( ("WaitForSingleObject() timed out in WriteStream()\n"));
3592
/* If block processing has stopped, abort! */
3593
if (blockingState->stopFlag) {
3594
return result = paStreamIsStopped;
3597
/* If a timeout is encountered, give up eventually. */
3598
return result = paTimedOut;
3602
/* Now, the ring buffer contains the required amount of free
3603
space to store the provided number of data frames.
3604
(Therefor we don't need to check the return argument of
3605
PaUtil_GetRingBufferWriteRegions(). ;-) )
3608
/* Retrieve pointer(s) to the ring buffer's current write
3609
position(s). If the first buffer segment is too small to
3610
store the requested number of bytes, an additional second
3611
segment is returned. Otherwise, i.e. if the first segment
3612
is large enough, the second segment's pointer will be NULL.
3614
PaUtil_GetRingBufferWriteRegions (pRb ,
3616
&pRingBufferData1st,
3617
&lRingBufferSize1st,
3618
&pRingBufferData2nd,
3619
&lRingBufferSize2nd);
3621
/* Set number of frames to be copied to the ring buffer. */
3622
PaUtil_SetOutputFrameCount (pBp, lRingBufferSize1st);
3623
/* Setup ring buffer access. */
3624
PaUtil_SetInterleavedOutputChannels (pBp , /* Buffer processor. */
3625
0 , /* The first channel's index. */
3626
pRingBufferData1st, /* First ring buffer segment. */
3627
0); /* Use all available channels. */
3629
/* If a second ring buffer segment is required. */
3630
if (lRingBufferSize2nd) {
3631
/* Set number of frames to be copied to the ring buffer. */
3632
PaUtil_Set2ndOutputFrameCount (pBp, lRingBufferSize2nd);
3633
/* Setup ring buffer access. */
3634
PaUtil_Set2ndInterleavedOutputChannels (pBp , /* Buffer processor. */
3635
0 , /* The first channel's index. */
3636
pRingBufferData2nd, /* Second ring buffer segment. */
3637
0); /* Use all available channels. */
3640
/* Let the buffer processor handle "copy and conversion" and
3641
update the ring buffer indices manually. */
3642
lFramesCopied = PaUtil_CopyOutput (pBp, &userBuffer, lFramesPerBlock);
3643
PaUtil_AdvanceRingBufferWriteIndex (pRb, lFramesCopied);
3645
/* Decrease number of unprocessed frames. */
3646
lFramesRemaining -= lFramesCopied;
3648
} /* Continue with the next data chunk. */
3650
while (lFramesRemaining);
3653
/* If there has been an output underflow within the callback */
3654
if (blockingState->outputUnderflowFlag) {
3655
blockingState->outputUnderflowFlag = FALSE;
3657
/* Return the corresponding error code. */
3658
result = paOutputUnderflowed;
3661
} /* If this is not an output stream. */
3663
result = paCanNotWriteToAnInputOnlyStream;
3670
static signed long GetStreamReadAvailable (PaStream* s)
3672
PaAsioStream *stream = (PaAsioStream*) s;
3674
/* Call buffer utility routine to get the number of available frames. */
3675
return PaUtil_GetRingBufferReadAvailable (&stream->blockingState->readRingBuffer);
3679
static signed long GetStreamWriteAvailable (PaStream* s)
3681
PaAsioStream *stream = (PaAsioStream*) s;
3683
/* Call buffer utility routine to get the number of empty buffers. */
3684
return PaUtil_GetRingBufferWriteAvailable (&stream->blockingState->writeRingBuffer);
3688
/* This routine will be called by the PortAudio engine when audio is needed.
3689
** It may called at interrupt level on some machines so don't do anything
3690
** that could mess up the system like calling malloc() or free().
3692
static int BlockingIoPaCallback (const void *inputBuffer ,
3693
void *outputBuffer ,
3694
unsigned long framesPerBuffer,
3695
const PaStreamCallbackTimeInfo *timeInfo ,
3696
PaStreamCallbackFlags statusFlags ,
3699
PaError result = paNoError; /* Initial return value. */
3700
PaAsioStream *stream = * (PaAsioStream**) userData; /* The PA ASIO stream. */
3701
PaAsioStreamBlockingState *blockingState = stream->blockingState; /* Persume blockingState is valid, otherwise the callback wouldn't be running. */
3703
/* Get a pointer to the stream's blocking i/o buffer processor. */
3704
PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
3705
PaUtilRingBuffer *pRb = NULL;
3707
/* If output data has been requested. */
3708
if (stream->outputChannelCount) {
3709
/* If the callback input argument signalizes a output underflow,
3710
make sure the WriteStream() function knows about it, too! */
3711
if (statusFlags & paOutputUnderflowed) {
3712
blockingState->outputUnderflowFlag = TRUE;
3715
/* Access the corresponding ring buffer. */
3716
pRb = &blockingState->writeRingBuffer;
3718
/* If the blocking i/o buffer contains enough output data, */
3719
if (PaUtil_GetRingBufferReadAvailable (pRb) >= (long) framesPerBuffer) {
3720
/* Extract the requested data from the ring buffer. */
3721
PaUtil_ReadRingBuffer (pRb, outputBuffer, framesPerBuffer);
3722
} else { /* If no output data is available :-( */
3723
/* Signalize a write-buffer underflow. */
3724
blockingState->outputUnderflowFlag = TRUE;
3726
/* Fill the output buffer with silence. */
3727
(*pBp->outputZeroer) (outputBuffer, 1, pBp->outputChannelCount * framesPerBuffer);
3729
/* If playback is to be stopped */
3730
if (blockingState->stopFlag && PaUtil_GetRingBufferReadAvailable (pRb) < (long) framesPerBuffer) {
3731
/* Extract all the remaining data from the ring buffer,
3732
whether it is a complete data block or not. */
3733
PaUtil_ReadRingBuffer (pRb, outputBuffer, PaUtil_GetRingBufferReadAvailable (pRb));
3737
/* Set blocking i/o event? */
3738
if (blockingState->writeBuffersRequestedFlag && PaUtil_GetRingBufferWriteAvailable (pRb) >= (long) blockingState->writeBuffersRequested) {
3739
/* Reset buffer request. */
3740
blockingState->writeBuffersRequestedFlag = FALSE;
3741
blockingState->writeBuffersRequested = 0;
3742
/* Signalize that requested buffers are ready. */
3743
SetEvent (blockingState->writeBuffersReadyEvent);
3744
/* What do we do if SetEvent() returns zero, i.e. the event
3745
could not be set? How to return errors from within the
3746
callback? - S.Fischer */
3750
/* If input data has been supplied. */
3751
if (stream->inputChannelCount) {
3752
/* If the callback input argument signalizes a input overflow,
3753
make sure the ReadStream() function knows about it, too! */
3754
if (statusFlags & paInputOverflowed) {
3755
blockingState->inputOverflowFlag = TRUE;
3758
/* Access the corresponding ring buffer. */
3759
pRb = &blockingState->readRingBuffer;
3761
/* If the blocking i/o buffer contains not enough input buffers */
3762
if (PaUtil_GetRingBufferWriteAvailable (pRb) < (long) framesPerBuffer) {
3763
/* Signalize a read-buffer overflow. */
3764
blockingState->inputOverflowFlag = TRUE;
3766
/* Remove some old data frames from the buffer. */
3767
PaUtil_AdvanceRingBufferReadIndex (pRb, framesPerBuffer);
3770
/* Insert the current input data into the ring buffer. */
3771
PaUtil_WriteRingBuffer (pRb, inputBuffer, framesPerBuffer);
3773
/* Set blocking i/o event? */
3774
if (blockingState->readFramesRequestedFlag && PaUtil_GetRingBufferReadAvailable (pRb) >= (long) blockingState->readFramesRequested) {
3775
/* Reset buffer request. */
3776
blockingState->readFramesRequestedFlag = FALSE;
3777
blockingState->readFramesRequested = 0;
3778
/* Signalize that requested buffers are ready. */
3779
SetEvent (blockingState->readFramesReadyEvent);
3780
/* What do we do if SetEvent() returns zero, i.e. the event
3781
could not be set? How to return errors from within the
3782
callback? - S.Fischer */
3783
/** @todo report an error with PA_DEBUG */
3791
PaError PaAsio_ShowControlPanel (PaDeviceIndex device, void* systemSpecific)
3793
PaError result = paNoError;
3794
PaUtilHostApiRepresentation *hostApi;
3795
PaDeviceIndex hostApiDevice;
3796
ASIODriverInfo asioDriverInfo;
3797
ASIOError asioError;
3798
int asioIsInitialized = 0;
3799
PaAsioHostApiRepresentation *asioHostApi;
3800
PaAsioDeviceInfo *asioDeviceInfo;
3803
result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
3805
if (result != paNoError)
3808
result = PaUtil_DeviceIndexToHostApiDeviceIndex (&hostApiDevice, device, hostApi);
3810
if (result != paNoError)
3814
In theory we could proceed if the currently open device was the same
3815
one for which the control panel was requested, however because the
3816
window pointer is not available until this function is called we
3817
currently need to call ASIOInit() again here, which of course can't be
3818
done safely while a stream is open.
3821
asioHostApi = (PaAsioHostApiRepresentation*) hostApi;
3823
if (asioHostApi->openAsioDeviceIndex != paNoDevice) {
3824
result = paDeviceUnavailable;
3828
asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[hostApiDevice];
3830
/* See notes about CoInitialize(0) in LoadAsioDriver(). */
3833
if (!asioHostApi->asioDrivers->loadDriver (const_cast<char*> (asioDeviceInfo->commonDeviceInfo.name))) {
3834
result = paUnanticipatedHostError;
3839
memset (&asioDriverInfo, 0, sizeof (ASIODriverInfo));
3840
asioDriverInfo.asioVersion = 2;
3841
asioDriverInfo.sysRef = systemSpecific;
3842
asioError = ASIOInit (&asioDriverInfo);
3844
if (asioError != ASE_OK) {
3845
result = paUnanticipatedHostError;
3846
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3849
asioIsInitialized = 1;
3852
PA_DEBUG ( ("PaAsio_ShowControlPanel: ASIOInit(): %s\n", PaAsio_GetAsioErrorText (asioError)));
3853
PA_DEBUG ( ("asioVersion: ASIOInit(): %ld\n", asioDriverInfo.asioVersion));
3854
PA_DEBUG ( ("driverVersion: ASIOInit(): %ld\n", asioDriverInfo.driverVersion));
3855
PA_DEBUG ( ("Name: ASIOInit(): %s\n", asioDriverInfo.name));
3856
PA_DEBUG ( ("ErrorMessage: ASIOInit(): %s\n", asioDriverInfo.errorMessage));
3858
asioError = ASIOControlPanel();
3860
if (asioError != ASE_OK) {
3861
PA_DEBUG ( ("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText (asioError)));
3862
result = paUnanticipatedHostError;
3863
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3867
PA_DEBUG ( ("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText (asioError)));
3869
asioError = ASIOExit();
3871
if (asioError != ASE_OK) {
3872
result = paUnanticipatedHostError;
3873
PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3874
asioIsInitialized = 0;
3879
PA_DEBUG ( ("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText (asioError)));
3885
if (asioIsInitialized) {
3895
PaError PaAsio_GetInputChannelName (PaDeviceIndex device, int channelIndex,
3896
const char** channelName)
3898
PaError result = paNoError;
3899
PaUtilHostApiRepresentation *hostApi;
3900
PaDeviceIndex hostApiDevice;
3901
PaAsioDeviceInfo *asioDeviceInfo;
3904
result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
3906
if (result != paNoError)
3909
result = PaUtil_DeviceIndexToHostApiDeviceIndex (&hostApiDevice, device, hostApi);
3911
if (result != paNoError)
3914
asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[hostApiDevice];
3916
if (channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxInputChannels) {
3917
result = paInvalidChannelCount;
3921
*channelName = asioDeviceInfo->asioChannelInfos[channelIndex].name;
3930
PaError PaAsio_GetOutputChannelName (PaDeviceIndex device, int channelIndex,
3931
const char** channelName)
3933
PaError result = paNoError;
3934
PaUtilHostApiRepresentation *hostApi;
3935
PaDeviceIndex hostApiDevice;
3936
PaAsioDeviceInfo *asioDeviceInfo;
3939
result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
3941
if (result != paNoError)
3944
result = PaUtil_DeviceIndexToHostApiDeviceIndex (&hostApiDevice, device, hostApi);
3946
if (result != paNoError)
3949
asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[hostApiDevice];
3951
if (channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxOutputChannels) {
3952
result = paInvalidChannelCount;
3956
*channelName = asioDeviceInfo->asioChannelInfos[
3957
asioDeviceInfo->commonDeviceInfo.maxInputChannels + channelIndex].name;
3966
/* NOTE: the following functions are ASIO-stream specific, and are called directly
3967
by client code. We need to check for many more error conditions here because
3968
we don't have the benefit of pa_front.c's parameter checking.
3971
static PaError GetAsioStreamPointer (PaAsioStream **stream, PaStream *s)
3974
PaUtilHostApiRepresentation *hostApi;
3975
PaAsioHostApiRepresentation *asioHostApi;
3977
result = PaUtil_ValidateStreamPointer (s);
3979
if (result != paNoError)
3982
result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
3984
if (result != paNoError)
3987
asioHostApi = (PaAsioHostApiRepresentation*) hostApi;
3989
if (PA_STREAM_REP (s)->streamInterface == &asioHostApi->callbackStreamInterface
3990
|| PA_STREAM_REP (s)->streamInterface == &asioHostApi->blockingStreamInterface) {
3991
/* s is an ASIO stream */
3992
*stream = (PaAsioStream *) s;
3995
return paIncompatibleStreamHostApi;
4000
PaError PaAsio_SetStreamSampleRate (PaStream* s, double sampleRate)
4002
PaAsioStream *stream;
4003
PaError result = GetAsioStreamPointer (&stream, s);
4005
if (result != paNoError)
4008
if (stream != theAsioStream)
4009
return paBadStreamPtr;
4011
return ValidateAndSetSampleRate (sampleRate);