Added support for conversion nroutines in pa_convert.c.

SHifted Dither value right by one to account for high pass filter.
This commit is contained in:
philburk 2002-03-21 00:32:50 +00:00
commit cf24fdd1c0
2 changed files with 63 additions and 71 deletions

View file

@ -36,6 +36,8 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "portaudio.h"
#ifdef __cplusplus
extern "C"
@ -59,6 +61,12 @@ extern "C"
typedef unsigned short uint16;
#endif
/* Used to convert between various sample formats. */
typedef void (PortAudioConverter)(
void *inputBuffer, int inputStride,
void *outputBuffer, int outputStride,
int numSamples );
#define PA_MAGIC (0x18273645)
/************************************************************************************/
@ -76,7 +84,9 @@ typedef struct internalPortAudioStream
int past_NumOutputChannels;
PaDeviceID past_InputDeviceID;
PaDeviceID past_OutputDeviceID;
PaSampleFormat past_NativeInputSampleFormat;
PaSampleFormat past_InputSampleFormat;
PaSampleFormat past_NativeOutputSampleFormat;
PaSampleFormat past_OutputSampleFormat;
void *past_DeviceData;
PortAudioCallback *past_Callback;
@ -99,11 +109,19 @@ typedef struct internalPortAudioStream
double past_AverageTotalCount;
double past_Usage;
int past_IfLastExitValid;
/* Format Conversion */
/* These are setup by PaConversion_Setup() */
PortAudioConverter *past_InputConversionProc;
int past_InputConversionSourceStride;
int past_InputConversionTargetStride;
PortAudioConverter *past_OutputConversionProc;
int past_OutputConversionSourceStride;
int past_OutputConversionTargetStride;
}
internalPortAudioStream;
/************************************************************************************/
/****************** Prototypes ******************************************************/
/******** These functions must be provided by a platform implementation. ************/
/************************************************************************************/
PaError PaHost_Init( void );
@ -120,22 +138,42 @@ PaError PaHost_StartEngine( internalPortAudioStream *past );
PaError PaHost_StopEngine( internalPortAudioStream *past, int abort );
PaError PaHost_StreamActive( internalPortAudioStream *past );
long Pa_CallConvertInt16( internalPortAudioStream *past,
short *nativeInputBuffer,
short *nativeOutputBuffer );
long Pa_CallConvertFloat32( internalPortAudioStream *past,
float *nativeInputBuffer,
float *nativeOutputBuffer );
void *PaHost_AllocateFastMemory( long numBytes );
void PaHost_FreeFastMemory( void *addr, long numBytes );
/* This only called if PA_VALIDATE_RATE IS CALLED. */
PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
double *closestFrameRatePtr );
/**********************************************************************/
/************ Common Utility Routines provided by PA ******************/
/**********************************************************************/
int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable,
int numRates, double frameRate );
long Pa_CallConvertInt16( internalPortAudioStream *past,
short *nativeInputBuffer,
short *nativeOutputBuffer );
/* Calculate 2 LSB dither signal with a triangular distribution.
** Ranged properly for adding to a 32 bit 1.31 fixed point value prior to >>15.
** Range of output is +/- 65535
** Multiply by PA_DITHER_SCALE to get a float between -2.0 and 2.0. */
#define PA_DITHER_BITS (15)
#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
long PaConvert_TriangularDither( void );
PaError PaConvert_SetupInput( internalPortAudioStream *past,
PaSampleFormat nativeInputSampleFormat );
PaError PaConvert_SetupOutput( internalPortAudioStream *past,
PaSampleFormat nativeOutputSampleFormat );
long PaConvert_Process( internalPortAudioStream *past,
void *nativeInputBuffer,
void *nativeOutputBuffer );
#ifdef __cplusplus
}
#endif /* __cplusplus */

View file

@ -217,7 +217,7 @@ PaError Pa_OpenStream(
past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */
past->past_FramesPerUserBuffer = framesPerBuffer;
past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() NMUST CHECK FOR ZERO! */
past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() MUST CHECK FOR ZERO! */
past->past_Callback = callback;
past->past_UserData = userData;
past->past_OutputSampleFormat = outputSampleFormat;
@ -248,7 +248,7 @@ PaError Pa_OpenStream(
#else
past->past_SampleRate = sampleRate;
#endif
/* Allocate single Input buffer. */
/* Allocate single Input buffer for passing formatted samples to user callback. */
past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
if( past->past_InputBuffer == NULL )
@ -481,10 +481,11 @@ double Pa_GetCPULoad( PortAudioStream* stream)
/*************************************************************
** Calculate 2 LSB dither signal with a triangular distribution.
** Ranged properly for adding to a 32 bit integer prior to >>15.
** Range of output is +/- 32767
*/
#define DITHER_BITS (15)
#define DITHER_SCALE (1.0f / ((1<<DITHER_BITS)-1))
static long Pa_TriangularDither( void )
#define PA_DITHER_BITS (15)
#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
long PaConvert_TriangularDither( void )
{
static unsigned long previous = 0;
static unsigned long randSeed1 = 22222;
@ -493,8 +494,12 @@ static long Pa_TriangularDither( void )
/* Generate two random numbers. */
randSeed1 = (randSeed1 * 196314165) + 907633515;
randSeed2 = (randSeed2 * 196314165) + 907633515;
/* Generate triangular distribution about 0. */
current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS));
/* Generate triangular distribution about 0.
* Shift before adding to prevent overflow which would skew the distribution.
* Also shift an extra bit for the high pass filter.
*/
#define DITHER_SHIFT ((32 - PA_DITHER_BITS) + 1)
current = (((long)randSeed1)>>DITHER_SHIFT) + (((long)randSeed2)>>DITHER_SHIFT);
/* High pass filter to reduce audibility. */
highPass = current - previous;
previous = current;
@ -513,8 +518,6 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
short *nativeOutputBuffer )
{
long temp;
long bytesEmpty = 0;
long bytesFilled = 0;
int userResult;
unsigned int i;
void *inputBuffer = NULL;
@ -576,7 +579,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
for( i=0; i<samplesPerBuffer; i++ )
{
temp = nativeInputBuffer[i];
temp += Pa_TriangularDither() >> 8; /* PLB20010820 */
temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
inBufPtr[i] = (char)(temp >> 8);
}
@ -602,7 +605,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
for( i=0; i<samplesPerBuffer; i++ )
{
temp = nativeInputBuffer[i];
temp += Pa_TriangularDither() >> 8; /* PLB20010820 */
temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
inBufPtr[i] = (unsigned char)((temp>>8) + 0x80); /* PLB20010820 */
}
@ -669,7 +672,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
/* If you dither then you have to clip because dithering could push the signal out of range! */
for( i=0; i<samplesPerBuffer; i++ )
{
float dither = Pa_TriangularDither()*DITHER_SCALE;
float dither = PaConvert_TriangularDither()*PA_DITHER_SCALE;
float dithered = (outBufPtr[i] * (32767.0f)) + dither;
temp = (long) (dithered);
*nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
@ -693,7 +696,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
for( i=0; i<samplesPerBuffer; i++ )
{
/* Shift one bit down before dithering so that we have room for overflow from add. */
temp = (outBufPtr[i] >> 1) + Pa_TriangularDither();
temp = (outBufPtr[i] >> 1) + PaConvert_TriangularDither();
temp = temp >> 15;
*nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
}
@ -730,55 +733,6 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
return userResult;
}
/*************************************************************************
** Called by host code.
** Convert input from Float32, call user code, then convert output
** to Float32 format for native use.
** Assumes host native format is Float32.
** Returns result from user callback.
** FIXME - Unimplemented for formats other than paFloat32!!!!
*/
long Pa_CallConvertFloat32( internalPortAudioStream *past,
float *nativeInputBuffer,
float *nativeOutputBuffer )
{
long bytesEmpty = 0;
long bytesFilled = 0;
int userResult;
void *inputBuffer = NULL;
void *outputBuffer = NULL;
/* Get native data from DirectSound. */
if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
{
inputBuffer = nativeInputBuffer; /* FIXME */
}
/* Are we doing output time? */
if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
{
/* May already be in native format so just write directly to native buffer. */
outputBuffer = (past->past_OutputSampleFormat == paFloat32) ?
nativeOutputBuffer : past->past_OutputBuffer;
}
/*
AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
*/
/* Call user callback routine. */
userResult = past->past_Callback(
inputBuffer,
outputBuffer,
past->past_FramesPerUserBuffer,
past->past_FrameCount,
past->past_UserData );
past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
/* Convert to native format if necessary. */ /* FIXME */
return userResult;
}
/*************************************************************************/
PaError Pa_Initialize( void )
{