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