]> git.sesse.net Git - vlc/blob - modules/audio_filter/spatializer/spatializer.cpp
Fix assertions. (dts-dynrng and spdif are boolean parameters)
[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 along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdlib.h>                                      /* malloc(), free() */
35 #include <math.h>
36
37 #include <new>
38 using std::nothrow;
39
40 #include <vlc_common.h>
41 #include <vlc_plugin.h>
42 #include <vlc_aout.h>
43 #include <vlc_filter.h>
44
45 #include "revmodel.hpp"
46 #define SPAT_AMP 0.3
47
48 /*****************************************************************************
49  * Module descriptor
50  *****************************************************************************/
51 static int  Open ( vlc_object_t * );
52 static void Close( vlc_object_t * );
53
54 #define ROOMSIZE_TEXT N_("Room size")
55 #define ROOMSIZE_LONGTEXT N_("Defines the virtual surface of the room" \
56                              " emulated by the filter." )
57
58 #define WIDTH_TEXT N_("Room width")
59 #define WIDTH_LONGTEXT N_("Width of the virtual room")
60
61 #define WET_TEXT N_("Wet")
62 #define WET_LONGTEXT NULL
63
64 #define DRY_TEXT N_("Dry")
65 #define DRY_LONGTEXT NULL
66
67 #define DAMP_TEXT N_("Damp")
68 #define DAMP_LONGTEXT NULL
69
70 vlc_module_begin ()
71     set_description( N_("Audio Spatializer") )
72     set_shortname( N_("Spatializer" ) )
73     set_capability( "audio filter", 0 )
74     set_category( CAT_AUDIO )
75     set_subcategory( SUBCAT_AUDIO_AFILTER )
76
77     set_callbacks( Open, Close )
78     add_shortcut( "spatializer" )
79     add_float( "spatializer-roomsize", 1.05, NULL, ROOMSIZE_TEXT,
80                ROOMSIZE_LONGTEXT, true )
81     add_float( "spatializer-width", 10., NULL, WIDTH_TEXT,WIDTH_LONGTEXT, true )
82     add_float( "spatializer-wet", 3., NULL, WET_TEXT,WET_LONGTEXT, true )
83     add_float( "spatializer-dry", 2., NULL, DRY_TEXT,DRY_LONGTEXT, true )
84     add_float( "spatializer-damp", 1., NULL, DAMP_TEXT,DAMP_LONGTEXT, true )
85 vlc_module_end ()
86
87 /*****************************************************************************
88  * Local prototypes
89  *****************************************************************************/
90 struct filter_sys_t
91 {
92     vlc_mutex_t lock;
93     revmodel *p_reverbm;
94 };
95
96 #define DECLARECB(fn) static int fn (vlc_object_t *,char const *, \
97                                      vlc_value_t, vlc_value_t, void *)
98 DECLARECB( RoomCallback  );
99 DECLARECB( WetCallback   );
100 DECLARECB( DryCallback   );
101 DECLARECB( DampCallback  );
102 DECLARECB( WidthCallback );
103
104 #undef  DECLARECB
105
106 struct callback_s {
107   const char *psz_name;
108   int (*fp_callback)(vlc_object_t *,const char *,
109                      vlc_value_t,vlc_value_t,void *);
110   void (revmodel::* fp_set)(float);
111 };
112
113 static const callback_s callbacks[] = {
114     { "spatializer-roomsize", RoomCallback,  &revmodel::setroomsize },
115     { "spatializer-width",    WidthCallback, &revmodel::setwidth },
116     { "spatializer-wet",      WetCallback,   &revmodel::setwet },
117     { "spatializer-dry",      DryCallback,   &revmodel::setdry },
118     { "spatializer-damp",     DampCallback,  &revmodel::setdamp }
119 };
120 enum { num_callbacks=sizeof(callbacks)/sizeof(callback_s) };
121
122 static block_t *DoWork( filter_t *, block_t * );
123
124 /*****************************************************************************
125  * Open:
126  *****************************************************************************/
127 static int Open( vlc_object_t *p_this )
128 {
129     filter_t     *p_filter = (filter_t *)p_this;
130     filter_sys_t *p_sys;
131     vlc_object_t *p_aout = p_filter->p_parent;
132
133     if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 ||
134         p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
135     {
136         p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
137         p_filter->fmt_out.audio.i_format = VLC_CODEC_FL32;
138         msg_Warn( p_filter, "bad input or output format" );
139         return VLC_EGENERIC;
140     }
141     if ( !AOUT_FMTS_SIMILAR( &p_filter->fmt_in.audio, &p_filter->fmt_out.audio ) )
142     {
143         memcpy( &p_filter->fmt_out.audio, &p_filter->fmt_in.audio,
144                 sizeof(audio_sample_format_t) );
145         msg_Warn( p_filter, "input and output formats are not similar" );
146         return VLC_EGENERIC;
147     }
148
149     p_filter->pf_audio_filter = DoWork;
150
151      /* Allocate structure */
152     p_sys = p_filter->p_sys = (filter_sys_t*)malloc( sizeof( *p_sys ) );
153     if( !p_sys )
154         return VLC_ENOMEM;
155
156     /* Force new to return 0 on failure instead of throwing, since we don't
157        want an exception to leak back to C code. Bad things would happen. */
158     p_sys->p_reverbm = new (nothrow) revmodel;
159     if( !p_sys->p_reverbm )
160     {
161         free( p_sys );
162         return VLC_ENOMEM;
163     }
164
165     vlc_mutex_init( &p_sys->lock );
166
167     for(unsigned i=0;i<num_callbacks;++i)
168     {
169         /* NOTE: C++ pointer-to-member function call from table lookup. */
170         (p_sys->p_reverbm->*(callbacks[i].fp_set))
171             (var_CreateGetFloatCommand(p_aout,callbacks[i].psz_name));
172         var_AddCallback( p_aout, callbacks[i].psz_name,
173                          callbacks[i].fp_callback, p_sys );
174     }
175
176     return VLC_SUCCESS;
177 }
178
179 /*****************************************************************************
180  * Close: close the plugin
181  *****************************************************************************/
182 static void Close( vlc_object_t *p_this )
183 {
184     filter_t     *p_filter = (filter_t *)p_this;
185     filter_sys_t *p_sys = p_filter->p_sys;
186     vlc_object_t *p_aout = p_filter->p_parent;
187
188     /* Delete the callbacks */
189     for(unsigned i=0;i<num_callbacks;++i)
190     {
191         var_DelCallback( p_aout, callbacks[i].psz_name,
192                          callbacks[i].fp_callback, p_sys );
193     }
194
195     delete p_sys->p_reverbm;
196     vlc_mutex_destroy( &p_sys->lock );
197     free( p_sys );
198     msg_Dbg( p_this, "Closing filter spatializer" );
199 }
200
201 /*****************************************************************************
202  * SpatFilter: process samples buffer
203  * DoWork: call SpatFilter
204  *****************************************************************************/
205
206 static void SpatFilter( filter_t *p_filter, float *out, float *in,
207                         unsigned i_samples, unsigned i_channels )
208 {
209     filter_sys_t *p_sys = p_filter->p_sys;
210     vlc_mutex_locker locker( &p_sys->lock );
211
212     for( unsigned i = 0; i < i_samples; i++ )
213     {
214         for( unsigned ch = 0 ; ch < 2; ch++)
215         {
216             in[ch] = in[ch] * SPAT_AMP;
217         }
218         p_sys->p_reverbm->processreplace( in, out , 1, i_channels);
219         in  += i_channels;
220         out += i_channels;
221     }
222 }
223
224 static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
225 {
226     SpatFilter( p_filter, (float*)p_in_buf->p_buffer,
227                (float*)p_in_buf->p_buffer, p_in_buf->i_nb_samples,
228                aout_FormatNbChannels( &p_filter->fmt_in.audio ) );
229     return p_in_buf;
230 }
231
232
233 /*****************************************************************************
234  * Variables callbacks
235  *****************************************************************************/
236
237 static int RoomCallback( vlc_object_t *p_this, char const *,
238                          vlc_value_t, vlc_value_t newval, void *p_data )
239 {
240     filter_sys_t *p_sys = (filter_sys_t*)p_data;
241     vlc_mutex_locker locker( &p_sys->lock );
242
243     p_sys->p_reverbm->setroomsize(newval.f_float);
244     msg_Dbg( p_this, "room size is now %3.1f", newval.f_float );
245     return VLC_SUCCESS;
246 }
247
248 static int WidthCallback( vlc_object_t *p_this, char const *,
249                           vlc_value_t, vlc_value_t newval, void *p_data )
250 {
251     filter_sys_t *p_sys = (filter_sys_t*)p_data;
252     vlc_mutex_locker locker( &p_sys->lock );
253
254     p_sys->p_reverbm->setwidth(newval.f_float);
255     msg_Dbg( p_this, "width is now %3.1f", newval.f_float );
256     return VLC_SUCCESS;
257 }
258
259 static int WetCallback( vlc_object_t *p_this, char const *,
260                         vlc_value_t, vlc_value_t newval, void *p_data )
261 {
262     filter_sys_t *p_sys = (filter_sys_t*)p_data;
263     vlc_mutex_locker locker( &p_sys->lock );
264
265     p_sys->p_reverbm->setwet(newval.f_float);
266     msg_Dbg( p_this, "'wet' value is now %3.1f", newval.f_float );
267     return VLC_SUCCESS;
268 }
269
270 static int DryCallback( vlc_object_t *p_this, char const *,
271                         vlc_value_t, vlc_value_t newval, void *p_data )
272 {
273     filter_sys_t *p_sys = (filter_sys_t*)p_data;
274     vlc_mutex_locker locker( &p_sys->lock );
275
276     p_sys->p_reverbm->setdry(newval.f_float);
277     msg_Dbg( p_this, "'dry' value is now %3.1f", newval.f_float );
278     return VLC_SUCCESS;
279 }
280
281 static int DampCallback( vlc_object_t *p_this, char const *,
282                          vlc_value_t, vlc_value_t newval, void *p_data )
283 {
284     filter_sys_t *p_sys = (filter_sys_t*)p_data;
285     vlc_mutex_locker locker( &p_sys->lock );
286
287     p_sys->p_reverbm->setdamp(newval.f_float);
288     msg_Dbg( p_this, "'damp' value is now %3.1f", newval.f_float );
289     return VLC_SUCCESS;
290 }
291