From 2b626a5adf276002d32bce96633c8ffea01d834e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 23 Oct 2015 16:58:17 +0200 Subject: [PATCH] audioconvert: use pack/unpack functions Rework the converter to use the pack/unpack functions Because the unpack functions can only unpack to 1 format, add a separate conversion step for doubles when the unpack function produces int. Do conversion to S32 in the quantize function directly. Tweak the conversion factor for doing float->int conversion slightly to get the full range of negative samples, use clamp to make sure we don't exceed our int range on the positive axis (see also #755301) --- gst/audioconvert/audioconvert.c | 655 ++++---------------------------- gst/audioconvert/audioconvert.h | 13 +- gst/audioconvert/gstaudioconvertorc.orc | 590 +--------------------------- gst/audioconvert/gstaudioquantize.c | 53 +-- gst/audioconvert/gstchannelmix.c | 9 +- 5 files changed, 123 insertions(+), 1197 deletions(-) diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c index f1a30fd..98059b4 100644 --- a/gst/audioconvert/audioconvert.c +++ b/gst/audioconvert/audioconvert.c @@ -31,557 +31,36 @@ #include "audioconvert.h" #include "gstaudioconvertorc.h" -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define audio_convert_orc_unpack_u16_le audio_convert_orc_unpack_u16 -#define audio_convert_orc_unpack_u16_be audio_convert_orc_unpack_u16_swap -#define audio_convert_orc_unpack_s16_le audio_convert_orc_unpack_s16 -#define audio_convert_orc_unpack_s16_be audio_convert_orc_unpack_s16_swap -#define audio_convert_orc_unpack_u32_le audio_convert_orc_unpack_u32 -#define audio_convert_orc_unpack_u32_be audio_convert_orc_unpack_u32_swap -#define audio_convert_orc_unpack_s32_le audio_convert_orc_unpack_s32 -#define audio_convert_orc_unpack_s32_be audio_convert_orc_unpack_s32_swap -#define audio_convert_orc_unpack_float_le audio_convert_orc_unpack_float_s32 -#define audio_convert_orc_unpack_float_be audio_convert_orc_unpack_float_s32_swap -#define audio_convert_orc_unpack_double_le audio_convert_orc_unpack_double_s32 -#define audio_convert_orc_unpack_double_be audio_convert_orc_unpack_double_s32_swap -#define audio_convert_orc_unpack_float_hq_le audio_convert_orc_unpack_float_double -#define audio_convert_orc_unpack_float_hq_be audio_convert_orc_unpack_float_double_swap -#define audio_convert_orc_unpack_double_hq_le audio_convert_orc_unpack_double_double -#define audio_convert_orc_unpack_double_hq_be audio_convert_orc_unpack_double_double_swap -#define audio_convert_orc_unpack_u8_float audio_convert_orc_unpack_u8_double -#define audio_convert_orc_unpack_u16_le_float audio_convert_orc_unpack_u16_double -#define audio_convert_orc_unpack_u16_be_float audio_convert_orc_unpack_u16_double_swap -#define audio_convert_orc_unpack_u32_le_float audio_convert_orc_unpack_u32_double -#define audio_convert_orc_unpack_u32_be_float audio_convert_orc_unpack_u32_double_swap -#define audio_convert_orc_unpack_s8_float audio_convert_orc_unpack_s8_double -#define audio_convert_orc_unpack_s16_le_float audio_convert_orc_unpack_s16_double -#define audio_convert_orc_unpack_s16_be_float audio_convert_orc_unpack_s16_double_swap -#define audio_convert_orc_unpack_s32_le_float audio_convert_orc_unpack_s32_double -#define audio_convert_orc_unpack_s32_be_float audio_convert_orc_unpack_s32_double_swap -#define audio_convert_orc_pack_u8 audio_convert_orc_pack_u8 -#define audio_convert_orc_pack_u16_le audio_convert_orc_pack_u16 -#define audio_convert_orc_pack_u16_be audio_convert_orc_pack_u16_swap -#define audio_convert_orc_pack_s16_le audio_convert_orc_pack_s16 -#define audio_convert_orc_pack_s16_be audio_convert_orc_pack_s16_swap -#define audio_convert_orc_pack_u32_le audio_convert_orc_pack_u32 -#define audio_convert_orc_pack_u32_be audio_convert_orc_pack_u32_swap -#define audio_convert_orc_pack_s32_le audio_convert_orc_pack_s32 -#define audio_convert_orc_pack_s32_be audio_convert_orc_pack_s32_swap -#define audio_convert_orc_pack_float_le audio_convert_orc_pack_s32_float -#define audio_convert_orc_pack_float_be audio_convert_orc_pack_s32_float_swap -#define audio_convert_orc_pack_double_le audio_convert_orc_pack_s32_double -#define audio_convert_orc_pack_double_be audio_convert_orc_pack_s32_double_swap -#define audio_convert_orc_pack_float_hq_le audio_convert_orc_pack_double_float -#define audio_convert_orc_pack_float_hq_be audio_convert_orc_pack_double_float_swap -#define audio_convert_orc_pack_s8_float audio_convert_orc_pack_double_s8 -#define audio_convert_orc_pack_s16_le_float audio_convert_orc_pack_double_s16 -#define audio_convert_orc_pack_s16_be_float audio_convert_orc_pack_double_s16_swap -#define audio_convert_orc_pack_s32_le_float audio_convert_orc_pack_double_s32 -#define audio_convert_orc_pack_s32_be_float audio_convert_orc_pack_double_s32_swap -#define audio_convert_orc_pack_u8_float audio_convert_orc_pack_double_u8 -#define audio_convert_orc_pack_u16_le_float audio_convert_orc_pack_double_u16 -#define audio_convert_orc_pack_u16_be_float audio_convert_orc_pack_double_u16_swap -#define audio_convert_orc_pack_u32_le_float audio_convert_orc_pack_double_u32 -#define audio_convert_orc_pack_u32_be_float audio_convert_orc_pack_double_u32_swap -#else -#define audio_convert_orc_unpack_u16_be audio_convert_orc_unpack_u16 -#define audio_convert_orc_unpack_u16_le audio_convert_orc_unpack_u16_swap -#define audio_convert_orc_unpack_s16_be audio_convert_orc_unpack_s16 -#define audio_convert_orc_unpack_s16_le audio_convert_orc_unpack_s16_swap -#define audio_convert_orc_unpack_u32_be audio_convert_orc_unpack_u32 -#define audio_convert_orc_unpack_u32_le audio_convert_orc_unpack_u32_swap -#define audio_convert_orc_unpack_s32_be audio_convert_orc_unpack_s32 -#define audio_convert_orc_unpack_s32_le audio_convert_orc_unpack_s32_swap -#define audio_convert_orc_unpack_float_be audio_convert_orc_unpack_float_s32 -#define audio_convert_orc_unpack_float_le audio_convert_orc_unpack_float_s32_swap -#define audio_convert_orc_unpack_double_be audio_convert_orc_unpack_double_s32 -#define audio_convert_orc_unpack_double_le audio_convert_orc_unpack_double_s32_swap -#define audio_convert_orc_unpack_float_hq_be audio_convert_orc_unpack_float_double -#define audio_convert_orc_unpack_float_hq_le audio_convert_orc_unpack_float_double_swap -#define audio_convert_orc_unpack_double_hq_be audio_convert_orc_unpack_double_double -#define audio_convert_orc_unpack_double_hq_le audio_convert_orc_unpack_double_double_swap -#define audio_convert_orc_unpack_u8_float audio_convert_orc_unpack_u8_double -#define audio_convert_orc_unpack_u16_be_float audio_convert_orc_unpack_u16_double -#define audio_convert_orc_unpack_u16_le_float audio_convert_orc_unpack_u16_double_swap -#define audio_convert_orc_unpack_u32_be_float audio_convert_orc_unpack_u32_double -#define audio_convert_orc_unpack_u32_le_float audio_convert_orc_unpack_u32_double_swap -#define audio_convert_orc_unpack_s8_float audio_convert_orc_unpack_s8_double -#define audio_convert_orc_unpack_s16_be_float audio_convert_orc_unpack_s16_double -#define audio_convert_orc_unpack_s16_le_float audio_convert_orc_unpack_s16_double_swap -#define audio_convert_orc_unpack_s32_be_float audio_convert_orc_unpack_s32_double -#define audio_convert_orc_unpack_s32_le_float audio_convert_orc_unpack_s32_double_swap -#define audio_convert_orc_pack_u8 audio_convert_orc_pack_u8 -#define audio_convert_orc_pack_u16_be audio_convert_orc_pack_u16 -#define audio_convert_orc_pack_u16_le audio_convert_orc_pack_u16_swap -#define audio_convert_orc_pack_s16_be audio_convert_orc_pack_s16 -#define audio_convert_orc_pack_s16_le audio_convert_orc_pack_s16_swap -#define audio_convert_orc_pack_u32_be audio_convert_orc_pack_u32 -#define audio_convert_orc_pack_u32_le audio_convert_orc_pack_u32_swap -#define audio_convert_orc_pack_s32_be audio_convert_orc_pack_s32 -#define audio_convert_orc_pack_s32_le audio_convert_orc_pack_s32_swap -#define audio_convert_orc_pack_float_be audio_convert_orc_pack_s32_float -#define audio_convert_orc_pack_float_le audio_convert_orc_pack_s32_float_swap -#define audio_convert_orc_pack_double_be audio_convert_orc_pack_s32_double -#define audio_convert_orc_pack_double_le audio_convert_orc_pack_s32_double_swap -#define audio_convert_orc_pack_float_hq_be audio_convert_orc_pack_double_float -#define audio_convert_orc_pack_float_hq_le audio_convert_orc_pack_double_float_swap -#define audio_convert_orc_pack_s8_float audio_convert_orc_pack_double_s8 -#define audio_convert_orc_pack_s16_be_float audio_convert_orc_pack_double_s16 -#define audio_convert_orc_pack_s16_le_float audio_convert_orc_pack_double_s16_swap -#define audio_convert_orc_pack_s32_be_float audio_convert_orc_pack_double_s32 -#define audio_convert_orc_pack_s32_le_float audio_convert_orc_pack_double_s32_swap -#define audio_convert_orc_pack_u8_float audio_convert_orc_pack_double_u8 -#define audio_convert_orc_pack_u16_be_float audio_convert_orc_pack_double_u16 -#define audio_convert_orc_pack_u16_le_float audio_convert_orc_pack_double_u16_swap -#define audio_convert_orc_pack_u32_be_float audio_convert_orc_pack_double_u32 -#define audio_convert_orc_pack_u32_le_float audio_convert_orc_pack_double_u32_swap -#endif - -/* sign bit in the intermediate format */ -#define SIGNED (1U<<31) - -/*** - * unpack code - */ -#define MAKE_UNPACK_FUNC_NAME(name) \ -audio_convert_unpack_##name -#define MAKE_ORC_UNPACK_FUNC_NAME(name) \ -audio_convert_orc_unpack_##name - -/* unpack from integer to signed integer 32 */ -#define MAKE_UNPACK_FUNC_II(name, stride, sign, READ_FUNC) \ -static void \ -MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gint32 *dst, \ - gint scale, gint count) \ -{ \ - for (;count; count--) { \ - *dst++ = (((gint32) READ_FUNC (src)) << scale) ^ (sign); \ - src+=stride; \ - } \ -} - -/* unpack from integer to signed integer 32 with orc */ -#define MAKE_UNPACK_FUNC_ORC_II(name, stride, sign, READ_FUNC) \ -static void \ -MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gint32 *dst, \ - gint scale, gint count) \ -{ \ - MAKE_ORC_UNPACK_FUNC_NAME (name) (dst, src, scale, count); \ -} - -/* unpack from float to signed integer 32 */ -#define MAKE_UNPACK_FUNC_FI(name, type, READ_FUNC) \ -static void \ -MAKE_UNPACK_FUNC_NAME (name) (type * src, gint32 * dst, gint s, gint count) \ -{ \ - gdouble temp; \ - \ - for (; count; count--) { \ - /* blow up to 32 bit */ \ - temp = floor ((READ_FUNC (*src++) * 2147483647.0) + 0.5); \ - *dst++ = (gint32) CLAMP (temp, G_MININT32, G_MAXINT32); \ - } \ -} - -/* unpack from float to signed integer 32 with orc */ -#define MAKE_UNPACK_FUNC_ORC_FI(name, type, READ_FUNC) \ -static void \ -MAKE_UNPACK_FUNC_NAME (name) (type * src, gint32 * dst, gint s, gint count) \ -{ \ - MAKE_ORC_UNPACK_FUNC_NAME (name) ((guint32 *) dst, src, count); \ -} - -/* unpack from float to float 64 (double) */ -#define MAKE_UNPACK_FUNC_FF(name, type, FUNC) \ -static void \ -MAKE_UNPACK_FUNC_NAME (name) (type * src, gdouble * dst, gint s, \ - gint count) \ -{ \ - for (; count; count--) \ - *dst++ = (gdouble) FUNC (*src++); \ -} - -/* unpack from float to float 64 (double) with orc */ -#define MAKE_UNPACK_FUNC_ORC_FF(name, type, FUNC) \ -static void \ -MAKE_UNPACK_FUNC_NAME (name) (type * src, gdouble * dst, gint s, \ - gint count) \ -{ \ - MAKE_ORC_UNPACK_FUNC_NAME (name) ((gdouble *) dst, src, count); \ -} - -/* unpack from int to float 64 (double) */ -#define MAKE_UNPACK_FUNC_IF(name, stride, sign, READ_FUNC) \ -static void \ -MAKE_UNPACK_FUNC_NAME (name) (guint8 * src, gdouble * dst, gint scale, \ - gint count) \ -{ \ - gdouble tmp; \ - for (; count; count--) { \ - tmp = (gdouble) ((((gint32) READ_FUNC (src)) << scale) ^ (sign)); \ - *dst++ = tmp * (1.0 / 2147483647.0); \ - src += stride; \ - } \ -} - -#define MAKE_UNPACK_FUNC_ORC_IF(name, stride, sign, READ_FUNC) \ -static void \ -MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gdouble *dst, \ - gint scale, gint count) \ -{ \ - MAKE_ORC_UNPACK_FUNC_NAME (name) (dst, src, scale, count); \ -} - -#define READ8(p) GST_READ_UINT8(p) -#define READ16_FROM_LE(p) GST_READ_UINT16_LE (p) -#define READ16_FROM_BE(p) GST_READ_UINT16_BE (p) -#define READ24_FROM_LE(p) (p[0] | (p[1] << 8) | (p[2] << 16)) -#define READ24_FROM_BE(p) (p[2] | (p[1] << 8) | (p[0] << 16)) -#define READ32_FROM_LE(p) GST_READ_UINT32_LE (p) -#define READ32_FROM_BE(p) GST_READ_UINT32_BE (p) - - - -MAKE_UNPACK_FUNC_ORC_II (u8, 1, SIGNED, READ8); -MAKE_UNPACK_FUNC_ORC_II (s8, 1, 0, READ8); -MAKE_UNPACK_FUNC_ORC_II (u16_le, 2, SIGNED, READ16_FROM_LE); -MAKE_UNPACK_FUNC_ORC_II (s16_le, 2, 0, READ16_FROM_LE); -MAKE_UNPACK_FUNC_ORC_II (u16_be, 2, SIGNED, READ16_FROM_BE); -MAKE_UNPACK_FUNC_ORC_II (s16_be, 2, 0, READ16_FROM_BE); -MAKE_UNPACK_FUNC_II (u24_le, 3, SIGNED, READ24_FROM_LE); -MAKE_UNPACK_FUNC_II (s24_le, 3, 0, READ24_FROM_LE); -MAKE_UNPACK_FUNC_II (u24_be, 3, SIGNED, READ24_FROM_BE); -MAKE_UNPACK_FUNC_II (s24_be, 3, 0, READ24_FROM_BE); -MAKE_UNPACK_FUNC_ORC_II (u32_le, 4, SIGNED, READ32_FROM_LE); -MAKE_UNPACK_FUNC_ORC_II (s32_le, 4, 0, READ32_FROM_LE); -MAKE_UNPACK_FUNC_ORC_II (u32_be, 4, SIGNED, READ32_FROM_BE); -MAKE_UNPACK_FUNC_ORC_II (s32_be, 4, 0, READ32_FROM_BE); -MAKE_UNPACK_FUNC_ORC_FI (float_le, gfloat, GFLOAT_FROM_LE); -MAKE_UNPACK_FUNC_ORC_FI (float_be, gfloat, GFLOAT_FROM_BE); -MAKE_UNPACK_FUNC_ORC_FI (double_le, gdouble, GDOUBLE_FROM_LE); -MAKE_UNPACK_FUNC_ORC_FI (double_be, gdouble, GDOUBLE_FROM_BE); -MAKE_UNPACK_FUNC_ORC_FF (float_hq_le, gfloat, GFLOAT_FROM_LE); -MAKE_UNPACK_FUNC_ORC_FF (float_hq_be, gfloat, GFLOAT_FROM_BE); -MAKE_UNPACK_FUNC_ORC_FF (double_hq_le, gdouble, GDOUBLE_FROM_LE); -MAKE_UNPACK_FUNC_ORC_FF (double_hq_be, gdouble, GDOUBLE_FROM_BE); -MAKE_UNPACK_FUNC_ORC_IF (u8_float, 1, SIGNED, READ8); -MAKE_UNPACK_FUNC_ORC_IF (s8_float, 1, 0, READ8); -MAKE_UNPACK_FUNC_ORC_IF (u16_le_float, 2, SIGNED, READ16_FROM_LE); -MAKE_UNPACK_FUNC_ORC_IF (s16_le_float, 2, 0, READ16_FROM_LE); -MAKE_UNPACK_FUNC_ORC_IF (u16_be_float, 2, SIGNED, READ16_FROM_BE); -MAKE_UNPACK_FUNC_ORC_IF (s16_be_float, 2, 0, READ16_FROM_BE); -MAKE_UNPACK_FUNC_IF (u24_le_float, 3, SIGNED, READ24_FROM_LE); -MAKE_UNPACK_FUNC_IF (s24_le_float, 3, 0, READ24_FROM_LE); -MAKE_UNPACK_FUNC_IF (u24_be_float, 3, SIGNED, READ24_FROM_BE); -MAKE_UNPACK_FUNC_IF (s24_be_float, 3, 0, READ24_FROM_BE); -MAKE_UNPACK_FUNC_ORC_IF (u32_le_float, 4, SIGNED, READ32_FROM_LE); -MAKE_UNPACK_FUNC_ORC_IF (s32_le_float, 4, 0, READ32_FROM_LE); -MAKE_UNPACK_FUNC_ORC_IF (u32_be_float, 4, SIGNED, READ32_FROM_BE); -MAKE_UNPACK_FUNC_ORC_IF (s32_be_float, 4, 0, READ32_FROM_BE); - -/* One of the double_hq_* functions generated above is inefficient, but it's - * never used anyway. The same is true for one of the s32_* functions. */ - -/*** - * packing code - */ -#define MAKE_PACK_FUNC_NAME(name) \ -audio_convert_pack_##name -#define MAKE_PACK_FUNC_NAME_ORC(name) \ -audio_convert_orc_pack_##name - -/* - * These functions convert the signed 32 bit integers to the - * target format. For this to work the following steps are done: +/** + * int -> int + * - unpack S32 + * - convert F64 + * - (channel mix S32) (channel mix F64) + * - (quantize+dither S32) quantize+dither+ns F64->S32 + * - pack from S32 * - * 1) If the output format is unsigned we will XOR the sign bit. This - * will do the same as if we add 1<<31. - * 2) Afterwards we shift to the target depth. It's necessary to left-shift - * on signed values here to get arithmetical shifting. - * 3) This is then written into our target array by the corresponding write - * function for the target width. - */ - -/* pack from signed integer 32 to integer using Orc */ -#define MAKE_PACK_FUNC_ORC_II(name, stride, sign, WRITE_FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gint32 *src, guint8 * dst, \ - gint scale, gint count) \ -{ \ - MAKE_PACK_FUNC_NAME_ORC (name) (dst, src, scale, count); \ -} - -/* pack from signed integer 32 to integer */ -#define MAKE_PACK_FUNC_II(name, stride, sign, WRITE_FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gint32 *src, guint8 * dst, \ - gint scale, gint count) \ -{ \ - gint32 tmp; \ - for (;count; count--) { \ - tmp = (*src++ ^ (sign)) >> scale; \ - WRITE_FUNC (dst, tmp); \ - dst += stride; \ - } \ -} - -/* pack from signed integer 32 to float using orc */ -#define MAKE_PACK_FUNC_ORC_IF(name, type, FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gint32 * src, type * dst, gint scale, \ - gint count) \ -{ \ - MAKE_PACK_FUNC_NAME_ORC (name) (dst, src, count); \ -} - -/* pack from signed integer 32 to float */ -#define MAKE_PACK_FUNC_IF(name, type, FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gint32 * src, type * dst, gint scale, \ - gint count) \ -{ \ - for (; count; count--) \ - *dst++ = FUNC ((type) ((*src++) * (1.0 / 2147483647.0))); \ -} - -/* pack from float 64 (double) to float */ -#define MAKE_PACK_FUNC_FF(name, type, FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gdouble * src, type * dst, gint s, \ - gint count) \ -{ \ - for (; count; count--) \ - *dst++ = FUNC ((type) (*src++)); \ -} - -/* pack from float 64 (double) to float with orc */ -#define MAKE_PACK_FUNC_ORC_FF(name, type, FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gdouble * src, type * dst, gint s, \ - gint count) \ -{ \ - MAKE_PACK_FUNC_NAME_ORC (name) (dst, src, count); \ -} - -/* pack from float 64 (double) to signed int. - * the floats are already in the correct range. Only a cast is needed. - */ -#define MAKE_PACK_FUNC_FI_S(name, stride, WRITE_FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gdouble * src, guint8 * dst, gint scale, \ - gint count) \ -{ \ - gint32 tmp; \ - for (; count; count--) { \ - tmp = (gint32) (*src); \ - WRITE_FUNC (dst, tmp); \ - src++; \ - dst += stride; \ - } \ -} - -/* pack from float 64 (double) to unsigned int. - * the floats are already in the correct range. Only a cast is needed - * and an addition of 2^(target_depth-1) to get in the correct unsigned - * range. */ -#define MAKE_PACK_FUNC_FI_U(name, stride, WRITE_FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gdouble * src, guint8 * dst, gint scale, \ - gint count) \ -{ \ - guint32 tmp; \ - gdouble limit = (1U<<(32-scale-1)); \ - for (; count; count--) { \ - tmp = (guint32) (*src + limit); \ - WRITE_FUNC (dst, tmp); \ - src++; \ - dst += stride; \ - } \ -} - -/* pack from float 64 (double) to signed int with orc. - * the floats are already in the correct range. Only a cast is needed. - */ -#define MAKE_PACK_FUNC_ORC_FI_S(name, stride, WRITE_FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gdouble * src, guint8 * dst, gint scale, \ - gint count) \ -{ \ - MAKE_PACK_FUNC_NAME_ORC (name) (dst, src, scale, count); \ -} - -/* pack from float 64 (double) to unsigned int with orc. - * the floats are already in the correct range. Only a cast is needed. + * int -> float + * - unpack S32 + * - convert F64 + * - (channel mix F64) + * - pack from F64 + * + * float -> int + * - unpack F64 + * - (channel mix F64) + * - quantize+dither+ns F64->S32 + * - pack from S32 + * + * float -> float + * - unpack F64 + * - (channel mix F64) + * - pack from F64 */ -#define MAKE_PACK_FUNC_ORC_FI_U(name, stride, WRITE_FUNC) \ -static void \ -MAKE_PACK_FUNC_NAME (name) (gdouble * src, guint8 * dst, gint scale, \ - gint count) \ -{ \ - MAKE_PACK_FUNC_NAME_ORC (name) (dst, src, scale, count); \ -} - -#define WRITE8(p, v) GST_WRITE_UINT8 (p, v) -#define WRITE16_TO_LE(p,v) GST_WRITE_UINT16_LE (p, (guint16)(v)) -#define WRITE16_TO_BE(p,v) GST_WRITE_UINT16_BE (p, (guint16)(v)) -#define WRITE24_TO_LE(p,v) p[0] = v & 0xff; p[1] = (v >> 8) & 0xff; p[2] = (v >> 16) & 0xff -#define WRITE24_TO_BE(p,v) p[2] = v & 0xff; p[1] = (v >> 8) & 0xff; p[0] = (v >> 16) & 0xff -#define WRITE32_TO_LE(p,v) GST_WRITE_UINT32_LE (p, (guint32)(v)) -#define WRITE32_TO_BE(p,v) GST_WRITE_UINT32_BE (p, (guint32)(v)) - -MAKE_PACK_FUNC_ORC_II (u8, 1, SIGNED, WRITE8); -MAKE_PACK_FUNC_ORC_II (s8, 1, 0, WRITE8); -MAKE_PACK_FUNC_ORC_II (u16_le, 2, SIGNED, WRITE16_TO_LE); -MAKE_PACK_FUNC_ORC_II (s16_le, 2, 0, WRITE16_TO_LE); -MAKE_PACK_FUNC_ORC_II (u16_be, 2, SIGNED, WRITE16_TO_BE); -MAKE_PACK_FUNC_ORC_II (s16_be, 2, 0, WRITE16_TO_BE); -MAKE_PACK_FUNC_II (u24_le, 3, SIGNED, WRITE24_TO_LE); -MAKE_PACK_FUNC_II (s24_le, 3, 0, WRITE24_TO_LE); -MAKE_PACK_FUNC_II (u24_be, 3, SIGNED, WRITE24_TO_BE); -MAKE_PACK_FUNC_II (s24_be, 3, 0, WRITE24_TO_BE); -MAKE_PACK_FUNC_ORC_II (u32_le, 4, SIGNED, WRITE32_TO_LE); -MAKE_PACK_FUNC_ORC_II (s32_le, 4, 0, WRITE32_TO_LE); -MAKE_PACK_FUNC_ORC_II (u32_be, 4, SIGNED, WRITE32_TO_BE); -MAKE_PACK_FUNC_ORC_II (s32_be, 4, 0, WRITE32_TO_BE); -MAKE_PACK_FUNC_ORC_IF (float_le, gfloat, GFLOAT_TO_LE); -MAKE_PACK_FUNC_ORC_IF (float_be, gfloat, GFLOAT_TO_BE); -MAKE_PACK_FUNC_ORC_IF (double_le, gdouble, GDOUBLE_TO_LE); -MAKE_PACK_FUNC_ORC_IF (double_be, gdouble, GDOUBLE_TO_BE); -MAKE_PACK_FUNC_ORC_FF (float_hq_le, gfloat, GFLOAT_TO_LE); -MAKE_PACK_FUNC_ORC_FF (float_hq_be, gfloat, GFLOAT_TO_BE); -MAKE_PACK_FUNC_ORC_FI_U (u8_float, 1, WRITE8); -MAKE_PACK_FUNC_ORC_FI_S (s8_float, 1, WRITE8); -MAKE_PACK_FUNC_ORC_FI_U (u16_le_float, 2, WRITE16_TO_LE); -MAKE_PACK_FUNC_ORC_FI_S (s16_le_float, 2, WRITE16_TO_LE); -MAKE_PACK_FUNC_ORC_FI_U (u16_be_float, 2, WRITE16_TO_BE); -MAKE_PACK_FUNC_ORC_FI_S (s16_be_float, 2, WRITE16_TO_BE); -MAKE_PACK_FUNC_FI_U (u24_le_float, 3, WRITE24_TO_LE); -MAKE_PACK_FUNC_FI_S (s24_le_float, 3, WRITE24_TO_LE); -MAKE_PACK_FUNC_FI_U (u24_be_float, 3, WRITE24_TO_BE); -MAKE_PACK_FUNC_FI_S (s24_be_float, 3, WRITE24_TO_BE); -MAKE_PACK_FUNC_ORC_FI_U (u32_le_float, 4, WRITE32_TO_LE); -MAKE_PACK_FUNC_ORC_FI_S (s32_le_float, 4, WRITE32_TO_LE); -MAKE_PACK_FUNC_ORC_FI_U (u32_be_float, 4, WRITE32_TO_BE); -MAKE_PACK_FUNC_ORC_FI_S (s32_be_float, 4, WRITE32_TO_BE); - -/* For double_hq, packing and unpacking is the same, so we reuse the unpacking - * functions here. */ -#define audio_convert_pack_double_hq_le MAKE_UNPACK_FUNC_NAME (double_hq_le) -#define audio_convert_pack_double_hq_be MAKE_UNPACK_FUNC_NAME (double_hq_be) - -static const AudioConvertUnpack unpack_funcs[] = { - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u8), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s8), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u8), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s8), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u16_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s16_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u16_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s16_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u24_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s24_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u24_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s24_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u32_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u32_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_hq_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_hq_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_hq_le), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_hq_be), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u8_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s8_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u8_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s8_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u16_le_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s16_le_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u16_be_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s16_be_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u24_le_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s24_le_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u24_be_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s24_be_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u32_le_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_le_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u32_be_float), - (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_be_float), -}; - -static const AudioConvertPack pack_funcs[] = { - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u8), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s8), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u8), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s8), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u16_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s16_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u16_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s16_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u24_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s24_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u24_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s24_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u32_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u32_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (float_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (float_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (double_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (double_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (float_hq_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (float_hq_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (double_hq_le), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (double_hq_be), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u8_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s8_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u8_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s8_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u16_le_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s16_le_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u16_be_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s16_be_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u24_le_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s24_le_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u24_be_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s24_be_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u32_le_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_le_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (u32_be_float), - (AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_be_float), -}; - -#define DOUBLE_INTERMEDIATE_FORMAT(ctx) \ - ((!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->in.finfo) && \ - !GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo)) || \ +#define DOUBLE_INTERMEDIATE_FORMAT(ctx) \ + (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->in.finfo) || \ + !GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo) || \ (ctx->ns != NOISE_SHAPING_NONE)) -static gint -audio_convert_get_func_index (AudioConvertCtx * ctx, - const GstAudioFormatInfo * fmt) -{ - gint index = 0; - - if (GST_AUDIO_FORMAT_INFO_IS_INTEGER (fmt)) { - index += (GST_AUDIO_FORMAT_INFO_WIDTH (fmt) / 8 - 1) * 4; - index += GST_AUDIO_FORMAT_INFO_IS_LITTLE_ENDIAN (fmt) ? 0 : 2; - index += GST_AUDIO_FORMAT_INFO_IS_SIGNED (fmt) ? 1 : 0; - index += (ctx->ns == NOISE_SHAPING_NONE) ? 0 : 24; - } else { - /* this is float/double */ - index = 16; - index += (GST_AUDIO_FORMAT_INFO_WIDTH (fmt) == 32) ? 0 : 2; - index += GST_AUDIO_FORMAT_INFO_IS_LITTLE_ENDIAN (fmt) ? 0 : 1; - index += (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? 4 : 0; - } - - return index; -} - static inline gboolean check_default (AudioConvertCtx * ctx, const GstAudioFormatInfo * fmt) { @@ -597,7 +76,6 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, GstAudioInfo * out, GstAudioConvertDithering dither, GstAudioConvertNoiseShaping ns) { - gint idx_in, idx_out; gint in_depth, out_depth; g_return_val_if_fail (ctx != NULL, FALSE); @@ -641,41 +119,52 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in, gst_channel_mix_setup_matrix (ctx); - idx_in = audio_convert_get_func_index (ctx, in->finfo); - ctx->unpack = unpack_funcs[idx_in]; - - idx_out = audio_convert_get_func_index (ctx, out->finfo); - ctx->pack = pack_funcs[idx_out]; - - GST_INFO ("func index in %d, out %d", idx_in, idx_out); - - /* if both formats are float/double or we use noise shaping use double as + /* if one formats is float/double or we use noise shaping use double as * intermediate format and switch mixing */ - if (!DOUBLE_INTERMEDIATE_FORMAT (ctx)) { - GST_INFO ("use int mixing"); - ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_int; - } else { + if (DOUBLE_INTERMEDIATE_FORMAT (ctx)) { GST_INFO ("use float mixing"); ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_float; + + if (ctx->in.finfo->unpack_format != GST_AUDIO_FORMAT_F64) { + ctx->convert = audio_convert_orc_s32_to_double; + GST_INFO ("convert input to F64"); + } + /* check if input needs to be unpacked to intermediate format */ + ctx->in_default = + GST_AUDIO_FORMAT_INFO_FORMAT (in->finfo) == GST_AUDIO_FORMAT_F64; + + if (GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo)) { + /* quantization will convert to s32, check if this is our final output format */ + ctx->out_default = + GST_AUDIO_FORMAT_INFO_FORMAT (out->finfo) == GST_AUDIO_FORMAT_S32; + } else { + ctx->out_default = + GST_AUDIO_FORMAT_INFO_FORMAT (out->finfo) == GST_AUDIO_FORMAT_F64; + } + } else { + GST_INFO ("use int mixing"); + ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_int; + /* check if input needs to be unpacked to intermediate format */ + ctx->in_default = + GST_AUDIO_FORMAT_INFO_FORMAT (in->finfo) == GST_AUDIO_FORMAT_S32; + /* check if output is in default format */ + ctx->out_default = + GST_AUDIO_FORMAT_INFO_FORMAT (out->finfo) == GST_AUDIO_FORMAT_S32; } + GST_INFO ("unitsizes: %d -> %d", in->bpf, out->bpf); - /* check if input is in default format */ - ctx->in_default = check_default (ctx, in->finfo); /* check if channel mixer is passthrough */ ctx->mix_passthrough = gst_channel_mix_passthrough (ctx); - /* check if output is in default format */ - ctx->out_default = check_default (ctx, out->finfo); + ctx->quant_default = check_default (ctx, out->finfo); GST_INFO ("in default %d, mix passthrough %d, out default %d", ctx->in_default, ctx->mix_passthrough, ctx->out_default); - ctx->in_scale = - GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo) ? (32 - in_depth) : 0; ctx->out_scale = GST_AUDIO_FORMAT_INFO_IS_INTEGER (out->finfo) ? (32 - out_depth) : 0; - GST_INFO ("scale in %d, out %d", ctx->in_scale, ctx->out_scale); + GST_INFO ("scale out %d", ctx->out_scale); gst_audio_quantize_setup (ctx); @@ -698,6 +187,7 @@ audio_convert_clean_context (AudioConvertCtx * ctx) gst_channel_mix_unset_matrix (ctx); gst_audio_info_init (&ctx->in); gst_audio_info_init (&ctx->out); + ctx->convert = NULL; g_free (ctx->tmpbuf); ctx->tmpbuf = NULL; @@ -749,7 +239,7 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, if (!ctx->in_default) intemp = gst_util_uint64_scale (insize, size * 8, in_width); - if (!ctx->mix_passthrough || !ctx->out_default) + if (!ctx->mix_passthrough || !ctx->quant_default) outtemp = gst_util_uint64_scale (outsize, size * 8, out_width); biggest = MAX (intemp, outtemp); @@ -768,24 +258,37 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, /* start conversion */ if (!ctx->in_default) { + gpointer t; + /* check if final conversion */ - if (!(ctx->out_default && ctx->mix_passthrough)) + if (!(ctx->quant_default && ctx->mix_passthrough)) outbuf = tmpbuf; else outbuf = dst; + /* move samples to the middle of the array so that we can + * convert them in-place */ + if (ctx->convert) + t = ((gint32 *) outbuf) + (samples * ctx->in.channels); + else + t = outbuf; + /* unpack to default format */ - ctx->unpack (src, outbuf, ctx->in_scale, samples * ctx->in.channels); + ctx->in.finfo->unpack_func (ctx->in.finfo, 0, t, src, + samples * ctx->in.channels); + + if (ctx->convert) + ctx->convert (outbuf, t, samples * ctx->in.channels); src = outbuf; } if (!ctx->mix_passthrough) { /* check if final conversion */ - if (!ctx->out_default) - outbuf = tmpbuf; - else + if (ctx->quant_default) outbuf = dst; + else + outbuf = tmpbuf; /* convert channels */ ctx->channel_mix (ctx, src, outbuf, samples); @@ -799,12 +302,14 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src, outbuf = dst; else outbuf = tmpbuf; + ctx->quantize (ctx, src, outbuf, samples); } if (!ctx->out_default) { /* pack default format into dst */ - ctx->pack (src, dst, ctx->out_scale, samples * ctx->out.channels); + ctx->out.finfo->pack_func (ctx->out.finfo, 0, src, dst, + samples * ctx->out.channels); } return TRUE; diff --git a/gst/audioconvert/audioconvert.h b/gst/audioconvert/audioconvert.h index 56080cc..fde28a3 100644 --- a/gst/audioconvert/audioconvert.h +++ b/gst/audioconvert/audioconvert.h @@ -87,23 +87,16 @@ struct _AudioConvertFmt }; #endif -typedef void (*AudioConvertUnpack) (gpointer src, gpointer dst, gint scale, - gint count); -typedef void (*AudioConvertPack) (gpointer src, gpointer dst, gint scale, - gint count); - typedef void (*AudioConvertMix) (AudioConvertCtx *, gpointer, gpointer, gint); typedef void (*AudioConvertQuantize) (AudioConvertCtx * ctx, gpointer src, gpointer dst, gint count); +typedef void (*AudioConvertToF64) (gdouble *dst, const gint32 *src, gint count); struct _AudioConvertCtx { GstAudioInfo in; GstAudioInfo out; - AudioConvertUnpack unpack; - AudioConvertPack pack; - /* channel conversion matrix, m[in_channels][out_channels]. * If identity matrix, passthrough applies. */ gfloat **matrix; @@ -117,16 +110,16 @@ struct _AudioConvertCtx gboolean in_default; gboolean mix_passthrough; + gboolean quant_default; gboolean out_default; gpointer tmpbuf; gint tmpbufsize; - gint in_scale; gint out_scale; + AudioConvertToF64 convert; AudioConvertMix channel_mix; - AudioConvertQuantize quantize; GstAudioConvertDithering dither; diff --git a/gst/audioconvert/gstaudioconvertorc.orc b/gst/audioconvert/gstaudioconvertorc.orc index 8d57a35..dee6b61 100644 --- a/gst/audioconvert/gstaudioconvertorc.orc +++ b/gst/audioconvert/gstaudioconvertorc.orc @@ -1,591 +1,15 @@ - -.function audio_convert_orc_unpack_u8 -.dest 4 d1 gint32 -.source 1 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 2 t2 -.temp 4 t3 - -convubw t2, s1 -convuwl t3, t2 -shll t3, t3, p1 -xorl d1, t3, c1 - - -.function audio_convert_orc_unpack_s8 -.dest 4 d1 gint32 -.source 1 s1 guint8 -.param 4 p1 -.temp 2 t2 -.temp 4 t3 - -convubw t2, s1 -convuwl t3, t2 -shll d1, t3, p1 - - -.function audio_convert_orc_unpack_u16 -.dest 4 d1 gint32 -.source 2 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t2 - -convuwl t2, s1 -shll t2, t2, p1 -xorl d1, t2, c1 - - -.function audio_convert_orc_unpack_s16 -.dest 4 d1 gint32 -.source 2 s1 guint8 -.param 4 p1 -.temp 4 t2 - -convuwl t2, s1 -shll d1, t2, p1 - - -.function audio_convert_orc_unpack_u16_swap -.dest 4 d1 gint32 -.source 2 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 2 t1 -.temp 4 t2 - -swapw t1, s1 -convuwl t2, t1 -shll t2, t2, p1 -xorl d1, t2, c1 - - -.function audio_convert_orc_unpack_s16_swap -.dest 4 d1 gint32 -.source 2 s1 guint8 -.param 4 p1 -.temp 2 t1 -.temp 4 t2 - -swapw t1, s1 -convuwl t2, t1 -shll d1, t2, p1 - - -.function audio_convert_orc_unpack_u32 -.dest 4 d1 gint32 -.source 4 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 - -shll t1, s1, p1 -xorl d1, t1, c1 - - -.function audio_convert_orc_unpack_s32 -.dest 4 d1 gint32 -.source 4 s1 guint8 -.param 4 p1 - -shll d1, s1, p1 - - -.function audio_convert_orc_unpack_u32_swap -.dest 4 d1 gint32 -.source 4 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 - -swapl t1, s1 -shll t1, t1, p1 -xorl d1, t1, c1 - - -.function audio_convert_orc_unpack_s32_swap -.dest 4 d1 gint32 -.source 4 s1 guint8 -.param 4 p1 -.temp 4 t1 - -swapl t1, s1 -shll d1, t1, p1 - -.function audio_convert_orc_unpack_float_s32 -.source 4 s1 gfloat -.dest 4 d1 guint32 -.temp 4 t1 - -loadl t1, s1 -# multiply with 2147483647.0 -mulf t1, t1, 0x4F000000 -# add 0.5 for rounding -addf t1, t1, 0x3F000000 -convfl d1, t1 - -.function audio_convert_orc_unpack_float_s32_swap -.source 4 s1 gfloat -.dest 4 d1 guint32 -.temp 4 t1 - -swapl t1, s1 -# multiply with 2147483647.0 -mulf t1, t1, 0x4F000000 -# add 0.5 for rounding -addf t1, t1, 0x3F000000 -convfl d1, t1 - -.function audio_convert_orc_unpack_double_s32 -.source 8 s1 gdouble -.dest 4 d1 guint32 -.temp 8 t1 - -loadq t1, s1 -# multiply with 2147483647.0 -muld t1, t1, 0x41DFFFFFFFC00000L -# add 0.5 for rounding -addd t1, t1, 0x3FE0000000000000L -convdl d1, t1 - -.function audio_convert_orc_unpack_double_s32_swap -.source 8 s1 gdouble -.dest 4 d1 guint32 -.temp 8 t1 - -swapq t1, s1 -# multiply with 2147483647.0 -muld t1, t1, 0x41DFFFFFFFC00000L -# add 0.5 for rounding -addd t1, t1, 0x3FE0000000000000L -convdl d1, t1 - -.function audio_convert_orc_unpack_float_double -.dest 8 d1 gdouble -.source 4 s1 gfloat - -convfd d1, s1 - -.function audio_convert_orc_unpack_float_double_swap -.dest 8 d1 gdouble -.source 4 s1 gfloat -.temp 4 t1 - -swapl t1, s1 -convfd d1, t1 - -.function audio_convert_orc_unpack_double_double -.dest 8 d1 gdouble -.source 8 s1 gdouble - -copyq d1, s1 - -.function audio_convert_orc_unpack_double_double_swap -.dest 8 d1 gdouble -.source 8 s1 gdouble - -swapq d1, s1 - -.function audio_convert_orc_unpack_u8_double -.dest 8 d1 gdouble -.source 1 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 2 t2 -.temp 4 t3 - -convubw t2, s1 -convuwl t3, t2 -shll t3, t3, p1 -xorl t3, t3, c1 -convld d1, t3 - -.function audio_convert_orc_unpack_s8_double -.dest 8 d1 gdouble -.source 1 s1 guint8 -.param 4 p1 -.temp 2 t2 -.temp 4 t3 - -convubw t2, s1 -convuwl t3, t2 -shll t3, t3, p1 -convld d1, t3 - -.function audio_convert_orc_unpack_u16_double -.dest 8 d1 gdouble -.source 2 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t2 - -convuwl t2, s1 -shll t2, t2, p1 -xorl t2, t2, c1 -convld d1, t2 - -.function audio_convert_orc_unpack_s16_double -.dest 8 d1 gdouble -.source 2 s1 guint8 -.param 4 p1 -.temp 4 t2 - -convuwl t2, s1 -shll t2, t2, p1 -convld d1, t2 - -.function audio_convert_orc_unpack_u16_double_swap -.dest 8 d1 gdouble -.source 2 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 2 t1 -.temp 4 t2 - -swapw t1, s1 -convuwl t2, t1 -shll t2, t2, p1 -xorl t2, t2, c1 -convld d1, t2 - -.function audio_convert_orc_unpack_s16_double_swap -.dest 8 d1 gdouble -.source 2 s1 guint8 -.param 4 p1 -.temp 2 t1 -.temp 4 t2 - -swapw t1, s1 -convuwl t2, t1 -shll t2, t2, p1 -convld d1, t2 - -.function audio_convert_orc_unpack_u32_double -.dest 8 d1 gdouble -.source 4 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 - -shll t1, s1, p1 -xorl t1, t1, c1 -convld d1, t1 - -.function audio_convert_orc_unpack_s32_double -.dest 8 d1 gdouble -.source 4 s1 guint8 -.param 4 p1 -.temp 4 t1 - -shll t1, s1, p1 -convld d1, t1 - -.function audio_convert_orc_unpack_u32_double_swap -.dest 8 d1 gdouble -.source 4 s1 guint8 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 - -swapl t1, s1 -shll t1, t1, p1 -xorl t1, t1, c1 -convld d1, t1 - -.function audio_convert_orc_unpack_s32_double_swap -.dest 8 d1 gdouble -.source 4 s1 guint8 -.param 4 p1 -.temp 4 t1 - -swapl t1, s1 -shll t1, t1, p1 -convld d1, t1 - -.function audio_convert_orc_pack_u8 -.dest 1 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 -.temp 2 t2 - -xorl t1, s1, c1 -shrul t1, t1, p1 -convlw t2, t1 -convwb d1, t2 - - -.function audio_convert_orc_pack_s8 -.dest 1 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 -.temp 4 t1 -.temp 2 t2 - -shrsl t1, s1, p1 -convlw t2, t1 -convwb d1, t2 - - - -.function audio_convert_orc_pack_u16 -.dest 2 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 - -xorl t1, s1, c1 -shrul t1, t1, p1 -convlw d1, t1 - - -.function audio_convert_orc_pack_s16 -.dest 2 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 -.temp 4 t1 - -shrsl t1, s1, p1 -convlw d1, t1 - - -.function audio_convert_orc_pack_u16_swap -.dest 2 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 -.temp 2 t2 - -xorl t1, s1, c1 -shrul t1, t1, p1 -convlw t2, t1 -swapw d1, t2 - - -.function audio_convert_orc_pack_s16_swap -.dest 2 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 -.temp 4 t1 -.temp 2 t2 - -shrsl t1, s1, p1 -convlw t2, t1 -swapw d1, t2 - - - -.function audio_convert_orc_pack_u32 -.dest 4 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 - -xorl t1, s1, c1 -shrul d1, t1, p1 - - -.function audio_convert_orc_pack_s32 -.dest 4 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 - -shrsl d1, s1, p1 - - -.function audio_convert_orc_pack_u32_swap -.dest 4 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 - -xorl t1, s1, c1 -shrul t1, t1, p1 -swapl d1, t1 - - -.function audio_convert_orc_pack_s32_swap -.dest 4 d1 guint8 -.source 4 s1 gint32 -.param 4 p1 -.temp 4 t1 - -shrsl t1, s1, p1 -swapl d1, t1 - -.function audio_convert_orc_pack_s32_float -.dest 4 d1 gfloat -.source 4 s1 gint32 -.temp 4 t1 - -convlf t1, s1 -# divide by 2147483647.0 -divf t1, t1, 0x4F000000 -storel d1, t1 - -.function audio_convert_orc_pack_s32_float_swap -.dest 4 d1 gfloat -.source 4 s1 gint32 -.temp 4 t1 - -convlf t1, s1 -# divide by 2147483647.0 -divf t1, t1, 0x4F000000 -swapl d1, t1 - -.function audio_convert_orc_pack_s32_double -.dest 8 d1 gdouble -.source 4 s1 gint32 -.temp 8 t1 - -convld t1, s1 -# divide by 2147483647.0 -divd t1, t1, 0x41DFFFFFFFC00000L -storeq d1, t1 - -.function audio_convert_orc_pack_s32_double_swap +.function audio_convert_orc_s32_to_double .dest 8 d1 gdouble .source 4 s1 gint32 .temp 8 t1 convld t1, s1 -# divide by 2147483647.0 -divd t1, t1, 0x41DFFFFFFFC00000L -swapq d1, t1 - -.function audio_convert_orc_pack_double_float -.dest 4 d1 gfloat -.source 8 s1 gdouble - -convdf d1, s1 - -.function audio_convert_orc_pack_double_float_swap -.dest 4 d1 gfloat -.source 8 s1 gdouble -.temp 4 t1 - -convdf t1, s1 -swapl d1, t1 - -.function audio_convert_orc_pack_double_u8 -.dest 1 d1 guint8 -.source 8 s1 gdouble -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 -.temp 2 t2 - -convdl t1, s1 -xorl t1, t1, c1 -shrul t1, t1, p1 -convlw t2, t1 -convwb d1, t2 - -.function audio_convert_orc_pack_double_s8 -.dest 1 d1 guint8 -.source 8 s1 gdouble -.param 4 p1 -.temp 4 t1 -.temp 2 t2 - -convdl t1, s1 -shrsl t1, t1, p1 -convlw t2, t1 -convwb d1, t2 - -.function audio_convert_orc_pack_double_u16 -.dest 2 d1 guint8 -.source 8 s1 gdouble -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 +divd d1, t1, 0x41DFFFFFFFC00000L -convdl t1, s1 -xorl t1, t1, c1 -shrul t1, t1, p1 -convlw d1, t1 - -.function audio_convert_orc_pack_double_s16 -.dest 2 d1 guint8 -.source 8 s1 gdouble -.param 4 p1 -.temp 4 t1 - -convdl t1, s1 -shrsl t1, t1, p1 -convlw d1, t1 - -.function audio_convert_orc_pack_double_u16_swap -.dest 2 d1 guint8 -.source 8 s1 gdouble -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 -.temp 2 t2 - -convdl t1, s1 -xorl t1, t1, c1 -shrul t1, t1, p1 -convlw t2, t1 -swapw d1, t2 - -.function audio_convert_orc_pack_double_s16_swap -.dest 2 d1 guint8 -.source 8 s1 gdouble -.param 4 p1 -.temp 4 t1 -.temp 2 t2 - -convdl t1, s1 -shrsl t1, t1, p1 -convlw t2, t1 -swapw d1, t2 - -.function audio_convert_orc_pack_double_u32 -.dest 4 d1 guint8 -.source 8 s1 gdouble -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 - -convdl t1, s1 -xorl t1, t1, c1 -shrul d1, t1, p1 - -.function audio_convert_orc_pack_double_s32 -.dest 4 d1 guint8 -.source 8 s1 gdouble -.param 4 p1 -.temp 4 t1 - -convdl t1, s1 -shrsl d1, t1, p1 - -.function audio_convert_orc_pack_double_u32_swap -.dest 4 d1 guint8 -.source 8 s1 gdouble -.param 4 p1 -.const 4 c1 0x80000000 -.temp 4 t1 - -convdl t1, s1 -xorl t1, t1, c1 -shrul t1, t1, p1 -swapl d1, t1 - -.function audio_convert_orc_pack_double_s32_swap -.dest 4 d1 guint8 +.function audio_convert_orc_double_to_s32 +.dest 4 d1 gint32 .source 8 s1 gdouble -.param 4 p1 -.temp 4 t1 - -convdl t1, s1 -shrsl t1, t1, p1 -swapl d1, t1 +.temp 8 t1 +muld t1, s1, 0x41DFFFFFFFC00000L +convdl d1, t1 diff --git a/gst/audioconvert/gstaudioquantize.c b/gst/audioconvert/gstaudioquantize.c index 91a8c12..b61860e 100644 --- a/gst/audioconvert/gstaudioquantize.c +++ b/gst/audioconvert/gstaudioquantize.c @@ -35,6 +35,7 @@ #include #include #include "audioconvert.h" +#include "gstaudioconvertorc.h" #include "gstaudioquantize.h" #include "gstfastrandom.h" @@ -70,12 +71,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \ } \ } \ } else { \ - for (;count;count--) { \ - for (chan_pos = 0; chan_pos < channels; chan_pos++) { \ - *dst = *src++; \ - dst++; \ - } \ - } \ + memcpy (dst, src, count * channels * 4); \ } \ } @@ -88,15 +84,14 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \ UPDATE_ERROR_FUNC) \ static void \ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ - gdouble *dst, gint count) \ + gint32 *dst, gint count) \ { \ gint scale = ctx->out_scale; \ gint channels = ctx->out.channels; \ gint chan_pos; \ - gdouble factor = (1U<<(32-scale-1)) - 1; \ + gdouble tmp, d, factor = (1U<<(32-scale-1)); \ \ if (scale > 0) { \ - gdouble tmp; \ DITHER_INIT_FUNC() \ NS_INIT_FUNC() \ \ @@ -105,19 +100,14 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ tmp = *src++; \ ADD_NS_FUNC() \ ADD_DITHER_FUNC() \ - tmp = floor(tmp * factor + 0.5); \ - *dst = CLAMP (tmp, -factor - 1, factor); \ + tmp = floor(tmp * factor); \ + d = CLAMP (tmp, -factor, factor - 1); \ UPDATE_ERROR_FUNC() \ - dst++; \ + *dst++ = ((gint32)d) << scale; \ } \ } \ } else { \ - for (;count;count--) { \ - for (chan_pos = 0; chan_pos < channels; chan_pos++) { \ - *dst = *src++ * 2147483647.0; \ - dst++; \ - } \ - } \ + audio_convert_orc_double_to_s32 (dst, src, count * channels); \ } \ } @@ -233,7 +223,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ tmp -= errors[chan_pos]; #define UPDATE_ERROR_ERROR_FEEDBACK() \ - errors[chan_pos] += (*dst)/factor - orig; + errors[chan_pos] += (d)/factor - orig; /* Same as error feedback but also add 1/2 of the previous error value. * This moves the noise a bit more into the higher frequencies. */ @@ -249,7 +239,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \ #define UPDATE_ERROR_SIMPLE() \ errors[chan_pos*2 + 1] = errors[chan_pos*2]; \ - errors[chan_pos*2] = (*dst)/factor - orig; + errors[chan_pos*2] = (d)/factor - orig; /* Noise shaping coefficients from[1], moves most power of the @@ -279,7 +269,7 @@ static const gdouble ns_medium_coeffs[] = { #define UPDATE_ERROR_MEDIUM() \ for (j = 4; j > 0; j--) \ errors[chan_pos*5 + j] = errors[chan_pos*5 + j-1]; \ - errors[chan_pos*5] = (*dst)/factor - orig; + errors[chan_pos*5] = (d)/factor - orig; /* Noise shaping coefficients by David Schleef, moves most power of the * error noise into inaudible frequency ranges */ @@ -303,7 +293,7 @@ static const gdouble ns_high_coeffs[] = { #define UPDATE_ERROR_HIGH() \ for (j = 7; j > 0; j--) \ errors[chan_pos + j] = errors[chan_pos + j-1]; \ - errors[chan_pos] = (*dst)/factor - orig; + errors[chan_pos] = (d)/factor - orig; MAKE_QUANTIZE_FUNC_I (int_none_none, NONE_FUNC, NONE_FUNC, ROUND); @@ -314,6 +304,8 @@ MAKE_QUANTIZE_FUNC_I (int_tpdf_none, INIT_DITHER_TPDF_I, ADD_DITHER_TPDF_I, MAKE_QUANTIZE_FUNC_I (int_tpdf_hf_none, INIT_DITHER_TPDF_HF_I, ADD_DITHER_TPDF_HF_I, NONE_FUNC); +MAKE_QUANTIZE_FUNC_F (float_none_none, NONE_FUNC, + NONE_FUNC, NONE_FUNC, NONE_FUNC, NONE_FUNC); MAKE_QUANTIZE_FUNC_F (float_none_error_feedback, NONE_FUNC, INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, NONE_FUNC, UPDATE_ERROR_ERROR_FEEDBACK); @@ -324,6 +316,8 @@ MAKE_QUANTIZE_FUNC_F (float_none_medium, NONE_FUNC, INIT_NS_MEDIUM, MAKE_QUANTIZE_FUNC_F (float_none_high, NONE_FUNC, INIT_NS_HIGH, ADD_NS_HIGH, NONE_FUNC, UPDATE_ERROR_HIGH); +MAKE_QUANTIZE_FUNC_F (float_rpdf_none, INIT_DITHER_RPDF_F, + NONE_FUNC, NONE_FUNC, ADD_DITHER_RPDF_F, NONE_FUNC); MAKE_QUANTIZE_FUNC_F (float_rpdf_error_feedback, INIT_DITHER_RPDF_F, INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, ADD_DITHER_RPDF_F, UPDATE_ERROR_ERROR_FEEDBACK); @@ -334,6 +328,8 @@ MAKE_QUANTIZE_FUNC_F (float_rpdf_medium, INIT_DITHER_RPDF_F, INIT_NS_MEDIUM, MAKE_QUANTIZE_FUNC_F (float_rpdf_high, INIT_DITHER_RPDF_F, INIT_NS_HIGH, ADD_NS_HIGH, ADD_DITHER_RPDF_F, UPDATE_ERROR_HIGH); +MAKE_QUANTIZE_FUNC_F (float_tpdf_none, INIT_DITHER_TPDF_F, + NONE_FUNC, NONE_FUNC, ADD_DITHER_TPDF_F, NONE_FUNC); MAKE_QUANTIZE_FUNC_F (float_tpdf_error_feedback, INIT_DITHER_TPDF_F, INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, ADD_DITHER_TPDF_F, UPDATE_ERROR_ERROR_FEEDBACK); @@ -344,6 +340,8 @@ MAKE_QUANTIZE_FUNC_F (float_tpdf_medium, INIT_DITHER_TPDF_F, INIT_NS_MEDIUM, MAKE_QUANTIZE_FUNC_F (float_tpdf_high, INIT_DITHER_TPDF_F, INIT_NS_HIGH, ADD_NS_HIGH, ADD_DITHER_TPDF_F, UPDATE_ERROR_HIGH); +MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_none, INIT_DITHER_TPDF_HF_F, + NONE_FUNC, NONE_FUNC, ADD_DITHER_TPDF_HF_F, NONE_FUNC); MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_error_feedback, INIT_DITHER_TPDF_HF_F, INIT_NS_ERROR_FEEDBACK, ADD_NS_ERROR_FEEDBACK, ADD_DITHER_TPDF_HF_F, UPDATE_ERROR_ERROR_FEEDBACK); @@ -359,18 +357,22 @@ static const AudioConvertQuantize quantize_funcs[] = { (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_rpdf_none), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_none), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_hf_none), + (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_none), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_error_feedback), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_simple), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_medium), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_high), + (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_none), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_error_feedback), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_simple), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_medium), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_high), + (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_none), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_error_feedback), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_simple), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_medium), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_high), + (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_none), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_error_feedback), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_simple), (AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_medium), @@ -462,11 +464,12 @@ gst_audio_quantize_setup_quantize_func (AudioConvertCtx * ctx) return; } - if (ctx->ns == NOISE_SHAPING_NONE) { + if (ctx->ns == NOISE_SHAPING_NONE + && GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->in.finfo)) { index += ctx->dither; } else { - index += 4 + (4 * ctx->dither); - index += ctx->ns - 1; + index += 4 + (5 * ctx->dither); + index += ctx->ns; } ctx->quantize = quantize_funcs[index]; diff --git a/gst/audioconvert/gstchannelmix.c b/gst/audioconvert/gstchannelmix.c index f144c20..2bc1528 100644 --- a/gst/audioconvert/gstchannelmix.c +++ b/gst/audioconvert/gstchannelmix.c @@ -614,7 +614,7 @@ gst_channel_mix_setup_matrix_int (AudioConvertCtx * this) for (j = 0; j < this->out.channels; j++) { tmp = this->matrix[i][j] * factor; - this->matrix_int[i][j] = (gint)tmp; + this->matrix_int[i][j] = (gint) tmp; } } } @@ -647,7 +647,7 @@ gst_channel_mix_setup_matrix (AudioConvertCtx * this) /* setup the matrix' internal values */ gst_channel_mix_fill_matrix (this); - gst_channel_mix_setup_matrix_int(this); + gst_channel_mix_setup_matrix_int (this); #ifndef GST_DISABLE_GST_DEBUG /* debug */ @@ -725,7 +725,8 @@ gst_channel_mix_mix_int (AudioConvertCtx * this, /* convert */ res = 0; for (in = 0; in < inchannels; in++) { - res += in_data[n * inchannels + in] * (gint64)this->matrix_int[in][out]; + res += + in_data[n * inchannels + in] * (gint64) this->matrix_int[in][out]; } /* remove factor from int matrix */ @@ -760,7 +761,7 @@ gst_channel_mix_mix_float (AudioConvertCtx * this, outchannels = this->out.channels; backwards = outchannels > inchannels; - /* FIXME: use liboil here? */ + /* FIXME: use orc here? */ for (n = (backwards ? samples - 1 : 0); n < samples && n >= 0; backwards ? n-- : n++) { for (out = 0; out < outchannels; out++) { -- 2.7.4