]> git.sesse.net Git - vlc/blob - modules/audio_filter/spatializer/spatializer.cpp
d9043495076d6818ab541d42cfd404fbb6ea32c6
[vlc] / modules / audio_filter / spatializer / spatializer.cpp
1 /*****************************************************************************
2  * spatializer.cpp: sound reverberation
3  *****************************************************************************
4  * Copyright (C) 2004, 2006, 2007 the VideoLAN team
5  *
6  * Google Summer of Code 2007
7  *
8  * Authors: Biodun Osunkunle <biodun@videolan.org>
9  *
10  * Mentor : Jean-Baptiste Kempf <jb@videolan.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <stdlib.h>                                      /* malloc(), free() */
31 #include <math.h>
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
39 #include "vlc_aout.h"
40 #include "revmodel.hpp"
41 #define SPAT_AMP 0.3
42 /*****************************************************************************
43  * Module descriptor
44  *****************************************************************************/
45 static int  Open ( vlc_object_t * );
46 static void Close( vlc_object_t * );
47
48 #define ROOMSIZE_TEXT N_("Room size")
49 #define ROOMSIZE_LONGTEXT N_("Defines the virtual surface of the room" \
50                                 "emulated by the filter." )
51
52 #define WIDTH_TEXT N_("Room width")
53 #define WIDTH_LONGTEXT N_("Width of the virtual room")
54
55 #define WET_TEXT ""
56 #define WET_LONGTEXT ""
57
58 #define DRY_TEXT ""
59 #define DRY_LONGTEXT ""
60
61 #define DAMP_TEXT ""
62 #define DAMP_LONGTEXT ""
63
64 vlc_module_begin ()
65     set_description( N_("Audio Spatializer") )
66     set_shortname( N_("Spatializer" ) )
67     set_capability( "audio filter", 0 )
68     set_category( CAT_AUDIO )
69     set_subcategory( SUBCAT_AUDIO_AFILTER )
70
71     set_callbacks( Open, Close )
72     add_shortcut( "spatializer" )
73     add_float( "roomsize", 1.05, NULL, ROOMSIZE_TEXT,ROOMSIZE_LONGTEXT, true)
74     add_float( "width", 10.0, NULL, WIDTH_TEXT,WIDTH_LONGTEXT, true)
75     add_float( "wet", 3.0, NULL, WET_TEXT,WET_LONGTEXT, true)
76     add_float( "dry", 2.0, NULL, DRY_TEXT,DRY_LONGTEXT, true)
77     add_float( "damp", 1.0, NULL, DAMP_TEXT,DAMP_LONGTEXT, true)
78 vlc_module_end ()
79
80 /*****************************************************************************
81  * Local prototypes
82  *****************************************************************************/
83 struct aout_filter_sys_t
84 {
85     vlc_mutex_t lock;
86     revmodel *p_reverbm;
87
88 };
89
90 class CLocker
91 {
92 public:
93     CLocker( vlc_mutex_t *p_lock ) : p_lock(p_lock) {
94         vlc_mutex_lock( p_lock );
95     }
96     virtual ~CLocker() {
97         vlc_mutex_unlock( p_lock );
98     }
99 private:
100     vlc_mutex_t *p_lock;
101 };
102
103 static const char *psz_control_names[] =
104 {
105     "Roomsize", "Width" , "Wet", "Dry", "Damp"
106 };
107 static void DoWork( aout_instance_t *, aout_filter_t *,
108                     aout_buffer_t *, aout_buffer_t * );
109
110 static int  SpatInit( aout_filter_t *);
111 static void SpatFilter( aout_instance_t *,aout_filter_t *, float *, float *,
112                         int, int );
113 static void SpatClean( aout_filter_t * );
114 static int RoomCallback ( vlc_object_t *, char const *,
115                                            vlc_value_t, vlc_value_t, void * );
116 static int WetCallback ( vlc_object_t *, char const *,
117                                            vlc_value_t, vlc_value_t, void * );
118 static int DryCallback ( vlc_object_t *, char const *,
119                                            vlc_value_t, vlc_value_t, void * );
120 static int DampCallback ( vlc_object_t *, char const *,
121                                            vlc_value_t, vlc_value_t, void * );
122 static int WidthCallback ( vlc_object_t *, char const *,
123                                            vlc_value_t, vlc_value_t, void * );
124
125 /*****************************************************************************
126  * Open:
127  *****************************************************************************/
128 static int Open( vlc_object_t *p_this )
129 {
130     aout_filter_t     *p_filter = (aout_filter_t *)p_this;
131     aout_filter_sys_t *p_sys;
132     bool         b_fit = true;
133     msg_Dbg(p_this, "Opening filter spatializer %s %s %d\n", __FILE__,__func__,__LINE__);
134
135     if( p_filter->input.i_format != VLC_FOURCC('f','l','3','2' ) ||
136         p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
137     {
138         b_fit = false;
139         p_filter->input.i_format = VLC_FOURCC('f','l','3','2');
140         p_filter->output.i_format = VLC_FOURCC('f','l','3','2');
141         msg_Warn( p_filter, "bad input or output format" );
142     }
143     if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
144     {
145         b_fit = false;
146         memcpy( &p_filter->output, &p_filter->input,
147                 sizeof(audio_sample_format_t) );
148         msg_Warn( p_filter, "input and output formats are not similar" );
149     }
150
151     if ( ! b_fit )
152     {
153         return VLC_EGENERIC;
154     }
155
156     p_filter->pf_do_work = DoWork;
157     p_filter->b_in_place = true;
158
159      /* Allocate structure */
160     p_sys = p_filter->p_sys = (aout_filter_sys_t*)malloc( sizeof( aout_filter_sys_t ) );
161     if( !p_sys )
162         return VLC_ENOMEM;
163
164     vlc_mutex_init( &p_sys->lock );
165     p_sys->p_reverbm = new revmodel();
166     p_sys->p_reverbm->setroomsize(1.05);
167     p_sys->p_reverbm->setwet(10.0f);
168     p_sys->p_reverbm->setdry(1.0f);
169     p_sys->p_reverbm->setdamp(0.3);
170     p_sys->p_reverbm->setwidth(0.9);
171     SpatInit( p_filter);
172
173     return VLC_SUCCESS;
174 }
175
176 /*****************************************************************************
177  * Close: close the plugin
178  *****************************************************************************/
179 static void Close( vlc_object_t *p_this )
180 {
181     aout_filter_t     *p_filter = (aout_filter_t *)p_this;
182     aout_filter_sys_t *p_sys = p_filter->p_sys;
183     SpatClean( p_filter );
184     delete p_sys->p_reverbm;
185     vlc_mutex_destroy( &p_sys->lock );
186     free( p_sys );
187     msg_Dbg(p_this, "Closing filter spatializer %s %s %d\n", __FILE__,__func__,__LINE__);
188 }
189
190 /*****************************************************************************
191  * DoWork: process samples buffer
192  *****************************************************************************/
193 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
194                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
195 {
196     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
197     p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
198
199     SpatFilter( p_aout, p_filter, (float*)p_out_buf->p_buffer,
200                (float*)p_in_buf->p_buffer, p_in_buf->i_nb_samples,
201                aout_FormatNbChannels( &p_filter->input ) );
202 }
203
204 static int SpatInit( aout_filter_t *p_filter )
205 {
206     aout_filter_sys_t *p_sys = p_filter->p_sys;
207     int i, ch;
208     vlc_value_t val1, val2, val3, val4, val5;
209     aout_instance_t *p_aout = (aout_instance_t *)p_filter->p_parent;
210
211     for( i = 0; i < 5 ; i ++ )
212         var_Create( p_aout, psz_control_names[i], VLC_VAR_FLOAT
213                             | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
214
215     /* Get initial values */
216     var_Get( p_aout, psz_control_names[0], &val1 );
217     var_Get( p_aout, psz_control_names[1], &val2 );
218     var_Get( p_aout, psz_control_names[2], &val3 );
219     var_Get( p_aout, psz_control_names[3], &val4 );
220     var_Get( p_aout, psz_control_names[4], &val5);
221
222     RoomCallback( VLC_OBJECT( p_aout ), NULL, val1, val1, p_sys );
223     WidthCallback( VLC_OBJECT( p_aout ), NULL, val2, val2, p_sys );
224     WetCallback( VLC_OBJECT( p_aout ), NULL, val3, val3, p_sys );
225     DryCallback( VLC_OBJECT( p_aout ), NULL, val4, val4, p_sys );
226     DampCallback( VLC_OBJECT( p_aout ), NULL, val5, val5, p_sys );
227
228     msg_Dbg( p_filter, "%f", val1.f_float );
229     /* Add our own callbacks */
230     var_AddCallback( p_aout, psz_control_names[0], RoomCallback, p_sys );
231     var_AddCallback( p_aout, psz_control_names[1], WidthCallback, p_sys );
232     var_AddCallback( p_aout, psz_control_names[2], WetCallback, p_sys );
233     var_AddCallback( p_aout, psz_control_names[3], DryCallback, p_sys );
234     var_AddCallback( p_aout, psz_control_names[4], DampCallback, p_sys );
235
236     return VLC_SUCCESS;
237 }
238
239 static void SpatFilter( aout_instance_t *p_aout,
240                        aout_filter_t *p_filter, float *out, float *in,
241                        int i_samples, int i_channels )
242 {
243     aout_filter_sys_t *p_sys = p_filter->p_sys;
244     CLocker locker( &p_sys->lock );
245
246     int i, ch, j;
247     for( i = 0; i < i_samples; i++ )
248     {
249         for( ch = 0 ; ch < 2; ch++)
250         {
251             in[ch] = in[ch] * SPAT_AMP;
252         }
253         p_sys->p_reverbm->processreplace( in, out , 1, i_channels);
254         in  += i_channels;
255         out += i_channels;
256     }
257 }
258
259 static void SpatClean( aout_filter_t *p_filter )
260 {
261     aout_instance_t *p_aout = (aout_instance_t *)p_filter->p_parent;
262     aout_filter_sys_t *p_sys = p_filter->p_sys;
263
264     var_DelCallback( p_aout, psz_control_names[0], RoomCallback, p_sys );
265     var_DelCallback( p_aout, psz_control_names[1], WidthCallback, p_sys );
266     var_DelCallback( p_aout, psz_control_names[2], WetCallback, p_sys );
267     var_DelCallback( p_aout, psz_control_names[3], DryCallback, p_sys );
268     var_DelCallback( p_aout, psz_control_names[4], DampCallback, p_sys );
269 }
270
271 /*****************************************************************************
272  * Variables callbacks
273  *****************************************************************************/
274
275 static int RoomCallback( vlc_object_t *p_this, char const *psz_cmd,
276                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
277 {
278     aout_filter_sys_t *p_sys = (aout_filter_sys_t*)p_data;
279     CLocker locker( &p_sys->lock );
280
281     p_sys->p_reverbm->setroomsize(newval.f_float);
282     msg_Dbg (p_this,"room callback %3.1f %s %s %d\n", newval.f_float, __FILE__,__func__,__LINE__);
283     return VLC_SUCCESS;
284 }
285
286 static int WidthCallback( vlc_object_t *p_this, char const *psz_cmd,
287                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
288 {
289     aout_filter_sys_t *p_sys = (aout_filter_sys_t*)p_data;
290     CLocker locker( &p_sys->lock );
291
292     p_sys->p_reverbm->setwidth(newval.f_float);
293     msg_Dbg (p_this,"width callback %3.1f %s %s %d\n", newval.f_float,  __FILE__,__func__,__LINE__);
294     return VLC_SUCCESS;
295 }
296 static int WetCallback( vlc_object_t *p_this, char const *psz_cmd,
297                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
298 {
299     aout_filter_sys_t *p_sys = (aout_filter_sys_t*)p_data;
300     CLocker locker( &p_sys->lock );
301
302     p_sys->p_reverbm->setwet(newval.f_float);
303     msg_Dbg (p_this,"wet callback %3.1f %s %s %d\n", newval.f_float,  __FILE__,__func__,__LINE__);
304     return VLC_SUCCESS;
305 }
306 static int DryCallback( vlc_object_t *p_this, char const *psz_cmd,
307                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
308 {
309     aout_filter_sys_t *p_sys = (aout_filter_sys_t*)p_data;
310     CLocker locker( &p_sys->lock );
311
312     p_sys->p_reverbm->setdry(newval.f_float);
313     msg_Dbg (p_this,"dry callback %3.1f %s %s %d\n", newval.f_float, __FILE__,__func__,__LINE__);
314     return VLC_SUCCESS;
315 }
316 static int DampCallback( vlc_object_t *p_this, char const *psz_cmd,
317                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
318 {
319     aout_filter_sys_t *p_sys = (aout_filter_sys_t*)p_data;
320     CLocker locker( &p_sys->lock );
321
322     p_sys->p_reverbm->setdamp(newval.f_float);
323     msg_Dbg (p_this, "damp callback %3.1f %s %s %d\n", newval.f_float, __FILE__,__func__,__LINE__);
324     return VLC_SUCCESS;
325 }
326