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>
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_S24ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
79 static void Do_S32ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
82 static int Create_S16ToFL32_SW( vlc_object_t * );
83 static void Do_S16ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
85 static void Do_S24ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
87 static void Do_S32ToFL32_SW( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
90 static int Create_S8ToFL32( vlc_object_t * );
91 static void Do_S8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
94 static int Create_U8ToFL32( vlc_object_t * );
95 static void Do_U8ToFL32( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
98 /*****************************************************************************
100 *****************************************************************************/
102 set_description( N_("Floating-point audio format conversions") )
104 set_capability( "audio filter", 10 )
105 set_callbacks( Create_F32ToFL32, NULL )
107 set_capability( "audio filter", 1 )
108 set_callbacks( Create_FL32ToS16, NULL )
110 set_capability( "audio filter", 1 )
111 set_callbacks( Create_FL32ToS8, NULL )
113 set_capability( "audio filter", 1 )
114 set_callbacks( Create_FL32ToU16, NULL )
116 set_capability( "audio filter", 1 )
117 set_callbacks( Create_FL32ToU8, NULL )
119 set_capability( "audio filter", 1 )
120 set_callbacks( Create_S16ToFL32, NULL )
122 set_capability( "audio filter", 1 )
123 set_callbacks( Create_S16ToFL32_SW, NULL ) /* Endianness conversion*/
125 set_capability( "audio filter", 1 )
126 set_callbacks( Create_S8ToFL32, NULL )
128 set_capability( "audio filter", 1 )
129 set_callbacks( Create_U8ToFL32, NULL )
132 /*****************************************************************************
133 * Fixed 32 to Float 32 and backwards
134 *****************************************************************************/
135 static int Create_F32ToFL32( vlc_object_t *p_this )
137 aout_filter_t * p_filter = (aout_filter_t *)p_this;
139 if( ( p_filter->input.i_format != VLC_FOURCC('f','i','3','2')
140 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
141 && ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
142 || p_filter->output.i_format != VLC_FOURCC('f','i','3','2') ) )
147 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
152 if( p_filter->input.i_format == VLC_FOURCC('f','i','3','2') )
154 p_filter->pf_do_work = Do_F32ToFL32;
158 p_filter->pf_do_work = Do_FL32ToF32;
161 p_filter->b_in_place = 1;
166 static void Do_F32ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
167 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
171 vlc_fixed_t * p_in = (vlc_fixed_t *)p_in_buf->p_buffer;
172 float * p_out = (float *)p_out_buf->p_buffer;
174 for ( i = p_in_buf->i_nb_samples
175 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
177 *p_out++ = (float)*p_in++ / (float)FIXED32_ONE;
180 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
181 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
184 static void Do_FL32ToF32( aout_instance_t * p_aout, aout_filter_t * p_filter,
185 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
189 float * p_in = (float *)p_in_buf->p_buffer;
190 vlc_fixed_t * p_out = (vlc_fixed_t *)p_out_buf->p_buffer;
192 for ( i = p_in_buf->i_nb_samples
193 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
195 *p_out++ = (vlc_fixed_t)( *p_in++ * (float)FIXED32_ONE );
198 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
199 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
202 /*****************************************************************************
204 *****************************************************************************/
205 static int Create_FL32ToS16( vlc_object_t *p_this )
207 aout_filter_t * p_filter = (aout_filter_t *)p_this;
209 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
210 || p_filter->output.i_format != AOUT_FMT_S16_NE )
215 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
220 p_filter->pf_do_work = Do_FL32ToS16;
221 p_filter->b_in_place = 1;
226 static void Do_FL32ToS16( aout_instance_t * p_aout, aout_filter_t * p_filter,
227 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
231 float * p_in = (float *)p_in_buf->p_buffer;
232 int16_t * p_out = (int16_t *)p_out_buf->p_buffer;
234 for ( i = p_in_buf->i_nb_samples
235 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
239 if ( *p_in >= 1.0 ) *p_out = 32767;
240 else if ( *p_in < -1.0 ) *p_out = -32768;
241 else *p_out = *p_in * 32768.0;
243 /* This is walken's trick based on IEEE float format. */
244 union { float f; int32_t i; } u;
246 if ( u.i > 0x43c07fff ) *p_out = 32767;
247 else if ( u.i < 0x43bf8000 ) *p_out = -32768;
248 else *p_out = u.i - 0x43c00000;
253 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
254 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
257 /*****************************************************************************
259 *****************************************************************************/
260 static int Create_FL32ToS8( vlc_object_t *p_this )
262 aout_filter_t * p_filter = (aout_filter_t *)p_this;
264 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
265 || p_filter->output.i_format != VLC_FOURCC('s','8',' ',' ') )
270 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
275 p_filter->pf_do_work = Do_FL32ToS8;
276 p_filter->b_in_place = 1;
281 static void Do_FL32ToS8( aout_instance_t * p_aout, aout_filter_t * p_filter,
282 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
286 float * p_in = (float *)p_in_buf->p_buffer;
287 int8_t * p_out = (int8_t *)p_out_buf->p_buffer;
289 for ( i = p_in_buf->i_nb_samples
290 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
292 if ( *p_in >= 1.0 ) *p_out = 127;
293 else if ( *p_in < -1.0 ) *p_out = -128;
294 else *p_out = (int8_t)(*p_in * 128);
298 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
299 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
302 /*****************************************************************************
304 *****************************************************************************/
305 static int Create_FL32ToU16( vlc_object_t *p_this )
307 aout_filter_t * p_filter = (aout_filter_t *)p_this;
309 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
310 || p_filter->output.i_format != AOUT_FMT_U16_NE )
315 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
320 p_filter->pf_do_work = Do_FL32ToU16;
321 p_filter->b_in_place = 1;
326 static void Do_FL32ToU16( aout_instance_t * p_aout, aout_filter_t * p_filter,
327 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
331 float * p_in = (float *)p_in_buf->p_buffer;
332 uint16_t * p_out = (uint16_t *)p_out_buf->p_buffer;
334 for ( i = p_in_buf->i_nb_samples
335 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
337 if ( *p_in >= 1.0 ) *p_out = 65535;
338 else if ( *p_in < -1.0 ) *p_out = 0;
339 else *p_out = (uint16_t)(32768 + *p_in * 32768);
343 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
344 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
347 /*****************************************************************************
349 *****************************************************************************/
350 static int Create_FL32ToU8( vlc_object_t *p_this )
352 aout_filter_t * p_filter = (aout_filter_t *)p_this;
354 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
355 || p_filter->output.i_format != VLC_FOURCC('u','8',' ',' ') )
360 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
365 p_filter->pf_do_work = Do_FL32ToU8;
366 p_filter->b_in_place = 1;
371 static void Do_FL32ToU8( aout_instance_t * p_aout, aout_filter_t * p_filter,
372 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
376 float * p_in = (float *)p_in_buf->p_buffer;
377 uint8_t * p_out = (uint8_t *)p_out_buf->p_buffer;
379 for ( i = p_in_buf->i_nb_samples
380 * aout_FormatNbChannels( &p_filter->input ); i-- ; )
382 if ( *p_in >= 1.0 ) *p_out = 255;
383 else if ( *p_in < -1.0 ) *p_out = 0;
384 else *p_out = (uint8_t)(128 + *p_in * 128);
388 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
389 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 4;
392 /*****************************************************************************
394 *****************************************************************************/
395 static int Create_S16ToFL32( vlc_object_t *p_this )
397 aout_filter_t * p_filter = (aout_filter_t *)p_this;
399 if ( ( p_filter->input.i_format != AOUT_FMT_S16_NE &&
400 p_filter->input.i_format != AOUT_FMT_S24_NE &&
401 p_filter->input.i_format != AOUT_FMT_S32_NE )
402 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
407 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
412 if( p_filter->input.i_format == AOUT_FMT_S32_NE )
413 p_filter->pf_do_work = Do_S32ToFL32;
414 else if( p_filter->input.i_format == AOUT_FMT_S24_NE )
415 p_filter->pf_do_work = Do_S24ToFL32;
417 p_filter->pf_do_work = Do_S16ToFL32;
419 p_filter->b_in_place = true;
424 static void Do_S16ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
425 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
428 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
430 /* We start from the end because b_in_place is true */
431 int16_t * p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
432 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
438 *p_out = (float)*p_in / 32768.0;
440 /* This is walken's trick based on IEEE float format. On my PIII
441 * this takes 16 seconds to perform one billion conversions, instead
442 * of 19 seconds for the above division. */
443 union { float f; int32_t i; } u;
444 u.i = *p_in + 0x43c00000;
445 *p_out = u.f - 384.0;
451 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
452 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 2;
455 static void Do_S24ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
456 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
459 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
461 /* We start from the end because b_in_place is true */
462 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
463 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
467 #ifdef WORDS_BIGENDIAN
468 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in)) << 8) + p_in[2]))
470 *p_out = ((float)( (((int32_t)*(int16_t *)(p_in+1)) << 8) + p_in[0]))
477 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
478 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
481 static void Do_S32ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
482 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
485 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
487 /* We start from the end because b_in_place is true */
488 int32_t * p_in = (int32_t *)p_in_buf->p_buffer + i - 1;
489 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
493 *p_out-- = (float)*p_in-- / 2147483648.0;
496 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
497 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 4;
500 /*****************************************************************************
501 * S16 To Float32 with endianness conversion
502 *****************************************************************************/
503 static int Create_S16ToFL32_SW( vlc_object_t *p_this )
505 aout_filter_t * p_filter = (aout_filter_t *)p_this;
507 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
512 if ( (p_filter->input.i_format == VLC_FOURCC('s','1','6','l') ||
513 p_filter->input.i_format == VLC_FOURCC('s','1','6','b'))
514 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
515 && p_filter->input.i_format != AOUT_FMT_S16_NE )
517 p_filter->pf_do_work = Do_S16ToFL32_SW;
518 p_filter->b_in_place = true;
523 if ( (p_filter->input.i_format == VLC_FOURCC('s','2','4','l') ||
524 p_filter->input.i_format == VLC_FOURCC('s','2','4','b'))
525 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
526 && p_filter->input.i_format != AOUT_FMT_S24_NE )
528 p_filter->pf_do_work = Do_S24ToFL32_SW;
529 p_filter->b_in_place = true;
534 if ( (p_filter->input.i_format == VLC_FOURCC('s','3','2','l') ||
535 p_filter->input.i_format == VLC_FOURCC('s','3','2','b'))
536 && p_filter->output.i_format == VLC_FOURCC('f','l','3','2')
537 && p_filter->input.i_format != AOUT_FMT_S32_NE )
539 p_filter->pf_do_work = Do_S32ToFL32_SW;
540 p_filter->b_in_place = true;
548 static void Do_S16ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
549 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
552 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
554 /* We start from the end because b_in_place is true */
556 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
560 int16_t * p_swabbed = alloca( i * sizeof(int16_t) );
562 int16_t * p_swabbed = malloc( i * sizeof(int16_t) );
565 swab( p_in_buf->p_buffer, (void *)p_swabbed, i * sizeof(int16_t) );
566 p_in = p_swabbed + i - 1;
570 p_in = (int16_t *)p_in_buf->p_buffer + i - 1;
576 p_tmp[0] = ((uint8_t *)p_in)[1];
577 p_tmp[1] = ((uint8_t *)p_in)[0];
578 *p_out = (float)( *(int16_t *)p_tmp ) / 32768.0;
580 *p_out = (float)*p_in / 32768.0;
591 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
592 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 2;
595 static void Do_S24ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
596 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
599 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
601 /* We start from the end because b_in_place is true */
602 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + (i - 1) * 3;
603 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
613 #ifdef WORDS_BIGENDIAN
614 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp)) << 8) + p_tmp[2]))
616 *p_out = ((float)( (((int32_t)*(int16_t *)(p_tmp+1)) << 8) + p_tmp[0]))
623 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
624 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 3;
627 static void Do_S32ToFL32_SW( aout_instance_t * p_aout, aout_filter_t * p_filter,
628 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
631 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
633 /* We start from the end because b_in_place is true */
634 int32_t * p_in = (int32_t *)p_in_buf->p_buffer + i - 1;
635 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
639 *p_out-- = (float)*p_in-- / 2147483648.0;
642 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
643 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * 4 / 4;
647 /*****************************************************************************
649 *****************************************************************************/
650 static int Create_S8ToFL32( vlc_object_t *p_this )
652 aout_filter_t * p_filter = (aout_filter_t *)p_this;
654 if ( p_filter->input.i_format != VLC_FOURCC('s','8',' ',' ')
655 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
660 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
665 p_filter->pf_do_work = Do_S8ToFL32;
666 p_filter->b_in_place = true;
671 static void Do_S8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
672 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
675 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
677 /* We start from the end because b_in_place is true */
678 int8_t * p_in = (int8_t *)p_in_buf->p_buffer + i - 1;
679 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
683 *p_out = (float)(*p_in) / 128.0;
687 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
688 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);
691 /*****************************************************************************
693 *****************************************************************************/
694 static int Create_U8ToFL32( vlc_object_t *p_this )
696 aout_filter_t * p_filter = (aout_filter_t *)p_this;
698 if ( p_filter->input.i_format != VLC_FOURCC('u','8',' ',' ')
699 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
704 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
709 p_filter->pf_do_work = Do_U8ToFL32;
710 p_filter->b_in_place = true;
715 static void Do_U8ToFL32( aout_instance_t * p_aout, aout_filter_t * p_filter,
716 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
719 int i = p_in_buf->i_nb_samples * aout_FormatNbChannels( &p_filter->input );
721 /* We start from the end because b_in_place is true */
722 uint8_t * p_in = (uint8_t *)p_in_buf->p_buffer + i - 1;
723 float * p_out = (float *)p_out_buf->p_buffer + i - 1;
727 *p_out = ((float)*p_in -128) / 128.0;
731 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
732 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * sizeof(float);