Mercurial > audlegacy
annotate libaudacious/xconvert.c @ 2132:aec6570f056f trunk
[svn] - run update-po
- update welsh translation (419 messages translated, 100% translation coverage)
author | nenolod |
---|---|
date | Fri, 15 Dec 2006 18:11:42 -0800 |
parents | f18a5b617c34 |
children |
rev | line source |
---|---|
2056 | 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 | |
0 | 8 * |
2056 | 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 | |
2105
f18a5b617c34
[svn] - move to GPLv2-only. Based on my interpretation of the license, we are
nenolod
parents:
2060
diff
changeset
|
11 * the Free Software Foundation; under version 2 of the License. |
2056 | 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. | |
0 | 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 | |
2060 | 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 **/ | |
0 | 38 struct buffer { |
39 void *buffer; | |
40 int size; | |
41 }; | |
42 | |
2060 | 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 **/ | |
0 | 52 struct xmms_convert_buffers { |
53 struct buffer format_buffer, stereo_buffer, freq_buffer; | |
54 }; | |
55 | |
2056 | 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 **/ | |
0 | 63 struct xmms_convert_buffers * |
64 xmms_convert_buffers_new(void) | |
65 { | |
66 return g_malloc0(sizeof(struct xmms_convert_buffers)); | |
67 } | |
68 | |
2056 | 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 **/ | |
0 | 76 static void * |
77 convert_get_buffer(struct buffer *buffer, size_t size) | |
78 { | |
625
0a73d1faeb4e
[svn] GCC 4.1 warning fixes by Diego 'Flameeyes' Petteno from Gentoo.
chainsaw
parents:
0
diff
changeset
|
79 if (size > 0 && size <= (size_t)buffer->size) |
0 | 80 return buffer->buffer; |
81 | |
82 buffer->size = size; | |
83 buffer->buffer = g_realloc(buffer->buffer, size); | |
84 return buffer->buffer; | |
85 } | |
86 | |
2056 | 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 **/ | |
0 | 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 | |
2056 | 101 /** |
102 * xmms_convert_buffers_destroy: | |
103 * @buf: An xmms_convert_buffers structure to destroy. | |
104 * | |
105 * Destroys an xmms_convert_buffers structure. | |
106 **/ | |
0 | 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 | |
2056 | 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 **/ | |
0 | 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 | |
2056 | 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 **/ | |
0 | 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 | |
2056 | 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 **/ | |
0 | 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 } |