]> git.sesse.net Git - vlc/blob - modules/audio_filter/format.c
55b5fd0f5bd7996b35410482c4c8ca70901ed9a8
[vlc] / modules / audio_filter / format.c
1 /*****************************************************************************
2  * format.c : PCM format converter
3  *****************************************************************************
4  * Copyright (C) 2002-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc/vlc.h>
34 #include <vlc_plugin.h>
35 #include <vlc_aout.h>
36 #include <vlc_block.h>
37 #include "vlc_filter.h"
38
39 #ifdef WORDS_BIGENDIAN
40 #   define AOUT_FMT_S24_IE VLC_FOURCC('s','2','4','l')
41 #   define AOUT_FMT_S16_IE VLC_FOURCC('s','1','6','l')
42 #   define AOUT_FMT_U16_IE VLC_FOURCC('u','1','6','l')
43 #else
44 #   define AOUT_FMT_S24_IE VLC_FOURCC('s','2','4','b')
45 #   define AOUT_FMT_S16_IE VLC_FOURCC('s','1','6','b')
46 #   define AOUT_FMT_U16_IE VLC_FOURCC('u','1','6','b')
47 #endif
48
49
50 /*****************************************************************************
51  * Local prototypes
52  *****************************************************************************/
53 static int  Open ( vlc_object_t * );
54
55 static block_t *Float32toS24( filter_t *, block_t * );
56 static block_t *Float32toS16( filter_t *, block_t * );
57 static block_t *Float32toU16( filter_t *, block_t * );
58 static block_t *Float32toS8 ( filter_t *, block_t * );
59 static block_t *Float32toU8 ( filter_t *, block_t * );
60
61 static block_t *S24toFloat32  ( filter_t *, block_t * );
62 static block_t *S24toS16      ( filter_t *, block_t * );
63 static block_t *S24toS16Invert( filter_t *, block_t * );
64
65 static block_t *S16toFloat32  ( filter_t *, block_t * );
66 static block_t *S16toS24      ( filter_t *, block_t * );
67 static block_t *S16toS24Invert( filter_t *, block_t * );
68 static block_t *S16toS8       ( filter_t *, block_t * );
69 static block_t *S16toU8       ( filter_t *, block_t * );
70 static block_t *S16toU16      ( filter_t *, block_t * );
71
72 static block_t *U16toFloat32( filter_t *, block_t * );
73 static block_t *U16toS8     ( filter_t *, block_t * );
74 static block_t *U16toU8     ( filter_t *, block_t * );
75 static block_t *U16toS16    ( filter_t *, block_t * );
76
77 static block_t *Float32toS24Invert( filter_t *, block_t * );
78 static block_t *Float32toS16Invert( filter_t *, block_t * );
79 static block_t *Float32toU16Invert( filter_t *, block_t * );
80
81 static block_t *S24InverttoFloat32  ( filter_t *, block_t * );
82 static block_t *S24InverttoS16      ( filter_t *, block_t * );
83 static block_t *S24InverttoS16Invert( filter_t *, block_t * );
84
85 static block_t *S16InverttoFloat32  ( filter_t *, block_t * );
86 static block_t *S16InverttoS24      ( filter_t *, block_t * );
87 static block_t *S16InverttoS24Invert( filter_t *, block_t * );
88 static block_t *S16InverttoS8       ( filter_t *, block_t * );
89 static block_t *S16InverttoU8       ( filter_t *, block_t * );
90 static block_t *S16InverttoU16      ( filter_t *, block_t * );
91
92 static block_t *U16InverttoFloat32( filter_t *, block_t * );
93 static block_t *U16InverttoS8     ( filter_t *, block_t * );
94 static block_t *U16InverttoU8     ( filter_t *, block_t * );
95 static block_t *U16InverttoS16    ( filter_t *, block_t * );
96
97 static block_t *S8toFloat32  ( filter_t *, block_t * );
98 static block_t *S8toS16      ( filter_t *, block_t * );
99 static block_t *S8toU16      ( filter_t *, block_t * );
100 static block_t *S8toU8       ( filter_t *, block_t * );
101 static block_t *S8toS16Invert( filter_t *, block_t * );
102 static block_t *S8toU16Invert( filter_t *, block_t * );
103
104 static block_t *U8toFloat32  ( filter_t *, block_t * );
105 static block_t *U8toFloat32  ( filter_t *, block_t * );
106 static block_t *U8toS16      ( filter_t *, block_t * );
107 static block_t *U8toU16      ( filter_t *, block_t * );
108 static block_t *U8toS8       ( filter_t *, block_t * );
109 static block_t *U8toS16Invert( filter_t *, block_t * );
110 static block_t *U8toU16Invert( filter_t *, block_t * );
111
112
113 static block_t *U8toS8( filter_t *, block_t * );
114 static block_t *S8toU8( filter_t *, block_t * );
115
116
117 static block_t *Swap16( filter_t *, block_t * );
118 static block_t *Swap24( filter_t *, block_t * );
119
120 static struct
121 {
122     vlc_fourcc_t i_src;
123     vlc_fourcc_t i_dst;
124     block_t *(*pf_convert)( filter_t *, block_t *);
125 } ConvertTable[] =
126 {
127     /* From fl32 */
128     { VLC_FOURCC('f','l','3','2'), AOUT_FMT_S24_NE, Float32toS24 },
129     { VLC_FOURCC('f','l','3','2'), AOUT_FMT_S16_NE, Float32toS16 },
130     { VLC_FOURCC('f','l','3','2'), AOUT_FMT_U16_NE, Float32toU16 },
131     { VLC_FOURCC('f','l','3','2'), AOUT_FMT_S24_IE, Float32toS24Invert },
132     { VLC_FOURCC('f','l','3','2'), AOUT_FMT_S16_IE, Float32toS16Invert },
133     { VLC_FOURCC('f','l','3','2'), AOUT_FMT_U16_IE, Float32toU16Invert },
134     { VLC_FOURCC('f','l','3','2'), VLC_FOURCC('s','8',' ',' '), Float32toS8 },
135     { VLC_FOURCC('f','l','3','2'), VLC_FOURCC('u','8',' ',' '), Float32toU8 },
136
137     /* From s24 invert */
138     { AOUT_FMT_S24_NE, VLC_FOURCC('f','l','3','2'), S24toFloat32 },
139     { AOUT_FMT_S24_NE, AOUT_FMT_S24_IE,             Swap24 },
140     { AOUT_FMT_S24_NE, AOUT_FMT_S16_NE,             S24toS16 },
141     { AOUT_FMT_S24_NE, AOUT_FMT_S16_IE,             S24toS16Invert },
142
143     /* From s16 */
144     { AOUT_FMT_S16_NE, VLC_FOURCC('f','l','3','2'), S16toFloat32 },
145     { AOUT_FMT_S16_NE, AOUT_FMT_S24_NE,             S16toS24 },
146     { AOUT_FMT_S16_NE, AOUT_FMT_S24_IE,             S16toS24Invert },
147     { AOUT_FMT_S16_NE, AOUT_FMT_S16_IE,             Swap16 },
148     { AOUT_FMT_S16_NE, AOUT_FMT_U16_IE,             S16toU16 },
149     { AOUT_FMT_S16_NE, VLC_FOURCC('s','8',' ',' '), S16toS8 },
150     { AOUT_FMT_S16_NE, VLC_FOURCC('u','8',' ',' '), S16toU8 },
151
152     /* From u16 */
153     { AOUT_FMT_U16_NE, VLC_FOURCC('f','l','3','2'), U16toFloat32 },
154     { AOUT_FMT_U16_NE, AOUT_FMT_U16_IE,             Swap16 },
155     { AOUT_FMT_U16_NE, AOUT_FMT_S16_IE,             U16toS16 },
156     { AOUT_FMT_U16_NE, VLC_FOURCC('s','8',' ',' '), U16toS8 },
157     { AOUT_FMT_U16_NE, VLC_FOURCC('u','8',' ',' '), U16toU8 },
158
159     /* From s8 */
160     { VLC_FOURCC('s','8',' ',' '), VLC_FOURCC('f','l','3','2'), S8toFloat32 },
161     { VLC_FOURCC('s','8',' ',' '), AOUT_FMT_S16_NE,             S8toS16 },
162     { VLC_FOURCC('s','8',' ',' '), AOUT_FMT_S16_IE,             S8toS16Invert },
163     { VLC_FOURCC('s','8',' ',' '), AOUT_FMT_U16_NE,             S8toU16 },
164     { VLC_FOURCC('s','8',' ',' '), AOUT_FMT_U16_IE,             S8toU16Invert },
165     { VLC_FOURCC('s','8',' ',' '), VLC_FOURCC('u','8',' ',' '), S8toU8 },
166  
167     /* From u8 */
168     { VLC_FOURCC('u','8',' ',' '), VLC_FOURCC('f','l','3','2'), U8toFloat32 },
169     { VLC_FOURCC('u','8',' ',' '), AOUT_FMT_S16_NE,             U8toS16 },
170     { VLC_FOURCC('u','8',' ',' '), AOUT_FMT_S16_IE,             U8toS16Invert },
171     { VLC_FOURCC('u','8',' ',' '), AOUT_FMT_U16_NE,             U8toU16 },
172     { VLC_FOURCC('u','8',' ',' '), AOUT_FMT_U16_IE,             U8toU16Invert },
173     { VLC_FOURCC('u','8',' ',' '), VLC_FOURCC('s','8',' ',' '), U8toS8 },
174
175     /* From s24 invert */
176     { AOUT_FMT_S24_IE, VLC_FOURCC('f','l','3','2'), S24InverttoFloat32 },
177     { AOUT_FMT_S24_IE, AOUT_FMT_S24_NE,             Swap24 },
178     { AOUT_FMT_S24_IE, AOUT_FMT_S16_NE,             S24InverttoS16 },
179     { AOUT_FMT_S24_IE, AOUT_FMT_S16_IE,             S24InverttoS16Invert },
180
181     /* From s16 invert */
182     { AOUT_FMT_S16_IE, VLC_FOURCC('f','l','3','2'), S16InverttoFloat32 },
183     { AOUT_FMT_S16_IE, AOUT_FMT_S24_NE,             S16InverttoS24 },
184     { AOUT_FMT_S16_IE, AOUT_FMT_S24_IE,             S16InverttoS24Invert },
185     { AOUT_FMT_S16_IE, AOUT_FMT_S16_NE,             Swap16 },
186     { AOUT_FMT_S16_IE, AOUT_FMT_U16_NE,             S16InverttoU16 },
187     { AOUT_FMT_S16_IE, VLC_FOURCC('s','8',' ',' '), S16InverttoS8 },
188     { AOUT_FMT_S16_IE, VLC_FOURCC('u','8',' ',' '), S16InverttoU8 },
189
190     /* From u16 invert */
191     { AOUT_FMT_U16_IE, VLC_FOURCC('f','l','3','2'), U16InverttoFloat32 },
192     { AOUT_FMT_U16_IE, AOUT_FMT_U16_NE,             Swap16 },
193     { AOUT_FMT_U16_IE, AOUT_FMT_S16_NE,             U16InverttoS16 },
194     { AOUT_FMT_U16_IE, VLC_FOURCC('s','8',' ',' '), U16InverttoS8 },
195     { AOUT_FMT_U16_IE, VLC_FOURCC('u','8',' ',' '), U16InverttoU8 },
196
197     { 0, 0, NULL },
198 };
199
200
201 /*****************************************************************************
202  * Module descriptor
203  *****************************************************************************/
204 vlc_module_begin();
205     set_description( N_("Audio filter for PCM format conversion") );
206     set_category( CAT_AUDIO );
207     set_subcategory( SUBCAT_AUDIO_MISC );
208     set_capability( "audio filter2", 1 );
209     set_callbacks( Open, NULL );
210 vlc_module_end();
211
212 /*****************************************************************************
213  * Open:
214  *****************************************************************************/
215 static int Open( vlc_object_t *p_this )
216 {
217     filter_t *p_filter = (filter_t *)p_this;
218     int i;
219
220     for( i = 0; ConvertTable[i].pf_convert != NULL; i++ )
221     {
222         if( ConvertTable[i].i_src == p_filter->fmt_in.i_codec &&
223             ConvertTable[i].i_dst == p_filter->fmt_out.i_codec )
224             break;
225     }
226     if( ConvertTable[i].pf_convert == NULL )
227         return VLC_EGENERIC;
228
229     p_filter->pf_audio_filter = ConvertTable[i].pf_convert;
230     p_filter->fmt_out.audio = p_filter->fmt_in.audio;
231     p_filter->fmt_out.audio.i_format = p_filter->fmt_out.i_codec;
232
233     msg_Dbg( p_this, "%4.4s->%4.4s, bits per sample: %i",
234              (char *)&p_filter->fmt_in.i_codec,
235              (char *)&p_filter->fmt_out.i_codec,
236              p_filter->fmt_in.audio.i_bitspersample );
237
238     return VLC_SUCCESS;
239 }
240
241 /*****************************************************************************
242  * Convert a buffer
243  *****************************************************************************/
244 static block_t *Float32toS24( filter_t *p_filter, block_t *p_block )
245 {
246     VLC_UNUSED(p_filter);
247     int i;
248     float *p_in = (float *)p_block->p_buffer;
249     uint8_t *p_out = (uint8_t *)p_in;
250     int32_t out;
251
252     for( i = p_block->i_buffer / 4; i--; )
253     {
254         if ( *p_in >= 1.0 ) out = 8388607;
255         else if ( *p_in < -1.0 ) out = -8388608;
256         else out = *p_in * 8388608.0;
257
258 #ifdef WORDS_BIGENDIAN
259     *((int16_t *)p_out) = out >> 8;
260     p_out[2] = out & 0xFF;
261 #else
262     *((int16_t *)(p_out+1)) = out >> 8;
263     p_out[0] = out & 0xFF;
264 #endif
265
266         p_in++; p_out += 3;
267     }
268
269     p_block->i_buffer = p_block->i_buffer * 3 / 4;
270     return p_block;
271 }
272
273 static block_t *Float32toS16( filter_t *p_filter, block_t *p_block )
274 {
275     VLC_UNUSED(p_filter);
276     int i;
277     float *p_in = (float *)p_block->p_buffer;
278     int16_t *p_out = (int16_t *)p_in;
279
280     for( i = p_block->i_buffer / 4; i--; )
281     {
282 #if 0
283         /* Slow version. */
284         if ( *p_in >= 1.0 ) *p_out = 32767;
285         else if ( *p_in < -1.0 ) *p_out = -32768;
286         else *p_out = *p_in * 32768.0;
287 #else
288         /* This is walken's trick based on IEEE float format. */
289         union { float f; int32_t i; } u;
290         u.f = *p_in + 384.0;
291         if ( u.i > 0x43c07fff ) *p_out = 32767;
292         else if ( u.i < 0x43bf8000 ) *p_out = -32768;
293         else *p_out = u.i - 0x43c00000;
294 #endif
295         p_in++; p_out++;
296     }
297
298     p_block->i_buffer /= 2;
299     return p_block;
300 }
301
302 static block_t *Float32toU16( filter_t *p_filter, block_t *p_block )
303 {
304     VLC_UNUSED(p_filter);
305     int i;
306     float *p_in = (float *)p_block->p_buffer;
307     uint16_t *p_out = (uint16_t *)p_in;
308
309     for( i = p_block->i_buffer / 4; i--; )
310     {
311         if ( *p_in >= 1.0 ) *p_out = 65535;
312         else if ( *p_in < -1.0 ) *p_out = 0;
313         else *p_out = (uint16_t)(32768 + *p_in * 32768);
314         p_in++; p_out++;
315     }
316
317     p_block->i_buffer /= 2;
318     return p_block;
319 }
320
321 static block_t *S24toFloat32( filter_t *p_filter, block_t *p_block )
322 {
323     block_t *p_block_out;
324     uint8_t *p_in;
325     float *p_out;
326     int i;
327
328     p_block_out =
329         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer * 4 / 3 );
330     if( !p_block_out )
331     {
332         msg_Warn( p_filter, "can't get output buffer" );
333         return NULL;
334     }
335
336     p_in = p_block->p_buffer;
337     p_out = (float *)p_block_out->p_buffer;
338
339     for( i = p_block->i_buffer / 3; i--; )
340     {
341         /* FIXME: unaligned reads */
342 #ifdef WORDS_BIGENDIAN
343         *p_out = ((float)( (((int32_t)*(int16_t *)(p_in)) << 8) + p_in[2]))
344 #else
345         *p_out = ((float)( (((int32_t)*(int16_t *)(p_in+1)) << 8) + p_in[0]))
346 #endif
347             / 8388608.0;
348
349         p_in += 3; p_out++;
350     }
351
352     p_block_out->i_samples = p_block->i_samples;
353     p_block_out->i_dts = p_block->i_dts;
354     p_block_out->i_pts = p_block->i_pts;
355     p_block_out->i_length = p_block->i_length;
356     p_block_out->i_rate = p_block->i_rate;
357
358     p_block->pf_release( p_block );
359     return p_block_out;
360 }
361
362 static block_t *S24toS16( filter_t *p_filter, block_t *p_block )
363 {
364     VLC_UNUSED(p_filter);
365     int i;
366     uint8_t *p_in = (uint8_t *)p_block->p_buffer;
367     uint8_t *p_out = (uint8_t *)p_in;
368
369     for( i = p_block->i_buffer / 3; i--; )
370     {
371 #ifdef WORDS_BIGENDIAN
372         *p_out++ = *p_in++;
373         *p_out++ = *p_in++;
374         p_in++;
375 #else
376         p_in++;
377         *p_out++ = *p_in++;
378         *p_out++ = *p_in++;
379 #endif
380     }
381
382     p_block->i_buffer = p_block->i_buffer * 2 / 3;
383     return p_block;
384 }
385
386 static block_t *S16toFloat32( filter_t *p_filter, block_t *p_block )
387 {
388     block_t *p_block_out;
389     int16_t *p_in;
390     float *p_out;
391     int i;
392
393     p_block_out =
394         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
395     if( !p_block_out )
396     {
397         msg_Warn( p_filter, "can't get output buffer" );
398         return NULL;
399     }
400
401     p_in = (int16_t *)p_block->p_buffer;
402     p_out = (float *)p_block_out->p_buffer;
403
404     for( i = p_block->i_buffer / 2; i--; )
405     {
406 #if 0
407         /* Slow version */
408         *p_out = (float)*p_in / 32768.0;
409 #else
410         /* This is walken's trick based on IEEE float format. On my PIII
411          * this takes 16 seconds to perform one billion conversions, instead
412          * of 19 seconds for the above division. */
413         union { float f; int32_t i; } u;
414         u.i = *p_in + 0x43c00000;
415         *p_out = u.f - 384.0;
416 #endif
417
418         p_in++; p_out++;
419     }
420
421     p_block_out->i_samples = p_block->i_samples;
422     p_block_out->i_dts = p_block->i_dts;
423     p_block_out->i_pts = p_block->i_pts;
424     p_block_out->i_length = p_block->i_length;
425     p_block_out->i_rate = p_block->i_rate;
426
427     p_block->pf_release( p_block );
428     return p_block_out;
429 }
430
431 static block_t *U16toFloat32( filter_t *p_filter, block_t *p_block )
432 {
433     block_t *p_block_out;
434     uint16_t *p_in;
435     float *p_out;
436     int i;
437
438     p_block_out =
439         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
440     if( !p_block_out )
441     {
442         msg_Warn( p_filter, "can't get output buffer" );
443         return NULL;
444     }
445
446     p_in = (uint16_t *)p_block->p_buffer;
447     p_out = (float *)p_block_out->p_buffer;
448
449     for( i = p_block->i_buffer / 2; i--; )
450     {
451         *p_out++ = (float)(*p_in++ - 32768) / 32768.0;
452     }
453
454     p_block_out->i_samples = p_block->i_samples;
455     p_block_out->i_dts = p_block->i_dts;
456     p_block_out->i_pts = p_block->i_pts;
457     p_block_out->i_length = p_block->i_length;
458     p_block_out->i_rate = p_block->i_rate;
459
460     p_block->pf_release( p_block );
461     return p_block_out;
462 }
463
464 static block_t *S16toS24( filter_t *p_filter, block_t *p_block )
465 {
466     block_t *p_block_out;
467     uint8_t *p_in, *p_out;
468     int i;
469
470     p_block_out =
471         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*3/2 );
472     if( !p_block_out )
473     {
474         msg_Warn( p_filter, "can't get output buffer" );
475         return NULL;
476     }
477
478     p_in = (uint8_t *)p_block->p_buffer;
479     p_out = (uint8_t *)p_block_out->p_buffer;
480
481     for( i = p_block->i_buffer / 2; i--; )
482     {
483 #ifdef WORDS_BIGENDIAN
484         *p_out++ = *p_in++;
485         *p_out++ = *p_in++;
486         *p_out++ = 0;
487 #else
488         *p_out++ = 0;
489         *p_out++ = *p_in++;
490         *p_out++ = *p_in++;
491 #endif
492     }
493
494     p_block_out->i_samples = p_block->i_samples;
495     p_block_out->i_dts = p_block->i_dts;
496     p_block_out->i_pts = p_block->i_pts;
497     p_block_out->i_length = p_block->i_length;
498     p_block_out->i_rate = p_block->i_rate;
499
500     p_block->pf_release( p_block );
501     return p_block_out;
502 }
503
504 static block_t *S16toS8( filter_t *p_filter, block_t *p_block )
505 {
506     VLC_UNUSED(p_filter);
507     int i;
508     int16_t *p_in = (int16_t *)p_block->p_buffer;
509     int8_t *p_out = (int8_t *)p_in;
510
511     for( i = p_block->i_buffer / 2; i--; )
512         *p_out++ = (*p_in++) >> 8;
513
514     p_block->i_buffer /= 2;
515     return p_block;
516 }
517 static block_t *S16toU8( filter_t *p_filter, block_t *p_block )
518 {
519     VLC_UNUSED(p_filter);
520     int i;
521     int16_t *p_in = (int16_t *)p_block->p_buffer;
522     uint8_t *p_out = (uint8_t *)p_in;
523
524     for( i = p_block->i_buffer / 2; i--; )
525         *p_out++ = ((*p_in++) + 32768) >> 8;
526
527     p_block->i_buffer /= 2;
528     return p_block;
529 }
530 static block_t *S16toU16( filter_t *p_filter, block_t *p_block )
531 {
532     VLC_UNUSED(p_filter);
533     int i;
534     int16_t *p_in = (int16_t *)p_block->p_buffer;
535     uint16_t *p_out = (uint16_t *)p_in;
536
537     for( i = p_block->i_buffer / 2; i--; )
538         *p_out++ = (*p_in++) + 32768;
539
540     return p_block;
541 }
542
543 static block_t *U16toS8( filter_t *p_filter, block_t *p_block )
544 {
545     VLC_UNUSED(p_filter);
546     int i;
547     uint16_t *p_in = (uint16_t *)p_block->p_buffer;
548     int8_t *p_out = (int8_t *)p_in;
549
550     for( i = p_block->i_buffer / 2; i--; )
551         *p_out++ = ((int)(*p_in++) - 32768) >> 8;
552
553     p_block->i_buffer /= 2;
554     return p_block;
555 }
556 static block_t *U16toU8( filter_t *p_filter, block_t *p_block )
557 {
558     VLC_UNUSED(p_filter);
559     int i;
560     uint16_t *p_in = (uint16_t *)p_block->p_buffer;
561     uint8_t *p_out = (uint8_t *)p_in;
562
563     for( i = p_block->i_buffer / 2; i--; )
564         *p_out++ = (*p_in++) >> 8;
565
566     p_block->i_buffer /= 2;
567     return p_block;
568 }
569 static block_t *U16toS16( filter_t *p_filter, block_t *p_block )
570 {
571     VLC_UNUSED(p_filter);
572     int i;
573     uint16_t *p_in = (uint16_t *)p_block->p_buffer;
574     int16_t *p_out = (int16_t *)p_in;
575
576     for( i = p_block->i_buffer / 2; i--; )
577         *p_out++ = (int)(*p_in++) - 32768;
578
579     return p_block;
580 }
581
582 static block_t *S8toU8( filter_t *p_filter, block_t *p_block )
583 {
584     VLC_UNUSED(p_filter);
585     int i;
586     int8_t *p_in = (int8_t *)p_block->p_buffer;
587     uint8_t *p_out = (uint8_t *)p_in;
588
589     for( i = p_block->i_buffer; i--; )
590         *p_out++ = ((*p_in++) + 128);
591
592     return p_block;
593 }
594 static block_t *U8toS8( filter_t *p_filter, block_t *p_block )
595 {
596     VLC_UNUSED(p_filter);
597     int i;
598     uint8_t *p_in = (uint8_t *)p_block->p_buffer;
599     int8_t *p_out = (int8_t *)p_in;
600
601     for( i = p_block->i_buffer; i--; )
602         *p_out++ = ((*p_in++) - 128);
603
604     return p_block;
605 }
606
607 /* */
608 static block_t *S8toU16( filter_t *p_filter, block_t *p_block )
609 {
610     block_t *p_block_out;
611     int8_t *p_in;
612     uint16_t *p_out;
613     int i;
614
615     p_block_out =
616         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
617     if( !p_block_out )
618     {
619         msg_Warn( p_filter, "can't get output buffer" );
620         return NULL;
621     }
622
623     p_in = (int8_t *)p_block->p_buffer;
624     p_out = (uint16_t *)p_block_out->p_buffer;
625
626     for( i = p_block->i_buffer; i--; )
627         *p_out++ = ((*p_in++) + 128) << 8;
628
629     p_block_out->i_samples = p_block->i_samples;
630     p_block_out->i_dts = p_block->i_dts;
631     p_block_out->i_pts = p_block->i_pts;
632     p_block_out->i_length = p_block->i_length;
633     p_block_out->i_rate = p_block->i_rate;
634
635     p_block->pf_release( p_block );
636     return p_block_out;
637 }
638
639 static block_t *U8toS16( filter_t *p_filter, block_t *p_block )
640 {
641     block_t *p_block_out;
642     uint8_t *p_in;
643     int16_t *p_out;
644     int i;
645
646     p_block_out =
647         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
648     if( !p_block_out )
649     {
650         msg_Warn( p_filter, "can't get output buffer" );
651         return NULL;
652     }
653
654     p_in = (uint8_t *)p_block->p_buffer;
655     p_out = (int16_t *)p_block_out->p_buffer;
656
657     for( i = p_block->i_buffer; i--; )
658         *p_out++ = ((*p_in++) - 128) << 8;
659
660     p_block_out->i_samples = p_block->i_samples;
661     p_block_out->i_dts = p_block->i_dts;
662     p_block_out->i_pts = p_block->i_pts;
663     p_block_out->i_length = p_block->i_length;
664     p_block_out->i_rate = p_block->i_rate;
665
666     p_block->pf_release( p_block );
667     return p_block_out;
668 }
669
670
671 static block_t *S8toS16( filter_t *p_filter, block_t *p_block )
672 {
673     block_t *p_block_out;
674     int8_t *p_in;
675     int16_t *p_out;
676     int i;
677
678     p_block_out =
679         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
680     if( !p_block_out )
681     {
682         msg_Warn( p_filter, "can't get output buffer" );
683         return NULL;
684     }
685
686     p_in = (int8_t *)p_block->p_buffer;
687     p_out = (int16_t *)p_block_out->p_buffer;
688
689     for( i = p_block->i_buffer; i--; )
690         *p_out++ = (*p_in++) << 8;
691
692     p_block_out->i_samples = p_block->i_samples;
693     p_block_out->i_dts = p_block->i_dts;
694     p_block_out->i_pts = p_block->i_pts;
695     p_block_out->i_length = p_block->i_length;
696     p_block_out->i_rate = p_block->i_rate;
697
698     p_block->pf_release( p_block );
699     return p_block_out;
700 }
701
702 static block_t *U8toU16( filter_t *p_filter, block_t *p_block )
703 {
704     block_t *p_block_out;
705     uint8_t *p_in;
706     uint16_t *p_out;
707     int i;
708
709     p_block_out =
710         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
711     if( !p_block_out )
712     {
713         msg_Warn( p_filter, "can't get output buffer" );
714         return NULL;
715     }
716
717     p_in = (uint8_t *)p_block->p_buffer;
718     p_out = (uint16_t *)p_block_out->p_buffer;
719
720     for( i = p_block->i_buffer; i--; )
721         *p_out++ = (*p_in++) << 8;
722
723     p_block_out->i_samples = p_block->i_samples;
724     p_block_out->i_dts = p_block->i_dts;
725     p_block_out->i_pts = p_block->i_pts;
726     p_block_out->i_length = p_block->i_length;
727     p_block_out->i_rate = p_block->i_rate;
728
729     p_block->pf_release( p_block );
730     return p_block_out;
731 }
732
733 /*****************************************************************************
734  * Swap a buffer of words
735  *****************************************************************************/
736 static block_t *Swap16( filter_t *p_filter, block_t *p_block )
737 {
738     VLC_UNUSED(p_filter);
739     int i;
740     uint8_t *p_in = (uint8_t *)p_block->p_buffer;
741     uint8_t tmp;
742
743     for( i = 0; i < p_block->i_buffer / 2; i++ )
744     {
745         tmp = p_in[0];
746         p_in[0] = p_in[1];
747         p_in[1] = tmp;
748         p_in += 2;
749     }
750
751     return p_block;
752 }
753
754 static block_t *Swap24( filter_t *p_filter, block_t *p_block )
755 {
756     VLC_UNUSED(p_filter);
757     int i;
758     uint8_t *p_in = (uint8_t *)p_block->p_buffer;
759     uint8_t tmp;
760
761     for( i = 0; i < p_block->i_buffer / 3; i++ )
762     {
763         tmp = p_in[0];
764         p_in[0] = p_in[2];
765         p_in[2] = tmp;
766         p_in += 3;
767     }
768
769     return p_block;
770 }
771
772 #define CONVERT_NN( func, f_in, f_out, b_pre_invert, b_post_invert, swapa, swapb ) \
773 static block_t *func( filter_t *p_filter, block_t *p_block ) \
774 {                                                   \
775     if( b_pre_invert )                              \
776         swapa( p_filter, p_block );                  \
777                                                     \
778     p_block = f_in##to##f_out( p_filter, p_block ); \
779                                                     \
780     if( b_post_invert )                             \
781         swapb( p_filter, p_block );                  \
782                                                     \
783     return p_block;                                 \
784 }
785
786 CONVERT_NN( Float32toS24Invert, Float32, S24, 0, 1, Swap24, Swap24 )
787 CONVERT_NN( Float32toS16Invert, Float32, S16, 0, 1, Swap16, Swap16 )
788 CONVERT_NN( Float32toU16Invert, Float32, U16, 0, 1, Swap16, Swap16 )
789
790 CONVERT_NN( S24InverttoFloat32, S24, Float32, 1, 0, Swap24, Swap24 )
791 CONVERT_NN( S24InverttoS16,     S24, S16,     1, 0, Swap24, Swap16 )
792 CONVERT_NN( S24InverttoS16Invert, S24, S16,   1, 1, Swap24, Swap16 )
793 CONVERT_NN( S24toS16Invert,     S24, S16,     0, 1, Swap24, Swap16 )
794
795 CONVERT_NN( S16InverttoFloat32, S16, Float32, 1, 0, Swap16, Swap16 )
796 CONVERT_NN( S16InverttoS24,     S16, S24,     1, 0, Swap16, Swap24 )
797 CONVERT_NN( S16toS24Invert,     S16, S24,     0, 1, Swap16, Swap24 )
798 CONVERT_NN( S16InverttoS24Invert, S16, S24,   1, 1, Swap16, Swap24 )
799 CONVERT_NN( S16InverttoS8,      S16, S8,      1, 0, Swap16, Swap16 )
800 CONVERT_NN( S16InverttoU8,      S16, U8,      1, 0, Swap16, Swap16 )
801 CONVERT_NN( S16InverttoU16,     S16, U16,     1, 0, Swap16, Swap16 )
802
803 CONVERT_NN( U16InverttoFloat32, U16, Float32, 1, 0, Swap16, Swap16 )
804 CONVERT_NN( U16InverttoS8,      U16, S8,      1, 0, Swap16, Swap16 )
805 CONVERT_NN( U16InverttoU8,      U16, U8,      1, 0, Swap16, Swap16 )
806 CONVERT_NN( U16InverttoS16,     U16, S16,     1, 0, Swap16, Swap16 )
807
808 #undef CONVERT_NN
809
810 #define CONVERT_INDIRECT( func, f_in, f_mid, f_out )                    \
811 static block_t *func( filter_t *p_filter, block_t *p_block )            \
812 {                                                                       \
813     return f_mid##to##f_out( p_filter,                                  \
814                              f_in##to##f_mid( p_filter, p_block ) );    \
815 }
816
817 CONVERT_INDIRECT( Float32toS8,   Float32, S16, U8 )
818 CONVERT_INDIRECT( Float32toU8,   Float32, U16, U8 )
819 CONVERT_INDIRECT( S8toFloat32,   S8,      S16, Float32 )
820 CONVERT_INDIRECT( U8toFloat32,   U8,      U16, Float32 )
821
822 #define S16toS16Invert Swap16
823 #define U16toU16Invert Swap16
824
825 CONVERT_INDIRECT( U8toS16Invert, U8,      S16, S16Invert )
826 CONVERT_INDIRECT( S8toU16Invert, S8,      U16, U16Invert )
827
828 CONVERT_INDIRECT( U8toU16Invert, U8,      U16, U16Invert )
829 CONVERT_INDIRECT( S8toS16Invert, S8,      S16, S16Invert )
830
831 #undef CONVERT_INDIRECT