1 /*****************************************************************************
2 * spatializer.cpp: sound reverberation
3 *****************************************************************************
4 * Copyright (C) 2004, 2006, 2007 the VideoLAN team
6 * Google Summer of Code 2007
8 * Authors: Biodun Osunkunle <biodun@videolan.org>
10 * Mentor : Jean-Baptiste Kempf <jb@videolan.org>
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.
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.
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 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
34 #include <stdlib.h> /* malloc(), free() */
40 #include <vlc_common.h>
41 #include <vlc_plugin.h>
43 #include <vlc_filter.h>
45 #include "revmodel.hpp"
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Open ( vlc_object_t * );
52 static void Close( vlc_object_t * );
54 #define ROOMSIZE_TEXT N_("Room size")
55 #define ROOMSIZE_LONGTEXT N_("Defines the virtual surface of the room" \
56 " emulated by the filter." )
58 #define WIDTH_TEXT N_("Room width")
59 #define WIDTH_LONGTEXT N_("Width of the virtual room")
61 #define WET_TEXT N_("Wet")
62 #define WET_LONGTEXT NULL
64 #define DRY_TEXT N_("Dry")
65 #define DRY_LONGTEXT NULL
67 #define DAMP_TEXT N_("Damp")
68 #define DAMP_LONGTEXT NULL
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 )
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 )
87 /*****************************************************************************
89 *****************************************************************************/
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 );
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);
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 }
120 enum { num_callbacks=sizeof(callbacks)/sizeof(callback_s) };
122 static block_t *DoWork( filter_t *, block_t * );
124 /*****************************************************************************
126 *****************************************************************************/
127 static int Open( vlc_object_t *p_this )
129 filter_t *p_filter = (filter_t *)p_this;
131 vlc_object_t *p_aout = p_filter->p_parent;
133 if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 ||
134 p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
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" );
141 if ( !AOUT_FMTS_SIMILAR( &p_filter->fmt_in.audio, &p_filter->fmt_out.audio ) )
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" );
149 p_filter->pf_audio_filter = DoWork;
151 /* Allocate structure */
152 p_sys = p_filter->p_sys = (filter_sys_t*)malloc( sizeof( *p_sys ) );
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 )
165 vlc_mutex_init( &p_sys->lock );
167 for(unsigned i=0;i<num_callbacks;++i)
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 );
179 /*****************************************************************************
180 * Close: close the plugin
181 *****************************************************************************/
182 static void Close( vlc_object_t *p_this )
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;
188 /* Delete the callbacks */
189 for(unsigned i=0;i<num_callbacks;++i)
191 var_DelCallback( p_aout, callbacks[i].psz_name,
192 callbacks[i].fp_callback, p_sys );
195 delete p_sys->p_reverbm;
196 vlc_mutex_destroy( &p_sys->lock );
198 msg_Dbg( p_this, "Closing filter spatializer" );
201 /*****************************************************************************
202 * SpatFilter: process samples buffer
203 * DoWork: call SpatFilter
204 *****************************************************************************/
206 static void SpatFilter( filter_t *p_filter, float *out, float *in,
207 unsigned i_samples, unsigned i_channels )
209 filter_sys_t *p_sys = p_filter->p_sys;
210 vlc_mutex_locker locker( &p_sys->lock );
212 for( unsigned i = 0; i < i_samples; i++ )
214 for( unsigned ch = 0 ; ch < 2; ch++)
216 in[ch] = in[ch] * SPAT_AMP;
218 p_sys->p_reverbm->processreplace( in, out , 1, i_channels);
224 static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
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 ) );
233 /*****************************************************************************
234 * Variables callbacks
235 *****************************************************************************/
237 static int RoomCallback( vlc_object_t *p_this, char const *,
238 vlc_value_t, vlc_value_t newval, void *p_data )
240 filter_sys_t *p_sys = (filter_sys_t*)p_data;
241 vlc_mutex_locker locker( &p_sys->lock );
243 p_sys->p_reverbm->setroomsize(newval.f_float);
244 msg_Dbg( p_this, "room size is now %3.1f", newval.f_float );
248 static int WidthCallback( vlc_object_t *p_this, char const *,
249 vlc_value_t, vlc_value_t newval, void *p_data )
251 filter_sys_t *p_sys = (filter_sys_t*)p_data;
252 vlc_mutex_locker locker( &p_sys->lock );
254 p_sys->p_reverbm->setwidth(newval.f_float);
255 msg_Dbg( p_this, "width is now %3.1f", newval.f_float );
259 static int WetCallback( vlc_object_t *p_this, char const *,
260 vlc_value_t, vlc_value_t newval, void *p_data )
262 filter_sys_t *p_sys = (filter_sys_t*)p_data;
263 vlc_mutex_locker locker( &p_sys->lock );
265 p_sys->p_reverbm->setwet(newval.f_float);
266 msg_Dbg( p_this, "'wet' value is now %3.1f", newval.f_float );
270 static int DryCallback( vlc_object_t *p_this, char const *,
271 vlc_value_t, vlc_value_t newval, void *p_data )
273 filter_sys_t *p_sys = (filter_sys_t*)p_data;
274 vlc_mutex_locker locker( &p_sys->lock );
276 p_sys->p_reverbm->setdry(newval.f_float);
277 msg_Dbg( p_this, "'dry' value is now %3.1f", newval.f_float );
281 static int DampCallback( vlc_object_t *p_this, char const *,
282 vlc_value_t, vlc_value_t newval, void *p_data )
284 filter_sys_t *p_sys = (filter_sys_t*)p_data;
285 vlc_mutex_locker locker( &p_sys->lock );
287 p_sys->p_reverbm->setdamp(newval.f_float);
288 msg_Dbg( p_this, "'damp' value is now %3.1f", newval.f_float );