00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdlib.h>
00028 #include <string.h>
00029
00030 #include <vlc/vlc.h>
00031 #include "audio_output.h"
00032 #include "aout_internal.h"
00033
00034
00035
00036
00037 static int Create ( vlc_object_t * );
00038
00039 static void DoWork ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
00040 aout_buffer_t * );
00041
00042
00043
00044
00045 vlc_module_begin();
00046 set_category( CAT_AUDIO );
00047 set_subcategory( SUBCAT_AUDIO_MISC );
00048 set_description( _("audio filter for fixed32->s16 conversion") );
00049 set_capability( "audio filter", 10 );
00050 set_callbacks( Create, NULL );
00051 vlc_module_end();
00052
00053
00054
00055
00056
00057
00058 static int Create( vlc_object_t *p_this )
00059 {
00060 aout_filter_t * p_filter = (aout_filter_t *)p_this;
00061
00062 if ( p_filter->input.i_format != VLC_FOURCC('f','i','3','2')
00063 || p_filter->output.i_format != AOUT_FMT_S16_NE )
00064 {
00065 return -1;
00066 }
00067
00068 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
00069 {
00070 return -1;
00071 }
00072
00073 p_filter->pf_do_work = DoWork;
00074 p_filter->b_in_place = 1;
00075
00076 return 0;
00077 }
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 #define VLC_F_FRACBITS 28
00095
00096 # if VLC_F_FRACBITS == 28
00097 # define VLC_F(x) ((vlc_fixed_t) (x##L))
00098 # endif
00099
00100 # define VLC_F_ONE VLC_F(0x10000000)
00101
00102 struct audio_dither {
00103 vlc_fixed_t error[3];
00104 vlc_fixed_t random;
00105 };
00106
00107
00108
00109
00110
00111 static inline unsigned long prng(unsigned long state)
00112 {
00113 return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
00114 }
00115
00116
00117
00118
00119
00120 static inline int16_t mpg321_s24_to_s16_pcm(unsigned int bits, vlc_fixed_t sample,
00121 struct audio_dither *dither)
00122 {
00123 unsigned int scalebits;
00124 vlc_fixed_t output, mask, random;
00125
00126 enum {
00127 MIN = -VLC_F_ONE,
00128 MAX = VLC_F_ONE - 1
00129 };
00130
00131
00132 sample += dither->error[0] - dither->error[1] + dither->error[2];
00133
00134 dither->error[2] = dither->error[1];
00135 dither->error[1] = dither->error[0] / 2;
00136
00137
00138 output = sample + (1L << (VLC_F_FRACBITS + 1 - bits - 1));
00139
00140 scalebits = VLC_F_FRACBITS + 1 - bits;
00141 mask = (1L << scalebits) - 1;
00142
00143
00144 random = prng(dither->random);
00145 output += (random & mask) - (dither->random & mask);
00146
00147 dither->random = random;
00148
00149
00150 if (output > MAX) {
00151 output = MAX;
00152
00153 if (sample > MAX)
00154 sample = MAX;
00155 }
00156 else if (output < MIN) {
00157 output = MIN;
00158
00159 if (sample < MIN)
00160 sample = MIN;
00161 }
00162
00163
00164 output &= ~mask;
00165
00166
00167 dither->error[0] = sample - output;
00168
00169
00170 return output >> scalebits;
00171 }
00172
00173
00174
00175
00176 static inline int16_t s24_to_s16_pcm(vlc_fixed_t sample)
00177 {
00178
00179 sample += (1L << (VLC_F_FRACBITS - 16));
00180
00181
00182 if (sample >= VLC_F_ONE)
00183 sample = VLC_F_ONE - 1;
00184 else if (sample < -VLC_F_ONE)
00185 sample = -VLC_F_ONE;
00186
00187
00188 return (sample >> (VLC_F_FRACBITS + 1 - 16));
00189 }
00190
00191
00192
00193
00194 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
00195 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
00196 {
00197 int i;
00198 vlc_fixed_t * p_in = (vlc_fixed_t *)p_in_buf->p_buffer;
00199 int16_t * p_out = (int16_t *)p_out_buf->p_buffer;
00200 #if 0
00201 static struct audio_dither dither;
00202 #endif
00203
00204 for ( i = p_in_buf->i_nb_samples
00205 * aout_FormatNbChannels( &p_filter->input ) ; i-- ; )
00206 {
00207 #if 0
00208
00209 *p_out++ = mpg321_s24_to_s16_pcm(16, *p_in++, &dither);
00210 #endif
00211
00212 *p_out++ = s24_to_s16_pcm(*p_in++);
00213 }
00214 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
00215 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes / 2;
00216 }