]> git.sesse.net Git - vlc/blob - modules/audio_filter/channel_mixer/simple.c
36da5ab689917362ec9a08cde0d6951750342e64
[vlc] / modules / audio_filter / channel_mixer / simple.c
1 /*****************************************************************************
2  * simple.c : simple channel mixer plug-in (only 7/7.1/5/5.1 -> Stereo for now)
3  *****************************************************************************
4  * Copyright (C) 2002, 2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
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 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_aout.h>
34 #include <vlc_filter.h>
35 #include <vlc_block.h>
36
37 /*****************************************************************************
38  * Local prototypes
39  *****************************************************************************/
40 static int  Create    ( vlc_object_t * );
41
42 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
43                         aout_buffer_t * );
44
45 static int  OpenFilter ( vlc_object_t * );
46 static block_t *Filter( filter_t *, block_t * );
47
48 /*****************************************************************************
49  * Module descriptor
50  *****************************************************************************/
51 vlc_module_begin();
52     set_description( N_("Audio filter for simple channel mixing") );
53     set_capability( "audio filter", 10 );
54     set_category( CAT_AUDIO );
55     set_subcategory( SUBCAT_AUDIO_MISC );
56     set_callbacks( Create, NULL );
57
58     add_submodule();
59     set_description( N_("audio filter for simple channel mixing") );
60     set_capability( "audio filter2", 10 );
61     set_callbacks( OpenFilter, NULL );
62 vlc_module_end();
63
64 /*****************************************************************************
65  * Create: allocate trivial channel mixer
66  *****************************************************************************/
67 static int Create( vlc_object_t *p_this )
68 {
69     aout_filter_t * p_filter = (aout_filter_t *)p_this;
70
71     if ( (p_filter->input.i_physical_channels
72            == p_filter->output.i_physical_channels
73            && p_filter->input.i_original_channels
74                == p_filter->output.i_original_channels)
75           || p_filter->input.i_format != p_filter->output.i_format
76           || p_filter->input.i_rate != p_filter->output.i_rate
77           || p_filter->input.i_format != VLC_FOURCC('f','l','3','2') )
78     {
79         return -1;
80     }
81
82     /* Only conversion to Mono, Stereo and 4.0 right now */
83     if( p_filter->output.i_physical_channels !=
84         (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)
85         && p_filter->output.i_physical_channels !=
86         ( AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
87         AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT)
88         && p_filter->output.i_physical_channels != AOUT_CHAN_CENTER )
89     {
90         return -1;
91     }
92
93     /* Only from 7/7.1/5/5.1/2.0 */
94     if( (p_filter->input.i_physical_channels & ~AOUT_CHAN_LFE) !=
95         (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
96          AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT) &&
97         (p_filter->input.i_physical_channels & ~AOUT_CHAN_LFE) !=
98         (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
99          AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
100          AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT) &&
101         p_filter->input.i_physical_channels !=
102         (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
103     {
104         return -1;
105     }
106
107     p_filter->pf_do_work = DoWork;
108     p_filter->b_in_place = 0;
109
110     return 0;
111 }
112
113 /*****************************************************************************
114  * DoWork: convert a buffer
115  *****************************************************************************/
116 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
117                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
118 {
119     VLC_UNUSED(p_aout);
120     int i_input_nb = aout_FormatNbChannels( &p_filter->input );
121     int i_output_nb = aout_FormatNbChannels( &p_filter->output );
122     float *p_dest = (float *)p_out_buf->p_buffer;
123     float *p_src = (float *)p_in_buf->p_buffer;
124     int i;
125
126     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
127     p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * i_output_nb / i_input_nb;
128
129     if( p_filter->output.i_physical_channels ==
130                             (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
131     {
132         if( p_filter->input.i_physical_channels & AOUT_CHAN_MIDDLELEFT )
133         for( i = p_in_buf->i_nb_samples; i--; )
134         {
135             *p_dest = p_src[6] + 0.5 * p_src[0] + p_src[2] / 4 + p_src[4] / 4;
136             p_dest++;
137             *p_dest = p_src[6] + 0.5 * p_src[1] + p_src[3] / 4 + p_src[5] / 4;
138             p_dest++;
139
140             p_src += 7;
141
142             if( p_filter->input.i_physical_channels & AOUT_CHAN_LFE ) p_src++;
143         }
144         else
145         for( i = p_in_buf->i_nb_samples; i--; )
146         {
147             *p_dest = p_src[4] + 0.5 * p_src[0] + 0.33 * p_src[2];
148             p_dest++;
149             *p_dest = p_src[4] + 0.5 * p_src[1] + 0.33 * p_src[3];
150             p_dest++;
151
152             p_src += 5;
153
154             if( p_filter->input.i_physical_channels & AOUT_CHAN_LFE ) p_src++;
155         }
156     }
157     else if( p_filter->output.i_physical_channels == AOUT_CHAN_CENTER )
158     {
159         if( p_filter->input.i_physical_channels & AOUT_CHAN_MIDDLELEFT )
160         for( i = p_in_buf->i_nb_samples; i--; )
161         {
162             *p_dest = p_src[6] + p_src[0] / 4 + p_src[1] / 4 + p_src[2] / 8 + p_src[3] / 8 + p_src[4] / 8 + p_src[5] / 8;
163             p_dest++;
164
165             p_src += 7;
166
167             if( p_filter->input.i_physical_channels & AOUT_CHAN_LFE ) p_src++;
168         }
169         else if( p_filter->input.i_physical_channels & AOUT_CHAN_REARLEFT )
170         for( i = p_in_buf->i_nb_samples; i--; )
171         {
172             *p_dest = p_src[4] + p_src[0] / 4 + p_src[1] / 4 + p_src[2] / 6 + p_src[3] / 6;
173             p_dest++;
174
175             p_src += 5;
176
177             if( p_filter->input.i_physical_channels & AOUT_CHAN_LFE ) p_src++;
178         }
179         else
180         for( i = p_in_buf->i_nb_samples; i--; )
181         {
182             *p_dest = p_src[0] / 2 + p_src[1] / 2;
183             p_dest++;
184
185             p_src += 2;
186         }
187     }
188     else
189     {
190         if( p_filter->input.i_physical_channels & AOUT_CHAN_MIDDLELEFT )
191         for( i = p_in_buf->i_nb_samples; i--; )
192         {
193             *p_dest = p_src[6] + 0.5 * p_src[0] + p_src[2] / 6;
194             p_dest++;
195             *p_dest = p_src[6] + 0.5 * p_src[1] + p_src[3] / 6;
196             p_dest++;
197             *p_dest = p_src[2] / 6 +  p_src[4];
198             p_dest++;
199             *p_dest = p_src[3] / 6 +  p_src[5];
200             p_dest++;
201
202             p_src += 7;
203
204             if( p_filter->input.i_physical_channels & AOUT_CHAN_LFE ) p_src++;
205         }
206         else
207         for( i = p_in_buf->i_nb_samples; i--; )
208         {
209             *p_dest = p_src[4] + 0.5 * p_src[0];
210             p_dest++;
211             *p_dest = p_src[4] + 0.5 * p_src[1];
212             p_dest++;
213             *p_dest = p_src[2];
214             p_dest++;
215             *p_dest = p_src[3];
216             p_dest++;
217
218             p_src += 5;
219
220             if( p_filter->input.i_physical_channels & AOUT_CHAN_LFE ) p_src++;
221         }
222
223     }
224 }
225
226 /*****************************************************************************
227  * OpenFilter:
228  *****************************************************************************/
229 static int OpenFilter( vlc_object_t *p_this )
230 {
231     filter_t *p_filter = (filter_t *)p_this;
232
233     if ( (p_filter->fmt_in.audio.i_physical_channels
234            == p_filter->fmt_out.audio.i_physical_channels
235            && p_filter->fmt_in.audio.i_original_channels
236                == p_filter->fmt_out.audio.i_original_channels)
237           || p_filter->fmt_in.i_codec != p_filter->fmt_out.i_codec
238           || p_filter->fmt_in.audio.i_rate != p_filter->fmt_out.audio.i_rate
239           || p_filter->fmt_in.i_codec != VLC_FOURCC('f','l','3','2') )
240     {
241         return -1;
242     }
243
244     /* Only conversion to Mono, Stereo and 4.0 right now */
245     if( p_filter->fmt_out.audio.i_physical_channels !=
246         (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)
247         && p_filter->fmt_out.audio.i_physical_channels !=
248         ( AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
249         AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT)
250         && p_filter->fmt_out.audio.i_physical_channels != AOUT_CHAN_CENTER )
251     {
252         return -1;
253     }
254
255     /* Only from 7/7.1/5/5.1/2.0 */
256     if( (p_filter->fmt_in.audio.i_physical_channels & ~AOUT_CHAN_LFE) !=
257         (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
258          AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT) &&
259         (p_filter->fmt_in.audio.i_physical_channels & ~AOUT_CHAN_LFE) !=
260         (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
261          AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
262          AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT) &&
263         p_filter->fmt_in.audio.i_physical_channels !=
264         (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT) )
265     {
266         return -1;
267     }
268
269     p_filter->pf_audio_filter = Filter;
270
271     return 0;
272 }
273
274 /*****************************************************************************
275  * Filter:
276  *****************************************************************************/
277 static block_t *Filter( filter_t *p_filter, block_t *p_block )
278 {
279     aout_filter_t aout_filter;
280     aout_buffer_t in_buf, out_buf;
281     block_t *p_out;
282     int i_out_size;
283
284     if( !p_block || !p_block->i_samples )
285     {
286         if( p_block ) p_block->pf_release( p_block );
287         return NULL;
288     }
289
290     i_out_size = p_block->i_samples *
291       p_filter->fmt_out.audio.i_bitspersample *
292         p_filter->fmt_out.audio.i_channels / 8;
293
294     p_out = p_filter->pf_audio_buffer_new( p_filter, i_out_size );
295     if( !p_out )
296     {
297         msg_Warn( p_filter, "can't get output buffer" );
298         p_block->pf_release( p_block );
299         return NULL;
300     }
301
302     p_out->i_samples = p_block->i_samples;
303     p_out->i_dts = p_block->i_dts;
304     p_out->i_pts = p_block->i_pts;
305     p_out->i_length = p_block->i_length;
306
307     aout_filter.p_sys = (struct aout_filter_sys_t *)p_filter->p_sys;
308     aout_filter.input = p_filter->fmt_in.audio;
309     aout_filter.input.i_format = p_filter->fmt_in.i_codec;
310     aout_filter.output = p_filter->fmt_out.audio;
311     aout_filter.output.i_format = p_filter->fmt_out.i_codec;
312
313     in_buf.p_buffer = p_block->p_buffer;
314     in_buf.i_nb_bytes = p_block->i_buffer;
315     in_buf.i_nb_samples = p_block->i_samples;
316     out_buf.p_buffer = p_out->p_buffer;
317     out_buf.i_nb_bytes = p_out->i_buffer;
318     out_buf.i_nb_samples = p_out->i_samples;
319
320     DoWork( (aout_instance_t *)p_filter, &aout_filter, &in_buf, &out_buf );
321
322     p_block->pf_release( p_block );
323
324     p_out->i_buffer = out_buf.i_nb_bytes;
325     p_out->i_samples = out_buf.i_nb_samples;
326
327     return p_out;
328 }
329