]> git.sesse.net Git - vlc/blob - modules/audio_filter/channel_mixer/trivial.c
trivial_mixer: fix arithmetic
[vlc] / modules / audio_filter / channel_mixer / trivial.c
1 /*****************************************************************************
2  * trivial.c : trivial channel mixer plug-in (drops unwanted channels)
3  *****************************************************************************
4  * Copyright (C) 2002, 2006, 2014 VLC authors and VideoLAN
5  *
6  * Authors: Christophe Massiot <massiot@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_aout.h>
36 #include <vlc_filter.h>
37
38 static int Create( vlc_object_t * );
39
40 vlc_module_begin ()
41     set_description( N_("Audio filter for trivial channel mixing") )
42     set_capability( "audio converter", 1 )
43     set_category( CAT_AUDIO )
44     set_subcategory( SUBCAT_AUDIO_MISC )
45     set_callbacks( Create, NULL )
46 vlc_module_end ()
47
48 /**
49  * Trivially upmixes
50  */
51 static block_t *Upmix( filter_t *p_filter, block_t *p_in_buf )
52 {
53     unsigned i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
54     unsigned i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );
55
56     assert( i_input_nb < i_output_nb );
57
58     block_t *p_out_buf = block_Alloc(
59                               p_in_buf->i_buffer * i_output_nb / i_input_nb );
60     if( unlikely(p_out_buf == NULL) )
61     {
62         block_Release( p_in_buf );
63         return NULL;
64     }
65
66     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
67     p_out_buf->i_dts        = p_in_buf->i_dts;
68     p_out_buf->i_pts        = p_in_buf->i_pts;
69     p_out_buf->i_length     = p_in_buf->i_length;
70
71     float *p_dest = (float *)p_out_buf->p_buffer;
72     const float *p_src = (float *)p_in_buf->p_buffer;
73
74     for( size_t i = 0; i < p_in_buf->i_nb_samples; i++ )
75     {
76         for( unsigned j = 0; j < i_output_nb; j++ )
77             p_dest[j] = p_src[j % i_input_nb];
78
79         p_src += i_input_nb;
80         p_dest += i_output_nb;
81     }
82
83     block_Release( p_in_buf );
84     return p_out_buf;
85 }
86
87 /**
88  * Trivially downmixes (i.e. drop extra channels)
89  */
90 static block_t *Downmix( filter_t *p_filter, block_t *p_buf )
91 {
92     unsigned i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
93     unsigned i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );
94
95     assert( i_input_nb >= i_output_nb );
96
97     float *p_dest = (float *)p_buf->p_buffer;
98     const float *p_src = p_dest;
99
100     for( size_t i = 0; i < p_buf->i_nb_samples; i++ )
101     {
102         for( unsigned j = 0; j < i_output_nb; j++ )
103             p_dest[j] = p_src[j];
104
105         p_src += i_input_nb;
106         p_dest += i_output_nb;
107     }
108
109     return p_buf;
110 }
111
112 static block_t *CopyLeft( filter_t *p_filter, block_t *p_buf )
113 {
114     float *p = (float *)p_buf->p_buffer;
115
116     for( unsigned i = 0; i < p_buf->i_nb_samples; i++ )
117     {
118         p[1] = p[0];
119         p += 2;
120     }
121     (void) p_filter;
122     return p_buf;
123 }
124
125 static block_t *CopyRight( filter_t *p_filter, block_t *p_buf )
126 {
127     float *p = (float *)p_buf->p_buffer;
128
129     for( unsigned i = 0; i < p_buf->i_nb_samples; i++ )
130     {
131         p[0] = p[1];
132         p += 2;
133     }
134     (void) p_filter;
135     return p_buf;
136 }
137
138 static block_t *ExtractLeft( filter_t *p_filter, block_t *p_buf )
139 {
140     float *p_dest = (float *)p_buf->p_buffer;
141     const float *p_src = p_dest;
142
143     for( unsigned i = 0; i < p_buf->i_nb_samples; i++ )
144     {
145         *(p_dest++) = *p_src;
146         p_src += 2;
147     }
148     (void) p_filter;
149     return p_buf;
150 }
151
152 static block_t *ExtractRight( filter_t *p_filter, block_t *p_buf )
153 {
154     float *p_dest = (float *)p_buf->p_buffer;
155     const float *p_src = p_dest;
156
157     for( unsigned i = 0; i < p_buf->i_nb_samples; i++ )
158     {
159         p_src++;
160         *(p_dest++) = *(p_src++);
161     }
162     (void) p_filter;
163     return p_buf;
164 }
165
166 static block_t *ReverseStereo( filter_t *p_filter, block_t *p_buf )
167 {
168     float *p = (float *)p_buf->p_buffer;
169
170     /* Reverse-stereo mode */
171     for( unsigned i = 0; i < p_buf->i_nb_samples; i++ )
172     {
173         float f = p[0];
174         p[0] = p[1];
175         p[1] = f;
176         p += 2;
177     }
178     (void) p_filter;
179     return p_buf;
180 }
181
182 /**
183  * Probes the trivial channel mixer
184  */
185 static int Create( vlc_object_t *p_this )
186 {
187     filter_t *p_filter = (filter_t *)p_this;
188     const audio_format_t *infmt = &p_filter->fmt_in.audio;
189     const audio_format_t *outfmt = &p_filter->fmt_out.audio;
190
191     if( infmt->i_format != outfmt->i_format
192      || infmt->i_rate != outfmt->i_rate
193      || infmt->i_format != VLC_CODEC_FL32 )
194         return VLC_EGENERIC;
195     if( infmt->i_physical_channels == outfmt->i_physical_channels
196      && infmt->i_original_channels == outfmt->i_original_channels )
197         return VLC_EGENERIC;
198
199     if( outfmt->i_physical_channels == AOUT_CHANS_STEREO )
200     {
201         bool swap = (outfmt->i_original_channels & AOUT_CHAN_REVERSESTEREO)
202                   != (infmt->i_original_channels & AOUT_CHAN_REVERSESTEREO);
203
204         if( (outfmt->i_original_channels & AOUT_CHAN_PHYSMASK)
205                                                             == AOUT_CHAN_LEFT )
206         {
207             p_filter->pf_audio_filter = swap ? CopyRight : CopyLeft;
208             return VLC_SUCCESS;
209         }
210
211         if( (outfmt->i_original_channels & AOUT_CHAN_PHYSMASK)
212                                                            == AOUT_CHAN_RIGHT )
213         {
214             p_filter->pf_audio_filter = swap ? CopyLeft : CopyRight;
215             return VLC_SUCCESS;
216         }
217
218         if( swap )
219         {
220             p_filter->pf_audio_filter = ReverseStereo;
221             return VLC_SUCCESS;
222         }
223     }
224
225     if ( aout_FormatNbChannels( outfmt ) == 1 )
226     {
227         bool mono = !!(infmt->i_original_channels & AOUT_CHAN_DUALMONO);
228
229         if( mono && (infmt->i_original_channels & AOUT_CHAN_LEFT) )
230         {
231             p_filter->pf_audio_filter = ExtractLeft;
232             return VLC_SUCCESS;
233         }
234
235         if( mono && (infmt->i_original_channels & AOUT_CHAN_RIGHT) )
236         {
237             p_filter->pf_audio_filter = ExtractRight;
238             return VLC_SUCCESS;
239         }
240     }
241
242     if( aout_FormatNbChannels( outfmt ) > aout_FormatNbChannels( infmt ) )
243         p_filter->pf_audio_filter = Upmix;
244     else
245         p_filter->pf_audio_filter = Downmix;
246
247     return VLC_SUCCESS;
248 }