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