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 *****************************************************************************/
37 #include <vlc_plugin.h>
49 /*****************************************************************************
51 *****************************************************************************/
52 static int Create_F32ToFL32 ( vlc_object_t * );
53 static void Do_F32ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
55 static void Do_FL32ToF32 ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
58 static int Create_FL32ToS16 ( vlc_object_t * );
59 static void Do_FL32ToS16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
62 static int Create_FL32ToS8 ( vlc_object_t * );
63 static void Do_FL32ToS8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
66 static int Create_FL32ToU16 ( vlc_object_t * );
67 static void Do_FL32ToU16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
70 static int Create_FL32ToU8 ( vlc_object_t * );
71 static void Do_FL32ToU8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
74 static int Create_S16ToFL32( vlc_object_t * );
75 static void Do_S16ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
77 static void Do_S16ToFL24( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
80 static int Create_S16ToFL32_SW( vlc_object_t * );
81 static void Do_S16ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
83 static void Do_S16ToFL24_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( _("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->output.i_format != VLC_FOURCC('f','l','3','2') )
402 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
407 if( p_filter->input.i_format == AOUT_FMT_S24_NE )
408 p_filter->pf_do_work = Do_S16ToFL24;
410 p_filter->pf_do_work = Do_S16ToFL32;
412 p_filter->b_in_place = true;
417 static void Do_S16ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
418 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
421 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
423 /* We start from the end because b_in_place is true */
424 int16_t * p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
425 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
431 *p_out = (float)*p_in / 32768.0;
433 /* This is walken's trick based on IEEE float format. On my PIII
434 * this takes 16 seconds to perform one billion conversions, instead
435 * of 19 seconds for the above division. */
436 union { float f; int32_t i; } u;
437 u.i = *p_in + 0x43c00000;
438 *p_out = u.f - 384.0;
444 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
445 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
448 static void Do_S16ToFL24( aout_instance_t * p_aout, aout_filter_t * p_filter,
449 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
452 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
454 /* We start from the end because b_in_place is true */
455 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
456 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
460 #ifdef WORDS_BIGENDIAN
461 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in)) << 8) + p_in[2]))
463 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in+1)) << 8) + p_in[0]))
470 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
471 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
474 /*****************************************************************************
475 * S16 To Float32 with endianness conversion
476 *****************************************************************************/
477 static int Create_S16ToFL32_SW( vlc_object_t *p_this )
479 aout_filter_t * p_filter = (aout_filter_t *)p_this;
481 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
486 if ( (p_filter->input.i_format == VLC_FOURCC('s','1','6','l') ||
487 p_filter->input.i_format == VLC_FOURCC('s','1','6','b'))
488 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
489 && p_filter->input.i_format != AOUT_FMT_S16_NE )
491 p_filter->pf_do_work = Do_S16ToFL32_SW;
492 p_filter->b_in_place = true;
497 if ( (p_filter->input.i_format == VLC_FOURCC('s','2','4','l') ||
498 p_filter->input.i_format == VLC_FOURCC('s','2','4','b'))
499 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
500 && p_filter->input.i_format != AOUT_FMT_S24_NE )
502 p_filter->pf_do_work = Do_S16ToFL24_SW;
503 p_filter->b_in_place = true;
510 static void Do_S16ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
511 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
514 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
516 /* We start from the end because b_in_place is true */
518 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
522 int16_t * p_swabbed = alloca( i * sizeof(int16_t) );
524 int16_t * p_swabbed = malloc( i * sizeof(int16_t) );
527 swab( p_in_buf->p_buffer, (void *)p_swabbed, i * sizeof(int16_t) );
528 p_in = p_swabbed + i - 1;
532 p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
538 p_tmp[0] = ((uint8_t *)p_in)[1];
539 p_tmp[1] = ((uint8_t *)p_in)[0];
540 *p_out = (float)( *(int16_t *)p_tmp ) / 32768.0;
542 *p_out = (float)*p_in / 32768.0;
553 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
554 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
557 static void Do_S16ToFL24_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
558 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
561 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
563 /* We start from the end because b_in_place is true */
564 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
565 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
575 #ifdef WORDS_BIGENDIAN
576 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp)) << 8) + p_tmp[2]))
578 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp+1)) << 8) + p_tmp[0]))
585 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
586 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
589 /*****************************************************************************
591 *****************************************************************************/
592 static int Create_S8ToFL32( vlc_object_t *p_this )
594 aout_filter_t * p_filter = (aout_filter_t *)p_this;
596 if ( p_filter->input.i_format != VLC_FOURCC('s','8',' ',' ')
597 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
602 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
607 p_filter->pf_do_work = Do_S8ToFL32;
608 p_filter->b_in_place = true;
613 static void Do_S8ToFL32( 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 int8_t * p_in = (int8_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) / 128.0;
629 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
630 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);
633 /*****************************************************************************
635 *****************************************************************************/
636 static int Create_U8ToFL32( 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('u','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_U8ToFL32;
652 p_filter->b_in_place = true;
657 static void Do_U8ToFL32( 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 uint8_t * p_in = (uint8_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) / 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);