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