1 /*
2 * VstEffectControls.cpp - controls for VST effect plugins
3 *
4 * Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
5 *
6 * This file is part of LMMS - https://lmms.io
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program (see COPYING); if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA.
22 *
23 */
24
25 #include <QDomElement>
26
27 #include "VstEffectControls.h"
28 #include "VstEffect.h"
29
30 #include "LocaleHelper.h"
31 #include "MainWindow.h"
32 #include "GuiApplication.h"
33 #include <QMdiArea>
34 #include <QApplication>
35
36
37
VstEffectControls(VstEffect * _eff)38 VstEffectControls::VstEffectControls( VstEffect * _eff ) :
39 EffectControls( _eff ),
40 m_effect( _eff ),
41 m_subWindow( NULL ),
42 knobFModel( NULL ),
43 ctrHandle( NULL ),
44 lastPosInMenu (0),
45 m_vstGuiVisible ( true )
46 // m_presetLabel ( NULL )
47 {
48 }
49
50
51
52
~VstEffectControls()53 VstEffectControls::~VstEffectControls()
54 {
55 delete ctrHandle;
56 ctrHandle = NULL;
57 }
58
59
60
61
loadSettings(const QDomElement & _this)62 void VstEffectControls::loadSettings( const QDomElement & _this )
63 {
64 //m_effect->closePlugin();
65 //m_effect->openPlugin( _this.attribute( "plugin" ) );
66 m_effect->m_pluginMutex.lock();
67 if( m_effect->m_plugin != NULL )
68 {
69 m_vstGuiVisible = _this.attribute( "guivisible" ).toInt();
70
71 m_effect->m_plugin->loadSettings( _this );
72
73 const QMap<QString, QString> & dump = m_effect->m_plugin->parameterDump();
74 paramCount = dump.size();
75 char paramStr[35];
76 knobFModel = new FloatModel *[ paramCount ];
77 QStringList s_dumpValues;
78 for( int i = 0; i < paramCount; i++ )
79 {
80 sprintf( paramStr, "param%d", i );
81 s_dumpValues = dump[ paramStr ].split( ":" );
82
83 knobFModel[i] = new FloatModel( 0.0f, 0.0f, 1.0f, 0.01f, this, QString::number(i) );
84 knobFModel[i]->loadSettings( _this, paramStr );
85
86 if( !( knobFModel[ i ]->isAutomated() ||
87 knobFModel[ i ]->controllerConnection() ) )
88 {
89 knobFModel[ i ]->setValue(LocaleHelper::toFloat(s_dumpValues.at(2)));
90 knobFModel[ i ]->setInitValue(LocaleHelper::toFloat(s_dumpValues.at(2)));
91 }
92
93 #if QT_VERSION < 0x050000
94 connect( knobFModel[i], SIGNAL( dataChanged( Model * ) ),
95 this, SLOT( setParameter( Model * ) ), Qt::DirectConnection );
96 #else
97 connect( knobFModel[i], &FloatModel::dataChanged, this,
98 [this, i]() { setParameter( knobFModel[i] ); }, Qt::DirectConnection);
99 #endif
100 }
101
102 }
103 m_effect->m_pluginMutex.unlock();
104 }
105
106
107
108
setParameter(Model * action)109 void VstEffectControls::setParameter( Model * action )
110 {
111 int knobUNID = action->displayName().toInt();
112
113 if ( m_effect->m_plugin != NULL ) {
114 m_effect->m_plugin->setParam( knobUNID, knobFModel[knobUNID]->value() );
115 }
116 }
117
118
119
120
saveSettings(QDomDocument & _doc,QDomElement & _this)121 void VstEffectControls::saveSettings( QDomDocument & _doc, QDomElement & _this )
122 {
123 _this.setAttribute( "plugin", m_effect->m_key.attributes["file"] );
124 m_effect->m_pluginMutex.lock();
125 if( m_effect->m_plugin != NULL )
126 {
127 m_effect->m_plugin->saveSettings( _doc, _this );
128 if (knobFModel != NULL) {
129 const QMap<QString, QString> & dump = m_effect->m_plugin->parameterDump();
130 paramCount = dump.size();
131 char paramStr[35];
132 for( int i = 0; i < paramCount; i++ )
133 {
134 if (knobFModel[i]->isAutomated() || knobFModel[i]->controllerConnection()) {
135 sprintf( paramStr, "param%d", i);
136 knobFModel[i]->saveSettings( _doc, _this, paramStr );
137 }
138 }
139 }
140 }
141 m_effect->m_pluginMutex.unlock();
142 }
143
144
145
146
controlCount()147 int VstEffectControls::controlCount()
148 {
149 return m_effect->m_plugin != NULL ? 1 : 0;
150 }
151
152
153
createView()154 EffectControlDialog *VstEffectControls::createView()
155 {
156 auto dialog = new VstEffectControlDialog( this );
157 dialog->togglePluginUI( m_vstGuiVisible );
158 return dialog;
159 }
160
161
162
163
managePlugin(void)164 void VstEffectControls::managePlugin( void )
165 {
166 if ( m_effect->m_plugin != NULL && m_subWindow == NULL ) {
167 manageVSTEffectView * tt = new manageVSTEffectView( m_effect, this);
168 ctrHandle = (QObject *)tt;
169 } else if (m_subWindow != NULL) {
170 if (m_subWindow->widget()->isVisible() == false ) {
171 m_scrollArea->show();
172 m_subWindow->show();
173 } else {
174 m_scrollArea->hide();
175 m_subWindow->hide();
176 }
177 }
178 }
179
180
181
182
183
savePreset(void)184 void VstEffectControls::savePreset( void )
185 {
186
187 if ( m_effect->m_plugin != NULL ) {
188 m_effect->m_plugin->savePreset( );
189 /* bool converted;
190 QString str = m_vi->m_plugin->currentProgramName().section("/", 0, 0);
191 if (str != "")
192 lastPosInMenu = str.toInt(&converted, 10) - 1;
193 QWidget::update();*/
194 }
195
196 }
197
198
199
200
updateMenu(void)201 void VstEffectControls::updateMenu( void )
202 {
203
204 // get all presets -
205 if ( m_effect->m_plugin != NULL )
206 {
207 m_effect->m_plugin->loadProgramNames();
208 ///QWidget::update();
209
210 QString str = m_effect->m_plugin->allProgramNames();
211
212 QStringList list1 = str.split("|");
213
214 QMenu * to_menu = m_selPresetButton->menu();
215 to_menu->clear();
216
217 QAction *presetActions[list1.size()];
218
219 for (int i = 0; i < list1.size(); i++) {
220 presetActions[i] = new QAction(this);
221 connect(presetActions[i], SIGNAL(triggered()), this, SLOT(selPreset()));
222
223 presetActions[i]->setText(QString("%1. %2").arg(QString::number(i+1), list1.at(i)));
224 presetActions[i]->setData(i);
225 if (i == lastPosInMenu) {
226 presetActions[i]->setIcon(embed::getIconPixmap( "sample_file", 16, 16 ));
227 } else presetActions[i]->setIcon(embed::getIconPixmap( "edit_copy", 16, 16 ));
228 to_menu->addAction( presetActions[i] );
229 }
230
231 }
232
233 }
234
235
236
237
openPreset(void)238 void VstEffectControls::openPreset( void )
239 {
240
241 if ( m_effect->m_plugin != NULL ) {
242 m_effect->m_plugin->openPreset( );
243 bool converted;
244 QString str = m_effect->m_plugin->currentProgramName().section("/", 0, 0);
245 if (str != "")
246 lastPosInMenu = str.toInt(&converted, 10) - 1;
247 //QWidget::update();
248 }
249
250 }
251
252
253
254
rollPreset(void)255 void VstEffectControls::rollPreset( void )
256 {
257
258 if ( m_effect->m_plugin != NULL ) {
259 m_effect->m_plugin->rotateProgram( 1 );
260 bool converted;
261 QString str = m_effect->m_plugin->currentProgramName().section("/", 0, 0);
262 if (str != "")
263 lastPosInMenu = str.toInt(&converted, 10) - 1;
264 //QWidget::update();
265 }
266 }
267
268
269
270
rolrPreset(void)271 void VstEffectControls::rolrPreset( void )
272 {
273
274 if ( m_effect->m_plugin != NULL ) {
275 m_effect->m_plugin->rotateProgram( -1 );
276 bool converted;
277 QString str = m_effect->m_plugin->currentProgramName().section("/", 0, 0);
278 if (str != "")
279 lastPosInMenu = str.toInt(&converted, 10) - 1;
280 //QWidget::update();
281 }
282 }
283
284
285
286
selPreset(void)287 void VstEffectControls::selPreset( void )
288 {
289
290 QAction *action = qobject_cast<QAction *>(sender());
291 if (action)
292 if ( m_effect->m_plugin != NULL ) {
293 lastPosInMenu = action->data().toInt();
294 m_effect->m_plugin->setProgram( lastPosInMenu );
295 //QWidget::update();
296 }
297 }
298
299
300
301
paintEvent(QPaintEvent *)302 void VstEffectControls::paintEvent( QPaintEvent * )
303 {
304
305 }
306
307
308
309
manageVSTEffectView(VstEffect * _eff,VstEffectControls * m_vi)310 manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls * m_vi ) :
311 m_effect( _eff )
312 {
313 m_vi2 = m_vi;
314 widget = new QWidget();
315 m_vi->m_scrollArea = new QScrollArea( widget );
316 l = new QGridLayout( widget );
317
318 m_vi->m_subWindow = gui->mainWindow()->addWindowedWidget(NULL, Qt::SubWindow |
319 Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
320 m_vi->m_subWindow->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
321 m_vi->m_subWindow->setFixedSize( 960, 300);
322 m_vi->m_subWindow->setWidget(m_vi->m_scrollArea);
323 m_vi->m_subWindow->setWindowTitle( _eff->m_plugin->name() + tr( " - VST parameter control" ) );
324 m_vi->m_subWindow->setWindowIcon( PLUGIN_NAME::getIconPixmap( "logo" ) );
325 m_vi->m_subWindow->setAttribute(Qt::WA_DeleteOnClose, false);
326
327
328 l->setContentsMargins( 20, 10, 10, 10 );
329 l->setVerticalSpacing( 10 );
330 l->setHorizontalSpacing( 23 );
331
332 m_syncButton = new QPushButton( tr( "VST Sync" ), widget );
333 connect( m_syncButton, SIGNAL( clicked() ), this,
334 SLOT( syncPlugin() ) );
335 m_syncButton->setWhatsThis(
336 tr( "Click here if you want to synchronize all parameters with VST plugin." ) );
337
338 l->addWidget( m_syncButton, 0, 0, 1, 2, Qt::AlignLeft );
339
340 m_displayAutomatedOnly = new QPushButton( tr( "Automated" ), widget );
341 connect( m_displayAutomatedOnly, SIGNAL( clicked() ), this,
342 SLOT( displayAutomatedOnly() ) );
343 m_displayAutomatedOnly->setWhatsThis(
344 tr( "Click here if you want to display automated parameters only." ) );
345
346 l->addWidget( m_displayAutomatedOnly, 0, 1, 1, 2, Qt::AlignLeft );
347
348
349 m_closeButton = new QPushButton( tr( " Close " ), widget );
350 connect( m_closeButton, SIGNAL( clicked() ), this,
351 SLOT( closeWindow() ) );
352 m_closeButton->setWhatsThis(
353 tr( "Close VST effect knob-controller window." ) );
354
355 l->addWidget( m_closeButton, 0, 2, 1, 7, Qt::AlignLeft );
356
357
358 for( int i = 0; i < 10; i++ )
359 {
360 l->addItem( new QSpacerItem( 68, 45, QSizePolicy::Fixed, QSizePolicy::Fixed ), 0, i );
361 }
362
363 const QMap<QString, QString> & dump = m_effect->m_plugin->parameterDump();
364 m_vi->paramCount = dump.size();
365
366 vstKnobs = new Knob *[ m_vi->paramCount ];
367
368 bool hasKnobModel = true;
369 if (m_vi->knobFModel == NULL) {
370 m_vi->knobFModel = new FloatModel *[ m_vi->paramCount ];
371 hasKnobModel = false;
372 }
373
374 char paramStr[35];
375 QStringList s_dumpValues;
376
377 for( int i = 0; i < m_vi->paramCount; i++ )
378 {
379 sprintf( paramStr, "param%d", i);
380 s_dumpValues = dump[ paramStr ].split( ":" );
381
382 vstKnobs[ i ] = new Knob( knobBright_26, widget, s_dumpValues.at( 1 ) );
383 vstKnobs[ i ]->setHintText( s_dumpValues.at( 1 ) + ":", "" );
384 vstKnobs[ i ]->setLabel( s_dumpValues.at( 1 ).left( 15 ) );
385
386 if( !hasKnobModel )
387 {
388 sprintf( paramStr, "%d", i);
389 m_vi->knobFModel[ i ] = new FloatModel( LocaleHelper::toFloat(s_dumpValues.at(2)),
390 0.0f, 1.0f, 0.01f, _eff, tr( paramStr ) );
391 }
392
393 FloatModel * model = m_vi->knobFModel[i];
394 #if QT_VERSION < 0x050000
395 connect( model, SIGNAL( dataChanged( Model * ) ), this,
396 SLOT( setParameter( Model * ) ), Qt::DirectConnection );
397 #else
398 connect( model, &FloatModel::dataChanged, this,
399 [this, model]() { setParameter( model ); }, Qt::DirectConnection);
400 #endif
401 vstKnobs[ i ] ->setModel( model );
402 }
403
404 int i = 0;
405 for( int lrow = 1; lrow < ( int( m_vi->paramCount / 10 ) + 1 ) + 1; lrow++ )
406 {
407 for( int lcolumn = 0; lcolumn < 10; lcolumn++ )
408 {
409 if( i < m_vi->paramCount )
410 {
411 l->addWidget( vstKnobs[i], lrow, lcolumn, Qt::AlignCenter );
412 }
413 i++;
414 }
415 }
416
417 l->setRowStretch( ( int( m_vi->paramCount / 10 ) + 1 ), 1 );
418 l->setColumnStretch( 10, 1 );
419
420 widget->setLayout(l);
421 widget->setAutoFillBackground(true);
422
423 m_vi->m_scrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
424 m_vi->m_scrollArea->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
425 m_vi->m_scrollArea->setPalette( QApplication::palette( m_vi->m_scrollArea ) );
426 m_vi->m_scrollArea->setMinimumHeight( 64 );
427
428 m_vi->m_scrollArea->setWidget( widget );
429
430 m_vi->m_subWindow->show();
431 }
432
433
434
435
closeWindow()436 void manageVSTEffectView::closeWindow()
437 {
438 m_vi2->m_subWindow->hide();
439 }
440
441
442
443
syncPlugin(void)444 void manageVSTEffectView::syncPlugin( void )
445 {
446 char paramStr[35];
447 QStringList s_dumpValues;
448 const QMap<QString, QString> & dump = m_effect->m_plugin->parameterDump();
449 float f_value;
450
451 for( int i = 0; i < m_vi2->paramCount; i++ )
452 {
453 // only not automated knobs are synced from VST
454 // those auto-setted values are not jurnaled, tracked for undo / redo
455 if( !( m_vi2->knobFModel[ i ]->isAutomated() ||
456 m_vi2->knobFModel[ i ]->controllerConnection() ) )
457 {
458 sprintf( paramStr, "param%d", i );
459 s_dumpValues = dump[ paramStr ].split( ":" );
460 f_value = LocaleHelper::toFloat(s_dumpValues.at(2));
461 m_vi2->knobFModel[ i ]->setAutomatedValue( f_value );
462 m_vi2->knobFModel[ i ]->setInitValue( f_value );
463 }
464 }
465 }
466
467
468
displayAutomatedOnly(void)469 void manageVSTEffectView::displayAutomatedOnly( void )
470 {
471 bool isAuto = QString::compare( m_displayAutomatedOnly->text(), tr( "Automated" ) ) == 0;
472
473 for( int i = 0; i< m_vi2->paramCount; i++ )
474 {
475
476 if( !( m_vi2->knobFModel[ i ]->isAutomated() ||
477 m_vi2->knobFModel[ i ]->controllerConnection() ) )
478 {
479 if( vstKnobs[ i ]->isVisible() == true && isAuto )
480 {
481 vstKnobs[ i ]->hide();
482 m_displayAutomatedOnly->setText( "All" );
483 } else {
484 vstKnobs[ i ]->show();
485 m_displayAutomatedOnly->setText( "Automated" );
486 }
487 }
488 }
489 }
490
491
492
493
setParameter(Model * action)494 void manageVSTEffectView::setParameter( Model * action )
495 {
496 int knobUNID = action->displayName().toInt();
497
498 if ( m_effect->m_plugin != NULL ) {
499 m_effect->m_plugin->setParam( knobUNID, m_vi2->knobFModel[knobUNID]->value() );
500 }
501 }
502
503
504
505
~manageVSTEffectView()506 manageVSTEffectView::~manageVSTEffectView()
507 {
508 if( m_vi2->knobFModel != NULL )
509 {
510 for( int i = 0; i < m_vi2->paramCount; i++ )
511 {
512 delete m_vi2->knobFModel[ i ];
513 delete vstKnobs[ i ];
514 }
515 }
516
517 if( vstKnobs != NULL )
518 {
519 delete [] vstKnobs;
520 vstKnobs = NULL;
521 }
522
523 if( m_vi2->knobFModel != NULL )
524 {
525 delete [] m_vi2->knobFModel;
526 m_vi2->knobFModel = NULL;
527 }
528
529 if( m_vi2->m_scrollArea != NULL )
530 {
531 delete m_vi2->m_scrollArea;
532 m_vi2->m_scrollArea = NULL;
533 }
534
535 if( m_vi2->m_subWindow != NULL )
536 {
537 m_vi2->m_subWindow->setAttribute( Qt::WA_DeleteOnClose );
538 m_vi2->m_subWindow->close();
539
540 if( m_vi2->m_subWindow != NULL )
541 {
542 delete m_vi2->m_subWindow;
543 }
544 m_vi2->m_subWindow = NULL;
545 }
546 //delete m_vi2->m_subWindow;
547 //m_vi2->m_subWindow = NULL;
548 }
549
550
551
552
553
554
555