fix out of buffer read in equalizer code
[vlc.git] / modules / gui / qt4 / components / extended_panels.cpp
1 /*****************************************************************************
2  * extended_panels.cpp : Extended controls panels
3  ****************************************************************************
4  * Copyright (C) 2006 the VideoLAN team
5  * $Id: preferences.cpp 16643 2006-09-13 12:45:46Z zorglub $
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@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 #include <QLabel>
25 #include <QVariant>
26 #include <QString>
27 #include <QFont>
28 #include <QGridLayout>
29 #include <QSignalMapper>
30
31 #include "components/extended_panels.hpp"
32 #include "dialogs/prefs_dialog.hpp"
33 #include "dialogs_provider.hpp"
34 #include "qt4.hpp"
35
36 #include "../../audio_filter/equalizer_presets.h"
37 #include <vlc_aout.h>
38 #include <vlc_intf_strings.h>
39 #include <vlc_vout.h>
40 #include <assert.h>
41
42 class ConfClickHandler : public QObject
43 {
44 public:
45     ConfClickHandler( intf_thread_t *_p_intf, ExtVideo *_e ) : QObject (_e) {
46         e = _e; p_intf = _p_intf;
47     }
48     virtual ~ConfClickHandler() {}
49     bool eventFilter( QObject *obj, QEvent *evt )
50     {
51         if( evt->type() == QEvent::MouseButtonPress )
52         {
53             e->gotoConf( obj );
54             return true;
55         }
56         return false;
57     }
58 private:
59     ExtVideo* e;
60     intf_thread_t *p_intf;
61 };
62
63 #define SETUP_VFILTER( widget, conf, tooltip, labtooltip ) \
64     ui.widget##Check->setToolTip( tooltip ); \
65     if (conf ) {\
66         ui.widget##Label->setToolTip( labtooltip ); \
67         ui.widget##Label->setPixmap( QPixmap(":/pixmaps/go-next.png") ); \
68         ui.widget##Label->installEventFilter(h); \
69     } \
70     CONNECT( ui.widget##Check, clicked(), this, updateFilters() ); \
71
72 ExtVideo::ExtVideo( intf_thread_t *_p_intf, QWidget *_parent ) :
73                            QWidget( _parent ) , p_intf( _p_intf )
74 {
75     ConfClickHandler* h = new ConfClickHandler( p_intf, this );
76
77     ui.setupUi( this );
78
79     SETUP_VFILTER( clone, true, qtr(I_CLONE_TIP),
80                                 qtr("Configure the clone filter") );
81     SETUP_VFILTER( magnify, false, qtr(I_MAGNIFY_TIP),
82                                 qtr("Configure the magnification effect"));
83     SETUP_VFILTER( wave, false, qtr(I_WAVE_TIP),
84                                 qtr("Configure the waves effect"));
85     SETUP_VFILTER( ripple, false, qtr(I_RIPPLE_TIP),
86                                   qtr("Configure the \"water\" effect"));
87     SETUP_VFILTER( invert, false, qtr(I_INVERT_TIP),
88                                   qtr("Configure the color inversion effect"));
89     SETUP_VFILTER( puzzle, true, qtr(I_PUZZLE_TIP),
90                                   qtr("Configure the puzzle effect"));
91     SETUP_VFILTER( wall, true, qtr(I_WALL_TIP),
92                                qtr("Configure the wall filter") );
93     SETUP_VFILTER( gradient, true, qtr(I_GRADIENT_TIP),
94                                    qtr("Configure the \"gradient\" effect"));
95     SETUP_VFILTER( colorthres, true, qtr(I_COLORTHRES_TIP),
96                                    qtr("Configure the color detection effect"));
97 }
98
99 ExtVideo::~ExtVideo()
100 {
101 }
102
103 static void ChangeVFiltersString( intf_thread_t *p_intf,
104                                  char *psz_name, vlc_bool_t b_add )
105 {
106     vout_thread_t *p_vout;
107     char *psz_parser, *psz_string;
108
109     psz_string = config_GetPsz( p_intf, "video-filter" );
110
111     if( !psz_string ) psz_string = strdup("");
112
113     psz_parser = strstr( psz_string, psz_name );
114
115     if( b_add )
116     {
117         if( !psz_parser )
118         {
119             psz_parser = psz_string;
120             asprintf( &psz_string, (*psz_string) ? "%s:%s" : "%s%s",
121                             psz_string, psz_name );
122             free( psz_parser );
123         }
124         else
125         {
126             return;
127         }
128     }
129     else
130     {
131         if( psz_parser )
132         {
133             memmove( psz_parser, psz_parser + strlen(psz_name) +
134                             (*(psz_parser + strlen(psz_name)) == ':' ? 1 : 0 ),
135                             strlen(psz_parser + strlen(psz_name)) + 1 );
136
137             /* Remove trailing : : */
138             if( *(psz_string+strlen(psz_string ) -1 ) == ':' )
139             {
140                 *(psz_string+strlen(psz_string ) -1 ) = '\0';
141             }
142          }
143          else
144          {
145              free( psz_string );
146              return;
147          }
148     }
149     /* Vout is not kept, so put that in the config */
150     config_PutPsz( p_intf, "video-filter", psz_string );
151
152     /* Try to set on the fly */
153     p_vout = (vout_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
154                                               FIND_ANYWHERE );
155     if( p_vout )
156     {
157         var_SetString( p_vout, "video-filter", psz_string );
158         vlc_object_release( p_vout );
159     }
160
161     free( psz_string );
162 }
163
164 void ExtVideo::updateFilters()
165 {
166     QCheckBox* filter = qobject_cast<QCheckBox*>(sender());
167     QString module = filter->objectName().replace("Check", "");
168
169     ChangeVFiltersString( p_intf, qtu(module), filter->isChecked() );
170 }
171
172 void ExtVideo::gotoConf( QObject* src )
173 {
174 #define SHOWCONF(module) \
175     if( src->objectName().contains(module) ) \
176     { \
177         PrefsDialog::getInstance( p_intf )->showModulePrefs( module ); \
178         return; \
179     }
180     SHOWCONF( "clone" );
181     SHOWCONF( "magnify" );
182     SHOWCONF( "wave" );
183     SHOWCONF( "ripple" );
184     SHOWCONF( "invert" );
185     SHOWCONF( "puzzle" );
186     SHOWCONF( "wall" );
187     SHOWCONF( "gradient" );
188     SHOWCONF( "colorthres" )
189 }
190
191 /**********************************************************************
192  * Equalizer
193  **********************************************************************/
194
195 static const QString band_frequencies[] =
196 {
197     "   60Hz  ", " 170 Hz " , " 310 Hz ", " 600 Hz ", "  1 kHz  ",
198     "  3 kHz  " , "  6 kHz ", " 12 kHz ", " 14 kHz ", " 16 kHz "
199 };
200
201 Equalizer::Equalizer( intf_thread_t *_p_intf, QWidget *_parent ) :
202                             QWidget( _parent ) , p_intf( _p_intf )
203 {
204     QFont smallFont = QApplication::font( static_cast<QWidget*>(0) );
205     smallFont.setPointSize( smallFont.pointSize() - 3 );
206
207     ui.setupUi( this );
208
209     ui.preampLabel->setFont( smallFont );
210     ui.preampSlider->setMaximum( 400 );
211     for( int i = 0 ; i < NB_PRESETS ; i ++ )
212     {
213         ui.presetsCombo->addItem( qtr( preset_list_text[i] ),
214                                   QVariant( i ) );
215     }
216     CONNECT( ui.presetsCombo, activated( int ), this, setPreset( int ) );
217
218     BUTTONACT( ui.enableCheck, enable() );
219     BUTTONACT( ui.eq2PassCheck, set2Pass() );
220
221     CONNECT( ui.preampSlider, valueChanged(int), this, setPreamp() );
222
223     QGridLayout *grid = new QGridLayout( ui.frame );
224     grid->setMargin( 0 );
225     for( int i = 0 ; i < BANDS ; i++ )
226     {
227         bands[i] = new QSlider( Qt::Vertical );
228         bands[i]->setMaximum( 400 );
229         bands[i]->setValue( 200 );
230         CONNECT( bands[i], valueChanged(int), this, setBand() );
231         band_texts[i] = new QLabel( band_frequencies[i] + "\n0.0dB" );
232         band_texts[i]->setFont( smallFont );
233         grid->addWidget( bands[i], 0, i );
234         grid->addWidget( band_texts[i], 1, i );
235     }
236
237     /* Write down initial values */
238     aout_instance_t *p_aout = (aout_instance_t *)vlc_object_find(p_intf,
239                                     VLC_OBJECT_AOUT, FIND_ANYWHERE);
240     char *psz_af = NULL;
241     char *psz_bands;
242     float f_preamp;
243     if( p_aout )
244     {
245         psz_af = var_GetString( p_aout, "audio-filter" );
246         if( var_GetBool( p_aout, "equalizer-2pass" ) )
247             ui.eq2PassCheck->setChecked( true );
248         psz_bands = var_GetString( p_aout, "equalizer-bands" );
249         f_preamp = var_GetFloat( p_aout, "equalizer-preamp" );
250         vlc_object_release( p_aout );
251     }
252     else
253     {
254         psz_af = config_GetPsz( p_intf, "audio-filter" );
255         if( config_GetInt( p_intf, "equalizer-2pass" ) )
256             ui.eq2PassCheck->setChecked( true );
257         psz_bands = config_GetPsz( p_intf, "equalizer-bands" );
258         f_preamp = config_GetFloat( p_intf, "equalizer-preamp" );
259     }
260     if( psz_af && strstr( psz_af, "equalizer" ) != NULL )
261         ui.enableCheck->setChecked( true );
262     enable( ui.enableCheck->isChecked() );
263
264     setValues( psz_bands, f_preamp );
265 }
266
267 Equalizer::~Equalizer()
268 {
269 }
270
271 void Equalizer::enable()
272 {
273     bool en = ui.enableCheck->isChecked();
274     aout_EnableFilter( VLC_OBJECT( p_intf ), "equalizer",
275                        en ? VLC_TRUE : VLC_FALSE );
276     enable( en );
277 }
278
279 void Equalizer::enable( bool en )
280 {
281     ui.eq2PassCheck->setEnabled( en );
282     ui.preampLabel->setEnabled( en );
283     ui.preampSlider->setEnabled( en  );
284     for( int i = 0 ; i< BANDS; i++ )
285     {
286         bands[i]->setEnabled( en ); band_texts[i]->setEnabled( en );
287     }
288 }
289
290 void Equalizer::set2Pass()
291 {
292     aout_instance_t *p_aout= (aout_instance_t *)vlc_object_find(p_intf,
293                                  VLC_OBJECT_AOUT, FIND_ANYWHERE);
294     vlc_bool_t b_2p = ui.eq2PassCheck->isChecked();
295
296     if( p_aout == NULL )
297         config_PutInt( p_intf, "equalizer-2pass", b_2p );
298     else
299     {
300         var_SetBool( p_aout, "equalizer-2pass", b_2p );
301         config_PutInt( p_intf, "equalizer-2pass", b_2p );
302         for( int i = 0; i < p_aout->i_nb_inputs; i++ )
303         {
304             p_aout->pp_inputs[i]->b_restart = VLC_TRUE;
305         }
306         vlc_object_release( p_aout );
307     }
308 }
309
310 void Equalizer::setPreamp()
311 {
312     float f= (float)(  ui.preampSlider->value() ) /10 - 20;
313     char psz_val[5];
314     aout_instance_t *p_aout= (aout_instance_t *)vlc_object_find(p_intf,
315                                        VLC_OBJECT_AOUT, FIND_ANYWHERE);
316
317     sprintf( psz_val, "%.1f", f );
318     ui.preampLabel->setText( qtr("Preamp\n") + psz_val + qtr("dB") );
319     if( p_aout )
320     {
321         delCallbacks( p_aout );
322         var_SetFloat( p_aout, "equalizer-preamp", f );
323         addCallbacks( p_aout );
324         vlc_object_release( p_aout );
325     }
326     config_PutFloat( p_intf, "equalizer-preamp", f );
327 }
328
329 void Equalizer::setBand()
330 {
331     char psz_values[102]; memset( psz_values, 0, 102 );
332
333     /**\todo smoothing */
334
335     for( int i = 0 ; i< BANDS ; i++ )
336     {
337         char psz_val[5];
338         float f_val = (float)(  bands[i]->value() ) / 10 - 20 ;
339         sprintf( psz_values, "%s %f", psz_values, f_val );
340         sprintf( psz_val, "% 5.1f", f_val );
341         band_texts[i]->setText( band_frequencies[i] + "\n" + psz_val + "dB" );
342     }
343     aout_instance_t *p_aout= (aout_instance_t *)vlc_object_find(p_intf,
344                                           VLC_OBJECT_AOUT, FIND_ANYWHERE);
345     if( p_aout )
346     {
347         delCallbacks( p_aout );
348         var_SetString( p_aout, "equalizer-bands", psz_values );
349         addCallbacks( p_aout );
350         vlc_object_release( p_aout );
351     }
352 }
353 void Equalizer::setValues( char *psz_bands, float f_preamp )
354 {
355     char *p = psz_bands;
356     if ( p )
357     {
358         for( int i = 0; i < 10; i++ )
359         {
360             char psz_val[5];
361             float f = strtof( p, &p );
362             int  i_val= (int)( ( f + 20 ) * 10 );
363             bands[i]->setValue(  i_val );
364             sprintf( psz_val, "% 5.1f", f );
365             band_texts[i]->setText( band_frequencies[i] + "\n" + psz_val +
366                                     "dB" );
367             if( p == NULL || *p == '\0' ) break;
368             p++;
369             if( *p == '\0' )  break;
370         }
371     }
372     char psz_val[5];
373     int i_val = (int)( ( f_preamp + 20 ) * 10 );
374     sprintf( psz_val, "%.1f", f_preamp );
375     ui.preampSlider->setValue( i_val );
376     ui.preampLabel->setText( qtr("Preamp\n") + psz_val + qtr("dB") );
377 }
378
379 void Equalizer::setPreset( int preset )
380 {
381     aout_instance_t *p_aout= (aout_instance_t *)vlc_object_find(p_intf,
382                                                 VLC_OBJECT_AOUT, FIND_ANYWHERE);
383
384     char psz_values[102]; memset( psz_values, 0, 102 );
385     for( int i = 0 ; i< 10 ;i++ )
386         sprintf( psz_values, "%s %.1f", psz_values,
387                                         eqz_preset_10b[preset]->f_amp[i] );
388
389     if( p_aout )
390     {
391         delCallbacks( p_aout );
392         var_SetString( p_aout, "equalizer-bands", psz_values );
393         var_SetFloat( p_aout, "equalizer-preamp",
394                       eqz_preset_10b[preset]->f_preamp );
395         addCallbacks( p_aout );
396         vlc_object_release( p_aout );
397     }
398     config_PutPsz( p_intf, "equalizer-bands", psz_values );
399     config_PutFloat( p_intf, "equalizer-preamp",
400                     eqz_preset_10b[preset]->f_preamp );
401
402     setValues( psz_values, eqz_preset_10b[preset]->f_preamp );
403 }
404
405 void Equalizer::delCallbacks( aout_instance_t *p_aout )
406 {
407 //    var_DelCallback( p_aout, "equalizer-bands", EqzCallback, this );
408 //    var_DelCallback( p_aout, "equalizer-preamp", EqzCallback, this );
409 }
410
411 void Equalizer::addCallbacks( aout_instance_t *p_aout )
412 {
413 //    var_AddCallback( p_aout, "equalizer-bands", EqzCallback, this );
414 //    var_AddCallback( p_aout, "equalizer-preamp", EqzCallback, this );
415 }
416
417
418 /**********************************************************************
419  * Video filters / Adjust
420  **********************************************************************/
421
422 /**********************************************************************
423  * Audio filters
424  **********************************************************************/
425
426 /**********************************************************************
427  * Extended playbak controls
428  **********************************************************************/