|
2313
|
1 /* Audacious
|
|
|
2 * Copyright (C) 2005-2007 Audacious team
|
|
|
3 *
|
|
|
4 * XMMS - Cross-platform multimedia player
|
|
|
5 * Copyright (C) 1998-2003 Peter Alm, Mikael Alm, Olle Hallnas,
|
|
|
6 * Thomas Nilsson and 4Front Technologies
|
|
|
7 * Copyright (C) 1999-2003 Haavard Kvaalen
|
|
|
8 *
|
|
|
9 * This program is free software; you can redistribute it and/or modify
|
|
|
10 * it under the terms of the GNU General Public License as published by
|
|
|
11 * the Free Software Foundation; under version 2 of the License.
|
|
|
12 *
|
|
|
13 * This program is distributed in the hope that it will be useful,
|
|
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
16 * GNU General Public License for more details.
|
|
|
17 *
|
|
|
18 * You should have received a copy of the GNU General Public License
|
|
|
19 * along with this program; if not, write to the Free Software
|
|
|
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
21 */
|
|
|
22
|
|
|
23 #include "config.h"
|
|
|
24 #include <stdlib.h>
|
|
|
25 #include <audacious/plugin.h>
|
|
|
26 #include "xconvert.h"
|
|
|
27
|
|
|
28 #define IS_BIG_ENDIAN (G_BYTE_ORDER==G_BIG_ENDIAN)
|
|
|
29
|
|
|
30 /**
|
|
|
31 * buffer:
|
|
|
32 *
|
|
|
33 * Contains data for conversion.
|
|
|
34 *
|
|
|
35 * @buffer: A pointer to the memory being used in the conversion process.
|
|
|
36 * @size: The size of the memory being referenced.
|
|
|
37 **/
|
|
|
38 struct buffer {
|
|
|
39 void *buffer;
|
|
|
40 int size;
|
|
|
41 };
|
|
|
42
|
|
|
43 /**
|
|
|
44 * xmms_convert_buffers:
|
|
|
45 *
|
|
|
46 * Stores data for conversion.
|
|
|
47 *
|
|
|
48 * @format_buffer: A buffer for converting formats.
|
|
|
49 * @stereo_buffer: A buffer for downmixing or upmixing.
|
|
|
50 * @freq_buffer: A buffer used for resampling.
|
|
|
51 **/
|
|
|
52 struct xmms_convert_buffers {
|
|
|
53 struct buffer format_buffer, stereo_buffer, freq_buffer;
|
|
|
54 };
|
|
|
55
|
|
|
56 /**
|
|
|
57 * xmms_convert_buffers_new:
|
|
|
58 *
|
|
|
59 * Factory for an #xmms_convert_buffers struct.
|
|
|
60 *
|
|
|
61 * Return value: An #xmms_convert_buffers struct.
|
|
|
62 **/
|
|
|
63 struct xmms_convert_buffers *
|
|
|
64 xmms_convert_buffers_new(void)
|
|
|
65 {
|
|
|
66 return g_malloc0(sizeof(struct xmms_convert_buffers));
|
|
|
67 }
|
|
|
68
|
|
|
69 /**
|
|
|
70 * convert_get_buffer:
|
|
|
71 * @buffer: A buffer to resize.
|
|
|
72 * @size: The new size for that buffer.
|
|
|
73 *
|
|
|
74 * Resizes a conversion buffer.
|
|
|
75 **/
|
|
|
76 static void *
|
|
|
77 convert_get_buffer(struct buffer *buffer, size_t size)
|
|
|
78 {
|
|
|
79 if (size > 0 && size <= (size_t)buffer->size)
|
|
|
80 return buffer->buffer;
|
|
|
81
|
|
|
82 buffer->size = size;
|
|
|
83 buffer->buffer = g_realloc(buffer->buffer, size);
|
|
|
84 return buffer->buffer;
|
|
|
85 }
|
|
|
86
|
|
|
87 /**
|
|
|
88 * xmms_convert_buffers_free:
|
|
|
89 * @buf: An xmms_convert_buffers structure to free.
|
|
|
90 *
|
|
|
91 * Frees the actual buffers contained inside the buffer struct.
|
|
|
92 **/
|
|
|
93 void
|
|
|
94 xmms_convert_buffers_free(struct xmms_convert_buffers *buf)
|
|
|
95 {
|
|
|
96 convert_get_buffer(&buf->format_buffer, 0);
|
|
|
97 convert_get_buffer(&buf->stereo_buffer, 0);
|
|
|
98 convert_get_buffer(&buf->freq_buffer, 0);
|
|
|
99 }
|
|
|
100
|
|
|
101 /**
|
|
|
102 * xmms_convert_buffers_destroy:
|
|
|
103 * @buf: An xmms_convert_buffers structure to destroy.
|
|
|
104 *
|
|
|
105 * Destroys an xmms_convert_buffers structure.
|
|
|
106 **/
|
|
|
107 void
|
|
|
108 xmms_convert_buffers_destroy(struct xmms_convert_buffers *buf)
|
|
|
109 {
|
|
|
110 if (!buf)
|
|
|
111 return;
|
|
|
112 xmms_convert_buffers_free(buf);
|
|
|
113 g_free(buf);
|
|
|
114 }
|
|
|
115
|
|
|
116 static int
|
|
|
117 convert_swap_endian(struct xmms_convert_buffers *buf, void **data, int length)
|
|
|
118 {
|
|
|
119 guint16 *ptr = *data;
|
|
|
120 int i;
|
|
|
121 for (i = 0; i < length; i += 2, ptr++)
|
|
|
122 *ptr = GUINT16_SWAP_LE_BE(*ptr);
|
|
|
123
|
|
|
124 return i;
|
|
|
125 }
|
|
|
126
|
|
|
127 static int
|
|
|
128 convert_swap_sign_and_endian_to_native(struct
|
|
|
129 xmms_convert_buffers
|
|
|
130 *buf, void **data, int length)
|
|
|
131 {
|
|
|
132 guint16 *ptr = *data;
|
|
|
133 int i;
|
|
|
134 for (i = 0; i < length; i += 2, ptr++)
|
|
|
135 *ptr = GUINT16_SWAP_LE_BE(*ptr) ^ 1 << 15;
|
|
|
136
|
|
|
137 return i;
|
|
|
138 }
|
|
|
139
|
|
|
140 static int
|
|
|
141 convert_swap_sign_and_endian_to_alien(struct
|
|
|
142 xmms_convert_buffers *buf,
|
|
|
143 void **data, int length)
|
|
|
144 {
|
|
|
145 guint16 *ptr = *data;
|
|
|
146 int i;
|
|
|
147 for (i = 0; i < length; i += 2, ptr++)
|
|
|
148 *ptr = GUINT16_SWAP_LE_BE(*ptr ^ 1 << 15);
|
|
|
149
|
|
|
150 return i;
|
|
|
151 }
|
|
|
152
|
|
|
153 static int
|
|
|
154 convert_swap_sign16(struct xmms_convert_buffers *buf, void **data, int length)
|
|
|
155 {
|
|
|
156 gint16 *ptr = *data;
|
|
|
157 int i;
|
|
|
158 for (i = 0; i < length; i += 2, ptr++)
|
|
|
159 *ptr ^= 1 << 15;
|
|
|
160
|
|
|
161 return i;
|
|
|
162 }
|
|
|
163
|
|
|
164 static int
|
|
|
165 convert_swap_sign8(struct xmms_convert_buffers *buf, void **data, int length)
|
|
|
166 {
|
|
|
167 gint8 *ptr = *data;
|
|
|
168 int i;
|
|
|
169 for (i = 0; i < length; i++)
|
|
|
170 *ptr++ ^= 1 << 7;
|
|
|
171
|
|
|
172 return i;
|
|
|
173 }
|
|
|
174
|
|
|
175 static int
|
|
|
176 convert_to_8_native_endian(struct xmms_convert_buffers *buf,
|
|
|
177 void **data, int length)
|
|
|
178 {
|
|
|
179 gint8 *output = *data;
|
|
|
180 gint16 *input = *data;
|
|
|
181 int i;
|
|
|
182 for (i = 0; i < length / 2; i++)
|
|
|
183 *output++ = *input++ >> 8;
|
|
|
184
|
|
|
185 return i;
|
|
|
186 }
|
|
|
187
|
|
|
188 static int
|
|
|
189 convert_to_8_native_endian_swap_sign(struct xmms_convert_buffers
|
|
|
190 *buf, void **data, int length)
|
|
|
191 {
|
|
|
192 gint8 *output = *data;
|
|
|
193 gint16 *input = *data;
|
|
|
194 int i;
|
|
|
195 for (i = 0; i < length / 2; i++)
|
|
|
196 *output++ = (*input++ >> 8) ^ (1 << 7);
|
|
|
197
|
|
|
198 return i;
|
|
|
199 }
|
|
|
200
|
|
|
201
|
|
|
202 static int
|
|
|
203 convert_to_8_alien_endian(struct xmms_convert_buffers *buf,
|
|
|
204 void **data, int length)
|
|
|
205 {
|
|
|
206 gint8 *output = *data;
|
|
|
207 gint16 *input = *data;
|
|
|
208 int i;
|
|
|
209 for (i = 0; i < length / 2; i++)
|
|
|
210 *output++ = *input++ & 0xff;
|
|
|
211
|
|
|
212 return i;
|
|
|
213 }
|
|
|
214
|
|
|
215 static int
|
|
|
216 convert_to_8_alien_endian_swap_sign(struct xmms_convert_buffers
|
|
|
217 *buf, void **data, int length)
|
|
|
218 {
|
|
|
219 gint8 *output = *data;
|
|
|
220 gint16 *input = *data;
|
|
|
221 int i;
|
|
|
222 for (i = 0; i < length / 2; i++)
|
|
|
223 *output++ = (*input++ & 0xff) ^ (1 << 7);
|
|
|
224
|
|
|
225 return i;
|
|
|
226 }
|
|
|
227
|
|
|
228 static int
|
|
|
229 convert_to_16_native_endian(struct xmms_convert_buffers *buf,
|
|
|
230 void **data, int length)
|
|
|
231 {
|
|
|
232 guint8 *input = *data;
|
|
|
233 guint16 *output;
|
|
|
234 int i;
|
|
|
235 *data = convert_get_buffer(&buf->format_buffer, length * 2);
|
|
|
236 output = *data;
|
|
|
237 for (i = 0; i < length; i++)
|
|
|
238 *output++ = *input++ << 8;
|
|
|
239
|
|
|
240 return i * 2;
|
|
|
241 }
|
|
|
242
|
|
|
243 static int
|
|
|
244 convert_to_16_native_endian_swap_sign(struct
|
|
|
245 xmms_convert_buffers *buf,
|
|
|
246 void **data, int length)
|
|
|
247 {
|
|
|
248 guint8 *input = *data;
|
|
|
249 guint16 *output;
|
|
|
250 int i;
|
|
|
251 *data = convert_get_buffer(&buf->format_buffer, length * 2);
|
|
|
252 output = *data;
|
|
|
253 for (i = 0; i < length; i++)
|
|
|
254 *output++ = (*input++ << 8) ^ (1 << 15);
|
|
|
255
|
|
|
256 return i * 2;
|
|
|
257 }
|
|
|
258
|
|
|
259
|
|
|
260 static int
|
|
|
261 convert_to_16_alien_endian(struct xmms_convert_buffers *buf,
|
|
|
262 void **data, int length)
|
|
|
263 {
|
|
|
264 guint8 *input = *data;
|
|
|
265 guint16 *output;
|
|
|
266 int i;
|
|
|
267 *data = convert_get_buffer(&buf->format_buffer, length * 2);
|
|
|
268 output = *data;
|
|
|
269 for (i = 0; i < length; i++)
|
|
|
270 *output++ = *input++;
|
|
|
271
|
|
|
272 return i * 2;
|
|
|
273 }
|
|
|
274
|
|
|
275 static int
|
|
|
276 convert_to_16_alien_endian_swap_sign(struct xmms_convert_buffers
|
|
|
277 *buf, void **data, int length)
|
|
|
278 {
|
|
|
279 guint8 *input = *data;
|
|
|
280 guint16 *output;
|
|
|
281 int i;
|
|
|
282 *data = convert_get_buffer(&buf->format_buffer, length * 2);
|
|
|
283 output = *data;
|
|
|
284 for (i = 0; i < length; i++)
|
|
|
285 *output++ = *input++ ^ (1 << 7);
|
|
|
286
|
|
|
287 return i * 2;
|
|
|
288 }
|
|
|
289
|
|
|
290 static AFormat
|
|
|
291 unnativize(AFormat fmt)
|
|
|
292 {
|
|
|
293 if (fmt == FMT_S16_NE) {
|
|
|
294 if (IS_BIG_ENDIAN)
|
|
|
295 return FMT_S16_BE;
|
|
|
296 else
|
|
|
297 return FMT_S16_LE;
|
|
|
298 }
|
|
|
299 if (fmt == FMT_U16_NE) {
|
|
|
300 if (IS_BIG_ENDIAN)
|
|
|
301 return FMT_U16_BE;
|
|
|
302 else
|
|
|
303 return FMT_U16_LE;
|
|
|
304 }
|
|
|
305 return fmt;
|
|
|
306 }
|
|
|
307
|
|
|
308 /**
|
|
|
309 * xmms_convert_get_func:
|
|
|
310 * @output: A format to output data as.
|
|
|
311 * @input: The format of the inbound data.
|
|
|
312 *
|
|
|
313 * Looks up the proper conversion method to use.
|
|
|
314 *
|
|
|
315 * Return value: A function pointer to the desired conversion function.
|
|
|
316 **/
|
|
|
317 convert_func_t
|
|
|
318 xmms_convert_get_func(AFormat output, AFormat input)
|
|
|
319 {
|
|
|
320 output = unnativize(output);
|
|
|
321 input = unnativize(input);
|
|
|
322
|
|
|
323 if (output == input)
|
|
|
324 return NULL;
|
|
|
325
|
|
|
326 if ((output == FMT_U16_BE && input == FMT_U16_LE) ||
|
|
|
327 (output == FMT_U16_LE && input == FMT_U16_BE) ||
|
|
|
328 (output == FMT_S16_BE && input == FMT_S16_LE) ||
|
|
|
329 (output == FMT_S16_LE && input == FMT_S16_BE))
|
|
|
330 return convert_swap_endian;
|
|
|
331
|
|
|
332 if ((output == FMT_U16_BE && input == FMT_S16_BE) ||
|
|
|
333 (output == FMT_U16_LE && input == FMT_S16_LE) ||
|
|
|
334 (output == FMT_S16_BE && input == FMT_U16_BE) ||
|
|
|
335 (output == FMT_S16_LE && input == FMT_U16_LE))
|
|
|
336 return convert_swap_sign16;
|
|
|
337
|
|
|
338 if ((IS_BIG_ENDIAN &&
|
|
|
339 ((output == FMT_U16_BE && input == FMT_S16_LE) ||
|
|
|
340 (output == FMT_S16_BE && input == FMT_U16_LE))) ||
|
|
|
341 (!IS_BIG_ENDIAN &&
|
|
|
342 ((output == FMT_U16_LE && input == FMT_S16_BE) ||
|
|
|
343 (output == FMT_S16_LE && input == FMT_U16_BE))))
|
|
|
344 return convert_swap_sign_and_endian_to_native;
|
|
|
345
|
|
|
346 if ((!IS_BIG_ENDIAN &&
|
|
|
347 ((output == FMT_U16_BE && input == FMT_S16_LE) ||
|
|
|
348 (output == FMT_S16_BE && input == FMT_U16_LE))) ||
|
|
|
349 (IS_BIG_ENDIAN &&
|
|
|
350 ((output == FMT_U16_LE && input == FMT_S16_BE) ||
|
|
|
351 (output == FMT_S16_LE && input == FMT_U16_BE))))
|
|
|
352 return convert_swap_sign_and_endian_to_alien;
|
|
|
353
|
|
|
354 if ((IS_BIG_ENDIAN &&
|
|
|
355 ((output == FMT_U8 && input == FMT_U16_BE) ||
|
|
|
356 (output == FMT_S8 && input == FMT_S16_BE))) ||
|
|
|
357 (!IS_BIG_ENDIAN &&
|
|
|
358 ((output == FMT_U8 && input == FMT_U16_LE) ||
|
|
|
359 (output == FMT_S8 && input == FMT_S16_LE))))
|
|
|
360 return convert_to_8_native_endian;
|
|
|
361
|
|
|
362 if ((IS_BIG_ENDIAN &&
|
|
|
363 ((output == FMT_U8 && input == FMT_S16_BE) ||
|
|
|
364 (output == FMT_S8 && input == FMT_U16_BE))) ||
|
|
|
365 (!IS_BIG_ENDIAN &&
|
|
|
366 ((output == FMT_U8 && input == FMT_S16_LE) ||
|
|
|
367 (output == FMT_S8 && input == FMT_U16_LE))))
|
|
|
368 return convert_to_8_native_endian_swap_sign;
|
|
|
369
|
|
|
370 if ((!IS_BIG_ENDIAN &&
|
|
|
371 ((output == FMT_U8 && input == FMT_U16_BE) ||
|
|
|
372 (output == FMT_S8 && input == FMT_S16_BE))) ||
|
|
|
373 (IS_BIG_ENDIAN &&
|
|
|
374 ((output == FMT_U8 && input == FMT_U16_LE) ||
|
|
|
375 (output == FMT_S8 && input == FMT_S16_LE))))
|
|
|
376 return convert_to_8_alien_endian;
|
|
|
377
|
|
|
378 if ((!IS_BIG_ENDIAN &&
|
|
|
379 ((output == FMT_U8 && input == FMT_S16_BE) ||
|
|
|
380 (output == FMT_S8 && input == FMT_U16_BE))) ||
|
|
|
381 (IS_BIG_ENDIAN &&
|
|
|
382 ((output == FMT_U8 && input == FMT_S16_LE) ||
|
|
|
383 (output == FMT_S8 && input == FMT_U16_LE))))
|
|
|
384 return convert_to_8_alien_endian_swap_sign;
|
|
|
385
|
|
|
386 if ((output == FMT_U8 && input == FMT_S8) ||
|
|
|
387 (output == FMT_S8 && input == FMT_U8))
|
|
|
388 return convert_swap_sign8;
|
|
|
389
|
|
|
390 if ((IS_BIG_ENDIAN &&
|
|
|
391 ((output == FMT_U16_BE && input == FMT_U8) ||
|
|
|
392 (output == FMT_S16_BE && input == FMT_S8))) ||
|
|
|
393 (!IS_BIG_ENDIAN &&
|
|
|
394 ((output == FMT_U16_LE && input == FMT_U8) ||
|
|
|
395 (output == FMT_S16_LE && input == FMT_S8))))
|
|
|
396 return convert_to_16_native_endian;
|
|
|
397
|
|
|
398 if ((IS_BIG_ENDIAN &&
|
|
|
399 ((output == FMT_U16_BE && input == FMT_S8) ||
|
|
|
400 (output == FMT_S16_BE && input == FMT_U8))) ||
|
|
|
401 (!IS_BIG_ENDIAN &&
|
|
|
402 ((output == FMT_U16_LE && input == FMT_S8) ||
|
|
|
403 (output == FMT_S16_LE && input == FMT_U8))))
|
|
|
404 return convert_to_16_native_endian_swap_sign;
|
|
|
405
|
|
|
406 if ((!IS_BIG_ENDIAN &&
|
|
|
407 ((output == FMT_U16_BE && input == FMT_U8) ||
|
|
|
408 (output == FMT_S16_BE && input == FMT_S8))) ||
|
|
|
409 (IS_BIG_ENDIAN &&
|
|
|
410 ((output == FMT_U16_LE && input == FMT_U8) ||
|
|
|
411 (output == FMT_S16_LE && input == FMT_S8))))
|
|
|
412 return convert_to_16_alien_endian;
|
|
|
413
|
|
|
414 if ((!IS_BIG_ENDIAN &&
|
|
|
415 ((output == FMT_U16_BE && input == FMT_S8) ||
|
|
|
416 (output == FMT_S16_BE && input == FMT_U8))) ||
|
|
|
417 (IS_BIG_ENDIAN &&
|
|
|
418 ((output == FMT_U16_LE && input == FMT_S8) ||
|
|
|
419 (output == FMT_S16_LE && input == FMT_U8))))
|
|
|
420 return convert_to_16_alien_endian_swap_sign;
|
|
|
421
|
|
|
422 g_warning("Translation needed, but not available.\n"
|
|
|
423 "Input: %d; Output %d.", input, output);
|
|
|
424 return NULL;
|
|
|
425 }
|
|
|
426
|
|
|
427 static int
|
|
|
428 convert_mono_to_stereo(struct xmms_convert_buffers *buf,
|
|
|
429 void **data, int length, int b16)
|
|
|
430 {
|
|
|
431 int i;
|
|
|
432 void *outbuf = convert_get_buffer(&buf->stereo_buffer, length * 2);
|
|
|
433
|
|
|
434 if (b16) {
|
|
|
435 guint16 *output = outbuf, *input = *data;
|
|
|
436 for (i = 0; i < length / 2; i++) {
|
|
|
437 *output++ = *input;
|
|
|
438 *output++ = *input;
|
|
|
439 input++;
|
|
|
440 }
|
|
|
441 }
|
|
|
442 else {
|
|
|
443 guint8 *output = outbuf, *input = *data;
|
|
|
444 for (i = 0; i < length; i++) {
|
|
|
445 *output++ = *input;
|
|
|
446 *output++ = *input;
|
|
|
447 input++;
|
|
|
448 }
|
|
|
449 }
|
|
|
450 *data = outbuf;
|
|
|
451
|
|
|
452 return length * 2;
|
|
|
453 }
|
|
|
454
|
|
|
455 static int
|
|
|
456 convert_mono_to_stereo_8(struct xmms_convert_buffers *buf,
|
|
|
457 void **data, int length)
|
|
|
458 {
|
|
|
459 return convert_mono_to_stereo(buf, data, length, FALSE);
|
|
|
460 }
|
|
|
461
|
|
|
462 static int
|
|
|
463 convert_mono_to_stereo_16(struct xmms_convert_buffers *buf,
|
|
|
464 void **data, int length)
|
|
|
465 {
|
|
|
466 return convert_mono_to_stereo(buf, data, length, TRUE);
|
|
|
467 }
|
|
|
468
|
|
|
469 static int
|
|
|
470 convert_stereo_to_mono_u8(struct xmms_convert_buffers *buf,
|
|
|
471 void **data, int length)
|
|
|
472 {
|
|
|
473 guint8 *output = *data, *input = *data;
|
|
|
474 int i;
|
|
|
475 for (i = 0; i < length / 2; i++) {
|
|
|
476 guint16 tmp;
|
|
|
477 tmp = *input++;
|
|
|
478 tmp += *input++;
|
|
|
479 *output++ = tmp / 2;
|
|
|
480 }
|
|
|
481 return length / 2;
|
|
|
482 }
|
|
|
483 static int
|
|
|
484 convert_stereo_to_mono_s8(struct xmms_convert_buffers *buf,
|
|
|
485 void **data, int length)
|
|
|
486 {
|
|
|
487 gint8 *output = *data, *input = *data;
|
|
|
488 int i;
|
|
|
489 for (i = 0; i < length / 2; i++) {
|
|
|
490 gint16 tmp;
|
|
|
491 tmp = *input++;
|
|
|
492 tmp += *input++;
|
|
|
493 *output++ = tmp / 2;
|
|
|
494 }
|
|
|
495 return length / 2;
|
|
|
496 }
|
|
|
497 static int
|
|
|
498 convert_stereo_to_mono_u16le(struct xmms_convert_buffers *buf,
|
|
|
499 void **data, int length)
|
|
|
500 {
|
|
|
501 guint16 *output = *data, *input = *data;
|
|
|
502 int i;
|
|
|
503 for (i = 0; i < length / 4; i++) {
|
|
|
504 guint32 tmp;
|
|
|
505 guint16 stmp;
|
|
|
506 tmp = GUINT16_FROM_LE(*input);
|
|
|
507 input++;
|
|
|
508 tmp += GUINT16_FROM_LE(*input);
|
|
|
509 input++;
|
|
|
510 stmp = tmp / 2;
|
|
|
511 *output++ = GUINT16_TO_LE(stmp);
|
|
|
512 }
|
|
|
513 return length / 2;
|
|
|
514 }
|
|
|
515
|
|
|
516 static int
|
|
|
517 convert_stereo_to_mono_u16be(struct xmms_convert_buffers *buf,
|
|
|
518 void **data, int length)
|
|
|
519 {
|
|
|
520 guint16 *output = *data, *input = *data;
|
|
|
521 int i;
|
|
|
522 for (i = 0; i < length / 4; i++) {
|
|
|
523 guint32 tmp;
|
|
|
524 guint16 stmp;
|
|
|
525 tmp = GUINT16_FROM_BE(*input);
|
|
|
526 input++;
|
|
|
527 tmp += GUINT16_FROM_BE(*input);
|
|
|
528 input++;
|
|
|
529 stmp = tmp / 2;
|
|
|
530 *output++ = GUINT16_TO_BE(stmp);
|
|
|
531 }
|
|
|
532 return length / 2;
|
|
|
533 }
|
|
|
534
|
|
|
535 static int
|
|
|
536 convert_stereo_to_mono_s16le(struct xmms_convert_buffers *buf,
|
|
|
537 void **data, int length)
|
|
|
538 {
|
|
|
539 gint16 *output = *data, *input = *data;
|
|
|
540 int i;
|
|
|
541 for (i = 0; i < length / 4; i++) {
|
|
|
542 gint32 tmp;
|
|
|
543 gint16 stmp;
|
|
|
544 tmp = GINT16_FROM_LE(*input);
|
|
|
545 input++;
|
|
|
546 tmp += GINT16_FROM_LE(*input);
|
|
|
547 input++;
|
|
|
548 stmp = tmp / 2;
|
|
|
549 *output++ = GINT16_TO_LE(stmp);
|
|
|
550 }
|
|
|
551 return length / 2;
|
|
|
552 }
|
|
|
553
|
|
|
554 static int
|
|
|
555 convert_stereo_to_mono_s16be(struct xmms_convert_buffers *buf,
|
|
|
556 void **data, int length)
|
|
|
557 {
|
|
|
558 gint16 *output = *data, *input = *data;
|
|
|
559 int i;
|
|
|
560 for (i = 0; i < length / 4; i++) {
|
|
|
561 gint32 tmp;
|
|
|
562 gint16 stmp;
|
|
|
563 tmp = GINT16_FROM_BE(*input);
|
|
|
564 input++;
|
|
|
565 tmp += GINT16_FROM_BE(*input);
|
|
|
566 input++;
|
|
|
567 stmp = tmp / 2;
|
|
|
568 *output++ = GINT16_TO_BE(stmp);
|
|
|
569 }
|
|
|
570 return length / 2;
|
|
|
571 }
|
|
|
572
|
|
|
573 /**
|
|
|
574 * xmms_convert_get_channel_func:
|
|
|
575 * @fmt: The format of the data.
|
|
|
576 * @output: The number of channels to output as.
|
|
|
577 * @input: The number of channels inbound.
|
|
|
578 *
|
|
|
579 * Looks up the proper conversion method to use.
|
|
|
580 *
|
|
|
581 * Return value: A function pointer to the desired conversion function.
|
|
|
582 **/
|
|
|
583 convert_channel_func_t
|
|
|
584 xmms_convert_get_channel_func(AFormat fmt, int output, int input)
|
|
|
585 {
|
|
|
586 fmt = unnativize(fmt);
|
|
|
587
|
|
|
588 if (output == input)
|
|
|
589 return NULL;
|
|
|
590
|
|
|
591 if (input == 1 && output == 2)
|
|
|
592 switch (fmt) {
|
|
|
593 case FMT_U8:
|
|
|
594 case FMT_S8:
|
|
|
595 return convert_mono_to_stereo_8;
|
|
|
596 case FMT_U16_LE:
|
|
|
597 case FMT_U16_BE:
|
|
|
598 case FMT_S16_LE:
|
|
|
599 case FMT_S16_BE:
|
|
|
600 return convert_mono_to_stereo_16;
|
|
|
601 default:
|
|
|
602 g_warning("Unknown format: %d" "No conversion available.", fmt);
|
|
|
603 return NULL;
|
|
|
604 }
|
|
|
605 if (input == 2 && output == 1)
|
|
|
606 switch (fmt) {
|
|
|
607 case FMT_U8:
|
|
|
608 return convert_stereo_to_mono_u8;
|
|
|
609 case FMT_S8:
|
|
|
610 return convert_stereo_to_mono_s8;
|
|
|
611 case FMT_U16_LE:
|
|
|
612 return convert_stereo_to_mono_u16le;
|
|
|
613 case FMT_U16_BE:
|
|
|
614 return convert_stereo_to_mono_u16be;
|
|
|
615 case FMT_S16_LE:
|
|
|
616 return convert_stereo_to_mono_s16le;
|
|
|
617 case FMT_S16_BE:
|
|
|
618 return convert_stereo_to_mono_s16be;
|
|
|
619 default:
|
|
|
620 g_warning("Unknown format: %d. "
|
|
|
621 "No conversion available.", fmt);
|
|
|
622 return NULL;
|
|
|
623
|
|
|
624 }
|
|
|
625
|
|
|
626 g_warning("Input has %d channels, soundcard uses %d channels\n"
|
|
|
627 "No conversion is available", input, output);
|
|
|
628 return NULL;
|
|
|
629 }
|
|
|
630
|
|
|
631
|
|
|
632 #define RESAMPLE_STEREO(sample_type, bswap) \
|
|
|
633 const int shift = sizeof (sample_type); \
|
|
|
634 int i, in_samples, out_samples, x, delta; \
|
|
|
635 sample_type *inptr = *data, *outptr; \
|
|
|
636 guint nlen = (((length >> shift) * ofreq) / ifreq); \
|
|
|
637 void *nbuf; \
|
|
|
638 if (nlen == 0) \
|
|
|
639 return 0; \
|
|
|
640 nlen <<= shift; \
|
|
|
641 if (bswap) \
|
|
|
642 convert_swap_endian(NULL, data, length); \
|
|
|
643 nbuf = convert_get_buffer(&buf->freq_buffer, nlen); \
|
|
|
644 outptr = nbuf; \
|
|
|
645 in_samples = length >> shift; \
|
|
|
646 out_samples = nlen >> shift; \
|
|
|
647 delta = (in_samples << 12) / out_samples; \
|
|
|
648 for (x = 0, i = 0; i < out_samples; i++) \
|
|
|
649 { \
|
|
|
650 int x1, frac; \
|
|
|
651 x1 = (x >> 12) << 12; \
|
|
|
652 frac = x - x1; \
|
|
|
653 *outptr++ = \
|
|
|
654 ((inptr[(x1 >> 12) << 1] * \
|
|
|
655 ((1<<12) - frac) + \
|
|
|
656 inptr[((x1 >> 12) + 1) << 1] * \
|
|
|
657 frac) >> 12); \
|
|
|
658 *outptr++ = \
|
|
|
659 ((inptr[((x1 >> 12) << 1) + 1] * \
|
|
|
660 ((1<<12) - frac) + \
|
|
|
661 inptr[(((x1 >> 12) + 1) << 1) + 1] * \
|
|
|
662 frac) >> 12); \
|
|
|
663 x += delta; \
|
|
|
664 } \
|
|
|
665 if (bswap) \
|
|
|
666 convert_swap_endian(NULL, &nbuf, nlen); \
|
|
|
667 *data = nbuf; \
|
|
|
668 return nlen; \
|
|
|
669
|
|
|
670
|
|
|
671 #define RESAMPLE_MONO(sample_type, bswap) \
|
|
|
672 const int shift = sizeof (sample_type) - 1; \
|
|
|
673 int i, x, delta, in_samples, out_samples; \
|
|
|
674 sample_type *inptr = *data, *outptr; \
|
|
|
675 guint nlen = (((length >> shift) * ofreq) / ifreq); \
|
|
|
676 void *nbuf; \
|
|
|
677 if (nlen == 0) \
|
|
|
678 return 0; \
|
|
|
679 nlen <<= shift; \
|
|
|
680 if (bswap) \
|
|
|
681 convert_swap_endian(NULL, data, length); \
|
|
|
682 nbuf = convert_get_buffer(&buf->freq_buffer, nlen); \
|
|
|
683 outptr = nbuf; \
|
|
|
684 in_samples = length >> shift; \
|
|
|
685 out_samples = nlen >> shift; \
|
|
|
686 delta = ((length >> shift) << 12) / out_samples; \
|
|
|
687 for (x = 0, i = 0; i < out_samples; i++) \
|
|
|
688 { \
|
|
|
689 int x1, frac; \
|
|
|
690 x1 = (x >> 12) << 12; \
|
|
|
691 frac = x - x1; \
|
|
|
692 *outptr++ = \
|
|
|
693 ((inptr[x1 >> 12] * ((1<<12) - frac) + \
|
|
|
694 inptr[(x1 >> 12) + 1] * frac) >> 12); \
|
|
|
695 x += delta; \
|
|
|
696 } \
|
|
|
697 if (bswap) \
|
|
|
698 convert_swap_endian(NULL, &nbuf, nlen); \
|
|
|
699 *data = nbuf; \
|
|
|
700 return nlen; \
|
|
|
701
|
|
|
702 static int
|
|
|
703 convert_resample_stereo_s16ne(struct xmms_convert_buffers *buf,
|
|
|
704 void **data, int length, int ifreq, int ofreq)
|
|
|
705 {
|
|
|
706 RESAMPLE_STEREO(gint16, FALSE);
|
|
|
707 }
|
|
|
708
|
|
|
709 static int
|
|
|
710 convert_resample_stereo_s16ae(struct xmms_convert_buffers *buf,
|
|
|
711 void **data, int length, int ifreq, int ofreq)
|
|
|
712 {
|
|
|
713 RESAMPLE_STEREO(gint16, TRUE);
|
|
|
714 }
|
|
|
715
|
|
|
716 static int
|
|
|
717 convert_resample_stereo_u16ne(struct xmms_convert_buffers *buf,
|
|
|
718 void **data, int length, int ifreq, int ofreq)
|
|
|
719 {
|
|
|
720 RESAMPLE_STEREO(guint16, FALSE);
|
|
|
721 }
|
|
|
722
|
|
|
723 static int
|
|
|
724 convert_resample_stereo_u16ae(struct xmms_convert_buffers *buf,
|
|
|
725 void **data, int length, int ifreq, int ofreq)
|
|
|
726 {
|
|
|
727 RESAMPLE_STEREO(guint16, TRUE);
|
|
|
728 }
|
|
|
729
|
|
|
730 static int
|
|
|
731 convert_resample_mono_s16ne(struct xmms_convert_buffers *buf,
|
|
|
732 void **data, int length, int ifreq, int ofreq)
|
|
|
733 {
|
|
|
734 RESAMPLE_MONO(gint16, FALSE);
|
|
|
735 }
|
|
|
736
|
|
|
737 static int
|
|
|
738 convert_resample_mono_s16ae(struct xmms_convert_buffers *buf,
|
|
|
739 void **data, int length, int ifreq, int ofreq)
|
|
|
740 {
|
|
|
741 RESAMPLE_MONO(gint16, TRUE);
|
|
|
742 }
|
|
|
743
|
|
|
744 static int
|
|
|
745 convert_resample_mono_u16ne(struct xmms_convert_buffers *buf,
|
|
|
746 void **data, int length, int ifreq, int ofreq)
|
|
|
747 {
|
|
|
748 RESAMPLE_MONO(guint16, FALSE);
|
|
|
749 }
|
|
|
750
|
|
|
751 static int
|
|
|
752 convert_resample_mono_u16ae(struct xmms_convert_buffers *buf,
|
|
|
753 void **data, int length, int ifreq, int ofreq)
|
|
|
754 {
|
|
|
755 RESAMPLE_MONO(guint16, TRUE);
|
|
|
756 }
|
|
|
757
|
|
|
758 static int
|
|
|
759 convert_resample_stereo_u8(struct xmms_convert_buffers *buf,
|
|
|
760 void **data, int length, int ifreq, int ofreq)
|
|
|
761 {
|
|
|
762 RESAMPLE_STEREO(guint8, FALSE);
|
|
|
763 }
|
|
|
764
|
|
|
765 static int
|
|
|
766 convert_resample_mono_u8(struct xmms_convert_buffers *buf,
|
|
|
767 void **data, int length, int ifreq, int ofreq)
|
|
|
768 {
|
|
|
769 RESAMPLE_MONO(guint8, FALSE);
|
|
|
770 }
|
|
|
771
|
|
|
772 static int
|
|
|
773 convert_resample_stereo_s8(struct xmms_convert_buffers *buf,
|
|
|
774 void **data, int length, int ifreq, int ofreq)
|
|
|
775 {
|
|
|
776 RESAMPLE_STEREO(gint8, FALSE);
|
|
|
777 }
|
|
|
778
|
|
|
779 static int
|
|
|
780 convert_resample_mono_s8(struct xmms_convert_buffers *buf,
|
|
|
781 void **data, int length, int ifreq, int ofreq)
|
|
|
782 {
|
|
|
783 RESAMPLE_MONO(gint8, FALSE);
|
|
|
784 }
|
|
|
785
|
|
|
786
|
|
|
787 /**
|
|
|
788 * xmms_convert_get_frequency_func:
|
|
|
789 * @fmt: The format of the data.
|
|
|
790 * @channels: The number of channels inbound.
|
|
|
791 *
|
|
|
792 * Looks up the proper conversion method to use.
|
|
|
793 *
|
|
|
794 * Return value: A function pointer to the desired conversion function.
|
|
|
795 **/
|
|
|
796 convert_freq_func_t
|
|
|
797 xmms_convert_get_frequency_func(AFormat fmt, int channels)
|
|
|
798 {
|
|
|
799 fmt = unnativize(fmt);
|
|
|
800 g_message("fmt %d, channels: %d", fmt, channels);
|
|
|
801
|
|
|
802 if (channels < 1 || channels > 2) {
|
|
|
803 g_warning("Unsupported number of channels: %d. "
|
|
|
804 "Resample function not available", channels);
|
|
|
805 return NULL;
|
|
|
806 }
|
|
|
807 if ((IS_BIG_ENDIAN && fmt == FMT_U16_BE) ||
|
|
|
808 (!IS_BIG_ENDIAN && fmt == FMT_U16_LE)) {
|
|
|
809 if (channels == 1)
|
|
|
810 return convert_resample_mono_u16ne;
|
|
|
811 else
|
|
|
812 return convert_resample_stereo_u16ne;
|
|
|
813 }
|
|
|
814 if ((IS_BIG_ENDIAN && fmt == FMT_S16_BE) ||
|
|
|
815 (!IS_BIG_ENDIAN && fmt == FMT_S16_LE)) {
|
|
|
816 if (channels == 1)
|
|
|
817 return convert_resample_mono_s16ne;
|
|
|
818 else
|
|
|
819 return convert_resample_stereo_s16ne;
|
|
|
820 }
|
|
|
821 if ((!IS_BIG_ENDIAN && fmt == FMT_U16_BE) ||
|
|
|
822 (IS_BIG_ENDIAN && fmt == FMT_U16_LE)) {
|
|
|
823 if (channels == 1)
|
|
|
824 return convert_resample_mono_u16ae;
|
|
|
825 else
|
|
|
826 return convert_resample_stereo_u16ae;
|
|
|
827 }
|
|
|
828 if ((!IS_BIG_ENDIAN && fmt == FMT_S16_BE) ||
|
|
|
829 (IS_BIG_ENDIAN && fmt == FMT_S16_LE)) {
|
|
|
830 if (channels == 1)
|
|
|
831 return convert_resample_mono_s16ae;
|
|
|
832 else
|
|
|
833 return convert_resample_stereo_s16ae;
|
|
|
834 }
|
|
|
835 if (fmt == FMT_U8) {
|
|
|
836 if (channels == 1)
|
|
|
837 return convert_resample_mono_u8;
|
|
|
838 else
|
|
|
839 return convert_resample_stereo_u8;
|
|
|
840 }
|
|
|
841 if (fmt == FMT_S8) {
|
|
|
842 if (channels == 1)
|
|
|
843 return convert_resample_mono_s8;
|
|
|
844 else
|
|
|
845 return convert_resample_stereo_s8;
|
|
|
846 }
|
|
|
847 g_warning("Resample function not available" "Format %d.", fmt);
|
|
|
848 return NULL;
|
|
|
849 }
|