📄 pa_converters.c
字号:
/*
* $Id: pa_converters.c,v 1.1.2.26 2004/12/11 16:32:38 aknudsen 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
@brief Conversion functions implementations.
If the C9x function lrintf() is available, define PA_USE_C99_LRINTF to use it
@todo Consider whether functions which dither but don't clip should exist,
V18 automatically enabled clipping whenever dithering was selected. Perhaps
we should do the same.
@todo implement the converters marked IMPLEMENT ME: Float32_To_UInt8_Dither,
Float32_To_UInt8_Clip, Float32_To_UInt8_DitherClip, Int32_To_Int24_Dither,
Int32_To_UInt8_Dither, Int24_To_Int16_Dither, Int24_To_Int8_Dither,
Int24_To_UInt8_Dither, Int16_To_Int8_Dither, Int16_To_UInt8_Dither,
@todo review the converters marked REVIEW: Float32_To_Int32,
Float32_To_Int32_Dither, Float32_To_Int32_Clip, Float32_To_Int32_DitherClip,
Int32_To_Int16_Dither, Int32_To_Int8_Dither, Int16_To_Int32
*/
#include "pa_converters.h"
#include "pa_dither.h"
#include "pa_endianness.h"
#include "pa_types.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 */
#ifdef PA_USE_C99_LRINTF
float scaled = *src * 0x7FFFFFFF;
*dest = lrintf(scaled-0.5f);
#else
double scaled = *src * 0x7FFFFFFF;
*dest = (signed long) scaled;
#endif
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-- )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -