1 /*
2 * $Id: pa_lib.c,v 1.3.4.2 2003/03/15 02:50:14 pieter Exp $
3 * Portable Audio I/O Library
4 * Host Independant Layer
5 *
6 * Based on the Open Source API proposed by Ross Bencina
7 * Copyright (c) 1999-2000 Phil Burk
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files
11 * (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * Any person wishing to distribute modifications to the Software is
21 * requested to send the modifications to the original developer so that
22 * they can be incorporated into the canonical version.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
28 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 *
32 */
33
34 /* Modification History:
35 PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
36 PLB20010820 - fix dither and shift for recording PaUInt8 format
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <math.h>
43
44 /* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
45 #ifdef _WIN32
46 #ifndef __MWERKS__
47 #include <memory.h>
48 #endif /* __MWERKS__ */
49 #else /* !_WIN32 */
50 #include <memory.h>
51 #endif /* _WIN32 */
52
53 #include "portaudio.h"
54 #include "pa_host.h"
55 #include "pa_trace.h"
56
57 /* The reason we might NOT want to validate the rate before opening the stream
58 * is because many DirectSound drivers lie about the rates they actually support.
59 */
60 #define PA_VALIDATE_RATE (0) /* If true validate sample rate against driver info. */
61
62 /*
63 O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion
64 */
65
66 #ifndef FALSE
67 #define FALSE (0)
68 #define TRUE (!FALSE)
69 #endif
70
71 #define PRINT(x) { printf x; fflush(stdout); }
72 #define ERR_RPT(x) PRINT(x)
73 #define DBUG(x) /* PRINT(x) */
74 #define DBUGX(x) /* PRINT(x) */
75
76 static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */
77
78 static PaError Pa_KillStream( PortAudioStream *stream, int abort );
79
80 /***********************************************************************/
PaHost_FindClosestTableEntry(double allowableError,const double * rateTable,int numRates,double frameRate)81 int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate )
82 {
83 double err, minErr = allowableError;
84 int i, bestFit = -1;
85
86 for( i=0; i<numRates; i++ )
87 {
88 err = fabs( frameRate - rateTable[i] );
89 if( err < minErr )
90 {
91 minErr = err;
92 bestFit = i;
93 }
94 }
95 return bestFit;
96 }
97
98 /**************************************************************************
99 ** Make sure sample rate is legal and also convert to enumeration for driver.
100 */
PaHost_ValidateSampleRate(PaDeviceID id,double requestedFrameRate,double * closestFrameRatePtr)101 PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
102 double *closestFrameRatePtr )
103 {
104 long bestRateIndex;
105 const PaDeviceInfo *pdi;
106 pdi = Pa_GetDeviceInfo( id );
107 if( pdi == NULL )
108 {
109 return paInvalidDeviceId;
110 }
111
112 if( pdi->numSampleRates == -1 )
113 {
114 /* Is it out of range? */
115 if( (requestedFrameRate < pdi->sampleRates[0]) ||
116 (requestedFrameRate > pdi->sampleRates[1]) )
117 {
118 return paInvalidSampleRate;
119 }
120
121 *closestFrameRatePtr = requestedFrameRate;
122 }
123 else
124 {
125 bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate );
126 if( bestRateIndex < 0 ) return paInvalidSampleRate;
127 *closestFrameRatePtr = pdi->sampleRates[bestRateIndex];
128 }
129 return paNoError;
130 }
131
132 /*************************************************************************/
Pa_OpenStream(PortAudioStream ** streamPtrPtr,PaDeviceID inputDeviceID,int numInputChannels,PaSampleFormat inputSampleFormat,void * inputDriverInfo,PaDeviceID outputDeviceID,int numOutputChannels,PaSampleFormat outputSampleFormat,void * outputDriverInfo,double sampleRate,unsigned long framesPerBuffer,unsigned long numberOfBuffers,unsigned long streamFlags,PortAudioCallback * callback,void * userData)133 PaError Pa_OpenStream(
134 PortAudioStream** streamPtrPtr,
135 PaDeviceID inputDeviceID,
136 int numInputChannels,
137 PaSampleFormat inputSampleFormat,
138 void *inputDriverInfo,
139 PaDeviceID outputDeviceID,
140 int numOutputChannels,
141 PaSampleFormat outputSampleFormat,
142 void *outputDriverInfo,
143 double sampleRate,
144 unsigned long framesPerBuffer,
145 unsigned long numberOfBuffers,
146 unsigned long streamFlags,
147 PortAudioCallback *callback,
148 void *userData )
149 {
150 internalPortAudioStream *past = NULL;
151 PaError result = paNoError;
152 int bitsPerInputSample;
153 int bitsPerOutputSample;
154 /* Print passed parameters. */
155 DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n",
156 streamPtrPtr, inputDeviceID, numInputChannels,
157 inputSampleFormat, inputDriverInfo ));
158 DBUG((" %d, %d, %d, %p, /* output */\n",
159 outputDeviceID, numOutputChannels,
160 outputSampleFormat, outputDriverInfo ));
161 DBUG((" %g, %d, %d, 0x%x, , %p )\n",
162 sampleRate, framesPerBuffer, numberOfBuffers,
163 streamFlags, userData ));
164
165 /* Check for parameter errors. */
166 if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag;
167 if( streamPtrPtr == NULL ) return paBadStreamPtr;
168 if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */
169 if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */
170 if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId;
171 if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) )
172 {
173 return paInvalidDeviceId;
174 }
175 if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount;
176
177 #if SUPPORT_AUDIO_CAPTURE
178 if( inputDeviceID >= 0 )
179 {
180 PaError size = Pa_GetSampleSize( inputSampleFormat );
181 if( size < 0 ) return size;
182 bitsPerInputSample = 8 * size;
183 if( (numInputChannels <= 0) ) return paInvalidChannelCount;
184 }
185 #else
186 if( inputDeviceID >= 0 )
187 {
188 return paInvalidChannelCount;
189 }
190 #endif /* SUPPORT_AUDIO_CAPTURE */
191 else
192 {
193 if( numInputChannels > 0 ) return paInvalidChannelCount;
194 bitsPerInputSample = 0;
195 }
196
197 if( outputDeviceID >= 0 )
198 {
199 PaError size = Pa_GetSampleSize( outputSampleFormat );
200 if( size < 0 ) return size;
201 bitsPerOutputSample = 8 * size;
202 if( (numOutputChannels <= 0) ) return paInvalidChannelCount;
203 }
204 else
205 {
206 if( numOutputChannels > 0 ) return paInvalidChannelCount;
207 bitsPerOutputSample = 0;
208 }
209
210 if( callback == NULL ) return paNullCallback;
211
212 /* Allocate and clear stream structure. */
213 past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) );
214 if( past == NULL ) return paInsufficientMemory;
215 memset( past, 0, sizeof(internalPortAudioStream) );
216 AddTraceMessage("Pa_OpenStream: past", (long) past );
217
218 past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */
219 past->past_FramesPerUserBuffer = framesPerBuffer;
220 past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() MUST CHECK FOR ZERO! */
221 past->past_Callback = callback;
222 past->past_UserData = userData;
223 past->past_OutputSampleFormat = outputSampleFormat;
224 past->past_InputSampleFormat = inputSampleFormat;
225 past->past_OutputDeviceID = outputDeviceID;
226 past->past_InputDeviceID = inputDeviceID;
227 past->past_NumInputChannels = numInputChannels;
228 past->past_NumOutputChannels = numOutputChannels;
229 past->past_Flags = streamFlags;
230
231 /* Check for absurd sample rates. */
232 if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
233 {
234 result = paInvalidSampleRate;
235 goto cleanup;
236 }
237
238 /* Allocate buffers that may be used for format conversion from user to native buffers. */
239 if( numInputChannels > 0 )
240 {
241
242 #if PA_VALIDATE_RATE
243 result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate );
244 if( result < 0 )
245 {
246 goto cleanup;
247 }
248 #else
249 past->past_SampleRate = sampleRate;
250 #endif
251 /* Allocate single Input buffer for passing formatted samples to user callback. */
252 past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
253 past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
254 if( past->past_InputBuffer == NULL )
255 {
256 result = paInsufficientMemory;
257 goto cleanup;
258 }
259 }
260 else
261 {
262 past->past_InputBuffer = NULL;
263 }
264
265 /* Allocate single Output buffer. */
266 if( numOutputChannels > 0 )
267 {
268 #if PA_VALIDATE_RATE
269 result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate );
270 if( result < 0 )
271 {
272 goto cleanup;
273 }
274 #else
275 past->past_SampleRate = sampleRate;
276 #endif
277 past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8);
278 past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize);
279 if( past->past_OutputBuffer == NULL )
280 {
281 result = paInsufficientMemory;
282 goto cleanup;
283 }
284 }
285 else
286 {
287 past->past_OutputBuffer = NULL;
288 }
289
290 result = PaHost_OpenStream( past );
291 if( result < 0 ) goto cleanup;
292
293 *streamPtrPtr = (void *) past;
294
295 return result;
296
297 cleanup:
298 if( past != NULL ) Pa_CloseStream( past );
299 *streamPtrPtr = NULL;
300 return result;
301 }
302
303
304 /*************************************************************************/
Pa_OpenDefaultStream(PortAudioStream ** stream,int numInputChannels,int numOutputChannels,PaSampleFormat sampleFormat,double sampleRate,unsigned long framesPerBuffer,unsigned long numberOfBuffers,PortAudioCallback * callback,void * userData)305 PaError Pa_OpenDefaultStream( PortAudioStream** stream,
306 int numInputChannels,
307 int numOutputChannels,
308 PaSampleFormat sampleFormat,
309 double sampleRate,
310 unsigned long framesPerBuffer,
311 unsigned long numberOfBuffers,
312 PortAudioCallback *callback,
313 void *userData )
314 {
315 return Pa_OpenStream(
316 stream,
317 ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice),
318 numInputChannels, sampleFormat, NULL,
319 ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
320 numOutputChannels, sampleFormat, NULL,
321 sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData );
322 }
323
324 /*************************************************************************/
Pa_CloseStream(PortAudioStream * stream)325 PaError Pa_CloseStream( PortAudioStream* stream)
326 {
327 PaError result;
328 internalPortAudioStream *past;
329
330 DBUG(("Pa_CloseStream()\n"));
331 if( stream == NULL ) return paBadStreamPtr;
332 past = (internalPortAudioStream *) stream;
333
334 Pa_AbortStream( past );
335 result = PaHost_CloseStream( past );
336
337 if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize );
338 if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize );
339 PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) );
340
341 return result;
342 }
343
344 /*************************************************************************/
Pa_StartStream(PortAudioStream * stream)345 PaError Pa_StartStream( PortAudioStream *stream )
346 {
347 PaError result = paHostError;
348 internalPortAudioStream *past;
349
350 if( stream == NULL ) return paBadStreamPtr;
351 past = (internalPortAudioStream *) stream;
352
353 past->past_FrameCount = 0.0;
354
355 if( past->past_NumInputChannels > 0 )
356 {
357 result = PaHost_StartInput( past );
358 DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result));
359 if( result < 0 ) goto error;
360 }
361
362 if( past->past_NumOutputChannels > 0 )
363 {
364 result = PaHost_StartOutput( past );
365 DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result));
366 if( result < 0 ) goto error;
367 }
368
369 result = PaHost_StartEngine( past );
370 DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result));
371 if( result < 0 ) goto error;
372
373 return paNoError;
374
375 error:
376 return result;
377 }
378
379 /*************************************************************************/
Pa_StopStream(PortAudioStream * stream)380 PaError Pa_StopStream( PortAudioStream *stream )
381 {
382 return Pa_KillStream( stream, 0 );
383 }
384
385 /*************************************************************************/
Pa_AbortStream(PortAudioStream * stream)386 PaError Pa_AbortStream( PortAudioStream *stream )
387 {
388 return Pa_KillStream( stream, 1 );
389 }
390
391 /*************************************************************************/
Pa_KillStream(PortAudioStream * stream,int abort)392 static PaError Pa_KillStream( PortAudioStream *stream, int abort )
393 {
394 PaError result = paNoError;
395 internalPortAudioStream *past;
396
397 DBUG(("Pa_StopStream().\n"));
398 if( stream == NULL ) return paBadStreamPtr;
399 past = (internalPortAudioStream *) stream;
400
401 if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) )
402 {
403 result = PaHost_StopEngine( past, abort );
404 DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result));
405 if( result < 0 ) goto error;
406 }
407
408 if( past->past_NumInputChannels > 0 )
409 {
410 result = PaHost_StopInput( past, abort );
411 DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result));
412 if( result != paNoError ) goto error;
413 }
414
415 if( past->past_NumOutputChannels > 0 )
416 {
417 result = PaHost_StopOutput( past, abort );
418 DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result));
419 if( result != paNoError ) goto error;
420 }
421
422 error:
423 past->past_Usage = 0;
424 past->past_IfLastExitValid = 0;
425
426 return result;
427 }
428
429 /*************************************************************************/
Pa_StreamActive(PortAudioStream * stream)430 PaError Pa_StreamActive( PortAudioStream *stream )
431 {
432 internalPortAudioStream *past;
433 if( stream == NULL ) return paBadStreamPtr;
434 past = (internalPortAudioStream *) stream;
435 return PaHost_StreamActive( past );
436 }
437
438 /*************************************************************************/
Pa_GetErrorText(PaError errnum)439 const char *Pa_GetErrorText( PaError errnum )
440 {
441 const char *msg;
442
443 switch(errnum)
444 {
445 case paNoError: msg = "Success"; break;
446 case paHostError: msg = "Host error."; break;
447 case paInvalidChannelCount: msg = "Invalid number of channels."; break;
448 case paInvalidSampleRate: msg = "Invalid sample rate."; break;
449 case paInvalidDeviceId: msg = "Invalid device ID."; break;
450 case paInvalidFlag: msg = "Invalid flag."; break;
451 case paSampleFormatNotSupported: msg = "Sample format not supported"; break;
452 case paBadIODeviceCombination: msg = "Illegal combination of I/O devices."; break;
453 case paInsufficientMemory: msg = "Insufficient memory."; break;
454 case paBufferTooBig: msg = "Buffer too big."; break;
455 case paBufferTooSmall: msg = "Buffer too small."; break;
456 case paNullCallback: msg = "No callback routine specified."; break;
457 case paBadStreamPtr: msg = "Invalid stream pointer."; break;
458 case paTimedOut : msg = "Wait Timed Out."; break;
459 case paInternalError: msg = "Internal PortAudio Error."; break;
460 case paDeviceUnavailable: msg = "Device Unavailable."; break;
461 default: msg = "Illegal error number."; break;
462 }
463 return msg;
464 }
465
466 /*
467 Get CPU Load as a fraction of total CPU time.
468 A value of 0.5 would imply that PortAudio and the sound generating
469 callback was consuming roughly 50% of the available CPU time.
470 The amount may vary depending on CPU load.
471 This function may be called from the callback function.
472 */
Pa_GetCPULoad(PortAudioStream * stream)473 double Pa_GetCPULoad( PortAudioStream* stream)
474 {
475 internalPortAudioStream *past;
476 if( stream == NULL ) return (double) paBadStreamPtr;
477 past = (internalPortAudioStream *) stream;
478 return past->past_Usage;
479 }
480
481 /*************************************************************************/
PaHost_GetStreamRepresentation(PortAudioStream * stream)482 internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream )
483 {
484 internalPortAudioStream* result = (internalPortAudioStream*) stream;
485
486 if( result == NULL || result->past_Magic != PA_MAGIC )
487 return NULL;
488 else
489 return result;
490 }
491
492 /*************************************************************
493 ** Calculate 2 LSB dither signal with a triangular distribution.
494 ** Ranged properly for adding to a 32 bit integer prior to >>15.
495 ** Range of output is +/- 32767
496 */
497 #define PA_DITHER_BITS (15)
498 #define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
PaConvert_TriangularDither(void)499 long PaConvert_TriangularDither( void )
500 {
501 static unsigned long previous = 0;
502 static unsigned long randSeed1 = 22222;
503 static unsigned long randSeed2 = 5555555;
504 long current, highPass;
505 /* Generate two random numbers. */
506 randSeed1 = (randSeed1 * 196314165) + 907633515;
507 randSeed2 = (randSeed2 * 196314165) + 907633515;
508 /* Generate triangular distribution about 0.
509 * Shift before adding to prevent overflow which would skew the distribution.
510 * Also shift an extra bit for the high pass filter.
511 */
512 #define DITHER_SHIFT ((32 - PA_DITHER_BITS) + 1)
513 current = (((long)randSeed1)>>DITHER_SHIFT) + (((long)randSeed2)>>DITHER_SHIFT);
514 /* High pass filter to reduce audibility. */
515 highPass = current - previous;
516 previous = current;
517 return highPass;
518 }
519
520 /*************************************************************************
521 ** Called by host code.
522 ** Convert input from Int16, call user code, then convert output
523 ** to Int16 format for native use.
524 ** Assumes host native format is paInt16.
525 ** Returns result from user callback.
526 */
Pa_CallConvertInt16(internalPortAudioStream * past,short * nativeInputBuffer,short * nativeOutputBuffer)527 long Pa_CallConvertInt16( internalPortAudioStream *past,
528 short *nativeInputBuffer,
529 short *nativeOutputBuffer )
530 {
531 long temp;
532 int userResult;
533 unsigned int i;
534 void *inputBuffer = NULL;
535 void *outputBuffer = NULL;
536
537 #if SUPPORT_AUDIO_CAPTURE
538 /* Get native data from DirectSound. */
539 if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
540 {
541 /* Convert from native format to PA format. */
542 unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels;
543 switch(past->past_InputSampleFormat)
544 {
545
546 case paFloat32:
547 {
548 float *inBufPtr = (float *) past->past_InputBuffer;
549 inputBuffer = past->past_InputBuffer;
550 for( i=0; i<samplesPerBuffer; i++ )
551 {
552 inBufPtr[i] = nativeInputBuffer[i] * (1.0f / 32767.0f);
553 }
554 break;
555 }
556
557 case paInt32:
558 {
559 /* Convert 16 bit data to 32 bit integers */
560 int *inBufPtr = (int *) past->past_InputBuffer;
561 inputBuffer = past->past_InputBuffer;
562 for( i=0; i<samplesPerBuffer; i++ )
563 {
564 inBufPtr[i] = nativeInputBuffer[i] << 16;
565 }
566 break;
567 }
568
569 case paInt16:
570 {
571 /* Already in correct format so don't copy. */
572 inputBuffer = nativeInputBuffer;
573 break;
574 }
575
576 case paInt8:
577 {
578 /* Convert 16 bit data to 8 bit chars */
579 char *inBufPtr = (char *) past->past_InputBuffer;
580 inputBuffer = past->past_InputBuffer;
581 if( past->past_Flags & paDitherOff )
582 {
583 for( i=0; i<samplesPerBuffer; i++ )
584 {
585 inBufPtr[i] = (char)(nativeInputBuffer[i] >> 8);
586 }
587 }
588 else
589 {
590 for( i=0; i<samplesPerBuffer; i++ )
591 {
592 temp = nativeInputBuffer[i];
593 temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
594 temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
595 inBufPtr[i] = (char)(temp >> 8);
596 }
597 }
598 break;
599 }
600
601 case paUInt8:
602 {
603 /* Convert 16 bit data to 8 bit unsigned chars */
604 unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer;
605 inputBuffer = past->past_InputBuffer;
606 if( past->past_Flags & paDitherOff )
607 {
608 for( i=0; i<samplesPerBuffer; i++ )
609 {
610 inBufPtr[i] = (unsigned char)((nativeInputBuffer[i] >> 8) + 0x80);
611 }
612 }
613 else
614 {
615 /* If you dither then you have to clip because dithering could push the signal out of range! */
616 for( i=0; i<samplesPerBuffer; i++ )
617 {
618 temp = nativeInputBuffer[i];
619 temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
620 temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
621 inBufPtr[i] = (unsigned char)((temp>>8) + 0x80); /* PLB20010820 */
622 }
623 }
624 break;
625 }
626
627 default:
628 break;
629 }
630 }
631 #endif /* SUPPORT_AUDIO_CAPTURE */
632
633 /* Are we doing output time? */
634 if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
635 {
636 /* May already be in native format so just write directly to native buffer. */
637 outputBuffer = (past->past_OutputSampleFormat == paInt16) ?
638 (void*)nativeOutputBuffer : past->past_OutputBuffer;
639 }
640 /*
641 AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
642 AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
643 */
644 /* Call user callback routine. */
645 userResult = past->past_Callback(
646 inputBuffer,
647 outputBuffer,
648 past->past_FramesPerUserBuffer,
649 past->past_FrameCount,
650 past->past_UserData );
651
652 past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
653
654 /* Convert to native format if necessary. */
655 if( outputBuffer != NULL )
656 {
657 unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
658 switch(past->past_OutputSampleFormat)
659 {
660 case paFloat32:
661 {
662 float *outBufPtr = (float *) past->past_OutputBuffer;
663 if( past->past_Flags & paDitherOff )
664 {
665 if( past->past_Flags & paClipOff ) /* NOTHING */
666 {
667 for( i=0; i<samplesPerBuffer; i++ )
668 {
669 *nativeOutputBuffer++ = (short) (outBufPtr[i] * (32767.0f));
670 }
671 }
672 else /* CLIP */
673 {
674 for( i=0; i<samplesPerBuffer; i++ )
675 {
676 temp = (long)(outBufPtr[i] * 32767.0f);
677 *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
678 }
679 }
680 }
681 else
682 {
683 /* If you dither then you have to clip because dithering could push the signal out of range! */
684 for( i=0; i<samplesPerBuffer; i++ )
685 {
686 float dither = PaConvert_TriangularDither()*PA_DITHER_SCALE;
687 float dithered = (outBufPtr[i] * (32767.0f)) + dither;
688 temp = (long) (dithered);
689 *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
690 }
691 }
692 break;
693 }
694
695 case paInt32:
696 {
697 int *outBufPtr = (int *) past->past_OutputBuffer;
698 if( past->past_Flags & paDitherOff )
699 {
700 for( i=0; i<samplesPerBuffer; i++ )
701 {
702 *nativeOutputBuffer++ = (short) (outBufPtr[i] >> 16 );
703 }
704 }
705 else
706 {
707 for( i=0; i<samplesPerBuffer; i++ )
708 {
709 /* Shift one bit down before dithering so that we have room for overflow from add. */
710 temp = (outBufPtr[i] >> 1) + PaConvert_TriangularDither();
711 temp = temp >> 15;
712 *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
713 }
714 }
715 break;
716 }
717
718 case paInt8:
719 {
720 char *outBufPtr = (char *) past->past_OutputBuffer;
721 for( i=0; i<samplesPerBuffer; i++ )
722 {
723 *nativeOutputBuffer++ = (short) (((int)outBufPtr[i]) << 8);
724 }
725 break;
726 }
727
728 case paUInt8:
729 {
730 unsigned char *outBufPtr = (unsigned char *) past->past_OutputBuffer;
731 for( i=0; i<samplesPerBuffer; i++ )
732 {
733 *nativeOutputBuffer++ = (short) (((int)(outBufPtr[i] - 0x80)) << 8);
734 }
735 break;
736 }
737
738 default:
739 break;
740 }
741
742 }
743
744 return userResult;
745 }
746
747 /*************************************************************************/
Pa_Initialize(void)748 PaError Pa_Initialize( void )
749 {
750 if( gInitCount++ > 0 ) return paNoError;
751 ResetTraceMessages();
752 return PaHost_Init();
753 }
754
Pa_Terminate(void)755 PaError Pa_Terminate( void )
756 {
757 PaError result = paNoError;
758
759 if( gInitCount == 0 ) return paNoError;
760 else if( --gInitCount == 0 )
761 {
762 result = PaHost_Term();
763 DumpTraceMessages();
764 }
765 return result;
766 }
767
PaHost_IsInitialized()768 int PaHost_IsInitialized()
769 {
770 return gInitCount;
771 }
772
773 /*************************************************************************/
Pa_GetSampleSize(PaSampleFormat format)774 PaError Pa_GetSampleSize( PaSampleFormat format )
775 {
776 int size;
777 switch(format )
778 {
779
780 case paUInt8:
781 case paInt8:
782 size = 1;
783 break;
784
785 case paInt16:
786 size = 2;
787 break;
788
789 case paPackedInt24:
790 size = 3;
791 break;
792
793 case paFloat32:
794 case paInt32:
795 case paInt24:
796 size = 4;
797 break;
798
799 default:
800 size = paSampleFormatNotSupported;
801 break;
802 }
803 return (PaError) size;
804 }
805
806
807