audioconvert.c 24.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* GStreamer
 * Copyright (C) 2005 Wim Taymans <wim at fluendo dot com>
 *
 * audioconvert.c: Convert audio to different audio formats automatically
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

26
#include <math.h>
27
28
29
#include <string.h>

#include "gstchannelmix.h"
30
#include "gstaudioquantize.h"
31
#include "audioconvert.h"
René Stadler's avatar
René Stadler committed
32
#include "gst/floatcast/floatcast.h"
33

34
/* sign bit in the intermediate format */
35
#define SIGNED  (1U<<31)
36

37
38
39
/*** 
 * unpack code
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
40
#define MAKE_UNPACK_FUNC_NAME(name)                                     \
41
42
audio_convert_unpack_##name

René Stadler's avatar
René Stadler committed
43
/* unpack from integer to signed integer 32 */
44
#define MAKE_UNPACK_FUNC_II(name, stride, sign, READ_FUNC)              \
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
45
static void                                                             \
46
MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gint32 *dst,                 \
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
47
48
49
        gint scale, gint count)                                         \
{                                                                       \
  for (;count; count--) {                                               \
50
51
    *dst++ = (((gint32) READ_FUNC (src)) << scale) ^ (sign);            \
    src+=stride;                                                        \
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
52
  }                                                                     \
53
54
}

René Stadler's avatar
René Stadler committed
55
56
57
58
59
60
61
62
63
/* 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 */                                                   \
64
    temp = floor ((READ_FUNC (*src++) * 2147483647.0) + 0.5);                 \
René Stadler's avatar
René Stadler committed
65
66
    *dst++ = (gint32) CLAMP (temp, G_MININT32, G_MAXINT32);                   \
  }                                                                           \
67
68
}

René Stadler's avatar
René Stadler committed
69
70
71
72
73
74
75
76
/* 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++);                                         \
77
78
}

79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* 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;                                                            \
  }                                                                           \
}

93
94
95
96
97
98
99
100
#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)

René Stadler's avatar
René Stadler committed
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
MAKE_UNPACK_FUNC_II (u8, 1, SIGNED, READ8);
MAKE_UNPACK_FUNC_II (s8, 1, 0, READ8);
MAKE_UNPACK_FUNC_II (u16_le, 2, SIGNED, READ16_FROM_LE);
MAKE_UNPACK_FUNC_II (s16_le, 2, 0, READ16_FROM_LE);
MAKE_UNPACK_FUNC_II (u16_be, 2, SIGNED, READ16_FROM_BE);
MAKE_UNPACK_FUNC_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_II (u32_le, 4, SIGNED, READ32_FROM_LE);
MAKE_UNPACK_FUNC_II (s32_le, 4, 0, READ32_FROM_LE);
MAKE_UNPACK_FUNC_II (u32_be, 4, SIGNED, READ32_FROM_BE);
MAKE_UNPACK_FUNC_II (s32_be, 4, 0, READ32_FROM_BE);
MAKE_UNPACK_FUNC_FI (float_le, gfloat, GFLOAT_FROM_LE);
MAKE_UNPACK_FUNC_FI (float_be, gfloat, GFLOAT_FROM_BE);
MAKE_UNPACK_FUNC_FI (double_le, gdouble, GDOUBLE_FROM_LE);
MAKE_UNPACK_FUNC_FI (double_be, gdouble, GDOUBLE_FROM_BE);
MAKE_UNPACK_FUNC_FF (float_hq_le, gfloat, GFLOAT_FROM_LE);
MAKE_UNPACK_FUNC_FF (float_hq_be, gfloat, GFLOAT_FROM_BE);
MAKE_UNPACK_FUNC_FF (double_hq_le, gdouble, GDOUBLE_FROM_LE);
MAKE_UNPACK_FUNC_FF (double_hq_be, gdouble, GDOUBLE_FROM_BE);
123
124
125
126
127
128
129
130
131
132
133
134
135
136
MAKE_UNPACK_FUNC_IF (u8_float, 1, SIGNED, READ8);
MAKE_UNPACK_FUNC_IF (s8_float, 1, 0, READ8);
MAKE_UNPACK_FUNC_IF (u16_le_float, 2, SIGNED, READ16_FROM_LE);
MAKE_UNPACK_FUNC_IF (s16_le_float, 2, 0, READ16_FROM_LE);
MAKE_UNPACK_FUNC_IF (u16_be_float, 2, SIGNED, READ16_FROM_BE);
MAKE_UNPACK_FUNC_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_IF (u32_le_float, 4, SIGNED, READ32_FROM_LE);
MAKE_UNPACK_FUNC_IF (s32_le_float, 4, 0, READ32_FROM_LE);
MAKE_UNPACK_FUNC_IF (u32_be_float, 4, SIGNED, READ32_FROM_BE);
MAKE_UNPACK_FUNC_IF (s32_be_float, 4, 0, READ32_FROM_BE);
René Stadler's avatar
René Stadler committed
137
138
139

/* One of the double_hq_* functions generated above is ineffecient, but it's
 * never used anyway.  The same is true for one of the s32_* functions. */
140
141
142
143

/*** 
 * packing code
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
144
#define MAKE_PACK_FUNC_NAME(name)                                       \
145
146
audio_convert_pack_##name

147
148
149
150
/*
 * These functions convert the signed 32 bit integers to the
 * target format. For this to work the following steps are done:
 *
151
 * 1) If the output format is unsigned we will XOR the sign bit. This
152
 *    will do the same as if we add 1<<31.
153
 * 2) Afterwards we shift to the target depth. It's necessary to left-shift
154
 *    on signed values here to get arithmetical shifting.
155
 * 3) This is then written into our target array by the corresponding write
156
157
158
 *    function for the target width.
 */

René Stadler's avatar
René Stadler committed
159
160
/* pack from signed integer 32 to integer */
#define MAKE_PACK_FUNC_II(name, stride, sign, WRITE_FUNC)               \
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
161
static void                                                             \
162
MAKE_PACK_FUNC_NAME (name) (gint32 *src, guint8 * dst,                  \
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
163
164
        gint scale, gint count)                                         \
{                                                                       \
165
  gint32 tmp;                                                           \
166
167
168
169
  for (;count; count--) {                                               \
    tmp = (*src++ ^ (sign)) >> scale;                                   \
    WRITE_FUNC (dst, tmp);                                              \
    dst += stride;                                                      \
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
170
  }                                                                     \
171
172
}

René Stadler's avatar
René Stadler committed
173
/* pack from signed integer 32 to float */
174
#define MAKE_PACK_FUNC_IF(name, type, FUNC)                             \
René Stadler's avatar
René Stadler committed
175
176
177
178
179
static void                                                             \
MAKE_PACK_FUNC_NAME (name) (gint32 * src, type * dst, gint scale,       \
    gint count)                                                         \
{                                                                       \
  for (; count; count--)                                                \
180
    *dst++ = FUNC ((type) ((*src++) * (1.0 / 2147483647.0)));           \
181
182
}

René Stadler's avatar
René Stadler committed
183
184
185
186
187
188
189
190
/* 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++));                                    \
191
192
}

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
/* 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;                                                      \
  }                                                                     \
}

229
230
231
232
233
234
235
236
#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))

René Stadler's avatar
René Stadler committed
237
238
239
240
241
242
243
244
245
246
247
248
249
250
MAKE_PACK_FUNC_II (u8, 1, SIGNED, WRITE8);
MAKE_PACK_FUNC_II (s8, 1, 0, WRITE8);
MAKE_PACK_FUNC_II (u16_le, 2, SIGNED, WRITE16_TO_LE);
MAKE_PACK_FUNC_II (s16_le, 2, 0, WRITE16_TO_LE);
MAKE_PACK_FUNC_II (u16_be, 2, SIGNED, WRITE16_TO_BE);
MAKE_PACK_FUNC_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_II (u32_le, 4, SIGNED, WRITE32_TO_LE);
MAKE_PACK_FUNC_II (s32_le, 4, 0, WRITE32_TO_LE);
MAKE_PACK_FUNC_II (u32_be, 4, SIGNED, WRITE32_TO_BE);
MAKE_PACK_FUNC_II (s32_be, 4, 0, WRITE32_TO_BE);
251
252
253
254
MAKE_PACK_FUNC_IF (float_le, gfloat, GFLOAT_TO_LE);
MAKE_PACK_FUNC_IF (float_be, gfloat, GFLOAT_TO_BE);
MAKE_PACK_FUNC_IF (double_le, gdouble, GDOUBLE_TO_LE);
MAKE_PACK_FUNC_IF (double_be, gdouble, GDOUBLE_TO_BE);
René Stadler's avatar
René Stadler committed
255
256
MAKE_PACK_FUNC_FF (float_hq_le, gfloat, GFLOAT_TO_LE);
MAKE_PACK_FUNC_FF (float_hq_be, gfloat, GFLOAT_TO_BE);
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
MAKE_PACK_FUNC_FI_U (u8_float, 1, WRITE8);
MAKE_PACK_FUNC_FI_S (s8_float, 1, WRITE8);
MAKE_PACK_FUNC_FI_U (u16_le_float, 2, WRITE16_TO_LE);
MAKE_PACK_FUNC_FI_S (s16_le_float, 2, WRITE16_TO_LE);
MAKE_PACK_FUNC_FI_U (u16_be_float, 2, WRITE16_TO_BE);
MAKE_PACK_FUNC_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_FI_U (u32_le_float, 4, WRITE32_TO_LE);
MAKE_PACK_FUNC_FI_S (s32_le_float, 4, WRITE32_TO_LE);
MAKE_PACK_FUNC_FI_U (u32_be_float, 4, WRITE32_TO_BE);
MAKE_PACK_FUNC_FI_S (s32_be_float, 4, WRITE32_TO_BE);

René Stadler's avatar
René Stadler committed
272
273
274
275
/* 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)
276

277
static AudioConvertUnpack unpack_funcs[] = {
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  (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),
René Stadler's avatar
René Stadler committed
294
295
296
297
298
299
300
301
  (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),
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  (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),
318
319
320
};

static AudioConvertPack pack_funcs[] = {
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  (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),
René Stadler's avatar
René Stadler committed
337
338
339
340
341
342
343
344
  (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),
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  (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),
361
362
};

363
364
365
#define DOUBLE_INTERMEDIATE_FORMAT(ctx)                                 \
    ((!ctx->in.is_int && !ctx->out.is_int) || (ctx->ns != NOISE_SHAPING_NONE))

366
static gint
367
audio_convert_get_func_index (AudioConvertCtx * ctx, AudioConvertFmt * fmt)
368
369
370
371
372
373
374
{
  gint index = 0;

  if (fmt->is_int) {
    index += (fmt->width / 8 - 1) * 4;
    index += fmt->endianness == G_LITTLE_ENDIAN ? 0 : 2;
    index += fmt->sign ? 1 : 0;
375
    index += (ctx->ns == NOISE_SHAPING_NONE) ? 0 : 24;
376
  } else {
377
    /* this is float/double */
René Stadler's avatar
René Stadler committed
378
379
380
    index = 16;
    index += (fmt->width == 32) ? 0 : 2;
    index += (fmt->endianness == G_LITTLE_ENDIAN) ? 0 : 1;
381
    index += (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? 4 : 0;
382
  }
383

384
385
386
  return index;
}

387
static inline gboolean
388
check_default (AudioConvertCtx * ctx, AudioConvertFmt * fmt)
389
{
390
  if (!DOUBLE_INTERMEDIATE_FORMAT (ctx)) {
391
392
393
    return (fmt->width == 32 && fmt->depth == 32 &&
        fmt->endianness == G_BYTE_ORDER && fmt->sign == TRUE);
  } else {
René Stadler's avatar
René Stadler committed
394
    return (fmt->width == 64 && fmt->endianness == G_BYTE_ORDER);
395
  }
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
}

gboolean
audio_convert_clean_fmt (AudioConvertFmt * fmt)
{
  g_return_val_if_fail (fmt != NULL, FALSE);

  g_free (fmt->pos);
  fmt->pos = NULL;

  return TRUE;
}


gboolean
audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in,
412
    AudioConvertFmt * out, DitherType dither, NoiseShapingType ns)
413
{
414
  gint idx_in, idx_out;
415
416
417
418
419
420
421
422
423
424
425

  g_return_val_if_fail (ctx != NULL, FALSE);
  g_return_val_if_fail (in != NULL, FALSE);
  g_return_val_if_fail (out != NULL, FALSE);

  /* first clean the existing context */
  audio_convert_clean_context (ctx);

  ctx->in = *in;
  ctx->out = *out;

426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
  /* Don't dither or apply noise shaping if out depth is bigger than 20 bits
   * as DA converters only can do a SNR up to 20 bits in reality.
   * Also don't dither or apply noise shaping if target depth is larger than
   * source depth. */
  if (ctx->out.depth <= 20 && (!ctx->in.is_int
          || ctx->in.depth >= ctx->out.depth)) {
    ctx->dither = dither;
    ctx->ns = ns;
  } else {
    ctx->dither = DITHER_NONE;
    ctx->ns = NOISE_SHAPING_NONE;
  }

  /* Use simple error feedback when output sample rate is smaller than
   * 32000 as the other methods might move the noise to audible ranges */
  if (ctx->ns > NOISE_SHAPING_ERROR_FEEDBACK && ctx->out.rate < 32000)
    ctx->ns = NOISE_SHAPING_ERROR_FEEDBACK;

444
445
  gst_channel_mix_setup_matrix (ctx);

446
  idx_in = audio_convert_get_func_index (ctx, in);
René Stadler's avatar
René Stadler committed
447
  ctx->unpack = unpack_funcs[idx_in];
448

449
  idx_out = audio_convert_get_func_index (ctx, out);
René Stadler's avatar
René Stadler committed
450
  ctx->pack = pack_funcs[idx_out];
451

452
453
454
  /* if both formats are float/double or we use noise shaping use double as
   * intermediate format and and switch mixing */
  if (!DOUBLE_INTERMEDIATE_FORMAT (ctx)) {
455
    GST_INFO ("use int mixing");
456
457
    ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_int;
  } else {
458
    GST_INFO ("use float mixing");
459
460
    ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_float;
  }
461
  GST_INFO ("unitsizes: %d -> %d", in->unit_size, out->unit_size);
462

463
  /* check if input is in default format */
464
  ctx->in_default = check_default (ctx, in);
465
466
467
  /* check if channel mixer is passthrough */
  ctx->mix_passthrough = gst_channel_mix_passthrough (ctx);
  /* check if output is in default format */
468
  ctx->out_default = check_default (ctx, out);
469

470
471
472
473
474
  GST_INFO ("in default %d, mix passthrough %d, out default %d",
      ctx->in_default, ctx->mix_passthrough, ctx->out_default);

  ctx->in_scale = (in->is_int) ? (32 - in->depth) : 0;
  ctx->out_scale = (out->is_int) ? (32 - out->depth) : 0;
475

476
477
  gst_audio_quantize_setup (ctx);

478
479
480
481
482
483
484
485
  return TRUE;
}

gboolean
audio_convert_clean_context (AudioConvertCtx * ctx)
{
  g_return_val_if_fail (ctx != NULL, FALSE);

486
  gst_audio_quantize_free (ctx);
487
488
489
490
491
492
  audio_convert_clean_fmt (&ctx->in);
  audio_convert_clean_fmt (&ctx->out);
  gst_channel_mix_unset_matrix (ctx);

  g_free (ctx->tmpbuf);
  ctx->tmpbuf = NULL;
493
  ctx->tmpbufsize = 0;
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515

  return TRUE;
}

gboolean
audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples, gint * srcsize,
    gint * dstsize)
{
  g_return_val_if_fail (ctx != NULL, FALSE);

  if (srcsize)
    *srcsize = samples * ctx->in.unit_size;
  if (dstsize)
    *dstsize = samples * ctx->out.unit_size;

  return TRUE;
}

gboolean
audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
    gpointer dst, gint samples, gboolean src_writable)
{
516
  gint insize, outsize, size;
517
  gpointer outbuf, tmpbuf;
518
  gint intemp = 0, outtemp = 0, biggest;
519
520
521
522
523
524
525
526
527
528

  g_return_val_if_fail (ctx != NULL, FALSE);
  g_return_val_if_fail (src != NULL, FALSE);
  g_return_val_if_fail (dst != NULL, FALSE);
  g_return_val_if_fail (samples >= 0, FALSE);

  if (samples == 0)
    return TRUE;

  insize = ctx->in.unit_size * samples;
529
  outsize = ctx->out.unit_size * samples;
530

531
  /* find biggest temp buffer size */
532
533
  size = (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? sizeof (gdouble)
      : sizeof (gint32);
534

535
  if (!ctx->in_default)
536
    intemp = insize * size * 8 / ctx->in.width;
537
  if (!ctx->mix_passthrough || !ctx->out_default)
538
539
    outtemp = outsize * size * 8 / ctx->out.width;
  biggest = MAX (intemp, outtemp);
540
541

  /* see if one of the buffers can be used as temp */
542
  if ((outsize >= biggest) && (ctx->out.unit_size <= size))
543
    tmpbuf = dst;
544
  else if ((insize >= biggest) && src_writable && (ctx->in.unit_size >= size))
545
546
547
548
549
    tmpbuf = src;
  else {
    if (biggest > ctx->tmpbufsize) {
      ctx->tmpbuf = g_realloc (ctx->tmpbuf, biggest);
      ctx->tmpbufsize = biggest;
550
    }
551
    tmpbuf = ctx->tmpbuf;
552
553
  }

554
  /* start conversion */
555
556
  if (!ctx->in_default) {
    /* check if final conversion */
557
    if (!(ctx->out_default && ctx->mix_passthrough))
558
      outbuf = tmpbuf;
559
560
    else
      outbuf = dst;
561

562
    /* unpack to default format */
563
    ctx->unpack (src, outbuf, ctx->in_scale, samples * ctx->in.channels);
564

565
    src = outbuf;
566
567
568
  }

  if (!ctx->mix_passthrough) {
569
570
    /* check if final conversion */
    if (!ctx->out_default)
571
572
573
      outbuf = tmpbuf;
    else
      outbuf = dst;
574

575
    /* convert channels */
576
    ctx->channel_mix (ctx, src, outbuf, samples);
577

578
    src = outbuf;
579
580
  }

581
582
583
584
585
586
587
588
589
  /* we only need to quantize if output format is int */
  if (ctx->out.is_int) {
    if (ctx->out_default)
      outbuf = dst;
    else
      outbuf = tmpbuf;
    ctx->quantize (ctx, src, outbuf, samples);
  }

590
  if (!ctx->out_default) {
591
    /* pack default format into dst */
592
    ctx->pack (src, dst, ctx->out_scale, samples * ctx->out.channels);
593
594
595
596
  }

  return TRUE;
}