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 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
45 /*****************************************************************************
47 *****************************************************************************/
48 static int Create_F32ToFL32 ( vlc_object_t * );
49 static void Do_F32ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
51 static void Do_FL32ToF32 ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
54 static int Create_FL32ToS16 ( vlc_object_t * );
55 static void Do_FL32ToS16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
58 static int Create_FL32ToS8 ( vlc_object_t * );
59 static void Do_FL32ToS8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
62 static int Create_FL32ToU16 ( vlc_object_t * );
63 static void Do_FL32ToU16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
66 static int Create_FL32ToU8 ( vlc_object_t * );
67 static void Do_FL32ToU8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
70 static int Create_S16ToFL32( vlc_object_t * );
71 static void Do_S16ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
73 static void Do_S24ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
75 static void Do_S32ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
78 static int Create_S16ToFL32_SW( vlc_object_t * );
79 static void Do_S16ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
81 static void Do_S24ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
83 static void Do_S32ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
86 static int Create_S8ToFL32( vlc_object_t * );
87 static void Do_S8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
90 static int Create_U8ToFL32( vlc_object_t * );
91 static void Do_U8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
94 /*****************************************************************************
96 *****************************************************************************/
98 set_description( N_("Floating-point audio format conversions") )
100 set_capability( "audio filter", 10 )
101 set_callbacks( Create_F32ToFL32, NULL )
103 set_capability( "audio filter", 1 )
104 set_callbacks( Create_FL32ToS16, NULL )
106 set_capability( "audio filter", 1 )
107 set_callbacks( Create_FL32ToS8, NULL )
109 set_capability( "audio filter", 1 )
110 set_callbacks( Create_FL32ToU16, NULL )
112 set_capability( "audio filter", 1 )
113 set_callbacks( Create_FL32ToU8, NULL )
115 set_capability( "audio filter", 1 )
116 set_callbacks( Create_S16ToFL32, NULL )
118 set_capability( "audio filter", 1 )
119 set_callbacks( Create_S16ToFL32_SW, NULL ) /* Endianness conversion*/
121 set_capability( "audio filter", 1 )
122 set_callbacks( Create_S8ToFL32, NULL )
124 set_capability( "audio filter", 1 )
125 set_callbacks( Create_U8ToFL32, NULL )
128 /*****************************************************************************
129 * Fixed 32 to Float 32 and backwards
130 *****************************************************************************/
131 static int Create_F32ToFL32( vlc_object_t *p_this )
133 aout_filter_t * p_filter = (aout_filter_t *)p_this;
135 if( ( p_filter->input.i_format != VLC_FOURCC('f','i','3','2')
136 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
137 && ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
138 || p_filter->output.i_format != VLC_FOURCC('f','i','3','2') ) )
143 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
148 if( p_filter->input.i_format == VLC_FOURCC('f','i','3','2') )
150 p_filter->pf_do_work = Do_F32ToFL32;
154 p_filter->pf_do_work = Do_FL32ToF32;
157 p_filter->b_in_place = 1;
162 static void Do_F32ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
163 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
167 vlc_fixed_t * p_in = (vlc_fixed_t *)p_in_buf->p_buffer;
168 float * p_out = (float *)p_out_buf->p_buffer;
170 for ( i = p_in_buf->i_nb_samples
171 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
173 *p_out++ = (float)*p_in++ / (float)FIXED32_ONE;
176 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
177 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
180 static void Do_FL32ToF32( aout_instance_t * p_aout, aout_filter_t * p_filter,
181 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
185 float * p_in = (float *)p_in_buf->p_buffer;
186 vlc_fixed_t * p_out = (vlc_fixed_t *)p_out_buf->p_buffer;
188 for ( i = p_in_buf->i_nb_samples
189 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
191 *p_out++ = (vlc_fixed_t)( *p_in++ * (float)FIXED32_ONE );
194 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
195 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
198 /*****************************************************************************
200 *****************************************************************************/
201 static int Create_FL32ToS16( vlc_object_t *p_this )
203 aout_filter_t * p_filter = (aout_filter_t *)p_this;
205 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
206 || p_filter->output.i_format != AOUT_FMT_S16_NE )
211 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
216 p_filter->pf_do_work = Do_FL32ToS16;
217 p_filter->b_in_place = 1;
222 static void Do_FL32ToS16( aout_instance_t * p_aout, aout_filter_t * p_filter,
223 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
227 float * p_in = (float *)p_in_buf->p_buffer;
228 int16_t * p_out = (int16_t *)p_out_buf->p_buffer;
230 for ( i = p_in_buf->i_nb_samples
231 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
235 if ( *p_in >= 1.0 ) *p_out = 32767;
236 else if ( *p_in < -1.0 ) *p_out = -32768;
237 else *p_out = *p_in * 32768.0;
239 /* This is walken's trick based on IEEE float format. */
240 union { float f; int32_t i; } u;
242 if ( u.i > 0x43c07fff ) *p_out = 32767;
243 else if ( u.i < 0x43bf8000 ) *p_out = -32768;
244 else *p_out = u.i - 0x43c00000;
249 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
250 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
253 /*****************************************************************************
255 *****************************************************************************/
256 static int Create_FL32ToS8( vlc_object_t *p_this )
258 aout_filter_t * p_filter = (aout_filter_t *)p_this;
260 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
261 || p_filter->output.i_format != VLC_FOURCC('s','8',' ',' ') )
266 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
271 p_filter->pf_do_work = Do_FL32ToS8;
272 p_filter->b_in_place = 1;
277 static void Do_FL32ToS8( aout_instance_t * p_aout, aout_filter_t * p_filter,
278 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
282 float * p_in = (float *)p_in_buf->p_buffer;
283 int8_t * p_out = (int8_t *)p_out_buf->p_buffer;
285 for ( i = p_in_buf->i_nb_samples
286 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
288 if ( *p_in >= 1.0 ) *p_out = 127;
289 else if ( *p_in < -1.0 ) *p_out = -128;
290 else *p_out = (int8_t)(*p_in * 128);
294 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
295 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
298 /*****************************************************************************
300 *****************************************************************************/
301 static int Create_FL32ToU16( vlc_object_t *p_this )
303 aout_filter_t * p_filter = (aout_filter_t *)p_this;
305 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
306 || p_filter->output.i_format != AOUT_FMT_U16_NE )
311 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
316 p_filter->pf_do_work = Do_FL32ToU16;
317 p_filter->b_in_place = 1;
322 static void Do_FL32ToU16( aout_instance_t * p_aout, aout_filter_t * p_filter,
323 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
327 float * p_in = (float *)p_in_buf->p_buffer;
328 uint16_t * p_out = (uint16_t *)p_out_buf->p_buffer;
330 for ( i = p_in_buf->i_nb_samples
331 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
333 if ( *p_in >= 1.0 ) *p_out = 65535;
334 else if ( *p_in < -1.0 ) *p_out = 0;
335 else *p_out = (uint16_t)(32768 + *p_in * 32768);
339 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
340 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
343 /*****************************************************************************
345 *****************************************************************************/
346 static int Create_FL32ToU8( vlc_object_t *p_this )
348 aout_filter_t * p_filter = (aout_filter_t *)p_this;
350 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
351 || p_filter->output.i_format != VLC_FOURCC('u','8',' ',' ') )
356 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
361 p_filter->pf_do_work = Do_FL32ToU8;
362 p_filter->b_in_place = 1;
367 static void Do_FL32ToU8( aout_instance_t * p_aout, aout_filter_t * p_filter,
368 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
372 float * p_in = (float *)p_in_buf->p_buffer;
373 uint8_t * p_out = (uint8_t *)p_out_buf->p_buffer;
375 for ( i = p_in_buf->i_nb_samples
376 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
378 if ( *p_in >= 1.0 ) *p_out = 255;
379 else if ( *p_in < -1.0 ) *p_out = 0;
380 else *p_out = (uint8_t)(128 + *p_in * 128);
384 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
385 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
388 /*****************************************************************************
390 *****************************************************************************/
391 static int Create_S16ToFL32( vlc_object_t *p_this )
393 aout_filter_t * p_filter = (aout_filter_t *)p_this;
395 if ( ( p_filter->input.i_format != AOUT_FMT_S16_NE &&
396 p_filter->input.i_format != AOUT_FMT_S24_NE &&
397 p_filter->input.i_format != AOUT_FMT_S32_NE )
398 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
403 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
408 if( p_filter->input.i_format == AOUT_FMT_S32_NE )
409 p_filter->pf_do_work = Do_S32ToFL32;
410 else if( p_filter->input.i_format == AOUT_FMT_S24_NE )
411 p_filter->pf_do_work = Do_S24ToFL32;
413 p_filter->pf_do_work = Do_S16ToFL32;
415 p_filter->b_in_place = true;
420 static void Do_S16ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
421 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
424 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
426 /* We start from the end because b_in_place is true */
427 int16_t * p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
428 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
434 *p_out = (float)*p_in / 32768.0;
436 /* This is walken's trick based on IEEE float format. On my PIII
437 * this takes 16 seconds to perform one billion conversions, instead
438 * of 19 seconds for the above division. */
439 union { float f; int32_t i; } u;
440 u.i = *p_in + 0x43c00000;
441 *p_out = u.f - 384.0;
447 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
448 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 2;
451 static void Do_S24ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
452 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
455 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
457 /* We start from the end because b_in_place is true */
458 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
459 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
463 #ifdef WORDS_BIGENDIAN
464 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in)) << 8) + p_in[2]))
466 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in+1)) << 8) + p_in[0]))
473 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
474 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
477 static void Do_S32ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
478 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
481 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
483 /* We start from the end because b_in_place is true */
484 int32_t * p_in = (int32_t *)p_in_buf->p_buffer + i - 1;
485 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
489 *p_out-- = (float)*p_in-- / 2147483648.0;
492 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
493 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 4;
496 /*****************************************************************************
497 * S16 To Float32 with endianness conversion
498 *****************************************************************************/
499 static int Create_S16ToFL32_SW( vlc_object_t *p_this )
501 aout_filter_t * p_filter = (aout_filter_t *)p_this;
503 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
508 if ( (p_filter->input.i_format == VLC_FOURCC('s','1','6','l') ||
509 p_filter->input.i_format == VLC_FOURCC('s','1','6','b'))
510 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
511 && p_filter->input.i_format != AOUT_FMT_S16_NE )
513 p_filter->pf_do_work = Do_S16ToFL32_SW;
514 p_filter->b_in_place = true;
519 if ( (p_filter->input.i_format == VLC_FOURCC('s','2','4','l') ||
520 p_filter->input.i_format == VLC_FOURCC('s','2','4','b'))
521 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
522 && p_filter->input.i_format != AOUT_FMT_S24_NE )
524 p_filter->pf_do_work = Do_S24ToFL32_SW;
525 p_filter->b_in_place = true;
530 if ( (p_filter->input.i_format == VLC_FOURCC('s','3','2','l') ||
531 p_filter->input.i_format == VLC_FOURCC('s','3','2','b'))
532 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
533 && p_filter->input.i_format != AOUT_FMT_S32_NE )
535 p_filter->pf_do_work = Do_S32ToFL32_SW;
536 p_filter->b_in_place = true;
544 static void Do_S16ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
545 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
548 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
550 /* We start from the end because b_in_place is true */
552 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
555 int16_t p_swabbed[i];
557 swab( p_in_buf->p_buffer, p_swabbed, i * sizeof(int16_t) );
558 p_in = p_swabbed + i - 1;
562 p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
568 p_tmp[0] = ((uint8_t *)p_in)[1];
569 p_tmp[1] = ((uint8_t *)p_in)[0];
570 *p_out = (float)( *(int16_t *)p_tmp ) / 32768.0;
572 *p_out = (float)*p_in / 32768.0;
577 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
578 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 2;
581 static void Do_S24ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
582 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
585 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
587 /* We start from the end because b_in_place is true */
588 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
589 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
599 #ifdef WORDS_BIGENDIAN
600 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp)) << 8) + p_tmp[2]))
602 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp+1)) << 8) + p_tmp[0]))
609 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
610 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
613 static void Do_S32ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
614 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
617 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
619 /* We start from the end because b_in_place is true */
620 int32_t * p_in = (int32_t *)p_in_buf->p_buffer + i - 1;
621 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
625 *p_out-- = (float)*p_in-- / 2147483648.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 * 4 / 4;
633 /*****************************************************************************
635 *****************************************************************************/
636 static int Create_S8ToFL32( vlc_object_t *p_this )
638 aout_filter_t * p_filter = (aout_filter_t *)p_this;
640 if ( p_filter->input.i_format != VLC_FOURCC('s','8',' ',' ')
641 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
646 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
651 p_filter->pf_do_work = Do_S8ToFL32;
652 p_filter->b_in_place = true;
657 static void Do_S8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
658 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
661 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
663 /* We start from the end because b_in_place is true */
664 int8_t * p_in = (int8_t *)p_in_buf->p_buffer + i - 1;
665 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
669 *p_out = (float)(*p_in) / 128.0;
673 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
674 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);
677 /*****************************************************************************
679 *****************************************************************************/
680 static int Create_U8ToFL32( vlc_object_t *p_this )
682 aout_filter_t * p_filter = (aout_filter_t *)p_this;
684 if ( p_filter->input.i_format != VLC_FOURCC('u','8',' ',' ')
685 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
690 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
695 p_filter->pf_do_work = Do_U8ToFL32;
696 p_filter->b_in_place = true;
701 static void Do_U8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
702 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
705 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
707 /* We start from the end because b_in_place is true */
708 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + i - 1;
709 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
713 *p_out = ((float)*p_in -128) / 128.0;
717 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
718 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);