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 )
165 vlc_fixed_t * p_in = (vlc_fixed_t *)p_in_buf->p_buffer;
166 float * p_out = (float *)p_out_buf->p_buffer;
168 for ( i = p_in_buf->i_nb_samples
169 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
171 *p_out++ = (float)*p_in++ / (float)FIXED32_ONE;
174 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
175 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
178 static void Do_FL32ToF32( aout_instance_t * p_aout, aout_filter_t * p_filter,
179 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
182 float * p_in = (float *)p_in_buf->p_buffer;
183 vlc_fixed_t * p_out = (vlc_fixed_t *)p_out_buf->p_buffer;
185 for ( i = p_in_buf->i_nb_samples
186 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
188 *p_out++ = (vlc_fixed_t)( *p_in++ * (float)FIXED32_ONE );
191 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
192 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
195 /*****************************************************************************
197 *****************************************************************************/
198 static int Create_FL32ToS16( vlc_object_t *p_this )
200 aout_filter_t * p_filter = (aout_filter_t *)p_this;
202 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
203 || p_filter->output.i_format != AOUT_FMT_S16_NE )
208 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
213 p_filter->pf_do_work = Do_FL32ToS16;
214 p_filter->b_in_place = 1;
219 static void Do_FL32ToS16( aout_instance_t * p_aout, aout_filter_t * p_filter,
220 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
223 float * p_in = (float *)p_in_buf->p_buffer;
224 int16_t * p_out = (int16_t *)p_out_buf->p_buffer;
226 for ( i = p_in_buf->i_nb_samples
227 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
231 if ( *p_in >= 1.0 ) *p_out = 32767;
232 else if ( *p_in < -1.0 ) *p_out = -32768;
233 else *p_out = *p_in * 32768.0;
235 /* This is walken's trick based on IEEE float format. */
236 union { float f; int32_t i; } u;
238 if ( u.i > 0x43c07fff ) *p_out = 32767;
239 else if ( u.i < 0x43bf8000 ) *p_out = -32768;
240 else *p_out = u.i - 0x43c00000;
245 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
246 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
249 /*****************************************************************************
251 *****************************************************************************/
252 static int Create_FL32ToS8( vlc_object_t *p_this )
254 aout_filter_t * p_filter = (aout_filter_t *)p_this;
256 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
257 || p_filter->output.i_format != VLC_FOURCC('s','8',' ',' ') )
262 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
267 p_filter->pf_do_work = Do_FL32ToS8;
268 p_filter->b_in_place = 1;
273 static void Do_FL32ToS8( aout_instance_t * p_aout, aout_filter_t * p_filter,
274 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
277 float * p_in = (float *)p_in_buf->p_buffer;
278 int8_t * p_out = (int8_t *)p_out_buf->p_buffer;
280 for ( i = p_in_buf->i_nb_samples
281 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
283 if ( *p_in >= 1.0 ) *p_out = 127;
284 else if ( *p_in < -1.0 ) *p_out = -128;
285 else *p_out = (int8_t)(*p_in * 128);
289 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
290 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
293 /*****************************************************************************
295 *****************************************************************************/
296 static int Create_FL32ToU16( vlc_object_t *p_this )
298 aout_filter_t * p_filter = (aout_filter_t *)p_this;
300 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
301 || p_filter->output.i_format != AOUT_FMT_U16_NE )
306 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
311 p_filter->pf_do_work = Do_FL32ToU16;
312 p_filter->b_in_place = 1;
317 static void Do_FL32ToU16( aout_instance_t * p_aout, aout_filter_t * p_filter,
318 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
321 float * p_in = (float *)p_in_buf->p_buffer;
322 uint16_t * p_out = (uint16_t *)p_out_buf->p_buffer;
324 for ( i = p_in_buf->i_nb_samples
325 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
327 if ( *p_in >= 1.0 ) *p_out = 65535;
328 else if ( *p_in < -1.0 ) *p_out = 0;
329 else *p_out = (uint16_t)(32768 + *p_in * 32768);
333 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
334 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
337 /*****************************************************************************
339 *****************************************************************************/
340 static int Create_FL32ToU8( vlc_object_t *p_this )
342 aout_filter_t * p_filter = (aout_filter_t *)p_this;
344 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
345 || p_filter->output.i_format != VLC_FOURCC('u','8',' ',' ') )
350 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
355 p_filter->pf_do_work = Do_FL32ToU8;
356 p_filter->b_in_place = 1;
361 static void Do_FL32ToU8( aout_instance_t * p_aout, aout_filter_t * p_filter,
362 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
365 float * p_in = (float *)p_in_buf->p_buffer;
366 uint8_t * p_out = (uint8_t *)p_out_buf->p_buffer;
368 for ( i = p_in_buf->i_nb_samples
369 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
371 if ( *p_in >= 1.0 ) *p_out = 255;
372 else if ( *p_in < -1.0 ) *p_out = 0;
373 else *p_out = (uint8_t)(128 + *p_in * 128);
377 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
378 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
381 /*****************************************************************************
383 *****************************************************************************/
384 static int Create_S16ToFL32( vlc_object_t *p_this )
386 aout_filter_t * p_filter = (aout_filter_t *)p_this;
388 if ( ( p_filter->input.i_format != AOUT_FMT_S16_NE &&
389 p_filter->input.i_format != AOUT_FMT_S24_NE )
390 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
395 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
400 if( p_filter->input.i_format == AOUT_FMT_S24_NE )
401 p_filter->pf_do_work = Do_S16ToFL24;
403 p_filter->pf_do_work = Do_S16ToFL32;
405 p_filter->b_in_place = VLC_TRUE;
410 static void Do_S16ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
411 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
413 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
415 /* We start from the end because b_in_place is true */
416 int16_t * p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
417 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
423 *p_out = (float)*p_in / 32768.0;
425 /* This is walken's trick based on IEEE float format. On my PIII
426 * this takes 16 seconds to perform one billion conversions, instead
427 * of 19 seconds for the above division. */
428 union { float f; int32_t i; } u;
429 u.i = *p_in + 0x43c00000;
430 *p_out = u.f - 384.0;
436 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
437 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
440 static void Do_S16ToFL24( aout_instance_t * p_aout, aout_filter_t * p_filter,
441 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
443 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
445 /* We start from the end because b_in_place is true */
446 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
447 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
451 #ifdef WORDS_BIGENDIAN
452 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in)) << 8) + p_in[2]))
454 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in+1)) << 8) + p_in[0]))
461 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
462 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
465 /*****************************************************************************
466 * S16 To Float32 with endianness conversion
467 *****************************************************************************/
468 static int Create_S16ToFL32_SW( vlc_object_t *p_this )
470 aout_filter_t * p_filter = (aout_filter_t *)p_this;
472 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
477 if ( (p_filter->input.i_format == VLC_FOURCC('s','1','6','l') ||
478 p_filter->input.i_format == VLC_FOURCC('s','1','6','b'))
479 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
480 && p_filter->input.i_format != AOUT_FMT_S16_NE )
482 p_filter->pf_do_work = Do_S16ToFL32_SW;
483 p_filter->b_in_place = VLC_TRUE;
488 if ( (p_filter->input.i_format == VLC_FOURCC('s','2','4','l') ||
489 p_filter->input.i_format == VLC_FOURCC('s','2','4','b'))
490 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
491 && p_filter->input.i_format != AOUT_FMT_S24_NE )
493 p_filter->pf_do_work = Do_S16ToFL24_SW;
494 p_filter->b_in_place = VLC_TRUE;
501 static void Do_S16ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
502 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
504 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
506 /* We start from the end because b_in_place is true */
508 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
512 int16_t * p_swabbed = alloca( i * sizeof(int16_t) );
514 int16_t * p_swabbed = malloc( i * sizeof(int16_t) );
517 swab( p_in_buf->p_buffer, (void *)p_swabbed, i * sizeof(int16_t) );
518 p_in = p_swabbed + i - 1;
522 p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
528 p_tmp[0] = ((byte_t *)p_in)[1];
529 p_tmp[1] = ((byte_t *)p_in)[0];
530 *p_out = (float)( *(int16_t *)p_tmp ) / 32768.0;
532 *p_out = (float)*p_in / 32768.0;
543 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
544 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
547 static void Do_S16ToFL24_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
548 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
550 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
552 /* We start from the end because b_in_place is true */
553 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
554 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
564 #ifdef WORDS_BIGENDIAN
565 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp)) << 8) + p_tmp[2]))
567 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp+1)) << 8) + p_tmp[0]))
574 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
575 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
578 /*****************************************************************************
580 *****************************************************************************/
581 static int Create_S8ToFL32( vlc_object_t *p_this )
583 aout_filter_t * p_filter = (aout_filter_t *)p_this;
585 if ( p_filter->input.i_format != VLC_FOURCC('s','8',' ',' ')
586 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
591 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
596 p_filter->pf_do_work = Do_S8ToFL32;
597 p_filter->b_in_place = VLC_TRUE;
602 static void Do_S8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
603 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
605 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
607 /* We start from the end because b_in_place is true */
608 int8_t * p_in = (int8_t *)p_in_buf->p_buffer + i - 1;
609 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
613 *p_out = (float)(*p_in) / 128.0;
617 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
618 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);
621 /*****************************************************************************
623 *****************************************************************************/
624 static int Create_U8ToFL32( vlc_object_t *p_this )
626 aout_filter_t * p_filter = (aout_filter_t *)p_this;
628 if ( p_filter->input.i_format != VLC_FOURCC('u','8',' ',' ')
629 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
634 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
639 p_filter->pf_do_work = Do_U8ToFL32;
640 p_filter->b_in_place = VLC_TRUE;
645 static void Do_U8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
646 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
648 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
650 /* We start from the end because b_in_place is true */
651 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + i - 1;
652 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
656 *p_out = ((float)*p_in -128) / 128.0;
660 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
661 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);