diff --git a/data/themes/default/stepper-down-press.png b/data/themes/default/stepper-down-press.png new file mode 100644 index 000000000..c1cec54a3 Binary files /dev/null and b/data/themes/default/stepper-down-press.png differ diff --git a/data/themes/default/stepper-down.png b/data/themes/default/stepper-down.png new file mode 100644 index 000000000..b7b8e2f1a Binary files /dev/null and b/data/themes/default/stepper-down.png differ diff --git a/data/themes/default/stepper-left-press.png b/data/themes/default/stepper-left-press.png new file mode 100644 index 000000000..4de798f7c Binary files /dev/null and b/data/themes/default/stepper-left-press.png differ diff --git a/data/themes/default/stepper-left.png b/data/themes/default/stepper-left.png new file mode 100644 index 000000000..7f2278056 Binary files /dev/null and b/data/themes/default/stepper-left.png differ diff --git a/data/themes/default/stepper-right-press.png b/data/themes/default/stepper-right-press.png new file mode 100644 index 000000000..ad634e175 Binary files /dev/null and b/data/themes/default/stepper-right-press.png differ diff --git a/data/themes/default/stepper-right.png b/data/themes/default/stepper-right.png new file mode 100644 index 000000000..215e88f6c Binary files /dev/null and b/data/themes/default/stepper-right.png differ diff --git a/data/themes/default/stepper-up-press.png b/data/themes/default/stepper-up-press.png new file mode 100644 index 000000000..99f47711f Binary files /dev/null and b/data/themes/default/stepper-up-press.png differ diff --git a/data/themes/default/stepper-up.png b/data/themes/default/stepper-up.png new file mode 100644 index 000000000..13329133d Binary files /dev/null and b/data/themes/default/stepper-up.png differ diff --git a/include/RemotePlugin.h b/include/RemotePlugin.h index 83083d817..da253d511 100644 --- a/include/RemotePlugin.h +++ b/include/RemotePlugin.h @@ -509,6 +509,11 @@ enum RemoteMessageIDs IdSaveSettingsToFile, IdLoadSettingsFromString, IdLoadSettingsFromFile, + IdLoadChunkFromPresetFile, + IdRotateProgram, + IdLoadPrograms, + IdSavePreset, + IdSetParameter, IdLoadPresetFromFile, IdDebugMessage, IdUserBase = 64 diff --git a/include/aeffectx.h b/include/aeffectx.h index 61f655646..1e8dea3f6 100644 --- a/include/aeffectx.h +++ b/include/aeffectx.h @@ -180,7 +180,7 @@ public: class VstParameterProperties { public: - float stepFloat; +/* float stepFloat; char label[64]; int flags; int minInteger; @@ -189,7 +189,24 @@ public: char shortLabel[8]; int category; char categoryLabel[24]; - char empty[128]; + char empty[128];*/ + + float stepFloat; + float smallStepFloat; + float largeStepFloat; + char label[64]; + unsigned int flags; + unsigned int minInteger; + unsigned int maxInteger; + unsigned int stepInteger; + unsigned int largeStepInteger; + char shortLabel[8]; + unsigned short displayIndex; + unsigned short category; + unsigned short numParametersInCategory; + unsigned short reserved; + char categoryLabel[24]; + char future[16]; } ; diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp index 7f285424c..fa79ef601 100644 --- a/plugins/vestige/vestige.cpp +++ b/plugins/vestige/vestige.cpp @@ -1,7 +1,7 @@ /* * vestige.cpp - instrument-plugin for hosting VST-instruments * - * Copyright (c) 2005-2009 Tobias Doerffel + * Copyright (c) 2005-2011 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include "engine.h" @@ -36,6 +38,7 @@ #include "InstrumentPlayHandle.h" #include "InstrumentTrack.h" #include "VstPlugin.h" +#include "MainWindow.h" #include "pixmap_button.h" #include "string_pair_drag.h" #include "text_float.h" @@ -44,6 +47,7 @@ #include "embed.cpp" + extern "C" { @@ -65,12 +69,16 @@ Plugin::Descriptor PLUGIN_EXPORT vestige_plugin_descriptor = QPixmap * VestigeInstrumentView::s_artwork = NULL; +QPixmap * manageVestigeInstrumentView::s_artwork = NULL; vestigeInstrument::vestigeInstrument( InstrumentTrack * _instrument_track ) : Instrument( _instrument_track, &vestige_plugin_descriptor ), m_plugin( NULL ), - m_pluginMutex() + m_pluginMutex(), + m_subWindow( NULL ), + knobFModel( NULL ), + vstKnobs( NULL ) { // now we need a play-handle which cares for calling play() InstrumentPlayHandle * iph = new InstrumentPlayHandle( this ); @@ -96,6 +104,28 @@ void vestigeInstrument::loadSettings( const QDomElement & _this ) if( m_plugin != NULL ) { m_plugin->loadSettings( _this ); + + const QMap & dump = m_plugin->parameterDump(); + int paramCount = (dump).size(); + char paramStr[35]; + vstKnobs = new knob *[paramCount]; + knobFModel = new FloatModel *[paramCount]; + QStringList list1; + QWidget * xx = new QWidget(); + for (int i = 0; i < paramCount; i++) { + sprintf( paramStr, "param%d", i); + list1 = dump[paramStr].split(":"); + + vstKnobs[i] = new knob( knobBright_26, xx ); + vstKnobs[i]->setHintText( list1.at(1) + ":", ""); + vstKnobs[i]->setLabel( list1.at(1).left(15) ); + + knobFModel[i] = new FloatModel( (list1.at(2)).toFloat(), 0.0f, 1.0f, 0.01f, this, QString::number(i) ); + knobFModel[i]->loadSettings( _this, paramStr ); + connect( knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) ); + + vstKnobs[i]->setModel( knobFModel[i] ); + } } m_pluginMutex.unlock(); } @@ -103,6 +133,20 @@ void vestigeInstrument::loadSettings( const QDomElement & _this ) +void vestigeInstrument::setParameter( void ) +{ + + Model *action = qobject_cast(sender()); + int knobUNID = action->displayName().toInt(); + + if ( m_plugin != NULL ) { + m_plugin->setParam( knobUNID, knobFModel[knobUNID]->value() ); + } +} + + + + void vestigeInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this ) { _this.setAttribute( "plugin", m_pluginDLL ); @@ -110,6 +154,40 @@ void vestigeInstrument::saveSettings( QDomDocument & _doc, QDomElement & _this ) if( m_plugin != NULL ) { m_plugin->saveSettings( _doc, _this ); + if (knobFModel != NULL) { + const QMap & dump = m_plugin->parameterDump(); + int paramCount = (dump).size(); + char paramStr[35]; + for (int i = 0; i < paramCount; i++) { + if (knobFModel[i]->isAutomated() || knobFModel[i]->getControllerConnection()) { + sprintf( paramStr, "param%d", i); + knobFModel[i]->saveSettings( _doc, _this, paramStr ); + } + +/* QDomElement me = _doc.createElement( paramStr ); + me.setAttribute( "id", knobFModel[i]->id() ); + me.setAttribute( "value", knobFModel[i]->value() ); + _this.appendChild( me ); + + ControllerConnection * m_controllerConnection = knobFModel[i]->getControllerConnection(); + if (m_controllerConnection) { + QDomElement controller_element; + QDomNode node = _this.namedItem( "connection" ); + if( node.isElement() ) + { + controller_element = node.toElement(); + } + else + { + controller_element = _doc.createElement( "connection" ); + _this.appendChild( controller_element ); + } + QDomElement element = _doc.createElement( paramStr ); + m_controllerConnection->saveSettings( _doc, element ); + controller_element.appendChild( element ); + }*/ + } + } } m_pluginMutex.unlock(); } @@ -246,7 +324,9 @@ PluginView * vestigeInstrument::instantiateView( QWidget * _parent ) VestigeInstrumentView::VestigeInstrumentView( Instrument * _instrument, QWidget * _parent ) : - InstrumentView( _instrument, _parent ) + InstrumentView( _instrument, _parent ), + tt ( NULL ), + lastPosInMenu (0) { if( s_artwork == NULL ) { @@ -271,8 +351,108 @@ VestigeInstrumentView::VestigeInstrumentView( Instrument * _instrument, "clicking on this button, a file-open-dialog appears " "and you can select your file." ) ); + m_managePluginButton = new pixmapButton( this, "" ); + m_managePluginButton->setCheckable( false ); + m_managePluginButton->setCursor( Qt::PointingHandCursor ); + m_managePluginButton->move( 220, 102 ); + m_managePluginButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "track_op_menu", 20, 20 ) ); + m_managePluginButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "track_op_menu", 20, 20 ) ); + connect( m_managePluginButton, SIGNAL( clicked() ), this, + SLOT( managePlugin() ) ); + toolTip::add( m_managePluginButton, tr( "Control VST-plugin from LMMS host" ) ); + + m_managePluginButton->setWhatsThis( + tr( "Click here, if you want to control VST-plugin from host." ) ); + + + m_openPresetButton = new pixmapButton( this, "" ); + m_openPresetButton->setCheckable( false ); + m_openPresetButton->setCursor( Qt::PointingHandCursor ); + m_openPresetButton->move( 224, 192 ); + m_openPresetButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-up-press" ) ); + m_openPresetButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-up" ) ); + connect( m_openPresetButton, SIGNAL( clicked() ), this, + SLOT( openPreset() ) ); + toolTip::add( m_openPresetButton, tr( "Open VST-plugin preset" ) ); + + m_openPresetButton->setWhatsThis( + tr( "Click here, if you want to open another *.fxp, *.fxb VST-plugin preset." ) ); + + + m_rolLPresetButton = new pixmapButton( this, "" ); + m_rolLPresetButton->setCheckable( false ); + m_rolLPresetButton->setCursor( Qt::PointingHandCursor ); + m_rolLPresetButton->move( 167, 192 ); + m_rolLPresetButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-left-press" ) ); + m_rolLPresetButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-left" ) ); + connect( m_rolLPresetButton, SIGNAL( clicked() ), this, + SLOT( rolrPreset() ) ); + toolTip::add( m_rolLPresetButton, tr( "Previous (-)" ) ); + + m_rolLPresetButton->setShortcut( Qt::Key_Minus ); + + m_rolLPresetButton->setWhatsThis( + tr( "Click here, if you want to switch to another VST-plugin presset program." ) ); + + + m_savePresetButton = new pixmapButton( this, "" ); + m_savePresetButton->setCheckable( false ); + m_savePresetButton->setCursor( Qt::PointingHandCursor ); + m_savePresetButton->move( 224, 213 ); + m_savePresetButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "project_save", 16, 16 ) ); + m_savePresetButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "project_save", 16, 16 ) ); + connect( m_savePresetButton, SIGNAL( clicked() ), this, + SLOT( savePreset() ) ); + toolTip::add( m_savePresetButton, tr( "Save preset" ) ); + + m_savePresetButton->setWhatsThis( + tr( "Click here, if you want to save current VST-plugin presset program." ) ); + + + m_rolRPresetButton = new pixmapButton( this, "" ); + m_rolRPresetButton->setCheckable( false ); + m_rolRPresetButton->setCursor( Qt::PointingHandCursor ); + m_rolRPresetButton->move( 186, 192 ); + m_rolRPresetButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-right-press" ) ); + m_rolRPresetButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-right" ) ); + connect( m_rolRPresetButton, SIGNAL( clicked() ), this, + SLOT( rollPreset() ) ); + toolTip::add( m_rolRPresetButton, tr( "Next (+)" ) ); + + m_rolRPresetButton->setShortcut( Qt::Key_Plus ); + + m_rolRPresetButton->setWhatsThis( + tr( "Click here, if you want to switch to another VST-plugin presset program." ) ); + + + + m_selPresetButton = new QPushButton( tr( "" ), this ); + m_selPresetButton->setGeometry( 205, 192, 16, 16 ); + + QMenu *menu = new QMenu; + + connect( menu, SIGNAL( aboutToShow() ), this, SLOT( updateMenu() ) ); + + + m_selPresetButton->setIcon( PLUGIN_NAME::getIconPixmap( "stepper-down" ) ); + m_selPresetButton->setWhatsThis( + tr( "Click here to select presets that are currently loaded in VST." ) ); + + m_selPresetButton->setMenu(menu); + + m_toggleGUIButton = new QPushButton( tr( "Show/hide GUI" ), this ); - m_toggleGUIButton->setGeometry( 20, 150, 200, 24 ); + m_toggleGUIButton->setGeometry( 20, 130, 200, 24 ); m_toggleGUIButton->setIcon( embed::getIconPixmap( "zoom" ) ); m_toggleGUIButton->setFont( pointSize<8>( m_toggleGUIButton->font() ) ); connect( m_toggleGUIButton, SIGNAL( clicked() ), this, @@ -283,16 +463,60 @@ VestigeInstrumentView::VestigeInstrumentView( Instrument * _instrument, QPushButton * note_off_all_btn = new QPushButton( tr( "Turn off all " "notes" ), this ); - note_off_all_btn->setGeometry( 20, 180, 200, 24 ); + note_off_all_btn->setGeometry( 20, 160, 200, 24 ); note_off_all_btn->setIcon( embed::getIconPixmap( "state_stop" ) ); note_off_all_btn->setFont( pointSize<8>( note_off_all_btn->font() ) ); connect( note_off_all_btn, SIGNAL( clicked() ), this, SLOT( noteOffAll() ) ); setAcceptDrops( true ); + _instrument2 = _instrument; + _parent2 = _parent; } +void VestigeInstrumentView::managePlugin( void ) +{ + if ( m_vi->m_plugin != NULL && m_vi->m_subWindow == NULL ) { + tt = new manageVestigeInstrumentView( _instrument2, _parent2, m_vi); + } else if (m_vi->m_subWindow != NULL) { + m_vi->m_scrollArea->show(); + m_vi->m_subWindow->show(); + } +} + + +void VestigeInstrumentView::updateMenu( void ) +{ + + // get all presets - + if ( m_vi->m_plugin != NULL ) { + m_vi->m_plugin->loadPrograms( 1 ); + QWidget::update(); + + QString str = m_vi->m_plugin->presetsString(); + + QStringList list1 = str.split("|"); + + QMenu * to_menu = m_selPresetButton->menu(); + to_menu->clear(); + + QAction *presetActions[list1.size()]; + + for (int i = 0; i < list1.size(); i++) { + presetActions[i] = new QAction(this); + connect(presetActions[i], SIGNAL(triggered()), this, SLOT(selPreset())); + + presetActions[i]->setText(QString("%1. %2").arg(QString::number(i+1), list1.at(i))); + presetActions[i]->setData(i); + if (i == lastPosInMenu) { + presetActions[i]->setIcon(embed::getIconPixmap( "sample_file", 16, 16 )); + } else presetActions[i]->setIcon(embed::getIconPixmap( "edit_copy", 16, 16 )); + to_menu->addAction( presetActions[i] ); + } + + } +} VestigeInstrumentView::~VestigeInstrumentView() @@ -346,6 +570,12 @@ void VestigeInstrumentView::openPlugin( void ) return; } engine::getMixer()->lock(); + + if (tt != NULL) { + delete tt; + tt = NULL; + } + m_vi->loadFile( ofd.selectedFiles()[0] ); engine::getMixer()->unlock(); if( m_vi->m_plugin && m_vi->m_plugin->pluginWidget() ) @@ -359,6 +589,87 @@ void VestigeInstrumentView::openPlugin( void ) +void VestigeInstrumentView::openPreset( void ) +{ + + if ( m_vi->m_plugin != NULL ) { + m_vi->m_plugin->openPreset( ); + bool converted; + QString str = m_vi->m_plugin->presetString().section("/", 0, 0); + if (str != "") + lastPosInMenu = str.toInt(&converted, 10) - 1; + QWidget::update(); + } + +} + + + + +void VestigeInstrumentView::savePreset( void ) +{ + + if ( m_vi->m_plugin != NULL ) { + m_vi->m_plugin->savePreset( ); +/* bool converted; + QString str = m_vi->m_plugin->presetString().section("/", 0, 0); + if (str != "") + lastPosInMenu = str.toInt(&converted, 10) - 1; + QWidget::update();*/ + } + +} + + + + +void VestigeInstrumentView::rollPreset( void ) +{ + + if ( m_vi->m_plugin != NULL ) { + m_vi->m_plugin->rollPreset( 1 ); + bool converted; + QString str = m_vi->m_plugin->presetString().section("/", 0, 0); + if (str != "") + lastPosInMenu = str.toInt(&converted, 10) - 1; + QWidget::update(); + } +} + + + + +void VestigeInstrumentView::rolrPreset( void ) +{ + + if ( m_vi->m_plugin != NULL ) { + m_vi->m_plugin->rollPreset( -1 ); + bool converted; + QString str = m_vi->m_plugin->presetString().section("/", 0, 0); + if (str != "") + lastPosInMenu = str.toInt(&converted, 10) - 1; + QWidget::update(); + } +} + + + + +void VestigeInstrumentView::selPreset( void ) +{ + + QAction *action = qobject_cast(sender()); + if (action) + if ( m_vi->m_plugin != NULL ) { + lastPosInMenu = action->data().toInt(); + m_vi->m_plugin->rollPreset( action->data().toInt() + 2 ); + QWidget::update(); + } +} + + + + void VestigeInstrumentView::toggleGUI( void ) { QMutexLocker ml( &m_vi->m_pluginMutex ); @@ -458,6 +769,7 @@ void VestigeInstrumentView::paintEvent( QPaintEvent * ) p.setPen( QColor( 32, 160, 54 ) ); p.drawText( 10, 100, plugin_name ); + p.drawText( 10, 211, tr( "Preset" ) ); // m_pluginMutex.lock(); if( m_vi->m_plugin != NULL ) @@ -467,6 +779,7 @@ void VestigeInstrumentView::paintEvent( QPaintEvent * ) p.setFont( pointSize<8>( f ) ); p.drawText( 10, 114, tr( "by" ) + " " + m_vi->m_plugin->vendorString() ); + p.drawText( 10, 225, m_vi->m_plugin->presetString() ); } // m_pluginMutex.unlock(); } @@ -474,6 +787,188 @@ void VestigeInstrumentView::paintEvent( QPaintEvent * ) +manageVestigeInstrumentView::manageVestigeInstrumentView( Instrument * _instrument, + QWidget * _parent, vestigeInstrument * m_vi2 ) : + InstrumentView( _instrument, _parent ) +{ + m_vi = m_vi2; + m_vi->m_scrollArea = new QScrollArea( this ); + widget = new QWidget(this); + l = new QGridLayout( this ); + + m_vi->m_subWindow = engine::mainWindow()->workspace()->addSubWindow(new QMdiSubWindow, Qt::SubWindow | + Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); + m_vi->m_subWindow->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + m_vi->m_subWindow->setFixedSize( 960, 300); + m_vi->m_subWindow->setWidget(m_vi->m_scrollArea); + m_vi->m_subWindow->setWindowTitle(m_vi->m_plugin->name()); + m_vi->m_subWindow->setWindowIcon( PLUGIN_NAME::getIconPixmap( "logo" ) ); + //m_vi->m_subWindow->setAttribute(Qt::WA_DeleteOnClose); + + + l->setContentsMargins( 20, 10, 10, 10 ); + l->setVerticalSpacing( 10 ); + l->setHorizontalSpacing( 23 ); + + m_syncButton = new QPushButton( tr( "VST Sync" ), this ); + connect( m_syncButton, SIGNAL( clicked() ), this, + SLOT( syncPlugin() ) ); + m_syncButton->setWhatsThis( + tr( "Click here if you want to synchronize all parameters with VST plugin." ) ); + + l->addWidget( m_syncButton, 0, 0, 1, 2, Qt::AlignLeft ); + + const QMap & dump = m_vi->m_plugin->parameterDump(); + int paramCount = (dump).size(); + + bool isVstKnobs = true, isKnobFModel = true; + + if (m_vi->vstKnobs == NULL) { + m_vi->vstKnobs = new knob *[paramCount]; + isVstKnobs = false; + } + if (m_vi->knobFModel == NULL) { + m_vi->knobFModel = new FloatModel *[paramCount]; + isKnobFModel = false; + } + + char paramStr[35]; + QStringList list1; + + if (isVstKnobs == false) { + for (int i = 0; i < paramCount; i++) { + sprintf( paramStr, "param%d", i); + list1 = dump[paramStr].split(":"); + + m_vi->vstKnobs[i] = new knob( knobBright_26, this ); + m_vi->vstKnobs[i]->setHintText( list1.at(1) + ":", ""); + m_vi->vstKnobs[i]->setLabel( list1.at(1).left(15) ); + + sprintf( paramStr, "%d", i); + m_vi->knobFModel[i] = new FloatModel( (list1.at(2)).toFloat(), 0.0f, 1.0f, 0.01f, + castModel(), tr( paramStr ) ); + connect( m_vi->knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) ); + m_vi->vstKnobs[i] ->setModel( m_vi->knobFModel[i] ); + } + } + + int i = 0; + for (int lrow = 0+1; lrow < (int(paramCount / 10) + 1)+1; lrow++) { + for (int lcolumn = 0; lcolumn < 10; lcolumn++) { + if (i < paramCount) + l->addWidget( m_vi->vstKnobs[i], lrow, lcolumn, Qt::AlignCenter ); + i++; + } + } + + l->setRowStretch( (int(paramCount / 10) + 1), 1 ); + l->setColumnStretch( 10, 1 ); + + widget->setLayout(l); + widget->setAutoFillBackground(true); + + m_vi->m_scrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); + m_vi->m_scrollArea->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + m_vi->m_scrollArea->setPalette( QApplication::palette( m_vi->m_scrollArea ) ); + m_vi->m_scrollArea->setMinimumHeight( 64 ); + + m_vi->m_scrollArea->setWidget( widget ); + + m_vi->m_subWindow->show(); +} + + + + +void manageVestigeInstrumentView::syncPlugin( void ) +{ + char paramStr[35]; + QStringList list1; + const QMap & dump = m_vi->m_plugin->parameterDump(); + float f; + + for (int i = 0; i<(dump).size(); i++) { + sprintf( paramStr, "param%d", i); + list1 = dump[paramStr].split(":"); + f = (list1.at(2)).toFloat(); + m_vi->knobFModel[i]->setValue(f); + m_vi->knobFModel[i]->setInitValue(f); + } +} + + +manageVestigeInstrumentView::~manageVestigeInstrumentView() +{ + delete m_vi->m_subWindow; + m_vi->m_subWindow = NULL; +} + + + + +void manageVestigeInstrumentView::modelChanged( void ) +{ + m_vi = castModel(); +} + + + +void manageVestigeInstrumentView::setParameter( void ) +{ + + Model *action = qobject_cast(sender()); + int knobUNID = action->displayName().toInt(); + + if ( m_vi->m_plugin != NULL ) { + m_vi->m_plugin->setParam( knobUNID, m_vi->knobFModel[knobUNID]->value() ); + } +} + + + +void manageVestigeInstrumentView::dragEnterEvent( QDragEnterEvent * _dee ) +{ + if( _dee->mimeData()->hasFormat( stringPairDrag::mimeType() ) ) + { + QString txt = _dee->mimeData()->data( + stringPairDrag::mimeType() ); + if( txt.section( ':', 0, 0 ) == "vstplugin" ) + { + _dee->acceptProposedAction(); + } + else + { + _dee->ignore(); + } + } + else + { + _dee->ignore(); + } +} + + + + +void manageVestigeInstrumentView::dropEvent( QDropEvent * _de ) +{ + QString type = stringPairDrag::decodeKey( _de ); + QString value = stringPairDrag::decodeValue( _de ); + if( type == "vstplugin" ) + { + m_vi->loadFile( value ); + _de->accept(); + return; + } + _de->ignore(); +} + + + + +void manageVestigeInstrumentView::paintEvent( QPaintEvent * ) +{ +} diff --git a/plugins/vestige/vestige.h b/plugins/vestige/vestige.h index 1b8242b54..bed73ada7 100644 --- a/plugins/vestige/vestige.h +++ b/plugins/vestige/vestige.h @@ -1,7 +1,7 @@ /* * vestige.h - instrument VeSTige for hosting VST-plugins * - * Copyright (c) 2005-2009 Tobias Doerffel + * Copyright (c) 2005-2011 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -28,11 +28,15 @@ #include +#include +#include +#include #include "Instrument.h" #include "InstrumentView.h" #include "midi.h" #include "note.h" +#include "knob.h" class QPixmap; @@ -68,6 +72,8 @@ public: virtual PluginView * instantiateView( QWidget * _parent ); +protected slots: + void setParameter( void ); private: void closePlugin( void ); @@ -79,13 +85,50 @@ private: QMutex m_pluginMutex; QString m_pluginDLL; + QMdiSubWindow * m_subWindow; + QScrollArea * m_scrollArea; + FloatModel ** knobFModel; + knob ** vstKnobs; friend class VestigeInstrumentView; + friend class manageVestigeInstrumentView; } ; +class manageVestigeInstrumentView : public InstrumentView +{ + Q_OBJECT +public: + manageVestigeInstrumentView( Instrument * _instrument, QWidget * _parent, vestigeInstrument * m_vi2 ); + virtual ~manageVestigeInstrumentView(); + + +protected slots: + void syncPlugin( void ); + void setParameter( void ); + + +protected: + virtual void dragEnterEvent( QDragEnterEvent * _dee ); + virtual void dropEvent( QDropEvent * _de ); + virtual void paintEvent( QPaintEvent * _pe ); + + +private: + virtual void modelChanged( void ); + + static QPixmap * s_artwork; + + vestigeInstrument * m_vi; + + QWidget *widget; + QGridLayout * l; + QPushButton * m_syncButton; + +} ; + class VestigeInstrumentView : public InstrumentView { @@ -93,10 +136,18 @@ class VestigeInstrumentView : public InstrumentView public: VestigeInstrumentView( Instrument * _instrument, QWidget * _parent ); virtual ~VestigeInstrumentView(); + manageVestigeInstrumentView * tt; protected slots: + void updateMenu( void ); void openPlugin( void ); + void managePlugin( void ); + void openPreset( void ); + void savePreset( void ); + void rollPreset( void ); + void rolrPreset( void ); + void selPreset( void ); void toggleGUI( void ); void noteOffAll( void ); @@ -114,8 +165,19 @@ private: vestigeInstrument * m_vi; + int lastPosInMenu; + pixmapButton * m_openPluginButton; + pixmapButton * m_openPresetButton; + pixmapButton * m_rolLPresetButton; + pixmapButton * m_rolRPresetButton; + QPushButton * m_selPresetButton; QPushButton * m_toggleGUIButton; + pixmapButton * m_managePluginButton; + pixmapButton * m_savePresetButton; + + Instrument * _instrument2; + QWidget * _parent2; } ; diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 3bb167252..2f17643d9 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -163,6 +163,9 @@ public: // determine product-string of plugin const char * pluginProductString(); + // determine name of plugipn preset + const char * presetName(); + // do a complete parameter-dump and post it void getParameterDump(); @@ -178,6 +181,18 @@ public: // restore settings chunk of plugin from file void loadChunkFromFile( const std::string & _file, int _len ); + // restore settings chunk of plugin from file + void loadChunkFromPresetFile( const std::string & _file ); + + // restore settings chunk of plugin from file + void rotateProgram( int _len ); + + // Load names VST of presets/programs + void loadPrograms( int _len ); + + // Save presets/programs + void savePreset( const std::string & _file ); + // number of inputs virtual int inputCount() const { @@ -386,6 +401,33 @@ bool RemoteVstPlugin::processMessage( const message & _m ) sendMessage( IdLoadSettingsFromFile ); break; + case IdLoadChunkFromPresetFile: + loadChunkFromPresetFile( _m.getString( 0 ) ); + sendMessage( IdLoadChunkFromPresetFile ); + break; + + case IdRotateProgram: + rotateProgram( _m.getInt( 0 ) ); + sendMessage( IdRotateProgram ); + break; + + case IdLoadPrograms: + loadPrograms( _m.getInt( 0 ) ); + sendMessage( IdLoadPrograms ); + break; + + case IdSavePreset: + savePreset( _m.getString( 0 ) ); + sendMessage( IdSavePreset ); + break; + + case IdSetParameter: + m_plugin->setParameter( m_plugin, _m.getInt( 0 ), _m.getFloat( 1 ) ); + sendMessage( IdSetParameter ); + break; + + + default: return RemotePluginClient::processMessage( _m ); } @@ -726,19 +768,34 @@ const char * RemoteVstPlugin::pluginProductString() +const char * RemoteVstPlugin::presetName() +{ + static char buf[32]; + buf[0] = 0; + + m_plugin->dispatcher(m_plugin, effGetProgramName, 0, 0, buf, 0); + + buf[31] = 0; + return buf; +} + + + void RemoteVstPlugin::getParameterDump() { - VstParameterProperties vst_props; - message m( IdVstParameterDump ); - m.addInt( m_plugin->numParams ); - for( int i = 0; i < m_plugin->numParams; ++i ) - { - pluginDispatch( effGetParameterProperties, i, 0, &vst_props ); - m.addInt( i ); - m.addString( vst_props.shortLabel ); - m.addFloat( m_plugin->getParameter( m_plugin, i ) ); - } - sendMessage( m ); + char curPresName[30]; + //VstParameterProperties vst_props; + message m( IdVstParameterDump ); + m.addInt( m_plugin->numParams ); + for( int i = 0; i < m_plugin->numParams; ++i ) + { + //pluginDispatch( effGetParameterProperties, i, 0, &vst_props ); + m_plugin->dispatcher(m_plugin, effGetParamName, i, 0, curPresName, 0); + m.addInt( i ); + m.addString( /*vst_props.shortLabel*/curPresName ); + m.addFloat( m_plugin->getParameter( m_plugin, i ) ); + } + sendMessage( m ); } @@ -812,6 +869,257 @@ void RemoteVstPlugin::saveChunkToFile( const std::string & _file ) +void RemoteVstPlugin::rotateProgram( int _len ) +{ + int currProgram; + if (isInitialized() == false) return; + if (_len <= 1) { + currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0) + _len; + if (currProgram >= m_plugin->numPrograms) currProgram = m_plugin->numPrograms - 1; + if (currProgram < 0) currProgram = 0; + m_plugin->dispatcher(m_plugin, effSetProgram, 0, currProgram++, 0, 0); + } else { + m_plugin->dispatcher(m_plugin, effSetProgram, 0, _len - 2, 0, 0); + currProgram = _len - 1; + } + + char presName[30]; + sprintf( presName, " %d/%d: %s", currProgram, m_plugin->numPrograms, presetName() ); + + sendMessage( message( IdVstPluginPresetString ).addString( presName ) ); +} + + + + +void RemoteVstPlugin::loadPrograms( int _len ) +{ + char presName[4096]; + char curProgName[30]; + if (isInitialized() == false) return; + bool progNameIndexed = (m_plugin->dispatcher(m_plugin, 29, 0, -1, curProgName, 0) == 1); + + if (m_plugin->numPrograms > 1) { + if (progNameIndexed) { + for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++) { + m_plugin->dispatcher(m_plugin, 29, i, -1, curProgName, 0); + if (i == 0) sprintf( presName, "%s", curProgName ); + else sprintf( presName + strlen(presName), "|%s", curProgName ); + } + } else { + int currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0); + for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++) { + m_plugin->dispatcher(m_plugin, effSetProgram, 0, i, 0, 0); + if (i == 0) sprintf( presName, "%s", presetName() ); + else sprintf( presName + strlen(presName), "|%s", presetName() ); + } + m_plugin->dispatcher(m_plugin, effSetProgram, 0, currProgram, 0, 0); + } + } else sprintf( presName, "%s", presetName() ); + + sendMessage( message( IdVstPluginPresetsString ).addString( presName ) ); +} + + + + +inline unsigned int endian_swap(unsigned int& x) +{ + return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24); +} + +struct sBank +{ + unsigned int chunkMagic; + unsigned int byteSize; + unsigned int fxMagic; + unsigned int version; + unsigned int fxID; + unsigned int fxVersion; + unsigned int numPrograms; + char prgName[28]; +}; + +void RemoteVstPlugin::savePreset( const std::string & _file ) +{ + unsigned int chunk_size = 0; + sBank * pBank = ( sBank* ) new char[ sizeof( sBank ) ]; + char progName[ 128 ] = { 0 }; + char* data = NULL; + const bool chunky = ( m_plugin->flags & ( 1 << 5 ) ) != 0; + bool isPreset = _file.substr( _file.find_last_of( "." ) + 1 ) == "fxp"; + int presNameLen = _file.find_last_of( "/" ) + _file.find_last_of( "\\" ) + 2; + + if (isPreset) { + for (int i = 0; i < _file.length() - 4 - presNameLen; i++) + progName[i] = i < 23 ? _file[presNameLen + i] : 0; + m_plugin->dispatcher(m_plugin, 4, 0, 0, progName, 0); + } // m_plugin->dispatcher( m_plugin, effGetProgramName, 0, 0, progName, 0.0f ); + if ( chunky ) + chunk_size = m_plugin->dispatcher( m_plugin, 23, isPreset, 0, &data, false ); + else { + if (isPreset) { + chunk_size = m_plugin->numParams * sizeof( float ); + data = new char[ chunk_size ]; + unsigned int* toUIntArray = reinterpret_cast( data ); + for ( int i = 0; i < m_plugin->numParams; i++ ) + { + float value = m_plugin->getParameter( m_plugin, i ); + unsigned int * pValue = ( unsigned int * ) &value; + toUIntArray[ i ] = endian_swap( *pValue ); + } + } else chunk_size = (((m_plugin->numParams * sizeof( float )) + 56)*m_plugin->numPrograms); + } + + pBank->chunkMagic = 0x4B6E6343; + pBank->byteSize = chunk_size + ( chunky ? sizeof( int ) : 0 ) + 48; + if (!isPreset) pBank->byteSize += 100; + pBank->byteSize = endian_swap( pBank->byteSize ); + pBank->fxMagic = chunky ? 0x68435046 : 0x6B437846; + if (!isPreset && chunky) pBank->fxMagic = 0x68434246; + if (!isPreset &&!chunky) pBank->fxMagic = 0x6B427846; + + pBank->version = 0x01000000; + unsigned int uIntToFile = (unsigned int) m_plugin->uniqueID; + pBank->fxID = endian_swap( uIntToFile ); + uIntToFile = (unsigned int) pluginVersion(); + pBank->fxVersion = endian_swap( uIntToFile ); + uIntToFile = (unsigned int) chunky ? m_plugin->numPrograms : m_plugin->numParams; + if (!isPreset &&!chunky) uIntToFile = (unsigned int) m_plugin->numPrograms; + pBank->numPrograms = endian_swap( uIntToFile ); + + FILE * stream = fopen( _file.c_str(), "w" ); + fwrite ( pBank, 1, 28, stream ); + fwrite ( progName, 1, isPreset ? 28 : 128, stream ); + if ( chunky ) { + uIntToFile = endian_swap( chunk_size ); + fwrite ( &uIntToFile, 1, 4, stream ); + } + if (pBank->fxMagic != 0x6B427846 ) + fwrite ( data, 1, chunk_size, stream ); + else { + int numPrograms = m_plugin->numPrograms; + int currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0); + chunk_size = (m_plugin->numParams * sizeof( float )); + pBank->byteSize = chunk_size + 48; + pBank->byteSize = endian_swap( pBank->byteSize ); + pBank->fxMagic = 0x6B437846; + uIntToFile = (unsigned int) m_plugin->numParams; + pBank->numPrograms = endian_swap( uIntToFile ); + data = new char[ chunk_size ]; + unsigned int* pValue,* toUIntArray = reinterpret_cast( data ); + float value; + for (int j = 0; j < numPrograms; j++) { + m_plugin->dispatcher(m_plugin, effSetProgram, 0, j, 0, 0); + m_plugin->dispatcher(m_plugin, effGetProgramName, 0, 0, pBank->prgName, 0); + fwrite ( pBank, 1, 56, stream ); + for ( int i = 0; i < m_plugin->numParams; i++ ) + { + value = m_plugin->getParameter( m_plugin, i ); + pValue = ( unsigned int * ) &value; + toUIntArray[ i ] = endian_swap( *pValue ); + } + fwrite ( data, 1, chunk_size, stream ); + } + m_plugin->dispatcher(m_plugin, effSetProgram, 0, currProgram, 0, 0); + } + fclose( stream ); + + if ( !chunky ) + delete[] data; + delete[] (sBank*)pBank; + +} + + + + +void RemoteVstPlugin::loadChunkFromPresetFile( const std::string & _file ) +{ + void * chunk = NULL; + unsigned int * pLen = new unsigned int[ 1 ]; + unsigned int len; + sBank * pBank = (sBank*) new char[ sizeof( sBank ) ]; + FILE * stream = fopen( _file.c_str(), "r" ); + fread ( pBank, 1, 56, stream ); + pBank->fxID = endian_swap( pBank->fxID ); + pBank->numPrograms = endian_swap( pBank->numPrograms ); + unsigned int toUInt; + float * pFloat; + + if (m_plugin->uniqueID != pBank->fxID) { + sendMessage( message( IdVstPluginPresetString ). + addString( "Error: Plugin UniqID not match" ) ); + fclose( stream ); + delete[] (unsigned int*)pLen; + delete[] (sBank*)pBank; + return; + } + + if( _file.substr( _file.find_last_of( "." ) + 1 ) != "fxp" ) + fseek ( stream , 156 , SEEK_SET ); + + if(pBank->fxMagic != 0x6B427846) { + if(pBank->fxMagic != 0x6B437846) { + fread (pLen, 1, 4, stream); + chunk = new char[len = endian_swap(*pLen)]; + } else chunk = new char[len = sizeof(float)*pBank->numPrograms]; + fread (chunk, len, 1, stream); + fclose( stream ); + } + + if(_file.substr(_file.find_last_of(".") + 1) == "fxp") { + pBank->prgName[23] = 0; + m_plugin->dispatcher(m_plugin, 4, 0, 0, pBank->prgName, 0); + if(pBank->fxMagic != 0x6B437846) + m_plugin->dispatcher(m_plugin, 24, 1, len, chunk, 0); + else { + unsigned int* toUIntArray = reinterpret_cast( chunk ); + for (int i = 0; i < pBank->numPrograms; i++ ) { + toUInt = endian_swap( toUIntArray[ i ] ); + pFloat = ( float* ) &toUInt; + m_plugin->setParameter( m_plugin, i, *pFloat ); + } + } + } else { + if(pBank->fxMagic != 0x6B427846) { + m_plugin->dispatcher(m_plugin, 24, 0, len, chunk, 0); + } else { + int numPrograms = pBank->numPrograms; + unsigned int * toUIntArray; + int currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0); + chunk = new char[ len = sizeof(float)*m_plugin->numParams ]; + toUIntArray = reinterpret_cast( chunk ); + for (int i =0; i < numPrograms; i++) { + fread (pBank, 1, 56, stream); + fread (chunk, len, 1, stream); + m_plugin->dispatcher(m_plugin, effSetProgram, 0, i, 0, 0); + pBank->prgName[23] = 0; + m_plugin->dispatcher(m_plugin, 4, 0, 0, pBank->prgName, 0); + for (int j = 0; j < m_plugin->numParams; j++ ) { + toUInt = endian_swap( toUIntArray[ j ] ); + pFloat = ( float* ) &toUInt; + m_plugin->setParameter( m_plugin, j, *pFloat ); + } + } + m_plugin->dispatcher(m_plugin, effSetProgram, 0, currProgram, 0, 0); + fclose( stream ); + } + } + char presName[30]; + int currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0) + 1; + sprintf( presName, " %d/%d: %s", currProgram, m_plugin->numPrograms, presetName() ); + + sendMessage( message( IdVstPluginPresetString ).addString( presName ) ); + + delete[] (unsigned int*)pLen; + delete[] (sBank*)pBank; + delete[] (char*)chunk; +} + + + + void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len ) { char * buf = NULL; diff --git a/plugins/vst_base/VstPlugin.cpp b/plugins/vst_base/VstPlugin.cpp index d5414f7ff..289686185 100644 --- a/plugins/vst_base/VstPlugin.cpp +++ b/plugins/vst_base/VstPlugin.cpp @@ -24,6 +24,7 @@ #include "VstPlugin.h" +#include #include #include #include @@ -86,7 +87,9 @@ VstPlugin::VstPlugin( const QString & _plugin ) : m_name(), m_version( 0 ), m_vendorString(), - m_productString() + m_productString(), + m_presetString(), + m_presetsString() { setSplittedChannels( true ); @@ -402,6 +405,14 @@ bool VstPlugin::processMessage( const message & _m ) m_productString = _m.getQString(); break; + case IdVstPluginPresetString: + m_presetString = _m.getQString(); + break; + + case IdVstPluginPresetsString: + m_presetsString = _m.getQString(); + break; + case IdVstPluginUniqueID: // TODO: display graphically in case of failure printf("unique ID: %s\n", _m.getString().c_str() ); @@ -420,7 +431,7 @@ bool VstPlugin::processMessage( const message & _m ) item.value = _m.getFloat( ++p ); m_parameterDump["param" + QString::number( item.index )] = QString::number( item.index ) + ":" + -// QString( item.shortLabel ) + ":" + +/*uncomented*/ /*QString( item.shortLabel )*/ QString::fromStdString(item.shortLabel) + ":" + QString::number( item.value ); } break; @@ -435,6 +446,93 @@ bool VstPlugin::processMessage( const message & _m ) +void VstPlugin::openPreset( ) +{ + + QFileDialog ofd( NULL, tr( "Open Preset" ), "", + tr( "Vst Plugin Preset (*.fxp *.fxb)" ) ); + ofd.setFileMode( QFileDialog::ExistingFiles ); + if( ofd.exec () == QDialog::Accepted && + !ofd.selectedFiles().isEmpty() ) + { + lock(); + sendMessage( message( IdLoadChunkFromPresetFile ). + addString( + QSTR_TO_STDSTR( + QDir::toNativeSeparators( ofd.selectedFiles()[0] ) ) ) + ); + waitForMessage( IdLoadChunkFromPresetFile ); + unlock(); + } +} + + + + +void VstPlugin::rollPreset( int step ) +{ + lock(); + sendMessage( message( IdRotateProgram ). + addInt( step ) ); + waitForMessage( IdRotateProgram ); + unlock(); +} + + + + +void VstPlugin::loadPrograms( int step ) +{ + lock(); + sendMessage( message( IdLoadPrograms ). + addInt( step ) ); + waitForMessage( IdLoadPrograms ); + unlock(); +} + + + + +void VstPlugin::savePreset( ) +{ + QString presName = this->presetString() == "" ? tr(": default"): this->presetString(); + QFileDialog sfd( NULL, tr( "Save Preset" ), presName.section(": ", 1, 1) + tr(".fxp"), + tr( "Vst Plugin Preset (*.fxp *.fxb)" ) ); + + sfd.setAcceptMode( QFileDialog::AcceptSave ); + sfd.setFileMode( QFileDialog::AnyFile ); + if( sfd.exec () == QDialog::Accepted && + !sfd.selectedFiles().isEmpty() && sfd.selectedFiles()[0] != "" ) + { + QString fns = sfd.selectedFiles()[0]; + if ((fns.toUpper().indexOf(tr(".FXP")) == -1) && (fns.toUpper().indexOf(tr(".FXB")) == -1)) + fns = fns + tr(".fxb"); + else fns = fns.left(fns.length() - 4) + (fns.right( 4 )).toLower(); + lock(); + sendMessage( message( IdSavePreset ). + addString( + QSTR_TO_STDSTR( + QDir::toNativeSeparators( fns ) ) ) + ); + waitForMessage( IdSavePreset ); + unlock(); + } +} + + + + +void VstPlugin::setParam( int i, float f ) +{ + lock(); + sendMessage( message( IdSetParameter ).addInt( i ).addFloat( f ) ); + waitForMessage( IdSetParameter ); + unlock(); +} + + + + void VstPlugin::loadChunk( const QByteArray & _chunk ) { QTemporaryFile tf; diff --git a/plugins/vst_base/VstPlugin.h b/plugins/vst_base/VstPlugin.h index fc48f021c..97a7d67e6 100644 --- a/plugins/vst_base/VstPlugin.h +++ b/plugins/vst_base/VstPlugin.h @@ -75,6 +75,16 @@ public: return m_productString; } + inline const QString & presetString() const + { + return m_presetString; + } + + inline const QString & presetsString() const + { + return m_presetsString; + } + const QMap & parameterDump(); void setParameterDump( const QMap & _pdump ); @@ -103,6 +113,11 @@ public: public slots: void setTempo( bpm_t _bpm ); void updateSampleRate(); + void openPreset( void ); + void rollPreset( int step ); + void loadPrograms( int step ); + void savePreset( void ); + void setParam( int i, float f ); private: @@ -120,6 +135,8 @@ private: Sint32 m_version; QString m_vendorString; QString m_productString; + QString m_presetString; + QString m_presetsString; QMap m_parameterDump; diff --git a/plugins/vst_base/communication.h b/plugins/vst_base/communication.h index 4012ef40f..542a4d142 100644 --- a/plugins/vst_base/communication.h +++ b/plugins/vst_base/communication.h @@ -74,6 +74,8 @@ enum VstRemoteMessageIDs IdVstPluginVersion, IdVstPluginVendorString, IdVstPluginProductString, + IdVstPluginPresetString, + IdVstPluginPresetsString, IdVstPluginUniqueID, IdVstParameterCount, IdVstParameterDump, diff --git a/plugins/vst_effect/VstEffect.h b/plugins/vst_effect/VstEffect.h index 5fdcfa224..4c11bbbcc 100644 --- a/plugins/vst_effect/VstEffect.h +++ b/plugins/vst_effect/VstEffect.h @@ -67,6 +67,7 @@ private: friend class VstEffectControls; friend class VstEffectControlDialog; + friend class manageVSTEffectView; } ; diff --git a/plugins/vst_effect/VstEffectControlDialog.cpp b/plugins/vst_effect/VstEffectControlDialog.cpp index a6c83b758..36fc411c9 100644 --- a/plugins/vst_effect/VstEffectControlDialog.cpp +++ b/plugins/vst_effect/VstEffectControlDialog.cpp @@ -1,7 +1,7 @@ /* * VstEffectControlDialog.cpp - dialog for displaying VST-effect GUI * - * Copyright (c) 2006-2010 Tobias Doerffel + * Copyright (c) 2006-2011 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -24,20 +24,24 @@ #include #include +#include #include #include "VstEffectControlDialog.h" #include "VstEffect.h" - +#include "pixmap_button.h" +#include "tooltip.h" + VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : EffectControlDialog( _ctl ), m_pluginWidget( NULL ) { - QVBoxLayout * l = new QVBoxLayout( this ); - l->setMargin( 0 ); - l->setSpacing( 0 ); + QGridLayout * l = new QGridLayout( this ); + l->setContentsMargins( 20, 10, 10, 10 ); + l->setVerticalSpacing( 2 ); + l->setHorizontalSpacing( 2 ); #ifdef LMMS_BUILD_LINUX _ctl->m_effect->m_plugin->showEditor(); @@ -47,9 +51,151 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : setWindowTitle( m_pluginWidget->windowTitle() ); QPushButton * btn = new QPushButton( tr( "Show/hide VST FX GUI" ) ); btn->setCheckable( true ); - l->addWidget( btn ); + l->addWidget( btn, 0, 0, 1, 13, Qt::AlignCenter ); connect( btn, SIGNAL( toggled( bool ) ), m_pluginWidget, SLOT( setVisible( bool ) ) ); + btn->setMinimumWidth( 200 ); + btn->setMaximumWidth( 200 ); + btn->setMinimumHeight( 24 ); + btn->setMaximumHeight( 24 ); + + + m_managePluginButton = new pixmapButton( this, "" ); + m_managePluginButton->setCheckable( false ); + m_managePluginButton->setCursor( Qt::PointingHandCursor ); + m_managePluginButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "track_op_menu" ) ); + m_managePluginButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "track_op_menu" ) ); + connect( m_managePluginButton, SIGNAL( clicked() ), _ctl, + SLOT( managePlugin() ) ); + toolTip::add( m_managePluginButton, tr( "Control VST-plugin from LMMS host" ) ); + + m_managePluginButton->setWhatsThis( + tr( "Click here, if you want to control VST-plugin from host." ) ); + + + m_managePluginButton->setMinimumWidth( 21 ); + m_managePluginButton->setMaximumWidth( 21 ); + m_managePluginButton->setMinimumHeight( 21 ); + m_managePluginButton->setMaximumHeight( 21 ); + + + m_openPresetButton = new pixmapButton( this, "" ); + m_openPresetButton->setCheckable( false ); + m_openPresetButton->setCursor( Qt::PointingHandCursor ); + m_openPresetButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-up-press" ) ); + m_openPresetButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-up" ) ); + connect( m_openPresetButton, SIGNAL( clicked() ), _ctl, + SLOT( openPreset() ) ); + toolTip::add( m_openPresetButton, tr( "Open VST-plugin preset" ) ); + + m_openPresetButton->setWhatsThis( + tr( "Click here, if you want to open another *.fxp, *.fxb VST-plugin preset." ) ); + + m_openPresetButton->setMinimumWidth( 16 ); + m_openPresetButton->setMaximumWidth( 16 ); + m_openPresetButton->setMinimumHeight( 16 ); + m_openPresetButton->setMaximumHeight( 16 ); + + + m_rolLPresetButton = new pixmapButton( this, "" ); + m_rolLPresetButton->setCheckable( false ); + m_rolLPresetButton->setCursor( Qt::PointingHandCursor ); + m_rolLPresetButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-left-press" ) ); + m_rolLPresetButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-left" ) ); + connect( m_rolLPresetButton, SIGNAL( clicked() ), _ctl, + SLOT( rolrPreset() ) ); + toolTip::add( m_rolLPresetButton, tr( "Previous (-)" ) ); + + m_rolLPresetButton->setShortcut( Qt::Key_Minus ); + + m_rolLPresetButton->setWhatsThis( + tr( "Click here, if you want to switch to another VST-plugin presset program." ) ); + + m_rolLPresetButton->setMinimumWidth( 16 ); + m_rolLPresetButton->setMaximumWidth( 16 ); + m_rolLPresetButton->setMinimumHeight( 16 ); + m_rolLPresetButton->setMaximumHeight( 16 ); + + + m_rolRPresetButton = new pixmapButton( this, "" ); + m_rolRPresetButton->setCheckable( false ); + m_rolRPresetButton->setCursor( Qt::PointingHandCursor ); + m_rolRPresetButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-right-press" ) ); + m_rolRPresetButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "stepper-right" ) ); + connect( m_rolRPresetButton, SIGNAL( clicked() ), _ctl, + SLOT( rollPreset() ) ); + toolTip::add( m_rolRPresetButton, tr( "Next (+)" ) ); + + m_rolRPresetButton->setShortcut( Qt::Key_Plus ); + + m_rolRPresetButton->setWhatsThis( + tr( "Click here, if you want to switch to another VST-plugin presset program." ) ); + + m_rolRPresetButton->setMinimumWidth( 16 ); + m_rolRPresetButton->setMaximumWidth( 16 ); + m_rolRPresetButton->setMinimumHeight( 16 ); + m_rolRPresetButton->setMaximumHeight( 16 ); + + + + _ctl->m_selPresetButton = new QPushButton( tr( "" ), this ); + + _ctl->m_selPresetButton->setCheckable( false ); + _ctl->m_selPresetButton->setCursor( Qt::PointingHandCursor ); + _ctl->m_selPresetButton->setIcon( PLUGIN_NAME::getIconPixmap( "stepper-down" ) ); + _ctl->m_selPresetButton->setWhatsThis( + tr( "Click here to select presets that are currently loaded in VST." ) ); + + _ctl->m_selPresetButton->setMenu(_ctl->menu); + + + _ctl->m_selPresetButton->setMinimumWidth( 16 ); + _ctl->m_selPresetButton->setMaximumWidth( 16 ); + _ctl->m_selPresetButton->setMinimumHeight( 16 ); + _ctl->m_selPresetButton->setMaximumHeight( 16 ); + + + m_savePresetButton = new pixmapButton( this, "" ); + m_savePresetButton->setCheckable( false ); + m_savePresetButton->setCursor( Qt::PointingHandCursor ); + m_savePresetButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "project_save", 21, 21 ) ); + m_savePresetButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "project_save", 21, 21 ) ); + connect( m_savePresetButton, SIGNAL( clicked() ), _ctl, + SLOT( savePreset() ) ); + toolTip::add( m_savePresetButton, tr( "Save preset" ) ); + + m_savePresetButton->setWhatsThis( + tr( "Click here, if you want to save current VST-plugin presset program." ) ); + + + m_savePresetButton->setMinimumWidth( 21 ); + m_savePresetButton->setMaximumWidth( 21 ); + m_savePresetButton->setMinimumHeight( 21 ); + m_savePresetButton->setMaximumHeight( 21 ); + + + l->addWidget( m_openPresetButton, 1, 7, Qt::AlignCenter ); + l->addWidget( m_rolLPresetButton, 1, 4, Qt::AlignCenter ); + l->addWidget( m_rolRPresetButton, 1, 5, Qt::AlignCenter ); + l->addWidget(_ctl->m_selPresetButton, 1, 6, Qt::AlignLeft ); + + l->addWidget( m_managePluginButton, 1, 10, 2, 2, Qt::AlignLeft ); + + l->addWidget( m_savePresetButton, 1, 8, 2, 2, Qt::AlignCenter ); + + l->setRowStretch( 3, 1 ); + l->setColumnStretch( 13, 1 ); + } #endif #ifdef LMMS_BUILD_WIN32 @@ -66,6 +212,14 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) : +void VstEffectControlDialog::paintEvent( QPaintEvent * ) +{ + +} + + + + VstEffectControlDialog::~VstEffectControlDialog() { delete m_pluginWidget; diff --git a/plugins/vst_effect/VstEffectControlDialog.h b/plugins/vst_effect/VstEffectControlDialog.h index 84e007062..bd4687511 100644 --- a/plugins/vst_effect/VstEffectControlDialog.h +++ b/plugins/vst_effect/VstEffectControlDialog.h @@ -27,8 +27,15 @@ #include "EffectControlDialog.h" +#include +#include + class VstEffectControls; +class pixmapButton; +class QPixmap; +class QPushButton; +class pixmapButton; class VstEffectControlDialog : public EffectControlDialog @@ -37,9 +44,19 @@ public: VstEffectControlDialog( VstEffectControls * _controls ); virtual ~VstEffectControlDialog(); +protected: + virtual void paintEvent( QPaintEvent * _pe ); + private: QWidget * m_pluginWidget; + pixmapButton * m_openPresetButton; + pixmapButton * m_rolLPresetButton; + pixmapButton * m_rolRPresetButton; + pixmapButton * m_selPresetButton; + pixmapButton * m_managePluginButton; + pixmapButton * m_savePresetButton; + } ; #endif diff --git a/plugins/vst_effect/VstEffectControls.cpp b/plugins/vst_effect/VstEffectControls.cpp index da910f38d..0e2da3c61 100644 --- a/plugins/vst_effect/VstEffectControls.cpp +++ b/plugins/vst_effect/VstEffectControls.cpp @@ -27,12 +27,33 @@ #include "VstEffectControls.h" #include "VstEffect.h" +#include "MainWindow.h" +#include +#include + VstEffectControls::VstEffectControls( VstEffect * _eff ) : EffectControls( _eff ), - m_effect( _eff ) + m_effect( _eff ), + m_subWindow( NULL ), + knobFModel( NULL ), + vstKnobs( NULL ), + ctrHandle( NULL ), + lastPosInMenu (0) +// m_presetLabel ( NULL ) { + menu = new QMenu; + connect( menu, SIGNAL( aboutToShow() ), this, SLOT( updateMenu() ) ); +} + + + + +VstEffectControls::~VstEffectControls() +{ + delete ctrHandle; + ctrHandle = NULL; } @@ -46,6 +67,29 @@ void VstEffectControls::loadSettings( const QDomElement & _this ) if( m_effect->m_plugin != NULL ) { m_effect->m_plugin->loadSettings( _this ); + + const QMap & dump = m_effect->m_plugin->parameterDump(); + int paramCount = (dump).size(); + char paramStr[35]; + vstKnobs = new knob *[paramCount]; + knobFModel = new FloatModel *[paramCount]; + QStringList list1; + QWidget * xx = new QWidget(); + for (int i = 0; i < paramCount; i++) { + sprintf( paramStr, "param%d", i); + list1 = dump[paramStr].split(":"); + + vstKnobs[i] = new knob( knobBright_26, xx ); + vstKnobs[i]->setHintText( list1.at(1) + ":", ""); + vstKnobs[i]->setLabel( list1.at(1).left(15) ); + + knobFModel[i] = new FloatModel( (list1.at(2)).toFloat(), 0.0f, 1.0f, 0.01f, this, QString::number(i) ); + knobFModel[i]->loadSettings( _this, paramStr ); + connect( knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) ); + + vstKnobs[i]->setModel( knobFModel[i] ); + } + } m_effect->m_pluginMutex.unlock(); } @@ -53,6 +97,20 @@ void VstEffectControls::loadSettings( const QDomElement & _this ) +void VstEffectControls::setParameter( void ) +{ + + Model *action = qobject_cast(sender()); + int knobUNID = action->displayName().toInt(); + + if ( m_effect->m_plugin != NULL ) { + m_effect->m_plugin->setParam( knobUNID, knobFModel[knobUNID]->value() ); + } +} + + + + void VstEffectControls::saveSettings( QDomDocument & _doc, QDomElement & _this ) { _this.setAttribute( "plugin", m_effect->m_key.attributes["file"] ); @@ -60,6 +118,16 @@ void VstEffectControls::saveSettings( QDomDocument & _doc, QDomElement & _this ) if( m_effect->m_plugin != NULL ) { m_effect->m_plugin->saveSettings( _doc, _this ); + if (knobFModel != NULL) { + const QMap & dump = m_effect->m_plugin->parameterDump(); + int paramCount = (dump).size(); + char paramStr[35]; + for (int i = 0; i < paramCount; i++) + if (knobFModel[i]->isAutomated() || knobFModel[i]->getControllerConnection()) { + sprintf( paramStr, "param%d", i); + knobFModel[i]->saveSettings( _doc, _this, paramStr ); + } + } } m_effect->m_pluginMutex.unlock(); } @@ -75,5 +143,281 @@ int VstEffectControls::controlCount() + +void VstEffectControls::managePlugin( void ) +{ + if ( m_effect->m_plugin != NULL && m_subWindow == NULL ) { + manageVSTEffectView * tt = new manageVSTEffectView( m_effect, this); + ctrHandle = (QObject *)tt; + } else if (m_subWindow != NULL) { + m_scrollArea->show(); + m_subWindow->show(); + } +} + + + + + +void VstEffectControls::savePreset( void ) +{ + + if ( m_effect->m_plugin != NULL ) { + m_effect->m_plugin->savePreset( ); +/* bool converted; + QString str = m_vi->m_plugin->presetString().section("/", 0, 0); + if (str != "") + lastPosInMenu = str.toInt(&converted, 10) - 1; + QWidget::update();*/ + } + +} + + + + +void VstEffectControls::updateMenu( void ) +{ + + // get all presets - + if ( m_effect->m_plugin != NULL ) { + m_effect->m_plugin->loadPrograms( 1 ); + ///QWidget::update(); + + QString str = m_effect->m_plugin->presetsString(); + + QStringList list1 = str.split("|"); + + QMenu * to_menu = m_selPresetButton->menu(); + to_menu->clear(); + + QAction *presetActions[list1.size()]; + + for (int i = 0; i < list1.size(); i++) { + presetActions[i] = new QAction(this); + connect(presetActions[i], SIGNAL(triggered()), this, SLOT(selPreset())); + + presetActions[i]->setText(QString("%1. %2").arg(QString::number(i+1), list1.at(i))); + presetActions[i]->setData(i); + if (i == lastPosInMenu) { + presetActions[i]->setIcon(embed::getIconPixmap( "sample_file", 16, 16 )); + } else presetActions[i]->setIcon(embed::getIconPixmap( "edit_copy", 16, 16 )); + to_menu->addAction( presetActions[i] ); + } + + } + +} + + + + +void VstEffectControls::openPreset( void ) +{ + + if ( m_effect->m_plugin != NULL ) { + m_effect->m_plugin->openPreset( ); + bool converted; + QString str = m_effect->m_plugin->presetString().section("/", 0, 0); + if (str != "") + lastPosInMenu = str.toInt(&converted, 10) - 1; + //QWidget::update(); + } + +} + + + + +void VstEffectControls::rollPreset( void ) +{ + + if ( m_effect->m_plugin != NULL ) { + m_effect->m_plugin->rollPreset( 1 ); + bool converted; + QString str = m_effect->m_plugin->presetString().section("/", 0, 0); + if (str != "") + lastPosInMenu = str.toInt(&converted, 10) - 1; + //QWidget::update(); + } +} + + + + +void VstEffectControls::rolrPreset( void ) +{ + + if ( m_effect->m_plugin != NULL ) { + m_effect->m_plugin->rollPreset( -1 ); + bool converted; + QString str = m_effect->m_plugin->presetString().section("/", 0, 0); + if (str != "") + lastPosInMenu = str.toInt(&converted, 10) - 1; + //QWidget::update(); + } +} + + + + +void VstEffectControls::selPreset( void ) +{ + + QAction *action = qobject_cast(sender()); + if (action) + if ( m_effect->m_plugin != NULL ) { + lastPosInMenu = action->data().toInt(); + m_effect->m_plugin->rollPreset( lastPosInMenu + 2 ); + //QWidget::update(); + } +} + + + + +void VstEffectControls::paintEvent( QPaintEvent * ) +{ + +} + + + + +manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls * m_vi ) : + m_effect( _eff ) +{ + m_vi2 = m_vi; + widget = new QWidget(); + m_vi->m_scrollArea = new QScrollArea( widget ); + l = new QGridLayout( widget ); + + m_vi->m_subWindow = engine::mainWindow()->workspace()->addSubWindow(new QMdiSubWindow, Qt::SubWindow | + Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); + m_vi->m_subWindow->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + m_vi->m_subWindow->setFixedSize( 960, 300); + m_vi->m_subWindow->setWidget(m_vi->m_scrollArea); + m_vi->m_subWindow->setWindowTitle(_eff->m_plugin->name()); + m_vi->m_subWindow->setWindowIcon( PLUGIN_NAME::getIconPixmap( "logo" ) ); + //m_vi->m_subWindow->setAttribute(Qt::WA_DeleteOnClose); + + + l->setContentsMargins( 20, 10, 10, 10 ); + l->setVerticalSpacing( 10 ); + l->setHorizontalSpacing( 23 ); + + m_syncButton = new QPushButton( tr( "VST Sync" ), widget ); + connect( m_syncButton, SIGNAL( clicked() ), this, + SLOT( syncPlugin() ) ); + m_syncButton->setWhatsThis( + tr( "Click here if you want to synchronize all parameters with VST plugin." ) ); + + l->addWidget( m_syncButton, 0, 0, 1, 2, Qt::AlignLeft ); + + const QMap & dump = m_effect->m_plugin->parameterDump(); + int paramCount = (dump).size(); + + bool isVstKnobs = true, isKnobFModel = true; + + + if (m_vi->vstKnobs == NULL) { + m_vi->vstKnobs = new knob *[paramCount]; + isVstKnobs = false; + } + if (m_vi->knobFModel == NULL) { + m_vi->knobFModel = new FloatModel *[paramCount]; + isKnobFModel = false; + } + + char paramStr[35]; + QStringList list1; + + if (isVstKnobs == false) { + for (int i = 0; i < paramCount; i++) { + sprintf( paramStr, "param%d", i); + list1 = dump[paramStr].split(":"); + + m_vi->vstKnobs[i] = new knob( knobBright_26, widget); + m_vi->vstKnobs[i]->setHintText( list1.at(1) + ":", ""); + m_vi->vstKnobs[i]->setLabel( list1.at(1).left(15) ); + + sprintf( paramStr, "%d", i); + m_vi->knobFModel[i] = new FloatModel( (list1.at(2)).toFloat(), 0.0f, 1.0f, 0.01f, + _eff, tr( paramStr ) ); + connect( m_vi->knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) ); + m_vi->vstKnobs[i] ->setModel( m_vi->knobFModel[i] ); + } + } + + int i = 0; + for (int lrow = 0+1; lrow < (int(paramCount / 10) + 1)+1; lrow++) { + for (int lcolumn = 0; lcolumn < 10; lcolumn++) { + if (i < paramCount) + l->addWidget( m_vi->vstKnobs[i], lrow, lcolumn, Qt::AlignCenter ); + i++; + } + } + + l->setRowStretch( (int(paramCount / 10) + 1), 1 ); + l->setColumnStretch( 10, 1 ); + + widget->setLayout(l); + widget->setAutoFillBackground(true); + + m_vi->m_scrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); + m_vi->m_scrollArea->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + m_vi->m_scrollArea->setPalette( QApplication::palette( m_vi->m_scrollArea ) ); + m_vi->m_scrollArea->setMinimumHeight( 64 ); + + m_vi->m_scrollArea->setWidget( widget ); + + m_vi->m_subWindow->show(); +} + + + + +void manageVSTEffectView::syncPlugin( void ) +{ + char paramStr[35]; + QStringList list1; + const QMap & dump = m_effect->m_plugin->parameterDump(); + float f; + + for (int i = 0; i<(dump).size(); i++) { + sprintf( paramStr, "param%d", i); + list1 = dump[paramStr].split(":"); + f = (list1.at(2)).toFloat(); + m_vi2->knobFModel[i]->setValue(f); + m_vi2->knobFModel[i]->setInitValue(f); + } +} + + + + +void manageVSTEffectView::setParameter( void ) +{ + + Model *action = qobject_cast(sender()); + int knobUNID = action->displayName().toInt(); + + if ( m_effect->m_plugin != NULL ) { + m_effect->m_plugin->setParam( knobUNID, m_vi2->knobFModel[knobUNID]->value() ); + } +} + + + + +manageVSTEffectView::~manageVSTEffectView() +{ + delete m_vi2->m_subWindow; + m_vi2->m_subWindow = NULL; +} + + + + #include "moc_VstEffectControls.cxx" diff --git a/plugins/vst_effect/VstEffectControls.h b/plugins/vst_effect/VstEffectControls.h index 179593de0..06ae7b14c 100644 --- a/plugins/vst_effect/VstEffectControls.h +++ b/plugins/vst_effect/VstEffectControls.h @@ -28,6 +28,17 @@ #include "EffectControls.h" #include "VstEffectControlDialog.h" +#include +#include "embed.h" +#include + +#include +#include +#include "knob.h" +#include +#include +#include + class VstEffect; @@ -37,9 +48,7 @@ class VstEffectControls : public EffectControls Q_OBJECT public: VstEffectControls( VstEffect * _eff ); - virtual ~VstEffectControls() - { - } + virtual ~VstEffectControls(); virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); virtual void loadSettings( const QDomElement & _this ); @@ -56,10 +65,70 @@ public: } +protected slots: + void updateMenu( void ); + void openPlugin( void ); + void managePlugin( void ); + void openPreset( void ); + void savePreset( void ); + void rollPreset( void ); + void rolrPreset( void ); + void selPreset( void ); + void setParameter( void ); + +protected: + virtual void paintEvent( QPaintEvent * _pe ); + private: VstEffect * m_effect; + QPushButton * m_selPresetButton; + QMenu *menu; + + QMdiSubWindow * m_subWindow; + QScrollArea * m_scrollArea; + FloatModel ** knobFModel; + knob ** vstKnobs; + + QObject * ctrHandle; + + int lastPosInMenu; +// QLabel * m_presetLabel; + friend class VstEffectControlDialog; + friend class manageVSTEffectView; + +} ; + + + + +class manageVSTEffectView : public QObject +{ + Q_OBJECT +public: + manageVSTEffectView( VstEffect * _eff, VstEffectControls * m_vi ); + virtual ~manageVSTEffectView(); + + +protected slots: + void syncPlugin( void ); + void setParameter( void ); + +private: + +// static QPixmap * s_artwork; + + VstEffectControls * m_vi2; + + + VstEffect * m_effect; + + + QWidget *widget; + QGridLayout * l; + + QPushButton * m_syncButton; } ;