diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e8401b82..6c3ca298d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ ENDIF(COMMAND CMAKE_POLICY) INCLUDE(AddFileDependencies) INCLUDE(CheckIncludeFiles) +INCLUDE(CheckLibraryExists) INCLUDE(FindPkgConfig) SET(VERSION_MAJOR "0") @@ -52,6 +53,7 @@ OPTION(WANT_CAPS "Include C* Audio Plugin Suite (LADSPA plugins)" ON) OPTION(WANT_CMT "Include Computer Music Toolkit LADSPA plugins" ON) OPTION(WANT_FFTW3F "Include SpectrumAnalyzer and ZynAddSubFX plugin" ON) OPTION(WANT_JACK "Include JACK (Jack Audio Connection Kit) support" ON) +OPTION(WANT_LV2 "Include LV2 support" ON) OPTION(WANT_OGGVORBIS "Include OGG/Vorbis support" ON) OPTION(WANT_PULSEAUDIO "Include PulseAudio support" ON) #OPTION(WANT_PORTAUDIO "Include PortAudio support" ON) # TODO: fix PortAudio support @@ -313,10 +315,46 @@ IF(WANT_SF2) ENDIF(FLUIDSYNTH_FOUND) ENDIF(WANT_SF2) +# check for LV2 (this has an implicit dependency on RDF as far as I can tell) +IF(WANT_LV2) + CHECK_INCLUDE_FILES(lv2.h LMMS_HAVE_LV2CORE) + + CHECK_LIBRARY_EXISTS(slv2 slv2_world_new "" LMMS_HAVE_SLV2) + +# MESSAGE("SLV2 Exists : '${LMMS_HAVE_SLV2}'") +# MESSAGE("SLV2 Library : '${SLV2_LIBRARY}'") #RIGHT +# MESSAGE("SLV2 Libraries : '${SLV2_LIBRARIES}'") # WRONG + + CHECK_LIBRARY_EXISTS(rdf librdf_new_world "" LMMS_HAVE_RDF) + +### TODO : mdda : Install requires : +# Fedora CCRMA : Want "lv2core" +# Fedora CCRMA : Want "slv2" + + SET(STATUS_LV2 "OK") + + IF(NOT LMMS_HAVE_LV2CORE) + SET(STATUS_LV2 "LV2 devel packages not found : need lv2core(-devel)") + ENDIF(NOT LMMS_HAVE_LV2CORE) + + IF(NOT LMMS_HAVE_SLV2) + SET(STATUS_LV2 "LV2 (Host) devel packages not found : need libslv2-dev, slv2-devel or similiar") + ENDIF(NOT LMMS_HAVE_SLV2) + + IF(NOT LMMS_HAVE_RDF) + SET(STATUS_LV2 "LV2 (RDF) devel packages not found : need librdf0-dev, redland-devel or similiar") + ENDIF(NOT LMMS_HAVE_RDF) + + IF("${STATUS_LV2}" STREQUAL "OK") + FIND_LIBRARY(SLV2_LIBRARY NAMES slv2 PATH /usr/lib /usr/local/lib) + FIND_LIBRARY(RDF_LIBRARY NAMES rdf PATH /usr/lib /usr/local/lib) + SET(LMMS_SUPPORT_LV2 TRUE) + ENDIF("${STATUS_LV2}" STREQUAL "OK") +ENDIF(WANT_LV2) + # check for WINE IF(WANT_VST) - INCLUDE(CheckLibraryExists) INCLUDE(CheckIncludeFileCXX) SET(CMAKE_REQUIRED_FLAGS_ORIG ${CMAKE_REQUIRED_FLAGS}) SET(CMAKE_REQUIRED_INCLUDES_ORIG ${CMAKE_REQUIRED_INCLUDES}) @@ -658,6 +696,7 @@ MESSAGE( "* Stk Mallets : ${STATUS_STK}\n" "* VST-instrument hoster : ${STATUS_VST}\n" "* VST-effect hoster : ${STATUS_VST}\n" +"* LV2 hoster : ${STATUS_LV2}\n" "* SpectrumAnalyzer : ${STATUS_FFTW3F}\n" "* CAPS LADSPA plugins : ${STATUS_CAPS}\n" "* CMT LADSPA plugins : ${STATUS_CMT}\n" diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 132524acf..2a825ab26 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -7,6 +7,7 @@ ADD_SUBDIRECTORY(ladspa_browser) ADD_SUBDIRECTORY(ladspa_effect) ADD_SUBDIRECTORY(lb302) #ADD_SUBDIRECTORY(lb303) +ADD_SUBDIRECTORY(lv2_browser) ADD_SUBDIRECTORY(midi_import) ADD_SUBDIRECTORY(organic) ADD_SUBDIRECTORY(papu) diff --git a/plugins/lv2_browser/CMakeLists.txt b/plugins/lv2_browser/CMakeLists.txt new file mode 100644 index 000000000..04da59849 --- /dev/null +++ b/plugins/lv2_browser/CMakeLists.txt @@ -0,0 +1,5 @@ +IF(LMMS_SUPPORT_LV2) + INCLUDE(BuildPlugin) + LINK_LIBRARIES(${SLV2_LIBRARY}) + BUILD_PLUGIN(lv2browser lv2_browser.cpp lv2_browser.h lv2_manager.cpp lv2_manager.h lv2_description.cpp lv2_description.h lv2_port_dialog.cpp lv2_port_dialog.h MOCFILES lv2_browser.h lv2_description.h lv2_port_dialog.h EMBEDDED_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.png) +ENDIF(LMMS_SUPPORT_LV2) diff --git a/plugins/lv2_browser/logo.png b/plugins/lv2_browser/logo.png new file mode 100644 index 000000000..89e9f3680 Binary files /dev/null and b/plugins/lv2_browser/logo.png differ diff --git a/plugins/lv2_browser/lv2_browser.cpp b/plugins/lv2_browser/lv2_browser.cpp new file mode 100644 index 000000000..6e71f1828 --- /dev/null +++ b/plugins/lv2_browser/lv2_browser.cpp @@ -0,0 +1,245 @@ +/* + * lv2_browser.cpp - dialog to display information about installed LV2 + * plugins + * + * Copyright (c) 2009-2009 Martin Andrews + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include "lv2_browser.h" +#include "lv2_manager.h" + + +#include +#include + + +#include "gui_templates.h" +#include "lv2_description.h" +#include "lv2_port_dialog.h" +#include "tab_bar.h" +#include "tab_button.h" + + +#undef SINGLE_SOURCE_COMPILE +#include "embed.cpp" + + + + +extern "C" +{ + +plugin::descriptor PLUGIN_EXPORT lv2browser_plugin_descriptor = +{ + STRINGIFY( PLUGIN_NAME ), + "LV2 Plugin Browser", + QT_TRANSLATE_NOOP( "pluginBrowser", + "List installed LV2 plugins" ), + "Martin Andrews ", + 0x0100, + plugin::Tool, + new pluginPixmapLoader( "logo" ), + NULL, + NULL +} ; + + +// neccessary for getting instance out of shared lib +plugin * PLUGIN_EXPORT lmms_plugin_main( model * _parent, void * _data ) +{ + return( new lv2Browser ); +} + +} + + + + +lv2Browser::lv2Browser( void ) : + tool( &lv2browser_plugin_descriptor, NULL ) +{ + if( static_lv2_manager == NULL ) + { + static_lv2_manager=new lv2Manager(); + } +} + + + + +lv2Browser::~lv2Browser() +{ + if( static_lv2_manager != NULL ) + { + delete static_lv2_manager; + } +} + + + + +QString lv2Browser::nodeName( void ) const +{ + return( lv2browser_plugin_descriptor.name ); +} + + + + + + +lv2BrowserView::lv2BrowserView( tool * _tool ) : + toolView( _tool ) +{ + QHBoxLayout * hlayout = new QHBoxLayout( this ); + hlayout->setSpacing( 0 ); + hlayout->setMargin( 0 ); + + m_tabBar = new tabBar( this, QBoxLayout::TopToBottom ); + m_tabBar->setExclusive( TRUE ); + m_tabBar->setFixedWidth( 72 ); + + QWidget * ws = new QWidget( this ); + ws->setFixedSize( 500, 480 ); + + QWidget * available = createTab( ws, tr( "Available Effects" ), VALID ); + QWidget * unavailable = createTab( ws, tr( "Unavailable Effects" ), INVALID ); + QWidget * instruments = createTab( ws, tr( "Instruments" ), SOURCE ); + QWidget * analysis = createTab( ws, tr( "Analysis Tools" ), SINK ); + QWidget * other = createTab( ws, tr( "Don't know" ), OTHER ); + + m_tabBar->addTab( available, tr( "Available Effects" ), + 0, FALSE, TRUE + )->setIcon( embed::getIconPixmap( "setup_audio" ) ); + m_tabBar->addTab( unavailable, tr( "Unavailable Effects" ), + 1, FALSE, TRUE + )->setIcon( embed::getIconPixmap( + "unavailable_sound" ) ); + m_tabBar->addTab( instruments, tr( "Instruments" ), + 2, FALSE, TRUE + )->setIcon( embed::getIconPixmap( + "setup_midi" ) ); + m_tabBar->addTab( analysis, tr( "Analysis Tools" ), + 3, FALSE, TRUE + )->setIcon( embed::getIconPixmap( "analysis" ) ); + m_tabBar->addTab( other, tr( "Don't know" ), + 4, TRUE, TRUE + )->setIcon( embed::getIconPixmap( "uhoh" ) ); + + m_tabBar->setActiveTab( 0 ); + + hlayout->addWidget( m_tabBar ); + hlayout->addSpacing( 10 ); + hlayout->addWidget( ws ); + hlayout->addSpacing( 10 ); + hlayout->addStretch(); + + setWhatsThis( tr( +"This dialog displays information on all of the LV2 plugins LMMS was " +"able to locate. The plugins are divided into five categories based " +"upon an interpretation of the port types and names.\n\n" + +"Available Effects are those that can be used by LMMS. In order for LMMS " +"to be able to use an effect, it must, first and foremost, be an effect, " +"which is to say, it has to have both input channels and output channels. " +"LMMS identifies an input channel as an audio rate port containing 'in' in " +"the name. Output channels are identified by the letters 'out'. Furthermore, " +"the effect must have the same number of inputs and outputs and be real time " +"capable.\n\n" + +"Unavailable Effects are those that were identified as effects, but either " +"didn't have the same number of input and output channels or weren't real " +"time capable.\n\n" + +"Instruments are plugins for which only output channels were identified.\n\n" + +"Analysis Tools are plugins for which only input channels were identified.\n\n" + +"Don't Knows are plugins for which no input or output channels were " +"identified.\n\n" + +"Double clicking any of the plugins will bring up information on the " +"ports." ) ); + + hide(); + if( parentWidget() ) + { + parentWidget()->hide(); + parentWidget()->layout()->setSizeConstraint( + QLayout::SetFixedSize ); + + Qt::WindowFlags flags = parentWidget()->windowFlags(); + flags |= Qt::MSWindowsFixedSizeDialogHint; + flags &= ~Qt::WindowMaximizeButtonHint; + parentWidget()->setWindowFlags( flags ); + } +} + + + + +lv2BrowserView::~lv2BrowserView() +{ +} + + + + +QWidget * lv2BrowserView::createTab( QWidget * _parent, const QString & _txt, + lv2PluginType _type ) +{ + QWidget * tab = new QWidget( _parent ); + tab->setFixedSize( 500, 400 ); + QVBoxLayout * layout = new QVBoxLayout( tab ); + layout->setSpacing( 0 ); + layout->setMargin( 0 ); + + const QString type = "" + tr( "Type:" ) + " "; + QLabel * title = new QLabel( type + _txt, tab ); + QFont f = title->font(); + f.setBold( TRUE ); + title->setFont( pointSize<12>( f ) ); + + layout->addSpacing( 5 ); + layout->addWidget( title ); + layout->addSpacing( 10 ); + + lv2Description * description = new lv2Description( tab, _type ); + + // Double-clicking on a row gives us a pop-up + connect( description, SIGNAL( doubleClicked( const lv2_key_t & ) ), + SLOT( showPorts( const lv2_key_t & ) ) ); + + layout->addWidget( description, 1 ); + + return( tab ); +} + + +void lv2BrowserView::showPorts( const lv2_key_t & _key ) +{ + lv2PortDialog ports( _key ); + ports.exec(); +} + + +#include "moc_lv2_browser.cxx" diff --git a/plugins/lv2_browser/lv2_browser.h b/plugins/lv2_browser/lv2_browser.h new file mode 100644 index 000000000..f7b6d16d9 --- /dev/null +++ b/plugins/lv2_browser/lv2_browser.h @@ -0,0 +1,75 @@ +/* + * ladspa_browser.h - dialog to display information about installed LADSPA + * plugins + * + * Copyright (c) 2009-2009 Martin Andrews + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#ifndef _LV2_BROWSER_H +#define _LV2_BROWSER_H + + +#include "lv2_manager.h" +#include "tool.h" + + +class tabBar; + + +class lv2BrowserView : public toolView +{ + Q_OBJECT +public: + lv2BrowserView( tool * _tool ); + virtual ~lv2BrowserView(); + + +public slots: + void showPorts( const lv2_key_t & _key ); + + +private: + tabBar * m_tabBar; + + QWidget * createTab( QWidget * _parent, const QString & _txt, + lv2PluginType _type ); + +} ; + + +class lv2Browser : public tool +{ +public: + lv2Browser( void ); + virtual ~lv2Browser(); + + virtual pluginView * instantiateView( QWidget * ) + { + return( new lv2BrowserView( this ) ); + } + + virtual QString nodeName( void ) const; + +} ; + + +#endif diff --git a/plugins/lv2_browser/lv2_description.cpp b/plugins/lv2_browser/lv2_description.cpp new file mode 100644 index 000000000..2a02ef15a --- /dev/null +++ b/plugins/lv2_browser/lv2_description.cpp @@ -0,0 +1,234 @@ +/* + * lv2_description.cpp - LV2 plugin description + * + * Copyright (c) 2007 Javier Serrano Polo + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include "lv2_description.h" + + +#include +#include +#include +#include +#include + + +#include "audio_device.h" +#include "engine.h" +// #include "ladspa_2_lmms.h" +#include "mixer.h" + + + + +lv2Description::lv2Description( QWidget * _parent, + lv2PluginType _type ) : + QWidget( _parent ) +{ +// ladspa2LMMS * manager = engine::getLADSPAManager(); + lv2Manager * manager = static_lv2_manager; +/* + switch( _type ) + { + case SOURCE: + plugins = manager->getInstruments(); + break; + case TRANSFER: + plugins = manager->getValidEffects(); + break; + case VALID: + plugins = manager->getValidEffects(); + break; + case INVALID: + plugins = manager->getInvalidEffects(); + break; + case SINK: + plugins = manager->getAnalysisTools(); + break; + case OTHER: + plugins = manager->getOthers(); + break; + default: + break; + } +*/ + // Simpler : Get all the plugins, and select based on the type... + l_sortable_plugin_t plugins = manager->getSortedPlugins(); + + QList pluginNames; + for( l_sortable_plugin_t::iterator it = plugins.begin(); + it != plugins.end(); it++ ) + { + lv2ManagerDescription * description=manager->getDescription( ( *it ).second ); + if( description->type == _type && + ( + _type != VALID || + description->inputChannels <= engine::getMixer()->audioDev()->channels() + ) + ) + { + pluginNames.push_back( ( *it ).first ); + m_pluginKeys.push_back( ( *it ).second ); + } + } + + QGroupBox * pluginsBox = new QGroupBox( tr( "Plugins" ), this ); + QListWidget * pluginList = new QListWidget( pluginsBox ); + pluginList->addItems( pluginNames ); + connect( pluginList, SIGNAL( currentRowChanged( int ) ), + SLOT( rowChanged( int ) ) ); + connect( pluginList, SIGNAL( itemDoubleClicked( QListWidgetItem * ) ), + SLOT( onDoubleClicked( QListWidgetItem * ) ) ); + ( new QVBoxLayout( pluginsBox ) )->addWidget( pluginList ); + + QGroupBox * descriptionBox = new QGroupBox( tr( "Description" ), this ); + QVBoxLayout * descriptionLayout = new QVBoxLayout( descriptionBox ); + descriptionLayout->setSpacing( 0 ); + descriptionLayout->setMargin( 0 ); + + m_scrollArea = new QScrollArea( descriptionBox ); + descriptionLayout->addWidget( m_scrollArea ); + + QVBoxLayout * layout = new QVBoxLayout( this ); + layout->addWidget( pluginsBox ); + layout->addWidget( descriptionBox ); + + if( pluginList->count() > 0 ) + { + pluginList->setCurrentRow( 0 ); + m_currentSelection = m_pluginKeys[0]; + update( m_currentSelection ); + } +} + + + + +lv2Description::~lv2Description() +{ +} + + + + +void lv2Description::update( const lv2_key_t & _key ) +{ + QWidget * description = new QWidget; + m_scrollArea->setWidget( description ); + + QVBoxLayout * layout = new QVBoxLayout( description ); + layout->setSizeConstraint( QLayout::SetFixedSize ); + +// ladspa2LMMS * manager = engine::getLADSPAManager(); + lv2Manager * manager = static_lv2_manager; + + QLabel * name = new QLabel( description ); + name->setText( QWidget::tr( "Name: " ) + manager->getName( _key ) ); + layout->addWidget( name ); + + QWidget * maker = new QWidget( description ); + QHBoxLayout * makerLayout = new QHBoxLayout( maker ); + makerLayout->setMargin( 0 ); + makerLayout->setSpacing( 0 ); + layout->addWidget( maker ); + + QLabel * maker_label = new QLabel( maker ); + maker_label->setText( QWidget::tr( "Maker: " ) ); + maker_label->setAlignment( Qt::AlignTop ); + QLabel * maker_content = new QLabel( maker ); + maker_content->setText( manager->getMaker( _key ) ); + maker_content->setWordWrap( TRUE ); + makerLayout->addWidget( maker_label ); + makerLayout->addWidget( maker_content, 1 ); + +/* + QWidget * copyright = new QWidget( description ); + QHBoxLayout * copyrightLayout = new QHBoxLayout( copyright ); + copyrightLayout->setMargin( 0 ); + copyrightLayout->setSpacing( 0 ); + layout->addWidget( copyright ); + + QLabel * copyright_label = new QLabel( copyright ); + copyright_label->setText( QWidget::tr( "Copyright: " ) ); + copyright_label->setAlignment( Qt::AlignTop ); + + QLabel * copyright_content = new QLabel( copyright ); + copyright_content->setText( manager->getCopyright( _key ) ); + copyright_content->setWordWrap( TRUE ); + copyrightLayout->addWidget( copyright_label ); + copyrightLayout->addWidget( copyright_content, 1 ); + + QLabel * requiresRealTime = new QLabel( description ); + requiresRealTime->setText( QWidget::tr( "Requires Real Time: " ) + + ( manager->hasRealTimeDependency( _key ) ? + QWidget::tr( "Yes" ) : + QWidget::tr( "No" ) ) ); + layout->addWidget( requiresRealTime ); + + QLabel * realTimeCapable = new QLabel( description ); + realTimeCapable->setText( QWidget::tr( "Real Time Capable: " ) + + ( manager->isRealTimeCapable( _key ) ? + QWidget::tr( "Yes" ) : + QWidget::tr( "No" ) ) ); + layout->addWidget( realTimeCapable ); + + QLabel * inplaceBroken = new QLabel( description ); + inplaceBroken->setText( QWidget::tr( "In Place Broken: " ) + + ( manager->isInplaceBroken( _key ) ? + QWidget::tr( "Yes" ) : + QWidget::tr( "No" ) ) ); + layout->addWidget( inplaceBroken ); +*/ + + QLabel * channelsIn = new QLabel( description ); + channelsIn->setText( QWidget::tr( "Channels In: " ) + QString::number( + manager->getDescription( _key )->inputChannels ) ); + layout->addWidget( channelsIn ); + + QLabel * channelsOut = new QLabel( description ); + channelsOut->setText( QWidget::tr( "Channels Out: " ) + QString::number( + manager->getDescription( _key )->outputChannels ) ); + layout->addWidget( channelsOut ); +} + + + + +void lv2Description::rowChanged( int _pluginIndex ) +{ + m_currentSelection = m_pluginKeys[_pluginIndex]; + update( m_currentSelection ); +} + + + + +void lv2Description::onDoubleClicked( QListWidgetItem * _item ) +{ + emit( doubleClicked( m_currentSelection ) ); +} + + + + +#include "moc_lv2_description.cxx" diff --git a/plugins/lv2_browser/lv2_description.h b/plugins/lv2_browser/lv2_description.h new file mode 100644 index 000000000..bd14087e8 --- /dev/null +++ b/plugins/lv2_browser/lv2_description.h @@ -0,0 +1,69 @@ +/* + * lv2_description.h - LV2 plugin description Pane of Information + * + * Copyright (c) 2009-2009 Martin Andrews + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#ifndef _LV2_DESCRIPTION_H +#define _LV2_DESCRIPTION_H + + +#include + +#include "lv2_manager.h" + + +class QListWidgetItem; +class QScrollArea; + + +class lv2Description : public QWidget +{ + Q_OBJECT +public: + lv2Description( QWidget * _parent, lv2PluginType _type ); + virtual ~lv2Description(); + + +signals: + void doubleClicked( const lv2_key_t & ); + + +private: + QScrollArea * m_scrollArea; + + QList m_pluginKeys; + lv2_key_t m_currentSelection; + + void update( const lv2_key_t & _key ); + + +private slots: + void rowChanged( int _pluginIndex ); + void onDoubleClicked( QListWidgetItem * _item ); + +} ; + + + + +#endif diff --git a/plugins/lv2_browser/lv2_manager.cpp b/plugins/lv2_browser/lv2_manager.cpp new file mode 100644 index 000000000..1a1bb5451 --- /dev/null +++ b/plugins/lv2_browser/lv2_manager.cpp @@ -0,0 +1,1201 @@ +/* + * ladspa_manager.cpp - a class to manage loading and instantiation + * of lv2 plugins + * + * Copyright (c) 2005-2008 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include +#include +#include +#include +// #include +#include + +#include + +#include "config_mgr.h" +#include "lv2_manager.h" + +lv2Manager * static_lv2_manager=(lv2Manager *)NULL; // There is only one of these... + +LV2World::LV2World() +{ + printf( "Creating static LV2World\n" ); + + world=slv2_world_new(); + slv2_world_load_all(world); + + input_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_INPUT); + output_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_OUTPUT); + control_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_CONTROL); + audio_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_AUDIO); + event_class = slv2_value_new_uri(world, SLV2_PORT_CLASS_EVENT); + midi_class = slv2_value_new_uri(world, SLV2_EVENT_CLASS_MIDI); + in_place_broken = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "inPlaceBroken"); + integer = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "integer"); + toggled = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "toggled"); + srate = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "sampleRate"); + gtk_gui = slv2_value_new_uri(world, "http://lv2plug.in/ns/extensions/ui#GtkUI"); +} + +LV2World::~LV2World() +{ + slv2_value_free(input_class); + slv2_value_free(output_class); + slv2_value_free(control_class); + slv2_value_free(audio_class); + slv2_value_free(event_class); + slv2_value_free(midi_class); + slv2_value_free(in_place_broken); + + slv2_world_free( world ); + printf("Destroyed SLV2\n"); +} + + + + +lv2Manager::lv2Manager( void ) +{ + if( m_lv2_bundle.world == NULL ) { + printf("Failed to Initialize slv2_world\n"); + return; + } + printf("Initialized slv2_world\n"); + + m_cache_file = configManager::inst()->workingDir() + "lv2_cache.txt"; + + loadFromCacheFile(); + + if( false ) { // This is to test the loading from the cache file + l_lv2_key_t keys = m_lv2ManagerMap.keys(); + for( l_lv2_key_t::iterator it = keys.begin(); + it != keys.end(); it++ ) + { + printf( "Read from file : '%s'\n", getName( *it ).toAscii().data() ); + } + } + +// slv2_world_load_all( m_world ); // No special path apart from LV2_PATH + m_plugin_list = slv2_world_get_all_plugins( m_lv2_bundle.world ); + + for(unsigned i=0; i < slv2_plugins_size( m_plugin_list ); i++) + { + SLV2Plugin p = slv2_plugins_get_at( m_plugin_list, i ); + addPlugins( p ); // This will just return if the plugin information is cached (after being loaded) + } + +/* + QStringList lv2Directories = QString( getenv( "LV2_PATH" ) ). + split( ',' ); +// lv2Directories += configManager::inst()->ladspaDir().split( ',' ); + + lv2Directories.push_back( configManager::inst()->pluginDir() + "lv2" ); +#ifndef LMMS_BUILD_WIN32 + lv2Directories.push_back( QString( LIB_DIR ) + "lv2" ); + lv2Directories.push_back( "/usr/lib/lmms/lv2" ); + lv2Directories.push_back( "/usr/local/lib/lmms/lv2" ); + lv2Directories.push_back( "/usr/lib/lv2" ); + lv2Directories.push_back( "/usr/local/lib/lv2" ); +#endif + + for( QStringList::iterator it = lv2Directories.begin(); + it != lv2Directories.end(); ++it ) + { + QDir directory( ( *it ) ); + QFileInfoList list = directory.entryInfoList(); + for( QFileInfoList::iterator file = list.begin(); + file != list.end(); ++file ) + { + const QFileInfo & f = *file; + if( !f.isFile() || +#ifdef LMMS_BUILD_WIN32 + f.fileName().right( 3 ).toLower() != "dll" +#else + f.fileName().right( 2 ).toLower() != "so" +#endif + ) + { + continue; + } + + QLibrary plugin_lib( f.absoluteFilePath() ); + + if( plugin_lib.load() == TRUE ) + { + LADSPA_Descriptor_Function descriptorFunction = + ( LADSPA_Descriptor_Function ) plugin_lib.resolve( + "ladspa_descriptor" ); + if( descriptorFunction != NULL ) + { + addPlugins( descriptorFunction, + f.fileName() ); + } + } + } + } + */ + + saveToCacheFile(); + + l_lv2_key_t keys = m_lv2ManagerMap.keys(); + for( l_lv2_key_t::iterator it = keys.begin(); + it != keys.end(); it++ ) + { + m_sortedPlugins.append( qMakePair( getName( *it ), *it ) ); + } + + qSort( m_sortedPlugins ); + printf("Sorted plugins\n"); +} + + + + +lv2Manager::~lv2Manager() +{ + for( lv2ManagerMapType::iterator it = m_lv2ManagerMap.begin(); + it != m_lv2ManagerMap.end(); ++it ) + { + delete it.value(); + } + + slv2_plugins_free( m_lv2_bundle.world, m_plugin_list ); + printf("Freed list of plugins\n"); + +// if( m_world != NULL ) { +// slv2_world_free( m_world ); +// } +} + + + + +lv2ManagerDescription * lv2Manager::getDescription( + const lv2_key_t & _plugin ) +{ + if( m_lv2ManagerMap.contains( _plugin ) ) + { + return( m_lv2ManagerMap[_plugin] ); + } + return( NULL ); // If it doesn't exist +} + + + + +void lv2Manager::ensureLV2DataExists( lv2ManagerDescription *desc ) +{ +// printf( "Ensuring LV2 Data for '%s'\n", (desc->uri).toAscii().data() ); + if( desc->plugin == NULL ) + { + printf( " Need to load actual plugin data for '%s'\n", (desc->uri).toAscii().constData() ); + + // use uri to get data + SLV2Value uri = slv2_value_new_uri( m_lv2_bundle.world, (desc->uri).toAscii().constData() ); + desc->plugin = slv2_plugins_get_by_uri( m_plugin_list, uri ); + slv2_value_free( uri ); + + if( desc->plugin == NULL ) // Still empty?? + { + printf( " Failed to load actual plugin data for '%s'\n", (desc->uri).toAscii().constData() ); + } + } + else { +// printf( " LV2 Data already existed for '%s'\n", (desc->uri).toAscii().data() ); + } + return; // There really should be data there now (or a suitable comment) +} + + + + +void lv2Manager::addPlugins( SLV2Plugin _plugin ) +{ + QString uri= QString( slv2_value_as_uri( slv2_plugin_get_uri( _plugin ) ) ); + lv2_key_t key = lv2_key_t( uri ); + + if( m_lv2ManagerMap.contains( key ) ) { + printf( "Already in Cache LV2 plugin URI : '%s'\n", uri.toAscii().constData() ); + return; + } + +/* +// Speed things up (before caching of data implemented) + if( ! uri.contains( "Organ" ) ) + { + printf( "Skipping LV2 plugin URI : '%s'\n", uri.toAscii().constData() ); + return; + } +*/ + printf( "Examining LV2 plugin URI : '%s'\n", uri.toAscii().constData() ); + + lv2ManagerDescription * description = new lv2ManagerDescription; + description->plugin = _plugin; + + // Investigate this plugin + description->uri = uri; + +// Any data accessed within the plugin itself causes the whole thing to be 'unwrapped' + SLV2Value data = slv2_plugin_get_name( _plugin ); + description->name = QString( slv2_value_as_string( data ) ); +// printf( " LV2 plugin Name : '%s'\n", slv2_value_as_string( data ) ); + slv2_value_free( data ); + + description->inputChannels = slv2_plugin_get_num_ports_of_class( _plugin, + m_lv2_bundle.input_class, m_lv2_bundle.audio_class, NULL); + + description->outputChannels = slv2_plugin_get_num_ports_of_class( _plugin, + m_lv2_bundle.output_class, m_lv2_bundle.audio_class, NULL); + +// This always seems to return 'Plugin', which isn't so useful to us +// SLV2PluginClass pclass = slv2_plugin_get_class( _plugin ); +// SLV2Value label = slv2_plugin_class_get_label( pclass ); +// printf( "Plugin Class is : '%s'\n", slv2_value_as_string( label ) ); + + printf( " Audio (input, output)=(%d,%d)\n", description->inputChannels, description->outputChannels ); + + if( description->inputChannels == 0 && description->outputChannels > 0 ) + { + description->type = SOURCE; + } + else if( description->inputChannels > 0 && + description->outputChannels > 0 ) + { + description->type = TRANSFER; + } + else if( description->inputChannels > 0 && + description->outputChannels == 0 ) + { + description->type = SINK; + } + else + { + description->type = OTHER; + } + + m_lv2ManagerMap[key] = description; + + printf( " Finished that plugin : type=%d\n", (int)description->type ); + +/* + const LADSPA_Descriptor * descriptor; + + for( long pluginIndex = 0; + ( descriptor = _descriptor_func( pluginIndex ) ) != NULL; + ++pluginIndex ) + { + ladspa_key_t key( _file, QString( descriptor->Label ) ); + if( m_ladspaManagerMap.contains( key ) ) + { + continue; + } + + plugIn->index = pluginIndex; + + m_ladspaManagerMap[key] = plugIn; + } +*/ + +} + + +/* +// This is an (Approximate) counting function + +Uint16 ladspaManager::getPluginInputs( + const LADSPA_Descriptor * _descriptor ) +{ + Uint16 inputs = 0; + + for( Uint16 port = 0; port < _descriptor->PortCount; port++ ) + { + if( LADSPA_IS_PORT_INPUT( + _descriptor->PortDescriptors[port] ) && + LADSPA_IS_PORT_AUDIO( + _descriptor->PortDescriptors[port] ) ) + { + QString name = QString( + _descriptor->PortNames[port] ); + if( name.toUpper().contains( "IN" ) ) + { + inputs++; + } + } + } + return inputs; +} + + +// This is an (Approximate) counting function + +Uint16 ladspaManager::getPluginOutputs( + const LADSPA_Descriptor * _descriptor ) +{ + Uint16 outputs = 0; + + for( Uint16 port = 0; port < _descriptor->PortCount; port++ ) + { + if( LADSPA_IS_PORT_OUTPUT( + _descriptor->PortDescriptors[port] ) && + LADSPA_IS_PORT_AUDIO( + _descriptor->PortDescriptors[port] ) ) + { + QString name = QString( + _descriptor->PortNames[port] ); + if( name.toUpper().contains( "OUT" ) ) + { + outputs++; + } + } + } + return outputs; +} + +*/ + + + +l_sortable_plugin_t lv2Manager::getSortedPlugins() +{ + return( m_sortedPlugins ); +} + + + +void lv2Manager::saveToCacheFile() +{ + QFile file( m_cache_file ); + QString line; + if ( file.open( QIODevice::WriteOnly ) ) { + QTextStream stream( &file ); + stream << "; This file is auto-regenerated by lmms\n\n"; + + l_lv2_key_t keys = m_lv2ManagerMap.keys(); + for( l_lv2_key_t::iterator it = keys.begin(); it != keys.end(); it++ ) + { + stream << "[" << (*it) << "]\n"; // Plugin URI + + lv2ManagerDescription * description=getDescription( (*it) ); + stream << "name=" << description->name << "\n"; // Plugin name + stream << "type=" << (int)description->type << "\n"; + stream << "channels.audio.input=" << description->inputChannels << "\n"; + stream << "channels.audio.output=" << description->outputChannels << "\n"; + + stream << "\n"; + } + + file.close(); + } + return; +} + + + + +void lv2Manager::loadFromCacheFile() +{ + QFile file( m_cache_file ); + QString line; + if ( file.open( QIODevice::ReadOnly ) ) { // file opened successfully + QTextStream stream( &file ); + while ( !stream.atEnd() ) { // until end of file... + line = stream.readLine().trimmed(); + if( line.startsWith( "[" ) && line.endsWith( "]" ) ) // Skip over everything else + { + lv2ManagerDescription * desc=new lv2ManagerDescription; + desc->plugin = NULL; // To ensure that we don't attempt to use it + desc->uri = line.mid( 1, line.length()-2 ); // Extract the URI + printf( "Reading Data for '%s' from the Cache\n", desc->uri.toAscii().data() ); + + // Read in data for this uri - until we get to a blank line + bool finished = false; + while ( !stream.atEnd() && !finished ) + { + line = stream.readLine().trimmed(); + if( line.length() == 0 ) + { + finished = true; + continue; + } + int equals = line.indexOf( "=" ); + if( equals > 0 ) + { + QString name = line.left(equals); + QString value = line.mid(equals+1); + printf( " Found '%s' = '%s'\n", name.toAscii().data(), value.toAscii().data() ); + + if( name == "name" ) + { + desc->name = value; + } + else if( name == "type" ) + { + desc->type = (lv2PluginType)value.toInt(); + } + else if( name == "channels.audio.input" ) + { + desc->inputChannels = value.toInt(); + } + else if( name == "channels.audio.output" ) + { + desc->outputChannels = value.toInt(); + } + else + { + printf( "Could not parse line : '%s' in lv2.cache\n", line.toAscii().data() ); + } + } + } + // Dump the discovered data into the manager + lv2_key_t key = lv2_key_t( desc->uri ); + m_lv2ManagerMap[key] = desc; + } + // Skip lines that don't match ^[.*]$ + } + // Close the file + file.close(); + } + return; +} + + + +/* + +QString ladspaManager::getLabel( const ladspa_key_t & _plugin ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + return( QString( descriptor->Label ) ); + } + else + { + return( QString( "" ) ); + } +} + + + + +bool ladspaManager::hasRealTimeDependency( + const ladspa_key_t & _plugin ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + return( LADSPA_IS_REALTIME( descriptor->Properties ) ); + } + else + { + return( FALSE ); + } +} + +*/ + + +bool lv2Manager::isInplaceBroken( const lv2_key_t & _plugin ) +{ + if( m_lv2ManagerMap.contains( _plugin ) ) + { + lv2ManagerDescription * d = m_lv2ManagerMap[_plugin]; + ensureLV2DataExists( d ); + return ( slv2_plugin_has_feature( d->plugin, m_lv2_bundle.in_place_broken ) ); + } + else + { + return( FALSE ); + } +} + + +/* + +bool ladspaManager::isRealTimeCapable( + const ladspa_key_t & _plugin ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + return( LADSPA_IS_HARD_RT_CAPABLE( descriptor->Properties ) ); + } + else + { + return( FALSE ); + } +} + +*/ + + +QString lv2Manager::getName( const lv2_key_t & _plugin ) +{ + if( m_lv2ManagerMap.contains( _plugin ) ) + { + // This is a cached entry - so it will be here + // whether the plugin rdf is fully loaded or not + return m_lv2ManagerMap[_plugin]->name; + } + else + { + return( QString( "" ) ); + } +} + + + + +QString lv2Manager::getMaker( const lv2_key_t & _plugin ) +{ + if( m_lv2ManagerMap.contains( _plugin ) ) + { + lv2ManagerDescription * d = m_lv2ManagerMap[_plugin]; + ensureLV2DataExists( d ); + SLV2Value data = slv2_plugin_get_author_name( d->plugin ); + QString ret = QString( data ? + slv2_value_as_string( data ) : "Unknown" ); + slv2_value_free( data ); + return( ret ); + } + else + { + return( QString( "" ) ); + } +} + + + + +QString lv2Manager::getCopyright( const lv2_key_t & _plugin ) +{ + if( m_lv2ManagerMap.contains( _plugin ) ) + { + lv2ManagerDescription * d = m_lv2ManagerMap[_plugin]; + ensureLV2DataExists( d ); + SLV2Value data = slv2_plugin_get_author_homepage( d->plugin ); + QString ret = QString( data ? + slv2_value_as_string( data ) : "Unknown" ); + slv2_value_free( data ); + return( ret ); + } + else + { + return( QString( "" ) ); + } +} + + + + +Uint32 lv2Manager::getPortCount( const lv2_key_t & _plugin ) +{ + if( m_lv2ManagerMap.contains( _plugin ) ) + { + lv2ManagerDescription * d = m_lv2ManagerMap[_plugin]; + ensureLV2DataExists( d ); + return( (Uint32) + slv2_plugin_get_num_ports( d->plugin ) + ); + } + else + { + return( 0 ); + } +} + +bool lv2Manager::isPortClass( const lv2_key_t & _plugin, + Uint32 _port, SLV2Value _class ) +{ + if( m_lv2ManagerMap.contains( _plugin ) ) + { + lv2ManagerDescription * d = m_lv2ManagerMap[_plugin]; + ensureLV2DataExists( d ); + if( _port < slv2_plugin_get_num_ports( d->plugin ) ) + { + SLV2Port port = slv2_plugin_get_port_by_index( d->plugin, _port ); + return( + slv2_port_is_a( d->plugin, port, _class ) + ); + } + } + return( FALSE ); // Not found +} + + + +bool lv2Manager::isPortInput( const lv2_key_t & _plugin, + Uint32 _port ) +{ + return isPortClass( _plugin, _port, m_lv2_bundle.input_class ); +} + + + +bool lv2Manager::isPortOutput( const lv2_key_t & _plugin, + Uint32 _port ) +{ + return isPortClass( _plugin, _port, m_lv2_bundle.output_class ); +} + + + + +bool lv2Manager::isPortAudio( const lv2_key_t & _plugin, + Uint32 _port ) +{ + return isPortClass( _plugin, _port, m_lv2_bundle.audio_class ); +} + + + + +bool lv2Manager::isPortControl( const lv2_key_t & _plugin, + Uint32 _port ) +{ + return isPortClass( _plugin, _port, m_lv2_bundle.control_class ); +} + + +/* + +bool ladspaManager::areHintsSampleRateDependent( + const ladspa_key_t & _plugin, + Uint32 _port ) +{ + if( m_ladspaManagerMap.contains( _plugin ) + && _port < getPortCount( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + LADSPA_PortRangeHintDescriptor hintDescriptor = + descriptor->PortRangeHints[_port].HintDescriptor; + return( LADSPA_IS_HINT_SAMPLE_RATE ( hintDescriptor ) ); + } + else + { + return( FALSE ); + } +} + +*/ + +void lv2Manager::getRanges( const lv2_key_t & _plugin, + Uint32 _port, float * _def, float * _min, float * _max ) +{ + if( m_lv2ManagerMap.contains( _plugin ) ) + { + lv2ManagerDescription * d = m_lv2ManagerMap[_plugin]; + ensureLV2DataExists( d ); + if( _port < slv2_plugin_get_num_ports( d->plugin ) ) + { + SLV2Port port = slv2_plugin_get_port_by_index( d->plugin, _port ); + SLV2Value def, min, max; + slv2_port_get_range( d->plugin, port, &def, &min, &max ); + *_def = NOHINT; + if( def != NULL ) + { + *_def = slv2_value_as_float(def); + slv2_value_free(def); + } + *_min = NOHINT; + if( min != NULL ) + { + *_min = slv2_value_as_float(min); + slv2_value_free(min); + } + *_max = NOHINT; + if( max != NULL ) + { + *_max = slv2_value_as_float(max); + slv2_value_free(max); + } + } + } +} + + +float lv2Manager::getLowerBound( const lv2_key_t & _plugin, Uint32 _port ) +{ + float def, min, max; + getRanges( _plugin, _port, &def, &min, &max ); + return( min ); +} + +float lv2Manager::getUpperBound( const lv2_key_t & _plugin, Uint32 _port ) +{ + float def, min, max; + getRanges( _plugin, _port, &def, &min, &max ); + return( max ); +} + +float lv2Manager::getDefaultSetting( const lv2_key_t & _plugin, Uint32 _port ) +{ + float def, min, max; + getRanges( _plugin, _port, &def, &min, &max ); + return( def ); +} + + + + +/* +float ladspaManager::getDefaultSetting( const ladspa_key_t & _plugin, + Uint32 _port ) +{ + if( m_ladspaManagerMap.contains( _plugin ) + && _port < getPortCount( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + LADSPA_PortRangeHintDescriptor hintDescriptor = + descriptor->PortRangeHints[_port].HintDescriptor; + switch( hintDescriptor & LADSPA_HINT_DEFAULT_MASK ) + { + case LADSPA_HINT_DEFAULT_NONE: + return( NOHINT ); + case LADSPA_HINT_DEFAULT_MINIMUM: + return( descriptor->PortRangeHints[_port]. + LowerBound ); + case LADSPA_HINT_DEFAULT_LOW: + if( LADSPA_IS_HINT_LOGARITHMIC + ( hintDescriptor ) ) + { + return( exp( log( descriptor->PortRangeHints[_port].LowerBound ) + * 0.75 + + log( descriptor->PortRangeHints[_port].UpperBound ) + * 0.25 ) ); + } + else + { + return( descriptor->PortRangeHints[_port].LowerBound + * 0.75 + + descriptor->PortRangeHints[_port].UpperBound + * 0.25 ); + } + case LADSPA_HINT_DEFAULT_MIDDLE: + if( LADSPA_IS_HINT_LOGARITHMIC + ( hintDescriptor ) ) + { + return( sqrt( descriptor->PortRangeHints[_port].LowerBound + * descriptor->PortRangeHints[_port].UpperBound ) ); + } + else + { + return( 0.5 * ( descriptor->PortRangeHints[_port].LowerBound + + descriptor->PortRangeHints[_port].UpperBound ) ); + } + case LADSPA_HINT_DEFAULT_HIGH: + if( LADSPA_IS_HINT_LOGARITHMIC + ( hintDescriptor ) ) + { + return( exp( log( descriptor->PortRangeHints[_port].LowerBound ) + * 0.25 + + log( descriptor->PortRangeHints[_port].UpperBound ) + * 0.75 ) ); + } + else + { + return( descriptor->PortRangeHints[_port].LowerBound + * 0.25 + + descriptor->PortRangeHints[_port].UpperBound + * 0.75 ); + } + case LADSPA_HINT_DEFAULT_MAXIMUM: + return( descriptor->PortRangeHints[_port].UpperBound ); + case LADSPA_HINT_DEFAULT_0: + return( 0.0 ); + case LADSPA_HINT_DEFAULT_1: + return( 1.0 ); + case LADSPA_HINT_DEFAULT_100: + return( 100.0 ); + case LADSPA_HINT_DEFAULT_440: + return( 440.0 ); + default: + return( NOHINT ); + } + } + else + { + return( NOHINT ); + } +} +*/ + + +/* +bool ladspaManager::isLogarithmic( const ladspa_key_t & _plugin, + Uint32 _port ) +{ + if( m_ladspaManagerMap.contains( _plugin ) + && _port < getPortCount( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + LADSPA_PortRangeHintDescriptor hintDescriptor = + descriptor->PortRangeHints[_port].HintDescriptor; + return( LADSPA_IS_HINT_LOGARITHMIC( hintDescriptor ) ); + } + else + { + return( FALSE ); + } +} + + +*/ + + + +QStringList lv2Manager::listEnumeration( const lv2_key_t & _plugin, Uint32 _port ) +{ + QStringList list; + if( m_lv2ManagerMap.contains( _plugin ) ) + { + lv2ManagerDescription * d = m_lv2ManagerMap[_plugin]; + ensureLV2DataExists( d ); + if( _port < slv2_plugin_get_num_ports( d->plugin ) ) + { + SLV2Port port = slv2_plugin_get_port_by_index( d->plugin, _port ); + SLV2ScalePoints sp_list = slv2_port_get_scale_points( d->plugin, port ); + if( sp_list != NULL ) + { + printf( "Got %d ScalePoints for port=%d\n", + slv2_scale_points_size( sp_list ), _port ); + + for( unsigned i = 0; i < slv2_scale_points_size( sp_list ); i++ ) + { + SLV2ScalePoint sp = slv2_scale_points_get_at( sp_list, i ); + SLV2Value label = slv2_scale_point_get_label( sp ); + list.append( QString( slv2_value_as_string( label ) ) ); + // slv2_value_free( label ); + // slv2_scale_point_free( sp ); + } + slv2_scale_points_free( sp_list ); + } + } + } + return( list ); +} + + + + + + +bool lv2Manager::isInteger( const lv2_key_t & _plugin, + Uint32 _port ) +{ + if( listEnumeration( _plugin, _port).size() >= 2 ) { + return( TRUE ); + } + return( FALSE ); +} + + + +bool lv2Manager::isPortToggled( const lv2_key_t & _plugin, + Uint32 _port ) +{ + if( listEnumeration( _plugin, _port).size() == 2 ) { + return( TRUE ); + } + return( FALSE ); +} + + + + + + +QString lv2Manager::getPortName( const lv2_key_t & _plugin, + Uint32 _port ) +{ + if( m_lv2ManagerMap.contains( _plugin ) ) + { + lv2ManagerDescription * d = m_lv2ManagerMap[_plugin]; + ensureLV2DataExists( d ); + if( _port < slv2_plugin_get_num_ports( d->plugin ) ) + { + SLV2Port port = slv2_plugin_get_port_by_index( d->plugin, _port ); + return( QString( + slv2_value_as_string( slv2_port_get_name( d->plugin, port ) ) + ) ); + } + } + return( QString( "" ) ); +} + + + +/* +const void * ladspaManager::getImplementationData( + const ladspa_key_t & _plugin ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + return( descriptor->ImplementationData ); + } + else + { + return( NULL ); + } +} + + + + +const LADSPA_Descriptor * ladspaManager::getDescriptor( + const ladspa_key_t & _plugin ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + return( descriptor ); + } + else + { + return( NULL ); + } +} + +*/ + + +/* +LADSPA_Handle ladspaManager::instantiate( + const ladspa_key_t & _plugin, + Uint32 _sample_rate ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + return( ( descriptor->instantiate ) + ( descriptor, _sample_rate ) ); + } + else + { + return( NULL ); + } +} + + + + +bool ladspaManager::connectPort( const ladspa_key_t & _plugin, + LADSPA_Handle _instance, + Uint32 _port, + LADSPA_Data * _data_location ) +{ + if( m_ladspaManagerMap.contains( _plugin ) + && _port < getPortCount( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + if( descriptor->connect_port != NULL ) + { + ( descriptor->connect_port ) + ( _instance, _port, _data_location ); + return( TRUE ); + } + } + return( FALSE ); +} + + + + +bool ladspaManager::activate( const ladspa_key_t & _plugin, + LADSPA_Handle _instance ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + if( descriptor->activate != NULL ) + { + ( descriptor->activate ) ( _instance ); + return( TRUE ); + } + } + return( FALSE ); +} + + + + +bool ladspaManager::run( const ladspa_key_t & _plugin, + LADSPA_Handle _instance, + Uint32 _sample_count ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + if( descriptor->run != NULL ) + { + ( descriptor->run ) ( _instance, _sample_count ); + return( TRUE ); + } + } + return( FALSE ); +} + + + + +bool ladspaManager::runAdding( const ladspa_key_t & _plugin, + LADSPA_Handle _instance, + Uint32 _sample_count ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + if( descriptor->run_adding != NULL && + descriptor->set_run_adding_gain != NULL ) + { + ( descriptor->run_adding ) ( _instance, _sample_count ); + return( TRUE ); + } + } + return( FALSE ); +} + + + + +bool ladspaManager::setRunAddingGain( const ladspa_key_t & _plugin, + LADSPA_Handle _instance, + LADSPA_Data _gain ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + if( descriptor->run_adding != NULL && + descriptor->set_run_adding_gain != NULL ) + { + ( descriptor->set_run_adding_gain ) + ( _instance, _gain ); + return( TRUE ); + } + } + return( FALSE ); +} + + + + +bool ladspaManager::deactivate( const ladspa_key_t & _plugin, + LADSPA_Handle _instance ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + if( descriptor->deactivate != NULL ) + { + ( descriptor->deactivate ) ( _instance ); + return( TRUE ); + } + } + return( FALSE ); +} + + + + +bool ladspaManager::cleanup( const ladspa_key_t & _plugin, + LADSPA_Handle _instance ) +{ + if( m_ladspaManagerMap.contains( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + if( descriptor->cleanup != NULL ) + { + ( descriptor->cleanup ) ( _instance ); + return( TRUE ); + } + } + return( FALSE ); +} +*/ + diff --git a/plugins/lv2_browser/lv2_manager.h b/plugins/lv2_browser/lv2_manager.h new file mode 100644 index 000000000..ed89f10aa --- /dev/null +++ b/plugins/lv2_browser/lv2_manager.h @@ -0,0 +1,384 @@ +/* + * ladspa_manager.h - declaration of class lv2Manager + * a class to manage + * lv2 plugins + * + * Copyright (c) 2005-2008 Danny McRae + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#ifndef _LV2_MANAGER_H +#define _LV2_MANAGER_H + +//#include +#include "slv2/world.h" +#include "slv2/plugin.h" +#include "slv2/scalepoint.h" +#include "slv2/scalepoints.h" + +#include +#include +#include +#include + + +#include "export.h" +#include "lmms_basics.h" + +const float NOHINT = -99342.2243f; + +//typedef QPair lv2_key_t; +typedef QString lv2_key_t; // Just need the URI for LV2... +typedef QPair sortable_plugin_t; +typedef QList l_sortable_plugin_t; +typedef QList l_lv2_key_t; + +/* lv2Manager provides a database of LV2 plug-ins. Upon instantiation, +it loads all of the plug-ins found in the LV2_PATH environmental variable +and stores their access descriptors according in a dictionary keyed on +the filename the plug-in was loaded from and the label of the plug-in. + +The can be retrieved by using lv2_key_t (which is really just the LV2 URI) : + +// lv2_key_t key( "lalala" ) + +as the plug-in key. */ + + +/** The SLV2World, and various cached (as symbols, fast) URIs. + * + * This object represents everything ardour 'knows' about LV2 + * (ie understood extensions/features/etc) + */ +struct LV2World { + LV2World(); + ~LV2World(); + + SLV2World world; + SLV2Value input_class; ///< Input port + SLV2Value output_class; ///< Output port + SLV2Value audio_class; ///< Audio port + SLV2Value control_class; ///< Control port + SLV2Value event_class; ///< Event port + SLV2Value midi_class; ///< MIDI event + SLV2Value in_place_broken; + SLV2Value integer; + SLV2Value toggled; + SLV2Value srate; + SLV2Value gtk_gui; +}; + + +enum lv2PluginType +{ + SOURCE, + TRANSFER, + VALID, + INVALID, + SINK, + OTHER +}; + +typedef struct lv2ManagerStorage +{ + SLV2Plugin plugin; +// Uint32 index; + QString uri; + QString name; + lv2PluginType type; + Uint16 inputChannels; + Uint16 outputChannels; +} lv2ManagerDescription; + + +class EXPORT lv2Manager +{ +public: + + lv2Manager( void ); + virtual ~lv2Manager(); + + void loadFromCacheFile(); + void saveToCacheFile(); + + l_sortable_plugin_t getSortedPlugins(); + lv2ManagerDescription * getDescription( const lv2_key_t & _plugin ); + + /* This identifier can be used as a unique, case-sensitive + identifier for the plugin type within the plugin file. Plugin + types should be identified by file and label rather than by index + or plugin name, which may be changed in new plugin + versions. Labels must not contain white-space characters. */ + QString getLabel( const lv2_key_t & _plugin ); + + /* Indicates that the plugin has a real-time dependency + (e.g. listens to a MIDI device) and so its output must not + be cached or subject to significant latency. */ +// bool hasRealTimeDependency( const lv2_key_t & _plugin ); + + /* Indicates that the plugin may cease to work correctly if the + host elects to use the same data location for both input and output + (see connectPort). */ + bool isInplaceBroken( const lv2_key_t & _plugin ); + + /* Indicates that the plugin is capable of running not only in a + conventional host but also in a 'hard real-time' environment. */ +// bool isRealTimeCapable( const lv2_key_t & _plugin ); + + /* Returns the name of the plug-in */ + QString getName( const lv2_key_t & _plugin ); + + /* Returns the the plug-in's author */ + QString getMaker( const lv2_key_t & _plugin ); + + /* Returns the copyright for the plug-in */ + QString getCopyright( const lv2_key_t & _plugin ); + + /* This indicates the number of ports (input AND output) present on + the plugin. */ + Uint32 getPortCount( const lv2_key_t & _plugin ); + + + /* Indicates that the port is an input. */ + bool isPortInput( const lv2_key_t & _plugin, Uint32 _port ); + + /* Indicates that the port is an output. */ + bool isPortOutput( const lv2_key_t & _plugin, Uint32 _port ); + + /* Indicates that the port is an audio. */ + bool isPortAudio( const lv2_key_t & _plugin, Uint32 _port ); + + /* Indicates that the port is an control. */ + bool isPortControl( const lv2_key_t & _plugin, Uint32 _port ); + + /* Indicates that any bounds specified should be interpreted as + multiples of the sample rate. For instance, a frequency range from + 0Hz to the Nyquist frequency (half the sample rate) could be requested + by this hint in conjunction with LowerBound = 0 and UpperBound = 0.5. + Hosts that support bounds at all must support this hint to retain + meaning. */ +// bool areHintsSampleRateDependent( const ladspa_key_t & _plugin, +// Uint32 _port ); + + /* Returns the lower boundary value for the given port. If + no lower bound is provided by the plug-in, returns -999e-99. When + areHintsSampleRateDependent() is also true then this value should be + multiplied by the relevant sample rate. */ + float getLowerBound( const lv2_key_t & _plugin, Uint32 _port ); + + /* Returns the upper boundary value for the given port. If + no upper bound is provided by the plug-in, returns -999e-99. When + areHintsSampleRateDependent() is also true then this value should be + multiplied by the relevant sample rate. */ + float getUpperBound( const lv2_key_t & _plugin, Uint32 _port ); + + /* Retrieves any default setting hints offered by the plug-in for + the given port. */ + float getDefaultSetting( const lv2_key_t & _plugin, Uint32 _port ); + + /* Indicates that a user interface would probably wish to provide a + stepped control taking only integer values. Any bounds set should be + slightly wider than the actual integer range required to avoid floating + point rounding errors. For instance, the integer set {0,1,2,3} might + be described as [-0.1, 3.1]. */ + bool isInteger( const lv2_key_t & _plugin, Uint32 _port ); + + /* Indicates whether the given port should be considered 0 or 1 + boolean switch. */ + bool isPortToggled( const lv2_key_t & _plugin, Uint32 _port ); + + /* return the labels to be applied on the UI */ + QStringList listEnumeration( const lv2_key_t & _plugin, Uint32 _port ); + + /* Indicates that it is likely that the user will find it more + intuitive to view values using a logarithmic scale. This is + particularly useful for frequencies and gains. */ +// bool isLogarithmic( const ladspa_key_t & _plugin, Uint32 _port ); + + + /* Returns the name of the port. */ + QString getPortName( const lv2_key_t & _plugin, Uint32 _port ); + + + /* This may be used by the plugin developer to pass any custom + implementation data into an instantiate call. It must not be used + or interpreted by the host. It is expected that most plugin + writers will not use this facility as LADSPA_Handle should be + used to hold instance data. */ +// const void * getImplementationData( +// const ladspa_key_t & _plugin ); + + + /* Returns a pointer to the plug-in's descriptor from which control + of the plug-in is accessible */ +// const LADSPA_Descriptor * getDescriptor( +// const ladspa_key_t & _plugin ); + + + /* The following methods are convenience functions for use during + development. A real instrument should use the getDescriptor() + method and implement the plug-in manipulations internally to avoid + the overhead associated with QMap lookups. */ + + + /* Returns a handle to an instantiation of the given plug-in. */ + //LADSPA_Handle instantiate( const ladspa_key_t & _plugin, + // Uint32 _sample_rate ); + + /* This method calls a function pointer that connects a port on an + instantiated plugin to a memory location at which a block of data + for the port will be read/written. The data location is expected + to be an array of LADSPA_Data for audio ports or a single + LADSPA_Data value for control ports. Memory issues will be + managed by the host. The plugin must read/write the data at these + locations every time run() or runAdding() is called and the data + present at the time of this connection call should not be + considered meaningful. + + connectPort() may be called more than once for a plugin instance + to allow the host to change the buffers that the plugin is + reading or writing. These calls may be made before or after + activate() or deactivate() calls. + + connectPort() must be called at least once for each port before + run() or runAdding() is called. */ +// bool connectPort( const ladspa_key_t & _plugin, +// LADSPA_Handle _instance, +// Uint32 _port, +// LADSPA_Data * _data_location ); + + /* This method calls a function pointer that initialises a plugin + instance and activates it for use. This is separated from + instantiate() to aid real-time support and so that hosts can + reinitialise a plugin instance by calling deactivate() and then + activate(). In this case the plugin instance must reset all state + information dependent on the history of the plugin instance + except for any data locations provided by connectPort() and any + gain set by setRunAddingGain(). If there is nothing for + activate() to do then the plugin writer may provide a NULL rather + than an empty function. + + When present, hosts must call this function once before run() (or + runAdding()) is called for the first time. This call should be + made as close to the run() call as possible and indicates to + real-time plugins that they are now live. Plugins should not rely + on a prompt call to run() after activate(). activate() may not be + called again unless deactivate() is called first. Note that + connectPort() may be called before or after a call to + activate(). */ +// bool activate( const ladspa_key_t & _plugin, +// LADSPA_Handle _instance ); + + /* This method calls a function pointer that runs an instance of a + plugin for a block. Two parameters are required: the first is a + handle to the particular instance to be run and the second + indicates the block size (in samples) for which the plugin + instance may run. + + Note that if an activate() function exists then it must be called + before run() or run_adding(). If deactivate() is called for a + plugin instance then the plugin instance may not be reused until + activate() has been called again. */ +// bool run( const ladspa_key_t & _plugin, +// LADSPA_Handle _instance, +// Uint32 _sample_count ); + + /* This method calls a function pointer that runs an instance of a + plugin for a block. This has identical behaviour to run() except + in the way data is output from the plugin. When run() is used, + values are written directly to the memory areas associated with + the output ports. However when runAdding() is called, values + must be added to the values already present in the memory + areas. Furthermore, output values written must be scaled by the + current gain set by setRunAddingGain() (see below) before + addition. + + runAdding() is optional. When it is not provided by a plugin, + this function pointer must be set to NULL. When it is provided, + the function setRunAddingGain() must be provided also. */ +// bool runAdding( const ladspa_key_t & _plugin, +// LADSPA_Handle _instance, +// Uint32 _sample_count ); + + /* This method calls a function pointer that sets the output gain for + use when runAdding() is called (see above). If this function is + never called the gain is assumed to default to 1. Gain + information should be retained when activate() or deactivate() + are called. + + This function should be provided by the plugin if and only if the + runAdding() function is provided. When it is absent this + function pointer must be set to NULL. */ +// bool setRunAddingGain( const ladspa_key_t & _plugin, +// LADSPA_Handle _instance, +// LADSPA_Data _gain ); + + /* This is the counterpart to activate() (see above). If there is + nothing for deactivate() to do then the plugin writer may provide + a NULL rather than an empty function. + + Hosts must deactivate all activated units after they have been + run() (or run_adding()) for the last time. This call should be + made as close to the last run() call as possible and indicates to + real-time plugins that they are no longer live. Plugins should + not rely on prompt deactivation. Note that connect_port() may be + called before or after a call to deactivate(). + + Deactivation is not similar to pausing as the plugin instance + will be reinitialised when activate() is called to reuse it. */ +// bool deactivate( const ladspa_key_t & _plugin, +// LADSPA_Handle _instance ); + + /* Once an instance of a plugin has been finished with it can be + deleted using the following function. The instance handle passed + ceases to be valid after this call. + + If activate() was called for a plugin instance then a + corresponding call to deactivate() must be made before cleanup() + is called. */ +// bool cleanup( const ladspa_key_t & _plugin, +// LADSPA_Handle _instance ); + +private: + void addPlugins( SLV2Plugin _plugin ); + void ensureLV2DataExists( lv2ManagerDescription *desc ); + + bool isPortClass( const lv2_key_t & _plugin, + Uint32 _port, SLV2Value _class ); + + void getRanges( const lv2_key_t & _plugin, + Uint32 _port, float * _def, float * _min, float * _max ); + + SLV2Plugins m_plugin_list; + typedef QMap lv2ManagerMapType; + lv2ManagerMapType m_lv2ManagerMap; + l_sortable_plugin_t m_sortedPlugins; + + LV2World m_lv2_bundle; + + QString m_cache_file; +} ; + + +// This is declared static in lv2_manager.cpp +extern lv2Manager * static_lv2_manager; // There is only one of these... + +#endif diff --git a/plugins/lv2_browser/lv2_port_dialog.cpp b/plugins/lv2_browser/lv2_port_dialog.cpp new file mode 100644 index 000000000..e2eb5573f --- /dev/null +++ b/plugins/lv2_browser/lv2_port_dialog.cpp @@ -0,0 +1,202 @@ +/* + * lv2_port_dialog.cpp - dialog to test an LV2 plugin + * + * Copyright (c) 2009-2009 Martin Andrews + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#include "lv2_port_dialog.h" + +#include +#include + +#include "embed.h" +#include "engine.h" +// #include "ladspa_2_lmms.h" +#include "mixer.h" + + +lv2PortDialog::lv2PortDialog( const lv2_key_t & _key ) +{ +// ladspa2LMMS * manager = engine::getLADSPAManager(); + lv2Manager * manager = static_lv2_manager; + + setWindowIcon( embed::getIconPixmap( "ports" ) ); + setWindowTitle( tr( "Ports" ) ); + setModal( TRUE ); + + QVBoxLayout * vlayout = new QVBoxLayout( this ); + vlayout->setSpacing( 0 ); + vlayout->setMargin( 0 ); + + Uint16 pc = manager->getPortCount( _key ); + + QStringList ports; + ports.append( tr( "Name" ) ); + ports.append( tr( "Rate" ) ); + ports.append( tr( "Direction" ) ); + ports.append( tr( "Type" ) ); + ports.append( tr( "Min < Default < Max" ) ); +// ports.append( tr( "Logarithmic" ) ); +// ports.append( tr( "SR Dependent" ) ); + + QTableWidget * settings = new QTableWidget( pc, ports.size(), this ); + settings->setHorizontalHeaderLabels( ports ); + + for( Uint16 row = 0; row < pc; row++ ) + { + for( Uint8 col = 0; col < ports.size(); ++col ) + { + QTableWidgetItem * item = new QTableWidgetItem; + item->setFlags( 0 ); + settings->setItem( row, col, item ); + } + + Uint8 col = 0; + settings->item( row, col++ )->setText( manager->getPortName( + _key, row ) ); + + settings->item( row, col++ )->setText( + manager->isPortAudio( _key, row ) ? + tr( "Audio" ) : tr( "Control" ) ); + + settings->item( row, col++ )->setText( + manager->isPortInput( _key, row ) ? + tr( "Input" ) : tr( "Output" ) ); + + QStringList values; + if( manager->isInteger( _key, row ) ) + { + values = manager->listEnumeration( _key, row ); + settings->item( row, col )->setText( values.join("|") ); + } + else + { + settings->item( row, col )->setText( tr( "Float" ) ); + } + col++; + +/* + settings->item( row, col++ )->setText( + manager->isPortToggled( _key, row ) ? tr( "Toggled" ) : + manager->isInteger( _key, row ) ? tr( "Integer" ) : + tr( "Float" ) ); +*/ + + float min = manager->getLowerBound( _key, row ); + float max = manager->getUpperBound( _key, row ); + float def = manager->getDefaultSetting( _key, row ); + QString range = ""; + +/* + if( manager->areHintsSampleRateDependent( _key, row ) ) + { + if( min != NOHINT ) + { + min *= engine::getMixer()->processingSampleRate(); + } + if( max != NOHINT ) + { + max *= engine::getMixer()->processingSampleRate(); + } + } +*/ + + if( min == NOHINT ) + { + range += "-Inf < "; + } + else if( values.size() >0 ) + { + // Don't have a minimum +// range += QString::number( static_cast( min ) ) + " < "; + } + else + { + range += QString::number( min ) + " < "; + } + + if( def == NOHINT ) + { + range += "None < "; + } +// else if( manager->isInteger( _key, row ) ) + else if( values.size() > 0 ) + { + def=( def < 0 )?0:(( def > values.size() )?values.size()-1:def); + range += values.at( static_cast( def ) ); +// range += QString::number( static_cast( def ) ) + " < "; + } + else + { + range += QString::number( def ) + " < "; + } + + if( max == NOHINT ) + { + range += "Inf"; + } + else if( values.size() >0 ) + { + // Don't have a maximum +// range += QString::number( static_cast( min ) ) + " < "; + } + else + { + range += QString::number( max ); + } + + settings->item( row, col++ )->setText( range ); + +/* + if( manager->isLogarithmic( _key, row ) ) + { + settings->item( row, col )->setText( tr( "Yes" ) ); + } + col++; +*/ + +/* + if( manager->areHintsSampleRateDependent( _key, row ) ) + { + settings->item( row, col )->setText( tr( "Yes" ) ); + } + col++; +*/ + } + + vlayout->addWidget( settings ); + + show(); +} + + + + +lv2PortDialog::~lv2PortDialog() +{ +} + + + + +#include "moc_lv2_port_dialog.cxx" + diff --git a/plugins/lv2_browser/lv2_port_dialog.h b/plugins/lv2_browser/lv2_port_dialog.h new file mode 100644 index 000000000..2ac0db3a1 --- /dev/null +++ b/plugins/lv2_browser/lv2_port_dialog.h @@ -0,0 +1,49 @@ +/* + * lv2_port_dialog.h - dialog to test an LV2 plugin + * + * Copyright (c) 2009-2009 Martin Andrews + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#ifndef _LV2_PORT_DIALOG_H +#define _LV2_PORT_DIALOG_H + + +#include + +#include "lv2_manager.h" + + + + +class lv2PortDialog : public QDialog +{ + Q_OBJECT +public: + lv2PortDialog( const lv2_key_t & _key ); + virtual ~lv2PortDialog(); + +}; + + + + +#endif