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