]> git.sesse.net Git - vlc/blob - modules/audio_filter/converter/mono.c
put mono audio in both (left/right) channels. For some reason AOUT_CHAN_CENTER doesn...
[vlc] / modules / audio_filter / converter / mono.c
1 /*****************************************************************************
2  * mono.c : stereo2mono downmixsimple channel mixer plug-in
3  *****************************************************************************
4  * Copyright (C) 2006 M2X
5  * $Id$
6  *
7  * Authors: Jean-Paul Saman <jpsaman at m2x dot nl>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #ifdef HAVE_STDINT_H
31 #   include <stdint.h>                                         /* int16_t .. */
32 #elif HAVE_INTTYPES_H
33 #   include <inttypes.h>                                       /* int16_t .. */
34 #endif
35
36 #ifdef HAVE_UNISTD_H
37 #   include <unistd.h>
38 #endif
39
40 #include <vlc/vlc.h>
41 #include <vlc_es.h>
42 #include <vlc_block.h>
43 #include <vlc_filter.h>
44 #include <audio_output.h>
45 #include <aout_internal.h>
46
47 /*****************************************************************************
48  * Local prototypes
49  *****************************************************************************/
50 static int  OpenFilter    ( vlc_object_t * );
51 static void CloseFilter   ( vlc_object_t * );
52
53 static block_t *Convert( filter_t *p_filter, block_t *p_block );
54
55 static unsigned int stereo_to_mono( aout_instance_t *, aout_filter_t *,
56                                     aout_buffer_t *, aout_buffer_t * );
57
58 /*****************************************************************************
59  * Local structures
60  *****************************************************************************/
61 struct filter_sys_t
62 {
63     int i_nb_channels; /* number of float32 per sample */
64     unsigned int i_channel_selected;
65     int i_bitspersample;
66 };
67
68 #define MONO_CHANNEL_TEXT ("Select channel to keep")
69 #define MONO_CHANNEL_LONGTEXT ("This option silcences all other channels " \
70     "except the selected channel. Choose one from (0=left, 1=right " \
71     "2=rear left, 3=rear right, 4=center, 5=left front)")
72
73 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5 };
74 static char *ppsz_pos_descriptions[] =
75 { N_("Left"), N_("Right"), N_("Left rear"), N_("Right rear"), N_("Center"),
76   N_("Left front") };
77
78 /* our internal channel order (WG-4 order) */
79 static const uint32_t pi_channels_out[] =
80 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
81   AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
82
83 #define MONO_CFG "sout-"
84 /*****************************************************************************
85  * Module descriptor
86  *****************************************************************************/
87 vlc_module_begin();
88     set_description( _("Audio filter for stereo to mono conversion") );
89     set_capability( "audio filter2", 5 );
90
91     add_integer( MONO_CFG "mono-channel", 0, NULL, MONO_CHANNEL_TEXT, MONO_CHANNEL_LONGTEXT, VLC_FALSE );
92         change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
93
94     set_category( CAT_AUDIO );
95     set_subcategory( SUBCAT_AUDIO_MISC );
96     set_callbacks( OpenFilter, CloseFilter );
97     set_shortname( "Mono" );
98 vlc_module_end();
99
100 /*****************************************************************************
101  * OpenFilter
102  *****************************************************************************/
103 static int OpenFilter( vlc_object_t *p_this )
104 {
105     filter_t * p_filter = (filter_t *)p_this;
106     filter_sys_t *p_sys = NULL;
107
108     if( aout_FormatNbChannels( &(p_filter->fmt_in.audio) ) == 1 )
109     {
110         msg_Dbg( p_filter, "filter discarded (incompatible format)" );
111         return VLC_EGENERIC;
112     }
113
114     if( (p_filter->fmt_in.i_codec != AOUT_FMT_S16_NE) ||
115         (p_filter->fmt_out.i_codec != AOUT_FMT_S16_NE) )
116     {
117         msg_Err( p_this, "filter discarded (invalid format)" );
118         return -1;
119     }
120
121     if( (p_filter->fmt_in.audio.i_format != p_filter->fmt_out.audio.i_format) &&
122         (p_filter->fmt_in.audio.i_rate != p_filter->fmt_out.audio.i_rate) &&
123         (p_filter->fmt_in.audio.i_format != AOUT_FMT_S16_NE) &&
124         (p_filter->fmt_out.audio.i_format != AOUT_FMT_S16_NE) )
125     {
126         msg_Err( p_this, "couldn't load mono filter" );
127         return VLC_EGENERIC;
128     }
129
130     /* Allocate the memory needed to store the module's structure */
131     p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) );
132     if( p_sys == NULL )
133     {
134         msg_Err( p_filter, "out of memory" );
135         return VLC_EGENERIC;
136     }
137
138     var_Create( p_this, MONO_CFG "mono-channel",
139                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
140     p_sys->i_channel_selected =
141             (unsigned int) var_GetInteger( p_this, MONO_CFG "mono-channel" );
142
143 #if 0
144     p_filter->fmt_out.audio.i_physical_channels = AOUT_CHAN_CENTER;
145 #else
146     p_filter->fmt_out.audio.i_physical_channels =
147                             (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT);
148 #endif
149     p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate;
150     p_filter->fmt_out.audio.i_format = p_filter->fmt_out.i_codec;
151
152     p_sys->i_nb_channels = aout_FormatNbChannels( &(p_filter->fmt_in.audio) );
153     p_sys->i_bitspersample = p_filter->fmt_out.audio.i_bitspersample;
154
155     p_filter->pf_audio_filter = Convert;
156
157     msg_Dbg( p_this, "%4.4s->%4.4s, channels %d->%d, bits per sample: %i->%i",
158              (char *)&p_filter->fmt_in.i_codec,
159              (char *)&p_filter->fmt_out.i_codec,
160              p_filter->fmt_in.audio.i_physical_channels,
161              p_filter->fmt_out.audio.i_physical_channels,
162              p_filter->fmt_in.audio.i_bitspersample,
163              p_filter->fmt_out.audio.i_bitspersample );
164
165     return VLC_SUCCESS;
166 }
167
168 /*****************************************************************************
169  * CloseFilter
170  *****************************************************************************/
171 static void CloseFilter( vlc_object_t *p_this)
172 {
173     filter_t *p_filter = (filter_t *) p_this;
174     filter_sys_t *p_sys = p_filter->p_sys;
175
176     var_Destroy( p_this, MONO_CFG "mono-channel" );
177     free( p_sys );
178 }
179
180 /*****************************************************************************
181  * Convert
182  *****************************************************************************/
183 static block_t *Convert( filter_t *p_filter, block_t *p_block )
184 {
185     aout_filter_t aout_filter;
186     aout_buffer_t in_buf, out_buf;
187     block_t *p_out = NULL;
188     int i_out_size;
189     unsigned int i_samples;
190
191     if( !p_block || !p_block->i_samples )
192     {
193         if( p_block )
194             p_block->pf_release( p_block );
195         return NULL;
196     }
197
198     i_out_size = p_block->i_samples * p_filter->p_sys->i_bitspersample/8 *
199                  aout_FormatNbChannels( &(p_filter->fmt_out.audio) );
200
201     p_out = p_filter->pf_audio_buffer_new( p_filter, i_out_size );
202     if( !p_out )
203     {
204         msg_Warn( p_filter, "can't get output buffer" );
205         p_block->pf_release( p_block );
206         return NULL;
207     }
208
209     p_out->i_samples = (p_block->i_samples / p_filter->p_sys->i_nb_channels) *
210                             aout_FormatNbChannels( &(p_filter->fmt_out.audio) );
211     p_out->i_dts = p_block->i_dts;
212     p_out->i_pts = p_block->i_pts;
213     p_out->i_length = p_block->i_length;
214
215     aout_filter.p_sys = (struct aout_filter_sys_t *)p_filter->p_sys;
216     aout_filter.input = p_filter->fmt_in.audio;
217     aout_filter.input.i_format = p_filter->fmt_in.i_codec;
218     aout_filter.output = p_filter->fmt_out.audio;
219     aout_filter.output.i_format = p_filter->fmt_out.i_codec;
220
221     in_buf.p_buffer = p_block->p_buffer;
222     in_buf.i_nb_bytes = p_block->i_buffer;
223     in_buf.i_nb_samples = p_block->i_samples;
224
225 #if 0
226     unsigned int i_in_size = in_buf.i_nb_samples  * (p_filter->p_sys->i_bitspersample/8) *
227                              aout_FormatNbChannels( &(p_filter->fmt_in.audio) );
228     if( (in_buf.i_nb_bytes != i_in_size) && ((i_in_size % 32) != 0) ) /* is it word aligned?? */
229     {
230         msg_Err( p_filter, "input buffer is not word aligned" );
231         /* Fix output buffer to be word aligned */
232     }
233 #endif
234
235     out_buf.p_buffer = p_out->p_buffer;
236     out_buf.i_nb_bytes = p_out->i_buffer;
237     out_buf.i_nb_samples = p_out->i_samples;
238
239     i_samples = stereo_to_mono( (aout_instance_t *)p_filter, &aout_filter,
240                                 &out_buf, &in_buf );
241
242     p_out->i_buffer = out_buf.i_nb_bytes;
243     p_out->i_samples = out_buf.i_nb_samples;
244
245     p_block->pf_release( p_block );
246     return p_out;
247 }
248
249 /* stereo_to_mono - mix 2 channels (left,right) into one and play silence on
250  * all other channels.
251  */
252 static unsigned int stereo_to_mono( aout_instance_t * p_aout, aout_filter_t *p_filter,
253                                     aout_buffer_t *p_output, aout_buffer_t *p_input )
254 {
255     filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
256     int16_t *p_in, *p_out;
257     unsigned int n;
258
259     p_in = (int16_t *) p_input->p_buffer;
260     p_out = (int16_t *) p_output->p_buffer;
261
262     for( n = 0; n < (p_input->i_nb_samples * p_sys->i_nb_channels); n++ )
263     {
264         /* Fake real mono. */
265         p_out[n] = (p_in[n] + p_in[n+1]) >> 1;
266         n++;
267     }
268     return n;
269 }