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