~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to sflphone-common/libs/pjproject/third_party/portaudio/src/hostapi/asio/pa_asio.cpp

  • Committer: Package Import Robot
  • Author(s): Francois Marier
  • Date: 2011-11-25 13:24:12 UTC
  • mfrom: (4.1.10 sid)
  • Revision ID: package-import@ubuntu.com-20111125132412-dc4qvhyosk74cd42
Tags: 1.0.1-4
Don't assume that arch:all packages will get built (closes: #649726)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * $Id: pa_asio.cpp 1416 2009-06-16 16:12:41Z rossb $
3
 
 * Portable Audio I/O Library for ASIO Drivers
4
 
 *
5
 
 * Author: Stephane Letz
6
 
 * Based on the Open Source API proposed by Ross Bencina
7
 
 * Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina
8
 
 * Blocking i/o implementation by Sven Fischer, Institute of Hearing
9
 
 * Technology and Audiology (www.hoertechnik-audiologie.de)
10
 
 *
11
 
 * Permission is hereby granted, free of charge, to any person obtaining
12
 
 * a copy of this software and associated documentation files
13
 
 * (the "Software"), to deal in the Software without restriction,
14
 
 * including without limitation the rights to use, copy, modify, merge,
15
 
 * publish, distribute, sublicense, and/or sell copies of the Software,
16
 
 * and to permit persons to whom the Software is furnished to do so,
17
 
 * subject to the following conditions:
18
 
 *
19
 
 * The above copyright notice and this permission notice shall be
20
 
 * included in all copies or substantial portions of the Software.
21
 
 *
22
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25
 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
26
 
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27
 
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
 
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
 
 */
30
 
 
31
 
/*
32
 
 * The text above constitutes the entire PortAudio license; however,
33
 
 * the PortAudio community also makes the following non-binding requests:
34
 
 *
35
 
 * Any person wishing to distribute modifications to the Software is
36
 
 * requested to send the modifications to the original developer so that
37
 
 * they can be incorporated into the canonical version. It is also
38
 
 * requested that these non-binding requests be included along with the
39
 
 * license above.
40
 
 */
41
 
 
42
 
/* Modification History
43
 
 
44
 
        08-03-01 First version : Stephane Letz
45
 
        08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk
46
 
        08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz
47
 
        08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz
48
 
        08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil
49
 
        08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when
50
 
                 the stream is stopped : Stephane Letz
51
 
        08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when
52
 
                 the stream is stopped : Stephane Letz
53
 
        10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that
54
 
                 respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz
55
 
        10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz
56
 
        10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil
57
 
        10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk
58
 
        10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz
59
 
        11-06-01 Rename functions : Stephane Letz
60
 
        11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz
61
 
        11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk
62
 
        01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly :  Stephane Letz
63
 
        02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz
64
 
        19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz
65
 
        09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz
66
 
        12-04-02 Add Mac includes for <Devices.h> and <Timer.h> : Phil Burk
67
 
        13-04-02 Removes another compiler warning : Stephane Letz
68
 
        30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz
69
 
        12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina
70
 
        18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B.
71
 
        21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina
72
 
        ** NOTE  maintanance history is now stored in CVS **
73
 
*/
74
 
 
75
 
/** @file
76
 
    @ingroup hostapi_src
77
 
 
78
 
    Note that specific support for paInputUnderflow, paOutputOverflow and
79
 
    paNeverDropInput is not necessary or possible with this driver due to the
80
 
    synchronous full duplex double-buffered architecture of ASIO.
81
 
 
82
 
    @todo implement host api specific extension to set i/o buffer sizes in frames
83
 
 
84
 
    @todo review ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
85
 
 
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.
88
 
 
89
 
    @todo implement IsFormatSupported
90
 
 
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
95
 
            and see what happens.
96
 
 
97
 
    @todo rigorously check asio return codes and convert to pa error codes
98
 
 
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.
103
 
 
104
 
    @todo investigate whether the asio processNow flag needs to be honoured
105
 
 
106
 
    @todo handle asioMessages() callbacks in a useful way, or at least document
107
 
            what cases we don't handle.
108
 
 
109
 
    @todo miscellaneous other FIXMEs
110
 
 
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
116
 
        must be closed).
117
 
*/
118
 
 
119
 
 
120
 
 
121
 
#include <stdio.h>
122
 
#include <assert.h>
123
 
#include <string.h>
124
 
//#include <values.h>
125
 
#include <new>
126
 
 
127
 
#include <windows.h>
128
 
#include <mmsystem.h>
129
 
 
130
 
#include "portaudio.h"
131
 
#include "pa_asio.h"
132
 
#include "pa_util.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"
140
 
 
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.
145
 
*/
146
 
#ifndef WIN32
147
 
#define WIN32
148
 
#endif
149
 
 
150
 
#include "asiosys.h"
151
 
#include "asio.h"
152
 
#include "asiodrivers.h"
153
 
#include "iasiothiscallresolver.h"
154
 
 
155
 
/*
156
 
#if MAC
157
 
#include <Devices.h>
158
 
#include <Timer.h>
159
 
#include <Math64.h>
160
 
#else
161
 
*/
162
 
/*
163
 
#include <math.h>
164
 
#include <windows.h>
165
 
#include <mmsystem.h>
166
 
*/
167
 
/*
168
 
#endif
169
 
*/
170
 
 
171
 
 
172
 
/* external reference to ASIO SDK's asioDrivers.
173
 
 
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.
178
 
 
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.
182
 
*/
183
 
extern AsioDrivers* asioDrivers;
184
 
 
185
 
 
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)
189
 
 
190
 
 
191
 
/* prototypes for functions declared in this file */
192
 
 
193
 
extern "C" PaError PaAsio_Initialize (PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex);
194
 
static void Terminate (struct PaUtilHostApiRepresentation *hostApi);
195
 
static PaError OpenStream (struct PaUtilHostApiRepresentation *hostApi,
196
 
                           PaStream** s,
197
 
                           const PaStreamParameters *inputParameters,
198
 
                           const PaStreamParameters *outputParameters,
199
 
                           double sampleRate,
200
 
                           unsigned long framesPerBuffer,
201
 
                           PaStreamFlags streamFlags,
202
 
                           PaStreamCallback *streamCallback,
203
 
                           void *userData);
204
 
static PaError IsFormatSupported (struct PaUtilHostApiRepresentation *hostApi,
205
 
                                  const PaStreamParameters *inputParameters,
206
 
                                  const PaStreamParameters *outputParameters,
207
 
                                  double sampleRate);
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);
220
 
 
221
 
/* Blocking i/o callback function. */
222
 
static int BlockingIoPaCallback (const void                     *inputBuffer    ,
223
 
                                 void                     *outputBuffer   ,
224
 
                                 unsigned long             framesPerBuffer,
225
 
                                 const PaStreamCallbackTimeInfo *timeInfo       ,
226
 
                                 PaStreamCallbackFlags     statusFlags    ,
227
 
                                 void                     *userData);
228
 
 
229
 
/* our ASIO callback functions */
230
 
 
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);
235
 
 
236
 
static ASIOCallbacks asioCallbacks_ = { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo };
237
 
 
238
 
 
239
 
#define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \
240
 
    PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText )
241
 
 
242
 
 
243
 
static void PaAsio_SetLastSystemError (DWORD errorCode)
244
 
{
245
 
    LPVOID lpMsgBuf;
246
 
    FormatMessage (
247
 
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
248
 
        NULL,
249
 
        errorCode,
250
 
        MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
251
 
        (LPTSTR) &lpMsgBuf,
252
 
        0,
253
 
        NULL
254
 
    );
255
 
    PaUtil_SetLastHostErrorInfo (paASIO, errorCode, (const char*) lpMsgBuf);
256
 
    LocalFree (lpMsgBuf);
257
 
}
258
 
 
259
 
#define PA_ASIO_SET_LAST_SYSTEM_ERROR( errorCode ) \
260
 
    PaAsio_SetLastSystemError( errorCode )
261
 
 
262
 
 
263
 
static const char* PaAsio_GetAsioErrorText (ASIOError asioError)
264
 
{
265
 
    const char *result;
266
 
 
267
 
    switch (asioError) {
268
 
        case ASE_OK:
269
 
        case ASE_SUCCESS:
270
 
            result = "Success";
271
 
            break;
272
 
        case ASE_NotPresent:
273
 
            result = "Hardware input or output is not present or available";
274
 
            break;
275
 
        case ASE_HWMalfunction:
276
 
            result = "Hardware is malfunctioning";
277
 
            break;
278
 
        case ASE_InvalidParameter:
279
 
            result = "Input parameter invalid";
280
 
            break;
281
 
        case ASE_InvalidMode:
282
 
            result = "Hardware is in a bad mode or used in a bad mode";
283
 
            break;
284
 
        case ASE_SPNotAdvancing:
285
 
            result = "Hardware is not running when sample position is inquired";
286
 
            break;
287
 
        case ASE_NoClock:
288
 
            result = "Sample clock or rate cannot be determined or is not present";
289
 
            break;
290
 
        case ASE_NoMemory:
291
 
            result = "Not enough memory for completing the request";
292
 
            break;
293
 
        default:
294
 
            result = "Unknown ASIO error";
295
 
            break;
296
 
    }
297
 
 
298
 
    return result;
299
 
}
300
 
 
301
 
 
302
 
#define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \
303
 
    PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) )
304
 
 
305
 
 
306
 
 
307
 
 
308
 
// Atomic increment and decrement operations
309
 
#if MAC
310
 
/* need to be implemented on Mac */
311
 
inline long PaAsio_AtomicIncrement (volatile long* v)
312
 
{
313
 
    return ++ (*const_cast<long*> (v));
314
 
}
315
 
inline long PaAsio_AtomicDecrement (volatile long* v)
316
 
{
317
 
    return -- (*const_cast<long*> (v));
318
 
}
319
 
#elif WINDOWS
320
 
inline long PaAsio_AtomicIncrement (volatile long* v)
321
 
{
322
 
    return InterlockedIncrement (const_cast<long*> (v));
323
 
}
324
 
inline long PaAsio_AtomicDecrement (volatile long* v)
325
 
{
326
 
    return InterlockedDecrement (const_cast<long*> (v));
327
 
}
328
 
#endif
329
 
 
330
 
 
331
 
 
332
 
typedef struct PaAsioDriverInfo {
333
 
    ASIODriverInfo asioDriverInfo;
334
 
    long inputChannelCount, outputChannelCount;
335
 
    long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity;
336
 
    bool postOutput;
337
 
}
338
 
PaAsioDriverInfo;
339
 
 
340
 
 
341
 
/* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */
342
 
 
343
 
typedef struct {
344
 
    PaUtilHostApiRepresentation inheritedHostApiRep;
345
 
    PaUtilStreamInterface callbackStreamInterface;
346
 
    PaUtilStreamInterface blockingStreamInterface;
347
 
 
348
 
    PaUtilAllocationGroup *allocations;
349
 
 
350
 
    AsioDrivers *asioDrivers;
351
 
    void *systemSpecific;
352
 
 
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.
357
 
 
358
 
        openAsioDeviceIndex will be PaNoDevice if there is no device open
359
 
        and a valid pa_asio (not global) device index otherwise.
360
 
 
361
 
        openAsioDriverInfo is populated with the driver info for the
362
 
        currently open device (if any)
363
 
    */
364
 
    PaDeviceIndex openAsioDeviceIndex;
365
 
    PaAsioDriverInfo openAsioDriverInfo;
366
 
}
367
 
PaAsioHostApiRepresentation;
368
 
 
369
 
 
370
 
/*
371
 
    Retrieve <driverCount> driver names from ASIO, returned in a char**
372
 
    allocated in <group>.
373
 
*/
374
 
static char **GetAsioDriverNames (PaAsioHostApiRepresentation *asioHostApi, PaUtilAllocationGroup *group, long driverCount)
375
 
{
376
 
    char **result = 0;
377
 
    int i;
378
 
 
379
 
    result = (char**) PaUtil_GroupAllocateMemory (
380
 
                 group, sizeof (char*) * driverCount);
381
 
 
382
 
    if (!result)
383
 
        goto error;
384
 
 
385
 
    result[0] = (char*) PaUtil_GroupAllocateMemory (
386
 
                    group, 32 * driverCount);
387
 
 
388
 
    if (!result[0])
389
 
        goto error;
390
 
 
391
 
    for (i=0; i<driverCount; ++i)
392
 
        result[i] = result[0] + (32 * i);
393
 
 
394
 
    asioHostApi->asioDrivers->getDriverNames (result, driverCount);
395
 
 
396
 
error:
397
 
    return result;
398
 
}
399
 
 
400
 
 
401
 
static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat (ASIOSampleType type)
402
 
{
403
 
    switch (type) {
404
 
        case ASIOSTInt16MSB:
405
 
        case ASIOSTInt16LSB:
406
 
            return paInt16;
407
 
 
408
 
        case ASIOSTFloat32MSB:
409
 
        case ASIOSTFloat32LSB:
410
 
        case ASIOSTFloat64MSB:
411
 
        case ASIOSTFloat64LSB:
412
 
            return paFloat32;
413
 
 
414
 
        case ASIOSTInt32MSB:
415
 
        case ASIOSTInt32LSB:
416
 
        case ASIOSTInt32MSB16:
417
 
        case ASIOSTInt32LSB16:
418
 
        case ASIOSTInt32MSB18:
419
 
        case ASIOSTInt32MSB20:
420
 
        case ASIOSTInt32MSB24:
421
 
        case ASIOSTInt32LSB18:
422
 
        case ASIOSTInt32LSB20:
423
 
        case ASIOSTInt32LSB24:
424
 
            return paInt32;
425
 
 
426
 
        case ASIOSTInt24MSB:
427
 
        case ASIOSTInt24LSB:
428
 
            return paInt24;
429
 
 
430
 
        default:
431
 
            return paCustomFormat;
432
 
    }
433
 
}
434
 
 
435
 
void AsioSampleTypeLOG (ASIOSampleType type)
436
 
{
437
 
    switch (type) {
438
 
        case ASIOSTInt16MSB:
439
 
            PA_DEBUG ( ("ASIOSTInt16MSB\n"));
440
 
            break;
441
 
        case ASIOSTInt16LSB:
442
 
            PA_DEBUG ( ("ASIOSTInt16LSB\n"));
443
 
            break;
444
 
        case ASIOSTFloat32MSB:
445
 
            PA_DEBUG ( ("ASIOSTFloat32MSB\n"));
446
 
            break;
447
 
        case ASIOSTFloat32LSB:
448
 
            PA_DEBUG ( ("ASIOSTFloat32LSB\n"));
449
 
            break;
450
 
        case ASIOSTFloat64MSB:
451
 
            PA_DEBUG ( ("ASIOSTFloat64MSB\n"));
452
 
            break;
453
 
        case ASIOSTFloat64LSB:
454
 
            PA_DEBUG ( ("ASIOSTFloat64LSB\n"));
455
 
            break;
456
 
        case ASIOSTInt32MSB:
457
 
            PA_DEBUG ( ("ASIOSTInt32MSB\n"));
458
 
            break;
459
 
        case ASIOSTInt32LSB:
460
 
            PA_DEBUG ( ("ASIOSTInt32LSB\n"));
461
 
            break;
462
 
        case ASIOSTInt32MSB16:
463
 
            PA_DEBUG ( ("ASIOSTInt32MSB16\n"));
464
 
            break;
465
 
        case ASIOSTInt32LSB16:
466
 
            PA_DEBUG ( ("ASIOSTInt32LSB16\n"));
467
 
            break;
468
 
        case ASIOSTInt32MSB18:
469
 
            PA_DEBUG ( ("ASIOSTInt32MSB18\n"));
470
 
            break;
471
 
        case ASIOSTInt32MSB20:
472
 
            PA_DEBUG ( ("ASIOSTInt32MSB20\n"));
473
 
            break;
474
 
        case ASIOSTInt32MSB24:
475
 
            PA_DEBUG ( ("ASIOSTInt32MSB24\n"));
476
 
            break;
477
 
        case ASIOSTInt32LSB18:
478
 
            PA_DEBUG ( ("ASIOSTInt32LSB18\n"));
479
 
            break;
480
 
        case ASIOSTInt32LSB20:
481
 
            PA_DEBUG ( ("ASIOSTInt32LSB20\n"));
482
 
            break;
483
 
        case ASIOSTInt32LSB24:
484
 
            PA_DEBUG ( ("ASIOSTInt32LSB24\n"));
485
 
            break;
486
 
        case ASIOSTInt24MSB:
487
 
            PA_DEBUG ( ("ASIOSTInt24MSB\n"));
488
 
            break;
489
 
        case ASIOSTInt24LSB:
490
 
            PA_DEBUG ( ("ASIOSTInt24LSB\n"));
491
 
            break;
492
 
        default:
493
 
            PA_DEBUG ( ("Custom Format%d\n",type));
494
 
            break;
495
 
 
496
 
    }
497
 
}
498
 
 
499
 
static int BytesPerAsioSample (ASIOSampleType sampleType)
500
 
{
501
 
    switch (sampleType) {
502
 
        case ASIOSTInt16MSB:
503
 
        case ASIOSTInt16LSB:
504
 
            return 2;
505
 
 
506
 
        case ASIOSTFloat64MSB:
507
 
        case ASIOSTFloat64LSB:
508
 
            return 8;
509
 
 
510
 
        case ASIOSTFloat32MSB:
511
 
        case ASIOSTFloat32LSB:
512
 
        case ASIOSTInt32MSB:
513
 
        case ASIOSTInt32LSB:
514
 
        case ASIOSTInt32MSB16:
515
 
        case ASIOSTInt32LSB16:
516
 
        case ASIOSTInt32MSB18:
517
 
        case ASIOSTInt32MSB20:
518
 
        case ASIOSTInt32MSB24:
519
 
        case ASIOSTInt32LSB18:
520
 
        case ASIOSTInt32LSB20:
521
 
        case ASIOSTInt32LSB24:
522
 
            return 4;
523
 
 
524
 
        case ASIOSTInt24MSB:
525
 
        case ASIOSTInt24LSB:
526
 
            return 3;
527
 
 
528
 
        default:
529
 
            return 0;
530
 
    }
531
 
}
532
 
 
533
 
 
534
 
static void Swap16 (void *buffer, long shift, long count)
535
 
{
536
 
    unsigned short *p = (unsigned short*) buffer;
537
 
    unsigned short temp;
538
 
    (void) shift; /* unused parameter */
539
 
 
540
 
    while (count--) {
541
 
        temp = *p;
542
 
        *p++ = (unsigned short) ( (temp<<8) | (temp>>8));
543
 
    }
544
 
}
545
 
 
546
 
static void Swap24 (void *buffer, long shift, long count)
547
 
{
548
 
    unsigned char *p = (unsigned char*) buffer;
549
 
    unsigned char temp;
550
 
    (void) shift; /* unused parameter */
551
 
 
552
 
    while (count--) {
553
 
        temp = *p;
554
 
        *p = * (p+2);
555
 
        * (p+2) = temp;
556
 
        p += 3;
557
 
    }
558
 
}
559
 
 
560
 
#define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24));
561
 
 
562
 
static void Swap32 (void *buffer, long shift, long count)
563
 
{
564
 
    unsigned long *p = (unsigned long*) buffer;
565
 
    unsigned long temp;
566
 
    (void) shift; /* unused parameter */
567
 
 
568
 
    while (count--) {
569
 
        temp = *p;
570
 
        *p++ = PA_SWAP32_ (temp);
571
 
    }
572
 
}
573
 
 
574
 
static void SwapShiftLeft32 (void *buffer, long shift, long count)
575
 
{
576
 
    unsigned long *p = (unsigned long*) buffer;
577
 
    unsigned long temp;
578
 
 
579
 
    while (count--) {
580
 
        temp = *p;
581
 
        temp = PA_SWAP32_ (temp);
582
 
        *p++ = temp << shift;
583
 
    }
584
 
}
585
 
 
586
 
static void ShiftRightSwap32 (void *buffer, long shift, long count)
587
 
{
588
 
    unsigned long *p = (unsigned long*) buffer;
589
 
    unsigned long temp;
590
 
 
591
 
    while (count--) {
592
 
        temp = *p >> shift;
593
 
        *p++ = PA_SWAP32_ (temp);
594
 
    }
595
 
}
596
 
 
597
 
static void ShiftLeft32 (void *buffer, long shift, long count)
598
 
{
599
 
    unsigned long *p = (unsigned long*) buffer;
600
 
    unsigned long temp;
601
 
 
602
 
    while (count--) {
603
 
        temp = *p;
604
 
        *p++ = temp << shift;
605
 
    }
606
 
}
607
 
 
608
 
static void ShiftRight32 (void *buffer, long shift, long count)
609
 
{
610
 
    unsigned long *p = (unsigned long*) buffer;
611
 
    unsigned long temp;
612
 
 
613
 
    while (count--) {
614
 
        temp = *p;
615
 
        *p++ = temp >> shift;
616
 
    }
617
 
}
618
 
 
619
 
#define PA_SWAP_( x, y ) temp=x; x = y; y = temp;
620
 
 
621
 
static void Swap64ConvertFloat64ToFloat32 (void *buffer, long shift, long count)
622
 
{
623
 
    double *in = (double*) buffer;
624
 
    float *out = (float*) buffer;
625
 
    unsigned char *p;
626
 
    unsigned char temp;
627
 
    (void) shift; /* unused parameter */
628
 
 
629
 
    while (count--) {
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]);
635
 
 
636
 
        *out++ = (float) (*in++);
637
 
    }
638
 
}
639
 
 
640
 
static void ConvertFloat64ToFloat32 (void *buffer, long shift, long count)
641
 
{
642
 
    double *in = (double*) buffer;
643
 
    float *out = (float*) buffer;
644
 
    (void) shift; /* unused parameter */
645
 
 
646
 
    while (count--)
647
 
        *out++ = (float) (*in++);
648
 
}
649
 
 
650
 
static void ConvertFloat32ToFloat64Swap64 (void *buffer, long shift, long count)
651
 
{
652
 
    float *in = ( (float*) buffer) + (count-1);
653
 
    double *out = ( (double*) buffer) + (count-1);
654
 
    unsigned char *p;
655
 
    unsigned char temp;
656
 
    (void) shift; /* unused parameter */
657
 
 
658
 
    while (count--) {
659
 
        *out = *in--;
660
 
 
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]);
666
 
 
667
 
        out--;
668
 
    }
669
 
}
670
 
 
671
 
static void ConvertFloat32ToFloat64 (void *buffer, long shift, long count)
672
 
{
673
 
    float *in = ( (float*) buffer) + (count-1);
674
 
    double *out = ( (double*) buffer) + (count-1);
675
 
    (void) shift; /* unused parameter */
676
 
 
677
 
    while (count--)
678
 
        *out-- = *in--;
679
 
}
680
 
 
681
 
#ifdef MAC
682
 
#define PA_MSB_IS_NATIVE_
683
 
#undef PA_LSB_IS_NATIVE_
684
 
#endif
685
 
 
686
 
#ifdef WINDOWS
687
 
#undef PA_MSB_IS_NATIVE_
688
 
#define PA_LSB_IS_NATIVE_
689
 
#endif
690
 
 
691
 
typedef void PaAsioBufferConverter (void *, long, long);
692
 
 
693
 
static void SelectAsioToPaConverter (ASIOSampleType type, PaAsioBufferConverter **converter, long *shift)
694
 
{
695
 
    *shift = 0;
696
 
    *converter = 0;
697
 
 
698
 
    switch (type) {
699
 
        case ASIOSTInt16MSB:
700
 
            /* dest: paInt16, no conversion necessary, possible byte swap*/
701
 
#ifdef PA_LSB_IS_NATIVE_
702
 
            *converter = Swap16;
703
 
#endif
704
 
            break;
705
 
        case ASIOSTInt16LSB:
706
 
            /* dest: paInt16, no conversion necessary, possible byte swap*/
707
 
#ifdef PA_MSB_IS_NATIVE_
708
 
            *converter = Swap16;
709
 
#endif
710
 
            break;
711
 
        case ASIOSTFloat32MSB:
712
 
            /* dest: paFloat32, no conversion necessary, possible byte swap*/
713
 
#ifdef PA_LSB_IS_NATIVE_
714
 
            *converter = Swap32;
715
 
#endif
716
 
            break;
717
 
        case ASIOSTFloat32LSB:
718
 
            /* dest: paFloat32, no conversion necessary, possible byte swap*/
719
 
#ifdef PA_MSB_IS_NATIVE_
720
 
            *converter = Swap32;
721
 
#endif
722
 
            break;
723
 
        case ASIOSTFloat64MSB:
724
 
            /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
725
 
#ifdef PA_LSB_IS_NATIVE_
726
 
            *converter = Swap64ConvertFloat64ToFloat32;
727
 
#else
728
 
            *converter = ConvertFloat64ToFloat32;
729
 
#endif
730
 
            break;
731
 
        case ASIOSTFloat64LSB:
732
 
            /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
733
 
#ifdef PA_MSB_IS_NATIVE_
734
 
            *converter = Swap64ConvertFloat64ToFloat32;
735
 
#else
736
 
            *converter = ConvertFloat64ToFloat32;
737
 
#endif
738
 
            break;
739
 
        case ASIOSTInt32MSB:
740
 
            /* dest: paInt32, no conversion necessary, possible byte swap */
741
 
#ifdef PA_LSB_IS_NATIVE_
742
 
            *converter = Swap32;
743
 
#endif
744
 
            break;
745
 
        case ASIOSTInt32LSB:
746
 
            /* dest: paInt32, no conversion necessary, possible byte swap */
747
 
#ifdef PA_MSB_IS_NATIVE_
748
 
            *converter = Swap32;
749
 
#endif
750
 
            break;
751
 
        case ASIOSTInt32MSB16:
752
 
            /* dest: paInt32, 16 bit shift, possible byte swap */
753
 
#ifdef PA_LSB_IS_NATIVE_
754
 
            *converter = SwapShiftLeft32;
755
 
#else
756
 
            *converter = ShiftLeft32;
757
 
#endif
758
 
            *shift = 16;
759
 
            break;
760
 
        case ASIOSTInt32MSB18:
761
 
            /* dest: paInt32, 14 bit shift, possible byte swap */
762
 
#ifdef PA_LSB_IS_NATIVE_
763
 
            *converter = SwapShiftLeft32;
764
 
#else
765
 
            *converter = ShiftLeft32;
766
 
#endif
767
 
            *shift = 14;
768
 
            break;
769
 
        case ASIOSTInt32MSB20:
770
 
            /* dest: paInt32, 12 bit shift, possible byte swap */
771
 
#ifdef PA_LSB_IS_NATIVE_
772
 
            *converter = SwapShiftLeft32;
773
 
#else
774
 
            *converter = ShiftLeft32;
775
 
#endif
776
 
            *shift = 12;
777
 
            break;
778
 
        case ASIOSTInt32MSB24:
779
 
            /* dest: paInt32, 8 bit shift, possible byte swap */
780
 
#ifdef PA_LSB_IS_NATIVE_
781
 
            *converter = SwapShiftLeft32;
782
 
#else
783
 
            *converter = ShiftLeft32;
784
 
#endif
785
 
            *shift = 8;
786
 
            break;
787
 
        case ASIOSTInt32LSB16:
788
 
            /* dest: paInt32, 16 bit shift, possible byte swap */
789
 
#ifdef PA_MSB_IS_NATIVE_
790
 
            *converter = SwapShiftLeft32;
791
 
#else
792
 
            *converter = ShiftLeft32;
793
 
#endif
794
 
            *shift = 16;
795
 
            break;
796
 
        case ASIOSTInt32LSB18:
797
 
            /* dest: paInt32, 14 bit shift, possible byte swap */
798
 
#ifdef PA_MSB_IS_NATIVE_
799
 
            *converter = SwapShiftLeft32;
800
 
#else
801
 
            *converter = ShiftLeft32;
802
 
#endif
803
 
            *shift = 14;
804
 
            break;
805
 
        case ASIOSTInt32LSB20:
806
 
            /* dest: paInt32, 12 bit shift, possible byte swap */
807
 
#ifdef PA_MSB_IS_NATIVE_
808
 
            *converter = SwapShiftLeft32;
809
 
#else
810
 
            *converter = ShiftLeft32;
811
 
#endif
812
 
            *shift = 12;
813
 
            break;
814
 
        case ASIOSTInt32LSB24:
815
 
            /* dest: paInt32, 8 bit shift, possible byte swap */
816
 
#ifdef PA_MSB_IS_NATIVE_
817
 
            *converter = SwapShiftLeft32;
818
 
#else
819
 
            *converter = ShiftLeft32;
820
 
#endif
821
 
            *shift = 8;
822
 
            break;
823
 
        case ASIOSTInt24MSB:
824
 
            /* dest: paInt24, no conversion necessary, possible byte swap */
825
 
#ifdef PA_LSB_IS_NATIVE_
826
 
            *converter = Swap24;
827
 
#endif
828
 
            break;
829
 
        case ASIOSTInt24LSB:
830
 
            /* dest: paInt24, no conversion necessary, possible byte swap */
831
 
#ifdef PA_MSB_IS_NATIVE_
832
 
            *converter = Swap24;
833
 
#endif
834
 
            break;
835
 
    }
836
 
}
837
 
 
838
 
 
839
 
static void SelectPaToAsioConverter (ASIOSampleType type, PaAsioBufferConverter **converter, long *shift)
840
 
{
841
 
    *shift = 0;
842
 
    *converter = 0;
843
 
 
844
 
    switch (type) {
845
 
        case ASIOSTInt16MSB:
846
 
            /* src: paInt16, no conversion necessary, possible byte swap*/
847
 
#ifdef PA_LSB_IS_NATIVE_
848
 
            *converter = Swap16;
849
 
#endif
850
 
            break;
851
 
        case ASIOSTInt16LSB:
852
 
            /* src: paInt16, no conversion necessary, possible byte swap*/
853
 
#ifdef PA_MSB_IS_NATIVE_
854
 
            *converter = Swap16;
855
 
#endif
856
 
            break;
857
 
        case ASIOSTFloat32MSB:
858
 
            /* src: paFloat32, no conversion necessary, possible byte swap*/
859
 
#ifdef PA_LSB_IS_NATIVE_
860
 
            *converter = Swap32;
861
 
#endif
862
 
            break;
863
 
        case ASIOSTFloat32LSB:
864
 
            /* src: paFloat32, no conversion necessary, possible byte swap*/
865
 
#ifdef PA_MSB_IS_NATIVE_
866
 
            *converter = Swap32;
867
 
#endif
868
 
            break;
869
 
        case ASIOSTFloat64MSB:
870
 
            /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
871
 
#ifdef PA_LSB_IS_NATIVE_
872
 
            *converter = ConvertFloat32ToFloat64Swap64;
873
 
#else
874
 
            *converter = ConvertFloat32ToFloat64;
875
 
#endif
876
 
            break;
877
 
        case ASIOSTFloat64LSB:
878
 
            /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
879
 
#ifdef PA_MSB_IS_NATIVE_
880
 
            *converter = ConvertFloat32ToFloat64Swap64;
881
 
#else
882
 
            *converter = ConvertFloat32ToFloat64;
883
 
#endif
884
 
            break;
885
 
        case ASIOSTInt32MSB:
886
 
            /* src: paInt32, no conversion necessary, possible byte swap */
887
 
#ifdef PA_LSB_IS_NATIVE_
888
 
            *converter = Swap32;
889
 
#endif
890
 
            break;
891
 
        case ASIOSTInt32LSB:
892
 
            /* src: paInt32, no conversion necessary, possible byte swap */
893
 
#ifdef PA_MSB_IS_NATIVE_
894
 
            *converter = Swap32;
895
 
#endif
896
 
            break;
897
 
        case ASIOSTInt32MSB16:
898
 
            /* src: paInt32, 16 bit shift, possible byte swap */
899
 
#ifdef PA_LSB_IS_NATIVE_
900
 
            *converter = ShiftRightSwap32;
901
 
#else
902
 
            *converter = ShiftRight32;
903
 
#endif
904
 
            *shift = 16;
905
 
            break;
906
 
        case ASIOSTInt32MSB18:
907
 
            /* src: paInt32, 14 bit shift, possible byte swap */
908
 
#ifdef PA_LSB_IS_NATIVE_
909
 
            *converter = ShiftRightSwap32;
910
 
#else
911
 
            *converter = ShiftRight32;
912
 
#endif
913
 
            *shift = 14;
914
 
            break;
915
 
        case ASIOSTInt32MSB20:
916
 
            /* src: paInt32, 12 bit shift, possible byte swap */
917
 
#ifdef PA_LSB_IS_NATIVE_
918
 
            *converter = ShiftRightSwap32;
919
 
#else
920
 
            *converter = ShiftRight32;
921
 
#endif
922
 
            *shift = 12;
923
 
            break;
924
 
        case ASIOSTInt32MSB24:
925
 
            /* src: paInt32, 8 bit shift, possible byte swap */
926
 
#ifdef PA_LSB_IS_NATIVE_
927
 
            *converter = ShiftRightSwap32;
928
 
#else
929
 
            *converter = ShiftRight32;
930
 
#endif
931
 
            *shift = 8;
932
 
            break;
933
 
        case ASIOSTInt32LSB16:
934
 
            /* src: paInt32, 16 bit shift, possible byte swap */
935
 
#ifdef PA_MSB_IS_NATIVE_
936
 
            *converter = ShiftRightSwap32;
937
 
#else
938
 
            *converter = ShiftRight32;
939
 
#endif
940
 
            *shift = 16;
941
 
            break;
942
 
        case ASIOSTInt32LSB18:
943
 
            /* src: paInt32, 14 bit shift, possible byte swap */
944
 
#ifdef PA_MSB_IS_NATIVE_
945
 
            *converter = ShiftRightSwap32;
946
 
#else
947
 
            *converter = ShiftRight32;
948
 
#endif
949
 
            *shift = 14;
950
 
            break;
951
 
        case ASIOSTInt32LSB20:
952
 
            /* src: paInt32, 12 bit shift, possible byte swap */
953
 
#ifdef PA_MSB_IS_NATIVE_
954
 
            *converter = ShiftRightSwap32;
955
 
#else
956
 
            *converter = ShiftRight32;
957
 
#endif
958
 
            *shift = 12;
959
 
            break;
960
 
        case ASIOSTInt32LSB24:
961
 
            /* src: paInt32, 8 bit shift, possible byte swap */
962
 
#ifdef PA_MSB_IS_NATIVE_
963
 
            *converter = ShiftRightSwap32;
964
 
#else
965
 
            *converter = ShiftRight32;
966
 
#endif
967
 
            *shift = 8;
968
 
            break;
969
 
        case ASIOSTInt24MSB:
970
 
            /* src: paInt24, no conversion necessary, possible byte swap */
971
 
#ifdef PA_LSB_IS_NATIVE_
972
 
            *converter = Swap24;
973
 
#endif
974
 
            break;
975
 
        case ASIOSTInt24LSB:
976
 
            /* src: paInt24, no conversion necessary, possible byte swap */
977
 
#ifdef PA_MSB_IS_NATIVE_
978
 
            *converter = Swap24;
979
 
#endif
980
 
            break;
981
 
    }
982
 
}
983
 
 
984
 
 
985
 
typedef struct PaAsioDeviceInfo {
986
 
    PaDeviceInfo commonDeviceInfo;
987
 
    long minBufferSize;
988
 
    long maxBufferSize;
989
 
    long preferredBufferSize;
990
 
    long bufferGranularity;
991
 
 
992
 
    ASIOChannelInfo *asioChannelInfos;
993
 
}
994
 
PaAsioDeviceInfo;
995
 
 
996
 
 
997
 
PaError PaAsio_GetAvailableLatencyValues (PaDeviceIndex device,
998
 
        long *minLatency, long *maxLatency, long *preferredLatency, long *granularity)
999
 
{
1000
 
    PaError result;
1001
 
    PaUtilHostApiRepresentation *hostApi;
1002
 
    PaDeviceIndex hostApiDevice;
1003
 
 
1004
 
    result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
1005
 
 
1006
 
    if (result == paNoError) {
1007
 
        result = PaUtil_DeviceIndexToHostApiDeviceIndex (&hostApiDevice, device, hostApi);
1008
 
 
1009
 
        if (result == paNoError) {
1010
 
            PaAsioDeviceInfo *asioDeviceInfo =
1011
 
                (PaAsioDeviceInfo*) hostApi->deviceInfos[hostApiDevice];
1012
 
 
1013
 
            *minLatency = asioDeviceInfo->minBufferSize;
1014
 
            *maxLatency = asioDeviceInfo->maxBufferSize;
1015
 
            *preferredLatency = asioDeviceInfo->preferredBufferSize;
1016
 
            *granularity = asioDeviceInfo->bufferGranularity;
1017
 
        }
1018
 
    }
1019
 
 
1020
 
    return result;
1021
 
}
1022
 
 
1023
 
/* Unload whatever we loaded in LoadAsioDriver().
1024
 
   Also balance the call to CoInitialize(0).
1025
 
*/
1026
 
static void UnloadAsioDriver (void)
1027
 
{
1028
 
    ASIOExit();
1029
 
    CoUninitialize();
1030
 
}
1031
 
 
1032
 
/*
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.
1037
 
*/
1038
 
static PaError LoadAsioDriver (PaAsioHostApiRepresentation *asioHostApi, const char *driverName,
1039
 
                               PaAsioDriverInfo *driverInfo, void *systemSpecific)
1040
 
{
1041
 
    PaError result = paNoError;
1042
 
    ASIOError asioError;
1043
 
    int asioIsInitialized = 0;
1044
 
 
1045
 
    /*
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().
1050
 
 
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.
1054
 
    */
1055
 
    CoInitialize (0);
1056
 
 
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.
1060
 
        */
1061
 
        result = paUnanticipatedHostError;
1062
 
        PA_ASIO_SET_LAST_HOST_ERROR (0, "Failed to load ASIO driver");
1063
 
        goto error;
1064
 
    }
1065
 
 
1066
 
    memset (&driverInfo->asioDriverInfo, 0, sizeof (ASIODriverInfo));
1067
 
    driverInfo->asioDriverInfo.asioVersion = 2;
1068
 
    driverInfo->asioDriverInfo.sysRef = systemSpecific;
1069
 
 
1070
 
    if ( (asioError = ASIOInit (&driverInfo->asioDriverInfo)) != ASE_OK) {
1071
 
        result = paUnanticipatedHostError;
1072
 
        PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
1073
 
        goto error;
1074
 
    } else {
1075
 
        asioIsInitialized = 1;
1076
 
    }
1077
 
 
1078
 
    if ( (asioError = ASIOGetChannels (&driverInfo->inputChannelCount,
1079
 
                                       &driverInfo->outputChannelCount)) != ASE_OK) {
1080
 
        result = paUnanticipatedHostError;
1081
 
        PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
1082
 
        goto error;
1083
 
    }
1084
 
 
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);
1090
 
        goto error;
1091
 
    }
1092
 
 
1093
 
    if (ASIOOutputReady() == ASE_OK)
1094
 
        driverInfo->postOutput = true;
1095
 
    else
1096
 
        driverInfo->postOutput = false;
1097
 
 
1098
 
    return result;
1099
 
 
1100
 
error:
1101
 
 
1102
 
    if (asioIsInitialized) {
1103
 
        ASIOExit();
1104
 
    }
1105
 
 
1106
 
    CoUninitialize();
1107
 
    return result;
1108
 
}
1109
 
 
1110
 
 
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
1115
 
  };
1116
 
 
1117
 
 
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
1122
 
 
1123
 
PaError PaAsio_Initialize (PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex)
1124
 
{
1125
 
    PaError result = paNoError;
1126
 
    int i, driverCount;
1127
 
    PaAsioHostApiRepresentation *asioHostApi;
1128
 
    PaAsioDeviceInfo *deviceInfoArray;
1129
 
    char **names;
1130
 
    PaAsioDriverInfo paAsioDriverInfo;
1131
 
 
1132
 
    asioHostApi = (PaAsioHostApiRepresentation*) PaUtil_AllocateMemory (sizeof (PaAsioHostApiRepresentation));
1133
 
 
1134
 
    if (!asioHostApi) {
1135
 
        result = paInsufficientMemory;
1136
 
        goto error;
1137
 
    }
1138
 
 
1139
 
    asioHostApi->asioDrivers = 0; /* avoid surprises in our error handler below */
1140
 
 
1141
 
    asioHostApi->allocations = PaUtil_CreateAllocationGroup();
1142
 
 
1143
 
    if (!asioHostApi->allocations) {
1144
 
        result = paInsufficientMemory;
1145
 
        goto error;
1146
 
    }
1147
 
 
1148
 
    /* Allocate the AsioDrivers() driver list (class from ASIO SDK) */
1149
 
    try {
1150
 
        asioHostApi->asioDrivers = new AsioDrivers(); /* calls CoInitialize(0) */
1151
 
    } catch (std::bad_alloc) {
1152
 
        asioHostApi->asioDrivers = 0;
1153
 
    }
1154
 
 
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;
1159
 
        goto error;
1160
 
    }
1161
 
 
1162
 
    asioDrivers = asioHostApi->asioDrivers; /* keep SDK global in sync until we stop depending on it */
1163
 
 
1164
 
    asioHostApi->systemSpecific = 0;
1165
 
    asioHostApi->openAsioDeviceIndex = paNoDevice;
1166
 
 
1167
 
    *hostApi = &asioHostApi->inheritedHostApiRep;
1168
 
    (*hostApi)->info.structVersion = 1;
1169
 
 
1170
 
    (*hostApi)->info.type = paASIO;
1171
 
    (*hostApi)->info.name = "ASIO";
1172
 
    (*hostApi)->info.deviceCount = 0;
1173
 
 
1174
 
#ifdef WINDOWS
1175
 
    /* use desktop window as system specific ptr */
1176
 
    asioHostApi->systemSpecific = GetDesktopWindow();
1177
 
#endif
1178
 
 
1179
 
    /* driverCount is the number of installed drivers - not necessarily
1180
 
        the number of installed physical devices. */
1181
 
#if MAC
1182
 
    driverCount = asioHostApi->asioDrivers->getNumFragments();
1183
 
#elif WINDOWS
1184
 
    driverCount = asioHostApi->asioDrivers->asioGetNumDev();
1185
 
#endif
1186
 
 
1187
 
    if (driverCount > 0) {
1188
 
        names = GetAsioDriverNames (asioHostApi, asioHostApi->allocations, driverCount);
1189
 
 
1190
 
        if (!names) {
1191
 
            result = paInsufficientMemory;
1192
 
            goto error;
1193
 
        }
1194
 
 
1195
 
 
1196
 
        /* allocate enough space for all drivers, even if some aren't installed */
1197
 
 
1198
 
        (*hostApi)->deviceInfos = (PaDeviceInfo**) PaUtil_GroupAllocateMemory (
1199
 
                                      asioHostApi->allocations, sizeof (PaDeviceInfo*) * driverCount);
1200
 
 
1201
 
        if (! (*hostApi)->deviceInfos) {
1202
 
            result = paInsufficientMemory;
1203
 
            goto error;
1204
 
        }
1205
 
 
1206
 
        /* allocate all device info structs in a contiguous block */
1207
 
        deviceInfoArray = (PaAsioDeviceInfo*) PaUtil_GroupAllocateMemory (
1208
 
                              asioHostApi->allocations, sizeof (PaAsioDeviceInfo) * driverCount);
1209
 
 
1210
 
        if (!deviceInfoArray) {
1211
 
            result = paInsufficientMemory;
1212
 
            goto error;
1213
 
        }
1214
 
 
1215
 
        IsDebuggerPresent_ = GetProcAddress (LoadLibrary ("Kernel32.dll"), "IsDebuggerPresent");
1216
 
 
1217
 
        for (i=0; i < driverCount; ++i) {
1218
 
 
1219
 
            PA_DEBUG ( ("ASIO names[%d]:%s\n",i,names[i]));
1220
 
 
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:
1227
 
 
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"
1232
 
               ) {
1233
 
                PA_DEBUG ( ("BLACKLISTED!!!\n"));
1234
 
                continue;
1235
 
            }
1236
 
 
1237
 
 
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"));
1243
 
                    continue;
1244
 
                }
1245
 
            }
1246
 
 
1247
 
 
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;
1252
 
 
1253
 
                deviceInfo->structVersion = 2;
1254
 
                deviceInfo->hostApi = hostApiIndex;
1255
 
 
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));
1264
 
 
1265
 
                deviceInfo->maxInputChannels  = paAsioDriverInfo.inputChannelCount;
1266
 
                deviceInfo->maxOutputChannels = paAsioDriverInfo.outputChannelCount;
1267
 
 
1268
 
                deviceInfo->defaultSampleRate = 0.;
1269
 
                bool foundDefaultSampleRate = false;
1270
 
 
1271
 
                for (int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j) {
1272
 
                    ASIOError asioError = ASIOCanSampleRate (defaultSampleRateSearchOrder_[j]);
1273
 
 
1274
 
                    if (asioError != ASE_NoClock && asioError != ASE_NotPresent) {
1275
 
                        deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
1276
 
                        foundDefaultSampleRate = true;
1277
 
                        break;
1278
 
                    }
1279
 
                }
1280
 
 
1281
 
                PA_DEBUG ( ("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate));
1282
 
 
1283
 
                if (foundDefaultSampleRate) {
1284
 
 
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.
1291
 
                    */
1292
 
 
1293
 
                    double defaultLowLatency =
1294
 
                        paAsioDriverInfo.bufferPreferredSize / deviceInfo->defaultSampleRate;
1295
 
 
1296
 
                    deviceInfo->defaultLowInputLatency = defaultLowLatency;
1297
 
                    deviceInfo->defaultLowOutputLatency = defaultLowLatency;
1298
 
 
1299
 
                    long defaultHighLatencyBufferSize =
1300
 
                        paAsioDriverInfo.bufferPreferredSize * 3;
1301
 
 
1302
 
                    if (defaultHighLatencyBufferSize > paAsioDriverInfo.bufferMaxSize)
1303
 
                        defaultHighLatencyBufferSize = paAsioDriverInfo.bufferMaxSize;
1304
 
 
1305
 
                    double defaultHighLatency =
1306
 
                        defaultHighLatencyBufferSize / deviceInfo->defaultSampleRate;
1307
 
 
1308
 
                    if (defaultHighLatency < defaultLowLatency)
1309
 
                        defaultHighLatency = defaultLowLatency; /* just incase the driver returns something strange */
1310
 
 
1311
 
                    deviceInfo->defaultHighInputLatency = defaultHighLatency;
1312
 
                    deviceInfo->defaultHighOutputLatency = defaultHighLatency;
1313
 
 
1314
 
                } else {
1315
 
 
1316
 
                    deviceInfo->defaultLowInputLatency = 0.;
1317
 
                    deviceInfo->defaultLowOutputLatency = 0.;
1318
 
                    deviceInfo->defaultHighInputLatency = 0.;
1319
 
                    deviceInfo->defaultHighOutputLatency = 0.;
1320
 
                }
1321
 
 
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));
1326
 
 
1327
 
                asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize;
1328
 
                asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize;
1329
 
                asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize;
1330
 
                asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity;
1331
 
 
1332
 
 
1333
 
                asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*) PaUtil_GroupAllocateMemory (
1334
 
                                                       asioHostApi->allocations,
1335
 
                                                       sizeof (ASIOChannelInfo) * (deviceInfo->maxInputChannels
1336
 
                                                                                   + deviceInfo->maxOutputChannels));
1337
 
 
1338
 
                if (!asioDeviceInfo->asioChannelInfos) {
1339
 
                    result = paInsufficientMemory;
1340
 
                    goto error_unload;
1341
 
                }
1342
 
 
1343
 
                int a;
1344
 
 
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]);
1349
 
 
1350
 
                    if (asioError != ASE_OK) {
1351
 
                        result = paUnanticipatedHostError;
1352
 
                        PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
1353
 
                        goto error_unload;
1354
 
                    }
1355
 
                }
1356
 
 
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]);
1362
 
 
1363
 
                    if (asioError != ASE_OK) {
1364
 
                        result = paUnanticipatedHostError;
1365
 
                        PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
1366
 
                        goto error_unload;
1367
 
                    }
1368
 
                }
1369
 
 
1370
 
 
1371
 
                /* unload the driver */
1372
 
                UnloadAsioDriver();
1373
 
 
1374
 
                (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
1375
 
                ++ (*hostApi)->info.deviceCount;
1376
 
            }
1377
 
        }
1378
 
    }
1379
 
 
1380
 
    if ( (*hostApi)->info.deviceCount > 0) {
1381
 
        (*hostApi)->info.defaultInputDevice = 0;
1382
 
        (*hostApi)->info.defaultOutputDevice = 0;
1383
 
    } else {
1384
 
        (*hostApi)->info.defaultInputDevice = paNoDevice;
1385
 
        (*hostApi)->info.defaultOutputDevice = paNoDevice;
1386
 
    }
1387
 
 
1388
 
 
1389
 
    (*hostApi)->Terminate = Terminate;
1390
 
    (*hostApi)->OpenStream = OpenStream;
1391
 
    (*hostApi)->IsFormatSupported = IsFormatSupported;
1392
 
 
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);
1398
 
 
1399
 
    PaUtil_InitializeStreamInterface (&asioHostApi->blockingStreamInterface, CloseStream, StartStream,
1400
 
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
1401
 
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
1402
 
                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable);
1403
 
 
1404
 
    return result;
1405
 
 
1406
 
error_unload:
1407
 
    UnloadAsioDriver();
1408
 
 
1409
 
error:
1410
 
 
1411
 
    if (asioHostApi) {
1412
 
        if (asioHostApi->allocations) {
1413
 
            PaUtil_FreeAllAllocations (asioHostApi->allocations);
1414
 
            PaUtil_DestroyAllocationGroup (asioHostApi->allocations);
1415
 
        }
1416
 
 
1417
 
        delete asioHostApi->asioDrivers;
1418
 
        asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
1419
 
 
1420
 
        PaUtil_FreeMemory (asioHostApi);
1421
 
    }
1422
 
 
1423
 
    return result;
1424
 
}
1425
 
 
1426
 
 
1427
 
static void Terminate (struct PaUtilHostApiRepresentation *hostApi)
1428
 
{
1429
 
    PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*) hostApi;
1430
 
 
1431
 
    /*
1432
 
        IMPLEMENT ME:
1433
 
            - clean up any resources not handled by the allocation group (need to review if there are any)
1434
 
    */
1435
 
 
1436
 
    if (asioHostApi->allocations) {
1437
 
        PaUtil_FreeAllAllocations (asioHostApi->allocations);
1438
 
        PaUtil_DestroyAllocationGroup (asioHostApi->allocations);
1439
 
    }
1440
 
 
1441
 
    delete asioHostApi->asioDrivers; /* calls CoUninitialize() */
1442
 
    asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
1443
 
 
1444
 
    PaUtil_FreeMemory (asioHostApi);
1445
 
}
1446
 
 
1447
 
 
1448
 
static PaError IsFormatSupported (struct PaUtilHostApiRepresentation *hostApi,
1449
 
                                  const PaStreamParameters *inputParameters,
1450
 
                                  const PaStreamParameters *outputParameters,
1451
 
                                  double sampleRate)
1452
 
{
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;
1460
 
 
1461
 
    if (inputParameters && outputParameters) {
1462
 
        /* full duplex ASIO stream must use the same device for input and output */
1463
 
 
1464
 
        if (inputParameters->device != outputParameters->device)
1465
 
            return paBadIODeviceCombination;
1466
 
    }
1467
 
 
1468
 
    if (inputParameters) {
1469
 
        inputChannelCount = inputParameters->channelCount;
1470
 
        inputSampleFormat = inputParameters->sampleFormat;
1471
 
 
1472
 
        /* all standard sample formats are supported by the buffer adapter,
1473
 
            this implementation doesn't support any custom sample formats */
1474
 
        if (inputSampleFormat & paCustomFormat)
1475
 
            return paSampleFormatNotSupported;
1476
 
 
1477
 
        /* unless alternate device specification is supported, reject the use of
1478
 
            paUseHostApiSpecificDeviceSpecification */
1479
 
 
1480
 
        if (inputParameters->device == paUseHostApiSpecificDeviceSpecification)
1481
 
            return paInvalidDevice;
1482
 
 
1483
 
        asioDeviceIndex = inputParameters->device;
1484
 
 
1485
 
        /* validate inputStreamInfo */
1486
 
        /** @todo do more validation here */
1487
 
        // if( inputParameters->hostApiSpecificStreamInfo )
1488
 
        //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1489
 
    } else {
1490
 
        inputChannelCount = 0;
1491
 
    }
1492
 
 
1493
 
    if (outputParameters) {
1494
 
        outputChannelCount = outputParameters->channelCount;
1495
 
        outputSampleFormat = outputParameters->sampleFormat;
1496
 
 
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;
1501
 
 
1502
 
        /* unless alternate device specification is supported, reject the use of
1503
 
            paUseHostApiSpecificDeviceSpecification */
1504
 
 
1505
 
        if (outputParameters->device == paUseHostApiSpecificDeviceSpecification)
1506
 
            return paInvalidDevice;
1507
 
 
1508
 
        asioDeviceIndex = outputParameters->device;
1509
 
 
1510
 
        /* validate outputStreamInfo */
1511
 
        /** @todo do more validation here */
1512
 
        // if( outputParameters->hostApiSpecificStreamInfo )
1513
 
        //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1514
 
    } else {
1515
 
        outputChannelCount = 0;
1516
 
    }
1517
 
 
1518
 
 
1519
 
 
1520
 
    /* if an ASIO device is open we can only get format information for the currently open device */
1521
 
 
1522
 
    if (asioHostApi->openAsioDeviceIndex != paNoDevice
1523
 
            && asioHostApi->openAsioDeviceIndex != asioDeviceIndex) {
1524
 
        return paDeviceUnavailable;
1525
 
    }
1526
 
 
1527
 
 
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 */
1530
 
 
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);
1535
 
 
1536
 
        if (result != paNoError)
1537
 
            return result;
1538
 
    }
1539
 
 
1540
 
    /* check that input device can support inputChannelCount */
1541
 
    if (inputChannelCount > 0) {
1542
 
        if (inputChannelCount > driverInfo->inputChannelCount) {
1543
 
            result = paInvalidChannelCount;
1544
 
            goto done;
1545
 
        }
1546
 
    }
1547
 
 
1548
 
    /* check that output device can support outputChannelCount */
1549
 
    if (outputChannelCount) {
1550
 
        if (outputChannelCount > driverInfo->outputChannelCount) {
1551
 
            result = paInvalidChannelCount;
1552
 
            goto done;
1553
 
        }
1554
 
    }
1555
 
 
1556
 
    /* query for sample rate support */
1557
 
    asioError = ASIOCanSampleRate (sampleRate);
1558
 
 
1559
 
    if (asioError == ASE_NoClock || asioError == ASE_NotPresent) {
1560
 
        result = paInvalidSampleRate;
1561
 
        goto done;
1562
 
    }
1563
 
 
1564
 
done:
1565
 
 
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 */
1569
 
    }
1570
 
 
1571
 
    if (result == paNoError)
1572
 
        return paFormatIsSupported;
1573
 
    else
1574
 
        return result;
1575
 
}
1576
 
 
1577
 
 
1578
 
 
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. */
1582
 
 
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. */
1585
 
 
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. */
1588
 
 
1589
 
    HANDLE writeBuffersReadyEvent; /**< Event to signal that requested output buffers are available. */
1590
 
    HANDLE readFramesReadyEvent;   /**< Event to signal that requested input frames are available. */
1591
 
 
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. */
1594
 
 
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). */
1597
 
 
1598
 
    long writeRingBufferInitialFrames; /**< The initial number of silent frames within the output ring buffer. */
1599
 
 
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. */
1602
 
 
1603
 
    PaUtilBufferProcessor bufferProcessor; /**< Buffer processor, used to handle the blocking i/o ring buffers. */
1604
 
 
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. */
1607
 
}
1608
 
PaAsioStreamBlockingState;
1609
 
 
1610
 
 
1611
 
 
1612
 
/* PaAsioStream - a stream data structure specifically for this implementation */
1613
 
 
1614
 
typedef struct PaAsioStream {
1615
 
    PaUtilStreamRepresentation streamRepresentation;
1616
 
    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
1617
 
    PaUtilBufferProcessor bufferProcessor;
1618
 
 
1619
 
    PaAsioHostApiRepresentation *asioHostApi;
1620
 
    unsigned long framesPerHostCallback;
1621
 
 
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
1624
 
        to work. */
1625
 
 
1626
 
    ASIOBufferInfo *asioBufferInfos;
1627
 
    ASIOChannelInfo *asioChannelInfos;
1628
 
    long inputLatency, outputLatency; // actual latencies returned by asio
1629
 
 
1630
 
    long inputChannelCount, outputChannelCount;
1631
 
    bool postOutput;
1632
 
 
1633
 
    void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */
1634
 
    void **inputBufferPtrs[2];
1635
 
    void **outputBufferPtrs[2];
1636
 
 
1637
 
    PaAsioBufferConverter *inputBufferConverter;
1638
 
    long inputShift;
1639
 
    PaAsioBufferConverter *outputBufferConverter;
1640
 
    long outputShift;
1641
 
 
1642
 
    volatile bool stopProcessing;
1643
 
    int stopPlayoutCount;
1644
 
    HANDLE completedBuffersPlayedEvent;
1645
 
 
1646
 
    bool streamFinishedCallbackCalled;
1647
 
    int isStopped;
1648
 
    volatile int isActive;
1649
 
    volatile bool zeroOutput; /* all future calls to the callback will output silence */
1650
 
 
1651
 
    volatile long reenterCount;
1652
 
    volatile long reenterError;
1653
 
 
1654
 
    PaStreamCallbackFlags callbackFlags;
1655
 
 
1656
 
    PaAsioStreamBlockingState *blockingState; /**< Blocking i/o data struct, or NULL when using callback interface. */
1657
 
}
1658
 
PaAsioStream;
1659
 
 
1660
 
static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */
1661
 
 
1662
 
 
1663
 
static void ZeroOutputBuffers (PaAsioStream *stream, long index)
1664
 
{
1665
 
    int i;
1666
 
 
1667
 
    for (i=0; i < stream->outputChannelCount; ++i) {
1668
 
        void *buffer = stream->asioBufferInfos[ i + stream->inputChannelCount ].buffers[index];
1669
 
 
1670
 
        int bytesPerSample = BytesPerAsioSample (stream->asioChannelInfos[ i + stream->inputChannelCount ].type);
1671
 
 
1672
 
        memset (buffer, 0, stream->framesPerHostCallback * bytesPerSample);
1673
 
    }
1674
 
}
1675
 
 
1676
 
 
1677
 
static unsigned long SelectHostBufferSize (unsigned long suggestedLatencyFrames,
1678
 
        PaAsioDriverInfo *driverInfo)
1679
 
{
1680
 
    unsigned long result;
1681
 
 
1682
 
    if (suggestedLatencyFrames == 0) {
1683
 
        result = driverInfo->bufferPreferredSize;
1684
 
    } else {
1685
 
        if (suggestedLatencyFrames <= (unsigned long) driverInfo->bufferMinSize) {
1686
 
            result = driverInfo->bufferMinSize;
1687
 
        } else if (suggestedLatencyFrames >= (unsigned long) driverInfo->bufferMaxSize) {
1688
 
            result = driverInfo->bufferMaxSize;
1689
 
        } else {
1690
 
            if (driverInfo->bufferGranularity == -1) {
1691
 
                /* power-of-two */
1692
 
                result = 2;
1693
 
 
1694
 
                while (result < suggestedLatencyFrames)
1695
 
                    result *= 2;
1696
 
 
1697
 
                if (result < (unsigned long) driverInfo->bufferMinSize)
1698
 
                    result = driverInfo->bufferMinSize;
1699
 
 
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.
1706
 
                */
1707
 
 
1708
 
                result = driverInfo->bufferPreferredSize;
1709
 
            } else {
1710
 
                /* modulo granularity */
1711
 
 
1712
 
                unsigned long remainder =
1713
 
                    suggestedLatencyFrames % driverInfo->bufferGranularity;
1714
 
 
1715
 
                if (remainder == 0) {
1716
 
                    result = suggestedLatencyFrames;
1717
 
                } else {
1718
 
                    result = suggestedLatencyFrames
1719
 
                             + (driverInfo->bufferGranularity - remainder);
1720
 
 
1721
 
                    if (result > (unsigned long) driverInfo->bufferMaxSize)
1722
 
                        result = driverInfo->bufferMaxSize;
1723
 
                }
1724
 
            }
1725
 
        }
1726
 
    }
1727
 
 
1728
 
    return result;
1729
 
}
1730
 
 
1731
 
 
1732
 
/* returns channelSelectors if present */
1733
 
 
1734
 
static PaError ValidateAsioSpecificStreamInfo (
1735
 
    const PaStreamParameters *streamParameters,
1736
 
    const PaAsioStreamInfo *streamInfo,
1737
 
    int deviceChannelCount,
1738
 
    int **channelSelectors)
1739
 
{
1740
 
    if (streamInfo) {
1741
 
        if (streamInfo->size != sizeof (PaAsioStreamInfo)
1742
 
                || streamInfo->version != 1) {
1743
 
            return paIncompatibleHostApiSpecificStreamInfo;
1744
 
        }
1745
 
 
1746
 
        if (streamInfo->flags & paAsioUseChannelSelectors)
1747
 
            *channelSelectors = streamInfo->channelSelectors;
1748
 
 
1749
 
        if (! (*channelSelectors))
1750
 
            return paIncompatibleHostApiSpecificStreamInfo;
1751
 
 
1752
 
        for (int i=0; i < streamParameters->channelCount; ++i) {
1753
 
            if ( (*channelSelectors) [i] < 0
1754
 
                    || (*channelSelectors) [i] >= deviceChannelCount) {
1755
 
                return paInvalidChannelCount;
1756
 
            }
1757
 
        }
1758
 
    }
1759
 
 
1760
 
    return paNoError;
1761
 
}
1762
 
 
1763
 
 
1764
 
static bool IsUsingExternalClockSource()
1765
 
{
1766
 
    bool result = false;
1767
 
    ASIOError asioError;
1768
 
    ASIOClockSource clocks[32];
1769
 
    long numSources=32;
1770
 
 
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 */
1774
 
 
1775
 
    asioError = ASIOGetClockSources (clocks, &numSources);
1776
 
 
1777
 
    if (asioError != ASE_OK) {
1778
 
        PA_DEBUG ( ("ERROR: ASIOGetClockSources: %s\n", PaAsio_GetAsioErrorText (asioError)));
1779
 
    } else {
1780
 
        PA_DEBUG ( ("INFO ASIOGetClockSources listing %d clocks\n", numSources));
1781
 
 
1782
 
        for (int i=0; i<numSources; ++i) {
1783
 
            PA_DEBUG ( ("ASIOClockSource%d %s current:%d\n", i, clocks[i].name, clocks[i].isCurrentSource));
1784
 
 
1785
 
            if (clocks[i].isCurrentSource)
1786
 
                result = true;
1787
 
        }
1788
 
    }
1789
 
 
1790
 
    return result;
1791
 
}
1792
 
 
1793
 
 
1794
 
static PaError ValidateAndSetSampleRate (double sampleRate)
1795
 
{
1796
 
    PaError result = paNoError;
1797
 
    ASIOError asioError;
1798
 
 
1799
 
    // check that the device supports the requested sample rate
1800
 
 
1801
 
    asioError = ASIOCanSampleRate (sampleRate);
1802
 
    PA_DEBUG ( ("ASIOCanSampleRate(%f):%d\n", sampleRate, asioError));
1803
 
 
1804
 
    if (asioError != ASE_OK) {
1805
 
        result = paInvalidSampleRate;
1806
 
        PA_DEBUG ( ("ERROR: ASIOCanSampleRate: %s\n", PaAsio_GetAsioErrorText (asioError)));
1807
 
        goto error;
1808
 
    }
1809
 
 
1810
 
    // retrieve the current sample rate, we only change to the requested
1811
 
    // sample rate if the device is not already in that rate.
1812
 
 
1813
 
    ASIOSampleRate oldRate;
1814
 
    asioError = ASIOGetSampleRate (&oldRate);
1815
 
 
1816
 
    if (asioError != ASE_OK) {
1817
 
        result = paInvalidSampleRate;
1818
 
        PA_DEBUG ( ("ERROR: ASIOGetSampleRate: %s\n", PaAsio_GetAsioErrorText (asioError)));
1819
 
        goto error;
1820
 
    }
1821
 
 
1822
 
    PA_DEBUG ( ("ASIOGetSampleRate:%f\n",oldRate));
1823
 
 
1824
 
    if (oldRate != sampleRate) {
1825
 
        /* Set sample rate */
1826
 
 
1827
 
        PA_DEBUG ( ("before ASIOSetSampleRate(%f)\n",sampleRate));
1828
 
 
1829
 
        /*
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.
1833
 
        */
1834
 
 
1835
 
        //if( IsUsingExternalClockSource() ){
1836
 
        if (false) {
1837
 
            asioError = ASIOSetSampleRate (0);
1838
 
        } else {
1839
 
            asioError = ASIOSetSampleRate (sampleRate);
1840
 
        }
1841
 
 
1842
 
        if (asioError != ASE_OK) {
1843
 
            result = paInvalidSampleRate;
1844
 
            PA_DEBUG ( ("ERROR: ASIOSetSampleRate: %s\n", PaAsio_GetAsioErrorText (asioError)));
1845
 
            goto error;
1846
 
        }
1847
 
 
1848
 
        PA_DEBUG ( ("after ASIOSetSampleRate(%f)\n",sampleRate));
1849
 
    } else {
1850
 
        PA_DEBUG ( ("No Need to change SR\n"));
1851
 
    }
1852
 
 
1853
 
error:
1854
 
    return result;
1855
 
}
1856
 
 
1857
 
 
1858
 
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream  parameters */
1859
 
 
1860
 
static PaError OpenStream (struct PaUtilHostApiRepresentation *hostApi,
1861
 
                           PaStream** s,
1862
 
                           const PaStreamParameters *inputParameters,
1863
 
                           const PaStreamParameters *outputParameters,
1864
 
                           double sampleRate,
1865
 
                           unsigned long framesPerBuffer,
1866
 
                           PaStreamFlags streamFlags,
1867
 
                           PaStreamCallback *streamCallback,
1868
 
                           void *userData)
1869
 
{
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;
1885
 
    int i;
1886
 
    PaAsioDriverInfo *driverInfo;
1887
 
    int *inputChannelSelectors = 0;
1888
 
    int *outputChannelSelectors = 0;
1889
 
 
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. */
1898
 
 
1899
 
    int callbackBufferProcessorInited = FALSE;
1900
 
    int blockingBufferProcessorInited = FALSE;
1901
 
 
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;
1907
 
    }
1908
 
 
1909
 
    assert (theAsioStream == 0);
1910
 
 
1911
 
    if (inputParameters && outputParameters) {
1912
 
        /* full duplex ASIO stream must use the same device for input and output */
1913
 
 
1914
 
        if (inputParameters->device != outputParameters->device) {
1915
 
            PA_DEBUG ( ("OpenStream paBadIODeviceCombination\n"));
1916
 
            return paBadIODeviceCombination;
1917
 
        }
1918
 
    }
1919
 
 
1920
 
    if (inputParameters) {
1921
 
        inputChannelCount = inputParameters->channelCount;
1922
 
        inputSampleFormat = inputParameters->sampleFormat;
1923
 
        suggestedInputLatencyFrames = (unsigned long) ( (inputParameters->suggestedLatency * sampleRate) +0.5f);
1924
 
 
1925
 
        /* unless alternate device specification is supported, reject the use of
1926
 
            paUseHostApiSpecificDeviceSpecification */
1927
 
        if (inputParameters->device == paUseHostApiSpecificDeviceSpecification)
1928
 
            return paInvalidDevice;
1929
 
 
1930
 
        asioDeviceIndex = inputParameters->device;
1931
 
 
1932
 
        PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[asioDeviceIndex];
1933
 
 
1934
 
        /* validate hostApiSpecificStreamInfo */
1935
 
        inputStreamInfo = (PaAsioStreamInfo*) inputParameters->hostApiSpecificStreamInfo;
1936
 
        result = ValidateAsioSpecificStreamInfo (inputParameters, inputStreamInfo,
1937
 
                 asioDeviceInfo->commonDeviceInfo.maxInputChannels,
1938
 
                 &inputChannelSelectors
1939
 
                                                );
1940
 
 
1941
 
        if (result != paNoError) return result;
1942
 
    } else {
1943
 
        inputChannelCount = 0;
1944
 
        inputSampleFormat = 0;
1945
 
        suggestedInputLatencyFrames = 0;
1946
 
    }
1947
 
 
1948
 
    if (outputParameters) {
1949
 
        outputChannelCount = outputParameters->channelCount;
1950
 
        outputSampleFormat = outputParameters->sampleFormat;
1951
 
        suggestedOutputLatencyFrames = (unsigned long) ( (outputParameters->suggestedLatency * sampleRate) +0.5f);
1952
 
 
1953
 
        /* unless alternate device specification is supported, reject the use of
1954
 
            paUseHostApiSpecificDeviceSpecification */
1955
 
        if (outputParameters->device == paUseHostApiSpecificDeviceSpecification)
1956
 
            return paInvalidDevice;
1957
 
 
1958
 
        asioDeviceIndex = outputParameters->device;
1959
 
 
1960
 
        PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[asioDeviceIndex];
1961
 
 
1962
 
        /* validate hostApiSpecificStreamInfo */
1963
 
        outputStreamInfo = (PaAsioStreamInfo*) outputParameters->hostApiSpecificStreamInfo;
1964
 
        result = ValidateAsioSpecificStreamInfo (outputParameters, outputStreamInfo,
1965
 
                 asioDeviceInfo->commonDeviceInfo.maxOutputChannels,
1966
 
                 &outputChannelSelectors
1967
 
                                                );
1968
 
 
1969
 
        if (result != paNoError) return result;
1970
 
    } else {
1971
 
        outputChannelCount = 0;
1972
 
        outputSampleFormat = 0;
1973
 
        suggestedOutputLatencyFrames = 0;
1974
 
    }
1975
 
 
1976
 
    driverInfo = &asioHostApi->openAsioDriverInfo;
1977
 
 
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 */
1980
 
 
1981
 
    result = LoadAsioDriver (asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
1982
 
                             driverInfo, asioHostApi->systemSpecific);
1983
 
 
1984
 
    if (result == paNoError)
1985
 
        asioIsInitialized = 1;
1986
 
    else {
1987
 
        PA_DEBUG ( ("OpenStream ERROR1 - LoadAsioDriver returned %d\n", result));
1988
 
        goto error;
1989
 
    }
1990
 
 
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"));
1996
 
            goto error;
1997
 
        }
1998
 
    }
1999
 
 
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"));
2005
 
            goto error;
2006
 
        }
2007
 
    }
2008
 
 
2009
 
    result = ValidateAndSetSampleRate (sampleRate);
2010
 
 
2011
 
    if (result != paNoError)
2012
 
        goto error;
2013
 
 
2014
 
    /*
2015
 
        IMPLEMENT ME:
2016
 
            - if a full duplex stream is requested, check that the combination
2017
 
                of input and output parameters is supported
2018
 
    */
2019
 
 
2020
 
    /* validate platform specific flags */
2021
 
    if ( (streamFlags & paPlatformSpecificFlags) != 0) {
2022
 
        PA_DEBUG ( ("OpenStream invalid flags!!\n"));
2023
 
        return paInvalidFlag; /* unexpected platform specific flag */
2024
 
    }
2025
 
 
2026
 
 
2027
 
    stream = (PaAsioStream*) PaUtil_AllocateMemory (sizeof (PaAsioStream));
2028
 
 
2029
 
    if (!stream) {
2030
 
        result = paInsufficientMemory;
2031
 
        PA_DEBUG ( ("OpenStream ERROR5\n"));
2032
 
        goto error;
2033
 
    }
2034
 
 
2035
 
    stream->blockingState = NULL; /* Blocking i/o not initialized, yet. */
2036
 
 
2037
 
 
2038
 
    stream->completedBuffersPlayedEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
2039
 
 
2040
 
    if (stream->completedBuffersPlayedEvent == NULL) {
2041
 
        result = paUnanticipatedHostError;
2042
 
        PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
2043
 
        PA_DEBUG ( ("OpenStream ERROR6\n"));
2044
 
        goto error;
2045
 
    }
2046
 
 
2047
 
    completedBuffersPlayedEventInited = 1;
2048
 
 
2049
 
 
2050
 
    stream->asioBufferInfos = 0; /* for deallocation in error */
2051
 
    stream->asioChannelInfos = 0; /* for deallocation in error */
2052
 
    stream->bufferPtrs = 0; /* for deallocation in error */
2053
 
 
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);
2064
 
    }
2065
 
 
2066
 
 
2067
 
    PaUtil_InitializeCpuLoadMeasurer (&stream->cpuLoadMeasurer, sampleRate);
2068
 
 
2069
 
 
2070
 
    stream->asioBufferInfos = (ASIOBufferInfo*) PaUtil_AllocateMemory (
2071
 
                                  sizeof (ASIOBufferInfo) * (inputChannelCount + outputChannelCount));
2072
 
 
2073
 
    if (!stream->asioBufferInfos) {
2074
 
        result = paInsufficientMemory;
2075
 
        PA_DEBUG ( ("OpenStream ERROR7\n"));
2076
 
        goto error;
2077
 
    }
2078
 
 
2079
 
 
2080
 
    for (i=0; i < inputChannelCount; ++i) {
2081
 
        ASIOBufferInfo *info = &stream->asioBufferInfos[i];
2082
 
 
2083
 
        info->isInput = ASIOTrue;
2084
 
 
2085
 
        if (inputChannelSelectors) {
2086
 
            // inputChannelSelectors values have already been validated in
2087
 
            // ValidateAsioSpecificStreamInfo() above
2088
 
            info->channelNum = inputChannelSelectors[i];
2089
 
        } else {
2090
 
            info->channelNum = i;
2091
 
        }
2092
 
 
2093
 
        info->buffers[0] = info->buffers[1] = 0;
2094
 
    }
2095
 
 
2096
 
    for (i=0; i < outputChannelCount; ++i) {
2097
 
        ASIOBufferInfo *info = &stream->asioBufferInfos[inputChannelCount+i];
2098
 
 
2099
 
        info->isInput = ASIOFalse;
2100
 
 
2101
 
        if (outputChannelSelectors) {
2102
 
            // outputChannelSelectors values have already been validated in
2103
 
            // ValidateAsioSpecificStreamInfo() above
2104
 
            info->channelNum = outputChannelSelectors[i];
2105
 
        } else {
2106
 
            info->channelNum = i;
2107
 
        }
2108
 
 
2109
 
        info->buffers[0] = info->buffers[1] = 0;
2110
 
    }
2111
 
 
2112
 
 
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);
2118
 
 
2119
 
    } else { /* Using callback interface... */
2120
 
        framesPerHostBuffer = SelectHostBufferSize (
2121
 
                                  ( (suggestedInputLatencyFrames > suggestedOutputLatencyFrames)
2122
 
                                    ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames),
2123
 
                                  driverInfo);
2124
 
    }
2125
 
 
2126
 
 
2127
 
    PA_DEBUG ( ("PaAsioOpenStream: framesPerHostBuffer :%d\n",  framesPerHostBuffer));
2128
 
 
2129
 
    asioError = ASIOCreateBuffers (stream->asioBufferInfos,
2130
 
                                   inputChannelCount+outputChannelCount,
2131
 
                                   framesPerHostBuffer, &asioCallbacks_);
2132
 
 
2133
 
    if (asioError != ASE_OK
2134
 
            && framesPerHostBuffer != (unsigned long) driverInfo->bufferPreferredSize) {
2135
 
        PA_DEBUG ( ("ERROR: ASIOCreateBuffers: %s\n", PaAsio_GetAsioErrorText (asioError)));
2136
 
        /*
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.
2141
 
        */
2142
 
 
2143
 
        framesPerHostBuffer = driverInfo->bufferPreferredSize;
2144
 
 
2145
 
        PA_DEBUG ( ("PaAsioOpenStream: CORRECTED framesPerHostBuffer :%d\n",  framesPerHostBuffer));
2146
 
 
2147
 
        ASIOError asioError2 = ASIOCreateBuffers (stream->asioBufferInfos,
2148
 
                               inputChannelCount+outputChannelCount,
2149
 
                               framesPerHostBuffer, &asioCallbacks_);
2150
 
 
2151
 
        if (asioError2 == ASE_OK)
2152
 
            asioError = ASE_OK;
2153
 
    }
2154
 
 
2155
 
    if (asioError != ASE_OK) {
2156
 
        result = paUnanticipatedHostError;
2157
 
        PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
2158
 
        PA_DEBUG ( ("OpenStream ERROR9\n"));
2159
 
        goto error;
2160
 
    }
2161
 
 
2162
 
    asioBuffersCreated = 1;
2163
 
 
2164
 
    stream->asioChannelInfos = (ASIOChannelInfo*) PaUtil_AllocateMemory (
2165
 
                                   sizeof (ASIOChannelInfo) * (inputChannelCount + outputChannelCount));
2166
 
 
2167
 
    if (!stream->asioChannelInfos) {
2168
 
        result = paInsufficientMemory;
2169
 
        PA_DEBUG ( ("OpenStream ERROR10\n"));
2170
 
        goto error;
2171
 
    }
2172
 
 
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]);
2177
 
 
2178
 
        if (asioError != ASE_OK) {
2179
 
            result = paUnanticipatedHostError;
2180
 
            PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
2181
 
            PA_DEBUG ( ("OpenStream ERROR11\n"));
2182
 
            goto error;
2183
 
        }
2184
 
    }
2185
 
 
2186
 
    stream->bufferPtrs = (void**) PaUtil_AllocateMemory (
2187
 
                             2 * sizeof (void*) * (inputChannelCount + outputChannelCount));
2188
 
 
2189
 
    if (!stream->bufferPtrs) {
2190
 
        result = paInsufficientMemory;
2191
 
        PA_DEBUG ( ("OpenStream ERROR12\n"));
2192
 
        goto error;
2193
 
    }
2194
 
 
2195
 
    if (inputChannelCount > 0) {
2196
 
        stream->inputBufferPtrs[0] = stream-> bufferPtrs;
2197
 
        stream->inputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount];
2198
 
 
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];
2202
 
        }
2203
 
    } else {
2204
 
        stream->inputBufferPtrs[0] = 0;
2205
 
        stream->inputBufferPtrs[1] = 0;
2206
 
    }
2207
 
 
2208
 
    if (outputChannelCount > 0) {
2209
 
        stream->outputBufferPtrs[0] = &stream->bufferPtrs[inputChannelCount*2];
2210
 
        stream->outputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount*2 + outputChannelCount];
2211
 
 
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];
2215
 
        }
2216
 
    } else {
2217
 
        stream->outputBufferPtrs[0] = 0;
2218
 
        stream->outputBufferPtrs[1] = 0;
2219
 
    }
2220
 
 
2221
 
    if (inputChannelCount > 0) {
2222
 
        /* FIXME: assume all channels use the same type for now */
2223
 
        ASIOSampleType inputType = stream->asioChannelInfos[0].type;
2224
 
 
2225
 
        PA_DEBUG ( ("ASIO Input  type:%d",inputType));
2226
 
        AsioSampleTypeLOG (inputType);
2227
 
        hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat (inputType);
2228
 
 
2229
 
        SelectAsioToPaConverter (inputType, &stream->inputBufferConverter, &stream->inputShift);
2230
 
    } else {
2231
 
        hostInputSampleFormat = 0;
2232
 
        stream->inputBufferConverter = 0;
2233
 
    }
2234
 
 
2235
 
    if (outputChannelCount > 0) {
2236
 
        /* FIXME: assume all channels use the same type for now */
2237
 
        ASIOSampleType outputType = stream->asioChannelInfos[inputChannelCount].type;
2238
 
 
2239
 
        PA_DEBUG ( ("ASIO Output type:%d",outputType));
2240
 
        AsioSampleTypeLOG (outputType);
2241
 
        hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat (outputType);
2242
 
 
2243
 
        SelectPaToAsioConverter (outputType, &stream->outputBufferConverter, &stream->outputShift);
2244
 
    } else {
2245
 
        hostOutputSampleFormat = 0;
2246
 
        stream->outputBufferConverter = 0;
2247
 
    }
2248
 
 
2249
 
 
2250
 
    ASIOGetLatencies (&stream->inputLatency, &stream->outputLatency);
2251
 
 
2252
 
 
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));
2257
 
 
2258
 
        if (!stream->blockingState) {
2259
 
            result = paInsufficientMemory;
2260
 
            PA_DEBUG ( ("ERROR! Blocking i/o interface struct allocation failed in OpenStream()\n"));
2261
 
            goto error;
2262
 
        }
2263
 
 
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. */
2272
 
 
2273
 
 
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;
2278
 
        }
2279
 
 
2280
 
 
2281
 
        /* Initialize callback buffer processor. */
2282
 
        result = PaUtil_InitializeBufferProcessor (&stream->bufferProcessor               ,
2283
 
                 inputChannelCount                     ,
2284
 
                 inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
2285
 
                 hostInputSampleFormat                 , /* Host format. */
2286
 
                 outputChannelCount                    ,
2287
 
                 outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
2288
 
                 hostOutputSampleFormat                , /* Host format. */
2289
 
                 sampleRate                            ,
2290
 
                 streamFlags                           ,
2291
 
                 framesPerBuffer                       , /* Frames per ring buffer block. */
2292
 
                 framesPerHostBuffer                   , /* Frames per asio buffer. */
2293
 
                 paUtilFixedHostBufferSize             ,
2294
 
                 streamCallback                        ,
2295
 
                 userData);
2296
 
 
2297
 
        if (result != paNoError) {
2298
 
            PA_DEBUG ( ("OpenStream ERROR13\n"));
2299
 
            goto error;
2300
 
        }
2301
 
 
2302
 
        callbackBufferProcessorInited = TRUE;
2303
 
 
2304
 
        /* Initialize the blocking i/o buffer processor. */
2305
 
        result = PaUtil_InitializeBufferProcessor (&stream->blockingState->bufferProcessor,
2306
 
                 inputChannelCount                     ,
2307
 
                 inputSampleFormat                     , /* User format. */
2308
 
                 inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
2309
 
                 outputChannelCount                    ,
2310
 
                 outputSampleFormat                    , /* User format. */
2311
 
                 outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
2312
 
                 sampleRate                            ,
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! */
2318
 
 
2319
 
        if (result != paNoError) {
2320
 
            PA_DEBUG ( ("ERROR! Blocking i/o buffer processor initialization failed in OpenStream()\n"));
2321
 
            goto error;
2322
 
        }
2323
 
 
2324
 
        blockingBufferProcessorInited = TRUE;
2325
 
 
2326
 
        /* If input is requested. */
2327
 
        if (inputChannelCount) {
2328
 
            /* Create the callback sync-event. */
2329
 
            stream->blockingState->readFramesReadyEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2330
 
 
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"));
2335
 
                goto error;
2336
 
            }
2337
 
 
2338
 
            blockingReadFramesReadyEventInitialized = 1;
2339
 
 
2340
 
 
2341
 
            /* Create pointer buffer to access non-interleaved data in ReadStream() */
2342
 
            stream->blockingState->readStreamBuffer = (void**) PaUtil_AllocateMemory (sizeof (void*) * inputChannelCount);
2343
 
 
2344
 
            if (!stream->blockingState->readStreamBuffer) {
2345
 
                result = paInsufficientMemory;
2346
 
                PA_DEBUG ( ("ERROR! Blocking i/o read stream buffer allocation failed in OpenStream()\n"));
2347
 
                goto error;
2348
 
            }
2349
 
 
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.
2353
 
 
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
2361
 
                  to samples frames.
2362
 
               5) Get the next larger (or equal) power-of-two buffer size.
2363
 
             */
2364
 
            lBlockingBufferSize = suggestedInputLatencyFrames - stream->inputLatency;
2365
 
            lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
2366
 
            lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
2367
 
            lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
2368
 
 
2369
 
            /* Get the next larger or equal power-of-two buffersize. */
2370
 
            lBlockingBufferSizePow2 = 1;
2371
 
 
2372
 
            while (lBlockingBufferSize > (lBlockingBufferSizePow2<<=1));
2373
 
 
2374
 
            lBlockingBufferSize = lBlockingBufferSizePow2;
2375
 
 
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)
2382
 
                / sampleRate;
2383
 
 
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.
2387
 
            */
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))
2395
 
                       ));
2396
 
 
2397
 
            /* Determine the size of ring buffer in bytes. */
2398
 
            lBytesPerFrame = inputChannelCount * Pa_GetSampleSize (inputSampleFormat);
2399
 
 
2400
 
            /* Allocate the blocking i/o input ring buffer memory. */
2401
 
            stream->blockingState->readRingBufferData = (void*) PaUtil_AllocateMemory (lBlockingBufferSize * lBytesPerFrame);
2402
 
 
2403
 
            if (!stream->blockingState->readRingBufferData) {
2404
 
                result = paInsufficientMemory;
2405
 
                PA_DEBUG ( ("ERROR! Blocking i/o input ring buffer allocation failed in OpenStream()\n"));
2406
 
                goto error;
2407
 
            }
2408
 
 
2409
 
            /* Initialize the input ring buffer struct. */
2410
 
            PaUtil_InitializeRingBuffer (&stream->blockingState->readRingBuffer    ,
2411
 
                                         lBytesPerFrame                           ,
2412
 
                                         lBlockingBufferSize                      ,
2413
 
                                         stream->blockingState->readRingBufferData);
2414
 
        }
2415
 
 
2416
 
        /* If output is requested. */
2417
 
        if (outputChannelCount) {
2418
 
            stream->blockingState->writeBuffersReadyEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2419
 
 
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"));
2424
 
                goto error;
2425
 
            }
2426
 
 
2427
 
            blockingWriteBuffersReadyEventInitialized = 1;
2428
 
 
2429
 
            /* Create pointer buffer to access non-interleaved data in WriteStream() */
2430
 
            stream->blockingState->writeStreamBuffer = (const void**) PaUtil_AllocateMemory (sizeof (const void*) * outputChannelCount);
2431
 
 
2432
 
            if (!stream->blockingState->writeStreamBuffer) {
2433
 
                result = paInsufficientMemory;
2434
 
                PA_DEBUG ( ("ERROR! Blocking i/o write stream buffer allocation failed in OpenStream()\n"));
2435
 
                goto error;
2436
 
            }
2437
 
 
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.
2441
 
 
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
2449
 
                  to samples frames.
2450
 
               5) Get the next larger (or equal) power-of-two buffer size.
2451
 
             */
2452
 
            lBlockingBufferSize = suggestedOutputLatencyFrames - stream->outputLatency;
2453
 
            lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
2454
 
            lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
2455
 
            lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
2456
 
 
2457
 
            /* The buffer size (without the additional block) corresponds
2458
 
               to the initial number of silent samples in the output ring
2459
 
               buffer. */
2460
 
            stream->blockingState->writeRingBufferInitialFrames = lBlockingBufferSize - framesPerBuffer;
2461
 
 
2462
 
            /* Get the next larger or equal power-of-two buffersize. */
2463
 
            lBlockingBufferSizePow2 = 1;
2464
 
 
2465
 
            while (lBlockingBufferSize > (lBlockingBufferSizePow2<<=1));
2466
 
 
2467
 
            lBlockingBufferSize = lBlockingBufferSizePow2;
2468
 
 
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)
2475
 
                / sampleRate;
2476
 
 
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.
2480
 
            */
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))
2488
 
                       ));
2489
 
 
2490
 
            /* Determine the size of ring buffer in bytes. */
2491
 
            lBytesPerFrame = outputChannelCount * Pa_GetSampleSize (outputSampleFormat);
2492
 
 
2493
 
            /* Allocate the blocking i/o output ring buffer memory. */
2494
 
            stream->blockingState->writeRingBufferData = (void*) PaUtil_AllocateMemory (lBlockingBufferSize * lBytesPerFrame);
2495
 
 
2496
 
            if (!stream->blockingState->writeRingBufferData) {
2497
 
                result = paInsufficientMemory;
2498
 
                PA_DEBUG ( ("ERROR! Blocking i/o output ring buffer allocation failed in OpenStream()\n"));
2499
 
                goto error;
2500
 
            }
2501
 
 
2502
 
            /* Initialize the output ring buffer struct. */
2503
 
            PaUtil_InitializeRingBuffer (&stream->blockingState->writeRingBuffer    ,
2504
 
                                         lBytesPerFrame                            ,
2505
 
                                         lBlockingBufferSize                       ,
2506
 
                                         stream->blockingState->writeRingBufferData);
2507
 
        }
2508
 
 
2509
 
        stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
2510
 
 
2511
 
 
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);
2519
 
 
2520
 
        if (result != paNoError) {
2521
 
            PA_DEBUG ( ("OpenStream ERROR13\n"));
2522
 
            goto error;
2523
 
        }
2524
 
 
2525
 
        callbackBufferProcessorInited = TRUE;
2526
 
 
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;
2534
 
 
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)
2542
 
                   ));
2543
 
 
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)
2549
 
                   ));
2550
 
    }
2551
 
 
2552
 
    stream->asioHostApi = asioHostApi;
2553
 
    stream->framesPerHostCallback = framesPerHostBuffer;
2554
 
 
2555
 
    stream->inputChannelCount = inputChannelCount;
2556
 
    stream->outputChannelCount = outputChannelCount;
2557
 
    stream->postOutput = driverInfo->postOutput;
2558
 
    stream->isStopped = 1;
2559
 
    stream->isActive = 0;
2560
 
 
2561
 
    asioHostApi->openAsioDeviceIndex = asioDeviceIndex;
2562
 
 
2563
 
    theAsioStream = stream;
2564
 
    *s = (PaStream*) stream;
2565
 
 
2566
 
    return result;
2567
 
 
2568
 
error:
2569
 
    PA_DEBUG ( ("goto errored\n"));
2570
 
 
2571
 
    if (stream) {
2572
 
        if (stream->blockingState) {
2573
 
            if (blockingBufferProcessorInited)
2574
 
                PaUtil_TerminateBufferProcessor (&stream->blockingState->bufferProcessor);
2575
 
 
2576
 
            if (stream->blockingState->writeRingBufferData)
2577
 
                PaUtil_FreeMemory (stream->blockingState->writeRingBufferData);
2578
 
 
2579
 
            if (stream->blockingState->writeStreamBuffer)
2580
 
                PaUtil_FreeMemory (stream->blockingState->writeStreamBuffer);
2581
 
 
2582
 
            if (blockingWriteBuffersReadyEventInitialized)
2583
 
                CloseHandle (stream->blockingState->writeBuffersReadyEvent);
2584
 
 
2585
 
            if (stream->blockingState->readRingBufferData)
2586
 
                PaUtil_FreeMemory (stream->blockingState->readRingBufferData);
2587
 
 
2588
 
            if (stream->blockingState->readStreamBuffer)
2589
 
                PaUtil_FreeMemory (stream->blockingState->readStreamBuffer);
2590
 
 
2591
 
            if (blockingReadFramesReadyEventInitialized)
2592
 
                CloseHandle (stream->blockingState->readFramesReadyEvent);
2593
 
 
2594
 
            PaUtil_FreeMemory (stream->blockingState);
2595
 
        }
2596
 
 
2597
 
        if (callbackBufferProcessorInited)
2598
 
            PaUtil_TerminateBufferProcessor (&stream->bufferProcessor);
2599
 
 
2600
 
        if (completedBuffersPlayedEventInited)
2601
 
            CloseHandle (stream->completedBuffersPlayedEvent);
2602
 
 
2603
 
        if (stream->asioBufferInfos)
2604
 
            PaUtil_FreeMemory (stream->asioBufferInfos);
2605
 
 
2606
 
        if (stream->asioChannelInfos)
2607
 
            PaUtil_FreeMemory (stream->asioChannelInfos);
2608
 
 
2609
 
        if (stream->bufferPtrs)
2610
 
            PaUtil_FreeMemory (stream->bufferPtrs);
2611
 
 
2612
 
        PaUtil_FreeMemory (stream);
2613
 
    }
2614
 
 
2615
 
    if (asioBuffersCreated)
2616
 
        ASIODisposeBuffers();
2617
 
 
2618
 
    if (asioIsInitialized) {
2619
 
        UnloadAsioDriver();
2620
 
    }
2621
 
 
2622
 
    return result;
2623
 
}
2624
 
 
2625
 
 
2626
 
/*
2627
 
    When CloseStream() is called, the multi-api layer ensures that
2628
 
    the stream has already been stopped or aborted.
2629
 
*/
2630
 
static PaError CloseStream (PaStream* s)
2631
 
{
2632
 
    PaError result = paNoError;
2633
 
    PaAsioStream *stream = (PaAsioStream*) s;
2634
 
 
2635
 
    /*
2636
 
        IMPLEMENT ME:
2637
 
            - additional stream closing + cleanup
2638
 
    */
2639
 
 
2640
 
    PaUtil_TerminateBufferProcessor (&stream->bufferProcessor);
2641
 
    PaUtil_TerminateStreamRepresentation (&stream->streamRepresentation);
2642
 
 
2643
 
    stream->asioHostApi->openAsioDeviceIndex = paNoDevice;
2644
 
 
2645
 
    CloseHandle (stream->completedBuffersPlayedEvent);
2646
 
 
2647
 
    /* Using blocking i/o interface... */
2648
 
    if (stream->blockingState) {
2649
 
        PaUtil_TerminateBufferProcessor (&stream->blockingState->bufferProcessor);
2650
 
 
2651
 
        if (stream->inputChannelCount) {
2652
 
            PaUtil_FreeMemory (stream->blockingState->readRingBufferData);
2653
 
            PaUtil_FreeMemory (stream->blockingState->readStreamBuffer);
2654
 
            CloseHandle (stream->blockingState->readFramesReadyEvent);
2655
 
        }
2656
 
 
2657
 
        if (stream->outputChannelCount) {
2658
 
            PaUtil_FreeMemory (stream->blockingState->writeRingBufferData);
2659
 
            PaUtil_FreeMemory (stream->blockingState->writeStreamBuffer);
2660
 
            CloseHandle (stream->blockingState->writeBuffersReadyEvent);
2661
 
        }
2662
 
 
2663
 
        PaUtil_FreeMemory (stream->blockingState);
2664
 
    }
2665
 
 
2666
 
    PaUtil_FreeMemory (stream->asioBufferInfos);
2667
 
    PaUtil_FreeMemory (stream->asioChannelInfos);
2668
 
    PaUtil_FreeMemory (stream->bufferPtrs);
2669
 
    PaUtil_FreeMemory (stream);
2670
 
 
2671
 
    ASIODisposeBuffers();
2672
 
    UnloadAsioDriver();
2673
 
 
2674
 
    theAsioStream = 0;
2675
 
 
2676
 
    return result;
2677
 
}
2678
 
 
2679
 
 
2680
 
static void bufferSwitch (long index, ASIOBool directProcess)
2681
 
{
2682
 
//TAKEN FROM THE ASIO SDK
2683
 
 
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
2687
 
    // simplicity.
2688
 
 
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
2692
 
 
2693
 
    ASIOTime  timeInfo;
2694
 
    memset (&timeInfo, 0, sizeof (timeInfo));
2695
 
 
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;
2700
 
 
2701
 
    // Call the real callback
2702
 
    bufferSwitchTimeInfo (&timeInfo, index, directProcess);
2703
 
}
2704
 
 
2705
 
 
2706
 
// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
2707
 
#if NATIVE_INT64
2708
 
#define ASIO64toDouble(a)  (a)
2709
 
#else
2710
 
const double twoRaisedTo32 = 4294967296.;
2711
 
#define ASIO64toDouble(a)  ((a).lo + (a).hi * twoRaisedTo32)
2712
 
#endif
2713
 
 
2714
 
static ASIOTime *bufferSwitchTimeInfo (ASIOTime *timeInfo, long index, ASIOBool directProcess)
2715
 
{
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.
2719
 
 
2720
 
 
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.
2727
 
 
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.
2731
 
    */
2732
 
 
2733
 
    (void) directProcess; /* suppress unused parameter warning */
2734
 
 
2735
 
#if 0
2736
 
    // store the timeInfo for later use
2737
 
    asioDriverInfo.tInfo = *timeInfo;
2738
 
 
2739
 
    // get the time stamp of the buffer, not necessary if no
2740
 
    // synchronization to other media is required
2741
 
 
2742
 
    if (timeInfo->timeInfo.flags & kSystemTimeValid)
2743
 
        asioDriverInfo.nanoSeconds = ASIO64toDouble (timeInfo->timeInfo.systemTime);
2744
 
    else
2745
 
        asioDriverInfo.nanoSeconds = 0;
2746
 
 
2747
 
    if (timeInfo->timeInfo.flags & kSamplePositionValid)
2748
 
        asioDriverInfo.samples = ASIO64toDouble (timeInfo->timeInfo.samplePosition);
2749
 
    else
2750
 
        asioDriverInfo.samples = 0;
2751
 
 
2752
 
    if (timeInfo->timeCode.flags & kTcValid)
2753
 
        asioDriverInfo.tcSamples = ASIO64toDouble (timeInfo->timeCode.timeCodeSamples);
2754
 
    else
2755
 
        asioDriverInfo.tcSamples = 0;
2756
 
 
2757
 
    // get the system reference time
2758
 
    asioDriverInfo.sysRefTime = get_sys_reference_time();
2759
 
#endif
2760
 
 
2761
 
#if 0
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;
2766
 
    char tmp[128];
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;
2770
 
#endif
2771
 
 
2772
 
 
2773
 
    if (!theAsioStream)
2774
 
        return 0L;
2775
 
 
2776
 
    // Keep sample position
2777
 
    // FIXME: asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
2778
 
 
2779
 
 
2780
 
    // protect against reentrancy
2781
 
    if (PaAsio_AtomicIncrement (&theAsioStream->reenterCount)) {
2782
 
        theAsioStream->reenterError++;
2783
 
        //DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError));
2784
 
        return 0L;
2785
 
    }
2786
 
 
2787
 
    int buffersDone = 0;
2788
 
 
2789
 
    do {
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
2793
 
 
2794
 
            if (theAsioStream->inputChannelCount > 0)
2795
 
                theAsioStream->callbackFlags |= paInputOverflow;
2796
 
 
2797
 
            if (theAsioStream->outputChannelCount > 0)
2798
 
                theAsioStream->callbackFlags |= paOutputUnderflow;
2799
 
        } else {
2800
 
            if (theAsioStream->zeroOutput) {
2801
 
                ZeroOutputBuffers (theAsioStream, index);
2802
 
 
2803
 
                // Finally if the driver supports the ASIOOutputReady() optimization,
2804
 
                // do it here, all data are in place
2805
 
                if (theAsioStream->postOutput)
2806
 
                    ASIOOutputReady();
2807
 
 
2808
 
                if (theAsioStream->stopProcessing) {
2809
 
                    if (theAsioStream->stopPlayoutCount < 2) {
2810
 
                        ++theAsioStream->stopPlayoutCount;
2811
 
 
2812
 
                        if (theAsioStream->stopPlayoutCount == 2) {
2813
 
                            theAsioStream->isActive = 0;
2814
 
 
2815
 
                            if (theAsioStream->streamRepresentation.streamFinishedCallback != 0)
2816
 
                                theAsioStream->streamRepresentation.streamFinishedCallback (theAsioStream->streamRepresentation.userData);
2817
 
 
2818
 
                            theAsioStream->streamFinishedCallbackCalled = true;
2819
 
                            SetEvent (theAsioStream->completedBuffersPlayedEvent);
2820
 
                        }
2821
 
                    }
2822
 
                }
2823
 
            } else {
2824
 
 
2825
 
#if 0
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
2828
 
 
2829
 
// check that sample delta matches buffer size (otherwise we must have skipped
2830
 
// a buffer.
2831
 
                static double last_samples = -512;
2832
 
                double samples;
2833
 
//if( timeInfo->timeCode.flags & kTcValid )
2834
 
//    samples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
2835
 
//else
2836
 
                samples = ASIO64toDouble (timeInfo->timeInfo.samplePosition);
2837
 
                int delta = samples - last_samples;
2838
 
//printf( "%d\n", delta);
2839
 
                last_samples = samples;
2840
 
 
2841
 
                if (delta > theAsioStream->framesPerHostCallback) {
2842
 
                    if (theAsioStream->inputChannelCount > 0)
2843
 
                        theAsioStream->callbackFlags |= paInputOverflow;
2844
 
 
2845
 
                    if (theAsioStream->outputChannelCount > 0)
2846
 
                        theAsioStream->callbackFlags |= paOutputUnderflow;
2847
 
                }
2848
 
 
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;
2852
 
 
2853
 
                if (index == previousIndex) {
2854
 
                    if (theAsioStream->inputChannelCount > 0)
2855
 
                        theAsioStream->callbackFlags |= paInputOverflow;
2856
 
 
2857
 
                    if (theAsioStream->outputChannelCount > 0)
2858
 
                        theAsioStream->callbackFlags |= paOutputUnderflow;
2859
 
                }
2860
 
 
2861
 
                previousIndex = index;
2862
 
#endif
2863
 
 
2864
 
                int i;
2865
 
 
2866
 
                PaUtil_BeginCpuLoadMeasurement (&theAsioStream->cpuLoadMeasurer);
2867
 
 
2868
 
                PaStreamCallbackTimeInfo paTimeInfo;
2869
 
 
2870
 
                // asio systemTime is supposed to be measured according to the same
2871
 
                // clock as timeGetTime
2872
 
                paTimeInfo.currentTime = (ASIO64toDouble (timeInfo->timeInfo.systemTime) * .000000001);
2873
 
 
2874
 
                /* patch from Paul Boege */
2875
 
                paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime -
2876
 
                                                ( (double) theAsioStream->inputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
2877
 
 
2878
 
                paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime +
2879
 
                                                 ( (double) theAsioStream->outputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
2880
 
 
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;
2884
 
                */
2885
 
 
2886
 
                /* Disabled! Stopping and re-starting the stream causes an input overflow / output undeflow. S.Fischer */
2887
 
#if 0
2888
 
// detect underflows by checking inter-callback time > 2 buffer period
2889
 
                static double previousTime = -1;
2890
 
 
2891
 
                if (previousTime > 0) {
2892
 
 
2893
 
                    double delta = paTimeInfo.currentTime - previousTime;
2894
 
 
2895
 
                    if (delta >= 2. * (theAsioStream->framesPerHostCallback / theAsioStream->streamRepresentation.streamInfo.sampleRate)) {
2896
 
                        if (theAsioStream->inputChannelCount > 0)
2897
 
                            theAsioStream->callbackFlags |= paInputOverflow;
2898
 
 
2899
 
                        if (theAsioStream->outputChannelCount > 0)
2900
 
                            theAsioStream->callbackFlags |= paOutputUnderflow;
2901
 
                    }
2902
 
                }
2903
 
 
2904
 
                previousTime = paTimeInfo.currentTime;
2905
 
#endif
2906
 
 
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.
2910
 
 
2911
 
                if (theAsioStream->inputBufferConverter) {
2912
 
                    for (i=0; i<theAsioStream->inputChannelCount; i++) {
2913
 
                        theAsioStream->inputBufferConverter (theAsioStream->inputBufferPtrs[index][i],
2914
 
                                                             theAsioStream->inputShift, theAsioStream->framesPerHostCallback);
2915
 
                    }
2916
 
                }
2917
 
 
2918
 
                PaUtil_BeginBufferProcessing (&theAsioStream->bufferProcessor, &paTimeInfo, theAsioStream->callbackFlags);
2919
 
 
2920
 
                /* reset status flags once they've been passed to the callback */
2921
 
                theAsioStream->callbackFlags = 0;
2922
 
 
2923
 
                PaUtil_SetInputFrameCount (&theAsioStream->bufferProcessor, 0 /* default to host buffer size */);
2924
 
 
2925
 
                for (i=0; i<theAsioStream->inputChannelCount; ++i)
2926
 
                    PaUtil_SetNonInterleavedInputChannel (&theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i]);
2927
 
 
2928
 
                PaUtil_SetOutputFrameCount (&theAsioStream->bufferProcessor, 0 /* default to host buffer size */);
2929
 
 
2930
 
                for (i=0; i<theAsioStream->outputChannelCount; ++i)
2931
 
                    PaUtil_SetNonInterleavedOutputChannel (&theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i]);
2932
 
 
2933
 
                int callbackResult;
2934
 
 
2935
 
                if (theAsioStream->stopProcessing)
2936
 
                    callbackResult = paComplete;
2937
 
                else
2938
 
                    callbackResult = paContinue;
2939
 
 
2940
 
                unsigned long framesProcessed = PaUtil_EndBufferProcessing (&theAsioStream->bufferProcessor, &callbackResult);
2941
 
 
2942
 
                if (theAsioStream->outputBufferConverter) {
2943
 
                    for (i=0; i<theAsioStream->outputChannelCount; i++) {
2944
 
                        theAsioStream->outputBufferConverter (theAsioStream->outputBufferPtrs[index][i],
2945
 
                                                              theAsioStream->outputShift, theAsioStream->framesPerHostCallback);
2946
 
                    }
2947
 
                }
2948
 
 
2949
 
                PaUtil_EndCpuLoadMeasurement (&theAsioStream->cpuLoadMeasurer, framesProcessed);
2950
 
 
2951
 
                // Finally if the driver supports the ASIOOutputReady() optimization,
2952
 
                // do it here, all data are in place
2953
 
                if (theAsioStream->postOutput)
2954
 
                    ASIOOutputReady();
2955
 
 
2956
 
                if (callbackResult == paContinue) {
2957
 
                    /* nothing special to do */
2958
 
                } else if (callbackResult == paAbort) {
2959
 
                    /* finish playback immediately  */
2960
 
                    theAsioStream->isActive = 0;
2961
 
 
2962
 
                    if (theAsioStream->streamRepresentation.streamFinishedCallback != 0)
2963
 
                        theAsioStream->streamRepresentation.streamFinishedCallback (theAsioStream->streamRepresentation.userData);
2964
 
 
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;
2971
 
 
2972
 
                    if (PaUtil_IsBufferProcessorOutputEmpty (&theAsioStream->bufferProcessor)) {
2973
 
                        theAsioStream->zeroOutput = true;
2974
 
                        theAsioStream->stopPlayoutCount = 0;
2975
 
                    }
2976
 
                }
2977
 
            }
2978
 
        }
2979
 
 
2980
 
        ++buffersDone;
2981
 
    } while (PaAsio_AtomicDecrement (&theAsioStream->reenterCount) >= 0);
2982
 
 
2983
 
    return 0L;
2984
 
}
2985
 
 
2986
 
 
2987
 
static void sampleRateChanged (ASIOSampleRate sRate)
2988
 
{
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.
2996
 
 
2997
 
    (void) sRate; /* unused parameter */
2998
 
    PA_DEBUG ( ("sampleRateChanged : %d \n", sRate));
2999
 
}
3000
 
 
3001
 
static long asioMessages (long selector, long value, void* message, double* opt)
3002
 
{
3003
 
// TAKEN FROM THE ASIO SDK
3004
 
    // currently the parameters "value", "message" and "opt" are not used.
3005
 
    long ret = 0;
3006
 
 
3007
 
    (void) message; /* unused parameters */
3008
 
    (void) opt;
3009
 
 
3010
 
    PA_DEBUG ( ("asioMessages : %d , %d \n", selector, value));
3011
 
 
3012
 
    switch (selector) {
3013
 
        case kAsioSelectorSupported:
3014
 
 
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)
3023
 
                ret = 1L;
3024
 
 
3025
 
            break;
3026
 
 
3027
 
        case kAsioBufferSizeChange:
3028
 
            //printf("kAsioBufferSizeChange \n");
3029
 
            break;
3030
 
 
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.
3036
 
 
3037
 
            /*FIXME: commented the next line out */
3038
 
            //asioDriverInfo.stopped;  // In this sample the processing will just stop
3039
 
            ret = 1L;
3040
 
            break;
3041
 
 
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.
3049
 
            ret = 1L;
3050
 
            break;
3051
 
 
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.
3056
 
            ret = 1L;
3057
 
            //printf("kAsioLatenciesChanged \n");
3058
 
            break;
3059
 
 
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
3063
 
            // by the driver
3064
 
            ret = 2L;
3065
 
            break;
3066
 
 
3067
 
        case kAsioSupportsTimeInfo:
3068
 
            // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
3069
 
            // is supported.
3070
 
            // For compatibility with ASIO 1.0 drivers the host application should always support
3071
 
            // the "old" bufferSwitch method, too.
3072
 
            ret = 1;
3073
 
            break;
3074
 
 
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
3078
 
            // to do.
3079
 
            ret = 0;
3080
 
            break;
3081
 
    }
3082
 
 
3083
 
    return ret;
3084
 
}
3085
 
 
3086
 
 
3087
 
static PaError StartStream (PaStream *s)
3088
 
{
3089
 
    PaError result = paNoError;
3090
 
    PaAsioStream *stream = (PaAsioStream*) s;
3091
 
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
3092
 
    ASIOError asioError;
3093
 
 
3094
 
    if (stream->outputChannelCount > 0) {
3095
 
        ZeroOutputBuffers (stream, 0);
3096
 
        ZeroOutputBuffers (stream, 1);
3097
 
    }
3098
 
 
3099
 
    PaUtil_ResetBufferProcessor (&stream->bufferProcessor);
3100
 
    stream->stopProcessing = false;
3101
 
    stream->zeroOutput = false;
3102
 
 
3103
 
    /* Reentrancy counter initialisation */
3104
 
    stream->reenterCount = -1;
3105
 
    stream->reenterError = 0;
3106
 
 
3107
 
    stream->callbackFlags = 0;
3108
 
 
3109
 
    if (ResetEvent (stream->completedBuffersPlayedEvent) == 0) {
3110
 
        result = paUnanticipatedHostError;
3111
 
        PA_ASIO_SET_LAST_SYSTEM_ERROR (GetLastError());
3112
 
    }
3113
 
 
3114
 
 
3115
 
    /* Using blocking i/o interface... */
3116
 
    if (blockingState) {
3117
 
        /* Reset blocking i/o buffer processor. */
3118
 
        PaUtil_ResetBufferProcessor (&blockingState->bufferProcessor);
3119
 
 
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());
3126
 
            }
3127
 
 
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);
3131
 
        }
3132
 
 
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());
3139
 
            }
3140
 
 
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);
3144
 
 
3145
 
            /* Initialize the output ring buffer to "silence". */
3146
 
            PaUtil_AdvanceRingBufferWriteIndex (&blockingState->writeRingBuffer, blockingState->writeRingBufferInitialFrames);
3147
 
        }
3148
 
 
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;
3157
 
    }
3158
 
 
3159
 
 
3160
 
    if (result == paNoError) {
3161
 
        assert (theAsioStream == stream);  /* theAsioStream should be set correctly in OpenStream */
3162
 
 
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;
3167
 
 
3168
 
        asioError = ASIOStart();
3169
 
 
3170
 
        if (asioError != ASE_OK) {
3171
 
            stream->isStopped = 1;
3172
 
            stream->isActive = 0;
3173
 
 
3174
 
            result = paUnanticipatedHostError;
3175
 
            PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3176
 
        }
3177
 
    }
3178
 
 
3179
 
    return result;
3180
 
}
3181
 
 
3182
 
static void EnsureCallbackHasCompleted (PaAsioStream *stream)
3183
 
{
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
3186
 
    // example.
3187
 
    int count = 2000;  // only wait for 2 seconds, rather than hanging.
3188
 
 
3189
 
    while (stream->reenterCount != -1 && count > 0) {
3190
 
        Sleep (1);
3191
 
        --count;
3192
 
    }
3193
 
}
3194
 
 
3195
 
static PaError StopStream (PaStream *s)
3196
 
{
3197
 
    PaError result = paNoError;
3198
 
    PaAsioStream *stream = (PaAsioStream*) s;
3199
 
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
3200
 
    ASIOError asioError;
3201
 
 
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;
3211
 
 
3212
 
            /* Wait until requested number of buffers has been freed. Time
3213
 
               out after twice the blocking i/o ouput buffer could have
3214
 
               been consumed. */
3215
 
            DWORD timeout = (DWORD) (2 * blockingState->writeRingBuffer.bufferSize * 1000
3216
 
                                     / stream->streamRepresentation.streamInfo.sampleRate);
3217
 
            DWORD waitResult = WaitForSingleObject (blockingState->writeBuffersReadyEvent, timeout);
3218
 
 
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;
3227
 
            }
3228
 
        }
3229
 
 
3230
 
        stream->stopProcessing = true;
3231
 
 
3232
 
        /* wait for the stream to finish playing out enqueued buffers.
3233
 
            timeout after four times the stream latency.
3234
 
 
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.
3238
 
        */
3239
 
        if (WaitForSingleObject (stream->completedBuffersPlayedEvent,
3240
 
                                 (DWORD) (stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.))
3241
 
                == WAIT_TIMEOUT) {
3242
 
            PA_DEBUG ( ("WaitForSingleObject() timed out in StopStream()\n"));
3243
 
        }
3244
 
    }
3245
 
 
3246
 
    asioError = ASIOStop();
3247
 
 
3248
 
    if (asioError == ASE_OK) {
3249
 
        EnsureCallbackHasCompleted (stream);
3250
 
    } else {
3251
 
        result = paUnanticipatedHostError;
3252
 
        PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3253
 
    }
3254
 
 
3255
 
    stream->isStopped = 1;
3256
 
    stream->isActive = 0;
3257
 
 
3258
 
    if (!stream->streamFinishedCallbackCalled) {
3259
 
        if (stream->streamRepresentation.streamFinishedCallback != 0)
3260
 
            stream->streamRepresentation.streamFinishedCallback (stream->streamRepresentation.userData);
3261
 
    }
3262
 
 
3263
 
    return result;
3264
 
}
3265
 
 
3266
 
static PaError AbortStream (PaStream *s)
3267
 
{
3268
 
    PaError result = paNoError;
3269
 
    PaAsioStream *stream = (PaAsioStream*) s;
3270
 
    ASIOError asioError;
3271
 
 
3272
 
    stream->zeroOutput = true;
3273
 
 
3274
 
    asioError = ASIOStop();
3275
 
 
3276
 
    if (asioError == ASE_OK) {
3277
 
        EnsureCallbackHasCompleted (stream);
3278
 
    } else {
3279
 
        result = paUnanticipatedHostError;
3280
 
        PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3281
 
    }
3282
 
 
3283
 
    stream->isStopped = 1;
3284
 
    stream->isActive = 0;
3285
 
 
3286
 
    if (!stream->streamFinishedCallbackCalled) {
3287
 
        if (stream->streamRepresentation.streamFinishedCallback != 0)
3288
 
            stream->streamRepresentation.streamFinishedCallback (stream->streamRepresentation.userData);
3289
 
    }
3290
 
 
3291
 
    return result;
3292
 
}
3293
 
 
3294
 
 
3295
 
static PaError IsStreamStopped (PaStream *s)
3296
 
{
3297
 
    PaAsioStream *stream = (PaAsioStream*) s;
3298
 
 
3299
 
    return stream->isStopped;
3300
 
}
3301
 
 
3302
 
 
3303
 
static PaError IsStreamActive (PaStream *s)
3304
 
{
3305
 
    PaAsioStream *stream = (PaAsioStream*) s;
3306
 
 
3307
 
    return stream->isActive;
3308
 
}
3309
 
 
3310
 
 
3311
 
static PaTime GetStreamTime (PaStream *s)
3312
 
{
3313
 
    (void) s; /* unused parameter */
3314
 
    return (double) timeGetTime() * .001;
3315
 
}
3316
 
 
3317
 
 
3318
 
static double GetStreamCpuLoad (PaStream* s)
3319
 
{
3320
 
    PaAsioStream *stream = (PaAsioStream*) s;
3321
 
 
3322
 
    return PaUtil_GetCpuLoad (&stream->cpuLoadMeasurer);
3323
 
}
3324
 
 
3325
 
 
3326
 
/*
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.
3330
 
*/
3331
 
 
3332
 
static PaError ReadStream (PaStream      *s     ,
3333
 
                           void          *buffer,
3334
 
                           unsigned long  frames)
3335
 
{
3336
 
    PaError result = paNoError; /* Initial return value. */
3337
 
    PaAsioStream *stream = (PaAsioStream*) s; /* The PA ASIO stream. */
3338
 
 
3339
 
    /* Pointer to the blocking i/o data struct. */
3340
 
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
3341
 
 
3342
 
    /* Get blocking i/o buffer processor and ring buffer pointers. */
3343
 
    PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
3344
 
    PaUtilRingBuffer      *pRb = &blockingState->readRingBuffer;
3345
 
 
3346
 
    /* Ring buffer segment(s) used for writing. */
3347
 
    void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
3348
 
    void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
3349
 
 
3350
 
    /* Number of frames per ring buffer segment. */
3351
 
    long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
3352
 
    long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
3353
 
 
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;
3360
 
 
3361
 
    /* Copy the input argument to avoid pointer increment! */
3362
 
    const void *userBuffer;
3363
 
    unsigned int i; /* Just a counter. */
3364
 
 
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;
3368
 
 
3369
 
 
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;
3374
 
        return result;
3375
 
    }
3376
 
 
3377
 
    /* If the stream is a input stream. */
3378
 
    if (stream->inputChannelCount) {
3379
 
        /* Prepare buffer access. */
3380
 
        if (!pBp->userOutputIsInterleaved) {
3381
 
            userBuffer = blockingState->readStreamBuffer;
3382
 
 
3383
 
            for (i = 0; i<pBp->inputChannelCount; ++i) {
3384
 
                ( (void**) userBuffer) [i] = ( (void**) buffer) [i];
3385
 
            }
3386
 
        } /* Use the unchanged buffer. */
3387
 
        else {
3388
 
            userBuffer = buffer;
3389
 
        }
3390
 
 
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. */
3399
 
 
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 ); */
3404
 
 
3405
 
                /* Set the number of requested buffers. */
3406
 
                blockingState->readFramesRequested = lFramesPerBlock;
3407
 
 
3408
 
                /* Signalize that additional buffers are need. */
3409
 
                blockingState->readFramesRequestedFlag = TRUE;
3410
 
 
3411
 
                /* Wait until requested number of buffers has been freed. */
3412
 
                waitResult = WaitForSingleObject (blockingState->readFramesReadyEvent, timeout);
3413
 
 
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());
3419
 
                    return result;
3420
 
                } else if (waitResult == WAIT_TIMEOUT) {
3421
 
                    PA_DEBUG ( ("WaitForSingleObject() timed out in ReadStream()\n"));
3422
 
 
3423
 
                    /* If block processing has stopped, abort! */
3424
 
                    if (blockingState->stopFlag) {
3425
 
                        return result = paStreamIsStopped;
3426
 
                    }
3427
 
 
3428
 
                    /* If a timeout is encountered, give up eventually. */
3429
 
                    return result = paTimedOut;
3430
 
                }
3431
 
            }
3432
 
 
3433
 
            /* Now, the ring buffer contains the required amount of data
3434
 
               frames.
3435
 
               (Therefor we don't need to check the return argument of
3436
 
               PaUtil_GetRingBufferReadRegions(). ;-) )
3437
 
            */
3438
 
 
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.
3444
 
            */
3445
 
            PaUtil_GetRingBufferReadRegions (pRb                ,
3446
 
                                             lFramesPerBlock    ,
3447
 
                                             &pRingBufferData1st,
3448
 
                                             &lRingBufferSize1st,
3449
 
                                             &pRingBufferData2nd,
3450
 
                                             &lRingBufferSize2nd);
3451
 
 
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. */
3459
 
 
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. */
3469
 
            }
3470
 
 
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);
3475
 
 
3476
 
            /* Decrease number of unprocessed frames. */
3477
 
            lFramesRemaining -= lFramesCopied;
3478
 
 
3479
 
        } /* Continue with the next data chunk. */
3480
 
 
3481
 
        while (lFramesRemaining);
3482
 
 
3483
 
 
3484
 
        /* If there has been an input overflow within the callback */
3485
 
        if (blockingState->inputOverflowFlag) {
3486
 
            blockingState->inputOverflowFlag = FALSE;
3487
 
 
3488
 
            /* Return the corresponding error code. */
3489
 
            result = paInputOverflowed;
3490
 
        }
3491
 
 
3492
 
    } /* If this is not an input stream. */
3493
 
    else {
3494
 
        result = paCanNotReadFromAnOutputOnlyStream;
3495
 
    }
3496
 
 
3497
 
    return result;
3498
 
}
3499
 
 
3500
 
static PaError WriteStream (PaStream      *s     ,
3501
 
                            const void    *buffer,
3502
 
                            unsigned long  frames)
3503
 
{
3504
 
    PaError result = paNoError; /* Initial return value. */
3505
 
    PaAsioStream *stream = (PaAsioStream*) s; /* The PA ASIO stream. */
3506
 
 
3507
 
    /* Pointer to the blocking i/o data struct. */
3508
 
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
3509
 
 
3510
 
    /* Get blocking i/o buffer processor and ring buffer pointers. */
3511
 
    PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
3512
 
    PaUtilRingBuffer      *pRb = &blockingState->writeRingBuffer;
3513
 
 
3514
 
    /* Ring buffer segment(s) used for writing. */
3515
 
    void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
3516
 
    void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
3517
 
 
3518
 
    /* Number of frames per ring buffer segment. */
3519
 
    long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
3520
 
    long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
3521
 
 
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;
3528
 
 
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;
3532
 
 
3533
 
    /* Copy the input argument to avoid pointer increment! */
3534
 
    const void *userBuffer;
3535
 
    unsigned int i; /* Just a counter. */
3536
 
 
3537
 
 
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;
3542
 
        return result;
3543
 
    }
3544
 
 
3545
 
    /* If the stream is a output stream. */
3546
 
    if (stream->outputChannelCount) {
3547
 
        /* Prepare buffer access. */
3548
 
        if (!pBp->userOutputIsInterleaved) {
3549
 
            userBuffer = blockingState->writeStreamBuffer;
3550
 
 
3551
 
            for (i = 0; i<pBp->outputChannelCount; ++i) {
3552
 
                ( (const void**) userBuffer) [i] = ( (const void**) buffer) [i];
3553
 
            }
3554
 
        } /* Use the unchanged buffer. */
3555
 
        else {
3556
 
            userBuffer = buffer;
3557
 
        }
3558
 
 
3559
 
 
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. */
3568
 
 
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 ); */
3573
 
 
3574
 
                /* Set the number of requested buffers. */
3575
 
                blockingState->writeBuffersRequested = lFramesPerBlock;
3576
 
 
3577
 
                /* Signalize that additional buffers are need. */
3578
 
                blockingState->writeBuffersRequestedFlag = TRUE;
3579
 
 
3580
 
                /* Wait until requested number of buffers has been freed. */
3581
 
                waitResult = WaitForSingleObject (blockingState->writeBuffersReadyEvent, timeout);
3582
 
 
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());
3588
 
                    return result;
3589
 
                } else if (waitResult == WAIT_TIMEOUT) {
3590
 
                    PA_DEBUG ( ("WaitForSingleObject() timed out in WriteStream()\n"));
3591
 
 
3592
 
                    /* If block processing has stopped, abort! */
3593
 
                    if (blockingState->stopFlag) {
3594
 
                        return result = paStreamIsStopped;
3595
 
                    }
3596
 
 
3597
 
                    /* If a timeout is encountered, give up eventually. */
3598
 
                    return result = paTimedOut;
3599
 
                }
3600
 
            }
3601
 
 
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(). ;-) )
3606
 
            */
3607
 
 
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.
3613
 
            */
3614
 
            PaUtil_GetRingBufferWriteRegions (pRb                ,
3615
 
                                              lFramesPerBlock    ,
3616
 
                                              &pRingBufferData1st,
3617
 
                                              &lRingBufferSize1st,
3618
 
                                              &pRingBufferData2nd,
3619
 
                                              &lRingBufferSize2nd);
3620
 
 
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. */
3628
 
 
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. */
3638
 
            }
3639
 
 
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);
3644
 
 
3645
 
            /* Decrease number of unprocessed frames. */
3646
 
            lFramesRemaining -= lFramesCopied;
3647
 
 
3648
 
        } /* Continue with the next data chunk. */
3649
 
 
3650
 
        while (lFramesRemaining);
3651
 
 
3652
 
 
3653
 
        /* If there has been an output underflow within the callback */
3654
 
        if (blockingState->outputUnderflowFlag) {
3655
 
            blockingState->outputUnderflowFlag = FALSE;
3656
 
 
3657
 
            /* Return the corresponding error code. */
3658
 
            result = paOutputUnderflowed;
3659
 
        }
3660
 
 
3661
 
    } /* If this is not an output stream. */
3662
 
    else {
3663
 
        result = paCanNotWriteToAnInputOnlyStream;
3664
 
    }
3665
 
 
3666
 
    return result;
3667
 
}
3668
 
 
3669
 
 
3670
 
static signed long GetStreamReadAvailable (PaStream* s)
3671
 
{
3672
 
    PaAsioStream *stream = (PaAsioStream*) s;
3673
 
 
3674
 
    /* Call buffer utility routine to get the number of available frames. */
3675
 
    return PaUtil_GetRingBufferReadAvailable (&stream->blockingState->readRingBuffer);
3676
 
}
3677
 
 
3678
 
 
3679
 
static signed long GetStreamWriteAvailable (PaStream* s)
3680
 
{
3681
 
    PaAsioStream *stream = (PaAsioStream*) s;
3682
 
 
3683
 
    /* Call buffer utility routine to get the number of empty buffers. */
3684
 
    return PaUtil_GetRingBufferWriteAvailable (&stream->blockingState->writeRingBuffer);
3685
 
}
3686
 
 
3687
 
 
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().
3691
 
*/
3692
 
static int BlockingIoPaCallback (const void                     *inputBuffer    ,
3693
 
                                 void                     *outputBuffer   ,
3694
 
                                 unsigned long             framesPerBuffer,
3695
 
                                 const PaStreamCallbackTimeInfo *timeInfo       ,
3696
 
                                 PaStreamCallbackFlags     statusFlags    ,
3697
 
                                 void                     *userData)
3698
 
{
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. */
3702
 
 
3703
 
    /* Get a pointer to the stream's blocking i/o buffer processor. */
3704
 
    PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
3705
 
    PaUtilRingBuffer      *pRb = NULL;
3706
 
 
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;
3713
 
        }
3714
 
 
3715
 
        /* Access the corresponding ring buffer. */
3716
 
        pRb = &blockingState->writeRingBuffer;
3717
 
 
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;
3725
 
 
3726
 
            /* Fill the output buffer with silence. */
3727
 
            (*pBp->outputZeroer) (outputBuffer, 1, pBp->outputChannelCount * framesPerBuffer);
3728
 
 
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));
3734
 
            }
3735
 
        }
3736
 
 
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 */
3747
 
        }
3748
 
    }
3749
 
 
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;
3756
 
        }
3757
 
 
3758
 
        /* Access the corresponding ring buffer. */
3759
 
        pRb = &blockingState->readRingBuffer;
3760
 
 
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;
3765
 
 
3766
 
            /* Remove some old data frames from the buffer. */
3767
 
            PaUtil_AdvanceRingBufferReadIndex (pRb, framesPerBuffer);
3768
 
        }
3769
 
 
3770
 
        /* Insert the current input data into the ring buffer. */
3771
 
        PaUtil_WriteRingBuffer (pRb, inputBuffer, framesPerBuffer);
3772
 
 
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 */
3784
 
        }
3785
 
    }
3786
 
 
3787
 
    return paContinue;
3788
 
}
3789
 
 
3790
 
 
3791
 
PaError PaAsio_ShowControlPanel (PaDeviceIndex device, void* systemSpecific)
3792
 
{
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;
3801
 
 
3802
 
 
3803
 
    result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
3804
 
 
3805
 
    if (result != paNoError)
3806
 
        goto error;
3807
 
 
3808
 
    result = PaUtil_DeviceIndexToHostApiDeviceIndex (&hostApiDevice, device, hostApi);
3809
 
 
3810
 
    if (result != paNoError)
3811
 
        goto error;
3812
 
 
3813
 
    /*
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.
3819
 
    */
3820
 
 
3821
 
    asioHostApi = (PaAsioHostApiRepresentation*) hostApi;
3822
 
 
3823
 
    if (asioHostApi->openAsioDeviceIndex != paNoDevice) {
3824
 
        result = paDeviceUnavailable;
3825
 
        goto error;
3826
 
    }
3827
 
 
3828
 
    asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[hostApiDevice];
3829
 
 
3830
 
    /* See notes about CoInitialize(0) in LoadAsioDriver(). */
3831
 
    CoInitialize (0);
3832
 
 
3833
 
    if (!asioHostApi->asioDrivers->loadDriver (const_cast<char*> (asioDeviceInfo->commonDeviceInfo.name))) {
3834
 
        result = paUnanticipatedHostError;
3835
 
        goto error;
3836
 
    }
3837
 
 
3838
 
    /* CRUCIAL!!! */
3839
 
    memset (&asioDriverInfo, 0, sizeof (ASIODriverInfo));
3840
 
    asioDriverInfo.asioVersion = 2;
3841
 
    asioDriverInfo.sysRef = systemSpecific;
3842
 
    asioError = ASIOInit (&asioDriverInfo);
3843
 
 
3844
 
    if (asioError != ASE_OK) {
3845
 
        result = paUnanticipatedHostError;
3846
 
        PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3847
 
        goto error;
3848
 
    } else {
3849
 
        asioIsInitialized = 1;
3850
 
    }
3851
 
 
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));
3857
 
 
3858
 
    asioError = ASIOControlPanel();
3859
 
 
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);
3864
 
        goto error;
3865
 
    }
3866
 
 
3867
 
    PA_DEBUG ( ("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText (asioError)));
3868
 
 
3869
 
    asioError = ASIOExit();
3870
 
 
3871
 
    if (asioError != ASE_OK) {
3872
 
        result = paUnanticipatedHostError;
3873
 
        PA_ASIO_SET_LAST_ASIO_ERROR (asioError);
3874
 
        asioIsInitialized = 0;
3875
 
        goto error;
3876
 
    }
3877
 
 
3878
 
    CoUninitialize();
3879
 
    PA_DEBUG ( ("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText (asioError)));
3880
 
 
3881
 
    return result;
3882
 
 
3883
 
error:
3884
 
 
3885
 
    if (asioIsInitialized) {
3886
 
        ASIOExit();
3887
 
    }
3888
 
 
3889
 
    CoUninitialize();
3890
 
 
3891
 
    return result;
3892
 
}
3893
 
 
3894
 
 
3895
 
PaError PaAsio_GetInputChannelName (PaDeviceIndex device, int channelIndex,
3896
 
                                    const char** channelName)
3897
 
{
3898
 
    PaError result = paNoError;
3899
 
    PaUtilHostApiRepresentation *hostApi;
3900
 
    PaDeviceIndex hostApiDevice;
3901
 
    PaAsioDeviceInfo *asioDeviceInfo;
3902
 
 
3903
 
 
3904
 
    result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
3905
 
 
3906
 
    if (result != paNoError)
3907
 
        goto error;
3908
 
 
3909
 
    result = PaUtil_DeviceIndexToHostApiDeviceIndex (&hostApiDevice, device, hostApi);
3910
 
 
3911
 
    if (result != paNoError)
3912
 
        goto error;
3913
 
 
3914
 
    asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[hostApiDevice];
3915
 
 
3916
 
    if (channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxInputChannels) {
3917
 
        result = paInvalidChannelCount;
3918
 
        goto error;
3919
 
    }
3920
 
 
3921
 
    *channelName = asioDeviceInfo->asioChannelInfos[channelIndex].name;
3922
 
 
3923
 
    return paNoError;
3924
 
 
3925
 
error:
3926
 
    return result;
3927
 
}
3928
 
 
3929
 
 
3930
 
PaError PaAsio_GetOutputChannelName (PaDeviceIndex device, int channelIndex,
3931
 
                                     const char** channelName)
3932
 
{
3933
 
    PaError result = paNoError;
3934
 
    PaUtilHostApiRepresentation *hostApi;
3935
 
    PaDeviceIndex hostApiDevice;
3936
 
    PaAsioDeviceInfo *asioDeviceInfo;
3937
 
 
3938
 
 
3939
 
    result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
3940
 
 
3941
 
    if (result != paNoError)
3942
 
        goto error;
3943
 
 
3944
 
    result = PaUtil_DeviceIndexToHostApiDeviceIndex (&hostApiDevice, device, hostApi);
3945
 
 
3946
 
    if (result != paNoError)
3947
 
        goto error;
3948
 
 
3949
 
    asioDeviceInfo = (PaAsioDeviceInfo*) hostApi->deviceInfos[hostApiDevice];
3950
 
 
3951
 
    if (channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxOutputChannels) {
3952
 
        result = paInvalidChannelCount;
3953
 
        goto error;
3954
 
    }
3955
 
 
3956
 
    *channelName = asioDeviceInfo->asioChannelInfos[
3957
 
                       asioDeviceInfo->commonDeviceInfo.maxInputChannels + channelIndex].name;
3958
 
 
3959
 
    return paNoError;
3960
 
 
3961
 
error:
3962
 
    return result;
3963
 
}
3964
 
 
3965
 
 
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.
3969
 
*/
3970
 
 
3971
 
static PaError GetAsioStreamPointer (PaAsioStream **stream, PaStream *s)
3972
 
{
3973
 
    PaError result;
3974
 
    PaUtilHostApiRepresentation *hostApi;
3975
 
    PaAsioHostApiRepresentation *asioHostApi;
3976
 
 
3977
 
    result = PaUtil_ValidateStreamPointer (s);
3978
 
 
3979
 
    if (result != paNoError)
3980
 
        return result;
3981
 
 
3982
 
    result = PaUtil_GetHostApiRepresentation (&hostApi, paASIO);
3983
 
 
3984
 
    if (result != paNoError)
3985
 
        return result;
3986
 
 
3987
 
    asioHostApi = (PaAsioHostApiRepresentation*) hostApi;
3988
 
 
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;
3993
 
        return paNoError;
3994
 
    } else {
3995
 
        return paIncompatibleStreamHostApi;
3996
 
    }
3997
 
}
3998
 
 
3999
 
 
4000
 
PaError PaAsio_SetStreamSampleRate (PaStream* s, double sampleRate)
4001
 
{
4002
 
    PaAsioStream *stream;
4003
 
    PaError result = GetAsioStreamPointer (&stream, s);
4004
 
 
4005
 
    if (result != paNoError)
4006
 
        return result;
4007
 
 
4008
 
    if (stream != theAsioStream)
4009
 
        return paBadStreamPtr;
4010
 
 
4011
 
    return ValidateAndSetSampleRate (sampleRate);
4012
 
}
4013