1 /*****************************************************************************
2 * format.c : PCM format converter
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: float32tos16.c 8391 2004-08-06 17:28:36Z sam $
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * Gildas Bazin <gbazin@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
32 #include <vlc/decoder.h>
33 #include "vlc_filter.h"
35 /*****************************************************************************
37 *****************************************************************************/
38 static int Open ( vlc_object_t * );
40 static block_t *Float32toS16( filter_t *, block_t * );
41 static block_t *Float32toU16( filter_t *, block_t * );
42 static block_t *S16toFloat32( filter_t *, block_t * );
43 static block_t *S16Invert ( filter_t *, block_t * );
45 /*****************************************************************************
47 *****************************************************************************/
49 set_description( _("audio filter for PCM format conversion") );
50 set_capability( "audio filter2", 1 );
51 set_callbacks( Open, NULL );
54 /*****************************************************************************
56 *****************************************************************************/
57 static int Open( vlc_object_t *p_this )
59 filter_t *p_filter = (filter_t *)p_this;
61 if( p_filter->fmt_in.i_codec == VLC_FOURCC('f','l','3','2') &&
62 p_filter->fmt_out.i_codec == AUDIO_FMT_S16_NE )
64 p_filter->pf_audio_filter = Float32toS16;
66 else if( p_filter->fmt_in.i_codec == VLC_FOURCC('f','l','3','2') &&
67 p_filter->fmt_out.i_codec == AUDIO_FMT_U16_NE )
69 p_filter->pf_audio_filter = Float32toU16;
71 else if( p_filter->fmt_in.i_codec == AUDIO_FMT_S16_NE &&
72 p_filter->fmt_out.i_codec == VLC_FOURCC('f','l','3','2') )
74 p_filter->pf_audio_filter = S16toFloat32;
76 else if( ( p_filter->fmt_in.i_codec == VLC_FOURCC('s','1','6','l') &&
77 p_filter->fmt_out.i_codec == VLC_FOURCC('s','1','6','b') ) ||
78 ( p_filter->fmt_in.i_codec == VLC_FOURCC('s','1','6','b') &&
79 p_filter->fmt_out.i_codec == VLC_FOURCC('s','1','6','l') ) )
81 p_filter->pf_audio_filter = S16Invert;
83 else return VLC_EGENERIC;
85 msg_Dbg( p_this, "%4.4s->%4.4s, bits per sample: %i",
86 (char *)&p_filter->fmt_in.i_codec,
87 (char *)&p_filter->fmt_out.i_codec,
88 p_filter->fmt_in.audio.i_bitspersample );
93 /*****************************************************************************
95 *****************************************************************************/
96 static block_t *Float32toS16( filter_t *p_filter, block_t *p_block )
99 float *p_in = (float *)p_block->p_buffer;
100 int16_t *p_out = (int16_t *)p_in;
102 for( i = p_block->i_buffer*8/p_filter->fmt_in.audio.i_bitspersample; i--; )
106 if ( *p_in >= 1.0 ) *p_out = 32767;
107 else if ( *p_in < -1.0 ) *p_out = -32768;
108 else *p_out = *p_in * 32768.0;
110 /* This is walken's trick based on IEEE float format. */
111 union { float f; int32_t i; } u;
113 if ( u.i > 0x43c07fff ) *p_out = 32767;
114 else if ( u.i < 0x43bf8000 ) *p_out = -32768;
115 else *p_out = u.i - 0x43c00000;
120 p_block->i_buffer /= 2;
124 static block_t *Float32toU16( filter_t *p_filter, block_t *p_block )
127 float *p_in = (float *)p_block->p_buffer;
128 uint16_t *p_out = (uint16_t *)p_in;
130 for( i = p_block->i_buffer*8/p_filter->fmt_in.audio.i_bitspersample; i--; )
132 if ( *p_in >= 1.0 ) *p_out = 65535;
133 else if ( *p_in < -1.0 ) *p_out = 0;
134 else *p_out = (uint16_t)(32768 + *p_in * 32768);
138 p_block->i_buffer /= 2;
142 static block_t *S16toFloat32( filter_t *p_filter, block_t *p_block )
144 block_t *p_block_out;
150 p_filter->pf_audio_buffer_new( p_filter, p_block->i_buffer*2 );
153 msg_Warn( p_filter, "can't get output buffer" );
157 p_in = (int16_t *)p_block->p_buffer;
158 p_out = (float *)p_block_out->p_buffer;
160 for( i = p_block->i_buffer*8/p_filter->fmt_in.audio.i_bitspersample; i--; )
164 *p_out = (float)*p_in / 32768.0;
166 /* This is walken's trick based on IEEE float format. On my PIII
167 * this takes 16 seconds to perform one billion conversions, instead
168 * of 19 seconds for the above division. */
169 union { float f; int32_t i; } u;
170 u.i = *p_in + 0x43c00000;
171 *p_out = u.f - 384.0;
177 p_block_out->i_samples = p_block->i_samples;
178 p_block_out->i_dts = p_block->i_dts;
179 p_block_out->i_pts = p_block->i_pts;
180 p_block_out->i_length = p_block->i_length;
181 p_block_out->i_rate = p_block->i_rate;
183 p_block->pf_release( p_block );
187 static block_t *S16Invert( filter_t *p_filter, block_t *p_block )
190 uint8_t *p_in = (uint8_t *)p_block->p_buffer;
193 for( i = 0; i < p_block->i_buffer / 2; i++ )