Check-in modules/Makefile.am
[vlc.git] / 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     VLC_UNUSED(p_filter);
246     int i;
247     float *p_in = (float *)p_block->p_buffer;
248     uint8_t *p_out = (uint8_t *)p_in;
249     int32_t out;
250
251     for( i = p_block->i_buffer / 4; i--; )
252     {
253         if ( *p_in >= 1.0 ) out = 8388607;
254         else if ( *p_in < -1.0 ) out = -8388608;
255         else out = *p_in * 8388608.0;
256
257 #ifdef WORDS_BIGENDIAN
258     *((int16_t *)p_out) = out >> 8;
259     p_out[2] = out & 0xFF;
260 #else
261     *((int16_t *)(p_out+1)) = out >> 8;
262     p_out[0] = out & 0xFF;
263 #endif
264
265         p_in++; p_out += 3;
266     }
267
268     p_block->i_buffer = p_block->i_buffer * 3 / 4;
269     return p_block;
270 }
271
272 static block_t *Float32toS16( filter_t *p_filter, block_t *p_block )
273 {
274     VLC_UNUSED(p_filter);
275     int i;
276     float *p_in = (float *)p_block->p_buffer;
277     int16_t *p_out = (int16_t *)p_in;
278
279     for( i = p_block->i_buffer / 4; i--; )
280     {
281 #if 0
282         /* Slow version. */
283         if ( *p_in >= 1.0 ) *p_out = 32767;
284         else if ( *p_in < -1.0 ) *p_out = -32768;
285         else *p_out = *p_in * 32768.0;
286 #else
287         /* This is walken's trick based on IEEE float format. */
288         union { float f; int32_t i; } u;
289         u.f = *p_in + 384.0;
290         if ( u.i > 0x43c07fff ) *p_out = 32767;
291         else if ( u.i < 0x43bf8000 ) *p_out = -32768;
292         else *p_out = u.i - 0x43c00000;
293 #endif
294         p_in++; p_out++;
295     }
296
297     p_block->i_buffer /= 2;
298     return p_block;
299 }
300
301 static block_t *Float32toU16( filter_t *p_filter, block_t *p_block )
302 {
303     VLC_UNUSED(p_filter);
304     int i;
305     float *p_in = (float *)p_block->p_buffer;
306     uint16_t *p_out = (uint16_t *)p_in;
307
308     for( i = p_block->i_buffer / 4; i--; )
309     {
310         if ( *p_in >= 1.0 ) *p_out = 65535;
311         else if ( *p_in < -1.0 ) *p_out = 0;
312         else *p_out = (uint16_t)(32768 + *p_in * 32768);
313         p_in++; p_out++;
314     }
315
316     p_block->i_buffer /= 2;
317     return p_block;
318 }
319
320 static block_t *S24toFloat32( filter_t *p_filter, block_t *p_block )
321 {
322     block_t *p_block_out;
323     uint8_t *p_in;
324     float *p_out;
325     int i;
326
327     p_block_out =
328         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer * 4 / 3 );
329     if( !p_block_out )
330     {
331         msg_Warn( p_filter, "can't get output buffer" );
332         return NULL;
333     }
334
335     p_in = p_block->p_buffer;
336     p_out = (float *)p_block_out->p_buffer;
337
338     for( i = p_block->i_buffer / 3; i--; )
339     {
340         /* FIXME: unaligned reads */
341 #ifdef WORDS_BIGENDIAN
342         *p_out = ((float)( (((int32_t)*(int16_t *)(p_in)) << 8) + p_in[2]))
343 #else
344         *p_out = ((float)( (((int32_t)*(int16_t *)(p_in+1)) << 8) + p_in[0]))
345 #endif
346             / 8388608.0;
347
348         p_in += 3; p_out++;
349     }
350
351     p_block_out->i_samples = p_block->i_samples;
352     p_block_out->i_dts = p_block->i_dts;
353     p_block_out->i_pts = p_block->i_pts;
354     p_block_out->i_length = p_block->i_length;
355     p_block_out->i_rate = p_block->i_rate;
356
357     p_block->pf_release( p_block );
358     return p_block_out;
359 }
360
361 static block_t *S24toS16( filter_t *p_filter, block_t *p_block )
362 {
363     VLC_UNUSED(p_filter);
364     int i;
365     uint8_t *p_in = (uint8_t *)p_block->p_buffer;
366     uint8_t *p_out = (uint8_t *)p_in;
367
368     for( i = p_block->i_buffer / 3; i--; )
369     {
370 #ifdef WORDS_BIGENDIAN
371         *p_out++ = *p_in++;
372         *p_out++ = *p_in++;
373         p_in++;
374 #else
375         p_in++;
376         *p_out++ = *p_in++;
377         *p_out++ = *p_in++;
378 #endif
379     }
380
381     p_block->i_buffer = p_block->i_buffer * 2 / 3;
382     return p_block;
383 }
384
385 static block_t *S16toFloat32( filter_t *p_filter, block_t *p_block )
386 {
387     block_t *p_block_out;
388     int16_t *p_in;
389     float *p_out;
390     int i;
391
392     p_block_out =
393         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
394     if( !p_block_out )
395     {
396         msg_Warn( p_filter, "can't get output buffer" );
397         return NULL;
398     }
399
400     p_in = (int16_t *)p_block->p_buffer;
401     p_out = (float *)p_block_out->p_buffer;
402
403     for( i = p_block->i_buffer / 2; i--; )
404     {
405 #if 0
406         /* Slow version */
407         *p_out = (float)*p_in / 32768.0;
408 #else
409         /* This is walken's trick based on IEEE float format. On my PIII
410          * this takes 16 seconds to perform one billion conversions, instead
411          * of 19 seconds for the above division. */
412         union { float f; int32_t i; } u;
413         u.i = *p_in + 0x43c00000;
414         *p_out = u.f - 384.0;
415 #endif
416
417         p_in++; p_out++;
418     }
419
420     p_block_out->i_samples = p_block->i_samples;
421     p_block_out->i_dts = p_block->i_dts;
422     p_block_out->i_pts = p_block->i_pts;
423     p_block_out->i_length = p_block->i_length;
424     p_block_out->i_rate = p_block->i_rate;
425
426     p_block->pf_release( p_block );
427     return p_block_out;
428 }
429
430 static block_t *U16toFloat32( filter_t *p_filter, block_t *p_block )
431 {
432     block_t *p_block_out;
433     uint16_t *p_in;
434     float *p_out;
435     int i;
436
437     p_block_out =
438         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
439     if( !p_block_out )
440     {
441         msg_Warn( p_filter, "can't get output buffer" );
442         return NULL;
443     }
444
445     p_in = (uint16_t *)p_block->p_buffer;
446     p_out = (float *)p_block_out->p_buffer;
447
448     for( i = p_block->i_buffer / 2; i--; )
449     {
450         *p_out++ = (float)(*p_in++ - 32768) / 32768.0;
451     }
452
453     p_block_out->i_samples = p_block->i_samples;
454     p_block_out->i_dts = p_block->i_dts;
455     p_block_out->i_pts = p_block->i_pts;
456     p_block_out->i_length = p_block->i_length;
457     p_block_out->i_rate = p_block->i_rate;
458
459     p_block->pf_release( p_block );
460     return p_block_out;
461 }
462
463 static block_t *S16toS24( filter_t *p_filter, block_t *p_block )
464 {
465     block_t *p_block_out;
466     uint8_t *p_in, *p_out;
467     int i;
468
469     p_block_out =
470         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*3/2 );
471     if( !p_block_out )
472     {
473         msg_Warn( p_filter, "can't get output buffer" );
474         return NULL;
475     }
476
477     p_in = (uint8_t *)p_block->p_buffer;
478     p_out = (uint8_t *)p_block_out->p_buffer;
479
480     for( i = p_block->i_buffer / 2; i--; )
481     {
482 #ifdef WORDS_BIGENDIAN
483         *p_out++ = *p_in++;
484         *p_out++ = *p_in++;
485         *p_out++ = 0;
486 #else
487         *p_out++ = 0;
488         *p_out++ = *p_in++;
489         *p_out++ = *p_in++;
490 #endif
491     }
492
493     p_block_out->i_samples = p_block->i_samples;
494     p_block_out->i_dts = p_block->i_dts;
495     p_block_out->i_pts = p_block->i_pts;
496     p_block_out->i_length = p_block->i_length;
497     p_block_out->i_rate = p_block->i_rate;
498
499     p_block->pf_release( p_block );
500     return p_block_out;
501 }
502
503 static block_t *S16toS8( filter_t *p_filter, block_t *p_block )
504 {
505     VLC_UNUSED(p_filter);
506     int i;
507     int16_t *p_in = (int16_t *)p_block->p_buffer;
508     int8_t *p_out = (int8_t *)p_in;
509
510     for( i = p_block->i_buffer / 2; i--; )
511         *p_out++ = (*p_in++) >> 8;
512
513     p_block->i_buffer /= 2;
514     return p_block;
515 }
516 static block_t *S16toU8( filter_t *p_filter, block_t *p_block )
517 {
518     VLC_UNUSED(p_filter);
519     int i;
520     int16_t *p_in = (int16_t *)p_block->p_buffer;
521     uint8_t *p_out = (uint8_t *)p_in;
522
523     for( i = p_block->i_buffer / 2; i--; )
524         *p_out++ = ((*p_in++) + 32768) >> 8;
525
526     p_block->i_buffer /= 2;
527     return p_block;
528 }
529 static block_t *S16toU16( filter_t *p_filter, block_t *p_block )
530 {
531     VLC_UNUSED(p_filter);
532     int i;
533     int16_t *p_in = (int16_t *)p_block->p_buffer;
534     uint16_t *p_out = (uint16_t *)p_in;
535
536     for( i = p_block->i_buffer / 2; i--; )
537         *p_out++ = (*p_in++) + 32768;
538
539     return p_block;
540 }
541
542 static block_t *U16toS8( filter_t *p_filter, block_t *p_block )
543 {
544     VLC_UNUSED(p_filter);
545     int i;
546     uint16_t *p_in = (uint16_t *)p_block->p_buffer;
547     int8_t *p_out = (int8_t *)p_in;
548
549     for( i = p_block->i_buffer / 2; i--; )
550         *p_out++ = ((int)(*p_in++) - 32768) >> 8;
551
552     p_block->i_buffer /= 2;
553     return p_block;
554 }
555 static block_t *U16toU8( filter_t *p_filter, block_t *p_block )
556 {
557     VLC_UNUSED(p_filter);
558     int i;
559     uint16_t *p_in = (uint16_t *)p_block->p_buffer;
560     uint8_t *p_out = (uint8_t *)p_in;
561
562     for( i = p_block->i_buffer / 2; i--; )
563         *p_out++ = (*p_in++) >> 8;
564
565     p_block->i_buffer /= 2;
566     return p_block;
567 }
568 static block_t *U16toS16( filter_t *p_filter, block_t *p_block )
569 {
570     VLC_UNUSED(p_filter);
571     int i;
572     uint16_t *p_in = (uint16_t *)p_block->p_buffer;
573     int16_t *p_out = (int16_t *)p_in;
574
575     for( i = p_block->i_buffer / 2; i--; )
576         *p_out++ = (int)(*p_in++) - 32768;
577
578     return p_block;
579 }
580
581 static block_t *S8toU8( filter_t *p_filter, block_t *p_block )
582 {
583     VLC_UNUSED(p_filter);
584     int i;
585     int8_t *p_in = (int8_t *)p_block->p_buffer;
586     uint8_t *p_out = (uint8_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 static block_t *U8toS8( filter_t *p_filter, block_t *p_block )
594 {
595     VLC_UNUSED(p_filter);
596     int i;
597     uint8_t *p_in = (uint8_t *)p_block->p_buffer;
598     int8_t *p_out = (int8_t *)p_in;
599
600     for( i = p_block->i_buffer; i--; )
601         *p_out++ = ((*p_in++) - 128);
602
603     return p_block;
604 }
605
606 /* */
607 static block_t *S8toU16( filter_t *p_filter, block_t *p_block )
608 {
609     block_t *p_block_out;
610     int8_t *p_in;
611     uint16_t *p_out;
612     int i;
613
614     p_block_out =
615         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
616     if( !p_block_out )
617     {
618         msg_Warn( p_filter, "can't get output buffer" );
619         return NULL;
620     }
621
622     p_in = (int8_t *)p_block->p_buffer;
623     p_out = (uint16_t *)p_block_out->p_buffer;
624
625     for( i = p_block->i_buffer; i--; )
626         *p_out++ = ((*p_in++) + 128) << 8;
627
628     p_block_out->i_samples = p_block->i_samples;
629     p_block_out->i_dts = p_block->i_dts;
630     p_block_out->i_pts = p_block->i_pts;
631     p_block_out->i_length = p_block->i_length;
632     p_block_out->i_rate = p_block->i_rate;
633
634     p_block->pf_release( p_block );
635     return p_block_out;
636 }
637
638 static block_t *U8toS16( filter_t *p_filter, block_t *p_block )
639 {
640     block_t *p_block_out;
641     uint8_t *p_in;
642     int16_t *p_out;
643     int i;
644
645     p_block_out =
646         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
647     if( !p_block_out )
648     {
649         msg_Warn( p_filter, "can't get output buffer" );
650         return NULL;
651     }
652
653     p_in = (uint8_t *)p_block->p_buffer;
654     p_out = (int16_t *)p_block_out->p_buffer;
655
656     for( i = p_block->i_buffer; i--; )
657         *p_out++ = ((*p_in++) - 128) << 8;
658
659     p_block_out->i_samples = p_block->i_samples;
660     p_block_out->i_dts = p_block->i_dts;
661     p_block_out->i_pts = p_block->i_pts;
662     p_block_out->i_length = p_block->i_length;
663     p_block_out->i_rate = p_block->i_rate;
664
665     p_block->pf_release( p_block );
666     return p_block_out;
667 }
668
669
670 static block_t *S8toS16( filter_t *p_filter, block_t *p_block )
671 {
672     block_t *p_block_out;
673     int8_t *p_in;
674     int16_t *p_out;
675     int i;
676
677     p_block_out =
678         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
679     if( !p_block_out )
680     {
681         msg_Warn( p_filter, "can't get output buffer" );
682         return NULL;
683     }
684
685     p_in = (int8_t *)p_block->p_buffer;
686     p_out = (int16_t *)p_block_out->p_buffer;
687
688     for( i = p_block->i_buffer; i--; )
689         *p_out++ = (*p_in++) << 8;
690
691     p_block_out->i_samples = p_block->i_samples;
692     p_block_out->i_dts = p_block->i_dts;
693     p_block_out->i_pts = p_block->i_pts;
694     p_block_out->i_length = p_block->i_length;
695     p_block_out->i_rate = p_block->i_rate;
696
697     p_block->pf_release( p_block );
698     return p_block_out;
699 }
700
701 static block_t *U8toU16( filter_t *p_filter, block_t *p_block )
702 {
703     block_t *p_block_out;
704     uint8_t *p_in;
705     uint16_t *p_out;
706     int i;
707
708     p_block_out =
709         p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
710     if( !p_block_out )
711     {
712         msg_Warn( p_filter, "can't get output buffer" );
713         return NULL;
714     }
715
716     p_in = (uint8_t *)p_block->p_buffer;
717     p_out = (uint16_t *)p_block_out->p_buffer;
718
719     for( i = p_block->i_buffer; i--; )
720         *p_out++ = (*p_in++) << 8;
721
722     p_block_out->i_samples = p_block->i_samples;
723     p_block_out->i_dts = p_block->i_dts;
724     p_block_out->i_pts = p_block->i_pts;
725     p_block_out->i_length = p_block->i_length;
726     p_block_out->i_rate = p_block->i_rate;
727
728     p_block->pf_release( p_block );
729     return p_block_out;
730 }
731
732 /*****************************************************************************
733  * Swap a buffer of words
734  *****************************************************************************/
735 static block_t *Swap16( filter_t *p_filter, block_t *p_block )
736 {
737     VLC_UNUSED(p_filter);
738     int i;
739     uint8_t *p_in = (uint8_t *)p_block->p_buffer;
740     uint8_t tmp;
741
742     for( i = 0; i < p_block->i_buffer / 2; i++ )
743     {
744         tmp = p_in[0];
745         p_in[0] = p_in[1];
746         p_in[1] = tmp;
747         p_in += 2;
748     }
749
750     return p_block;
751 }
752
753 static block_t *Swap24( filter_t *p_filter, block_t *p_block )
754 {
755     VLC_UNUSED(p_filter);
756     int i;
757     uint8_t *p_in = (uint8_t *)p_block->p_buffer;
758     uint8_t tmp;
759
760     for( i = 0; i < p_block->i_buffer / 3; i++ )
761     {
762         tmp = p_in[0];
763         p_in[0] = p_in[2];
764         p_in[2] = tmp;
765         p_in += 3;
766     }
767
768     return p_block;
769 }
770
771 #define CONVERT_NN( func, f_in, f_out, b_pre_invert, b_post_invert, swapa, swapb ) \
772 static block_t *func( filter_t *p_filter, block_t *p_block ) \
773 {                                                   \
774     if( b_pre_invert )                              \
775         swapa( p_filter, p_block );                  \
776                                                     \
777     p_block = f_in##to##f_out( p_filter, p_block ); \
778                                                     \
779     if( b_post_invert )                             \
780         swapb( p_filter, p_block );                  \
781                                                     \
782     return p_block;                                 \
783 }
784
785 CONVERT_NN( Float32toS24Invert, Float32, S24, 0, 1, Swap24, Swap24 )
786 CONVERT_NN( Float32toS16Invert, Float32, S16, 0, 1, Swap16, Swap16 )
787 CONVERT_NN( Float32toU16Invert, Float32, U16, 0, 1, Swap16, Swap16 )
788
789 CONVERT_NN( S24InverttoFloat32, S24, Float32, 1, 0, Swap24, Swap24 )
790 CONVERT_NN( S24InverttoS16,     S24, S16,     1, 0, Swap24, Swap16 )
791 CONVERT_NN( S24InverttoS16Invert, S24, S16,   1, 1, Swap24, Swap16 )
792 CONVERT_NN( S24toS16Invert,     S24, S16,     0, 1, Swap24, Swap16 )
793
794 CONVERT_NN( S16InverttoFloat32, S16, Float32, 1, 0, Swap16, Swap16 )
795 CONVERT_NN( S16InverttoS24,     S16, S24,     1, 0, Swap16, Swap24 )
796 CONVERT_NN( S16toS24Invert,     S16, S24,     0, 1, Swap16, Swap24 )
797 CONVERT_NN( S16InverttoS24Invert, S16, S24,   1, 1, Swap16, Swap24 )
798 CONVERT_NN( S16InverttoS8,      S16, S8,      1, 0, Swap16, Swap16 )
799 CONVERT_NN( S16InverttoU8,      S16, U8,      1, 0, Swap16, Swap16 )
800 CONVERT_NN( S16InverttoU16,     S16, U16,     1, 0, Swap16, Swap16 )
801
802 CONVERT_NN( U16InverttoFloat32, U16, Float32, 1, 0, Swap16, Swap16 )
803 CONVERT_NN( U16InverttoS8,      U16, S8,      1, 0, Swap16, Swap16 )
804 CONVERT_NN( U16InverttoU8,      U16, U8,      1, 0, Swap16, Swap16 )
805 CONVERT_NN( U16InverttoS16,     U16, S16,     1, 0, Swap16, Swap16 )
806
807 #undef CONVERT_NN
808
809 #define CONVERT_INDIRECT( func, f_in, f_mid, f_out )                    \
810 static block_t *func( filter_t *p_filter, block_t *p_block )            \
811 {                                                                       \
812     return f_mid##to##f_out( p_filter,                                  \
813                              f_in##to##f_mid( p_filter, p_block ) );    \
814 }
815
816 CONVERT_INDIRECT( Float32toS8,   Float32, S16, U8 )
817 CONVERT_INDIRECT( Float32toU8,   Float32, U16, U8 )
818 CONVERT_INDIRECT( S8toFloat32,   S8,      S16, Float32 )
819 CONVERT_INDIRECT( U8toFloat32,   U8,      U16, Float32 )
820
821 #define S16toS16Invert Swap16
822 #define U16toU16Invert Swap16
823
824 CONVERT_INDIRECT( U8toS16Invert, U8,      S16, S16Invert )
825 CONVERT_INDIRECT( S8toU16Invert, S8,      U16, U16Invert )
826
827 CONVERT_INDIRECT( U8toU16Invert, U8,      U16, U16Invert )
828 CONVERT_INDIRECT( S8toS16Invert, S8,      S16, S16Invert )
829
830 #undef CONVERT_INDIRECT