1 /*****************************************************************************
2 * float.c: Floating point audio format conversions
3 *****************************************************************************
4 * Copyright (C) 2002, 2006 the VideoLAN team
7 * Authors: Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
8 * Christophe Massiot <massiot@via.ecp.fr>
9 * Samuel Hocevar <sam@zoy.org>
10 * Xavier Maillard <zedek@fxgsproject.org>
11 * Henri Fallon <henri@videolan.org>
12 * Gildas Bazin <gbazin@netcourrier.com>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Create_F32ToFL32 ( vlc_object_t * );
52 static void Do_F32ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
54 static void Do_FL32ToF32 ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
57 static int Create_FL32ToS16 ( vlc_object_t * );
58 static void Do_FL32ToS16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
61 static int Create_FL32ToS8 ( vlc_object_t * );
62 static void Do_FL32ToS8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
65 static int Create_FL32ToU16 ( vlc_object_t * );
66 static void Do_FL32ToU16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
69 static int Create_FL32ToU8 ( vlc_object_t * );
70 static void Do_FL32ToU8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
73 static int Create_S16ToFL32( vlc_object_t * );
74 static void Do_S16ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
76 static void Do_S16ToFL24( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
79 static int Create_S16ToFL32_SW( vlc_object_t * );
80 static void Do_S16ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
82 static void Do_S16ToFL24_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
85 static int Create_S8ToFL32( vlc_object_t * );
86 static void Do_S8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
89 static int Create_U8ToFL32( vlc_object_t * );
90 static void Do_U8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
93 /*****************************************************************************
95 *****************************************************************************/
97 set_description( _("Floating-point audio format conversions") );
99 set_capability( "audio filter", 10 );
100 set_callbacks( Create_F32ToFL32, NULL );
102 set_capability( "audio filter", 1 );
103 set_callbacks( Create_FL32ToS16, NULL );
105 set_capability( "audio filter", 1 );
106 set_callbacks( Create_FL32ToS8, NULL );
108 set_capability( "audio filter", 1 );
109 set_callbacks( Create_FL32ToU16, NULL );
111 set_capability( "audio filter", 1 );
112 set_callbacks( Create_FL32ToU8, NULL );
114 set_capability( "audio filter", 1 );
115 set_callbacks( Create_S16ToFL32, NULL );
117 set_capability( "audio filter", 1 );
118 set_callbacks( Create_S16ToFL32_SW, NULL ); /* Endianness conversion*/
120 set_capability( "audio filter", 1 );
121 set_callbacks( Create_S8ToFL32, NULL );
123 set_capability( "audio filter", 1 );
124 set_callbacks( Create_U8ToFL32, NULL );
127 /*****************************************************************************
128 * Fixed 32 to Float 32 and backwards
129 *****************************************************************************/
130 static int Create_F32ToFL32( vlc_object_t *p_this )
132 aout_filter_t * p_filter = (aout_filter_t *)p_this;
134 if( ( p_filter->input.i_format != VLC_FOURCC('f','i','3','2')
135 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
136 && ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
137 || p_filter->output.i_format != VLC_FOURCC('f','i','3','2') ) )
142 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
147 if( p_filter->input.i_format == VLC_FOURCC('f','i','3','2') )
149 p_filter->pf_do_work = Do_F32ToFL32;
153 p_filter->pf_do_work = Do_FL32ToF32;
156 p_filter->b_in_place = 1;
161 static void Do_F32ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
162 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
166 vlc_fixed_t * p_in = (vlc_fixed_t *)p_in_buf->p_buffer;
167 float * p_out = (float *)p_out_buf->p_buffer;
169 for ( i = p_in_buf->i_nb_samples
170 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
172 *p_out++ = (float)*p_in++ / (float)FIXED32_ONE;
175 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
176 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
179 static void Do_FL32ToF32( aout_instance_t * p_aout, aout_filter_t * p_filter,
180 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
184 float * p_in = (float *)p_in_buf->p_buffer;
185 vlc_fixed_t * p_out = (vlc_fixed_t *)p_out_buf->p_buffer;
187 for ( i = p_in_buf->i_nb_samples
188 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
190 *p_out++ = (vlc_fixed_t)( *p_in++ * (float)FIXED32_ONE );
193 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
194 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
197 /*****************************************************************************
199 *****************************************************************************/
200 static int Create_FL32ToS16( vlc_object_t *p_this )
202 aout_filter_t * p_filter = (aout_filter_t *)p_this;
204 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
205 || p_filter->output.i_format != AOUT_FMT_S16_NE )
210 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
215 p_filter->pf_do_work = Do_FL32ToS16;
216 p_filter->b_in_place = 1;
221 static void Do_FL32ToS16( aout_instance_t * p_aout, aout_filter_t * p_filter,
222 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
226 float * p_in = (float *)p_in_buf->p_buffer;
227 int16_t * p_out = (int16_t *)p_out_buf->p_buffer;
229 for ( i = p_in_buf->i_nb_samples
230 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
234 if ( *p_in >= 1.0 ) *p_out = 32767;
235 else if ( *p_in < -1.0 ) *p_out = -32768;
236 else *p_out = *p_in * 32768.0;
238 /* This is walken's trick based on IEEE float format. */
239 union { float f; int32_t i; } u;
241 if ( u.i > 0x43c07fff ) *p_out = 32767;
242 else if ( u.i < 0x43bf8000 ) *p_out = -32768;
243 else *p_out = u.i - 0x43c00000;
248 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
249 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
252 /*****************************************************************************
254 *****************************************************************************/
255 static int Create_FL32ToS8( vlc_object_t *p_this )
257 aout_filter_t * p_filter = (aout_filter_t *)p_this;
259 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
260 || p_filter->output.i_format != VLC_FOURCC('s','8',' ',' ') )
265 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
270 p_filter->pf_do_work = Do_FL32ToS8;
271 p_filter->b_in_place = 1;
276 static void Do_FL32ToS8( aout_instance_t * p_aout, aout_filter_t * p_filter,
277 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
281 float * p_in = (float *)p_in_buf->p_buffer;
282 int8_t * p_out = (int8_t *)p_out_buf->p_buffer;
284 for ( i = p_in_buf->i_nb_samples
285 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
287 if ( *p_in >= 1.0 ) *p_out = 127;
288 else if ( *p_in < -1.0 ) *p_out = -128;
289 else *p_out = (int8_t)(*p_in * 128);
293 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
294 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
297 /*****************************************************************************
299 *****************************************************************************/
300 static int Create_FL32ToU16( vlc_object_t *p_this )
302 aout_filter_t * p_filter = (aout_filter_t *)p_this;
304 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
305 || p_filter->output.i_format != AOUT_FMT_U16_NE )
310 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
315 p_filter->pf_do_work = Do_FL32ToU16;
316 p_filter->b_in_place = 1;
321 static void Do_FL32ToU16( aout_instance_t * p_aout, aout_filter_t * p_filter,
322 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
326 float * p_in = (float *)p_in_buf->p_buffer;
327 uint16_t * p_out = (uint16_t *)p_out_buf->p_buffer;
329 for ( i = p_in_buf->i_nb_samples
330 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
332 if ( *p_in >= 1.0 ) *p_out = 65535;
333 else if ( *p_in < -1.0 ) *p_out = 0;
334 else *p_out = (uint16_t)(32768 + *p_in * 32768);
338 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
339 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
342 /*****************************************************************************
344 *****************************************************************************/
345 static int Create_FL32ToU8( vlc_object_t *p_this )
347 aout_filter_t * p_filter = (aout_filter_t *)p_this;
349 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
350 || p_filter->output.i_format != VLC_FOURCC('u','8',' ',' ') )
355 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
360 p_filter->pf_do_work = Do_FL32ToU8;
361 p_filter->b_in_place = 1;
366 static void Do_FL32ToU8( aout_instance_t * p_aout, aout_filter_t * p_filter,
367 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
371 float * p_in = (float *)p_in_buf->p_buffer;
372 uint8_t * p_out = (uint8_t *)p_out_buf->p_buffer;
374 for ( i = p_in_buf->i_nb_samples
375 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
377 if ( *p_in >= 1.0 ) *p_out = 255;
378 else if ( *p_in < -1.0 ) *p_out = 0;
379 else *p_out = (uint8_t)(128 + *p_in * 128);
383 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
384 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
387 /*****************************************************************************
389 *****************************************************************************/
390 static int Create_S16ToFL32( vlc_object_t *p_this )
392 aout_filter_t * p_filter = (aout_filter_t *)p_this;
394 if ( ( p_filter->input.i_format != AOUT_FMT_S16_NE &&
395 p_filter->input.i_format != AOUT_FMT_S24_NE )
396 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
401 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
406 if( p_filter->input.i_format == AOUT_FMT_S24_NE )
407 p_filter->pf_do_work = Do_S16ToFL24;
409 p_filter->pf_do_work = Do_S16ToFL32;
411 p_filter->b_in_place = VLC_TRUE;
416 static void Do_S16ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
417 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
420 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
422 /* We start from the end because b_in_place is true */
423 int16_t * p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
424 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
430 *p_out = (float)*p_in / 32768.0;
432 /* This is walken's trick based on IEEE float format. On my PIII
433 * this takes 16 seconds to perform one billion conversions, instead
434 * of 19 seconds for the above division. */
435 union { float f; int32_t i; } u;
436 u.i = *p_in + 0x43c00000;
437 *p_out = u.f - 384.0;
443 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
444 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
447 static void Do_S16ToFL24( aout_instance_t * p_aout, aout_filter_t * p_filter,
448 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
451 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
453 /* We start from the end because b_in_place is true */
454 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
455 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
459 #ifdef WORDS_BIGENDIAN
460 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in)) << 8) + p_in[2]))
462 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in+1)) << 8) + p_in[0]))
469 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
470 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
473 /*****************************************************************************
474 * S16 To Float32 with endianness conversion
475 *****************************************************************************/
476 static int Create_S16ToFL32_SW( vlc_object_t *p_this )
478 aout_filter_t * p_filter = (aout_filter_t *)p_this;
480 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
485 if ( (p_filter->input.i_format == VLC_FOURCC('s','1','6','l') ||
486 p_filter->input.i_format == VLC_FOURCC('s','1','6','b'))
487 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
488 && p_filter->input.i_format != AOUT_FMT_S16_NE )
490 p_filter->pf_do_work = Do_S16ToFL32_SW;
491 p_filter->b_in_place = VLC_TRUE;
496 if ( (p_filter->input.i_format == VLC_FOURCC('s','2','4','l') ||
497 p_filter->input.i_format == VLC_FOURCC('s','2','4','b'))
498 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
499 && p_filter->input.i_format != AOUT_FMT_S24_NE )
501 p_filter->pf_do_work = Do_S16ToFL24_SW;
502 p_filter->b_in_place = VLC_TRUE;
509 static void Do_S16ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
510 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
513 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
515 /* We start from the end because b_in_place is true */
517 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
521 int16_t * p_swabbed = alloca( i * sizeof(int16_t) );
523 int16_t * p_swabbed = malloc( i * sizeof(int16_t) );
526 swab( p_in_buf->p_buffer, (void *)p_swabbed, i * sizeof(int16_t) );
527 p_in = p_swabbed + i - 1;
531 p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
537 p_tmp[0] = ((byte_t *)p_in)[1];
538 p_tmp[1] = ((byte_t *)p_in)[0];
539 *p_out = (float)( *(int16_t *)p_tmp ) / 32768.0;
541 *p_out = (float)*p_in / 32768.0;
552 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
553 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
556 static void Do_S16ToFL24_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
557 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
560 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
562 /* We start from the end because b_in_place is true */
563 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
564 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
574 #ifdef WORDS_BIGENDIAN
575 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp)) << 8) + p_tmp[2]))
577 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp+1)) << 8) + p_tmp[0]))
584 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
585 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
588 /*****************************************************************************
590 *****************************************************************************/
591 static int Create_S8ToFL32( vlc_object_t *p_this )
593 aout_filter_t * p_filter = (aout_filter_t *)p_this;
595 if ( p_filter->input.i_format != VLC_FOURCC('s','8',' ',' ')
596 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
601 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
606 p_filter->pf_do_work = Do_S8ToFL32;
607 p_filter->b_in_place = VLC_TRUE;
612 static void Do_S8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
613 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
616 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
618 /* We start from the end because b_in_place is true */
619 int8_t * p_in = (int8_t *)p_in_buf->p_buffer + i - 1;
620 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
624 *p_out = (float)(*p_in) / 128.0;
628 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
629 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);
632 /*****************************************************************************
634 *****************************************************************************/
635 static int Create_U8ToFL32( vlc_object_t *p_this )
637 aout_filter_t * p_filter = (aout_filter_t *)p_this;
639 if ( p_filter->input.i_format != VLC_FOURCC('u','8',' ',' ')
640 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
645 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
650 p_filter->pf_do_work = Do_U8ToFL32;
651 p_filter->b_in_place = VLC_TRUE;
656 static void Do_U8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
657 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
660 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
662 /* We start from the end because b_in_place is true */
663 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + i - 1;
664 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
668 *p_out = ((float)*p_in -128) / 128.0;
672 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
673 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);