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 *****************************************************************************/
44 /*****************************************************************************
46 *****************************************************************************/
47 static int Create_F32ToFL32 ( vlc_object_t * );
48 static void Do_F32ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
50 static void Do_FL32ToF32 ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
53 static int Create_FL32ToS16 ( vlc_object_t * );
54 static void Do_FL32ToS16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
57 static int Create_FL32ToS8 ( vlc_object_t * );
58 static void Do_FL32ToS8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
61 static int Create_FL32ToU16 ( vlc_object_t * );
62 static void Do_FL32ToU16( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
65 static int Create_FL32ToU8 ( vlc_object_t * );
66 static void Do_FL32ToU8( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
69 static int Create_S16ToFL32( vlc_object_t * );
70 static void Do_S16ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
72 static void Do_S16ToFL24( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
75 static int Create_S16ToFL32_SW( vlc_object_t * );
76 static void Do_S16ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
78 static void Do_S16ToFL24_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
81 static int Create_S8ToFL32( vlc_object_t * );
82 static void Do_S8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
85 static int Create_U8ToFL32( vlc_object_t * );
86 static void Do_U8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
89 /*****************************************************************************
91 *****************************************************************************/
93 set_description( _("Floating-point audio format conversions") );
95 set_capability( "audio filter", 10 );
96 set_callbacks( Create_F32ToFL32, NULL );
98 set_capability( "audio filter", 1 );
99 set_callbacks( Create_FL32ToS16, NULL );
101 set_capability( "audio filter", 1 );
102 set_callbacks( Create_FL32ToS8, NULL );
104 set_capability( "audio filter", 1 );
105 set_callbacks( Create_FL32ToU16, NULL );
107 set_capability( "audio filter", 1 );
108 set_callbacks( Create_FL32ToU8, NULL );
110 set_capability( "audio filter", 1 );
111 set_callbacks( Create_S16ToFL32, NULL );
113 set_capability( "audio filter", 1 );
114 set_callbacks( Create_S16ToFL32_SW, NULL ); /* Endianness conversion*/
116 set_capability( "audio filter", 1 );
117 set_callbacks( Create_S8ToFL32, NULL );
119 set_capability( "audio filter", 1 );
120 set_callbacks( Create_U8ToFL32, NULL );
123 /*****************************************************************************
124 * Fixed 32 to Float 32 and backwards
125 *****************************************************************************/
126 static int Create_F32ToFL32( vlc_object_t *p_this )
128 aout_filter_t * p_filter = (aout_filter_t *)p_this;
130 if( ( p_filter->input.i_format != VLC_FOURCC('f','i','3','2')
131 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
132 && ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
133 || p_filter->output.i_format != VLC_FOURCC('f','i','3','2') ) )
138 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
143 if( p_filter->input.i_format == VLC_FOURCC('f','i','3','2') )
145 p_filter->pf_do_work = Do_F32ToFL32;
149 p_filter->pf_do_work = Do_FL32ToF32;
152 p_filter->b_in_place = 1;
157 static void Do_F32ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
158 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
161 vlc_fixed_t * p_in = (vlc_fixed_t *)p_in_buf->p_buffer;
162 float * p_out = (float *)p_out_buf->p_buffer;
164 for ( i = p_in_buf->i_nb_samples
165 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
167 *p_out++ = (float)*p_in++ / (float)FIXED32_ONE;
170 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
171 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
174 static void Do_FL32ToF32( aout_instance_t * p_aout, aout_filter_t * p_filter,
175 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
178 float * p_in = (float *)p_in_buf->p_buffer;
179 vlc_fixed_t * p_out = (vlc_fixed_t *)p_out_buf->p_buffer;
181 for ( i = p_in_buf->i_nb_samples
182 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
184 *p_out++ = (vlc_fixed_t)( *p_in++ * (float)FIXED32_ONE );
187 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
188 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
191 /*****************************************************************************
193 *****************************************************************************/
194 static int Create_FL32ToS16( vlc_object_t *p_this )
196 aout_filter_t * p_filter = (aout_filter_t *)p_this;
198 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
199 || p_filter->output.i_format != AOUT_FMT_S16_NE )
204 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
209 p_filter->pf_do_work = Do_FL32ToS16;
210 p_filter->b_in_place = 1;
215 static void Do_FL32ToS16( aout_instance_t * p_aout, aout_filter_t * p_filter,
216 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
219 float * p_in = (float *)p_in_buf->p_buffer;
220 int16_t * p_out = (int16_t *)p_out_buf->p_buffer;
222 for ( i = p_in_buf->i_nb_samples
223 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
227 if ( *p_in >= 1.0 ) *p_out = 32767;
228 else if ( *p_in < -1.0 ) *p_out = -32768;
229 else *p_out = *p_in * 32768.0;
231 /* This is walken's trick based on IEEE float format. */
232 union { float f; int32_t i; } u;
234 if ( u.i > 0x43c07fff ) *p_out = 32767;
235 else if ( u.i < 0x43bf8000 ) *p_out = -32768;
236 else *p_out = u.i - 0x43c00000;
241 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
242 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
245 /*****************************************************************************
247 *****************************************************************************/
248 static int Create_FL32ToS8( vlc_object_t *p_this )
250 aout_filter_t * p_filter = (aout_filter_t *)p_this;
252 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
253 || p_filter->output.i_format != VLC_FOURCC('s','8',' ',' ') )
258 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
263 p_filter->pf_do_work = Do_FL32ToS8;
264 p_filter->b_in_place = 1;
269 static void Do_FL32ToS8( aout_instance_t * p_aout, aout_filter_t * p_filter,
270 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
273 float * p_in = (float *)p_in_buf->p_buffer;
274 int8_t * p_out = (int8_t *)p_out_buf->p_buffer;
276 for ( i = p_in_buf->i_nb_samples
277 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
279 if ( *p_in >= 1.0 ) *p_out = 127;
280 else if ( *p_in < -1.0 ) *p_out = -128;
281 else *p_out = (int8_t)(*p_in * 128);
285 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
286 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
289 /*****************************************************************************
291 *****************************************************************************/
292 static int Create_FL32ToU16( vlc_object_t *p_this )
294 aout_filter_t * p_filter = (aout_filter_t *)p_this;
296 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
297 || p_filter->output.i_format != AOUT_FMT_U16_NE )
302 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
307 p_filter->pf_do_work = Do_FL32ToU16;
308 p_filter->b_in_place = 1;
313 static void Do_FL32ToU16( aout_instance_t * p_aout, aout_filter_t * p_filter,
314 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
317 float * p_in = (float *)p_in_buf->p_buffer;
318 uint16_t * p_out = (uint16_t *)p_out_buf->p_buffer;
320 for ( i = p_in_buf->i_nb_samples
321 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
323 if ( *p_in >= 1.0 ) *p_out = 65535;
324 else if ( *p_in < -1.0 ) *p_out = 0;
325 else *p_out = (uint16_t)(32768 + *p_in * 32768);
329 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
330 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
333 /*****************************************************************************
335 *****************************************************************************/
336 static int Create_FL32ToU8( vlc_object_t *p_this )
338 aout_filter_t * p_filter = (aout_filter_t *)p_this;
340 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
341 || p_filter->output.i_format != VLC_FOURCC('u','8',' ',' ') )
346 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
351 p_filter->pf_do_work = Do_FL32ToU8;
352 p_filter->b_in_place = 1;
357 static void Do_FL32ToU8( aout_instance_t * p_aout, aout_filter_t * p_filter,
358 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
361 float * p_in = (float *)p_in_buf->p_buffer;
362 uint8_t * p_out = (uint8_t *)p_out_buf->p_buffer;
364 for ( i = p_in_buf->i_nb_samples
365 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
367 if ( *p_in >= 1.0 ) *p_out = 255;
368 else if ( *p_in < -1.0 ) *p_out = 0;
369 else *p_out = (uint8_t)(128 + *p_in * 128);
373 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
374 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
377 /*****************************************************************************
379 *****************************************************************************/
380 static int Create_S16ToFL32( vlc_object_t *p_this )
382 aout_filter_t * p_filter = (aout_filter_t *)p_this;
384 if ( ( p_filter->input.i_format != AOUT_FMT_S16_NE &&
385 p_filter->input.i_format != AOUT_FMT_S24_NE )
386 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
391 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
396 if( p_filter->input.i_format == AOUT_FMT_S24_NE )
397 p_filter->pf_do_work = Do_S16ToFL24;
399 p_filter->pf_do_work = Do_S16ToFL32;
401 p_filter->b_in_place = VLC_TRUE;
406 static void Do_S16ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
407 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
409 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
411 /* We start from the end because b_in_place is true */
412 int16_t * p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
413 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
419 *p_out = (float)*p_in / 32768.0;
421 /* This is walken's trick based on IEEE float format. On my PIII
422 * this takes 16 seconds to perform one billion conversions, instead
423 * of 19 seconds for the above division. */
424 union { float f; int32_t i; } u;
425 u.i = *p_in + 0x43c00000;
426 *p_out = u.f - 384.0;
432 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
433 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
436 static void Do_S16ToFL24( aout_instance_t * p_aout, aout_filter_t * p_filter,
437 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
439 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
441 /* We start from the end because b_in_place is true */
442 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
443 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
447 #ifdef WORDS_BIGENDIAN
448 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in)) << 8) + p_in[2]))
450 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in+1)) << 8) + p_in[0]))
457 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
458 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
461 /*****************************************************************************
462 * S16 To Float32 with endianness conversion
463 *****************************************************************************/
464 static int Create_S16ToFL32_SW( vlc_object_t *p_this )
466 aout_filter_t * p_filter = (aout_filter_t *)p_this;
468 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
473 if ( (p_filter->input.i_format == VLC_FOURCC('s','1','6','l') ||
474 p_filter->input.i_format == VLC_FOURCC('s','1','6','b'))
475 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
476 && p_filter->input.i_format != AOUT_FMT_S16_NE )
478 p_filter->pf_do_work = Do_S16ToFL32_SW;
479 p_filter->b_in_place = VLC_TRUE;
484 if ( (p_filter->input.i_format == VLC_FOURCC('s','2','4','l') ||
485 p_filter->input.i_format == VLC_FOURCC('s','2','4','b'))
486 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
487 && p_filter->input.i_format != AOUT_FMT_S24_NE )
489 p_filter->pf_do_work = Do_S16ToFL24_SW;
490 p_filter->b_in_place = VLC_TRUE;
497 static void Do_S16ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
498 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
500 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
502 /* We start from the end because b_in_place is true */
504 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
508 int16_t * p_swabbed = alloca( i * sizeof(int16_t) );
510 int16_t * p_swabbed = malloc( i * sizeof(int16_t) );
513 swab( p_in_buf->p_buffer, (void *)p_swabbed, i * sizeof(int16_t) );
514 p_in = p_swabbed + i - 1;
518 p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
524 p_tmp[0] = ((byte_t *)p_in)[1];
525 p_tmp[1] = ((byte_t *)p_in)[0];
526 *p_out = (float)( *(int16_t *)p_tmp ) / 32768.0;
528 *p_out = (float)*p_in / 32768.0;
539 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
540 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 2;
543 static void Do_S16ToFL24_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
544 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
546 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
548 /* We start from the end because b_in_place is true */
549 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
550 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
560 #ifdef WORDS_BIGENDIAN
561 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp)) << 8) + p_tmp[2]))
563 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp+1)) << 8) + p_tmp[0]))
570 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
571 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
574 /*****************************************************************************
576 *****************************************************************************/
577 static int Create_S8ToFL32( vlc_object_t *p_this )
579 aout_filter_t * p_filter = (aout_filter_t *)p_this;
581 if ( p_filter->input.i_format != VLC_FOURCC('s','8',' ',' ')
582 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
587 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
592 p_filter->pf_do_work = Do_S8ToFL32;
593 p_filter->b_in_place = VLC_TRUE;
598 static void Do_S8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
599 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
601 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
603 /* We start from the end because b_in_place is true */
604 int8_t * p_in = (int8_t *)p_in_buf->p_buffer + i - 1;
605 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
609 *p_out = (float)(*p_in) / 128.0;
613 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
614 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);
617 /*****************************************************************************
619 *****************************************************************************/
620 static int Create_U8ToFL32( vlc_object_t *p_this )
622 aout_filter_t * p_filter = (aout_filter_t *)p_this;
624 if ( p_filter->input.i_format != VLC_FOURCC('u','8',' ',' ')
625 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
630 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
635 p_filter->pf_do_work = Do_U8ToFL32;
636 p_filter->b_in_place = VLC_TRUE;
641 static void Do_U8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
642 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
644 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
646 /* We start from the end because b_in_place is true */
647 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + i - 1;
648 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
652 *p_out = ((float)*p_in -128) / 128.0;
656 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
657 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);