1 /*****************************************************************************
2 * extended_panels.cpp : Extended controls panels
3 ****************************************************************************
4 * Copyright (C) 2006-2013 the VideoLAN team
7 * Authors: Clément Stenac <zorglub@videolan.org>
8 * Antoine Cellerier <dionoea .t videolan d@t org>
9 * Jean-Baptiste Kempf <jb@videolan.org>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * ( at your option ) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
38 #include <QGridLayout>
41 #include <QFileDialog>
42 #include <QGraphicsScene>
45 #include <QApplication>
48 #include "components/extended_panels.hpp"
49 #include "dialogs/preferences.hpp"
51 #include "input_manager.hpp"
52 #include "util/qt_dirs.hpp"
53 #include "util/customwidgets.hpp"
55 #include "../../audio_filter/equalizer_presets.h"
57 #include <vlc_modules.h>
58 #include <vlc_plugin.h>
60 static bool filterIsPresent( const QString
&filters
, const QString
&filter
)
62 QStringList list
= filters
.split( ':', QString::SplitBehavior::SkipEmptyParts
);
63 foreach( const QString
&filterCmp
, list
)
65 if( filterCmp
.compare( filter
) == 0 )
71 static const char* GetVFilterType( struct intf_thread_t
*p_intf
, const char *psz_name
)
73 module_t
*p_obj
= module_find( psz_name
);
76 msg_Err( p_intf
, "Unable to find filter module \"%s\".", psz_name
);
80 if( module_provides( p_obj
, "video splitter" ) )
81 return "video-splitter";
82 else if( module_provides( p_obj
, "video filter" ) )
83 return "video-filter";
84 else if( module_provides( p_obj
, "sub source" ) )
86 else if( module_provides( p_obj
, "sub filter" ) )
90 msg_Err( p_intf
, "Unknown video filter type." );
95 static const QString
ModuleFromWidgetName( QObject
*obj
)
97 return obj
->objectName().replace( "Enable","" );
100 static QString
OptionFromWidgetName( QObject
*obj
)
102 /* Gruik ? ... nah */
103 return obj
->objectName()
104 .remove( QRegExp( "Slider|Combo|Dial|Check|Spin|Text" ) )
105 .replace( QRegExp( "([A-Z])" ), "-\\1" )
109 static inline void setup_vfilter( intf_thread_t
*p_intf
, const char* psz_name
, QWidget
*widget
)
111 const char *psz_filter_type
= GetVFilterType( p_intf
, psz_name
);
112 if( psz_filter_type
== NULL
)
115 char *psz_filters
= var_InheritString( THEPL
, psz_filter_type
);
116 if( psz_filters
== NULL
)
119 QCheckBox
*checkbox
= qobject_cast
<QCheckBox
*>( widget
);
120 QGroupBox
*groupbox
= qobject_cast
<QGroupBox
*>( widget
);
121 if( filterIsPresent( qfu(psz_filters
), qfu(psz_name
) ) )
123 if( checkbox
) checkbox
->setChecked( true ); \
124 else if (groupbox
) groupbox
->setChecked( true ); \
128 if( checkbox
) checkbox
->setChecked( false );
129 else if (groupbox
) groupbox
->setChecked( false );
134 #define SETUP_VFILTER( widget ) \
135 setup_vfilter( p_intf, #widget, ui.widget##Enable ); \
136 CONNECT( ui.widget##Enable, clicked(), this, updateFilters() );
138 #define SETUP_VFILTER_OPTION( widget, signal ) \
139 initComboBoxItems( ui.widget ); \
140 setWidgetValue( ui.widget ); \
141 CONNECT( ui.widget, signal, this, updateFilterOptions() );
143 ExtVideo::ExtVideo( intf_thread_t
*_p_intf
, QTabWidget
*_parent
) :
144 QObject( _parent
), p_intf( _p_intf
)
146 ui
.setupUi( _parent
);
148 SETUP_VFILTER( adjust
)
149 SETUP_VFILTER_OPTION( hueSlider
, valueChanged( int ) )
150 SETUP_VFILTER_OPTION( contrastSlider
, valueChanged( int ) )
151 SETUP_VFILTER_OPTION( brightnessSlider
, valueChanged( int ) )
152 SETUP_VFILTER_OPTION( saturationSlider
, valueChanged( int ) )
153 SETUP_VFILTER_OPTION( gammaSlider
, valueChanged( int ) )
154 SETUP_VFILTER_OPTION( brightnessThresholdCheck
, stateChanged( int ) )
156 SETUP_VFILTER( extract
)
157 SETUP_VFILTER_OPTION( extractComponentText
, textChanged( const QString
& ) )
159 SETUP_VFILTER( posterize
)
161 SETUP_VFILTER( colorthres
)
162 SETUP_VFILTER_OPTION( colorthresColorText
, textChanged( const QString
& ) )
163 SETUP_VFILTER_OPTION( colorthresSaturationthresSlider
, valueChanged( int ) )
164 SETUP_VFILTER_OPTION( colorthresSimilaritythresSlider
, valueChanged( int ) )
166 SETUP_VFILTER( sepia
)
167 SETUP_VFILTER_OPTION( sepiaIntensitySpin
, valueChanged( int ) )
169 SETUP_VFILTER( invert
)
171 SETUP_VFILTER( gradient
)
172 SETUP_VFILTER_OPTION( gradientModeCombo
, currentIndexChanged( QString
) )
173 SETUP_VFILTER_OPTION( gradientTypeCheck
, stateChanged( int ) )
174 SETUP_VFILTER_OPTION( gradientCartoonCheck
, stateChanged( int ) )
176 SETUP_VFILTER( motionblur
)
177 SETUP_VFILTER_OPTION( blurFactorSlider
, valueChanged( int ) )
179 SETUP_VFILTER( motiondetect
)
181 SETUP_VFILTER( psychedelic
)
183 SETUP_VFILTER( sharpen
)
184 SETUP_VFILTER_OPTION( sharpenSigmaSlider
, valueChanged( int ) )
186 SETUP_VFILTER( ripple
)
188 SETUP_VFILTER( wave
)
190 SETUP_VFILTER( transform
)
191 SETUP_VFILTER_OPTION( transformTypeCombo
, currentIndexChanged( QString
) )
193 SETUP_VFILTER( rotate
)
194 SETUP_VFILTER_OPTION( rotateAngleDial
, valueChanged( int ) )
195 ui
.rotateAngleDial
->setWrapping( true );
196 ui
.rotateAngleDial
->setNotchesVisible( true );
198 SETUP_VFILTER( puzzle
)
199 SETUP_VFILTER_OPTION( puzzleRowsSpin
, valueChanged( int ) )
200 SETUP_VFILTER_OPTION( puzzleColsSpin
, valueChanged( int ) )
202 SETUP_VFILTER( magnify
)
204 SETUP_VFILTER( clone
)
205 SETUP_VFILTER_OPTION( cloneCountSpin
, valueChanged( int ) )
207 SETUP_VFILTER( wall
)
208 SETUP_VFILTER_OPTION( wallRowsSpin
, valueChanged( int ) )
209 SETUP_VFILTER_OPTION( wallColsSpin
, valueChanged( int ) )
212 SETUP_VFILTER( erase
)
213 SETUP_VFILTER_OPTION( eraseMaskText
, editingFinished() )
214 SETUP_VFILTER_OPTION( eraseYSpin
, valueChanged( int ) )
215 SETUP_VFILTER_OPTION( eraseXSpin
, valueChanged( int ) )
216 BUTTONACT( ui
.eraseBrowseBtn
, browseEraseFile() );
218 SETUP_VFILTER( marq
)
219 SETUP_VFILTER_OPTION( marqMarqueeText
, textChanged( const QString
& ) )
220 SETUP_VFILTER_OPTION( marqPositionCombo
, currentIndexChanged( QString
) )
222 SETUP_VFILTER( logo
)
223 SETUP_VFILTER_OPTION( logoFileText
, editingFinished() )
224 SETUP_VFILTER_OPTION( logoYSpin
, valueChanged( int ) )
225 SETUP_VFILTER_OPTION( logoXSpin
, valueChanged( int ) )
226 SETUP_VFILTER_OPTION( logoOpacitySlider
, valueChanged( int ) )
227 BUTTONACT( ui
.logoBrowseBtn
, browseLogo() );
229 SETUP_VFILTER( gradfun
)
230 SETUP_VFILTER_OPTION( gradfunRadiusSlider
, valueChanged( int ) )
232 SETUP_VFILTER( grain
)
233 SETUP_VFILTER_OPTION( grainVarianceSlider
, valueChanged( int ) )
235 SETUP_VFILTER( mirror
)
237 SETUP_VFILTER( gaussianblur
)
238 SETUP_VFILTER_OPTION( gaussianblurSigmaSlider
, valueChanged( int ) )
240 SETUP_VFILTER( antiflicker
)
241 SETUP_VFILTER_OPTION( antiflickerSofteningSizeSlider
, valueChanged( int ) )
243 SETUP_VFILTER( hqdn3d
)
244 SETUP_VFILTER_OPTION( hqdn3dLumaSpatSlider
, valueChanged( int ) )
245 SETUP_VFILTER_OPTION( hqdn3dLumaTempSlider
, valueChanged( int ) )
246 SETUP_VFILTER_OPTION( hqdn3dChromaSpatSlider
, valueChanged( int ) )
247 SETUP_VFILTER_OPTION( hqdn3dChromaTempSlider
, valueChanged( int ) )
250 SETUP_VFILTER( anaglyph
)
253 #undef SETUP_VFILTER_OPTION
255 CONNECT( ui
.cropTopPx
, valueChanged( int ), this, cropChange() );
256 CONNECT( ui
.cropBotPx
, valueChanged( int ), this, cropChange() );
257 CONNECT( ui
.cropLeftPx
, valueChanged( int ), this, cropChange() );
258 CONNECT( ui
.cropRightPx
, valueChanged( int ), this, cropChange() );
259 CONNECT( ui
.leftRightCropSync
, toggled ( bool ), this, cropChange() );
260 CONNECT( ui
.topBotCropSync
, toggled ( bool ), this, cropChange() );
261 CONNECT( ui
.topBotCropSync
, toggled( bool ),
262 ui
.cropBotPx
, setDisabled( bool ) );
263 CONNECT( ui
.leftRightCropSync
, toggled( bool ),
264 ui
.cropRightPx
, setDisabled( bool ) );
267 void ExtVideo::cropChange()
269 if( ui
.topBotCropSync
->isChecked() )
270 ui
.cropBotPx
->setValue( ui
.cropTopPx
->value() );
271 if( ui
.leftRightCropSync
->isChecked() )
272 ui
.cropRightPx
->setValue( ui
.cropLeftPx
->value() );
274 QVector
<vout_thread_t
*> p_vouts
= THEMIM
->getVouts();
275 foreach( vout_thread_t
*p_vout
, p_vouts
)
277 var_SetInteger( p_vout
, "crop-top", ui
.cropTopPx
->value() );
278 var_SetInteger( p_vout
, "crop-bottom", ui
.cropBotPx
->value() );
279 var_SetInteger( p_vout
, "crop-left", ui
.cropLeftPx
->value() );
280 var_SetInteger( p_vout
, "crop-right", ui
.cropRightPx
->value() );
281 vlc_object_release( p_vout
);
285 void ExtVideo::clean()
287 ui
.cropTopPx
->setValue( 0 );
288 ui
.cropBotPx
->setValue( 0 );
289 ui
.cropLeftPx
->setValue( 0 );
290 ui
.cropRightPx
->setValue( 0 );
293 static QString
ChangeFiltersString( struct intf_thread_t
*p_intf
, const char *psz_filter_type
, const char *psz_name
, bool b_add
)
295 char* psz_chain
= var_GetString( THEPL
, psz_filter_type
);
297 QString
const chain
= QString( psz_chain
? psz_chain
: "" );
298 QStringList list
= chain
.split( ':', QString::SplitBehavior::SkipEmptyParts
);
300 if( b_add
&& std::find(list
.begin(), list
.end(), psz_name
) == list
.end() )
303 list
.removeAll( psz_name
);
307 return list
.join( ":" );
310 static void UpdateVFiltersString( struct intf_thread_t
*p_intf
,
311 const char *psz_filter_type
, const char *value
)
313 var_SetString( THEPL
, psz_filter_type
, value
);
315 /* Try to set non splitter filters on the fly */
316 if( strcmp( psz_filter_type
, "video-splitter" ) )
318 QVector
<vout_thread_t
*> p_vouts
= THEMIM
->getVouts();
319 foreach( vout_thread_t
*p_vout
, p_vouts
)
321 var_SetString( p_vout
, psz_filter_type
, value
);
322 vlc_object_release( p_vout
);
327 void ExtVideo::changeVFiltersString( const char *psz_name
, bool b_add
)
329 const char *psz_filter_type
= GetVFilterType( p_intf
, psz_name
);
330 if( psz_filter_type
== NULL
)
333 QString result
= ChangeFiltersString( p_intf
, psz_filter_type
, psz_name
, b_add
);
335 emit
configChanged( qfu( psz_filter_type
), result
);
337 UpdateVFiltersString( p_intf
, psz_filter_type
, qtu( result
) );
340 void ExtVideo::updateFilters()
342 QString module
= ModuleFromWidgetName( sender() );
344 QCheckBox
*checkbox
= qobject_cast
<QCheckBox
*>( sender() );
345 QGroupBox
*groupbox
= qobject_cast
<QGroupBox
*>( sender() );
347 changeVFiltersString( qtu( module
),
348 checkbox
? checkbox
->isChecked()
349 : groupbox
->isChecked() );
352 #define UPDATE_AND_APPLY_TEXT( widget, file ) \
353 CONNECT( ui.widget, textChanged( const QString& ), \
354 this, updateFilterOptions() ); \
355 ui.widget->setText( toNativeSeparators( file ) ); \
356 ui.widget->disconnect( SIGNAL( textChanged( const QString& ) ) );
358 void ExtVideo::browseLogo()
360 QString file
= QFileDialog::getOpenFileName( NULL
, qtr( "Logo filenames" ),
361 p_intf
->p_sys
->filepath
, "Images (*.png *.jpg);;All (*)" );
363 UPDATE_AND_APPLY_TEXT( logoFileText
, file
);
366 void ExtVideo::browseEraseFile()
368 QString file
= QFileDialog::getOpenFileName( NULL
, qtr( "Image mask" ),
369 p_intf
->p_sys
->filepath
, "Images (*.png *.jpg);;All (*)" );
371 UPDATE_AND_APPLY_TEXT( eraseMaskText
, file
);
374 #undef UPDATE_AND_APPLY_TEXT
376 void ExtVideo::initComboBoxItems( QObject
*widget
)
378 QComboBox
*combobox
= qobject_cast
<QComboBox
*>( widget
);
379 if( !combobox
) return;
381 QString option
= OptionFromWidgetName( widget
);
382 module_config_t
*p_item
= config_FindConfig( qtu( option
) );
385 msg_Err( p_intf
, "Couldn't find option \"%s\".", qtu( option
) );
389 if( p_item
->i_type
== CONFIG_ITEM_INTEGER
390 || p_item
->i_type
== CONFIG_ITEM_BOOL
)
394 ssize_t count
= config_GetIntChoices( VLC_OBJECT( p_intf
),
395 qtu( option
), &values
, &texts
);
396 for( ssize_t i
= 0; i
< count
; i
++ )
398 combobox
->addItem( qtr( texts
[i
] ), qlonglong(values
[i
]) );
404 else if( p_item
->i_type
== CONFIG_ITEM_STRING
)
408 ssize_t count
= config_GetPszChoices( VLC_OBJECT( p_intf
),
409 qtu( option
), &values
, &texts
);
410 for( ssize_t i
= 0; i
< count
; i
++ )
412 combobox
->addItem( qtr( texts
[i
] ), qfu(values
[i
]) );
421 void ExtVideo::setWidgetValue( QObject
*widget
)
423 QString module
= ModuleFromWidgetName( widget
->parent() );
424 //std::cout << "Module name: " << module.toStdString() << std::endl;
425 QString option
= OptionFromWidgetName( widget
);
426 //std::cout << "Option name: " << option.toStdString() << std::endl;
429 int i_type
= config_GetType( qtu( option
) ) & VLC_VAR_CLASS
;
432 case VLC_VAR_INTEGER
:
439 "Module %s's %s variable is of an unsupported type ( %d )",
440 qtu( module
), qtu( option
), i_type
);
443 if( var_Create( THEPL
, qtu( option
), i_type
| VLC_VAR_DOINHERIT
) )
445 if( var_GetChecked( THEPL
, qtu( option
), i_type
, &val
) )
448 /* Try to cast to all the widgets we're likely to encounter. Only
449 * one of the casts is expected to work. */
450 QSlider
*slider
= qobject_cast
<QSlider
*> ( widget
);
451 QCheckBox
*checkbox
= qobject_cast
<QCheckBox
*> ( widget
);
452 QSpinBox
*spinbox
= qobject_cast
<QSpinBox
*> ( widget
);
453 QDoubleSpinBox
*doublespinbox
= qobject_cast
<QDoubleSpinBox
*>( widget
);
454 VLCQDial
*dial
= qobject_cast
<VLCQDial
*> ( widget
);
455 QLineEdit
*lineedit
= qobject_cast
<QLineEdit
*> ( widget
);
456 QComboBox
*combobox
= qobject_cast
<QComboBox
*> ( widget
);
458 if( i_type
== VLC_VAR_INTEGER
|| i_type
== VLC_VAR_BOOL
)
460 if( slider
) slider
->setValue( val
.i_int
);
461 else if( checkbox
) checkbox
->setCheckState( val
.i_int
? Qt::Checked
463 else if( spinbox
) spinbox
->setValue( val
.i_int
);
464 else if( dial
) dial
->setValue( (360 - val
.i_int
) % 360 );
468 snprintf( str
, sizeof(str
), "%06" PRIX64
, val
.i_int
);
469 lineedit
->setText( str
);
471 else if( combobox
) combobox
->setCurrentIndex(
472 combobox
->findData( qlonglong(val
.i_int
) ) );
473 else msg_Warn( p_intf
, "Could not find the correct Integer widget" );
475 else if( i_type
== VLC_VAR_FLOAT
)
477 if( slider
) slider
->setValue( ( int )( val
.f_float
*( double )slider
->tickInterval() ) ); /* hack alert! */
478 else if( doublespinbox
) doublespinbox
->setValue( val
.f_float
);
479 else if( dial
) dial
->setValue( (360 - lroundf(val
.f_float
)) % 360 );
480 else msg_Warn( p_intf
, "Could not find the correct Float widget" );
482 else if( i_type
== VLC_VAR_STRING
)
484 if( lineedit
) lineedit
->setText( qfu( val
.psz_string
) );
485 else if( combobox
) combobox
->setCurrentIndex(
486 combobox
->findData( qfu( val
.psz_string
) ) );
487 else msg_Warn( p_intf
, "Could not find the correct String widget" );
488 free( val
.psz_string
);
492 void ExtVideo::setFilterOption( const char *psz_module
, const char *psz_option
,
493 int i_int
, double f_float
, const char *psz_string
)
495 QVector
<vout_thread_t
*> p_vouts
= THEMIM
->getVouts();
497 bool b_is_command
= false;
499 if( !p_vouts
.isEmpty() )
501 i_type
= var_Type( p_vouts
.at(0), psz_option
);
502 b_is_command
= ( i_type
& VLC_VAR_ISCOMMAND
);
505 i_type
= config_GetType( psz_option
);
508 i_type
&= VLC_VAR_CLASS
;
509 if( i_type
== VLC_VAR_INTEGER
|| i_type
== VLC_VAR_BOOL
)
511 emit
configChanged( qfu( psz_option
), QVariant( i_int
) );
512 if( i_type
== VLC_VAR_INTEGER
)
515 var_SetInteger( THEPL
, psz_option
, i_int
);
519 var_SetBool( THEPL
, psz_option
, i_int
);
523 else if( i_type
== VLC_VAR_FLOAT
)
525 emit
configChanged( qfu( psz_option
), QVariant( f_float
) );
526 var_SetFloat( THEPL
, psz_option
, f_float
);
527 val
.f_float
= f_float
;
529 else if( i_type
== VLC_VAR_STRING
)
531 if( psz_string
== NULL
)
533 emit
configChanged( qfu( psz_option
), QVariant( psz_string
) );
534 var_SetString( THEPL
, psz_option
, psz_string
);
535 val
.psz_string
= (char *) psz_string
;
540 "Module %s's %s variable is of an unsupported type ( %d )",
544 b_is_command
= false;
549 foreach( vout_thread_t
*p_vout
, p_vouts
)
551 var_SetChecked( p_vout
, psz_option
, i_type
, val
);
553 int i_cur_type
= var_Type( p_vout
, psz_option
);
554 assert( ( i_cur_type
& VLC_VAR_CLASS
) == i_type
);
555 assert( !!( i_cur_type
& VLC_VAR_ISCOMMAND
) == b_is_command
);
560 foreach( vout_thread_t
*p_vout
, p_vouts
)
561 vlc_object_release( p_vout
);
564 void ExtVideo::updateFilterOptions()
566 QString module
= ModuleFromWidgetName( sender()->parent() );
567 //msg_Dbg( p_intf, "Module name: %s", qtu( module ) );
568 QString option
= OptionFromWidgetName( sender() );
569 //msg_Dbg( p_intf, "Option name: %s", qtu( option ) );
571 /* Try to cast to all the widgets we're likely to encounter. Only
572 * one of the casts is expected to work. */
573 QSlider
*slider
= qobject_cast
<QSlider
*> ( sender() );
574 QCheckBox
*checkbox
= qobject_cast
<QCheckBox
*> ( sender() );
575 QSpinBox
*spinbox
= qobject_cast
<QSpinBox
*> ( sender() );
576 QDoubleSpinBox
*doublespinbox
= qobject_cast
<QDoubleSpinBox
*>( sender() );
577 VLCQDial
*dial
= qobject_cast
<VLCQDial
*> ( sender() );
578 QLineEdit
*lineedit
= qobject_cast
<QLineEdit
*> ( sender() );
579 QComboBox
*combobox
= qobject_cast
<QComboBox
*> ( sender() );
582 double f_float
= -1.;
586 i_int
= slider
->value();
587 f_float
= ( double )slider
->value() / ( double )slider
->tickInterval(); /* hack alert! */
589 else if( checkbox
) i_int
= checkbox
->checkState() == Qt::Checked
;
590 else if( spinbox
) i_int
= spinbox
->value();
591 else if( doublespinbox
) f_float
= doublespinbox
->value();
593 i_int
= (360 - dial
->value()) % 360;
596 else if( lineedit
) {
597 i_int
= lineedit
->text().toInt( NULL
,16 );
598 f_float
= lineedit
->text().toDouble();
599 val
= lineedit
->text();
601 else if( combobox
) {
602 i_int
= combobox
->itemData( combobox
->currentIndex() ).toInt();
603 val
= combobox
->itemData( combobox
->currentIndex() ).toString();
606 setFilterOption( qtu( module
), qtu( option
), i_int
, f_float
, qtu( val
) );
609 /**********************************************************************
611 **********************************************************************/
613 ExtV4l2::ExtV4l2( intf_thread_t
*_p_intf
, QWidget
*_parent
)
614 : QWidget( _parent
), p_intf( _p_intf
), box( NULL
)
616 QVBoxLayout
*layout
= new QVBoxLayout( this );
617 help
= new QLabel( qtr("No v4l2 instance found.\n"
618 "Please check that the device has been opened with VLC and is playing.\n\n"
619 "Controls will automatically appear here.")
621 help
->setAlignment( Qt::AlignHCenter
| Qt::AlignVCenter
);
622 help
->setWordWrap( true );
623 layout
->addWidget( help
);
627 void ExtV4l2::showEvent( QShowEvent
*event
)
629 QWidget::showEvent( event
);
633 void ExtV4l2::Refresh( void )
635 vlc_object_t
*p_obj
= (vlc_object_t
*)vlc_object_find_name( THEPL
, "v4l2" );
639 layout()->removeWidget( box
);
645 vlc_value_t val
, text
;
646 int i_ret
= var_Change( p_obj
, "controls", VLC_VAR_GETCHOICES
,
650 msg_Err( p_intf
, "Oops, v4l2 object doesn't have a 'controls' variable." );
652 vlc_object_release( p_obj
);
656 box
= new QGroupBox( this );
657 layout()->addWidget( box
);
658 QVBoxLayout
*layout
= new QVBoxLayout( box
);
659 box
->setLayout( layout
);
661 for( int i
= 0; i
< val
.p_list
->i_count
; i
++ )
664 const char *psz_var
= text
.p_list
->p_values
[i
].psz_string
;
666 if( var_Change( p_obj
, psz_var
, VLC_VAR_GETTEXT
, &vartext
, NULL
) )
669 QString name
= qtr( vartext
.psz_string
);
670 free( vartext
.psz_string
);
671 msg_Dbg( p_intf
, "v4l2 control \"%" PRIx64
"\": %s (%s)",
672 val
.p_list
->p_values
[i
].i_int
, psz_var
, qtu( name
) );
674 int i_type
= var_Type( p_obj
, psz_var
);
675 switch( i_type
& VLC_VAR_TYPE
)
677 case VLC_VAR_INTEGER
:
679 QLabel
*label
= new QLabel( name
, box
);
680 QHBoxLayout
*hlayout
= new QHBoxLayout();
681 hlayout
->addWidget( label
);
682 int i_val
= var_GetInteger( p_obj
, psz_var
);
683 if( i_type
& VLC_VAR_HASCHOICE
)
685 QComboBox
*combobox
= new QComboBox( box
);
686 combobox
->setObjectName( qfu( psz_var
) );
688 vlc_value_t val2
, text2
;
689 var_Change( p_obj
, psz_var
, VLC_VAR_GETCHOICES
,
691 for( int j
= 0; j
< val2
.p_list
->i_count
; j
++ )
694 text2
.p_list
->p_values
[j
].psz_string
,
695 qlonglong( val2
.p_list
->p_values
[j
].i_int
) );
696 if( i_val
== val2
.p_list
->p_values
[j
].i_int
)
697 combobox
->setCurrentIndex( j
);
699 var_FreeList( &val2
, &text2
);
701 CONNECT( combobox
, currentIndexChanged( int ), this,
702 ValueChange( int ) );
703 hlayout
->addWidget( combobox
);
707 QSlider
*slider
= new QSlider( box
);
708 slider
->setObjectName( qfu( psz_var
) );
709 slider
->setOrientation( Qt::Horizontal
);
711 var_Change( p_obj
, psz_var
, VLC_VAR_GETMIN
,
713 if( val2
.i_int
< INT_MIN
)
714 val2
.i_int
= INT_MIN
; /* FIXME */
715 slider
->setMinimum( val2
.i_int
);
716 var_Change( p_obj
, psz_var
, VLC_VAR_GETMAX
,
718 if( val2
.i_int
> INT_MAX
)
719 val2
.i_int
= INT_MAX
; /* FIXME */
720 slider
->setMaximum( val2
.i_int
);
721 if( !var_Change( p_obj
, psz_var
, VLC_VAR_GETSTEP
,
723 slider
->setSingleStep( val2
.i_int
);
724 slider
->setValue( i_val
);
725 CONNECT( slider
, valueChanged( int ), this,
726 ValueChange( int ) );
727 hlayout
->addWidget( slider
);
729 layout
->addLayout( hlayout
);
734 QCheckBox
*button
= new QCheckBox( name
, box
);
735 button
->setObjectName( qfu( psz_var
) );
736 button
->setChecked( var_GetBool( p_obj
, psz_var
) );
738 CONNECT( button
, clicked( bool ), this,
739 ValueChange( bool ) );
740 layout
->addWidget( button
);
745 if( i_type
& VLC_VAR_ISCOMMAND
)
747 QPushButton
*button
= new QPushButton( name
, box
);
748 button
->setObjectName( qfu( psz_var
) );
750 CONNECT( button
, clicked( bool ), this,
751 ValueChange( bool ) );
752 layout
->addWidget( button
);
756 QLabel
*label
= new QLabel( name
, box
);
757 layout
->addWidget( label
);
762 msg_Warn( p_intf
, "Unhandled var type for %s", psz_var
);
766 var_FreeList( &val
, &text
);
767 vlc_object_release( p_obj
);
771 msg_Dbg( p_intf
, "Couldn't find v4l2 instance" );
774 QTimer::singleShot( 2000, this, SLOT(Refresh()) );
778 void ExtV4l2::ValueChange( bool value
)
780 ValueChange( (int)value
);
783 void ExtV4l2::ValueChange( int value
)
785 QObject
*s
= sender();
786 vlc_object_t
*p_obj
= (vlc_object_t
*)vlc_object_find_name( THEPL
, "v4l2" );
789 QString var
= s
->objectName();
790 int i_type
= var_Type( p_obj
, qtu( var
) );
791 switch( i_type
& VLC_VAR_TYPE
)
793 case VLC_VAR_INTEGER
:
794 if( i_type
& VLC_VAR_HASCHOICE
)
796 QComboBox
*combobox
= qobject_cast
<QComboBox
*>( s
);
797 value
= combobox
->itemData( value
).toInt();
799 var_SetInteger( p_obj
, qtu( var
), value
);
802 var_SetBool( p_obj
, qtu( var
), value
);
805 var_TriggerCallback( p_obj
, qtu( var
) );
808 vlc_object_release( p_obj
);
812 msg_Warn( p_intf
, "Oops, v4l2 object isn't available anymore" );
817 /**********************************************************************
819 **********************************************************************/
821 FilterSliderData::FilterSliderData( QObject
*parent
, QSlider
*_slider
) :
822 QObject( parent
), slider( _slider
)
826 FilterSliderData::FilterSliderData( QObject
*parent
,
827 intf_thread_t
*_p_intf
,
829 QLabel
*_label
, QLabel
*_nameLabel
,
830 const slider_data_t
*_p_data
):
831 QObject( parent
), slider( _slider
), valueLabel( _label
),
832 nameLabel( _nameLabel
), p_data( _p_data
), p_intf( _p_intf
)
834 slider
->setMinimum( p_data
->f_min
/ p_data
->f_resolution
);
835 slider
->setMaximum( p_data
->f_max
/ p_data
->f_resolution
);
836 nameLabel
->setText( p_data
->descs
);
837 CONNECT( slider
, valueChanged( int ), this, updateText( int ) );
838 setValue( initialValue() );
839 /* In case current == min|max text would not be first updated */
840 if ( slider
->value() == slider
->maximum() ||
841 slider
->value() == slider
->minimum() )
842 updateText( slider
->value() );
843 CONNECT( slider
, valueChanged( int ), this, onValueChanged( int ) );
846 void FilterSliderData::setValue( float f
)
848 slider
->setValue( f
/ p_data
->f_resolution
);
851 void FilterSliderData::updateText( int i
)
853 float f
= ((float) i
) * p_data
->f_resolution
* p_data
->f_visual_multiplier
;
854 valueLabel
->setText( QString( p_data
->units
)
856 .arg( QString::number( f
, 'f', 1 ) ) );
859 float FilterSliderData::initialValue()
861 vlc_object_t
*p_aout
= (vlc_object_t
*) THEMIM
->getAout();
862 float f
= p_data
->f_value
;
865 if ( var_Type( p_aout
, qtu(p_data
->name
) ) == 0 )
867 vlc_object_release( p_aout
);
868 /* Not found, will try in config */
872 f
= var_GetFloat( p_aout
, qtu(p_data
->name
) );
873 vlc_object_release( p_aout
);
878 if ( ! config_FindConfig( qtu(p_data
->name
) ) )
881 f
= config_GetFloat( p_intf
, qtu(p_data
->name
) );
885 void FilterSliderData::onValueChanged( int i
)
887 float f
= ((float) i
) * p_data
->f_resolution
;
888 vlc_object_t
*p_aout
= (vlc_object_t
*) THEMIM
->getAout();
891 var_SetFloat( p_aout
, qtu(p_data
->name
), f
);
892 vlc_object_release( p_aout
);
897 void FilterSliderData::writeToConfig()
899 float f
= ((float) slider
->value()) * p_data
->f_resolution
;
900 emit
configChanged( p_data
->name
, QVariant( f
) );
903 AudioFilterControlWidget::AudioFilterControlWidget
904 ( intf_thread_t
*_p_intf
, QWidget
*parent
, const char *_shortcut
,
905 const char *_name
= NULL
) :
906 QWidget( parent
), p_intf( _p_intf
), shortcut( _shortcut
),
907 name( _name
? _name
: _shortcut
), i_smallfont(0)
911 void AudioFilterControlWidget::connectConfigChanged( FilterSliderData
*slider
)
913 connect( slider
, SIGNAL( configChanged(QString
, QVariant
) ),
914 this, SIGNAL( configChanged(QString
, QVariant
) ) );
917 void AudioFilterControlWidget::build()
919 QFont smallFont
= QApplication::font();
920 smallFont
.setPointSize( smallFont
.pointSize() + i_smallfont
);
922 QVBoxLayout
*layout
= new QVBoxLayout( this );
923 slidersBox
= new QGroupBox( qtr( "Enable" ) );
924 slidersBox
->setCheckable( true );
925 layout
->addWidget( slidersBox
);
927 QGridLayout
*ctrlLayout
= new QGridLayout( slidersBox
);
930 foreach( const FilterSliderData::slider_data_t
&data
, controls
)
932 QSlider
*slider
= new QSlider( Qt::Vertical
);
933 QLabel
*valueLabel
= new QLabel();
934 valueLabel
->setFont( smallFont
);
935 valueLabel
->setAlignment( Qt::AlignHCenter
);
936 QLabel
*nameLabel
= new QLabel();
937 nameLabel
->setFont( smallFont
);
938 nameLabel
->setAlignment( Qt::AlignHCenter
);
939 FilterSliderData
*filter
=
940 new FilterSliderData( this, p_intf
,
941 slider
, valueLabel
, nameLabel
, & data
);
942 ctrlLayout
->addWidget( slider
, 0, i
, Qt::AlignHCenter
);
943 ctrlLayout
->addWidget( valueLabel
, 1, i
, Qt::AlignHCenter
);
944 ctrlLayout
->addWidget( nameLabel
, 2, i
, Qt::AlignHCenter
);
946 sliderDatas
<< filter
;
947 connectConfigChanged( filter
);
950 char *psz_af
= var_InheritString( THEPL
, "audio-filter" );
952 if( psz_af
&& filterIsPresent( qfu(psz_af
), shortcut
) )
953 slidersBox
->setChecked( true );
955 slidersBox
->setChecked( false );
956 CONNECT( slidersBox
, toggled(bool), this, enable(bool) );
961 void AudioFilterControlWidget::enable( bool b_enable
)
963 module_t
*p_obj
= module_find( qtu(name
) );
966 msg_Err( p_intf
, "Unable to find filter module \"%s\".", qtu(name
) );
970 QString result
= ChangeFiltersString( p_intf
, "audio-filter", qtu(shortcut
),
972 emit
configChanged( qfu("audio-filter"), result
);
973 playlist_EnableAudioFilter( THEPL
, qtu(shortcut
), b_enable
);
976 /**********************************************************************
978 **********************************************************************/
980 EqualizerSliderData::EqualizerSliderData( QObject
*parent
, intf_thread_t
*_p_intf
,
981 QSlider
*slider
, QLabel
*_label
,
982 QLabel
*_nameLabel
, const slider_data_t
*_p_data
,
984 : FilterSliderData( parent
, slider
), index( _index
)
988 nameLabel
= _nameLabel
;
991 slider
->setMinimum( p_data
->f_min
/ p_data
->f_resolution
);
992 slider
->setMaximum( p_data
->f_max
/ p_data
->f_resolution
);
993 nameLabel
->setText( p_data
->descs
);
994 CONNECT( slider
, valueChanged( int ), this, updateText( int ) );
995 setValue( initialValue() );
996 updateText( slider
->value() );
997 CONNECT( slider
, valueChanged( int ), this, onValueChanged( int ) );
1000 QStringList
EqualizerSliderData::getBandsFromAout() const
1002 vlc_object_t
*p_aout
= (vlc_object_t
*) THEMIM
->getAout();
1006 if ( var_Type( p_aout
, qtu(p_data
->name
) ) == VLC_VAR_STRING
)
1008 char *psz_bands
= var_GetString( p_aout
, qtu(p_data
->name
) );
1011 bands
= QString( psz_bands
).split( " ", QString::SkipEmptyParts
);
1015 vlc_object_release( p_aout
);
1018 if ( bands
.count() ) return bands
;
1019 /* Or try config then */
1021 if ( ! config_FindConfig( qtu(p_data
->name
) ) )
1024 char *psz_bands
= config_GetPsz( p_intf
, qtu(p_data
->name
) );
1027 bands
= QString( psz_bands
).split( " ", QString::SkipEmptyParts
);
1034 float EqualizerSliderData::initialValue()
1036 float f
= p_data
->f_value
;
1037 QStringList bands
= getBandsFromAout();
1039 if ( bands
.count() > index
)
1040 f
= QLocale( QLocale::C
).toFloat( bands
[ index
] );
1045 void EqualizerSliderData::onValueChanged( int i
)
1047 QStringList bands
= getBandsFromAout();
1048 if ( bands
.count() > index
)
1050 float f
= ((float) i
) * p_data
->f_resolution
;
1051 bands
[ index
] = QLocale( QLocale::C
).toString( f
);
1052 vlc_object_t
*p_aout
= (vlc_object_t
*) THEMIM
->getAout();
1055 var_SetString( p_aout
, qtu(p_data
->name
), qtu(bands
.join( " " )) );
1056 vlc_object_release( p_aout
);
1062 void EqualizerSliderData::writeToConfig()
1064 QStringList bands
= getBandsFromAout();
1065 if ( bands
.count() > index
)
1067 float f
= (float) slider
->value() * p_data
->f_resolution
;
1068 bands
[ index
] = QLocale( QLocale::C
).toString( f
);
1069 emit
configChanged( p_data
->name
, QVariant( bands
.join( " " ) ) );
1073 Equalizer::Equalizer( intf_thread_t
*p_intf
, QWidget
*parent
)
1074 : AudioFilterControlWidget( p_intf
, parent
, "equalizer" )
1077 bool b_vlcBands
= var_InheritBool( p_intf
, "equalizer-vlcfreqs" );
1079 const FilterSliderData::slider_data_t vlc_bands
[10] =
1081 { "equalizer-bands", qtr("60 Hz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1082 { "equalizer-bands", qtr("170 Hz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1083 { "equalizer-bands", qtr("310 Hz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1084 { "equalizer-bands", qtr("600 Hz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1085 { "equalizer-bands", qtr("1 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1086 { "equalizer-bands", qtr("3 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1087 { "equalizer-bands", qtr("6 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1088 { "equalizer-bands", qtr("12 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1089 { "equalizer-bands", qtr("14 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1090 { "equalizer-bands", qtr("16 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1092 const FilterSliderData::slider_data_t iso_bands
[10] =
1094 { "equalizer-bands", qtr("31 Hz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1095 { "equalizer-bands", qtr("63 Hz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1096 { "equalizer-bands", qtr("125 Hz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1097 { "equalizer-bands", qtr("250 Hz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1098 { "equalizer-bands", qtr("500 Hz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1099 { "equalizer-bands", qtr("1 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1100 { "equalizer-bands", qtr("2 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1101 { "equalizer-bands", qtr("4 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1102 { "equalizer-bands", qtr("8 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1103 { "equalizer-bands", qtr("16 KHz"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 },
1105 const FilterSliderData::slider_data_t preamp_vals
=
1106 { "equalizer-preamp", qtr("Preamp"), qtr("dB"), -20.0f
, 20.0f
, 0.0f
, 0.1f
, 1.0 };
1108 for( int i
=0; i
<10 ;i
++ ) controls
.append( (b_vlcBands
) ? vlc_bands
[i
] : iso_bands
[i
] );
1109 preamp_values
= preamp_vals
;
1113 void Equalizer::build()
1115 QFont smallFont
= QApplication::font();
1116 smallFont
.setPointSize( smallFont
.pointSize() + i_smallfont
);
1118 Ui::EqualizerWidget ui
;
1121 QGridLayout
*ctrlLayout
= new QGridLayout( ui
.slidersPlaceholder
);
1123 /* set up preamp control */
1124 ui
.preampLabel
->setFont( smallFont
);
1125 ui
.preampValue
->setFont( smallFont
);
1126 preamp
= new FilterSliderData( this, p_intf
,
1127 ui
.preampSlider
, ui
.preampValue
, ui
.preampLabel
, & preamp_values
);
1128 connectConfigChanged( preamp
);
1130 /* fix sliders spacing accurately */
1131 int i_width
= qMax( QFontMetrics( smallFont
).width( "500 Hz" ),
1132 QFontMetrics( smallFont
).width( "-20.0 dB" ) );
1134 foreach( const FilterSliderData::slider_data_t
&data
, controls
)
1136 QSlider
*slider
= new QSlider( Qt::Vertical
);
1137 slider
->setMinimumWidth( i_width
);
1138 QLabel
*valueLabel
= new QLabel();
1139 valueLabel
->setFont( smallFont
);
1140 valueLabel
->setAlignment( Qt::AlignHCenter
);
1141 QLabel
*nameLabel
= new QLabel();
1142 nameLabel
->setFont( smallFont
);
1143 nameLabel
->setAlignment( Qt::AlignHCenter
);
1144 EqualizerSliderData
*filter
=
1145 new EqualizerSliderData( this, p_intf
,
1146 slider
, valueLabel
, nameLabel
, & data
, i
);
1147 ctrlLayout
->addWidget( slider
, 0, i
, Qt::AlignHCenter
);
1148 ctrlLayout
->addWidget( valueLabel
, 2, i
, Qt::AlignHCenter
);
1149 ctrlLayout
->addWidget( nameLabel
, 1, i
, Qt::AlignHCenter
);
1150 sliderDatas
<< filter
; /* keep track for applying presets */
1152 connectConfigChanged( filter
);
1155 /* Add the listed presets */
1156 ui
.presetsCombo
->addItem( "", QVariant() ); /* 1st entry = custom/modified */
1157 for( i
= 0 ; i
< NB_PRESETS
; i
++ )
1159 QGraphicsScene scene
;
1161 qreal f_ratio
= QApplication::primaryScreen()->devicePixelRatio();
1162 QPixmap
icon( 40 * f_ratio
, 40 * f_ratio
);
1164 QPixmap
icon( 40, 40 );
1166 icon
.fill( Qt::transparent
);
1167 QPainter
painter( &icon
);
1168 for ( int j
= 0; j
< eqz_preset_10b
[i
].i_band
; j
++ )
1170 float f_value
= eqz_preset_10b
[i
].f_amp
[j
];
1171 if ( f_value
> 20.0 ) f_value
= 20.0;
1172 if ( f_value
< -20.0 ) f_value
= -20.0;
1173 QRectF
shape( j
, 20.0 - f_value
, 1, f_value
);
1174 scene
.addRect( shape
, QPen(), palette().brush( QPalette::WindowText
) );
1176 scene
.addLine( 0.0, 20.0, eqz_preset_10b
[i
].i_band
, 20.0,
1177 palette().color( QPalette::WindowText
) );
1178 scene
.setSceneRect( 0.0, 0.0, eqz_preset_10b
[i
].i_band
, 40.0 );
1179 scene
.render( &painter
, icon
.rect(), scene
.sceneRect(), Qt::IgnoreAspectRatio
);
1180 ui
.presetsCombo
->addItem( icon
, qtr( preset_list_text
[i
] ),
1181 QVariant( preset_list
[i
] ) );
1183 CONNECT( ui
.presetsCombo
, activated(int), this, setCorePreset(int) );
1185 /* Set enable checkbox */
1186 vlc_object_t
*p_aout
= (vlc_object_t
*)THEMIM
->getAout();
1189 psz_af
= var_GetNonEmptyString( p_aout
, "audio-filter" );
1191 psz_af
= var_InheritString( THEPL
, "audio-filter" );
1193 /* To enable or disable subwidgets */
1194 /* If that list grows, better iterate over layout's childs */
1195 CONNECT( ui
.enableCheck
, toggled(bool), ui
.presetsCombo
, setEnabled(bool) );
1196 CONNECT( ui
.enableCheck
, toggled(bool), ui
.presetLabel
, setEnabled(bool) );
1197 CONNECT( ui
.enableCheck
, toggled(bool), ui
.eq2PassCheck
, setEnabled(bool) );
1198 CONNECT( ui
.enableCheck
, toggled(bool), ui
.slidersPlaceholder
, setEnabled(bool) );
1199 CONNECT( ui
.enableCheck
, toggled(bool), ui
.preampSlider
, setEnabled(bool) );
1200 CONNECT( ui
.enableCheck
, toggled(bool), ui
.preampValue
, setEnabled(bool) );
1201 CONNECT( ui
.enableCheck
, toggled(bool), ui
.preampLabel
, setEnabled(bool) );
1203 if( psz_af
&& filterIsPresent( qfu(psz_af
), name
) )
1204 ui
.enableCheck
->setChecked( true );
1206 ui
.enableCheck
->setChecked( false );
1208 /* workaround for non emitted toggle() signal */
1209 ui
.enableCheck
->toggle(); ui
.enableCheck
->toggle();
1212 CONNECT( ui
.enableCheck
, toggled(bool), this, enable(bool) );
1214 /* Connect and set 2 Pass checkbox */
1215 ui
.eq2PassCheck
->setChecked( var_InheritBool( p_aout
, "equalizer-2pass" ) );
1216 CONNECT( ui
.eq2PassCheck
, toggled(bool), this, enable2Pass(bool) );
1218 vlc_object_release( p_aout
);
1221 void Equalizer::setCorePreset( int i_preset
)
1226 i_preset
--;/* 1st in index was an empty entry */
1228 preamp
->setValue( eqz_preset_10b
[i_preset
].f_preamp
);
1229 for ( int i
=0; i
< qMin( eqz_preset_10b
[i_preset
].i_band
,
1230 sliderDatas
.count() ) ; i
++ )
1231 sliderDatas
[i
]->setValue( eqz_preset_10b
[i_preset
].f_amp
[i
] );
1233 vlc_object_t
*p_aout
= (vlc_object_t
*)THEMIM
->getAout();
1236 var_SetString( p_aout
, "equalizer-preset" , preset_list
[i_preset
] );
1237 vlc_object_release( p_aout
);
1239 emit
configChanged( qfu( "equalizer-preset" ), QVariant( qfu( preset_list
[i_preset
] ) ) );
1242 /* Function called when the set2Pass button is activated */
1243 void Equalizer::enable2Pass( bool b_enable
)
1245 vlc_object_t
*p_aout
= (vlc_object_t
*)THEMIM
->getAout();
1249 var_SetBool( p_aout
, "equalizer-2pass", b_enable
);
1250 vlc_object_release( p_aout
);
1252 emit
configChanged( qfu( "equalizer-2pass" ), QVariant( b_enable
) );
1255 /**********************************************************************
1257 **********************************************************************/
1259 /**********************************************************************
1260 * Dynamic range compressor
1261 **********************************************************************/
1263 Compressor::Compressor( intf_thread_t
*p_intf
, QWidget
*parent
)
1264 : AudioFilterControlWidget( p_intf
, parent
, "compressor" )
1267 const FilterSliderData::slider_data_t a
[7] =
1269 { "compressor-rms-peak", qtr("RMS/peak"), "", 0.0f
, 1.0f
, 0.00f
, 0.001f
, 1.0 },
1270 { "compressor-attack", qtr("Attack"), qtr("ms"), 1.5f
, 400.0f
, 25.00f
, 0.100f
, 1.0 },
1271 { "compressor-release", qtr("Release"), qtr("ms"), 2.0f
, 800.0f
, 100.00f
, 0.100f
, 1.0 },
1272 { "compressor-threshold", qtr("Threshold"), qtr("dB"), -30.0f
, 0.0f
, -11.00f
, 0.010f
, 1.0 },
1273 { "compressor-ratio", qtr("Ratio"), ":1", 1.0f
, 20.0f
, 8.00f
, 0.010f
, 1.0 },
1274 { "compressor-knee", qtr("Knee\nradius"), qtr("dB"), 1.0f
, 10.0f
, 2.50f
, 0.010f
, 1.0 },
1275 { "compressor-makeup-gain", qtr("Makeup\ngain"), qtr("dB"), 0.0f
, 24.0f
, 7.00f
, 0.010f
, 1.0 },
1277 for( int i
=0; i
<7 ;i
++ ) controls
.append( a
[i
] );
1281 /**********************************************************************
1283 **********************************************************************/
1285 Spatializer::Spatializer( intf_thread_t
*p_intf
, QWidget
*parent
)
1286 : AudioFilterControlWidget( p_intf
, parent
, "spatializer" )
1289 const FilterSliderData::slider_data_t a
[5] =
1291 { "spatializer-roomsize", qtr("Size"), "", 0.0f
, 1.1f
, 0.85f
, 0.1f
, 10.0 },
1292 { "spatializer-width", qtr("Width"), "", 0.0f
, 1.0f
, 1.0f
, 0.1f
, 10.0 },
1293 { "spatializer-wet", qtr("Wet"), "", 0.0f
, 1.0f
, 0.4f
, 0.1f
, 10.0 },
1294 { "spatializer-dry", qtr("Dry"), "", 0.0f
, 1.0f
, 0.5f
, 0.1f
, 10.0 },
1295 { "spatializer-damp", qtr("Damp"), "", 0.0f
, 1.0f
, 0.5f
, 0.1f
, 10.0 },
1297 for( int i
=0; i
<5 ;i
++ ) controls
.append( a
[i
] );
1301 /**********************************************************************
1303 **********************************************************************/
1305 StereoWidener::StereoWidener( intf_thread_t
*p_intf
, QWidget
*parent
)
1306 : AudioFilterControlWidget( p_intf
, parent
, "stereo_widen" )
1309 const FilterSliderData::slider_data_t a
[4] =
1311 { "stereowiden-delay", N_("Delay time"), "ms", 1.0, 100, 20, 1.0, 1.0 },
1312 { "stereowiden-feedback", N_("Feedback gain"), "%", 0.0, 0.9, 0.3, 0.1, 1.0 },
1313 { "stereowiden-crossfeed", N_("Crossfeed"), "%", 0.0, 0.8, 0.3, 0.1, 1.0 },
1314 { "stereowiden-dry-mix", N_("Dry mix"), "%", 0.0, 1.0, 0.8, 0.1, 1.0 },
1316 for( int i
=0; i
<4 ;i
++ ) controls
.append( a
[i
] );
1320 /**********************************************************************
1322 **********************************************************************/
1324 PitchShifter::PitchShifter( intf_thread_t
*p_intf
, QWidget
*parent
)
1325 : AudioFilterControlWidget( p_intf
, parent
, "pitch", "scaletempo" )
1328 controls
.append( { "pitch-shift", N_("Adjust pitch"), "semitones",
1329 -12.0, 12.0, 0.0, 0.25, 1.0 } );
1333 #include <QToolButton>
1334 #include <QGridLayout>
1336 #define SUBSDELAY_CFG_MODE "subsdelay-mode"
1337 #define SUBSDELAY_CFG_FACTOR "subsdelay-factor"
1338 #define SUBSDELAY_MODE_ABSOLUTE 0
1339 #define SUBSDELAY_MODE_RELATIVE_SOURCE_DELAY 1
1340 #define SUBSDELAY_MODE_RELATIVE_SOURCE_CONTENT 2
1342 SyncWidget::SyncWidget( QWidget
*_parent
) : QWidget( _parent
)
1344 QHBoxLayout
*layout
= new QHBoxLayout
;
1345 spinBox
.setAlignment( Qt::AlignRight
|Qt::AlignTrailing
|Qt::AlignVCenter
);
1346 spinBox
.setDecimals( 3 );
1347 spinBox
.setMinimum( -600.0 );
1348 spinBox
.setMaximum( 600.0 );
1349 spinBox
.setSingleStep( 0.1 );
1350 spinBox
.setSuffix( " s" );
1351 spinBox
.setButtonSymbols( QDoubleSpinBox::PlusMinus
);
1352 CONNECT( &spinBox
, valueChanged( double ), this, valueChangedHandler( double ) );
1353 layout
->addWidget( &spinBox
);
1354 layout
->addWidget( &spinLabel
);
1355 layout
->setContentsMargins( 0, 0, 0, 0 );
1356 setLayout( layout
);
1359 void SyncWidget::valueChangedHandler( double d
)
1362 spinLabel
.setText( qtr("(Hastened)") );
1364 spinLabel
.setText( qtr("(Delayed)") );
1366 spinLabel
.setText( "" );
1367 emit
valueChanged( d
);
1370 void SyncWidget::setValue( double d
)
1372 spinBox
.setValue( d
);
1375 SyncControls::SyncControls( intf_thread_t
*_p_intf
, QWidget
*_parent
) :
1376 QWidget( _parent
) , p_intf( _p_intf
)
1378 QGroupBox
*AVBox
, *subsBox
;
1379 QToolButton
*updateButton
;
1381 b_userAction
= true;
1383 QGridLayout
*mainLayout
= new QGridLayout( this );
1386 AVBox
= new QGroupBox( qtr( "Audio/Video" ) );
1387 QGridLayout
*AVLayout
= new QGridLayout( AVBox
);
1389 QLabel
*AVLabel
= new QLabel
;
1390 AVLabel
->setText( qtr( "Audio track synchronization:" ) );
1391 AVLayout
->addWidget( AVLabel
, 0, 0, 1, 1 );
1393 AVSpin
= new SyncWidget( this );
1394 AVLayout
->addWidget( AVSpin
, 0, 2, 1, 1 );
1395 mainLayout
->addWidget( AVBox
, 1, 0, 1, 5 );
1398 subsBox
= new QGroupBox( qtr( "Subtitles/Video" ) );
1399 QGridLayout
*subsLayout
= new QGridLayout( subsBox
);
1401 QLabel
*subsLabel
= new QLabel
;
1402 subsLabel
->setText( qtr( "Subtitle track synchronization:" ) );
1403 subsLayout
->addWidget( subsLabel
, 0, 0, 1, 1 );
1405 subsSpin
= new SyncWidget( this );
1406 subsLayout
->addWidget( subsSpin
, 0, 2, 1, 1 );
1408 QLabel
*subSpeedLabel
= new QLabel
;
1409 subSpeedLabel
->setText( qtr( "Subtitle speed:" ) );
1410 subsLayout
->addWidget( subSpeedLabel
, 1, 0, 1, 1 );
1412 subSpeedSpin
= new QDoubleSpinBox
;
1413 subSpeedSpin
->setAlignment( Qt::AlignRight
|Qt::AlignTrailing
|Qt::AlignVCenter
);
1414 subSpeedSpin
->setDecimals( 3 );
1415 subSpeedSpin
->setMinimum( 1 );
1416 subSpeedSpin
->setMaximum( 100 );
1417 subSpeedSpin
->setSingleStep( 0.2 );
1418 subSpeedSpin
->setSuffix( " fps" );
1419 subSpeedSpin
->setButtonSymbols( QDoubleSpinBox::PlusMinus
);
1420 subsLayout
->addWidget( subSpeedSpin
, 1, 2, 1, 1 );
1422 QLabel
*subDurationLabel
= new QLabel
;
1423 subDurationLabel
->setText( qtr( "Subtitle duration factor:" ) );
1424 subsLayout
->addWidget( subDurationLabel
, 2, 0, 1, 1 );
1426 subDurationSpin
= new QDoubleSpinBox
;
1427 subDurationSpin
->setAlignment( Qt::AlignRight
|Qt::AlignTrailing
|Qt::AlignVCenter
);
1428 subDurationSpin
->setDecimals( 3 );
1429 subDurationSpin
->setMinimum( 0 );
1430 subDurationSpin
->setMaximum( 20 );
1431 subDurationSpin
->setSingleStep( 0.2 );
1432 subDurationSpin
->setButtonSymbols( QDoubleSpinBox::PlusMinus
);
1433 subsLayout
->addWidget( subDurationSpin
, 2, 2, 1, 1 );
1435 mainLayout
->addWidget( subsBox
, 2, 0, 2, 5 );
1437 updateButton
= new QToolButton
;
1438 updateButton
->setAutoRaise( true );
1439 mainLayout
->addWidget( updateButton
, 0, 4, 1, 1 );
1441 /* Various Connects */
1442 CONNECT( AVSpin
, valueChanged ( double ), this, advanceAudio( double ) ) ;
1443 CONNECT( subsSpin
, valueChanged ( double ), this, advanceSubs( double ) ) ;
1444 CONNECT( subSpeedSpin
, valueChanged ( double ),
1445 this, adjustSubsSpeed( double ) );
1446 CONNECT( subDurationSpin
, valueChanged ( double ),
1447 this, adjustSubsDuration( double ) );
1449 CONNECT( THEMIM
->getIM(), synchroChanged(), this, update() );
1450 BUTTON_SET_ACT_I( updateButton
, "", update
,
1451 qtr( "Force update of this dialog's values" ), update() );
1459 SyncControls::~SyncControls()
1464 void SyncControls::clean()
1466 b_userAction
= false;
1467 AVSpin
->setValue( 0.0 );
1468 subsSpin
->setValue( 0.0 );
1469 subSpeedSpin
->setValue( 1.0 );
1471 b_userAction
= true;
1474 void SyncControls::update()
1476 b_userAction
= false;
1479 if( THEMIM
->getInput() )
1481 i_delay
= var_GetInteger( THEMIM
->getInput(), "audio-delay" );
1482 AVSpin
->setValue( ( (double)i_delay
) / CLOCK_FREQ
);
1483 i_delay
= var_GetInteger( THEMIM
->getInput(), "spu-delay" );
1484 subsSpin
->setValue( ( (double)i_delay
) / CLOCK_FREQ
);
1485 subSpeedSpin
->setValue( var_GetFloat( THEMIM
->getInput(), "sub-fps" ) );
1486 subDurationSpin
->setValue( var_InheritFloat( p_intf
, SUBSDELAY_CFG_FACTOR
) );
1488 b_userAction
= true;
1491 void SyncControls::advanceAudio( double f_advance
)
1493 if( THEMIM
->getInput() && b_userAction
)
1495 int64_t i_delay
= f_advance
* CLOCK_FREQ
;
1496 var_SetInteger( THEMIM
->getInput(), "audio-delay", i_delay
);
1500 void SyncControls::advanceSubs( double f_advance
)
1502 if( THEMIM
->getInput() && b_userAction
)
1504 int64_t i_delay
= f_advance
* CLOCK_FREQ
;
1505 var_SetInteger( THEMIM
->getInput(), "spu-delay", i_delay
);
1509 void SyncControls::adjustSubsSpeed( double f_fps
)
1511 if( THEMIM
->getInput() && b_userAction
)
1513 var_SetFloat( THEMIM
->getInput(), "sub-fps", f_fps
);
1517 void SyncControls::adjustSubsDuration( double f_factor
)
1519 if( THEMIM
->getInput() && b_userAction
)
1521 subsdelaySetFactor( f_factor
);
1522 changeVFiltersString( "subsdelay", f_factor
> 0 );
1526 void SyncControls::initSubsDuration()
1528 int i_mode
= var_InheritInteger( p_intf
, SUBSDELAY_CFG_MODE
);
1533 case SUBSDELAY_MODE_ABSOLUTE
:
1534 subDurationSpin
->setToolTip( qtr( "Extend subtitle duration by this value.\n"
1535 "Set 0 to disable." ) );
1536 subDurationSpin
->setSuffix( " s" );
1538 case SUBSDELAY_MODE_RELATIVE_SOURCE_DELAY
:
1539 subDurationSpin
->setToolTip( qtr( "Multiply subtitle duration by this value.\n"
1540 "Set 0 to disable." ) );
1541 subDurationSpin
->setSuffix( "" );
1543 case SUBSDELAY_MODE_RELATIVE_SOURCE_CONTENT
:
1544 subDurationSpin
->setToolTip( qtr( "Recalculate subtitle duration according\n"
1545 "to their content and this value.\n"
1546 "Set 0 to disable." ) );
1547 subDurationSpin
->setSuffix( "" );
1552 void SyncControls::subsdelayClean()
1554 /* Remove subsdelay filter */
1555 changeVFiltersString( "subsdelay", false );
1558 void SyncControls::subsdelaySetFactor( double f_factor
)
1560 QVector
<vout_thread_t
*> p_vouts
= THEMIM
->getVouts();
1561 foreach( vout_thread_t
*p_vout
, p_vouts
)
1563 var_SetFloat( p_vout
, SUBSDELAY_CFG_FACTOR
, f_factor
);
1564 vlc_object_release( p_vout
);
1568 void SyncControls::changeVFiltersString( const char *psz_name
, bool b_add
)
1570 const char *psz_filter_type
= GetVFilterType( p_intf
, psz_name
);
1571 if( psz_filter_type
== NULL
)
1574 QString result
= ChangeFiltersString( p_intf
, psz_filter_type
, psz_name
, b_add
);
1576 UpdateVFiltersString( p_intf
, psz_filter_type
, qtu( result
) );
1580 /**********************************************************************
1581 * Video filters / Adjust
1582 **********************************************************************/
1584 /**********************************************************************
1585 * Extended playbak controls
1586 **********************************************************************/