diff options
author | Guenter Geiger <ggeiger@users.sourceforge.net> | 2003-05-09 16:04:00 +0000 |
---|---|---|
committer | Guenter Geiger <ggeiger@users.sourceforge.net> | 2003-05-09 16:04:00 +0000 |
commit | 9c0e19a3be2288db79e2502e5fa450c3e20a668d (patch) | |
tree | ca97ce615e037a533304fc4660dcf372ca3b9cd6 /pd/portaudio/pa_common | |
parent | ef50dd62804d54af7da18d8bd8413c0dccd729b8 (diff) |
This commit was generated by cvs2svn to compensate for changes in r610,
which included commits to RCS files with non-trunk default branches.
svn path=/trunk/; revision=611
Diffstat (limited to 'pd/portaudio/pa_common')
29 files changed, 8397 insertions, 316 deletions
diff --git a/pd/portaudio/pa_common/pa_allocation.c b/pd/portaudio/pa_common/pa_allocation.c new file mode 100644 index 00000000..5eefeabb --- /dev/null +++ b/pd/portaudio/pa_common/pa_allocation.c @@ -0,0 +1,217 @@ +/* + * Id: + * Portable Audio I/O Library allocation group implementation + * memory allocation group for tracking allocation groups + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "pa_allocation.h" +#include "pa_util.h" + +/* + Maintain 3 singly linked lists... + linkBlocks: the buffers used to allocate the links + spareLinks: links available for use in the allocations list + allocations: the buffers currently allocated using PaUtil_ContextAllocateMemory() + + Link block size is doubled every time new links are allocated. +*/ + + +#define PA_INITIAL_LINK_COUNT_ 16 + +struct PaUtilAllocationGroupLink +{ + struct PaUtilAllocationGroupLink *next; + void *buffer; +}; + +/* + Allocate a block of links. The first link will have it's buffer member + pointing to the block, and it's next member set to <nextBlock>. The remaining + links will have NULL buffer members, and each link will point to + the next link except the last, which will point to <nextSpare> +*/ +static struct PaUtilAllocationGroupLink *AllocateLinks( long count, + struct PaUtilAllocationGroupLink *nextBlock, + struct PaUtilAllocationGroupLink *nextSpare ) +{ + struct PaUtilAllocationGroupLink *result; + int i; + + result = PaUtil_AllocateMemory( sizeof(struct PaUtilAllocationGroupLink) * count ); + if( result ) + { + /* the block link */ + result[0].buffer = result; + result[0].next = nextBlock; + + /* the spare links */ + for( i=1; i<count; ++i ) + { + result[i].buffer = 0; + result[i].next = &result[i+1]; + } + result[count-1].next = nextSpare; + } + + return result; +} + + +PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void ) +{ + PaUtilAllocationGroup* result = 0; + struct PaUtilAllocationGroupLink *links; + + + links = AllocateLinks( PA_INITIAL_LINK_COUNT_, 0, 0 ); + if( links != 0 ) + { + result = (PaUtilAllocationGroup*)PaUtil_AllocateMemory( sizeof(PaUtilAllocationGroup) ); + if( result ) + { + result->linkCount = PA_INITIAL_LINK_COUNT_; + result->linkBlocks = &links[0]; + result->spareLinks = &links[1]; + result->allocations = 0; + } + else + { + PaUtil_FreeMemory( links ); + } + } + + return result; +} + + +void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group ) +{ + struct PaUtilAllocationGroupLink *current = group->linkBlocks; + struct PaUtilAllocationGroupLink *next; + + while( current ) + { + next = current->next; + PaUtil_FreeMemory( current->buffer ); + current = next; + } + + PaUtil_FreeMemory( group ); +} + + +void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size ) +{ + struct PaUtilAllocationGroupLink *links, *link; + void *result = 0; + + /* allocate more links if necessary */ + if( !group->spareLinks ) + { + /* double the link count on each block allocation */ + links = AllocateLinks( group->linkCount, group->linkBlocks, group->spareLinks ); + if( links ) + { + group->linkCount += group->linkCount; + group->linkBlocks = &links[0]; + group->spareLinks = &links[1]; + } + } + + if( group->spareLinks ) + { + result = PaUtil_AllocateMemory( size ); + if( result ) + { + link = group->spareLinks; + group->spareLinks = link->next; + + link->buffer = result; + link->next = group->allocations; + + group->allocations = link; + } + } + + return result; +} + + +void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer ) +{ + struct PaUtilAllocationGroupLink *current = group->allocations; + struct PaUtilAllocationGroupLink *previous = 0; + + if( buffer == 0 ) + return; + + /* find the right link and remove it */ + while( current ) + { + if( current->buffer == buffer ) + { + previous->next = current->next; + + current->buffer = 0; + current->next = group->spareLinks; + group->spareLinks = current; + } + previous = current; + current = current->next; + } + + PaUtil_FreeMemory( buffer ); /* free the memory whether we found it in the list or not */ +} + + +void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group ) +{ + struct PaUtilAllocationGroupLink *current = group->allocations; + struct PaUtilAllocationGroupLink *previous = 0; + + /* free all buffers in the allocations list */ + while( current ) + { + PaUtil_FreeMemory( current->buffer ); + current->buffer = 0; + + previous = current; + current = current->next; + } + + /* link the former allocations list onto the front of the spareLinks list */ + if( previous ) + { + previous->next = group->spareLinks; + group->spareLinks = group->allocations; + group->allocations = 0; + } +} + diff --git a/pd/portaudio/pa_common/pa_allocation.h b/pd/portaudio/pa_common/pa_allocation.h new file mode 100644 index 00000000..b906c14b --- /dev/null +++ b/pd/portaudio/pa_common/pa_allocation.h @@ -0,0 +1,92 @@ +#ifndef PA_ALLOCATION_H +#define PA_ALLOCATION_H +/* + * Id: + * Portable Audio I/O Library allocation context header + * memory allocation context for tracking allocation groups + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @file + An allocation group is useful for keeping track of multiple blocks + of memory which are allocated at the same time (such as during initialization) + and need to be deallocated at the same time. The allocation group maintains + a list of allocated blocks, and can deallocate them all simultaneously which + can be usefull for cleaning up after a partially initialized object fails. + + The allocation group implementation is built on top of the lower + level allocation functions defined in pa_util.h +*/ + + + +typedef struct +{ + long linkCount; + struct PaUtilAllocationGroupLink *linkBlocks; + struct PaUtilAllocationGroupLink *spareLinks; + struct PaUtilAllocationGroupLink *allocations; +}PaUtilAllocationGroup; + + + +/** Create an allocation group. +*/ +PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void ); + +/** Destroy an allocation group, but not the memory allocated through the group. +*/ +void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group ); + +/** Allocate a block of memory though an allocation group. +*/ +void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size ); + +/** Free a block of memory that was previously allocated though an allocation + group. Calling this function is a relatively time consuming operation. + Under normal circumstances clients should call PaUtil_FreeAllAllocations to + free all allocated blocks simultaneously. + @see PaUtil_FreeAllAllocations +*/ +void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer ); + +/** Free all blocks of memory which have been allocated through the allocation + group. This function doesn't destroy the group itself. +*/ +void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_ALLOCATION_H */ diff --git a/pd/portaudio/pa_common/pa_allocation.o b/pd/portaudio/pa_common/pa_allocation.o Binary files differnew file mode 100644 index 00000000..43ac4148 --- /dev/null +++ b/pd/portaudio/pa_common/pa_allocation.o diff --git a/pd/portaudio/pa_common/pa_converters.c b/pd/portaudio/pa_common/pa_converters.c new file mode 100644 index 00000000..39e5e47f --- /dev/null +++ b/pd/portaudio/pa_common/pa_converters.c @@ -0,0 +1,1653 @@ +/* + * $Id: pa_converters.c,v 1.1.2.13 2003/02/28 01:49:59 rossbencina Exp $ + * Portable Audio I/O Library sample conversion mechanism + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + + @todo implement the converters marked IMPLEMENT ME: Float32_To_UInt8_Dither, + Float32_To_UInt8_Clip, Float32_To_UInt8_DitherClip, Int32_To_Int24, + Int32_To_Int24_Dither, Int32_To_Int16, Int32_To_Int16_Dither, Int32_To_Int8, + Int32_To_Int8_Dither, Int32_To_UInt8, Int32_To_UInt8_Dither, Int24_To_Int32, + Int24_To_Int16, Int24_To_Int16_Dither, Int24_To_Int8, Int24_To_Int8_Dither, + Int24_To_UInt8, Int24_To_UInt8_Dither, Int16_To_Int32, Int16_To_Int24, + Int16_To_Int8, Int16_To_Int8_Dither, Int16_To_UInt8, Int16_To_UInt8_Dither, + Int8_To_Int32, Int8_To_Int24, Int8_To_Int16, Int8_To_UInt8, UInt8_To_Int32, + UInt8_To_Int24, UInt8_To_Int16, UInt8_To_Int8 + + @todo review the converters marked REVIEW: Float32_To_Int32, + Float32_To_Int32_Dither, Float32_To_Int32_Clip, Float32_To_Int32_DitherClip +*/ + + +#include "pa_converters.h" +#include "pa_dither.h" +#include "pa_endianness.h" + + +PaSampleFormat PaUtil_SelectClosestAvailableFormat( + PaSampleFormat availableFormats, PaSampleFormat format ) +{ + PaSampleFormat result; + + format &= ~paNonInterleaved; + availableFormats &= ~paNonInterleaved; + + if( (format & availableFormats) == 0 ) + { + /* NOTE: this code depends on the sample format constants being in + descending order of quality - ie best quality is 0 + FIXME: should write an assert which checks that all of the + known constants conform to that requirement. + */ + + if( format != 0x01 ) + { + /* scan for better formats */ + result = format; + do + { + result >>= 1; + } + while( (result & availableFormats) == 0 && result != 0 ); + } + else + { + result = 0; + } + + if( result == 0 ){ + /* scan for worse formats */ + result = format; + do + { + result <<= 1; + } + while( (result & availableFormats) == 0 && result != paCustomFormat ); + + if( (result & availableFormats) == 0 ) + result = paSampleFormatNotSupported; + } + + }else{ + result = format; + } + + return result; +} + +/* -------------------------------------------------------------------------- */ + +#define PA_SELECT_FORMAT_( format, float32, int32, int24, int16, int8, uint8 ) \ + switch( format & ~paNonInterleaved ){ \ + case paFloat32: \ + float32 \ + case paInt32: \ + int32 \ + case paInt24: \ + int24 \ + case paInt16: \ + int16 \ + case paInt8: \ + int8 \ + case paUInt8: \ + uint8 \ + default: return 0; \ + } + +/* -------------------------------------------------------------------------- */ + +#define PA_SELECT_CONVERTER_DITHER_CLIP_( flags, source, destination ) \ + if( flags & paClipOff ){ /* no clip */ \ + if( flags & paDitherOff ){ /* no dither */ \ + return paConverters. source ## _To_ ## destination; \ + }else{ /* dither */ \ + return paConverters. source ## _To_ ## destination ## _Dither; \ + } \ + }else{ /* clip */ \ + if( flags & paDitherOff ){ /* no dither */ \ + return paConverters. source ## _To_ ## destination ## _Clip; \ + }else{ /* dither */ \ + return paConverters. source ## _To_ ## destination ## _DitherClip;\ + } \ + } + +/* -------------------------------------------------------------------------- */ + +#define PA_SELECT_CONVERTER_DITHER_( flags, source, destination ) \ + if( flags & paDitherOff ){ /* no dither */ \ + return paConverters. source ## _To_ ## destination; \ + }else{ /* dither */ \ + return paConverters. source ## _To_ ## destination ## _Dither; \ + } + +/* -------------------------------------------------------------------------- */ + +#define PA_USE_CONVERTER_( source, destination )\ + return paConverters. source ## _To_ ## destination; + +/* -------------------------------------------------------------------------- */ + +#define PA_UNITY_CONVERSION_( wordlength )\ + return paConverters.Copy_ ## wordlength ## _To_ ## wordlength; + +/* -------------------------------------------------------------------------- */ + +PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat, + PaSampleFormat destinationFormat, PaStreamFlags flags ) +{ + PA_SELECT_FORMAT_( sourceFormat, + /* paFloat32: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_UNITY_CONVERSION_( 32 ), + /* paInt32: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int32 ), + /* paInt24: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int24 ), + /* paInt16: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int16 ), + /* paInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int8 ), + /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, UInt8 ) + ), + /* paInt32: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( Int32, Float32 ), + /* paInt32: */ PA_UNITY_CONVERSION_( 32 ), + /* paInt24: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int24 ), + /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int16 ), + /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int8 ), + /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, UInt8 ) + ), + /* paInt24: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( Int24, Float32 ), + /* paInt32: */ PA_USE_CONVERTER_( Int24, Int32 ), + /* paInt24: */ PA_UNITY_CONVERSION_( 24 ), + /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int16 ), + /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int8 ), + /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, UInt8 ) + ), + /* paInt16: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( Int16, Float32 ), + /* paInt32: */ PA_USE_CONVERTER_( Int16, Int32 ), + /* paInt24: */ PA_USE_CONVERTER_( Int16, Int24 ), + /* paInt16: */ PA_UNITY_CONVERSION_( 16 ), + /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, Int8 ), + /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, UInt8 ) + ), + /* paInt8: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( Int8, Float32 ), + /* paInt32: */ PA_USE_CONVERTER_( Int8, Int32 ), + /* paInt24: */ PA_USE_CONVERTER_( Int8, Int24 ), + /* paInt16: */ PA_USE_CONVERTER_( Int8, Int16 ), + /* paInt8: */ PA_UNITY_CONVERSION_( 8 ), + /* paUInt8: */ PA_USE_CONVERTER_( Int8, UInt8 ) + ), + /* paUInt8: */ + PA_SELECT_FORMAT_( destinationFormat, + /* paFloat32: */ PA_USE_CONVERTER_( UInt8, Float32 ), + /* paInt32: */ PA_USE_CONVERTER_( UInt8, Int32 ), + /* paInt24: */ PA_USE_CONVERTER_( UInt8, Int24 ), + /* paInt16: */ PA_USE_CONVERTER_( UInt8, Int16 ), + /* paInt8: */ PA_USE_CONVERTER_( UInt8, Int8 ), + /* paUInt8: */ PA_UNITY_CONVERSION_( 8 ) + ) + ) +} + +/* -------------------------------------------------------------------------- */ + +#ifdef PA_NO_STANDARD_CONVERTERS + +/* -------------------------------------------------------------------------- */ + +PaUtilConverterTable paConverters = { + 0, /* PaUtilConverter *Float32_To_Int32; */ + 0, /* PaUtilConverter *Float32_To_Int32_Dither; */ + 0, /* PaUtilConverter *Float32_To_Int32_Clip; */ + 0, /* PaUtilConverter *Float32_To_Int32_DitherClip; */ + + 0, /* PaUtilConverter *Float32_To_Int24; */ + 0, /* PaUtilConverter *Float32_To_Int24_Dither; */ + 0, /* PaUtilConverter *Float32_To_Int24_Clip; */ + 0, /* PaUtilConverter *Float32_To_Int24_DitherClip; */ + + 0, /* PaUtilConverter *Float32_To_Int16; */ + 0, /* PaUtilConverter *Float32_To_Int16_Dither; */ + 0, /* PaUtilConverter *Float32_To_Int16_Clip; */ + 0, /* PaUtilConverter *Float32_To_Int16_DitherClip; */ + + 0, /* PaUtilConverter *Float32_To_Int8; */ + 0, /* PaUtilConverter *Float32_To_Int8_Dither; */ + 0, /* PaUtilConverter *Float32_To_Int8_Clip; */ + 0, /* PaUtilConverter *Float32_To_Int8_DitherClip; */ + + 0, /* PaUtilConverter *Float32_To_UInt8; */ + 0, /* PaUtilConverter *Float32_To_UInt8_Dither; */ + 0, /* PaUtilConverter *Float32_To_UInt8_Clip; */ + 0, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */ + + 0, /* PaUtilConverter *Int32_To_Float32; */ + 0, /* PaUtilConverter *Int32_To_Int24; */ + 0, /* PaUtilConverter *Int32_To_Int24_Dither; */ + 0, /* PaUtilConverter *Int32_To_Int16; */ + 0, /* PaUtilConverter *Int32_To_Int16_Dither; */ + 0, /* PaUtilConverter *Int32_To_Int8; */ + 0, /* PaUtilConverter *Int32_To_Int8_Dither; */ + 0, /* PaUtilConverter *Int32_To_UInt8; */ + 0, /* PaUtilConverter *Int32_To_UInt8_Dither; */ + + 0, /* PaUtilConverter *Int24_To_Float32; */ + 0, /* PaUtilConverter *Int24_To_Int32; */ + 0, /* PaUtilConverter *Int24_To_Int16; */ + 0, /* PaUtilConverter *Int24_To_Int16_Dither; */ + 0, /* PaUtilConverter *Int24_To_Int8; */ + 0, /* PaUtilConverter *Int24_To_Int8_Dither; */ + 0, /* PaUtilConverter *Int24_To_UInt8; */ + 0, /* PaUtilConverter *Int24_To_UInt8_Dither; */ + + 0, /* PaUtilConverter *Int16_To_Float32; */ + 0, /* PaUtilConverter *Int16_To_Int32; */ + 0, /* PaUtilConverter *Int16_To_Int24; */ + 0, /* PaUtilConverter *Int16_To_Int8; */ + 0, /* PaUtilConverter *Int16_To_Int8_Dither; */ + 0, /* PaUtilConverter *Int16_To_UInt8; */ + 0, /* PaUtilConverter *Int16_To_UInt8_Dither; */ + + 0, /* PaUtilConverter *Int8_To_Float32; */ + 0, /* PaUtilConverter *Int8_To_Int32; */ + 0, /* PaUtilConverter *Int8_To_Int24 */ + 0, /* PaUtilConverter *Int8_To_Int16; */ + 0, /* PaUtilConverter *Int8_To_UInt8; */ + + 0, /* PaUtilConverter *UInt8_To_Float32; */ + 0, /* PaUtilConverter *UInt8_To_Int32; */ + 0, /* PaUtilConverter *UInt8_To_Int24; */ + 0, /* PaUtilConverter *UInt8_To_Int16; */ + 0, /* PaUtilConverter *UInt8_To_Int8; */ + + 0, /* PaUtilConverter *Copy_8_To_8; */ + 0, /* PaUtilConverter *Copy_16_To_16; */ + 0, /* PaUtilConverter *Copy_24_To_24; */ + 0 /* PaUtilConverter *Copy_32_To_32; */ +}; + +/* -------------------------------------------------------------------------- */ + +#else /* PA_NO_STANDARD_CONVERTERS is not defined */ + +/* -------------------------------------------------------------------------- */ + +#define PA_CLIP_( val, min, max )\ + { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); } + + +static const float const_1_div_128_ = 1.0f / 128.0f; /* 8 bit multiplier */ + +static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */ + +static const double const_1_div_2147483648_ = 1.0 / 2147483648.0; /* 32 bit multiplier */ + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed long *dest = (signed long*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* REVIEW */ + double scaled = *src * 0x7FFFFFFF; + *dest = (signed long) scaled; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed long *dest = (signed long*)destinationBuffer; + + while( count-- ) + { + /* REVIEW */ + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + double dithered = ((double)*src * (2147483646.0)) + dither; + *dest = (signed long) dithered; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed long *dest = (signed long*)destinationBuffer; + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* REVIEW */ + double scaled = *src * 0x7FFFFFFF; + PA_CLIP_( scaled, -2147483648., 2147483647. ); + *dest = (signed long) scaled; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int32_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed long *dest = (signed long*)destinationBuffer; + + while( count-- ) + { + /* REVIEW */ + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + double dithered = ((double)*src * (2147483646.0)) + dither; + PA_CLIP_( dithered, -2147483648., 2147483647. ); + *dest = (signed long) dithered; + + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + signed long temp; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* convert to 32 bit and drop the low 8 bits */ + double scaled = *src * 0x7FFFFFFF; + temp = (signed long) scaled; + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(temp >> 24); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 8); +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + signed long temp; + + while( count-- ) + { + /* convert to 32 bit and drop the low 8 bits */ + + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + double dithered = ((double)*src * (2147483646.0)) + dither; + + temp = (signed long) dithered; + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(temp >> 24); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 8); +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + signed long temp; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + /* convert to 32 bit and drop the low 8 bits */ + double scaled = *src * 0x7FFFFFFF; + PA_CLIP_( scaled, -2147483648., 2147483647. ); + temp = (signed long) scaled; + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(temp >> 24); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 8); +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int24_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + signed long temp; + + while( count-- ) + { + /* convert to 32 bit and drop the low 8 bits */ + + double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + double dithered = ((double)*src * (2147483646.0)) + dither; + PA_CLIP_( dithered, -2147483648., 2147483647. ); + + temp = (signed long) dithered; + +#if defined(PA_LITTLE_ENDIAN) + dest[0] = (unsigned char)(temp >> 8); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 24); +#elif defined(PA_BIG_ENDIAN) + dest[0] = (unsigned char)(temp >> 24); + dest[1] = (unsigned char)(temp >> 16); + dest[2] = (unsigned char)(temp >> 8); +#endif + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + short samp = (short) (*src * (32767.0f)); + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + + while( count-- ) + { + + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (32766.0f)) + dither; + *dest = (signed short) dithered; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + long samp = (signed long) (*src * (32767.0f)); + PA_CLIP_( samp, -0x8000, 0x7FFF ); + *dest = (signed short) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int16_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (32766.0f)) + dither; + signed long samp = (signed long) dithered; + PA_CLIP_( samp, -0x8000, 0x7FFF ); + *dest = (signed short) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + signed char samp = (signed char) (*src * (127.0f)); + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (126.0f)) + dither; + signed long samp = (signed long) dithered; + *dest = (signed char) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int8_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + signed long samp = (signed long)(*src * (127.0f)); + PA_CLIP_( samp, -0x80, 0x7F ); + *dest = (signed char) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_Int8_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator ); + /* use smaller scaler to prevent overflow when we add the dither */ + float dithered = (*src * (126.0f)) + dither; + signed long samp = (signed long) dithered; + PA_CLIP_( samp, -0x80, 0x7F ); + *dest = (signed char) samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + unsigned char samp = (unsigned char)(128 + ((unsigned char) (*src * (127.0f)))); + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_UInt8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_UInt8_Clip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Float32_To_UInt8_DitherClip( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + float *src = (float*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed long *src = (signed long*)sourceBuffer; + float *dest = (float*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = (double)*src * const_1_div_2147483648_; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int24_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed long *src = (signed long*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int16_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed long *src = (signed long*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed long *src = (signed long*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_Int8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed long *src = (signed long*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed long *src = (signed long*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int32_To_UInt8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed long *src = (signed long*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + float *dest = (float*)destinationBuffer; + signed long temp; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + +#if defined(PA_LITTLE_ENDIAN) + temp = (((long)src[0]) << 8); + temp = temp | (((long)src[1]) << 16); + temp = temp | (((long)src[2]) << 24); +#elif defined(PA_BIG_ENDIAN) + temp = (((long)src[0]) << 24); + temp = temp | (((long)src[1]) << 16); + temp = temp | (((long)src[2]) << 8); +#endif + + *dest = (double)temp * const_1_div_2147483648_; + + src += sourceStride * 3; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int16_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_Int8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int24_To_UInt8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed short *src = (signed short*)sourceBuffer; + float *dest = (float*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + float samp = *src * const_1_div_32768_; /* FIXME: i'm concerned about this being asymetrical with float->int16 -rb */ + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed short *src = (signed short*)sourceBuffer; + signed long *dest = (signed long*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed short *src = (signed short*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_Int8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed short *src = (signed short*)sourceBuffer; + signed char *dest = (signed char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed short *src = (signed short*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int16_To_UInt8_Dither( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed short *src = (signed short*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + float *dest = (float*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + float samp = *src * const_1_div_128_; + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + signed long *dest = (signed long*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Int8_To_UInt8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + signed char *src = (signed char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Float32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + float *dest = (float*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + float samp = (*src - 128) * const_1_div_128_; + *dest = samp; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Int32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + signed long *dest = (signed long*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Int24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + (void) destinationBuffer; /* unused parameters */ + (void) destinationStride; /* unused parameters */ + (void) sourceBuffer; /* unused parameters */ + (void) sourceStride; /* unused parameters */ + (void) count; /* unused parameters */ + (void) ditherGenerator; /* unused parameters */ + /* IMPLEMENT ME */ +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Int16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + signed short *dest = (signed short*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void UInt8_To_Int8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + float *dest = (float*)destinationBuffer; + (void)ditherGenerator; /* unused parameter */ + + while( count-- ) + { + + /* IMPLEMENT ME */ + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Copy_8_To_8( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = *src; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Copy_16_To_16( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned short *src = (unsigned short*)sourceBuffer; + unsigned short *dest = (unsigned short*)destinationBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = *src; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Copy_24_To_24( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned char *src = (unsigned char*)sourceBuffer; + unsigned char *dest = (unsigned char*)destinationBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + + src += sourceStride * 3; + dest += destinationStride * 3; + } +} + +/* -------------------------------------------------------------------------- */ + +static void Copy_32_To_32( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) +{ + unsigned long *dest = (unsigned long*)destinationBuffer; + unsigned long *src = (unsigned long*)sourceBuffer; + + (void) ditherGenerator; /* unused parameter */ + + while( count-- ) + { + *dest = *src; + + src += sourceStride; + dest += destinationStride; + } +} + +/* -------------------------------------------------------------------------- */ + +PaUtilConverterTable paConverters = { + Float32_To_Int32, /* PaUtilConverter *Float32_To_Int32; */ + Float32_To_Int32_Dither, /* PaUtilConverter *Float32_To_Int32_Dither; */ + Float32_To_Int32_Clip, /* PaUtilConverter *Float32_To_Int32_Clip; */ + Float32_To_Int32_DitherClip, /* PaUtilConverter *Float32_To_Int32_DitherClip; */ + + Float32_To_Int24, /* PaUtilConverter *Float32_To_Int24; */ + Float32_To_Int24_Dither, /* PaUtilConverter *Float32_To_Int24_Dither; */ + Float32_To_Int24_Clip, /* PaUtilConverter *Float32_To_Int24_Clip; */ + Float32_To_Int24_DitherClip, /* PaUtilConverter *Float32_To_Int24_DitherClip; */ + + Float32_To_Int16, /* PaUtilConverter *Float32_To_Int16; */ + Float32_To_Int16_Dither, /* PaUtilConverter *Float32_To_Int16_Dither; */ + Float32_To_Int16_Clip, /* PaUtilConverter *Float32_To_Int16_Clip; */ + Float32_To_Int16_DitherClip, /* PaUtilConverter *Float32_To_Int16_DitherClip; */ + + Float32_To_Int8, /* PaUtilConverter *Float32_To_Int8; */ + Float32_To_Int8_Dither, /* PaUtilConverter *Float32_To_Int8_Dither; */ + Float32_To_Int8_Clip, /* PaUtilConverter *Float32_To_Int8_Clip; */ + Float32_To_Int8_DitherClip, /* PaUtilConverter *Float32_To_Int8_DitherClip; */ + + Float32_To_UInt8, /* PaUtilConverter *Float32_To_UInt8; */ + Float32_To_UInt8_Dither, /* PaUtilConverter *Float32_To_UInt8_Dither; */ + Float32_To_UInt8_Clip, /* PaUtilConverter *Float32_To_UInt8_Clip; */ + Float32_To_UInt8_DitherClip, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */ + + Int32_To_Float32, /* PaUtilConverter *Int32_To_Float32; */ + Int32_To_Int24, /* PaUtilConverter *Int32_To_Int24; */ + Int32_To_Int24_Dither, /* PaUtilConverter *Int32_To_Int24_Dither; */ + Int32_To_Int16, /* PaUtilConverter *Int32_To_Int16; */ + Int32_To_Int16_Dither, /* PaUtilConverter *Int32_To_Int16_Dither; */ + Int32_To_Int8, /* PaUtilConverter *Int32_To_Int8; */ + Int32_To_Int8_Dither, /* PaUtilConverter *Int32_To_Int8_Dither; */ + Int32_To_UInt8, /* PaUtilConverter *Int32_To_UInt8; */ + Int32_To_UInt8_Dither, /* PaUtilConverter *Int32_To_UInt8_Dither; */ + + Int24_To_Float32, /* PaUtilConverter *Int24_To_Float32; */ + Int24_To_Int32, /* PaUtilConverter *Int24_To_Int32; */ + Int24_To_Int16, /* PaUtilConverter *Int24_To_Int16; */ + Int24_To_Int16_Dither, /* PaUtilConverter *Int24_To_Int16_Dither; */ + Int24_To_Int8, /* PaUtilConverter *Int24_To_Int8; */ + Int24_To_Int8_Dither, /* PaUtilConverter *Int24_To_Int8_Dither; */ + Int24_To_UInt8, /* PaUtilConverter *Int24_To_UInt8; */ + Int24_To_UInt8_Dither, /* PaUtilConverter *Int24_To_UInt8_Dither; */ + + Int16_To_Float32, /* PaUtilConverter *Int16_To_Float32; */ + Int16_To_Int32, /* PaUtilConverter *Int16_To_Int32; */ + Int16_To_Int24, /* PaUtilConverter *Int16_To_Int24; */ + Int16_To_Int8, /* PaUtilConverter *Int16_To_Int8; */ + Int16_To_Int8_Dither, /* PaUtilConverter *Int16_To_Int8_Dither; */ + Int16_To_UInt8, /* PaUtilConverter *Int16_To_UInt8; */ + Int16_To_UInt8_Dither, /* PaUtilConverter *Int16_To_UInt8_Dither; */ + + Int8_To_Float32, /* PaUtilConverter *Int8_To_Float32; */ + Int8_To_Int32, /* PaUtilConverter *Int8_To_Int32; */ + Int8_To_Int24, /* PaUtilConverter *Int8_To_Int24 */ + Int8_To_Int16, /* PaUtilConverter *Int8_To_Int16; */ + Int8_To_UInt8, /* PaUtilConverter *Int8_To_UInt8; */ + + UInt8_To_Float32, /* PaUtilConverter *UInt8_To_Float32; */ + UInt8_To_Int32, /* PaUtilConverter *UInt8_To_Int32; */ + UInt8_To_Int24, /* PaUtilConverter *UInt8_To_Int24; */ + UInt8_To_Int16, /* PaUtilConverter *UInt8_To_Int16; */ + UInt8_To_Int8, /* PaUtilConverter *UInt8_To_Int8; */ + + Copy_8_To_8, /* PaUtilConverter *Copy_8_To_8; */ + Copy_16_To_16, /* PaUtilConverter *Copy_16_To_16; */ + Copy_24_To_24, /* PaUtilConverter *Copy_24_To_24; */ + Copy_32_To_32 /* PaUtilConverter *Copy_32_To_32; */ +}; + +/* -------------------------------------------------------------------------- */ + +#endif /* PA_NO_STANDARD_CONVERTERS */ diff --git a/pd/portaudio/pa_common/pa_converters.h b/pd/portaudio/pa_common/pa_converters.h new file mode 100644 index 00000000..8fa0fda7 --- /dev/null +++ b/pd/portaudio/pa_common/pa_converters.h @@ -0,0 +1,197 @@ +#ifndef PA_CONVERTERS_H +#define PA_CONVERTERS_H +/* + * $Id: pa_converters.h,v 1.1.2.7 2002/10/22 08:58:17 rossbencina Exp $ + * Portable Audio I/O Library sample conversion mechanism + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "portaudio.h" /* for PaSampleFormat */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +struct PaUtilTriangularDitherGenerator; + + +/** Choose an available sample format which is most appropriate for + representing the requested format. If the requested format is not available + higher quality formats are considered before lower quality formates. + @param availableFormats A variable containing the logical OR of all available + formats. + @param format The desired format. + @return The most appropriate available format for representing the requested + format. +*/ +PaSampleFormat PaUtil_SelectClosestAvailableFormat( + PaSampleFormat availableFormats, PaSampleFormat format ); + + +/* high level conversions functions for use by implementations */ + + +/** The generic sample converter prototype. Sample converters convert count + samples from sourceBuffer to destinationBuffer. The actual type of the data + pointed to by these parameters varys for different converter functions. + @param destinationBuffer A pointer to the first sample of the destination. + @param destinationStride An offset between successive destination samples + expressed in samples (not bytes.) It may be negative. + @param sourceBuffer A pointer to the first sample of the source. + @param sourceStride An offset between successive source samples + expressed in samples (not bytes.) It may be negative. + @param count The number of samples to convert. + @param ditherState State information used to calculate dither. Converters + that do not perform dithering will ignore this parameter, in which case + NULL or invalid dither state may be passed. +*/ +typedef void PaUtilConverter( + void *destinationBuffer, signed int destinationStride, + void *sourceBuffer, signed int sourceStride, + unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ); + + +/** Find a sample converter function for the given source and destinations + formats and flags (clip and dither.) + @return + A pointer to a PaUtil_Converter which will perform the requested + conversion, or NULL if the given format conversion is not supported. + For conversions where clipping or dithering is not necessary, the + clip and dither flags are ignored and a non-clipping or dithering + version is returned. + If the source and destination formats are the same, a function which + copies data of the appropriate size will be returned. +*/ +PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat, + PaSampleFormat destinationFormat, PaStreamFlags flags ); + + +/* low level functions and data structures which may be used for + substituting additional conversion functions */ + + +/** The type used to store all sample conversion functions. + @see paConverters; +*/ +typedef struct{ + PaUtilConverter *Float32_To_Int32; + PaUtilConverter *Float32_To_Int32_Dither; + PaUtilConverter *Float32_To_Int32_Clip; + PaUtilConverter *Float32_To_Int32_DitherClip; + + PaUtilConverter *Float32_To_Int24; + PaUtilConverter *Float32_To_Int24_Dither; + PaUtilConverter *Float32_To_Int24_Clip; + PaUtilConverter *Float32_To_Int24_DitherClip; + + PaUtilConverter *Float32_To_Int16; + PaUtilConverter *Float32_To_Int16_Dither; + PaUtilConverter *Float32_To_Int16_Clip; + PaUtilConverter *Float32_To_Int16_DitherClip; + + PaUtilConverter *Float32_To_Int8; + PaUtilConverter *Float32_To_Int8_Dither; + PaUtilConverter *Float32_To_Int8_Clip; + PaUtilConverter *Float32_To_Int8_DitherClip; + + PaUtilConverter *Float32_To_UInt8; + PaUtilConverter *Float32_To_UInt8_Dither; + PaUtilConverter *Float32_To_UInt8_Clip; + PaUtilConverter *Float32_To_UInt8_DitherClip; + + PaUtilConverter *Int32_To_Float32; + PaUtilConverter *Int32_To_Int24; + PaUtilConverter *Int32_To_Int24_Dither; + PaUtilConverter *Int32_To_Int16; + PaUtilConverter *Int32_To_Int16_Dither; + PaUtilConverter *Int32_To_Int8; + PaUtilConverter *Int32_To_Int8_Dither; + PaUtilConverter *Int32_To_UInt8; + PaUtilConverter *Int32_To_UInt8_Dither; + + PaUtilConverter *Int24_To_Float32; + PaUtilConverter *Int24_To_Int32; + PaUtilConverter *Int24_To_Int16; + PaUtilConverter *Int24_To_Int16_Dither; + PaUtilConverter *Int24_To_Int8; + PaUtilConverter *Int24_To_Int8_Dither; + PaUtilConverter *Int24_To_UInt8; + PaUtilConverter *Int24_To_UInt8_Dither; + + PaUtilConverter *Int16_To_Float32; + PaUtilConverter *Int16_To_Int32; + PaUtilConverter *Int16_To_Int24; + PaUtilConverter *Int16_To_Int8; + PaUtilConverter *Int16_To_Int8_Dither; + PaUtilConverter *Int16_To_UInt8; + PaUtilConverter *Int16_To_UInt8_Dither; + + PaUtilConverter *Int8_To_Float32; + PaUtilConverter *Int8_To_Int32; + PaUtilConverter *Int8_To_Int24; + PaUtilConverter *Int8_To_Int16; + PaUtilConverter *Int8_To_UInt8; + + PaUtilConverter *UInt8_To_Float32; + PaUtilConverter *UInt8_To_Int32; + PaUtilConverter *UInt8_To_Int24; + PaUtilConverter *UInt8_To_Int16; + PaUtilConverter *UInt8_To_Int8; + + PaUtilConverter *Copy_8_To_8; /* copy without any conversion */ + PaUtilConverter *Copy_16_To_16; /* copy without any conversion */ + PaUtilConverter *Copy_24_To_24; /* copy without any conversion */ + PaUtilConverter *Copy_32_To_32; /* copy without any conversion */ +} PaUtilConverterTable; + + +/** A table of pointers to all required converter functions. + PaUtil_SelectConverter() uses this table to lookup the appropriate + conversion functions. The fields of this structure are initialized + with default conversion functions. Fields may be NULL, indicating that + no conversion function is available. User code may substitue optimised + conversion functions by assigning different function pointers to + these fields. + + @note + If the PA_NO_STANDARD_CONVERTERS preprocessor variable is defined, + PortAudio's standard converters will not be compiled, and all fields + of this structure will be initialized to NULL. In such cases, users + should supply their own conversion functions if the require PortAudio + to open a stream that requires sample conversion. + + @see PaUtilConverterTable, PaUtilConverter, PaUtil_SelectConverter +*/ +extern PaUtilConverterTable paConverters; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_CONVERTERS_H */ diff --git a/pd/portaudio/pa_common/pa_converters.o b/pd/portaudio/pa_common/pa_converters.o Binary files differnew file mode 100644 index 00000000..3baede8e --- /dev/null +++ b/pd/portaudio/pa_common/pa_converters.o diff --git a/pd/portaudio/pa_common/pa_cpuload.c b/pd/portaudio/pa_common/pa_cpuload.c new file mode 100644 index 00000000..bce82aff --- /dev/null +++ b/pd/portaudio/pa_common/pa_cpuload.c @@ -0,0 +1,79 @@ +/* + * $Id: pa_cpuload.c,v 1.1.2.9 2002/10/22 08:58:17 rossbencina Exp $ + * Portable Audio I/O Library CPU Load measurement functions + * Portable CPU load measurement facility. + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2002 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "pa_cpuload.h" + +#include <assert.h> + +#include "pa_util.h" /* for PaUtil_GetTime() */ + + +void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate ) +{ + assert( sampleRate > 0 ); + + measurer->samplingPeriod = 1. / sampleRate; +} + + +void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer ) +{ + measurer->measurementStartTime = PaUtil_GetTime(); +} + + +void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed ) +{ + double measurementEndTime, secondsFor100Percent, measuredLoad; + + if( framesProcessed > 0 ){ + measurementEndTime = PaUtil_GetTime(); + + assert( framesProcessed > 0 ); + secondsFor100Percent = framesProcessed * measurer->samplingPeriod; + + measuredLoad = (measurementEndTime - measurer->measurementStartTime) / secondsFor100Percent; + + /* Low pass filter the calculated CPU load to reduce jitter using a simple IIR low pass filter. */ +#define LOWPASS_COEFFICIENT_0 (0.9) +#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) + + measurer->averageLoad = (LOWPASS_COEFFICIENT_0 * measurer->averageLoad) + + (LOWPASS_COEFFICIENT_1 * measuredLoad); + } +} + + +double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer ) +{ + return measurer->averageLoad; +} diff --git a/pd/portaudio/pa_common/pa_cpuload.h b/pd/portaudio/pa_common/pa_cpuload.h new file mode 100644 index 00000000..28c4c29a --- /dev/null +++ b/pd/portaudio/pa_common/pa_cpuload.h @@ -0,0 +1,56 @@ +#ifndef PA_CPULOAD_H +#define PA_CPULOAD_H +/* + * $Id: pa_cpuload.h,v 1.1.2.8 2002/10/22 08:58:17 rossbencina Exp $ + * Portable Audio I/O Library CPU Load measurement functions + * Portable CPU load measurement facility. + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2002 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +typedef struct { + double samplingPeriod; + double measurementStartTime; + double averageLoad; +} PaUtilCpuLoadMeasurer; /** @todo need better name than measurer */ + +void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate ); +void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer ); +void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed ); +double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_CPULOAD_H */ diff --git a/pd/portaudio/pa_common/pa_cpuload.o b/pd/portaudio/pa_common/pa_cpuload.o Binary files differnew file mode 100644 index 00000000..bc599f45 --- /dev/null +++ b/pd/portaudio/pa_common/pa_cpuload.o diff --git a/pd/portaudio/pa_common/pa_dither.c b/pd/portaudio/pa_common/pa_dither.c new file mode 100644 index 00000000..10f43e69 --- /dev/null +++ b/pd/portaudio/pa_common/pa_dither.c @@ -0,0 +1,91 @@ +/* + * $Id: pa_dither.c,v 1.1.2.3 2002/06/16 13:11:02 rossbencina Exp $ + * Portable Audio I/O Library triangular dither generator + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "pa_dither.h" + +#define PA_DITHER_BITS_ (15) + + +void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *state ) +{ + state->previous = 0; + state->randSeed1 = 22222; + state->randSeed2 = 5555555; +} + + +signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state ) +{ + signed long current, highPass; + + /* Generate two random numbers. */ + state->randSeed1 = (state->randSeed1 * 196314165) + 907633515; + state->randSeed2 = (state->randSeed2 * 196314165) + 907633515; + + /* 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 = (((signed long)state->randSeed1)>>DITHER_SHIFT_) + + (((signed long)state->randSeed2)>>DITHER_SHIFT_); + + /* High pass filter to reduce audibility. */ + highPass = current - state->previous; + state->previous = current; + return highPass; +} + +/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */ +#define PA_FLOAT_DITHER_SCALE_ (1.0f / ((1<<PA_DITHER_BITS_)-1)) +static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_; + +float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *state ) +{ + signed long current, highPass; + + /* Generate two random numbers. */ + state->randSeed1 = (state->randSeed1 * 196314165) + 907633515; + state->randSeed2 = (state->randSeed2 * 196314165) + 907633515; + + /* 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 = (((signed long)state->randSeed1)>>DITHER_SHIFT_) + + (((signed long)state->randSeed2)>>DITHER_SHIFT_); + + /* High pass filter to reduce audibility. */ + highPass = current - state->previous; + state->previous = current; + return ((float)highPass) * const_float_dither_scale_; +} diff --git a/pd/portaudio/pa_common/pa_dither.h b/pd/portaudio/pa_common/pa_dither.h new file mode 100644 index 00000000..97116f0f --- /dev/null +++ b/pd/portaudio/pa_common/pa_dither.h @@ -0,0 +1,189 @@ +#ifndef PA_DITHER_H +#define PA_DITHER_H +/* + * $Id: pa_dither.h,v 1.1.2.2 2002/06/05 22:37:03 rossb Exp $ + * Portable Audio I/O Library triangular dither generator + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +typedef struct PaUtilTriangularDitherGenerator{ + unsigned long previous; + unsigned long randSeed1; + unsigned long randSeed2; +} PaUtilTriangularDitherGenerator; +/**< State needed to generate a dither signal */ + + +void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState ); +/**< Initialize dither state */ + +signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState ); +/**< + Calculate 2 LSB dither signal with a triangular distribution. + Ranged for adding to a 1 bit right-shifted 32 bit integer + prior to >>15. eg: +<pre> + signed long in = * + signed long dither = PaUtil_Generate16BitTriangularDither( ditherState ); + signed short out = (signed short)(((in>>1) + dither) >> 15); +</pre> + @return + A signed long with a range of +32767 to -32768 +*/ + + +float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState ); +/**< + Calculate 2 LSB dither signal with a triangular distribution. + Ranged for adding to a pre-scaled float. +<pre> + float in = * + float dither = PaUtil_GenerateFloatTriangularDither( ditherState ); + // use smaller scaler to prevent overflow when we add the dither + signed short out = (signed short)(in*(32766.0f) + dither ); +</pre> + @return + A float with a range of -2.0 to +1.99999. +*/ + + + +/* +The following alternate dither algorithms are known... +*/ + +/*Noise shaped dither (March 2000) +------------------- + +This is a simple implementation of highpass triangular-PDF dither with +2nd-order noise shaping, for use when truncating floating point audio +data to fixed point. + +The noise shaping lowers the noise floor by 11dB below 5kHz (@ 44100Hz +sample rate) compared to triangular-PDF dither. The code below assumes +input data is in the range +1 to -1 and doesn't check for overloads! + +To save time when generating dither for multiple channels you can do +things like this: r3=(r1 & 0x7F)<<8; instead of calling rand() again. + + + + int r1, r2; //rectangular-PDF random numbers + float s1, s2; //error feedback buffers + float s = 0.5f; //set to 0.0f for no noise shaping + float w = pow(2.0,bits-1); //word length (usually bits=16) + float wi= 1.0f/w; + float d = wi / RAND_MAX; //dither amplitude (2 lsb) + float o = wi * 0.5f; //remove dc offset + float in, tmp; + int out; + + +//for each sample... + + r2=r1; //can make HP-TRI dither by + r1=rand(); //subtracting previous rand() + + in += s * (s1 + s1 - s2); //error feedback + tmp = in + o + d * (float)(r1 - r2); //dc offset and dither + + out = (int)(w * tmp); //truncate downwards + if(tmp<0.0f) out--; //this is faster than floor() + + s2 = s1; + s1 = in - wi * (float)out; //error + + + +-- +paul.kellett@maxim.abel.co.uk +http://www.maxim.abel.co.uk +*/ + + +/* +16-to-8-bit first-order dither + +Type : First order error feedforward dithering code +References : Posted by Jon Watte + +Notes : +This is about as simple a dithering algorithm as you can implement, but it's +likely to sound better than just truncating to N bits. + +Note that you might not want to carry forward the full difference for infinity. +It's probably likely that the worst performance hit comes from the saturation +conditionals, which can be avoided with appropriate instructions on many DSPs +and integer SIMD type instructions, or CMOV. + +Last, if sound quality is paramount (such as when going from > 16 bits to 16 +bits) you probably want to use a higher-order dither function found elsewhere +on this site. + + +Code : +// This code will down-convert and dither a 16-bit signed short +// mono signal into an 8-bit unsigned char signal, using a first +// order forward-feeding error term dither. + +#define uchar unsigned char + +void dither_one_channel_16_to_8( short * input, uchar * output, int count, int * memory ) +{ + int m = *memory; + while( count-- > 0 ) { + int i = *input++; + i += m; + int j = i + 32768 - 128; + uchar o; + if( j < 0 ) { + o = 0; + } + else if( j > 65535 ) { + o = 255; + } + else { + o = (uchar)((j>>8)&0xff); + } + m = ((j-32768+128)-i); + *output++ = o; + } + *memory = m; +} +*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_DITHER_H */ diff --git a/pd/portaudio/pa_common/pa_dither.o b/pd/portaudio/pa_common/pa_dither.o Binary files differnew file mode 100644 index 00000000..fc7a4bb4 --- /dev/null +++ b/pd/portaudio/pa_common/pa_dither.o diff --git a/pd/portaudio/pa_common/pa_endianness.h b/pd/portaudio/pa_common/pa_endianness.h new file mode 100644 index 00000000..aaccaf75 --- /dev/null +++ b/pd/portaudio/pa_common/pa_endianness.h @@ -0,0 +1,108 @@ +#ifndef PA_ENDIANNESS_H +#define PA_ENDIANNESS_H +/* + * $Id: pa_endianness.h,v 1.1.2.1 2003/02/28 01:49:59 rossbencina Exp $ + * Portable Audio I/O Library current platform endianness macros + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @file + Arrange for either the PA_LITTLE_ENDIAN or PA_BIG_ENDIAN preprocessor symbols + to be defined. The one that is defined reflects the endianness of the target + platform and may be used to implement conditional compilation of byte-order + dependent code. + + If either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN is defined already, then no attempt + is made to override that setting. This may be useful if you have a better way + of determining the platform's endianness. The autoconf mechanism uses this for + example. + + A PA_VALIDATE_ENDIANNESS macro is provided to compare the compile time + and runtime endiannes and raise an assertion if they don't match. +*/ + + +#if defined(PA_LITTLE_ENDIAN) || defined(PA_BIG_ENDIAN) + /* endianness define has been set externally, such as by autoconf */ + + #if defined(PA_LITTLE_ENDIAN) && defined(PA_BIG_ENDIAN) + #error both PA_LITTLE_ENDIAN and PA_BIG_ENDIAN have been defined externally to pa_endianness.h - only one endianness at a time please + #endif + +#else + /* endianness define has not been set externally */ + + /* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */ + + #ifdef WIN32 + + #define PA_LITTLE_ENDIAN /* win32, assume intel byte order */ + + #else + +#endif + + #if !defined(PA_LITTLE_ENDIAN) && !defined(PA_BIG_ENDIAN) + /* + If the following error is raised, you either need to modify the code above + to automatically determine the endianness from other symbols defined on your + platform, or define either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN externally. + */ + #error pa_endianness.h was unable to automatically determine the endianness of the target platform + #endif + +#endif + +/* PA_VALIDATE_ENDIANNESS compares the compile time and runtime endianness, + and raises an assertion if they don't match. <assert.h> must be included in + the context in which this macro is used. +*/ +#if defined(PA_LITTLE_ENDIAN) + #define PA_VALIDATE_ENDIANNESS \ + { \ + const long nativeOne = 1; \ + assert( "compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 1 ); \ + } +#elif defined(PA_BIG_ENDIAN) + #define PA_VALIDATE_ENDIANNESS \ + { \ + const long nativeOne = 1; \ + assert( "compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \ + } +#endif + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_ENDIANNESS_H */ diff --git a/pd/portaudio/pa_common/pa_front.c b/pd/portaudio/pa_common/pa_front.c new file mode 100644 index 00000000..27293b20 --- /dev/null +++ b/pd/portaudio/pa_common/pa_front.c @@ -0,0 +1,1884 @@ +/* + * $Id: pa_front.c,v 1.1.2.36 2003/02/28 01:49:59 rossbencina Exp $ + * Portable Audio I/O Library Multi-Host API front end + * Validate function parameters and manage multiple host APIs. + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* doxygen index page */ +/** @mainpage + +PortAudio is an open-source cross-platform ‘C’ library for audio input +and output. It is designed to simplify the porting of audio applications +between various platforms, and also to simplify the development of audio +software in general by hiding the complexities of device interfacing. + +See the PortAudio website for further information http://www.portaudio.com/ + +This documentation pertains to PortAudio V19, API version 2.0 which is +currently under development. API version 2.0 differs in a number of ways from +previous versions, please consult the enhancement proposals for further details: +http://www.portaudio.com/docs/proposals/index.html + +This documentation is under construction. Things you might be interested in +include: + +- The PortAudio API 2.0 documented in portaudio.h + +- The possibly incomplete and totally unorganised <a href="todo.html">Todo List</a> +*/ + +#include <stdio.h> +#include <stdarg.h> +#include <memory.h> +#include <string.h> +#include <assert.h> /* needed by PA_VALIDATE_ENDIANNESS */ + +#include "portaudio.h" +#include "pa_util.h" +#include "pa_endianness.h" +#include "pa_hostapi.h" +#include "pa_stream.h" + +#include "pa_trace.h" + + +#define PA_VERSION_ 1899 +#define PA_VERSION_TEXT_ "PortAudio V19-devel" + + + +/* #define PA_LOG_API_CALLS */ + +/* + The basic format for log messages is as follows: + + - entry (void function): + + "FunctionName called.\n" + + - entry (non void function): + + "FunctionName called:\n" + "\tParam1Type param1: param1Value\n" + "\tParam2Type param2: param2Value\n" (etc...) + + + - exit (no return value) + + "FunctionName returned.\n" + + - exit (simple return value) + + "FunctionName returned:\n" + "\tReturnType: returnValue\n\n" + + if the return type is an error code, the error text is displayed in () + + if the return type is not an error code, but has taken a special value + because an error occurred, then the reason for the error is shown in [] + + if the return type is a struct ptr, the struct is dumped. + + see the code for more detailed examples +*/ + +int Pa_GetVersion( void ) +{ + return PA_VERSION_; +} + + +const char* Pa_GetVersionText( void ) +{ + return PA_VERSION_TEXT_; +} + + + +#define PA_LAST_HOST_ERROR_TEXT_LENGTH_ 1024 + +static char lastHostErrorText_[ PA_LAST_HOST_ERROR_TEXT_LENGTH_ + 1 ] = {0}; + +static PaHostErrorInfo lastHostErrorInfo_ = { -1, 0, lastHostErrorText_ }; + + +void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode, + const char *errorText ) +{ + lastHostErrorInfo_.hostApiType = hostApiType; + lastHostErrorInfo_.errorCode = errorCode; + + strncpy( lastHostErrorText_, errorText, PA_LAST_HOST_ERROR_TEXT_LENGTH_ ); +} + + +void PaUtil_DebugPrint( const char *format, ... ) +{ + va_list ap; + + va_start( ap, format ); + vfprintf( stderr, format, ap ); + va_end( ap ); + + fflush( stderr ); +} + + +static PaUtilHostApiRepresentation **hostApis_ = 0; +static int hostApisCount_ = 0; +static int initializationCount_ = 0; +static int deviceCount_ = 0; + +PaUtilStreamRepresentation *firstOpenStream_ = NULL; + + +#define PA_IS_INITIALISED_ (initializationCount_ != 0) + + +static int CountHostApiInitializers( void ) +{ + int result = 0; + + while( paHostApiInitializers[ result ] != 0 ) + ++result; + return result; +} + + +static void TerminateHostApis( void ) +{ + /* terminate in reverse order from initialization */ + + while( hostApisCount_ > 0 ) + { + --hostApisCount_; + hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] ); + } + hostApisCount_ = 0; + deviceCount_ = 0; + + if( hostApis_ != 0 ) + PaUtil_FreeMemory( hostApis_ ); + hostApis_ = 0; +} + + +static PaError InitializeHostApis( void ) +{ + PaError result = paNoError; + int i, initializerCount, baseDeviceIndex; + + initializerCount = CountHostApiInitializers(); + + hostApis_ = PaUtil_AllocateMemory( sizeof(PaUtilHostApiRepresentation*) * initializerCount ); + if( !hostApis_ ) + { + result = paInsufficientMemory; + goto error; + } + + hostApisCount_ = 0; + deviceCount_ = 0; + baseDeviceIndex = 0; + + for( i=0; i< initializerCount; ++i ) + { + hostApis_[hostApisCount_] = NULL; + result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ ); + if( result != paNoError ) + goto error; + + if( hostApis_[hostApisCount_] ) + { + + hostApis_[hostApisCount_]->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex; + + if( hostApis_[hostApisCount_]->info.defaultInputDevice != paNoDevice ) + hostApis_[hostApisCount_]->info.defaultInputDevice += baseDeviceIndex; + + if( hostApis_[hostApisCount_]->info.defaultOutputDevice != paNoDevice ) + hostApis_[hostApisCount_]->info.defaultOutputDevice += baseDeviceIndex; + + baseDeviceIndex += hostApis_[hostApisCount_]->info.deviceCount; + deviceCount_ += hostApis_[hostApisCount_]->info.deviceCount; + + ++hostApisCount_; + } + } + + return result; + +error: + TerminateHostApis(); + return result; +} + + +/* + FindHostApi() finds the index of the host api to which + <device> belongs and returns it. if <hostSpecificDeviceIndex> is + non-null, the host specific device index is returned in it. + returns -1 if <device> is out of range. + +*/ +static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex ) +{ + int i=0; + + if( !PA_IS_INITIALISED_ ) + return -1; + + if( device < 0 ) + return -1; + + while( i < hostApisCount_ + && device >= hostApis_[i]->info.deviceCount ) + { + + device -= hostApis_[i]->info.deviceCount; + ++i; + } + + if( i >= hostApisCount_ ) + return -1; + + if( hostSpecificDeviceIndex ) + *hostSpecificDeviceIndex = device; + + return i; +} + + +static void AddOpenStream( PaStream* stream ) +{ + ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_; + firstOpenStream_ = (PaUtilStreamRepresentation*)stream; +} + + +static void RemoveOpenStream( PaStream* stream ) +{ + PaUtilStreamRepresentation *previous = NULL; + PaUtilStreamRepresentation *current = firstOpenStream_; + + while( current != NULL ) + { + if( ((PaStream*)current) == stream ) + { + if( previous == NULL ) + { + firstOpenStream_ = current->nextOpenStream; + } + else + { + previous->nextOpenStream = current->nextOpenStream; + } + return; + } + else + { + previous = current; + current = current->nextOpenStream; + } + } +} + + +static void CloseOpenStreams( void ) +{ + /* we call Pa_CloseStream() here to ensure that the same destruction + logic is used for automatically closed streams */ + + while( firstOpenStream_ != NULL ) + Pa_CloseStream( firstOpenStream_ ); +} + + +PaError Pa_Initialize( void ) +{ + PaError result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint( "Pa_Initialize called.\n" ); +#endif + + if( PA_IS_INITIALISED_ ) + { + ++initializationCount_; + result = paNoError; + } + else + { + PA_VALIDATE_ENDIANNESS; + + PaUtil_InitializeClock(); + PaUtil_ResetTraceMessages(); + + result = InitializeHostApis(); + if( result == paNoError ) + ++initializationCount_; + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint( "Pa_Initialize returned:\n" ); + PaUtil_DebugPrint( "\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +PaError Pa_Terminate( void ) +{ + PaError result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_Terminate called.\n" ); +#endif + + if( PA_IS_INITIALISED_ ) + { + if( --initializationCount_ == 0 ) + { + CloseOpenStreams(); + + TerminateHostApis(); + + PaUtil_DumpTraceMessages(); + } + result = paNoError; + } + else + { + result= paNotInitialized; + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_Terminate returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ) +{ + return &lastHostErrorInfo_; +} + + +const char *Pa_GetErrorText( PaError errorNumber ) +{ + const char *result; + + switch( errorNumber ) + { + case paNoError: result = "Success"; break; + case paNotInitialized: result = "PortAudio not initialized"; break; + /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError */ + case paUnanticipatedHostError: result = "Unanticipated host error"; break; + case paInvalidChannelCount: result = "Invalid number of channels"; break; + case paInvalidSampleRate: result = "Invalid sample rate"; break; + case paInvalidDevice: result = "Invalid device"; break; + case paInvalidFlag: result = "Invalid flag"; break; + case paSampleFormatNotSupported: result = "Sample format not supported"; break; + case paBadIODeviceCombination: result = "Illegal combination of I/O devices"; break; + case paInsufficientMemory: result = "Insufficient memory"; break; + case paBufferTooBig: result = "Buffer too big"; break; + case paBufferTooSmall: result = "Buffer too small"; break; + case paNullCallback: result = "No callback routine specified"; break; + case paBadStreamPtr: result = "Invalid stream pointer"; break; + case paTimedOut: result = "Wait timed out"; break; + case paInternalError: result = "Internal PortAudio error"; break; + case paDeviceUnavailable: result = "Device unavailable"; break; + case paIncompatibleHostApiSpecificStreamInfo: result = "Incompatible host API specific stream info"; break; + case paStreamIsStopped: result = "Stream is stopped"; break; + case paStreamIsNotStopped: result = "Stream is not stopped"; break; + default: result = "Illegal error number"; break; + } + return result; +} + + +PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ) +{ + PaHostApiIndex result; + int i; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex called:\n" ); + PaUtil_DebugPrint("\PaHostApiTypeId type: %d\n", type ); +#endif + + if( !PA_IS_INITIALISED_ ) + { + + result = -1; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex returned:\n" ); + PaUtil_DebugPrint("\tPaHostApiIndex: -1 [ PortAudio not initialized ]\n\n" ); +#endif + + } + else + { + result = -1; + + for( i=0; i < hostApisCount_; ++i ) + { + if( hostApis_[i]->info.type == type ) + { + result = i; + break; + } + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex returned:\n" ); + PaUtil_DebugPrint("\tPaHostApiIndex: %d\n\n", result ); +#endif + } + + return result; +} + + +PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi, + PaHostApiTypeId type ) +{ + PaError result; + int i; + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + } + else + { + result = paInternalError; /* @todo should return host API not found */ + + for( i=0; i < hostApisCount_; ++i ) + { + if( hostApis_[i]->info.type == type ) + { + *hostApi = hostApis_[i]; + result = paNoError; + break; + } + } + } + + return result; +} + + +PaError PaUtil_DeviceIndexToHostApiDeviceIndex( + PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi ) +{ + PaError result; + PaDeviceIndex x; + + x = device - hostApi->privatePaFrontInfo.baseDeviceIndex; + + if( x < 0 || x >= hostApi->info.deviceCount ) + { + result = paInvalidDevice; + } + else + { + *hostApiDevice = x; + result = paNoError; + } + + return result; +} + + +PaHostApiIndex Pa_CountHostApis( void ) +{ + int result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_CountHostApis called.\n" ); +#endif + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_CountHostApis returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; + } + else + { + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_CountHostApis returned:\n" ); + PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", hostApisCount_ ); +#endif + + return hostApisCount_; + } +} + + +PaHostApiIndex Pa_GetDefaultHostApi( void ) +{ + int result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDefaultHostApi called.\n" ); +#endif + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; + } + else + { + result = paDefaultHostApiIndex; + + /* internal consistency check: make sure that the default host api + index is within range */ + + if( result < 0 || result >= hostApisCount_ ) + { + result = paInternalError; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + } + else + { +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" ); + PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", result ); +#endif + } + + return result; + } +} + + +const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi ) +{ + PaHostApiInfo *info; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetHostApiInfo called:\n" ); + PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi ); +#endif + + if( !PA_IS_INITIALISED_ ) + { + info = NULL; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" ); + PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n\n" ); +#endif + + } + else if( hostApi < 0 || hostApi >= hostApisCount_ ) + { + info = NULL; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" ); + PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n\n" ); +#endif + + } + else + { + info = &hostApis_[hostApi]->info; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" ); + PaUtil_DebugPrint("\tPaHostApiInfo*: 0x%p\n", info ); + PaUtil_DebugPrint("\t{" ); + PaUtil_DebugPrint("\t\tint structVersion: %d\n", info->structVersion ); + PaUtil_DebugPrint("\t\tPaHostApiTypeId type: %d\n", info->type ); + PaUtil_DebugPrint("\t\tconst char *name: %s\n\n", info->name ); + PaUtil_DebugPrint("\t}\n\n" ); +#endif + + } + + return info; +} + + +PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex ) +{ + PaDeviceIndex result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex called:\n" ); + PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi ); + PaUtil_DebugPrint("\tint hostApiDeviceIndex: %d\n", hostApiDeviceIndex ); +#endif + + + if( !PA_IS_INITIALISED_ ) + { + result = paNoDevice; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceIndex: paNoDevice [ PortAudio not initialized ]\n\n" ); +#endif + + } + else + { + if( hostApi < 0 || hostApi >= hostApisCount_ ) + { + result = paNoDevice; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceIndex: paNoDevice [ hostApi out of range ]\n\n" ); +#endif + + } + else + { + if( hostApiDeviceIndex < 0 || + hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount ) + { + result = paNoDevice; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceIndex: paNoDevice [ hostApiDeviceIndex out of range ]\n\n" ); +#endif + + } + else + { + result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result ); +#endif + } + } + } + + return result; +} + + +PaDeviceIndex Pa_CountDevices( void ) +{ + PaDeviceIndex result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_CountDevices called.\n" ); +#endif + + if( !PA_IS_INITIALISED_ ) + { + result = 0; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_CountDevices returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceIndex: 0 [ PortAudio not initialized ]\n\n" ); +#endif + + } + else + { + result = deviceCount_; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_CountDevices returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result ); +#endif + + } + + return result; +} + + +PaDeviceIndex Pa_GetDefaultInputDevice( void ) +{ + PaHostApiIndex hostApi; + PaDeviceIndex result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDefaultInputDevice called.\n" ); +#endif + + hostApi = Pa_GetDefaultHostApi(); + if( hostApi < 0 ) + { + result = paNoDevice; + } + else + { + result = hostApis_[hostApi]->info.defaultInputDevice; + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDefaultInputDevice returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result ); +#endif + + return result; +} + + +PaDeviceIndex Pa_GetDefaultOutputDevice( void ) +{ + PaHostApiIndex hostApi; + PaDeviceIndex result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDefaultOutputDevice called.\n" ); +#endif + + hostApi = Pa_GetDefaultHostApi(); + if( hostApi < 0 ) + { + result = paNoDevice; + } + else + { + result = hostApis_[hostApi]->info.defaultOutputDevice; + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDefaultOutputDevice returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result ); +#endif + + return result; +} + + +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ) +{ + int hostSpecificDeviceIndex; + int hostApiIndex = FindHostApi( device, &hostSpecificDeviceIndex ); + PaDeviceInfo *result; + + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDeviceInfo called:\n" ); + PaUtil_DebugPrint("\tPaDeviceIndex device: %d\n", device ); +#endif + + if( hostApiIndex < 0 ) + { + result = NULL; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceInfo* NULL [ invalid device index ]\n\n" ); +#endif + + } + else + { + result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ]; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" ); + PaUtil_DebugPrint("\tPaDeviceInfo*: 0x%p:\n", result ); + PaUtil_DebugPrint("\t{" ); + + PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion ); + PaUtil_DebugPrint("\t\tconst char *name: %s\n", result->name ); + PaUtil_DebugPrint("\t\tPaHostApiIndex hostApi: %d\n", result->hostApi ); + PaUtil_DebugPrint("\t\tint maxInputChannels: %d\n", result->maxInputChannels ); + PaUtil_DebugPrint("\t\tint maxOutputChannels: %d\n", result->maxOutputChannels ); + PaUtil_DebugPrint("\t}\n\n" ); +#endif + + } + + return result; +} + + +/* + SampleFormatIsValid() returns 1 if sampleFormat is a sample format + defined in portaudio.h, or 0 otherwise. +*/ +static int SampleFormatIsValid( PaSampleFormat format ) +{ + switch( format & ~paNonInterleaved ) + { + case paFloat32: return 1; + case paInt16: return 1; + case paInt32: return 1; + case paInt24: return 1; + case paInt8: return 1; + case paUInt8: return 1; + case paCustomFormat: return 1; + default: return 0; + } +} + +/* + NOTE: make sure this validation list is kept syncronised with the one in + pa_hostapi.h + + ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream() + conform to the expected values as described below. This function is + also designed to be used with the proposed Pa_IsFormatSupported() function. + + There are basically two types of validation that could be performed: + Generic conformance validation, and device capability mismatch + validation. This function performs only generic conformance validation. + Validation that would require knowledge of device capabilities is + not performed because of potentially complex relationships between + combinations of parameters - for example, even if the sampleRate + seems ok, it might not be for a duplex stream - we have no way of + checking this in an API-neutral way, so we don't try. + + On success the function returns PaNoError and fills in hostApi, + hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure + the function returns an error code indicating the first encountered + parameter error. + + + If ValidateOpenStreamParameters() returns paNoError, the following + assertions are guaranteed to be true. + + - at least one of inputParameters & outputParmeters is valid (not NULL) + + - if inputParameters & outputParmeters are both valid, that + inputParameters->device & outputParmeters->device both use the same host api + + PaDeviceIndex inputParameters->device + - is within range (0 to Pa_CountDevices-1) Or: + - is paUseHostApiSpecificDeviceSpecification and + inputParameters->hostApiSpecificStreamInfo is non-NULL and refers + to a valid host api + + int inputParameters->channelCount + - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0 + - upper bound is NOT validated against device capabilities + + PaSampleFormat inputParameters->sampleFormat + - is one of the sample formats defined in portaudio.h + + void *inputParameters->hostApiSpecificStreamInfo + - if supplied its hostApi field matches the input device's host Api + + PaDeviceIndex outputParmeters->device + - is within range (0 to Pa_CountDevices-1) + + int outputParmeters->channelCount + - if inputDevice is valid, channelCount is > 0 + - upper bound is NOT validated against device capabilities + + PaSampleFormat outputParmeters->sampleFormat + - is one of the sample formats defined in portaudio.h + + void *outputParmeters->hostApiSpecificStreamInfo + - if supplied its hostApi field matches the output device's host Api + + double sampleRate + - is not an 'absurd' rate (less than 1000. or greater than 200000.) + - sampleRate is NOT validated against device capabilities + + PaStreamFlags streamFlags + - unused platform neutral flags are zero +*/ +static PaError ValidateOpenStreamParameters( + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + PaStreamFlags streamFlags, + PaUtilHostApiRepresentation **hostApi, + PaDeviceIndex *hostApiInputDevice, + PaDeviceIndex *hostApiOutputDevice ) +{ + int inputHostApiIndex=0, outputHostApiIndex=0; + + if( (inputParameters == NULL) && (outputParameters == NULL) ) + { + + return paInvalidDevice; /* @todo should be a new error code "invalid device parameters" or something */ + + } + else + { + if( inputParameters == NULL ) + { + *hostApiInputDevice = paNoDevice; + } + else if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + if( inputParameters->hostApiSpecificStreamInfo ) + { + inputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex( + ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType ); + + if( inputHostApiIndex != -1 ) + { + *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification; + *hostApi = hostApis_[inputHostApiIndex]; + } + else + { + return paInvalidDevice; + } + } + else + { + return paInvalidDevice; + } + } + else + { + if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ ) + return paInvalidDevice; + + inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice ); + if( inputHostApiIndex < 0 ) + return paInternalError; + + *hostApi = hostApis_[inputHostApiIndex]; + + if( inputParameters->channelCount <= 0 ) + return paInvalidChannelCount; + + if( !SampleFormatIsValid( inputParameters->sampleFormat ) ) + return paSampleFormatNotSupported; + + if( inputParameters->hostApiSpecificStreamInfo != NULL ) + { + if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType + != (*hostApi)->info.type ) + return paIncompatibleHostApiSpecificStreamInfo; + } + } + + if( outputParameters == NULL ) + { + *hostApiOutputDevice = paNoDevice; + } + else if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + if( outputParameters->hostApiSpecificStreamInfo ) + { + outputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex( + ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType ); + + if( outputHostApiIndex != -1 ) + { + *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification; + *hostApi = hostApis_[outputHostApiIndex]; + } + else + { + return paInvalidDevice; + } + } + else + { + return paInvalidDevice; + } + } + else + { + if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ ) + return paInvalidDevice; + + outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice ); + if( outputHostApiIndex < 0 ) + return paInternalError; + + *hostApi = hostApis_[outputHostApiIndex]; + + if( outputParameters->channelCount <= 0 ) + return paInvalidChannelCount; + + if( !SampleFormatIsValid( outputParameters->sampleFormat ) ) + return paSampleFormatNotSupported; + + if( outputParameters->hostApiSpecificStreamInfo != NULL ) + { + if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType + != (*hostApi)->info.type ) + return paIncompatibleHostApiSpecificStreamInfo; + } + } + + if( (inputParameters != NULL) && (outputParameters != NULL) ) + { + /* ensure that both devices use the same API */ + if( inputHostApiIndex != outputHostApiIndex ) + return paBadIODeviceCombination; + } + } + + + /* Check for absurd sample rates. */ + if( (sampleRate < 1000.0) || (sampleRate > 200000.0) ) + return paInvalidSampleRate; + + if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 ) + return paInvalidFlag; + + return paNoError; +} + + +PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + PaError result; + PaUtilHostApiRepresentation *hostApi; + PaDeviceIndex hostApiInputDevice, hostApiOutputDevice; + PaStreamParameters hostApiInputParameters, hostApiOutputParameters; + PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr; + + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_IsFormatSupported called:\n" ); + + if( inputParameters == NULL ){ + PaUtil_DebugPrint("\PaStreamParameters *inputParameters: NULL\n" ); + }else{ + PaUtil_DebugPrint("\PaStreamParameters *inputParameters: 0x%p\n", inputParameters ); + PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device ); + PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount ); + PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat ); + PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency ); + PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo ); + } + + if( outputParameters == NULL ){ + PaUtil_DebugPrint("\PaStreamParameters *outputParameters: NULL\n" ); + }else{ + PaUtil_DebugPrint("\PaStreamParameters *outputParameters: 0x%p\n", outputParameters ); + PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device ); + PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount ); + PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat ); + PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency ); + PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo ); + } + + PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate ); +#endif + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + return result; + } + + result = ValidateOpenStreamParameters( inputParameters, + outputParameters, + sampleRate, paNoFlag, + &hostApi, + &hostApiInputDevice, + &hostApiOutputDevice ); + if( result != paNoError ) + { +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + return result; + } + + + if( inputParameters ) + { + hostApiInputParameters.device = hostApiInputDevice; + hostApiInputParameters.channelCount = inputParameters->channelCount; + hostApiInputParameters.sampleFormat = inputParameters->sampleFormat; + hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency; + hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo; + hostApiInputParametersPtr = &hostApiInputParameters; + } + else + { + hostApiInputParametersPtr = NULL; + } + + if( outputParameters ) + { + hostApiOutputParameters.device = hostApiOutputDevice; + hostApiOutputParameters.channelCount = outputParameters->channelCount; + hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat; + hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency; + hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo; + hostApiOutputParametersPtr = &hostApiOutputParameters; + } + else + { + hostApiOutputParametersPtr = NULL; + } + + result = hostApi->IsFormatSupported( hostApi, + hostApiInputParametersPtr, hostApiOutputParametersPtr, + sampleRate ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_OpenStream returned:\n" ); + if( result == paFormatIsSupported ) + PaUtil_DebugPrint("\tPaError: 0 [ paFormatIsSupported ]\n\n" ); + else + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +PaError Pa_OpenStream( PaStream** stream, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result; + PaUtilHostApiRepresentation *hostApi; + PaDeviceIndex hostApiInputDevice, hostApiOutputDevice; + PaStreamParameters hostApiInputParameters, hostApiOutputParameters; + PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr; + + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_OpenStream called:\n" ); + PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream ); + + if( inputParameters == NULL ){ + PaUtil_DebugPrint("\PaStreamParameters *inputParameters: NULL\n" ); + }else{ + PaUtil_DebugPrint("\PaStreamParameters *inputParameters: 0x%p\n", inputParameters ); + PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device ); + PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount ); + PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat ); + PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency ); + PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo ); + } + + if( outputParameters == NULL ){ + PaUtil_DebugPrint("\PaStreamParameters *outputParameters: NULL\n" ); + }else{ + PaUtil_DebugPrint("\PaStreamParameters *outputParameters: 0x%p\n", outputParameters ); + PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device ); + PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount ); + PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat ); + PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency ); + PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo ); + } + + PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate ); + PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer ); + PaUtil_DebugPrint("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags ); + PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback ); + PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData ); +#endif + + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_OpenStream returned:\n" ); + PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + return result; + } + + /* Check for parameter errors. */ + + if( stream == NULL ) + { + result = paBadStreamPtr; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_OpenStream returned:\n" ); + PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + return result; + } + + result = ValidateOpenStreamParameters( inputParameters, + outputParameters, + sampleRate, streamFlags, + &hostApi, + &hostApiInputDevice, + &hostApiOutputDevice ); + if( result != paNoError ) + { +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_OpenStream returned:\n" ); + PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + return result; + } + + + if( inputParameters ) + { + hostApiInputParameters.device = hostApiInputDevice; + hostApiInputParameters.channelCount = inputParameters->channelCount; + hostApiInputParameters.sampleFormat = inputParameters->sampleFormat; + hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency; + hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo; + hostApiInputParametersPtr = &hostApiInputParameters; + } + else + { + hostApiInputParametersPtr = NULL; + } + + if( outputParameters ) + { + hostApiOutputParameters.device = hostApiOutputDevice; + hostApiOutputParameters.channelCount = outputParameters->channelCount; + hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat; + hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency; + hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo; + hostApiOutputParametersPtr = &hostApiOutputParameters; + } + else + { + hostApiOutputParametersPtr = NULL; + } + + result = hostApi->OpenStream( hostApi, stream, + hostApiInputParametersPtr, hostApiOutputParametersPtr, + sampleRate, framesPerBuffer, streamFlags, streamCallback, userData ); + + if( result == paNoError ) + AddOpenStream( *stream ); + + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_OpenStream returned:\n" ); + PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p\n", *stream ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +PaError Pa_OpenDefaultStream( PaStream** stream, + int inputChannelCount, + int outputChannelCount, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result; + PaStreamParameters hostApiInputParameters, hostApiOutputParameters; + PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_OpenDefaultStream called:\n" ); + PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream ); + PaUtil_DebugPrint("\tint inputChannelCount: %d\n", inputChannelCount ); + PaUtil_DebugPrint("\tint outputChannelCount: %d\n", outputChannelCount ); + PaUtil_DebugPrint("\tPaSampleFormat sampleFormat: %d\n", sampleFormat ); + PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate ); + PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer ); + PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback ); + PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData ); +#endif + + + if( inputChannelCount > 0 ) + { + hostApiInputParameters.device = Pa_GetDefaultInputDevice(); + hostApiInputParameters.channelCount = inputChannelCount; + hostApiInputParameters.sampleFormat = sampleFormat; + hostApiInputParameters.suggestedLatency = /* REVIEW: should we be using high input latency here? */ + Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency; + hostApiInputParameters.hostApiSpecificStreamInfo = NULL; + hostApiInputParametersPtr = &hostApiInputParameters; + } + else + { + hostApiInputParametersPtr = NULL; + } + + if( outputChannelCount > 0 ) + { + hostApiOutputParameters.device = Pa_GetDefaultOutputDevice(); + hostApiOutputParameters.channelCount = outputChannelCount; + hostApiOutputParameters.sampleFormat = sampleFormat; + hostApiOutputParameters.suggestedLatency = /* REVIEW: should we be using high input latency here? */ + Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency; + hostApiOutputParameters.hostApiSpecificStreamInfo = NULL; + hostApiOutputParametersPtr = &hostApiOutputParameters; + } + else + { + hostApiOutputParametersPtr = NULL; + } + + + result = Pa_OpenStream( + stream, hostApiInputParametersPtr, hostApiOutputParametersPtr, + sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_OpenDefaultStream returned:\n" ); + PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p", *stream ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +static PaError ValidateStream( PaStream* stream ) +{ + if( !PA_IS_INITIALISED_ ) return paNotInitialized; + + if( stream == NULL ) return paBadStreamPtr; + + if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC ) + return paBadStreamPtr; + + return paNoError; +} + + +PaError Pa_CloseStream( PaStream* stream ) +{ + PaUtilStreamInterface *interface; + PaError result = ValidateStream( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_CloseStream called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + /* always remove the open stream from our list, even if this function + eventually returns an error. Otherwise CloseOpenStreams() will + get stuck in an infinite loop */ + RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */ + + if( result == paNoError ) + { + interface = PA_STREAM_INTERFACE(stream); + if( !interface->IsStopped( stream ) ) + { + result = interface->Abort( stream ); + } + + if( result == paNoError ) /* REVIEW: shouldn't we close anyway? */ + result = interface->Close( stream ); + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_CloseStream returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ) +{ + PaError result = ValidateStream( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_SetStreamFinishedCallback called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); + PaUtil_DebugPrint("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback ); +#endif + + if( result == paNoError ) + { + if( !PA_STREAM_INTERFACE(stream)->IsStopped( stream ) ) + { + result = paStreamIsNotStopped ; + } + else + { + PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback; + } + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_SetStreamFinishedCallback returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; + +} + + +PaError Pa_StartStream( PaStream *stream ) +{ + PaError result = ValidateStream( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_StartStream called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( result == paNoError ) + { + if( !PA_STREAM_INTERFACE(stream)->IsStopped( stream ) ) + { + result = paStreamIsNotStopped ; + } + else + { + result = PA_STREAM_INTERFACE(stream)->Start( stream ); + } + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_StartStream returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +PaError Pa_StopStream( PaStream *stream ) +{ + PaError result = ValidateStream( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_StopStream called\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( result == paNoError ) + { + if( PA_STREAM_INTERFACE(stream)->IsStopped( stream ) ) + { + result = paStreamIsStopped; + } + else + { + result = PA_STREAM_INTERFACE(stream)->Stop( stream ); + } + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_StopStream returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +PaError Pa_AbortStream( PaStream *stream ) +{ + PaError result = ValidateStream( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_AbortStream called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( result == paNoError ) + { + if( PA_STREAM_INTERFACE(stream)->IsStopped( stream ) ) + { + result = paStreamIsStopped; + } + else + { + result = PA_STREAM_INTERFACE(stream)->Abort( stream ); + } + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_AbortStream returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +PaError Pa_IsStreamStopped( PaStream *stream ) +{ + PaError result = ValidateStream( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_IsStreamStopped called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( result == paNoError ) + result = PA_STREAM_INTERFACE(stream)->IsStopped( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_IsStreamStopped returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +PaError Pa_IsStreamActive( PaStream *stream ) +{ + PaError result = ValidateStream( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_IsStreamActive called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( result == paNoError ) + result = PA_STREAM_INTERFACE(stream)->IsActive( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_IsStreamActive returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ) +{ + PaError error = ValidateStream( stream ); + const PaStreamInfo *result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamInfo called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( error != paNoError ) + { + result = 0; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" ); + PaUtil_DebugPrint("\const PaStreamInfo*: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) ); +#endif + + } + else + { + result = &PA_STREAM_REP( stream )->streamInfo; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" ); + PaUtil_DebugPrint("\tconst PaStreamInfo*: 0x%p:\n", result ); + PaUtil_DebugPrint("\t{" ); + + PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion ); + PaUtil_DebugPrint("\t\tPaTime inputLatency: %f\n", result->inputLatency ); + PaUtil_DebugPrint("\t\tPaTime outputLatency: %f\n", result->outputLatency ); + PaUtil_DebugPrint("\t\tdouble sampleRate: %f\n", result->sampleRate ); + PaUtil_DebugPrint("\t}\n\n" ); +#endif + + } + + return result; +} + + +PaTime Pa_GetStreamTime( PaStream *stream ) +{ + PaError error = ValidateStream( stream ); + PaTime result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamTime called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( error != paNoError ) + { + result = 0; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" ); + PaUtil_DebugPrint("\tPaTime: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) ); +#endif + + } + else + { + result = PA_STREAM_INTERFACE(stream)->GetTime( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" ); + PaUtil_DebugPrint("\tPaTime: %g\n\n", result ); +#endif + + } + + return result; +} + + +double Pa_GetStreamCpuLoad( PaStream* stream ) +{ + PaError error = ValidateStream( stream ); + double result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamCpuLoad called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( error != paNoError ) + { + + result = 0.0; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" ); + PaUtil_DebugPrint("\tdouble: 0.0 [PaError error: %d ( %s )]\n\n", error, Pa_GetErrorText( error ) ); +#endif + + } + else + { + result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" ); + PaUtil_DebugPrint("\tdouble: %g\n\n", result ); +#endif + + } + + return result; +} + + +PaError Pa_ReadStream( PaStream* stream, + void *buffer, + unsigned long frames ) +{ + PaError result = ValidateStream( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_ReadStream called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + /* @todo should return an error if buffer is zero or frames <= 0 */ + if( frames > 0 && buffer != 0 ) + result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_ReadStream returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + + +PaError Pa_WriteStream( PaStream* stream, + void *buffer, + unsigned long frames ) +{ + PaError result = ValidateStream( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_WriteStream called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + /* @todo should return an error if buffer is zero or frames <= 0 */ + if( frames > 0 && buffer != 0 ) + result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_WriteStream returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return result; +} + +signed long Pa_GetStreamReadAvailable( PaStream* stream ) +{ + PaError error = ValidateStream( stream ); + signed long result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamReadAvailable called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( error != paNoError ) + { + result = 0; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" ); + PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) ); +#endif + + } + else + { + result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + } + + return result; +} + + +signed long Pa_GetStreamWriteAvailable( PaStream* stream ) +{ + PaError error = ValidateStream( stream ); + signed long result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamWriteAvailable called:\n" ); + PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream ); +#endif + + if( error != paNoError ) + { + result = 0; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" ); + PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) ); +#endif + + } + else + { + result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream ); + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" ); + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + } + + return result; +} + + +PaError Pa_GetSampleSize( PaSampleFormat format ) +{ + int result; + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetSampleSize called:\n" ); + PaUtil_DebugPrint("\tPaSampleFormat format: %d\n", format ); +#endif + + switch( format & ~paNonInterleaved ) + { + + case paUInt8: + case paInt8: + result = 1; + break; + + case paInt16: + result = 2; + break; + + case paInt24: + result = 3; + break; + + case paFloat32: + case paInt32: + result = 4; + break; + + default: + result = paSampleFormatNotSupported; + break; + } + +#ifdef PA_LOG_API_CALLS + PaUtil_DebugPrint("Pa_GetSampleSize returned:\n" ); + if( result > 0 ) + PaUtil_DebugPrint("\tint: %d\n\n", result ); + else + PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) ); +#endif + + return (PaError) result; +} + diff --git a/pd/portaudio/pa_common/pa_front.o b/pd/portaudio/pa_common/pa_front.o Binary files differnew file mode 100644 index 00000000..0ce74a68 --- /dev/null +++ b/pd/portaudio/pa_common/pa_front.o diff --git a/pd/portaudio/pa_common/pa_hostapi.h b/pd/portaudio/pa_common/pa_hostapi.h new file mode 100644 index 00000000..f1f7a7ea --- /dev/null +++ b/pd/portaudio/pa_common/pa_hostapi.h @@ -0,0 +1,238 @@ +#ifndef PA_HOSTAPI_H +#define PA_HOSTAPI_H +/* + * + * Portable Audio I/O Library + * host api representation + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + Virtualised host api mechanism used by pa_front. +*/ + +#include "portaudio.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +typedef struct PaUtilPrivatePaFrontHostApiInfo { +/* **for the use of pa_front.c only** + don't use fields in this structure, they my change at any time + use functions defined in pa_util.h if you think you need functionality + which can be derived from here +*/ + + unsigned long baseDeviceIndex; +}PaUtilPrivatePaFrontHostApiInfo; + + +/** The common header for all data structures whose pointers are passed through + the hostApiSpecificStreamInfo field of the PaStreamParameters structure. + Note that in order to keep the public PortAudio interface clean, this structure + is not used explicitly when declaring hostApiSpecificStreamInfo data structures + however some code in pa_front depends on the first 3 members being equivalent + with this structure. + @see PaStreamParameters +*/ +typedef struct PaUtilHostApiSpecificStreamInfoHeader +{ + unsigned long size; /**< size of whole structure including this header */ + PaHostApiTypeId hostApiType; /**< host API for which this data is intended */ + unsigned long version; /**< structure version */ +} PaUtilHostApiSpecificStreamInfoHeader; + + + +/* + PaUtilHostApiRepresentation must be implemented by each host api implementation. + +*/ + +typedef struct PaUtilHostApiRepresentation { + PaUtilPrivatePaFrontHostApiInfo privatePaFrontInfo; + + /** + The host api implementation should populate the info field. In the + case of info.defaultInputDevice and info.defaultOutputDevice the + values stored should be 0 based indicies within the host api's own + device index range (0 to deviceCount). These values will be converted + to global device indicies after PaUtilHostApiInitializer() returns. + */ + PaHostApiInfo info; + + PaDeviceInfo** deviceInfos; + + /** + (*Terminate)() is guaranteed to be called with a valid <hostApi> + parameter, which was previously returned from the same implementation's + initializer. + */ + void (*Terminate)( struct PaUtilHostApiRepresentation *hostApi ); + + /** + The inputParameters and outputParameters pointers should not be saved + as they will not remain valid after OpenStream is called. + + + The following guarantees are made about parameters to (*OpenStream)(): + + [NOTE: the following list up to *END PA FRONT VALIDATIONS* should be + kept in sync with the one for ValidateOpenStreamParameters and + Pa_OpenStream in pa_front.c] + + PaHostApiRepresentation *hostApi + - is valid for this implementation + + PaStream** stream + - is non-null + + - at least one of inputParameters & outputParmeters is valid (not NULL) + + - if inputParameters & outputParmeters are both valid, that + inputParameters->device & outputParmeters->device both use the same host api + + PaDeviceIndex inputParameters->device + - is within range (0 to Pa_CountDevices-1) Or: + - is paUseHostApiSpecificDeviceSpecification and + inputParameters->hostApiSpecificStreamInfo is non-NULL and refers + to a valid host api + + int inputParameters->numChannels + - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, numInputChannels is > 0 + - upper bound is NOT validated against device capabilities + + PaSampleFormat inputParameters->sampleFormat + - is one of the sample formats defined in portaudio.h + + void *inputParameters->hostApiSpecificStreamInfo + - if supplied its hostApi field matches the input device's host Api + + PaDeviceIndex outputParmeters->device + - is within range (0 to Pa_CountDevices-1) + + int outputParmeters->numChannels + - if inputDevice is valid, numInputChannels is > 0 + - upper bound is NOT validated against device capabilities + + PaSampleFormat outputParmeters->sampleFormat + - is one of the sample formats defined in portaudio.h + + void *outputParmeters->hostApiSpecificStreamInfo + - if supplied its hostApi field matches the output device's host Api + + double sampleRate + - is not an 'absurd' rate (less than 1000. or greater than 200000.) + - sampleRate is NOT validated against device capabilities + + PaStreamFlags streamFlags + - unused platform neutral flags are zero + + [*END PA FRONT VALIDATIONS*] + + + The following validations MUST be performed by (*OpenStream)(): + + - check that input device can support numInputChannels + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - if inputStreamInfo is supplied, validate its contents, + or return an error if no inputStreamInfo is expected + + - check that output device can support numOutputChannels + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - if outputStreamInfo is supplied, validate its contents, + or return an error if no outputStreamInfo is expected + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + + - check that the device supports sampleRate + + - alter sampleRate to a close allowable rate if necessary + + - validate inputLatency and outputLatency + + - validate any platform specific flags, if flags are supplied they + must be valid. + */ + PaError (*OpenStream)( struct PaUtilHostApiRepresentation *hostApi, + PaStream** stream, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerCallback, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); + + + PaError (*IsFormatSupported)( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +} PaUtilHostApiRepresentation; + + +/** + every host api implementation must supply a host api initializer in the + following form. +*/ +typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex ); + + +/** + paHostApiInitializers is a NULL-terminated array of host api initializers + for the host apis which will be initialized when Pa_Initialize() is called. + each platform has a file which defines paHostApiInitializers for that platform. + see pa_win_init.c for example. +*/ +extern PaUtilHostApiInitializer *paHostApiInitializers[]; + + +/** index of the default host API in the paHostApiInitializers array. Each + platform has a file which defines paDefaultHostApiIndex for that platform. + see pa_win_init.c for example. +*/ +extern int paDefaultHostApiIndex; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_HOSTAPI_H */ diff --git a/pd/portaudio/pa_common/pa_process.c b/pd/portaudio/pa_common/pa_process.c new file mode 100644 index 00000000..2fbeb277 --- /dev/null +++ b/pd/portaudio/pa_common/pa_process.c @@ -0,0 +1,1355 @@ +/* + * $Id: pa_process.c,v 1.1.2.28 2002/10/26 05:33:29 rossbencina Exp $ + * Portable Audio I/O Library + * streamCallback <-> host buffer processing adapter + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <assert.h> +#include <string.h> /* memset() */ + +#include "pa_process.h" +#include "pa_util.h" + +/** @file + The code in this file is not optimised yet. there may appear to be redundancies + that could be factored into common functions, but the redundanceis are left + intentionally as each appearance may have different optimisation possibilities. + + The optimisations which are planned involve only converting data in-place + where possible, rather than copying to the temp buffer(s). + + Note that in the extreme case of being able to convert in-place, and there + being no conversion necessary there should be some code which short-circuits + the operation. + + Cache tilings for intereave<->deinterleave also need to be considered. + + @todo The abort flag from the streamCallback is currently not honoured properly + in this file, see fixmes. + + @todo see FIXMEs + + @todo implement the streamFlags callback parameter, currently it is + always zero. It needs to be passed from the host layer somehow. +*/ + +#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024 + + +/* greatest common divisor - PGCD in french */ +static unsigned long GCD( unsigned long a, unsigned long b ) +{ + return (b==0) ? a : GCD( b, a%b); +} + +/* least common multiple - PPCM in french */ +static unsigned long LCM( unsigned long a, unsigned long b ) +{ + return (a*b) / GCD(a,b); +} + +#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b)) + +static unsigned long CalculateFrameShift( unsigned long M, unsigned long N ) +{ + unsigned long result = 0; + unsigned long i; + unsigned long lcm; + lcm = LCM( M, N ); + for( i = M; i < lcm; i += M ) + result = PA_MAX_( result, i % N ); + + return result; +} + + +PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp, + int inputChannelCount, PaSampleFormat userInputSampleFormat, + PaSampleFormat hostInputSampleFormat, + int outputChannelCount, PaSampleFormat userOutputSampleFormat, + PaSampleFormat hostOutputSampleFormat, + double sampleRate, + PaStreamFlags streamFlags, + unsigned long framesPerUserBuffer, + unsigned long framesPerHostBuffer, + PaUtilHostBufferSizeMode hostBufferSizeMode, + PaStreamCallback *streamCallback, void *userData ) +{ + PaError result = paNoError; + PaError bytesPerSample; + unsigned long tempInputBufferSize, tempOutputBufferSize; + + /* initialize buffer ptrs to zero so they can be freed if necessary in error */ + bp->tempInputBuffer = 0; + bp->tempInputBufferPtrs = 0; + bp->tempOutputBuffer = 0; + bp->tempOutputBufferPtrs = 0; + + bp->framesPerUserBuffer = framesPerUserBuffer; + bp->framesPerHostBuffer = framesPerHostBuffer; + + bp->inputChannelCount = inputChannelCount; + bp->outputChannelCount = outputChannelCount; + + bp->hostBufferSizeMode = hostBufferSizeMode; + + bp->hostInputChannels[0] = 0; + bp->hostOutputChannels[0] = 0; + + if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */ + { + bp->useNonAdaptingProcess = 1; + bp->framesInTempInputBuffer = 0; + bp->framesInTempOutputBuffer = 0; + + if( hostBufferSizeMode == paUtilFixedHostBufferSize + || hostBufferSizeMode == paUtilBoundedHostBufferSize ) + { + bp->framesPerTempBuffer = framesPerHostBuffer; + } + else /* unknown host buffer size */ + { + bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_; + } + } + else + { + bp->framesPerTempBuffer = framesPerUserBuffer; + + if( hostBufferSizeMode == paUtilFixedHostBufferSize + && framesPerHostBuffer % framesPerUserBuffer == 0 ) + { + bp->useNonAdaptingProcess = 1; + bp->framesInTempInputBuffer = 0; + bp->framesInTempOutputBuffer = 0; + } + else + { + bp->useNonAdaptingProcess = 0; + + if( inputChannelCount > 0 && outputChannelCount > 0 ) + { + /* full duplex */ + if( hostBufferSizeMode == paUtilFixedHostBufferSize ) + { + unsigned long frameShift = + CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer ); + + if( framesPerUserBuffer > framesPerHostBuffer ) + { + bp->framesInTempInputBuffer = frameShift; + bp->framesInTempOutputBuffer = 0; + } + else + { + bp->framesInTempInputBuffer = 0; + bp->framesInTempOutputBuffer = frameShift; + } + } + else /* variable host buffer size, add framesPerUserBuffer latency */ + { + bp->framesInTempInputBuffer = 0; + bp->framesInTempOutputBuffer = framesPerUserBuffer; + } + } + else + { + /* half duplex */ + bp->framesInTempInputBuffer = 0; + bp->framesInTempOutputBuffer = 0; + } + } + } + + + + if( inputChannelCount > 0 ) + { + bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat ); + if( bytesPerSample > 0 ) + { + bp->bytesPerHostInputSample = bytesPerSample; + } + else + { + result = bytesPerSample; + goto error; + } + + bytesPerSample = Pa_GetSampleSize( userInputSampleFormat ); + if( bytesPerSample > 0 ) + { + bp->bytesPerUserInputSample = bytesPerSample; + } + else + { + result = bytesPerSample; + goto error; + } + + bp->inputConverter = + PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, streamFlags ); + + + bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1; + + + tempInputBufferSize = + bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount; + + bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize ); + if( bp->tempInputBuffer == 0 ) + { + result = paInsufficientMemory; + goto error; + } + + if( bp->framesInTempInputBuffer > 0 ) + memset( bp->tempInputBuffer, 0, tempInputBufferSize ); + + if( userInputSampleFormat & paNonInterleaved ) + { + bp->tempInputBufferPtrs = + PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount ); + if( bp->tempInputBufferPtrs == 0 ) + { + result = paInsufficientMemory; + goto error; + } + } + + bp->hostInputChannels[0] = (PaUtilChannelDescriptor*) + PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2); + if( bp->hostInputChannels[0] == 0 ) + { + result = paInsufficientMemory; + goto error; + } + + bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount]; + } + + if( outputChannelCount > 0 ) + { + bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat ); + if( bytesPerSample > 0 ) + { + bp->bytesPerHostOutputSample = bytesPerSample; + } + else + { + result = bytesPerSample; + goto error; + } + + bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat ); + if( bytesPerSample > 0 ) + { + bp->bytesPerUserOutputSample = bytesPerSample; + } + else + { + result = bytesPerSample; + goto error; + } + + bp->outputConverter = + PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags ); + + + bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1; + + tempOutputBufferSize = + bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount; + + bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize ); + if( bp->tempOutputBuffer == 0 ) + { + result = paInsufficientMemory; + goto error; + } + + if( bp->framesInTempOutputBuffer > 0 ) + memset( bp->tempOutputBuffer, 0, tempOutputBufferSize ); + + if( userOutputSampleFormat & paNonInterleaved ) + { + bp->tempOutputBufferPtrs = + PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount ); + if( bp->tempOutputBufferPtrs == 0 ) + { + result = paInsufficientMemory; + goto error; + } + } + + bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*) + PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 ); + if( bp->hostOutputChannels[0] == 0 ) + { + result = paInsufficientMemory; + goto error; + } + + bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount]; + } + + PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator ); + + bp->samplePeriod = 1. / sampleRate; + + bp->streamCallback = streamCallback; + bp->userData = userData; + + return result; + +error: + if( bp->tempInputBuffer ) + PaUtil_FreeMemory( bp->tempInputBuffer ); + + if( bp->tempInputBufferPtrs ) + PaUtil_FreeMemory( bp->tempInputBufferPtrs ); + + if( bp->hostInputChannels[0] ) + PaUtil_FreeMemory( bp->hostInputChannels[0] ); + + if( bp->tempOutputBuffer ) + PaUtil_FreeMemory( bp->tempOutputBuffer ); + + if( bp->tempOutputBufferPtrs ) + PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); + + if( bp->hostOutputChannels[0] ) + PaUtil_FreeMemory( bp->hostOutputChannels[0] ); + + return result; +} + + +void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp ) +{ + if( bp->tempInputBuffer ) + PaUtil_FreeMemory( bp->tempInputBuffer ); + + if( bp->tempInputBufferPtrs ) + PaUtil_FreeMemory( bp->tempInputBufferPtrs ); + + if( bp->hostInputChannels[0] ) + PaUtil_FreeMemory( bp->hostInputChannels[0] ); + + if( bp->tempOutputBuffer ) + PaUtil_FreeMemory( bp->tempOutputBuffer ); + + if( bp->tempOutputBufferPtrs ) + PaUtil_FreeMemory( bp->tempOutputBufferPtrs ); + + if( bp->hostOutputChannels[0] ) + PaUtil_FreeMemory( bp->hostOutputChannels[0] ); +} + + +void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp, PaStreamCallbackTimeInfo* timeInfo ) +{ + bp->timeInfo = timeInfo; + + /* the first streamCallback will be called to process samples which are + currently in the input buffer before the ones starting at the timeInfo time */ + + bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod; + + (void)bp->timeInfo->currentTime; /* FIXME: @todo time info currentTime not implemented */ + + /* the first streamCallback will be called to generate samples which will be + outputted after the frames currently in the output buffer have been + outputted. */ + bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod; + + bp->hostInputFrameCount[1] = 0; + bp->hostOutputFrameCount[1] = 0; +} + + +static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, + PaUtilChannelDescriptor *hostInputChannels, + PaUtilChannelDescriptor *hostOutputChannels, + unsigned long frameCount ); + +static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, + PaUtilChannelDescriptor *hostInputChannels, + unsigned long frameCount ); + +static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, + PaUtilChannelDescriptor *hostOutputChannels, + unsigned long framesToProcess ); + +static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, int processPartialUserBuffers ); + +#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) ) + +unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult ) +{ + unsigned long framesToProcess, framesToGo; + unsigned long framesProcessed = 0; + + if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) + { + assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) == + (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) ); + } + + + if( bp->useNonAdaptingProcess ) + { + if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) + { + /* full duplex non-adapting process, splice buffers if they are + different lengths */ + + framesToGo = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]; /* relies on assert above for input/output equivalence */ + + do{ + unsigned long *hostInputFrameCount; + PaUtilChannelDescriptor *hostInputChannels; + unsigned long *hostOutputFrameCount; + PaUtilChannelDescriptor *hostOutputChannels; + unsigned long framesProcessedThisIteration; + + if( bp->hostInputFrameCount[0] != 0 ) + { + hostInputFrameCount = &bp->hostInputFrameCount[0]; + hostInputChannels = bp->hostInputChannels[0]; + } + else + { + hostInputFrameCount = &bp->hostInputFrameCount[1]; + hostInputChannels = bp->hostInputChannels[1]; + } + + if( bp->hostOutputFrameCount[0] != 0 ) + { + hostOutputFrameCount = &bp->hostOutputFrameCount[0]; + hostOutputChannels = bp->hostOutputChannels[0]; + } + else + { + hostOutputFrameCount = &bp->hostOutputFrameCount[1]; + hostOutputChannels = bp->hostOutputChannels[1]; + } + + framesToProcess = PA_MIN_( *hostInputFrameCount, + *hostOutputFrameCount ); + + assert( framesToProcess != 0 ); + + framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult, + hostInputChannels, hostOutputChannels, + framesToProcess ); + + *hostInputFrameCount -= framesProcessedThisIteration; + *hostOutputFrameCount -= framesProcessedThisIteration; + + framesProcessed += framesProcessedThisIteration; + framesToGo -= framesProcessedThisIteration; + + }while( framesToGo > 0 ); + } + else + { + /* half duplex non-adapting process, just process 1st and 2nd buffer */ + /* process first buffer */ + + framesToProcess = (bp->inputChannelCount != 0) + ? bp->hostInputFrameCount[0] + : bp->hostOutputFrameCount[0]; + + framesProcessed = NonAdaptingProcess( bp, streamCallbackResult, + bp->hostInputChannels[0], bp->hostOutputChannels[0], + framesToProcess ); + + /* process second buffer if provided */ + + framesToProcess = (bp->inputChannelCount != 0) + ? bp->hostInputFrameCount[1] + : bp->hostOutputFrameCount[1]; + if( framesToProcess > 0 ) + { + framesProcessed += NonAdaptingProcess( bp, streamCallbackResult, + bp->hostInputChannels[1], bp->hostOutputChannels[1], + framesToProcess ); + } + } + } + else /* block adaption necessary*/ + { + + if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 ) + { + /* full duplex */ + + if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed ) + { + framesProcessed = AdaptingProcess( bp, streamCallbackResult, + 0 /* dont process partial user buffers */ ); + } + else + { + framesProcessed = AdaptingProcess( bp, streamCallbackResult, + 1 /* process partial user buffers */ ); + } + } + else if( bp->inputChannelCount != 0 ) + { + /* input only */ + framesToProcess = bp->hostInputFrameCount[0]; + + framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult, + bp->hostInputChannels[0], framesToProcess ); + + framesToProcess = bp->hostInputFrameCount[1]; + if( framesToProcess > 0 ) + { + framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult, + bp->hostInputChannels[1], framesToProcess ); + } + } + else + { + /* output only */ + framesToProcess = bp->hostOutputFrameCount[0]; + + framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult, + bp->hostOutputChannels[0], framesToProcess ); + + framesToProcess = bp->hostOutputFrameCount[1]; + if( framesToProcess > 0 ) + { + framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult, + bp->hostOutputChannels[1], framesToProcess ); + } + } + } + + return framesProcessed; +} + + +void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp, + unsigned long frameCount ) +{ + if( frameCount == 0 ) + bp->hostInputFrameCount[0] = bp->framesPerHostBuffer; + else + bp->hostInputFrameCount[0] = frameCount; +} + + +void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data, unsigned int stride ) +{ + assert( channel < bp->inputChannelCount ); + + bp->hostInputChannels[0][channel].data = data; + bp->hostInputChannels[0][channel].stride = stride; +} + + +void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp, + unsigned int firstChannel, void *data, unsigned int channelCount ) +{ + unsigned int i; + unsigned int channel = firstChannel; + unsigned char *p = (unsigned char*)data; + + if( channelCount == 0 ) + channelCount = bp->inputChannelCount; + + assert( firstChannel < bp->inputChannelCount ); + assert( firstChannel + channelCount <= bp->inputChannelCount ); + + for( i=0; i< channelCount; ++i ) + { + bp->hostInputChannels[0][channel+i].data = p; + p += bp->bytesPerHostInputSample; + bp->hostInputChannels[0][channel+i].stride = channelCount; + } +} + + +void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data ) +{ + assert( channel < bp->inputChannelCount ); + + bp->hostInputChannels[0][channel].data = data; + bp->hostInputChannels[0][channel].stride = 1; +} + + +void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp, + unsigned long frameCount ) +{ + bp->hostInputFrameCount[1] = frameCount; +} + + +void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data, unsigned int stride ) +{ + assert( channel < bp->inputChannelCount ); + + bp->hostInputChannels[1][channel].data = data; + bp->hostInputChannels[1][channel].stride = stride; +} + + +void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp, + unsigned int firstChannel, void *data, unsigned int channelCount ) +{ + unsigned int i; + unsigned int channel = firstChannel; + unsigned char *p = (unsigned char*)data; + + if( channelCount == 0 ) + channelCount = bp->inputChannelCount; + + assert( firstChannel < bp->inputChannelCount ); + assert( firstChannel + channelCount <= bp->inputChannelCount ); + + for( i=0; i< channelCount; ++i ) + { + bp->hostInputChannels[1][channel+i].data = p; + p += bp->bytesPerHostInputSample; + bp->hostInputChannels[1][channel+i].stride = channelCount; + } +} + + +void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data ) +{ + assert( channel < bp->inputChannelCount ); + + bp->hostInputChannels[1][channel].data = data; + bp->hostInputChannels[1][channel].stride = 1; +} + + +void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp, + unsigned long frameCount ) +{ + if( frameCount == 0 ) + bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer; + else + bp->hostOutputFrameCount[0] = frameCount; +} + + +void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data, unsigned int stride ) +{ + assert( channel < bp->outputChannelCount ); + + bp->hostOutputChannels[0][channel].data = data; + bp->hostOutputChannels[0][channel].stride = stride; +} + + +void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp, + unsigned int firstChannel, void *data, unsigned int channelCount ) +{ + unsigned int i; + unsigned int channel = firstChannel; + unsigned char *p = (unsigned char*)data; + + if( channelCount == 0 ) + channelCount = bp->outputChannelCount; + + assert( firstChannel < bp->outputChannelCount ); + assert( firstChannel + channelCount <= bp->outputChannelCount ); + + for( i=0; i< channelCount; ++i ) + { + bp->hostOutputChannels[0][channel+i].data = p; + p += bp->bytesPerHostOutputSample; + bp->hostOutputChannels[0][channel+i].stride = channelCount; + } +} + + +void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data ) +{ + assert( channel < bp->outputChannelCount ); + + bp->hostOutputChannels[0][channel].data = data; + bp->hostOutputChannels[0][channel].stride = 1; +} + + +void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp, + unsigned long frameCount ) +{ + bp->hostOutputFrameCount[1] = frameCount; +} + + +void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data, unsigned int stride ) +{ + assert( channel < bp->outputChannelCount ); + + bp->hostOutputChannels[1][channel].data = data; + bp->hostOutputChannels[1][channel].stride = stride; +} + + +void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp, + unsigned int firstChannel, void *data, unsigned int channelCount ) +{ + unsigned int i; + unsigned int channel = firstChannel; + unsigned char *p = (unsigned char*)data; + + if( channelCount == 0 ) + channelCount = bp->outputChannelCount; + + assert( firstChannel < bp->outputChannelCount ); + assert( firstChannel + channelCount <= bp->outputChannelCount ); + + for( i=0; i< channelCount; ++i ) + { + bp->hostOutputChannels[1][channel+i].data = p; + p += bp->bytesPerHostOutputSample; + bp->hostOutputChannels[1][channel+i].stride = channelCount; + } +} + + +void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, + unsigned int channel, void *data ) +{ + assert( channel < bp->outputChannelCount ); + + bp->hostOutputChannels[1][channel].data = data; + bp->hostOutputChannels[1][channel].stride = 1; +} + + +/* + NonAdaptingProcess() is a simple buffer copying adaptor that can handle + both full and half duplex copies. It processes framesToProcess frames, + broken into blocks bp->framesPerTempBuffer long. + This routine can be used when the streamCallback doesn't care what length the + buffers are, or when framesToProcess is an integer multiple of + bp->framesPerTempBuffer, in which case streamCallback will always be called + with bp->framesPerTempBuffer samples. +*/ +static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, + PaUtilChannelDescriptor *hostInputChannels, + PaUtilChannelDescriptor *hostOutputChannels, + unsigned long framesToProcess ) +{ + void *userInput, *userOutput; + unsigned char *srcBytePtr, *destBytePtr; + unsigned int srcStride, srcBytePtrStride; + unsigned int destStride, destBytePtrStride; + unsigned int i; + unsigned long frameCount; + unsigned long framesToGo = framesToProcess; + unsigned long framesProcessed = 0; + unsigned long statusFlags = 0; // FIXME: implement this + + do + { + frameCount = ( bp->framesPerTempBuffer < framesToGo ) + ? bp->framesPerTempBuffer + : framesToGo; + + /* configure user input buffer and convert input data (host -> user) */ + if( bp->inputChannelCount == 0 ) + { + /* no input */ + userInput = 0; + } + else /* there are input channels */ + { + /* + could use more elaborate logic here and sometimes process + buffers in-place. + */ + + destBytePtr = bp->tempInputBuffer; + + if( bp->userInputIsInterleaved ) + { + destStride = bp->inputChannelCount; + destBytePtrStride = bp->bytesPerUserInputSample; + userInput = bp->tempInputBuffer; + } + else /* user input is not interleaved */ + { + destStride = 1; + destBytePtrStride = frameCount * bp->bytesPerUserInputSample; + + /* setup non-interleaved ptrs */ + for( i=0; i<bp->inputChannelCount; ++i ) + { + bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + + i * bp->bytesPerUserInputSample * frameCount; + } + + userInput = bp->tempInputBufferPtrs; + } + + for( i=0; i<bp->inputChannelCount; ++i ) + { + bp->inputConverter( destBytePtr, destStride, + hostInputChannels[i].data, + hostInputChannels[i].stride, + frameCount, &bp->ditherGenerator ); + + destBytePtr += destBytePtrStride; /* skip to next destination channel */ + + /* advance src ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; + } + } + + /* configure user output buffer */ + if( bp->outputChannelCount == 0 ) + { + /* no output */ + userOutput = 0; + } + else /* there are output channels */ + { + if( bp->userOutputIsInterleaved ) + { + userOutput = bp->tempOutputBuffer; + } + else /* user output is not interleaved */ + { + for( i = 0; i < bp->outputChannelCount; ++i ) + { + bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + + i * bp->bytesPerUserOutputSample * frameCount; + } + + userOutput = bp->tempOutputBufferPtrs; + } + } + + *streamCallbackResult = bp->streamCallback( userInput, userOutput, + frameCount, bp->timeInfo, + statusFlags, bp->userData ); + + bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod; + bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod; + + + // FIXME: if streamCallback result is abort, then abort! + + /* convert output data (user -> host) */ + if( bp->outputChannelCount != 0 ) + { + /* + could use more elaborate logic here and sometimes process + buffers in-place. + */ + + srcBytePtr = bp->tempOutputBuffer; + + if( bp->userOutputIsInterleaved ) + { + srcStride = bp->outputChannelCount; + srcBytePtrStride = bp->bytesPerUserOutputSample; + } + else /* user output is not interleaved */ + { + srcStride = 1; + srcBytePtrStride = frameCount * bp->bytesPerUserOutputSample; + } + + for( i=0; i<bp->outputChannelCount; ++i ) + { + bp->outputConverter( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + srcBytePtr, srcStride, + frameCount, &bp->ditherGenerator ); + + srcBytePtr += srcBytePtrStride; /* skip to next source channel */ + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + } + + framesProcessed += frameCount; + + framesToGo -= frameCount; + } + while( framesToGo > 0 ); + + return framesProcessed; +} + + +/* + AdaptingInputOnlyProcess() is a half duplex input buffer processor. It + converts data from the input buffers into the temporary input buffer, + when the temporary input buffer is full, it calls the streamCallback. +*/ +static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, + PaUtilChannelDescriptor *hostInputChannels, + unsigned long framesToProcess ) +{ + void *userInput, *userOutput; + unsigned char *destBytePtr; + unsigned int destStride, destBytePtrStride; + unsigned int i; + unsigned long frameCount; + unsigned long framesToGo = framesToProcess; + unsigned long framesProcessed = 0; + unsigned long statusFlags = 0; // FIXME: implement this + + userOutput = 0; + + do + { + frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer ) + ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer ) + : framesToGo; + + /* convert frameCount samples into temp buffer */ + + if( bp->userInputIsInterleaved ) + { + destBytePtr = ((unsigned char*)bp->tempInputBuffer) + + bp->bytesPerUserInputSample * bp->inputChannelCount * + bp->framesInTempInputBuffer; + + destStride = bp->inputChannelCount; + destBytePtrStride = bp->bytesPerUserInputSample; + + userInput = bp->tempInputBuffer; + } + else /* user input is not interleaved */ + { + destBytePtr = ((unsigned char*)bp->tempInputBuffer) + + bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; + + destStride = 1; + destBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; + + /* setup non-interleaved ptrs */ + for( i=0; i<bp->inputChannelCount; ++i ) + { + bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + + i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer; + } + + userInput = bp->tempInputBufferPtrs; + } + + for( i=0; i<bp->inputChannelCount; ++i ) + { + bp->inputConverter( destBytePtr, destStride, + hostInputChannels[i].data, + hostInputChannels[i].stride, + frameCount, &bp->ditherGenerator ); + + destBytePtr += destBytePtrStride; /* skip to next destination channel */ + + /* advance src ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; + } + + bp->framesInTempInputBuffer += frameCount; + + if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer ) + { + bp->timeInfo->outputBufferDacTime = 0; + + *streamCallbackResult = bp->streamCallback( userInput, userOutput, + bp->framesPerUserBuffer, bp->timeInfo, + statusFlags, bp->userData ); + + bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod; + + // FIXME: if streamCallback result is abort, then abort! + + bp->framesInTempInputBuffer = 0; + } + + framesProcessed += frameCount; + + framesToGo -= frameCount; + }while( framesToGo > 0 ); + + return framesProcessed; +} + + +/* + AdaptingOutputOnlyProcess() is a half duplex output buffer processor. + It converts data from the temporary output buffer, to the output buffers, + when the temporary output buffer is empty, it calls the streamCallback. +*/ +static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, + PaUtilChannelDescriptor *hostOutputChannels, + unsigned long framesToProcess ) +{ + void *userInput, *userOutput; + unsigned char *srcBytePtr; + unsigned int srcStride, srcBytePtrStride; + unsigned int i; + unsigned long frameCount; + unsigned long framesToGo = framesToProcess; + unsigned long framesProcessed = 0; + unsigned long statusFlags = 0; // FIXME: implement this + + do + { + if( bp->framesInTempOutputBuffer == 0 ) + { + userInput = 0; + + /* setup userOutput */ + if( bp->userOutputIsInterleaved ) + { + userOutput = bp->tempOutputBuffer; + } + else /* user output is not interleaved */ + { + for( i = 0; i < bp->outputChannelCount; ++i ) + { + bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + + i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; + } + + userOutput = bp->tempOutputBufferPtrs; + } + + bp->timeInfo->inputBufferAdcTime = 0; + + *streamCallbackResult = bp->streamCallback( userInput, userOutput, + bp->framesPerUserBuffer, bp->timeInfo, + statusFlags, bp->userData ); + + bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; + + // FIXME: if streamCallback result is abort, then abort! + + bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; + } + + frameCount = ( bp->framesInTempOutputBuffer > framesToGo ) + ? framesToGo + : bp->framesInTempOutputBuffer; + + /* convert frameCount frames from user buffer to host buffer */ + + if( bp->userOutputIsInterleaved ) + { + srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + + bp->bytesPerUserOutputSample * bp->outputChannelCount * + (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); + + srcStride = bp->outputChannelCount; + srcBytePtrStride = bp->bytesPerUserOutputSample; + } + else /* user output is not interleaved */ + { + srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + + bp->bytesPerUserOutputSample * + (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); + + srcStride = 1; + srcBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; + } + + for( i=0; i<bp->outputChannelCount; ++i ) + { + bp->outputConverter( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + srcBytePtr, srcStride, + frameCount, &bp->ditherGenerator ); + + srcBytePtr += srcBytePtrStride; /* skip to next source channel */ + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + + bp->framesInTempOutputBuffer -= frameCount; + + framesProcessed += frameCount; + + framesToGo -= frameCount; + + }while( framesToGo > 0 ); + + return framesProcessed; +} + + +/* + AdaptingProcess is a full duplex adapting buffer processor. It converts + data from the temporary output buffer into the host output buffers, then + from the host input buffers into the temporary input buffers. Calling the + streamCallback when necessary. + When processPartialUserBuffers is 0, all available input data will be + consumed and all available output space will be filled. When + processPartialUserBuffers is non-zero, as many full user buffers + as possible will be processed, but partial buffers will not be consumed. +*/ +static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp, + int *streamCallbackResult, int processPartialUserBuffers ) +{ + void *userInput, *userOutput; + unsigned long framesProcessed = 0; + unsigned long framesAvailable; + unsigned long endProcessingMinFrameCount; + unsigned long maxFramesToCopy; + PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels; + unsigned int frameCount; + unsigned char *srcBytePtr, *destBytePtr; + unsigned int srcStride, srcBytePtrStride, destStride, destBytePtrStride; + unsigned int i; + unsigned long statusFlags = 0; // FIXME: implement this + + framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffers frame count */ + + if( processPartialUserBuffers ) + endProcessingMinFrameCount = 0; + else + endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1); + + while( framesAvailable > endProcessingMinFrameCount ) + { + /* copy frames from user to host output buffers */ + while( bp->framesInTempOutputBuffer > 0 && + ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) ) + { + maxFramesToCopy = bp->framesInTempOutputBuffer; + + /* select the output buffer set (1st or 2nd) */ + if( bp->hostOutputFrameCount[0] > 0 ) + { + hostOutputChannels = bp->hostOutputChannels[0]; + frameCount = (bp->hostOutputFrameCount[0] < maxFramesToCopy) + ? bp->hostOutputFrameCount[0] + : maxFramesToCopy; + } + else + { + hostOutputChannels = bp->hostOutputChannels[1]; + frameCount = (bp->hostOutputFrameCount[1] < maxFramesToCopy) + ? bp->hostOutputFrameCount[1] + : maxFramesToCopy; + } + + if( bp->userOutputIsInterleaved ) + { + srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + + bp->bytesPerUserOutputSample * bp->outputChannelCount * + (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); + + srcStride = bp->outputChannelCount; + srcBytePtrStride = bp->bytesPerUserOutputSample; + } + else /* user output is not interleaved */ + { + srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) + + bp->bytesPerUserOutputSample * + (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer); + + srcStride = 1; + srcBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; + } + + for( i=0; i<bp->outputChannelCount; ++i ) + { + bp->outputConverter( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + srcBytePtr, srcStride, + frameCount, &bp->ditherGenerator ); + + srcBytePtr += srcBytePtrStride; /* skip to next source channel */ + + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + + if( bp->hostOutputFrameCount[0] > 0 ) + bp->hostOutputFrameCount[0] -= frameCount; + else + bp->hostOutputFrameCount[1] -= frameCount; + + bp->framesInTempOutputBuffer -= frameCount; + } + + + /* copy frames from host to user input buffers */ + while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer && + ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) ) + { + maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer; + + /* select the input buffer set (1st or 2nd) */ + if( bp->hostInputFrameCount[0] > 0 ) + { + hostInputChannels = bp->hostInputChannels[0]; + frameCount = (bp->hostInputFrameCount[0] < maxFramesToCopy) + ? bp->hostInputFrameCount[0] + : maxFramesToCopy; + } + else + { + hostInputChannels = bp->hostInputChannels[1]; + frameCount = (bp->hostInputFrameCount[1] < maxFramesToCopy) + ? bp->hostInputFrameCount[1] + : maxFramesToCopy; + } + + /* configure conversion destination pointers */ + if( bp->userInputIsInterleaved ) + { + destBytePtr = ((unsigned char*)bp->tempInputBuffer) + + bp->bytesPerUserInputSample * bp->inputChannelCount * + bp->framesInTempInputBuffer; + + destStride = bp->inputChannelCount; + destBytePtrStride = bp->bytesPerUserInputSample; + } + else /* user input is not interleaved */ + { + destBytePtr = ((unsigned char*)bp->tempInputBuffer) + + bp->bytesPerUserInputSample * bp->framesInTempInputBuffer; + + destStride = 1; + destBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserInputSample; + } + + for( i=0; i<bp->inputChannelCount; ++i ) + { + bp->inputConverter( destBytePtr, destStride, + hostInputChannels[i].data, + hostInputChannels[i].stride, + frameCount, &bp->ditherGenerator ); + + destBytePtr += destBytePtrStride; /* skip to next destination channel */ + + /* advance src ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; + } + + if( bp->hostInputFrameCount[0] > 0 ) + bp->hostInputFrameCount[0] -= frameCount; + else + bp->hostInputFrameCount[1] -= frameCount; + + bp->framesInTempInputBuffer += frameCount; + + /* update framesAvailable and framesProcessed based on input consumed + unless something is very wrong this will also correspond to the + amount of output generated */ + framesAvailable -= frameCount; + framesProcessed += frameCount; + } + + /* call streamCallback */ + if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer && + bp->framesInTempOutputBuffer == 0 ) + { + /* setup userInput */ + if( bp->userInputIsInterleaved ) + { + userInput = bp->tempInputBuffer; + } + else /* user input is not interleaved */ + { + for( i = 0; i < bp->inputChannelCount; ++i ) + { + bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + + i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample; + } + + userInput = bp->tempInputBufferPtrs; + } + + /* setup userOutput */ + if( bp->userOutputIsInterleaved ) + { + userOutput = bp->tempOutputBuffer; + } + else /* user output is not interleaved */ + { + for( i = 0; i < bp->outputChannelCount; ++i ) + { + bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + + i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample; + } + + userOutput = bp->tempOutputBufferPtrs; + } + + /* call streamCallback */ + + *streamCallbackResult = bp->streamCallback( userInput, userOutput, + bp->framesPerUserBuffer, bp->timeInfo, + statusFlags, bp->userData ); + + bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod; + bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod; + + + // FIXME: if streamCallback result is abort, then abort! + + + bp->framesInTempInputBuffer = 0; + bp->framesInTempOutputBuffer = bp->framesPerUserBuffer; + } + } + + return framesProcessed; +} diff --git a/pd/portaudio/pa_common/pa_process.h b/pd/portaudio/pa_common/pa_process.h new file mode 100644 index 00000000..47bc0d70 --- /dev/null +++ b/pd/portaudio/pa_common/pa_process.h @@ -0,0 +1,203 @@ +#ifndef PA_PROCESS_H +#define PA_PROCESS_H +/* + * $Id: pa_process.h,v 1.1.2.16 2002/10/26 05:33:29 rossbencina Exp $ + * Portable Audio I/O Library callback buffer processing adapters + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Phil Burk, Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "portaudio.h" +#include "pa_converters.h" +#include "pa_dither.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** @file + + @todo finish documentation for the buffer processor +*/ + +typedef enum { + paUtilFixedHostBufferSize, + paUtilBoundedHostBufferSize, + paUtilUnknownHostBufferSize, + paUtilVariableHostBufferSizePartialUsageAllowed, /**< the only mode where process() may not consume the whole buffer */ +}PaUtilHostBufferSizeMode; + + +typedef struct PaUtilChannelDescriptor{ + void *data; + unsigned int stride; +}PaUtilChannelDescriptor; + + +typedef struct { + unsigned long framesPerUserBuffer; + unsigned long framesPerHostBuffer; + + PaUtilHostBufferSizeMode hostBufferSizeMode; + int useNonAdaptingProcess; + unsigned long framesPerTempBuffer; + + unsigned int inputChannelCount; + unsigned int bytesPerHostInputSample; + unsigned int bytesPerUserInputSample; + int userInputIsInterleaved; + PaUtilConverter *inputConverter; + + unsigned int outputChannelCount; + unsigned int bytesPerHostOutputSample; + unsigned int bytesPerUserOutputSample; + int userOutputIsInterleaved; + PaUtilConverter *outputConverter; + + void *tempInputBuffer; /**< used for slips, block adaption, and conversion. */ + void **tempInputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user input */ + unsigned long framesInTempInputBuffer; /**< frames remaining in input buffer from previous adaption iteration */ + + void *tempOutputBuffer; /**< used for slips, block adaption, and conversion. */ + void **tempOutputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user output */ + unsigned long framesInTempOutputBuffer; /**< frames remaining in input buffer from previous adaption iteration */ + + PaStreamCallbackTimeInfo *timeInfo; + + unsigned long hostInputFrameCount[2]; + PaUtilChannelDescriptor *hostInputChannels[2]; + unsigned long hostOutputFrameCount[2]; + PaUtilChannelDescriptor *hostOutputChannels[2]; + + PaUtilTriangularDitherGenerator ditherGenerator; + + double samplePeriod; + + PaStreamCallback *streamCallback; + void *userData; +} PaUtilBufferProcessor; + + +/** + @param framesPerHostBuffer Specifies the number of frames per host buffer + for fixed the fixed buffer size mode, and the maximum number of frames + per host buffer for the bounded host buffer size mode. It is ignored for + the other modes. + + @note The interleave flag is ignored for host buffer formats. Host interleave + is determined by the use of different SetInput and SetOutput functions. +*/ +PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bufferProcessor, + int numInputChannels, PaSampleFormat userInputSampleFormat, + PaSampleFormat hostInputSampleFormat, + int numOutputChannels, PaSampleFormat userOutputSampleFormat, + PaSampleFormat hostOutputSampleFormat, + double sampleRate, + PaStreamFlags streamFlags, + unsigned long framesPerUserBuffer, /* 0 indicates don't care */ + unsigned long framesPerHostBuffer, + PaUtilHostBufferSizeMode hostBufferSizeMode, + PaStreamCallback *streamCallback, void *userData ); + + +void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bufferProcessor ); + + +/** + @param timeInfo Timing information for the first sample of the buffer(s) + passed to the buffer processor. The buffer processor may adjust this + information as necessary. +*/ +void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bufferProcessor, + PaStreamCallbackTimeInfo* timeInfo ); + +/** returns the number of frames processed */ +unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bufferProcessor, int *callbackResult ); + + +/** a 0 frameCount indicates to use the framesPerHostBuffer value passed to init */ +void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bufferProcessor, + unsigned long frameCount ); + + +void PaUtil_SetInputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data, unsigned int stride ); + +/** if channel count is zero use all channels as specified to initialize buffer processor */ +void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor, + unsigned int firstChannel, void *data, unsigned int channelCount ); + +void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data ); + + +void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bufferProcessor, + unsigned long frameCount ); + +void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data, unsigned int stride ); + +/** if channel count is zero use all channels as specified to initialize buffer processor */ +void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor, + unsigned int firstChannel, void *data, unsigned int channelCount ); + +void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data ); + +/** a 0 frameCount indicates to use the framesPerHostBuffer value passed to init */ +void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bufferProcessor, + unsigned long frameCount ); + +void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data, unsigned int stride ); + +/** if channel count is zero use all channels as specified to initialize buffer processor */ +void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor, + unsigned int firstChannel, void *data, unsigned int channelCount ); + +void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data ); + + +void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bufferProcessor, + unsigned long frameCount ); + +void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data, unsigned int stride ); + +/** if channel count is zero use all channels as specified to initialize buffer processor */ +void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor, + unsigned int firstChannel, void *data, unsigned int channelCount ); + +void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor, + unsigned int channel, void *data ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_PROCESS_H */ diff --git a/pd/portaudio/pa_common/pa_process.o b/pd/portaudio/pa_common/pa_process.o Binary files differnew file mode 100644 index 00000000..3429227b --- /dev/null +++ b/pd/portaudio/pa_common/pa_process.o diff --git a/pd/portaudio/pa_common/pa_skeleton.c b/pd/portaudio/pa_common/pa_skeleton.c new file mode 100644 index 00000000..d9a90f4b --- /dev/null +++ b/pd/portaudio/pa_common/pa_skeleton.c @@ -0,0 +1,724 @@ +/* + * $Id: pa_skeleton.c,v 1.1.2.27 2002/12/03 06:30:40 rossbencina Exp $ + * Portable Audio I/O Library skeleton implementation + * demonstrates how to use the common functions to implement support + * for a host API + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <string.h> /* strlen() */ + +#include "pa_util.h" +#include "pa_allocation.h" +#include "pa_hostapi.h" +#include "pa_stream.h" +#include "pa_cpuload.h" +#include "pa_process.h" + +/** @file + NOTE TO IMPLEMENTORS: + + This file is provided as a starting point for implementing support for + a new host API. IMPLEMENT ME comments are used to indicate functionality + which much be customised for each implementation. +*/ + + +/* prototypes for functions declared in this file */ + +PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ); +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); +static PaError CloseStream( PaStream* stream ); +static PaError StartStream( PaStream *stream ); +static PaError StopStream( PaStream *stream ); +static PaError AbortStream( PaStream *stream ); +static PaError IsStreamStopped( PaStream *s ); +static PaError IsStreamActive( PaStream *stream ); +static PaTime GetStreamInputLatency( PaStream *stream ); +static PaTime GetStreamOutputLatency( PaStream *stream ); +static PaTime GetStreamTime( PaStream *stream ); +static double GetStreamCpuLoad( PaStream* stream ); +static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); +static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames ); +static signed long GetStreamReadAvailable( PaStream* stream ); +static signed long GetStreamWriteAvailable( PaStream* stream ); + + +/* IMPLEMENT ME: a macro like the following one should be used for reporting + host errors */ +#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \ + PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) + +/* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */ + +typedef struct +{ + PaUtilHostApiRepresentation inheritedHostApiRep; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; + + PaUtilAllocationGroup *allocations; + + /* implementation specific data goes here */ +} +PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */ + + +PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) +{ + PaError result = paNoError; + int i, deviceCount; + PaSkeletonHostApiRepresentation *skeletonHostApi; + PaDeviceInfo *deviceInfoArray; + + skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) ); + if( !skeletonHostApi ) + { + result = paInsufficientMemory; + goto error; + } + + skeletonHostApi->allocations = PaUtil_CreateAllocationGroup(); + if( !skeletonHostApi->allocations ) + { + result = paInsufficientMemory; + goto error; + } + + *hostApi = &skeletonHostApi->inheritedHostApiRep; + (*hostApi)->info.structVersion = 1; + (*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */ + (*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */ + + (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */ + (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */ + + (*hostApi)->info.deviceCount = 0; + + deviceCount = 0; /* IMPLEMENT ME */ + + if( deviceCount > 0 ) + { + (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ); + if( !(*hostApi)->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( + skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + for( i=0; i < deviceCount; ++i ) + { + PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg: + deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 ); + if( !deviceName ) + { + result = paInsufficientMemory; + goto error; + } + strcpy( deviceName, srcName ); + deviceInfo->name = deviceName; + */ + + deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */ + deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */ + + deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */ + deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */ + deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */ + deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */ + + deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */ + + (*hostApi)->deviceInfos[i] = deviceInfo; + ++(*hostApi)->info.deviceCount; + } + } + + (*hostApi)->Terminate = Terminate; + (*hostApi)->OpenStream = OpenStream; + (*hostApi)->IsFormatSupported = IsFormatSupported; + + PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable ); + + PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream, + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + + return result; + +error: + if( skeletonHostApi ) + { + if( skeletonHostApi->allocations ) + { + PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); + PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); + } + + PaUtil_FreeMemory( skeletonHostApi ); + } + return result; +} + + +static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) +{ + PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi; + + /* + IMPLEMENT ME: + - clean up any resourced not handled by the allocation group + */ + + if( skeletonHostApi->allocations ) + { + PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); + PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); + } + + PaUtil_FreeMemory( skeletonHostApi ); +} + + +static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) +{ + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat, outputSampleFormat; + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support inputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + else + { + outputChannelCount = 0; + } + + /* + IMPLEMENT ME: + - check that input device can support inputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + + - check that the device supports sampleRate + */ + + return paFormatIsSupported; +} + +/* PaSkeletonStream - a stream data structure specifically for this implementation */ + +typedef struct PaSkeletonStream +{ /* IMPLEMENT ME: rename this */ + PaUtilStreamRepresentation streamRepresentation; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; + + /* IMPLEMENT ME: + - implementation specific data goes here + */ + unsigned long framesPerHostCallback; /* just an example */ +} +PaSkeletonStream; + +/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ + +static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) +{ + PaError result = paNoError; + PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi; + PaSkeletonStream *stream = 0; + unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */ + int inputChannelCount, outputChannelCount; + PaSampleFormat inputSampleFormat=0, outputSampleFormat=0; + PaSampleFormat hostInputSampleFormat=0, hostOutputSampleFormat=0; + + + if( inputParameters ) + { + inputChannelCount = inputParameters->channelCount; + inputSampleFormat = inputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that input device can support inputChannelCount */ + if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + return paInvalidChannelCount; + + /* validate inputStreamInfo */ + if( inputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + + /* IMPLEMENT ME - establish which host formats are available */ + hostInputSampleFormat = + PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat ); + } + else + { + inputChannelCount = 0; + } + + if( outputParameters ) + { + outputChannelCount = outputParameters->channelCount; + outputSampleFormat = outputParameters->sampleFormat; + + /* unless alternate device specification is supported, reject the use of + paUseHostApiSpecificDeviceSpecification */ + + if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + /* check that output device can support inputChannelCount */ + if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + return paInvalidChannelCount; + + /* validate outputStreamInfo */ + if( outputParameters->hostApiSpecificStreamInfo ) + return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + + /* IMPLEMENT ME - establish which host formats are available */ + hostOutputSampleFormat = + PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat ); + } + else + { + outputChannelCount = 0; + } + + /* + IMPLEMENT ME: + + ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? ) + + - check that input device can support inputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format + + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported + + - check that the device supports sampleRate + + - alter sampleRate to a close allowable rate if possible / necessary + + - validate suggestedInputLatency and suggestedOutputLatency parameters, + use default values where necessary + */ + + + + + /* validate platform specific flags */ + if( (streamFlags & paPlatformSpecificFlags) != 0 ) + return paInvalidFlag; /* unexpected platform specific flag */ + + + stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) ); + if( !stream ) + { + result = paInsufficientMemory; + goto error; + } + + if( streamCallback ) + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &skeletonHostApi->callbackStreamInterface, streamCallback, userData ); + } + else + { + PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &skeletonHostApi->blockingStreamInterface, streamCallback, userData ); + } + + /* + IMPLEMENT ME: initialise the following fields with estimated or actual + values. + */ + stream->streamRepresentation.streamInfo.inputLatency = 0.; + stream->streamRepresentation.streamInfo.outputLatency = 0.; + stream->streamRepresentation.streamInfo.sampleRate = sampleRate; + + PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); + + + /* we assume a fixed host buffer size in this example, but the buffer processor + can also support bounded and unknown host buffer sizes by passing + paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of + paUtilFixedHostBufferSize below. */ + + result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, + inputChannelCount, inputSampleFormat, hostInputSampleFormat, + outputChannelCount, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerBuffer, + framesPerHostBuffer, paUtilFixedHostBufferSize, + streamCallback, userData ); + if( result != paNoError ) + goto error; + + /* + IMPLEMENT ME: + - additional stream setup + opening + */ + + stream->framesPerHostCallback = framesPerHostBuffer; + + *s = (PaStream*)stream; + + return result; + +error: + if( stream ) + PaUtil_FreeMemory( stream ); + + return result; +} + +/* + ExampleHostProcessingLoop() illustrates the kind of processing which may + occur in a host implementation. + +*/ +static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)userData; + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */ + int callbackResult; + unsigned long framesProcessed; + + PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); + + /* + IMPLEMENT ME: + - generate timing information + - handle buffer slips + */ + + /* + If you need to byte swap or shift inputBuffer to convert it into a + portaudio format, do it here. + */ + + + + PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo ); + + /* + depending on whether the host buffers are interleaved, non-interleaved + or a mixture, you will want to call PaUtil_SetInterleaved*Channels(), + PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here. + */ + + PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); + PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, + 0, /* first channel of inputBuffer is channel 0 */ + inputBuffer, + 0 ); /* 0 - use inputChannelCount passed to init buffer processor */ + + PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); + PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, + 0, /* first channel of outputBuffer is channel 0 */ + outputBuffer, + 0 ); /* 0 - use outputChannelCount passed to init buffer processor */ + + framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); + + + /* + If you need to byte swap or shift outputBuffer to convert it to + host format, do it here. + */ + + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + + + if( callbackResult == paContinue ) + { + /* nothing special to do */ + } + else if( callbackResult == paAbort ) + { + /* IMPLEMENT ME - finish playback immediately */ + + /* once finished, call the finished callback */ + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } + else + { + /* User callback has asked us to stop with paComplete or other non-zero value */ + + /* IMPLEMENT ME - finish playback once currently queued audio has completed */ + + /* once finished, call the finished callback */ + if( stream->streamRepresentation.streamFinishedCallback != 0 ) + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + } +} + + +/* + When CloseStream() is called, the multi-api layer ensures that + the stream has already been stopped or aborted. +*/ +static PaError CloseStream( PaStream* s ) +{ + PaError result = paNoError; + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* + IMPLEMENT ME: + - additional stream closing + cleanup + */ + + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); + PaUtil_FreeMemory( stream ); + + return result; +} + + +static PaError StartStream( PaStream *s ) +{ + PaError result = paNoError; + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return result; +} + + +static PaError StopStream( PaStream *s ) +{ + PaError result = paNoError; + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return result; +} + + +static PaError AbortStream( PaStream *s ) +{ + PaError result = paNoError; + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return result; +} + + +static PaError IsStreamStopped( PaStream *s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return 0; +} + + +static PaError IsStreamActive( PaStream *s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior */ + + return 0; +} + + +static PaTime GetStreamTime( PaStream *s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + + +static double GetStreamCpuLoad( PaStream* s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); +} + + +/* + As separate stream interfaces are used for blocking and callback + streams, the following functions can be guaranteed to only be called + for blocking streams. +*/ + +static PaError ReadStream( PaStream* s, + void *buffer, + unsigned long frames ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return paNoError; +} + + +static PaError WriteStream( PaStream* s, + void *buffer, + unsigned long frames ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return paNoError; +} + + +static signed long GetStreamReadAvailable( PaStream* s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + + +static signed long GetStreamWriteAvailable( PaStream* s ) +{ + PaSkeletonStream *stream = (PaSkeletonStream*)s; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + + return 0; +} + + + diff --git a/pd/portaudio/pa_common/pa_skeleton.o b/pd/portaudio/pa_common/pa_skeleton.o Binary files differnew file mode 100644 index 00000000..4641670a --- /dev/null +++ b/pd/portaudio/pa_common/pa_skeleton.o diff --git a/pd/portaudio/pa_common/pa_stream.c b/pd/portaudio/pa_common/pa_stream.c new file mode 100644 index 00000000..b2eba53d --- /dev/null +++ b/pd/portaudio/pa_common/pa_stream.c @@ -0,0 +1,114 @@ +/* + * $Id: pa_stream.c,v 1.1.2.9 2002/12/03 06:30:40 rossbencina Exp $ + * Portable Audio I/O Library + * + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 2002 Ross Bencina + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "pa_stream.h" + +void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface, + PaError (*Close)( PaStream* ), + PaError (*Start)( PaStream* ), + PaError (*Stop)( PaStream* ), + PaError (*Abort)( PaStream* ), + PaError (*IsStopped)( PaStream* ), + PaError (*IsActive)( PaStream* ), + PaTime (*GetTime)( PaStream* ), + double (*GetCpuLoad)( PaStream* ), + PaError (*Read)( PaStream*, void *, unsigned long ), + PaError (*Write)( PaStream*, void *, unsigned long ), + signed long (*GetReadAvailable)( PaStream* ), + signed long (*GetWriteAvailable)( PaStream* ) ) +{ + streamInterface->Close = Close; + streamInterface->Start = Start; + streamInterface->Stop = Stop; + streamInterface->Abort = Abort; + streamInterface->IsStopped = IsStopped; + streamInterface->IsActive = IsActive; + streamInterface->GetTime = GetTime; + streamInterface->GetCpuLoad = GetCpuLoad; + streamInterface->Read = Read; + streamInterface->Write = Write; + streamInterface->GetReadAvailable = GetReadAvailable; + streamInterface->GetWriteAvailable = GetWriteAvailable; +} + + +void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation, + PaUtilStreamInterface *streamInterface, + PaStreamCallback *streamCallback, + void *userData ) +{ + streamRepresentation->magic = PA_STREAM_MAGIC; + streamRepresentation->nextOpenStream = 0; + streamRepresentation->streamInterface = streamInterface; + streamRepresentation->streamCallback = streamCallback; + streamRepresentation->streamFinishedCallback = 0; + + streamRepresentation->userData = userData; + + streamRepresentation->streamInfo.inputLatency = 0.; + streamRepresentation->streamInfo.outputLatency = 0.; + streamRepresentation->streamInfo.sampleRate = 0.; +} + + +void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation ) +{ + streamRepresentation->magic = 0; +} + + +PaError PaUtil_DummyReadWrite( PaStream* stream, + void *buffer, + unsigned long frames ) +{ + (void)stream; /* unused parameter */ + (void)buffer; /* unused parameter */ + (void)frames; /* unused parameter */ + + return paNoError; /* @todo FIXME: need new error code paCantReadWriteToCallbackStream or something */ +} + + +signed long PaUtil_DummyGetAvailable( PaStream* stream ) +{ + (void)stream; /* unused parameter */ + + return 0; +} + + +double PaUtil_DummyGetCpuLoad( PaStream* stream ) +{ + (void)stream; /* unused parameter */ + + return 0.0; +} diff --git a/pd/portaudio/pa_common/pa_stream.h b/pd/portaudio/pa_common/pa_stream.h new file mode 100644 index 00000000..5e66c097 --- /dev/null +++ b/pd/portaudio/pa_common/pa_stream.h @@ -0,0 +1,128 @@ +#ifndef PA_STREAM_H +#define PA_STREAM_H +/* + * $Id: pa_stream.h,v 1.1.2.9 2002/12/03 06:30:40 rossbencina Exp $ + * Portable Audio I/O Library + * stream interface + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + Interface used by pa_front to virtualise stream calls. +*/ + +#include "portaudio.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +#define PA_STREAM_MAGIC (0x18273645) + +typedef struct { + /* + all PaStreamInterface functions are guaranteed to be called with a + non-null, valid <stream> parameter + */ + PaError (*Close)( PaStream* stream ); + PaError (*Start)( PaStream *stream ); + PaError (*Stop)( PaStream *stream ); + PaError (*Abort)( PaStream *stream ); + PaError (*IsStopped)( PaStream *stream ); + PaError (*IsActive)( PaStream *stream ); + PaTime (*GetTime)( PaStream *stream ); + double (*GetCpuLoad)( PaStream* stream ); + PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ); + PaError (*Write)( PaStream* stream, void *buffer, unsigned long frames ); + signed long (*GetReadAvailable)( PaStream* stream ); + signed long (*GetWriteAvailable)( PaStream* stream ); +} PaUtilStreamInterface; + + +void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface, + PaError (*Close)( PaStream* ), + PaError (*Start)( PaStream* ), + PaError (*Stop)( PaStream* ), + PaError (*Abort)( PaStream* ), + PaError (*IsStopped)( PaStream* ), + PaError (*IsActive)( PaStream* ), + PaTime (*GetTime)( PaStream* ), + double (*GetCpuLoad)( PaStream* ), + PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ), + PaError (*Write)( PaStream* stream, void *buffer, unsigned long frames ), + signed long (*GetReadAvailable)( PaStream* stream ), + signed long (*GetWriteAvailable)( PaStream* stream ) ); + + +/** Use PaUtil_DummyReadWrite and PaUtil_DummyGetAvailable for + callback based streams. +*/ +PaError PaUtil_DummyReadWrite( PaStream* stream, + void *buffer, + unsigned long frames ); + + +signed long PaUtil_DummyGetAvailable( PaStream* stream ); + +/** Use PaUtil_DummyGetCpuLoad for read/write streams +*/ +double PaUtil_DummyGetCpuLoad( PaStream* stream ); + + +typedef struct PaUtilStreamRepresentation { + unsigned long magic; /* set to PA_STREAM_MAGIC */ + struct PaUtilStreamRepresentation *nextOpenStream; /* field used by multi-api code */ + PaUtilStreamInterface *streamInterface; + PaStreamCallback *streamCallback; + PaStreamFinishedCallback *streamFinishedCallback; + void *userData; + PaStreamInfo streamInfo; +} PaUtilStreamRepresentation; + + +void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation, + PaUtilStreamInterface *streamInterface, + PaStreamCallback *streamCallback, + void *userData ); + +void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation ); + + +#define PA_STREAM_REP( streamRepPtr )\ + ((PaUtilStreamRepresentation*) streamRepPtr ) + +#define PA_STREAM_INTERFACE( streamRepPtr )\ + PA_STREAM_REP( streamRepPtr )->streamInterface + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_STREAM_H */ diff --git a/pd/portaudio/pa_common/pa_stream.o b/pd/portaudio/pa_common/pa_stream.o Binary files differnew file mode 100644 index 00000000..c75789bb --- /dev/null +++ b/pd/portaudio/pa_common/pa_stream.o diff --git a/pd/portaudio/pa_common/pa_trace.c b/pd/portaudio/pa_common/pa_trace.c index d55a6d37..74e8bb2f 100644 --- a/pd/portaudio/pa_common/pa_trace.c +++ b/pd/portaudio/pa_common/pa_trace.c @@ -1,5 +1,5 @@ /* - * $Id: pa_trace.c,v 1.1.1.1 2002/01/22 00:52:11 phil Exp $ + * $Id: pa_trace.c,v 1.1.1.1.2.2 2002/10/26 05:34:03 rossbencina Exp $ * Portable Audio I/O Library Trace Facility * Store trace information in real-time for later printing. * @@ -35,7 +35,7 @@ #include <string.h> #include "pa_trace.h" -#if TRACE_REALTIME_EVENTS +#if PA_TRACE_REALTIME_EVENTS static char *traceTextArray[MAX_TRACE_RECORDS]; static int traceIntArray[MAX_TRACE_RECORDS]; @@ -43,19 +43,19 @@ static int traceIndex = 0; static int traceBlock = 0; /*********************************************************************/ -void ResetTraceMessages() +void PaUtil_ResetTraceMessages() { traceIndex = 0; } /*********************************************************************/ -void DumpTraceMessages() +void PaUtil_DumpTraceMessages() { int i; - int numDump = (traceIndex < MAX_TRACE_RECORDS) ? traceIndex : MAX_TRACE_RECORDS; + int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS; printf("DumpTraceMessages: traceIndex = %d\n", traceIndex ); - for( i=0; i<numDump; i++ ) + for( i=0; i<messageCount; i++ ) { printf("%3d: %s = 0x%08X\n", i, traceTextArray[i], traceIntArray[i] ); @@ -65,14 +65,14 @@ void DumpTraceMessages() } /*********************************************************************/ -void AddTraceMessage( char *msg, int data ) +void PaUtil_AddTraceMessage( const char *msg, int data ) { - if( (traceIndex == MAX_TRACE_RECORDS) && (traceBlock == 0) ) + if( (traceIndex == PA_MAX_TRACE_RECORDS) && (traceBlock == 0) ) { traceBlock = 1; - /* DumpTraceMessages(); */ + /* PaUtil_DumpTraceMessages(); */ } - else if( traceIndex < MAX_TRACE_RECORDS ) + else if( traceIndex < PA_MAX_TRACE_RECORDS ) { traceTextArray[traceIndex] = msg; traceIntArray[traceIndex] = data; @@ -80,4 +80,4 @@ void AddTraceMessage( char *msg, int data ) } } -#endif +#endif /* TRACE_REALTIME_EVENTS */ diff --git a/pd/portaudio/pa_common/pa_trace.h b/pd/portaudio/pa_common/pa_trace.h index d0fc904c..069d006d 100644 --- a/pd/portaudio/pa_common/pa_trace.h +++ b/pd/portaudio/pa_common/pa_trace.h @@ -1,7 +1,7 @@ #ifndef PA_TRACE_H #define PA_TRACE_H /* - * $Id: pa_trace.h,v 1.1.1.1 2002/01/22 00:52:11 phil Exp $ + * $Id: pa_trace.h,v 1.1.1.1.2.2 2002/10/22 08:58:16 rossbencina Exp $ * Portable Audio I/O Library Trace Facility * Store trace information in real-time for later printing. * @@ -32,9 +32,13 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/** @file + Event trace mechanism for debugging. Allows data to be written to the buffer + at interrupt time and dumped later. +*/ -#define TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */ -#define MAX_TRACE_RECORDS (2048) +#define PA_TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */ +#define PA_MAX_TRACE_RECORDS (2048) #ifdef __cplusplus extern "C" @@ -42,24 +46,21 @@ extern "C" #endif /* __cplusplus */ - /************************************************************************************/ - /****************** Prototypes ******************************************************/ - /************************************************************************************/ - -#if TRACE_REALTIME_EVENTS - - void DumpTraceMessages(); - void ResetTraceMessages(); - void AddTraceMessage( char *msg, int data ); +#if PA_TRACE_REALTIME_EVENTS +void PaUtil_ResetTraceMessages(); +void PaUtil_AddTraceMessage( const char *msg, int data ); +void PaUtil_DumpTraceMessages(); + #else -#define AddTraceMessage(msg,data) /* noop */ -#define ResetTraceMessages() /* noop */ -#define DumpTraceMessages() /* noop */ +#define PaUtil_ResetTraceMessages() /* noop */ +#define PaUtil_AddTraceMessage(msg,data) /* noop */ +#define PaUtil_DumpTraceMessages() /* noop */ #endif + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/pd/portaudio/pa_common/pa_trace.o b/pd/portaudio/pa_common/pa_trace.o Binary files differnew file mode 100644 index 00000000..0c160bea --- /dev/null +++ b/pd/portaudio/pa_common/pa_trace.o diff --git a/pd/portaudio/pa_common/pa_util.h b/pd/portaudio/pa_common/pa_util.h new file mode 100644 index 00000000..c87d71ca --- /dev/null +++ b/pd/portaudio/pa_common/pa_util.h @@ -0,0 +1,143 @@ +#ifndef PA_UTIL_H +#define PA_UTIL_H +/* + * Id: + * Portable Audio I/O Library implementation utilities header + * common implementation utilities and interfaces + * + * Based on the Open Source API proposed by Ross Bencina + * Copyright (c) 1999-2002 Ross Bencina, Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "portaudio.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +struct PaUtilHostApiRepresentation; + + +/** Retrieve a specific host API representation. This function can be used + by implementations to retrieve a pointer to their representation in + host api specific extension functions which aren't passed a rep pointer + by pa_front.c. + + @param hostApi A pointer to a host API represenation pointer. Apon success + this will receive the requested representation pointer. + + @param type A valid host API type identifier. + + @returns An error code. If the result is PaNoError then a pointer to the + requested host API representation will be stored in *hostApi. +*/ +PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi, + PaHostApiTypeId type ); + + +/** Convert a PortAudio device index into a host API specific device index. + @param hostApiDevice Pointer to a device index, on success this will recieve the + converted device index value. + @param device The PortAudio device index to convert. + @param hostApi The host api which the index should be converted for. + + @returns On success returns PaNoError and places the converted index in the + hostApiDevice parameter. +*/ +PaError PaUtil_DeviceIndexToHostApiDeviceIndex( + PaDeviceIndex *hostApiDevice, PaDeviceIndex device, + struct PaUtilHostApiRepresentation *hostApi ); + + +/** Set the host error information returned by Pa_GetLastHostErrorInfo. This + function and the paUnanticipatedHostError error code should be used as a + last resort. Implementors should use existing PA error codes where possible, + or nominate new ones. Note that at it is always better to use + PaUtil_SetLastHostErrorInfo() and paUnanticipatedHostError than to return an + ambiguous or inaccurate PaError code. + + @param hostApiType The host API which encountered the error (ie of the caller) + + @param errorCode The error code returned by the native API function. + + @param errorText A string describing the error. PaUtil_SetLastHostErrorInfo + makes a copy of the string, so it is not necessary for the pointer to remain + valid after the call to PaUtil_SetLastHostErrorInfo() returns. + +*/ +void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode, + const char *errorText ); + + + +/** +PA_DEBUG() provides a simple debug message printing facility. The macro +passes it's argument to a printf-like function called PaUtil_DebugPrint() +which prints to stderr and always flushes the stream after printing. +Because preprocessor macros cannot directly accept variable length argument +lists, calls to the macro must include an additional set of parenthesis, eg: +PA_DEBUG(("errorno: %d", 1001 )); +*/ + +void PaUtil_DebugPrint( const char *format, ... ); + +#if (0) /* set to 1 to print debug messages */ +#define PA_DEBUG(x) PaUtil_DebugPrint x ; +#else +#define PA_DEBUG(x) +#endif + + +/* the following functions are implemented in a per-platform .c file */ + +void *PaUtil_AllocateMemory( long size ); +/**< Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */ + +void PaUtil_FreeMemory( void *block ); +/**< Realease block if non-NULL. block may be NULL */ + +int PaUtil_CountCurrentlyAllocatedBlocks( void ); +/**< + Return the number of currently allocated blocks. This function can be + used for detecting memory leaks. + + @note Allocations will only be tracked if PA_TRACK_MEMORY is #defined. If + it isn't, this function will always return 0. +*/ + + +void PaUtil_InitializeClock( void ); +double PaUtil_GetTime( void ); /* system time in seconds, used to implement CPU load functions */ + +/* void Pa_Sleep( long msec ); must also be implemented in per-platform .c file */ + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PA_UTIL_H */ diff --git a/pd/portaudio/pa_common/portaudio.h b/pd/portaudio/pa_common/portaudio.h index 06f7079b..68303e1c 100644 --- a/pd/portaudio/pa_common/portaudio.h +++ b/pd/portaudio/pa_common/portaudio.h @@ -1,5 +1,5 @@ -#ifndef PORT_AUDIO_H -#define PORT_AUDIO_H +#ifndef PORTAUDIO_H +#define PORTAUDIO_H #ifdef __cplusplus extern "C" @@ -7,12 +7,12 @@ extern "C" #endif /* __cplusplus */ /* - * $Id: portaudio.h,v 1.5 2002/03/26 18:04:22 philburk Exp $ + * $Id: portaudio.h,v 1.5.2.34 2002/12/03 07:02:54 rossbencina Exp $ * PortAudio Portable Real-Time Audio Library * PortAudio API Header File - * Latest version available at: http://www.audiomulch.com/portaudio/ + * Latest version available at: http://www.portaudio.com/ * - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * Copyright (c) 1999-2002 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files @@ -39,14 +39,31 @@ extern "C" * */ + +/** Retrieve the release number of the currently running PortAudio build, + eg 1900. +*/ +int Pa_GetVersion( void ); + + +/** Retrieve a textual description of the current PortAudio build, + eg "PortAudio V19-devel 13 October 2002". +*/ +const char* Pa_GetVersionText( void ); + + +/** Error codes returned by PortAudio functions. */ + typedef int PaError; -typedef enum { +typedef enum PaErrorCode +{ paNoError = 0, - paHostError = -10000, + paNotInitialized = -10000, + paUnanticipatedHostError, paInvalidChannelCount, paInvalidSampleRate, - paInvalidDeviceId, + paInvalidDevice, paInvalidFlag, paSampleFormatNotSupported, paBadIODeviceCombination, @@ -57,407 +74,999 @@ typedef enum { paBadStreamPtr, paTimedOut, paInternalError, - paDeviceUnavailable -} PaErrorNum; + paDeviceUnavailable, + paIncompatibleHostApiSpecificStreamInfo, + paStreamIsStopped, + paStreamIsNotStopped, + paInputOverflowed, + paOutputUnderflowed +} PaErrorCode; -/* - Pa_Initialize() is the library initialisation function - call this before - using the library. +/** Translate the supplied PortAudio error number into a human readable + message. */ +const char *Pa_GetErrorText( PaError errorNumber ); -PaError Pa_Initialize( void ); -/* - Pa_Terminate() is the library termination function - call this after - using the library. +/** Library initialization function - call this before using PortAudio. + This function initialises internal data structures and prepares underlying + host APIs for use. This function MUST be called before using any other + PortAudio API functions. + + If Pa_Initialize() is called multiple times, each call must be matched with + a corresponding call to Pa_Terminate(). Pairs of calls to + Pa_Initialize()/Pa_Terminate() may overlap, and are not requireed to be fully + nested. + @return paNoError if successful, otherwise an error code indicating the cause + of failure. + + @see Pa_Terminate */ +PaError Pa_Initialize( void ); + + +/** Library termination function - call this when finished using PortAudio. + This function deallocates all resources allocated by PortAudio since it was + initializied by a call to Pa_Initialize(). In cases where Pa_Initialise() has + been called multiple times, each call must be matched with a corresponding call + to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically + close any PortAudio streams that are still open. + Pa_Terminate() MUST be called before exiting a program which uses PortAudio. + Failure to do so may result in serious resource leaks, such as audio devices + not being available until the next reboot. + + @return paNoError if successful, otherwise an error code indicating the cause + of failure. + + @see Pa_Initialize +*/ PaError Pa_Terminate( void ); -/* - Pa_GetHostError() returns a host specific error code. - This can be called after receiving a PortAudio error code of paHostError. + +/** The type used to refer to audio devices. Values of this type usually + range from 0 to (Pa_DeviceCount-1), and may also take on the PaNoDevice + and paUseHostApiSpecificDeviceSpecification values. + + @see Pa_DeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification */ +typedef int PaDeviceIndex; -long Pa_GetHostError( void ); -/* - Pa_GetErrorText() translates the supplied PortAudio error number - into a human readable message. - +/** A special PaDeviceIndex value indicating that no device is available, + or should be used. + + @see PaDeviceIndex */ +#define paNoDevice ((PaDeviceIndex)-1) -const char *Pa_GetErrorText( PaError errnum ); -/* - Sample formats - - These are formats used to pass sound data between the callback and the - stream. Each device has a "native" format which may be used when optimum - efficiency or control over conversion is required. - - Formats marked "always available" are supported (emulated) by all - PortAudio implementations. - - The floating point representation (paFloat32) uses +1.0 and -1.0 as the - maximum and minimum respectively. +/** A special PaDeviceIndex value indicating that the device(s) to be used + are specified in the host api specific stream info structure. - paUInt8 is an unsigned 8 bit format where 128 is considered "ground" + @see PaDeviceIndex +*/ +#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2) + +/* Host API enumeration mechanism */ + +/** The type used to enumerate to host APIs at runtime. Values of this type + range from 0 to (Pa_CountHostApis()-1). + + @see Pa_CountHostApis */ +typedef int PaHostApiIndex; -typedef unsigned long PaSampleFormat; -#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/ -#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/ -#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/ -#define paInt24 ((PaSampleFormat) (1<<3)) -#define paPackedInt24 ((PaSampleFormat) (1<<4)) -#define paInt8 ((PaSampleFormat) (1<<5)) -#define paUInt8 ((PaSampleFormat) (1<<6)) -#define paCustomFormat ((PaSampleFormat) (1<<16)) -/* - Device enumeration mechanism. - - Device ids range from 0 to Pa_CountDevices()-1. - - Devices may support input, output or both. +/** Retrieve the number of available host APIs. Even if a host API is + available it may have no devices available. + @return A non-negative value indicating the number of available host APIs. + Returns a negative PaErrorCode if PortAudio is not initialized or an error + is encountered. + + @see PaHostApiIndex */ +PaHostApiIndex Pa_CountHostApis( void ); -typedef int PaDeviceID; -#define paNoDevice -1 -int Pa_CountDevices( void ); +/** Retrieve the index of the default host API. The default host API will be + the lowest common denominator host API on the current platform and is + unlikely to provide the best performance. -typedef struct + @return A non-negative value indicating the default host API index. Returns a + negative PaErrorCode if PortAudio is not initialized or an error is encountered. +*/ +PaHostApiIndex Pa_GetDefaultHostApi( void ); + + +/** Unchanging unique identifiers for each supported host API. This type + is used in the PaHostApiInfo structure. The values are guaranteed to be + unique and to never change, thus allowing code to be written that + conditionally uses host API specific extensions. + + New type ids will be allocated when support for a host API reaches + "public alpha" status, prior to that developers should use the + paInDevelopment type id. + + @see PaHostApiInfo +*/ +typedef enum PaHostApiTypeId +{ + paInDevelopment=0, /* use while developing support for a new host API */ + paDirectSound=1, + paMME=2, + paASIO=3, + paSoundManager=4, + paCoreAudio=5, + paOSS=7, + paALSA=8, + paAL=9, + paBeOS=10 +} PaHostApiTypeId; + + +/** A structure containing information about a particular host API. */ + +typedef struct PaHostApiInfo { + /** this is struct version 1 */ int structVersion; + /** The well known unique identifier of this host API @see PaHostApiTypeId */ + PaHostApiTypeId type; + /** A textual description of the host API for display on user interfaces. */ const char *name; - int maxInputChannels; - int maxOutputChannels; - /* Number of discrete rates, or -1 if range supported. */ - int numSampleRates; - /* Array of supported sample rates, or {min,max} if range supported. */ - const double *sampleRates; - PaSampleFormat nativeSampleFormats; -} -PaDeviceInfo; -/* - Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() return the - default device ids for input and output respectively, or paNoDevice if - no device is available. - The result can be passed to Pa_OpenStream(). - + /** The number of devices belonging to this host API. This field may be + used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate + all devices for this host API. + @see Pa_HostApiDeviceIndexToDeviceIndex + */ + int deviceCount; + + /** The the default input device for this host API. The value will be a + device index ranging from 0 to (Pa_CountDevices()-1), or paNoDevice + if no default input device is available. + */ + PaDeviceIndex defaultInputDevice; + + /** The the default output device for this host API. The value will be a + device index ranging from 0 to (Pa_CountDevices()-1), or paNoDevice + if no default output device is available. + */ + PaDeviceIndex defaultOutputDevice; + +} PaHostApiInfo; + + +/** Retrieve a pointer to a structure containing information about a specific + host Api. + + @param hostApi A valid host API index ranging from 0 to (Pa_CountHostApis()-1) + + @return A pointer to an immutable PaHostApiInfo structure describing + a specific host API. If the hostApi parameter is out of range or an error + is encountered, the function returns NULL. + + The returned structure is owned by the PortAudio implementation and must not + be manipulated or freed. The pointer is only guaranteed to be valid between + calls to Pa_Initialize() and Pa_Terminate(). +*/ +const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi ); + + +/** Convert a static host API unique identifier, into a runtime + host API index. + + @param type A unique host API identifier belonging to the PaHostApiTypeId + enumeration. + + @return A valid PaHostApiIndex ranging from 0 to (Pa_CountHostApis()-1), or + -1 if the host API specified by the type parameter is not available. + + @see PaHostApiTypeId +*/ +PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ); + + +/** Convert a host-API-specific device index to standard PortAudio device index. + This function may be used in conjunction with the deviceCount field of + PaHostApiInfo to enumerate all devices for the specified host API. + + @param hostApi A valid host API index ranging from 0 to (Pa_CountHostApis()-1) + + @param hostApiDeviceIndex A valid per-host device index in the range + 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1) + + @see PaHostApiInfo +*/ +PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, + int hostApiDeviceIndex ); + + + +/** Structure used to return information about a host error condition. +*/ +typedef struct PaHostErrorInfo{ + PaHostApiTypeId hostApiType; /**< the host API which returned the error code */ + long errorCode; /**< the error code returned */ + const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */ +}PaHostErrorInfo; + + +/** Return information about the last host error encountered. The error + information returned by Pa_GetLastHostErrorInfo() will never be modified + asyncronously by errors occurring in other PortAudio owned threads + (such as the thread that manages the stream callback.) + + This function is provided as a last resort, primarily to enhance debugging + by providing clients with access to all available error information. + + @return A pointer to an immutable structure constaining information about + the host error. The values in this structure will only be valid if a + PortAudio function has previously returned the paUnanticipatedHostError + error code. +*/ +const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ); + + + +/* Device enumeration and capabilities */ + +/** Retrieve the number of available devices. + @return The number of available devices. May return 0 if PortAudio is + not initialized or an error has occured. +*/ +PaDeviceIndex Pa_CountDevices( void ); + + +/** Retrieve the index of the default input device. The result can be + used in the inputDevice parameter to Pa_OpenStream(). + + @return The default input device index for the defualt host API, or paNoDevice + if no default input device is available or an error was encountered. +*/ +PaDeviceIndex Pa_GetDefaultInputDevice( void ); + + +/** Retrieve the index of the default output device. The result can be + used in the outputDevice parameter to Pa_OpenStream(). + + @return The default output device index for the defualt host API, or paNoDevice + if no default output device is available or an error was encountered. + + @note On the PC, the user can specify a default device by setting an environment variable. For example, to use device #1. - - set PA_RECOMMENDED_OUTPUT_DEVICE=1 - +<pre> + set PA_RECOMMENDED_OUTPUT_DEVICE=1 +</pre> The user should first determine the available device ids by using the supplied application "pa_devs". +*/ +PaDeviceIndex Pa_GetDefaultOutputDevice( void ); + +/** The type used to represent monotonic time in seconds that can be used + for syncronisation. The type is used for the outTime argument to the + PaStreamCallback and as the result of Pa_GetStreamTime(). + + @see PaStreamCallback, Pa_GetStreamTime */ +typedef double PaTime; -PaDeviceID Pa_GetDefaultInputDeviceID( void ); -PaDeviceID Pa_GetDefaultOutputDeviceID( void ); +/** A type used to specify one or more sample formats. They indicate + the formats used to pass sound data between the stream callback and the + stream. Each device has one or more "native" formats which may be used when + optimum efficiency or control over conversion is required. + Formats marked "always available" are supported (emulated) by all + PortAudio implementations. -/* - Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure - for the device specified. - If the device parameter is out of range the function returns NULL. + The floating point representation (paFloat32) uses +1.0 and -1.0 as the + maximum and minimum respectively. - PortAudio manages the memory referenced by the returned pointer, the client - must not manipulate or free the memory. The pointer is only guaranteed to be - valid between calls to Pa_Initialize() and Pa_Terminate(). + paUInt8 is an unsigned 8 bit format where 128 is considered "ground" + + The paNonInterleaved flag indicates that a multichannel buffer is passed + as a set of non-interleaved pointers. + @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo + @see paFloat32, paInt16, paInt32, paInt24, paInt8 + @see paUInt8, paCustomFormat, paNonInterleaved */ +typedef unsigned long PaSampleFormat; -const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID device ); -/* - PaTimestamp is used to represent a continuous sample clock with arbitrary - start time that can be used for syncronization. The type is used for the - outTime argument to the PortAudioCallback and as the result of Pa_StreamTime() +#define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */ +#define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */ +#define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */ +#define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */ +#define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */ +#define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */ +#define paCustomFormat ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */ + +#define paNonInterleaved ((PaSampleFormat) 0x80000000) +/** A structure providing information and capabilities of PortAudio devices. + Devices may support input, output or both input and output. */ +typedef struct PaDeviceInfo +{ + int structVersion; /* this is struct version 2 */ + const char *name; + PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/ + + int maxInputChannels; + int maxOutputChannels; -typedef double PaTimestamp; + /* Default latency values for interactive performance. */ + PaTime defaultLowInputLatency; + PaTime defaultLowOutputLatency; + /* Default latency values for robust non-interactive applications (eg. playing sound files). */ + PaTime defaultHighInputLatency; + PaTime defaultHighOutputLatency; -/* - PortAudioCallback is implemented by PortAudio clients. - - inputBuffer and outputBuffer are arrays of interleaved samples, - the format, packing and number of channels used by the buffers are - determined by parameters to Pa_OpenStream() (see below). - - framesPerBuffer is the number of sample frames to be processed by the callback. - - outTime is the time in samples when the buffer(s) processed by - this callback will begin being played at the audio output. - See also Pa_StreamTime() - - userData is the value of a user supplied pointer passed to Pa_OpenStream() - intended for storing synthesis data etc. - - return value: - The callback can return a non-zero value to stop the stream. This may be - useful in applications such as soundfile players where a specific duration - of output is required. However, it is not necessary to utilise this mechanism - as StopStream() will also terminate the stream. A callback returning a - non-zero value must fill the entire outputBuffer. - - NOTE: None of the other stream functions may be called from within the - callback function except for Pa_GetCPULoad(). + double defaultSampleRate; +} PaDeviceInfo; + + +/** Retrieve a pointer to a PaDeviceInfo structure containing information + about the specified device. + @return A pointer to an immutable PaDeviceInfo structure. If the device + parameter is out of range the function returns NULL. + + @param device A valid device index in the range 0 to (Pa_CountDevices()-1) + @note PortAudio manages the memory referenced by the returned pointer, + the client must not manipulate or free the memory. The pointer is only + guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). + + @see PaDeviceInfo, PaDeviceIndex */ +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ); -typedef int (PortAudioCallback)( - void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, - PaTimestamp outTime, void *userData ); +/** Parameters for one direction (input or output) of a stream. +*/ +typedef struct PaStreamParameters +{ + /** A valid device index in the range 0 to (Pa_CountDevices()-1) + specifying the device to be used or the special constant + paUseHostApiSpecificDeviceSpecification which indicates that the actual + device(s) to use are specified in hostApiSpecificStreamInfo. + This field must not be set to paNoDevice. + */ + PaDeviceIndex device; + + /** The number of channels of sound to be delivered to the + stream callback or accessed by Pa_ReadStream() or Pa_WriteStream(). + It can range from 1 to the value of maxInputChannels in the + PaDeviceInfo record for the device specified by the device parameter. + */ + int channelCount; + + /** The sample format of the buffer provided to the stream callback, + a_ReadStream() or Pa_WriteStream(). It may be any of the formats described + by the PaSampleFormat enumeration. + FIXME: wrt below, what are we guaranteeing these days, if anything? + PortAudio guarantees support for + the device's native formats (nativeSampleFormats in the device info record) + and additionally 16 and 32 bit integer and 32 bit floating point formats. + Support for other formats is implementation defined. + */ + PaSampleFormat sampleFormat; + + /** The desired latency in seconds. Where practical, implementations should + configure their latency based on these parameters, otherwise they may + choose the closest viable latency instead. Unless the suggested latency + is greater than the absolute upper limit for the device implementations + shouldround the suggestedLatency up to the next practial value - ie to + provide an equal or higher latency than suggestedLatency whereever possibe. + Actual latency values for an open stream may be retrieved using the + inputLatency and outputLatency fields of the PaStreamInfo structure + returned by Pa_GetStreamInfo(). + @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo + */ + PaTime suggestedLatency; + + /** An optional pointer to a host api specific data structure + containing additional information for device setup and/or stream processing. + hostApiSpecificStreamInfo is never required for correct operation. + If not used it should be set to paNullHostApiSpecificStreamInfo (aka NULL) + FIXME: redocument this based on new changes: + If hostApiSpecificStreamInfo is supplied, it's + size and hostApi fields must be compatible with the input devices host api. + */ + void *hostApiSpecificStreamInfo; + +} PaStreamParameters; + + +/** Return code for Pa_IsFormatSupported indicating success. */ +#define paFormatIsSupported (0) + +/** Determine whether it would be possible to open a stream with the specified + parameters. + + @param inputParameters A structure that describes the input parameters used to + open a stream. The suggestedLatency field is ignored. See PaStreamParameters + for a description of these parameters. inputParameters must be NULL for + output-only streams. + + @param outputParameters A structure that describes the output parameters used + to open a stream. The suggestedLatency field is ignored. See PaStreamParameters + for a description of these parameters. outputParameters must be NULL for + input-only streams. + + @param sampleRate The required sampleRate. For full-duplex streams it is the + sample rate for both input and output -/* - Stream flags - - These flags may be supplied (ored together) in the streamFlags argument to - the Pa_OpenStream() function. + @return Returns 0 if the format is supported, and an error code indicating why + the format is not supported otherwise. The constant paFormatIsSupported is + provided to compare with the return value for success. + @see paFormatIsSupported, PaStreamParameters */ +PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); -#define paNoFlag (0) -#define paClipOff (1<<0) /* disable default clipping of out of range samples */ -#define paDitherOff (1<<1) /* disable default dithering */ -#define paPlatformSpecificFlags (0x00010000) -typedef unsigned long PaStreamFlags; -/* - A single PortAudioStream provides multiple channels of real-time - input and output audio streaming to a client application. - Pointers to PortAudioStream objects are passed between PortAudio functions. + +/* Streaming types and functions */ + + +/** + A single PaStream can provide multiple channels of real-time + streaming audio input and output to a client application. A stream + provides access to audio hardware represented by one or more + PaDevices. Depending on the underlying Host API, it may be possible + to open multiple streams using the same device, however this behavior + is implementation defined. Portable applications should assume that + a PaDevice may be simultaneously used by at most one PaStream. + + Pointers to PaStream objects are passed between PortAudio functions that + operate on streams. + + @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream, + Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive, + Pa_GetStreamTime, Pa_GetStreamCpuLoad + */ +typedef void PaStream; -typedef void PortAudioStream; -#define PaStream PortAudioStream -/* - Pa_OpenStream() opens a stream for either input, output or both. - - stream is the address of a PortAudioStream pointer which will receive +/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream() + or Pa_OpenDefaultStream() to indicate that the stream callback will + accept buffers of any size. +*/ +#define paFramesPerBufferUnspecified (0) + + +/** Flags used to control the behavior of a stream. They are passed as + parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be + ORed together. + + @see Pa_OpenStream, Pa_OpenDefaultStream + @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput, + paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags +*/ +typedef unsigned long PaStreamFlags; + +/** @see PaStreamFlags */ +#define paNoFlag ((PaStreamFlags) 0) + +/** Disable default clipping of out of range samples. + @see PaStreamFlags +*/ +#define paClipOff ((PaStreamFlags) 0x00000001) + +/** Disable default dithering. + @see PaStreamFlags +*/ +#define paDitherOff ((PaStreamFlags) 0x00000002) + +/** A full duplex stream will not discard overflowed input samples without + calling the stream callback, this flag is ignored for blocking read/write + streams. + @see PaStreamFlags +*/ +#define paNeverDropInput ((PaStreamFlags) 0x00000004) + +/** Call the stream callback to fill initial output buffers, rather than the + default behavior of priming the buffers with zeros (silence). This flag has + no effect for input-only and blocking read/write streams. + @see PaStreamFlags +*/ +#define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008) + +/** A mask specifying the platform specific bits. + @see PaStreamFlags +*/ +#define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000) + +/** + Timing information for the buffers passed to the stream callback. +*/ +typedef struct PaStreamCallbackTimeInfo{ + PaTime inputBufferAdcTime; + PaTime currentTime; + PaTime outputBufferDacTime; +} PaStreamCallbackTimeInfo; + + +/** + Flag bit constants for the statusFlags to PaStreamCallback. + + @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow, + paPrimingOutput +*/ +typedef unsigned long PaStreamCallbackFlags; + +/** Input data is all zeros because no real data is available. + @see PaStreamCallbackFlags +*/ +#define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001) + +/** Input data was discarded by PortAudio + @see PaStreamCallbackFlags +*/ +#define paInputOverflow ((PaStreamCallbackFlags) 0x00000002) + +/** Output data was inserted by PortAudio because the stream callback is using + too much CPU + @see PaStreamCallbackFlags +*/ +#define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004) + +/** Output data will be discarded because no room is available. + @see PaStreamCallbackFlags +*/ +#define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008) + +/** Some of all of the output data will be used to prime the stream, input + data may be zero. + @see PaStreamCallbackFlags +*/ +#define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010) + +/** + Allowable return values for the PaStreamCallback. + @see PaStreamCallback +*/ +typedef enum PaStreamCallbackResult +{ + paContinue=0, + paComplete=1, + paAbort=2 +} PaStreamCallbackResult; + + +/** + Functions of type PaStreamCallback are implemented by PortAudio clients. + They consume, process or generate audio in response to requests from an + active PortAudio stream. + + @param input and @param output are arrays of interleaved samples, + the format, packing and number of channels used by the buffers are + determined by parameters to Pa_OpenStream(). + + @param frameCount The number of sample frames to be processed by + the stream callback. + + @param timeInfo The time in seconds when the first sample of the input + buffer was received at the audio input, the time in seconds when the first + sample of the output buffer will begin being played at the audio output, and + the time in seconds when the stream callback was called. + See also Pa_GetStreamTime() + + @param statusFlags Flags indicating whether input and/or output buffers + have been inserted or will be dropped to overcome underflow or overflow + conditions. + + @param userData The value of a user supplied pointer passed to + Pa_OpenStream() intended for storing synthesis data etc. + + @return + The stream callback should return one of the values in the + PaStreamCallbackResult enumeration. To ensure that the callback is continues + to be called, it should return paContinue (0). Either paComplete or paAbort + can be returned to finish stream processing, after either of these values is + returned the callback will not be called again. If paAbort is returned the + stream will finish as soon as possible. If paComplete is returned, the stream + will continue until all buffers generated by the callback have been played. + This may be useful in applications such as soundfile players where a specific + duration of output is required. However, it is not necessary to utilise this + mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also + be used to stop the stream. The callback must always fill the entire output + buffer irrespective of its return value. + + @see Pa_OpenStream, Pa_OpenDefaultStream + + @note With the exception of Pa_GetStreamCpuLoad() it is not permissable to call + PortAudio API functions from within the stream callback. +*/ +typedef int PaStreamCallback( + void *input, void *output, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + + +/** Opens a stream for either input, output or both. + + @param stream The address of a PaStream pointer which will receive a pointer to the newly opened stream. + + @param inputParameters A structure that describes the input parameters used by + the opened stream. See PaStreamParameters for a description of these parameters. + inputParameters must be NULL for output-only streams. + + @param outputParameters A structure that describes the output parameters used by + the opened stream. See PaStreamParameters for a description of these parameters. + outputParameters must be NULL for input-only streams. - inputDevice is the id of the device used for input (see PaDeviceID above.) - inputDevice may be paNoDevice to indicate that an input device is not required. - - numInputChannels is the number of channels of sound to be delivered to the - callback. It can range from 1 to the value of maxInputChannels in the - PaDeviceInfo record for the device specified by the inputDevice parameter. - If inputDevice is paNoDevice numInputChannels is ignored. - - inputSampleFormat is the sample format of inputBuffer provided to the callback - function. inputSampleFormat may be any of the formats described by the - PaSampleFormat enumeration (see above). PortAudio guarantees support for - the device's native formats (nativeSampleFormats in the device info record) - and additionally 16 and 32 bit integer and 32 bit floating point formats. - Support for other formats is implementation defined. - - inputDriverInfo is a pointer to an optional driver specific data structure - containing additional information for device setup or stream processing. - inputDriverInfo is never required for correct operation. If not used - inputDriverInfo should be NULL. - - outputDevice is the id of the device used for output (see PaDeviceID above.) - outputDevice may be paNoDevice to indicate that an output device is not required. - - numOutputChannels is the number of channels of sound to be supplied by the - callback. See the definition of numInputChannels above for more details. - - outputSampleFormat is the sample format of the outputBuffer filled by the - callback function. See the definition of inputSampleFormat above for more - details. - - outputDriverInfo is a pointer to an optional driver specific data structure - containing additional information for device setup or stream processing. - outputDriverInfo is never required for correct operation. If not used - outputDriverInfo should be NULL. - - sampleRate is the desired sampleRate. For full-duplex streams it is the + @param sampleRate The desired sampleRate. For full-duplex streams it is the sample rate for both input and output + + @param framesPerBuffer The number of frames passed to the stream callback + function, or the preferred block granularity for a blocking read/write stream. + The special value paFramesPerBufferUnspecified (0) may be used to request that + the stream callback will recieve an optimal (and possibly varying) number of + frames based on host requirements and the requested latency settings. + Note: With some host APIs, the use of non-zero framesPerBuffer for a callback + stream may introduce an additional layer of buffering which could introduce + additional latency. PortAudio guarantees that the additional latency + will be kept to the theoretical minimum however, it is strongly recommended + that a non-zero framesPerBuffer value only be used when your algorithm + requires a fixed number of frames per stream callback. - framesPerBuffer is the length in sample frames of all internal sample buffers - used for communication with platform specific audio routines. Wherever - possible this corresponds to the framesPerBuffer parameter passed to the - callback function. - - numberOfBuffers is the number of buffers used for multibuffered communication - with the platform specific audio routines. If you pass zero, then an optimum - value will be chosen for you internally. This parameter is provided only - as a guide - and does not imply that an implementation must use multibuffered - i/o when reliable double buffering is available (such as SndPlayDoubleBuffer() - on the Macintosh.) - - streamFlags may contain a combination of flags ORed together. - These flags modify the behaviour of the streaming process. Some flags may only - be relevant to certain buffer formats. - - callback is a pointer to a client supplied function that is responsible - for processing and filling input and output buffers (see above for details.) - - userData is a client supplied pointer which is passed to the callback + @param streamFlags Flags which modify the behaviour of the streaming process. + This parameter may contain a combination of flags ORed together. Some flags may + only be relevant to certain buffer formats. + + @param streamCallback A pointer to a client supplied function that is responsible + for processing and filling input and output buffers. If this parameter is NULL + the stream will be opened in 'blocking read/write' mode. In blocking mode, + the client can receive sample data using Pa_ReadStream and write sample data + using Pa_WriteStream, the number of samples that may be read or written + without blocking is returned by Pa_GetStreamReadAvailable and + Pa_GetStreamWriteAvailable respectively. + + @param userData A client supplied pointer which is passed to the stream callback function. It could for example, contain a pointer to instance data necessary for processing the audio buffers. - - return value: - Upon success Pa_OpenStream() returns PaNoError and places a pointer to a - valid PortAudioStream in the stream argument. The stream is inactive (stopped). - If a call to Pa_OpenStream() fails a non-zero error code is returned (see - PaError above) and the value of stream is invalid. - + + @return + Upon success Pa_OpenStream() returns paNoError and places a pointer to a + valid PaStream in the stream argument. The stream is inactive (stopped). + If a call to Pa_OpenStream() fails, a non-zero error code is returned (see + PaError for possible error codes) and the value of stream is invalid. + + @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream, + Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable */ - -PaError Pa_OpenStream( PortAudioStream** stream, - PaDeviceID inputDevice, - int numInputChannels, - PaSampleFormat inputSampleFormat, - void *inputDriverInfo, - PaDeviceID outputDevice, - int numOutputChannels, - PaSampleFormat outputSampleFormat, - void *outputDriverInfo, +PaError Pa_OpenStream( PaStream** stream, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, - unsigned long numberOfBuffers, PaStreamFlags streamFlags, - PortAudioCallback *callback, + PaStreamCallback *streamCallback, void *userData ); -/* - Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens - the default input and/or output devices. Most parameters have identical meaning - to their Pa_OpenStream() counterparts, with the following exceptions: +/** A simplified version of Pa_OpenStream() that opens the default input + and/or output devices. + + @param stream The address of a PaStream pointer which will receive + a pointer to the newly opened stream. - If either numInputChannels or numOutputChannels is 0 the respective device - is not opened. This has the same effect as passing paNoDevice in the device - arguments to Pa_OpenStream(). + @param numInputChannels The number of channels of sound that will be supplied + to the stream callback or returned by Pa_ReadStream. It can range from 1 to + the value of maxInputChannels in the PaDeviceInfo record for the default input + device. If 0 the stream is opened as an output-only stream. + + @param numOutputChannels The number of channels of sound to be delivered to the + stream callback or passed to Pa_WriteStream. It can range from 1 to the value + of maxOutputChannels in the PaDeviceInfo record for the default output dvice. + If 0 the stream is opened as an output-only stream. + + @param sampleFormat The sample format of both the input and output buffers + provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream. + sampleFormat may be any of the formats described by the PaSampleFormat enumeration + (see above). + FIXME: the following may need to be rewritten - PortAudio guarantees support for + the device's native formats (nativeSampleFormats in the device info record) + and additionally 16 and 32 bit integer and 32 bit float - sampleFormat applies to both the input and output buffers. + @param sampleRate Same as Pa_OpenStream parameter of the same name. + @param framesPerBuffer Same as Pa_OpenStream parameter of the same name. + @param streamCallback Same as Pa_OpenStream parameter of the same name. + @param userData Same as Pa_OpenStream parameter of the same name. -*/ + @return As for Pa_OpenStream -PaError Pa_OpenDefaultStream( PortAudioStream** stream, + @see Pa_OpenStream, PaStreamCallback +*/ +PaError Pa_OpenDefaultStream( PaStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, - unsigned long numberOfBuffers, - PortAudioCallback *callback, + PaStreamCallback *streamCallback, void *userData ); -/* - Pa_CloseStream() closes an audio stream, flushing any pending buffers. +/** Closes an audio stream. If the audio stream is active it + discards any pending buffers as if Pa_AbortStream() had been called. +*/ +PaError Pa_CloseStream( PaStream *stream ); + + +/** Functions of type PaStreamFinishedCallback are implemented by PortAudio + clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback + function. Once registered they are called when the stream becomes inactive + (ie once a call to Pa_StopStream() will not block). + A stream will become inactive after the stream callback returns non-zero, + or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio + output, if the stream callback returns paComplete, or Pa_StopStream is called, + the stream finished callback will not be called until all generated sample data + has been played. + + @param userData The userData parameter supplied to Pa_OpenStream() + + @see Pa_SetStreamFinishedCallback */ +typedef void PaStreamFinishedCallback( void *userData ); -PaError Pa_CloseStream( PortAudioStream* ); -/* - Pa_StartStream() and Pa_StopStream() begin and terminate audio processing. - Pa_StopStream() waits until all pending audio buffers have been played. - Pa_AbortStream() stops playing immediately without waiting for pending +/** Register a stream finished callback function which will be called when the + stream becomes inactive. See the description of PaStreamFinishedCallback for + further details about when the callback will be called. + + @param stream a pointer to a PaStream that is in the stopped state - if the + stream is not stopped, the stream's finished callback will remain unchanged + and an error code will be returned. + + @param streamFinishedCallback a pointer to a function with the same signature + as PaStreamFinishedCallback, that will be called when the stream becomes + inactive. Passing NULL for this parameter will un-register a previously + registered stream finished callback function. + + @return on success returns paNoError, otherwise an error code indicating the cause + of the error. + + @see PaStreamFinishedCallback +*/ +PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); + + +/** Commences audio processing. +*/ +PaError Pa_StartStream( PaStream *stream ); + + +/** Terminates audio processing. It waits until all pending + audio buffers have been played before it returns. +*/ +PaError Pa_StopStream( PaStream *stream ); + + +/** Terminates audio processing immediately without waiting for pending buffers to complete. - */ +PaError Pa_AbortStream( PaStream *stream ); -PaError Pa_StartStream( PortAudioStream *stream ); -PaError Pa_StopStream( PortAudioStream *stream ); +/** @return Returns one (1) when the stream is stopped, zero (0) when + the stream is running, or a negative error number if the stream + is invalid. A stream is considered to be stopped prior to a successful + call to Pa_StartStream and after a successful call to Pa_StopStream + or Pa_AbortStream. If a stream callback returns a value other than + paContinue the stream is NOT considered to be stopped. +*/ +PaError Pa_IsStreamStopped( PaStream *stream ); -PaError Pa_AbortStream( PortAudioStream *stream ); -/* - Pa_StreamActive() returns one (1) when the stream is active (ie playing +/** @return Returns one (1) when the stream is active (ie playing or recording audio), zero (0) when not playing, or a negative error number if the stream is invalid. - The stream is active between calls to Pa_StartStream() and Pa_StopStream(), - but may also become inactive if the callback returns a non-zero value. - In the latter case, the stream is considered inactive after the last - buffer has finished playing. - + + A stream is active after a successful call to Pa_StartStream(), until it + becomes inactive either as a result of a call to Pa_StopStream() or + Pa_AbortStream(), or as a result of a return value other than paContinue from + the stream callback. In the latter case, the stream is considered inactive after + the last buffer has finished playing. + + @see Pa_StopStream, Pa_AbortStream */ +PaError Pa_IsStreamActive( PaStream *stream ); -PaError Pa_StreamActive( PortAudioStream *stream ); -/* - Pa_StreamTime() returns the current output time in samples for the stream. - This time may be used as a time reference (for example synchronizing audio to - MIDI). - + +/** A structure containing unchanging information about an open stream. + @see Pa_GetStreamInfo */ -PaTimestamp Pa_StreamTime( PortAudioStream *stream ); +typedef struct PaStreamInfo +{ + /** this is struct version 1 */ + int structVersion; -/* - Pa_GetCPULoad() returns the CPU Load for the stream. - The "CPU Load" is a fraction of total CPU time consumed by the stream's + /** The input latency of the stream in seconds. This value provides the most + accurate estimate of input latency available to the implementation. It may + differ significantly from the suggestedLatency value passed to Pa_OpenStream(). + The value of this field will be zero (0.) for output-only streams. + @see PaTime + */ + PaTime inputLatency; + + /** The output latency of the stream in seconds. This value provides the most + accurate estimate of output latency available to the implementation. It may + differ significantly from the suggestedLatency value passed to Pa_OpenStream(). + The value of this field will be zero (0.) for input-only streams. + @see PaTime + */ + PaTime outputLatency; + + /** The sample rate of the stream in Hertz (samples per second). In cases + where the hardware sample rate is inaccurate and PortAudio is aware of it, + the value of this field may be different from the sampleRate parameter + passed to Pa_OpenStream(). If information about the actual hardware sample + rate is not available, this field will have the same value as the sampleRate + parameter passed to Pa_OpenStream(). + */ + double sampleRate; + +} PaStreamInfo; + + +/** Retrieve a pointer to a PaStreamInfo structure containing information + about the specified stream. + @return A pointer to an immutable PaStreamInfo structure. If the stream + parameter invalid, or an error is encountered, the function returns NULL. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @note PortAudio manages the memory referenced by the returned pointer, + the client must not manipulate or free the memory. The pointer is only + guaranteed to be valid until the specified stream is closed. + + @see PaStreamInfo +*/ +const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ); + + +/** + @return The current time (in seconds) according to the same clock used to + generate buffer timestamps for stream. + This time may be used for syncronising other events to the audio stream, + for example synchronizing audio to MIDI. + + @see PaTime, PaStreamCallback +*/ +PaTime Pa_GetStreamTime( PaStream *stream ); + + +/** Retrieve CPU usage information for the specified stream. + The "CPU Load" is a fraction of total CPU time consumed by a callback stream's audio processing routines including, but not limited to the client supplied - callback. - A value of 0.5 would imply that PortAudio and the sound generating - callback was consuming roughly 50% of the available CPU time. - This function may be called from the callback function or the application. - + stream callback. This function does not work with blocking read/write streams. + + This function may be called from the stream callback function or the + application. + + @return + A floating point value, typically between 0.0 and 1.0, where 1.0 indicates + that the stream callback is consuming the maximum number of CPU cycles possible + to maintain real-time operation. A value of 0.5 would imply that PortAudio and + the stream callback was consuming roughly 50% of the available CPU time. The + return value may exceed 1.0. A value of 0.0 will always be returned for a + blocking read/write stream. */ +double Pa_GetStreamCpuLoad( PaStream* stream ); -double Pa_GetCPULoad( PortAudioStream* stream ); -/* - Pa_GetMinNumBuffers() returns the minimum number of buffers required by - the current host based on minimum latency. - On the PC, for the DirectSound implementation, latency can be optionally set - by user by setting an environment variable. - For example, to set latency to 200 msec, put: - - set PA_MIN_LATENCY_MSEC=200 - - in the AUTOEXEC.BAT file and reboot. - If the environment variable is not set, then the latency will be determined - based on the OS. Windows NT has higher latency than Win95. - +/** Read samples from an input stream. The function doesn't return until + the entire buffer has been filled - this may involve waiting for the operating + system to supply the data. + + @param buffer A pointer to a buffer of sample frames. The buffer contains + samples in the format specified by the inputParameters->sampleFormat field + used to open the stream, and the number of channels specified by + inputParameters->numChannels. If non-interleaved samples were requested, + buffer is a pointer to the first element of an array of non-interleaved + buffer pointers, one for each channel. + + @param frames The number of frames to be read into buffer. This parameter + is not constrained to a specific range, however high performance applications + will want to match this parameter to the framesPerBuffer parameter used + when opening the stream. + + @return On success PaNoError will be returned, or PaInputOverflowed if input + data was discarded by PortAudio after the previous call and before this call. */ +PaError Pa_ReadStream( PaStream* stream, + void *buffer, + unsigned long frames ); + + +/** Write samples to an output stream. This function doesn't return until the + entire buffer has been consumed - this may involve waiting for the operating + system to consume the data. + + @param buffer A pointer to a buffer of sample frames. The buffer contains + samples in the format specified by the outputParameters->sampleFormat field + used to open the stream, and the number of channels specified by + outputParameters->numChannels. If non-interleaved samples were requested, + buffer is a pointer to the first element of an array of non-interleaved + buffer pointers, one for each channel. + + @param frames The number of frames to be written from buffer. This parameter + is not constrained to a specific range, however high performance applications + will want to match this parameter to the framesPerBuffer parameter used + when opening the stream. + + @return On success PaNoError will be returned, or paOutputUnderflowed if + additional output data was inserted after the previous call and before this + call. +*/ +PaError Pa_WriteStream( PaStream* stream, + void *buffer, + unsigned long frames ); -int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ); -/* - Pa_Sleep() puts the caller to sleep for at least 'msec' milliseconds. - You may sleep longer than the requested time so don't rely on this for - accurate musical timing. - - Pa_Sleep() is provided as a convenience for authors of portable code (such as - the tests and examples in the PortAudio distribution.) - +/** Retrieve the number of frames that can be read from the stream without + waiting. + + @return If non-negative, the return value is the maximum number of frames + that can be read from the stream without blocking or busy waiting. A + negative value is a PaErrorCode. */ +signed long Pa_GetStreamReadAvailable( PaStream* stream ); -void Pa_Sleep( long msec ); -/* - Pa_GetSampleSize() returns the size in bytes of a single sample in the - supplied PaSampleFormat, or paSampleFormatNotSupported if the format is - no supported. - +/** Retrieve the number of frames that can be written to the stream without + waiting. + + @return If non-negative, the return value is the maximum number of frames + that can be written to the stream without blocking or busy waiting. A + negative value is a PaErrorCode. */ +signed long Pa_GetStreamWriteAvailable( PaStream* stream ); + + +/* Miscellaneous utilities */ + +/** + @return The size in bytes of a single sample in the specified format, + or paSampleFormatNotSupported if the format is not supported. +*/ PaError Pa_GetSampleSize( PaSampleFormat format ); +/** Puts the caller to sleep for at least 'msec' milliseconds. + It may sleep longer than requested so don't rely on this for accurate + musical timing. + + This function is provided only as a convenience for authors of portable code + (such as the tests and examples in the PortAudio distribution.) +*/ +void Pa_Sleep( long msec ); + + + #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* PORT_AUDIO_H */ +#endif /* PORTAUDIO_H */ |