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 *****************************************************************************/
33 #include <stdlib.h> /* malloc(), free() */
46 /*****************************************************************************
48 *****************************************************************************/
49 static int Create_F32ToFL32 ( vlc_object_t * );
50 static void Do_F32ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
52 static void Do_FL32ToF32 ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
55 static int Create_FL32ToS16 ( vlc_object_t * );
56 static void Do_FL32ToS16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
59 static int Create_FL32ToS8 ( vlc_object_t * );
60 static void Do_FL32ToS8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
63 static int Create_FL32ToU16 ( vlc_object_t * );
64 static void Do_FL32ToU16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
67 static int Create_FL32ToU8 ( vlc_object_t * );
68 static void Do_FL32ToU8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
71 static int Create_S16ToFL32( vlc_object_t * );
72 static void Do_S16ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
74 static void Do_S16ToFL24( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
77 static int Create_S16ToFL32_SW( vlc_object_t * );
78 static void Do_S16ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
80 static void Do_S16ToFL24_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
83 static int Create_S8ToFL32( vlc_object_t * );
84 static void Do_S8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
87 static int Create_U8ToFL32( vlc_object_t * );
88 static void Do_U8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
91 /*****************************************************************************
93 *****************************************************************************/
95 set_description( _("Floating-point audio format conversions") );
97 set_capability( "audio filter", 10 );
98 set_callbacks( Create_F32ToFL32, NULL );
100 set_capability( "audio filter", 1 );
101 set_callbacks( Create_FL32ToS16, NULL );
103 set_capability( "audio filter", 1 );
104 set_callbacks( Create_FL32ToS8, NULL );
106 set_capability( "audio filter", 1 );
107 set_callbacks( Create_FL32ToU16, NULL );
109 set_capability( "audio filter", 1 );
110 set_callbacks( Create_FL32ToU8, NULL );
112 set_capability( "audio filter", 1 );
113 set_callbacks( Create_S16ToFL32, NULL );
115 set_capability( "audio filter", 1 );
116 set_callbacks( Create_S16ToFL32_SW, NULL ); /* Endianness conversion*/
118 set_capability( "audio filter", 1 );
119 set_callbacks( Create_S8ToFL32, NULL );
121 set_capability( "audio filter", 1 );
122 set_callbacks( Create_U8ToFL32, NULL );
125 /*****************************************************************************
126 * Fixed 32 to Float 32 and backwards
127 *****************************************************************************/
128 static int Create_F32ToFL32( vlc_object_t *p_this )
130 aout_filter_t * p_filter = (aout_filter_t *)p_this;
132 if( ( p_filter->input.i_format != VLC_FOURCC('f','i','3','2')
133 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
134 && ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
135 || p_filter->output.i_format != VLC_FOURCC('f','i','3','2') ) )
140 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
145 if( p_filter->input.i_format == VLC_FOURCC('f','i','3','2') )
147 p_filter->pf_do_work = Do_F32ToFL32;
151 p_filter->pf_do_work = Do_FL32ToF32;
154 p_filter->b_in_place = 1;
159 static void Do_F32ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
160 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
163 vlc_fixed_t * p_in = (vlc_fixed_t *)p_in_buf->p_buffer;
164 float * p_out = (float *)p_out_buf->p_buffer;
166 for ( i = p_in_buf->i_nb_samples
167 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
169 *p_out++ = (float)*p_in++ / (float)FIXED32_ONE;
172 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
173 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
176 static void Do_FL32ToF32( aout_instance_t * p_aout, aout_filter_t * p_filter,
177 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
180 float * p_in = (float *)p_in_buf->p_buffer;
181 vlc_fixed_t * p_out = (vlc_fixed_t *)p_out_buf->p_buffer;
183 for ( i = p_in_buf->i_nb_samples
184 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
186 *p_out++ = (vlc_fixed_t)( *p_in++ * (float)FIXED32_ONE );
189 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
190 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
193 /*****************************************************************************
195 *****************************************************************************/
196 static int Create_FL32ToS16( vlc_object_t *p_this )
198 aout_filter_t * p_filter = (aout_filter_t *)p_this;
200 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
201 || p_filter->output.i_format != AOUT_FMT_S16_NE )
206 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
211 p_filter->pf_do_work = Do_FL32ToS16;
212 p_filter->b_in_place = 1;
217 static void Do_FL32ToS16( aout_instance_t * p_aout, aout_filter_t * p_filter,
218 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
221 float * p_in = (float *)p_in_buf->p_buffer;
222 int16_t * p_out = (int16_t *)p_out_buf->p_buffer;
224 for ( i = p_in_buf->i_nb_samples
225 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
229 if ( *p_in >= 1.0 ) *p_out = 32767;
230 else if ( *p_in < -1.0 ) *p_out = -32768;
231 else *p_out = *p_in * 32768.0;
233 /* This is walken's trick based on IEEE float format. */
234 union { float f; int32_t i; } u;
236 if ( u.i > 0x43c07fff ) *p_out = 32767;
237 else if ( u.i < 0x43bf8000 ) *p_out = -32768;
238 else *p_out = u.i - 0x43c00000;
243 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
244 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
247 /*****************************************************************************
249 *****************************************************************************/
250 static int Create_FL32ToS8( vlc_object_t *p_this )
252 aout_filter_t * p_filter = (aout_filter_t *)p_this;
254 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
255 || p_filter->output.i_format != VLC_FOURCC('s','8',' ',' ') )
260 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
265 p_filter->pf_do_work = Do_FL32ToS8;
266 p_filter->b_in_place = 1;
271 static void Do_FL32ToS8( aout_instance_t * p_aout, aout_filter_t * p_filter,
272 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
275 float * p_in = (float *)p_in_buf->p_buffer;
276 int8_t * p_out = (int8_t *)p_out_buf->p_buffer;
278 for ( i = p_in_buf->i_nb_samples
279 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
281 if ( *p_in >= 1.0 ) *p_out = 127;
282 else if ( *p_in < -1.0 ) *p_out = -128;
283 else *p_out = (int8_t)(*p_in * 128);
287 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
288 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
291 /*****************************************************************************
293 *****************************************************************************/
294 static int Create_FL32ToU16( vlc_object_t *p_this )
296 aout_filter_t * p_filter = (aout_filter_t *)p_this;
298 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
299 || p_filter->output.i_format != AOUT_FMT_U16_NE )
304 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
309 p_filter->pf_do_work = Do_FL32ToU16;
310 p_filter->b_in_place = 1;
315 static void Do_FL32ToU16( aout_instance_t * p_aout, aout_filter_t * p_filter,
316 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
319 float * p_in = (float *)p_in_buf->p_buffer;
320 uint16_t * p_out = (uint16_t *)p_out_buf->p_buffer;
322 for ( i = p_in_buf->i_nb_samples
323 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
325 if ( *p_in >= 1.0 ) *p_out = 65535;
326 else if ( *p_in < -1.0 ) *p_out = 0;
327 else *p_out = (uint16_t)(32768 + *p_in * 32768);
331 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
332 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
335 /*****************************************************************************
337 *****************************************************************************/
338 static int Create_FL32ToU8( vlc_object_t *p_this )
340 aout_filter_t * p_filter = (aout_filter_t *)p_this;
342 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
343 || p_filter->output.i_format != VLC_FOURCC('u','8',' ',' ') )
348 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
353 p_filter->pf_do_work = Do_FL32ToU8;
354 p_filter->b_in_place = 1;
359 static void Do_FL32ToU8( aout_instance_t * p_aout, aout_filter_t * p_filter,
360 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
363 float * p_in = (float *)p_in_buf->p_buffer;
364 uint8_t * p_out = (uint8_t *)p_out_buf->p_buffer;
366 for ( i = p_in_buf->i_nb_samples
367 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
369 if ( *p_in >= 1.0 ) *p_out = 255;
370 else if ( *p_in < -1.0 ) *p_out = 0;
371 else *p_out = (uint8_t)(128 + *p_in * 128);
375 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
376 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
379 /*****************************************************************************
381 *****************************************************************************/
382 static int Create_S16ToFL32( vlc_object_t *p_this )
384 aout_filter_t * p_filter = (aout_filter_t *)p_this;
386 if ( ( p_filter->input.i_format != AOUT_FMT_S16_NE &&
387 p_filter->input.i_format != AOUT_FMT_S24_NE )
388 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
393 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
398 if( p_filter->input.i_format == AOUT_FMT_S24_NE )
399 p_filter->pf_do_work = Do_S16ToFL24;
401 p_filter->pf_do_work = Do_S16ToFL32;
403 p_filter->b_in_place = VLC_TRUE;
408 static void Do_S16ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
409 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
411 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
413 /* We start from the end because b_in_place is true */
414 int16_t * p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
415 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
421 *p_out = (float)*p_in / 32768.0;
423 /* This is walken's trick based on IEEE float format. On my PIII
424 * this takes 16 seconds to perform one billion conversions, instead
425 * of 19 seconds for the above division. */
426 union { float f; int32_t i; } u;
427 u.i = *p_in + 0x43c00000;
428 *p_out = u.f - 384.0;
434 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
435 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
438 static void Do_S16ToFL24( aout_instance_t * p_aout, aout_filter_t * p_filter,
439 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
441 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
443 /* We start from the end because b_in_place is true */
444 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
445 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
449 #ifdef WORDS_BIGENDIAN
450 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in)) << 8) + p_in[2]))
452 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in+1)) << 8) + p_in[0]))
459 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
460 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
463 /*****************************************************************************
464 * S16 To Float32 with endianness conversion
465 *****************************************************************************/
466 static int Create_S16ToFL32_SW( vlc_object_t *p_this )
468 aout_filter_t * p_filter = (aout_filter_t *)p_this;
470 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
475 if ( (p_filter->input.i_format == VLC_FOURCC('s','1','6','l') ||
476 p_filter->input.i_format == VLC_FOURCC('s','1','6','b'))
477 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
478 && p_filter->input.i_format != AOUT_FMT_S16_NE )
480 p_filter->pf_do_work = Do_S16ToFL32_SW;
481 p_filter->b_in_place = VLC_TRUE;
486 if ( (p_filter->input.i_format == VLC_FOURCC('s','2','4','l') ||
487 p_filter->input.i_format == VLC_FOURCC('s','2','4','b'))
488 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
489 && p_filter->input.i_format != AOUT_FMT_S24_NE )
491 p_filter->pf_do_work = Do_S16ToFL24_SW;
492 p_filter->b_in_place = VLC_TRUE;
499 static void Do_S16ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
500 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
502 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
504 /* We start from the end because b_in_place is true */
506 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
510 int16_t * p_swabbed = alloca( i * sizeof(int16_t) );
512 int16_t * p_swabbed = malloc( i * sizeof(int16_t) );
515 swab( p_in_buf->p_buffer, (void *)p_swabbed, i * sizeof(int16_t) );
516 p_in = p_swabbed + i - 1;
520 p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
526 p_tmp[0] = ((byte_t *)p_in)[1];
527 p_tmp[1] = ((byte_t *)p_in)[0];
528 *p_out = (float)( *(int16_t *)p_tmp ) / 32768.0;
530 *p_out = (float)*p_in / 32768.0;
541 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
542 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
545 static void Do_S16ToFL24_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
546 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 */
551 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
552 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
562 #ifdef WORDS_BIGENDIAN
563 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp)) << 8) + p_tmp[2]))
565 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp+1)) << 8) + p_tmp[0]))
572 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
573 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
576 /*****************************************************************************
578 *****************************************************************************/
579 static int Create_S8ToFL32( vlc_object_t *p_this )
581 aout_filter_t * p_filter = (aout_filter_t *)p_this;
583 if ( p_filter->input.i_format != VLC_FOURCC('s','8',' ',' ')
584 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
589 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
594 p_filter->pf_do_work = Do_S8ToFL32;
595 p_filter->b_in_place = VLC_TRUE;
600 static void Do_S8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
601 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
603 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
605 /* We start from the end because b_in_place is true */
606 int8_t * p_in = (int8_t *)p_in_buf->p_buffer + i - 1;
607 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
611 *p_out = (float)(*p_in) / 128.0;
615 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
616 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);
619 /*****************************************************************************
621 *****************************************************************************/
622 static int Create_U8ToFL32( vlc_object_t *p_this )
624 aout_filter_t * p_filter = (aout_filter_t *)p_this;
626 if ( p_filter->input.i_format != VLC_FOURCC('u','8',' ',' ')
627 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
632 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
637 p_filter->pf_do_work = Do_U8ToFL32;
638 p_filter->b_in_place = VLC_TRUE;
643 static void Do_U8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
644 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
646 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
648 /* We start from the end because b_in_place is true */
649 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + i - 1;
650 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
654 *p_out = ((float)*p_in -128) / 128.0;
658 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
659 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);