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