|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
sample.h: The conversion from internal data to output samples of differing formats.
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
copyright 2007-9 by the mpg123 project - free software under the terms of the LGPL 2.1
|
|
Packit |
c32a2d |
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
|
Packit |
c32a2d |
initially written by Thomas Orgis, taking WRITE_SAMPLE from decode.c
|
|
Packit |
c32a2d |
Later added the end-conversion specific macros here, too.
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifndef SAMPLE_H
|
|
Packit |
c32a2d |
#define SAMPLE_H
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* mpg123lib_intern.h is included already, right? */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Special case is fixed point math... which does work, but not that nice yet. */
|
|
Packit |
c32a2d |
#ifdef REAL_IS_FIXED
|
|
Packit |
c32a2d |
static inline int16_t idiv_signed_rounded(int32_t x, int shift)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
x >>= (shift - 1);
|
|
Packit |
c32a2d |
x += (x & 1);
|
|
Packit |
c32a2d |
return (int16_t)(x >> 1);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
# define REAL_PLUS_32767 ( 32767 << 15 )
|
|
Packit |
c32a2d |
# define REAL_MINUS_32768 ( -32768 << 15 )
|
|
Packit |
c32a2d |
# define REAL_TO_SHORT(x) (idiv_signed_rounded(x, 15))
|
|
Packit |
c32a2d |
/* No better code (yet). */
|
|
Packit |
c32a2d |
# define REAL_TO_SHORT_ACCURATE(x) REAL_TO_SHORT(x)
|
|
Packit |
c32a2d |
/* This is just here for completeness, it is not used! */
|
|
Packit |
c32a2d |
# define REAL_TO_S32(x) (x)
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* From now on for single precision float... double precision is a possible option once we added some bits. But, it would be rather insane. */
|
|
Packit |
c32a2d |
#ifndef REAL_TO_SHORT
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#if (defined FORCE_ACCURATE) || (defined ACCURATE_ROUNDING)
|
|
Packit |
c32a2d |
/* Define the accurate rounding function. */
|
|
Packit |
c32a2d |
# if (defined REAL_IS_FLOAT) && (defined IEEE_FLOAT)
|
|
Packit |
c32a2d |
/* This function is only available for IEEE754 single-precision values
|
|
Packit |
c32a2d |
This is nearly identical to proper rounding, just -+0.5 is rounded to 0 */
|
|
Packit |
c32a2d |
static inline int16_t ftoi16(float x)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
union
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
float f;
|
|
Packit |
c32a2d |
int32_t i;
|
|
Packit |
c32a2d |
} u_fi;
|
|
Packit |
c32a2d |
u_fi.f = x + 12582912.0f; /* Magic Number: 2^23 + 2^22 */
|
|
Packit |
c32a2d |
return (int16_t)u_fi.i;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
# define REAL_TO_SHORT_ACCURATE(x) ftoi16(x)
|
|
Packit |
c32a2d |
# else
|
|
Packit |
c32a2d |
/* The "proper" rounding, plain C, a bit slow. */
|
|
Packit |
c32a2d |
# define REAL_TO_SHORT_ACCURATE(x) (short)((x)>0.0?(x)+0.5:(x)-0.5)
|
|
Packit |
c32a2d |
# endif
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Now define the normal rounding. */
|
|
Packit |
c32a2d |
# ifdef ACCURATE_ROUNDING
|
|
Packit |
c32a2d |
# define REAL_TO_SHORT(x) REAL_TO_SHORT_ACCURATE(x)
|
|
Packit |
c32a2d |
# else
|
|
Packit |
c32a2d |
/* Non-accurate rounding... simple truncation. Fastest, most LSB errors. */
|
|
Packit |
c32a2d |
# define REAL_TO_SHORT(x) (short)(x)
|
|
Packit |
c32a2d |
# endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#endif /* REAL_TO_SHORT */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* We should add dithering for S32, too? */
|
|
Packit |
c32a2d |
#ifndef REAL_TO_S32
|
|
Packit |
c32a2d |
# ifdef ACCURATE_ROUNDING
|
|
Packit |
c32a2d |
# define REAL_TO_S32(x) (int32_t)((x)>0.0?(x)+0.5:(x)-0.5)
|
|
Packit |
c32a2d |
# else
|
|
Packit |
c32a2d |
# define REAL_TO_S32(x) (int32_t)(x)
|
|
Packit |
c32a2d |
# endif
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifndef REAL_PLUS_32767
|
|
Packit |
c32a2d |
# define REAL_PLUS_32767 32767.0
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifndef REAL_MINUS_32768
|
|
Packit |
c32a2d |
# define REAL_MINUS_32768 -32768.0
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifndef REAL_PLUS_S32
|
|
Packit |
c32a2d |
# define REAL_PLUS_S32 2147483647.0
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifndef REAL_MINUS_S32
|
|
Packit |
c32a2d |
# define REAL_MINUS_S32 -2147483648.0
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* The actual storage of a decoded sample is separated in the following macros.
|
|
Packit |
c32a2d |
We can handle different types, we could also handle dithering here. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef NEWOLD_WRITE_SAMPLE
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* This is the old new mpg123 WRITE_SAMPLE, fixed for newer GCC by MPlayer folks.
|
|
Packit |
c32a2d |
Makes a huge difference on old machines. */
|
|
Packit |
c32a2d |
#if WORDS_BIGENDIAN
|
|
Packit |
c32a2d |
#define MANTISSA_OFFSET 1
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
#define MANTISSA_OFFSET 0
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#define WRITE_SHORT_SAMPLE(samples,sum,clip) { \
|
|
Packit |
c32a2d |
union { double dtemp; int itemp[2]; } u; int v; \
|
|
Packit |
c32a2d |
u.dtemp = ((((65536.0 * 65536.0 * 16)+(65536.0 * 0.5))* 65536.0)) + (sum);\
|
|
Packit |
c32a2d |
v = u.itemp[MANTISSA_OFFSET] - 0x80000000; \
|
|
Packit |
c32a2d |
if( v > 32767) { *(samples) = 0x7fff; (clip)++; } \
|
|
Packit |
c32a2d |
else if( v < -32768) { *(samples) = -0x8000; (clip)++; } \
|
|
Packit |
c32a2d |
else { *(samples) = v; } \
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
/* Macro to produce a short (signed 16bit) output sample from internal representation,
|
|
Packit |
c32a2d |
which may be float, double or indeed some integer for fixed point handling. */
|
|
Packit |
c32a2d |
#define WRITE_SHORT_SAMPLE(samples,sum,clip) \
|
|
Packit |
c32a2d |
if( (sum) > REAL_PLUS_32767) { *(samples) = 0x7fff; (clip)++; } \
|
|
Packit |
c32a2d |
else if( (sum) < REAL_MINUS_32768) { *(samples) = -0x8000; (clip)++; } \
|
|
Packit |
c32a2d |
else { *(samples) = REAL_TO_SHORT(sum); }
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Same as above, but always using accurate rounding. Would we want softer clipping here, too? */
|
|
Packit |
c32a2d |
#define WRITE_SHORT_SAMPLE_ACCURATE(samples,sum,clip) \
|
|
Packit |
c32a2d |
if( (sum) > REAL_PLUS_32767) { *(samples) = 0x7fff; (clip)++; } \
|
|
Packit |
c32a2d |
else if( (sum) < REAL_MINUS_32768) { *(samples) = -0x8000; (clip)++; } \
|
|
Packit |
c32a2d |
else { *(samples) = REAL_TO_SHORT_ACCURATE(sum); }
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
32bit signed
|
|
Packit |
c32a2d |
We do clipping with the same old borders... but different conversion.
|
|
Packit |
c32a2d |
We see here that we need extra work for non-16bit output... we optimized for 16bit.
|
|
Packit |
c32a2d |
-0x7fffffff-1 is the minimum 32 bit signed integer value expressed so that MSVC
|
|
Packit |
c32a2d |
does not give a compile time warning.
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
#define WRITE_S32_SAMPLE(samples,sum,clip) \
|
|
Packit |
c32a2d |
{ \
|
|
Packit |
c32a2d |
real tmpsum = REAL_MUL((sum),S32_RESCALE); \
|
|
Packit |
c32a2d |
if( tmpsum > REAL_PLUS_S32 ){ *(samples) = 0x7fffffff; (clip)++; } \
|
|
Packit |
c32a2d |
else if( tmpsum < REAL_MINUS_S32 ) { *(samples) = -0x7fffffff-1; (clip)++; } \
|
|
Packit |
c32a2d |
else { *(samples) = REAL_TO_S32(tmpsum); } \
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Produce an 8bit sample, via 16bit intermediate. */
|
|
Packit |
c32a2d |
#define WRITE_8BIT_SAMPLE(samples,sum,clip) \
|
|
Packit |
c32a2d |
{ \
|
|
Packit |
c32a2d |
int16_t write_8bit_tmp; \
|
|
Packit |
c32a2d |
if( (sum) > REAL_PLUS_32767) { write_8bit_tmp = 0x7fff; (clip)++; } \
|
|
Packit |
c32a2d |
else if( (sum) < REAL_MINUS_32768) { write_8bit_tmp = -0x8000; (clip)++; } \
|
|
Packit |
c32a2d |
else { write_8bit_tmp = REAL_TO_SHORT(sum); } \
|
|
Packit |
c32a2d |
*(samples) = fr->conv16to8[write_8bit_tmp>>AUSHIFT]; \
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#ifndef REAL_IS_FIXED
|
|
Packit |
c32a2d |
#define WRITE_REAL_SAMPLE(samples,sum,clip) *(samples) = ((real)1./SHORT_SCALE)*(sum)
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#endif
|