From d1cfe6941259b9a9197b1a30a4d4713de806af8a Mon Sep 17 00:00:00 2001 From: Martin Andrews Date: Thu, 30 Apr 2009 00:05:39 +0200 Subject: [PATCH] LV2Browser: initial version This commit integrates initial support for LV2 plugins. This currently includes the LV2 browser and is meant for development purposes only. According changes were made to the build system in order to find required libraries and header files. --- CMakeLists.txt | 41 +- plugins/CMakeLists.txt | 1 + plugins/lv2_browser/CMakeLists.txt | 5 + plugins/lv2_browser/logo.png | Bin 0 -> 3225 bytes plugins/lv2_browser/lv2_browser.cpp | 245 +++++ plugins/lv2_browser/lv2_browser.h | 75 ++ plugins/lv2_browser/lv2_description.cpp | 234 +++++ plugins/lv2_browser/lv2_description.h | 69 ++ plugins/lv2_browser/lv2_manager.cpp | 1201 +++++++++++++++++++++++ plugins/lv2_browser/lv2_manager.h | 384 ++++++++ plugins/lv2_browser/lv2_port_dialog.cpp | 202 ++++ plugins/lv2_browser/lv2_port_dialog.h | 49 + 12 files changed, 2505 insertions(+), 1 deletion(-) create mode 100644 plugins/lv2_browser/CMakeLists.txt create mode 100644 plugins/lv2_browser/logo.png create mode 100644 plugins/lv2_browser/lv2_browser.cpp create mode 100644 plugins/lv2_browser/lv2_browser.h create mode 100644 plugins/lv2_browser/lv2_description.cpp create mode 100644 plugins/lv2_browser/lv2_description.h create mode 100644 plugins/lv2_browser/lv2_manager.cpp create mode 100644 plugins/lv2_browser/lv2_manager.h create mode 100644 plugins/lv2_browser/lv2_port_dialog.cpp create mode 100644 plugins/lv2_browser/lv2_port_dialog.h 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 0000000000000000000000000000000000000000..89e9f3680118931dd86f065a8f6bc0b4c631a585 GIT binary patch literal 3225 zcmV;K3}*9*P)`#WFm#_KhbhiGA@U*^o_ z?)UBYo!>dX?|kR%N`_(3mE2^y!khFt%vlIo2DuiJ53xXoA?=VokVZ)2as;qQmgTQk zRaM=vc=6&zGiJEI(qbI$Du=q8bYDa-!T4lNbqv-;`L=^Wjh{! z{PDzr0|$(OfdS*wS|X7!+S=NTZQHgPH{X17r=lo7!t?I`l?SGwJ#pWC_ib3WZk^=u zcnAs-2L-lzW^j-sNr=^ICA-}&`giTxMVmKoKG)dT_#F&+=ZgeTk(ZbE`g6}cx3Ipx zo-7uNP>z*~#bN|6ki+2+_tF7m0%D3qqfy$lX%lVVzMZ}ClP?0mRdD@VPe1*1pFK+ofU!5YF*p_;mk!1RdhfmW(!qlVx8m0KCZmipN#!dc z@2y(3s(kh8)x@-MI-L{_hlM5C`Ybk^jnrh4`uqE7cz9SyBoY<$@dK>i=M!W2nLr>w znx+x<5$)KqV+jB{u*S}bDrA|2@=nO_ATw%fYsI2$>8`F$;YgF?CjYsg_e4i$2W4kv zQ$az2piC0LhJr!i2?oSK+S}VHFE5vP-rc)*{}2eF>pfud6P*|l_SoFF@*VCGB-9aZ? zPeb`Alvaf0c`QG}pg924)YOQ*)Y{sbx%PK2MKZTO(^ETl?i9+eU%y^(maWO$mZ3Zu zNlcocMGGov$^1NW>RoipjSI*ksU)FKQAR>5KhIz|n$4YCO|QN72T-UtbM3D{uKO$$ z@~UELR`@5Byj z4`h+zo<$aAMnm>O&a*Awn zPxH{UEQMxQc&NCtnCwyq$!ZTQEs^5zlQ-8zax6e$c_t+_T~OvMBH0Tsyg;wK^2+EQ z8l!n2FHXq=*kF&q)ju{*(9HaXX>j}Px6?iM+(RyG+@xV4zav0%vmYg=^*Cu!oW4m! zuBDA*j+v&p!K%2nNVZKW%OE6b~Y5RpWY|_YJSfhvm2)z`$~F^abYuOEx?(Ffd5Lp?=bod^+3dBUfxMc|96Q$q4mgbMEU{N@s`s zbnHkYAtM!YapUmHb8*<^@XOIFD=SOTi*qa}Z-?OyL5}em#OKMl05JK6wQJYD2>?Z$ z$1^wiL7trBG%r?!9H_FglFG}=MI>Pv9u8CQg)Zugcqo{dPsP^5WYuD{r}GZ_S6>yK zK6!*rpFS;wL9l{+p0MJqG_PTvlpb!$Lec3jS#xvqUH}M;2>=71 zM|4@ui*O>=)YK#vVs{r76$%>hZ$6AT@&t#1$ZLkg!r^d4oC(~=ijfhg&H)$gZdRx; z--r9EpbJtG5iWbWyQv3Rz~JBj?uTIQsIWYHSSXGF!3QGG$@rQ1KOCufW2kK*`Xk&nrS!F)y!(m)SLfjy?9+5hSNErgq-DPEaqfL z3!aDTR&sb`jteVhG&50SFd~LSn71r8yN&ENyWlnV^A(&G7Oz`U3(NXOyrXNQnW`zQ zV4RhP(YP-?;t68_6wk$d0G+dC%a%W*lKU#gwKIiexa>us+wktY?+SOZ^&^pp;H9Zd zy6`X^hm}za?Qd2byK#)SK}!&zTk3q)SHVz#!NVJP)o$MIG59$gcDzYt1^{-vhyTxfq9RLK=Q!$vCo!-M1NT={ zRQwT#Rn^peU}X4WY7L?DG3avyG+c)LaNN|F!DW_|LGbKoaI$fsCG>XNH5}&6BJ}&^GG`&b3ep!29q9x^( z4FDd{{_lY?UhH1VW*Nr=dV1Zd88WFFFynOK^I5ha|Iv{v8OlYgQ)A3~DERR#&!;9O zN?^_euKZg!q)P*UJ)r3_iVg)}qNsO6l;?3G?e>zx3B{E#1_ZFMh2n`^GEh#sEVfUo zJQ^sFt{8TTt6*kgfIM=5a;8C9w@u_bu}BED!60?_t2j|@6vMnEz!*~l5Q)plysTlm z@u~>b)UKd8)z#!Fm`yfU0ZJhk6pND@?WN(qHt}w={nPT4LQB#WO4X~OO50(#fHvNU)M=Gj$-QIf&KK?V_q0Y)+Y_X z0;YU(Nx=5do&8i=_kE(gTcEJPK7m2{M*fFItuC2-Wpl_^UQKi7`6%$uM`-`qHfq(r z0RVDpBU#9*hpEQ<8@hUSg0il8l*my$lJV*My{}8mCn*v+b38OXua>4?yO?gN3)8J1 zyiHqF%6)tP=vx$HLIA#Yy>!#hAB@+N&xPu+iHx3pETD*&R3u3s&BgTKbXixiH-h9X zk?AJO`=p$4(H^N*jFVyAnrW}nwX>Q?^35SV_&!nCPLgcl;^CwH!&?qwa52S(lFrkj zB?kSrP=BCqBfWIuJe`|}2Y5!k&`=_!~L6Y4|h9wI|L3x_;6f_5o*bosi z5<$#4jD6)IuRrFWo~xCo0DQ~~${2vMxIAv}p+J3=e8Y@NN4{(W-?_lCh#VCFAPQS3 z31`GHV_dxVl({NXbUM|n4cz%?-($P>HNVl_b?z@a8}_}`b0O4oTb*s8)$2s`atMx! z`7oZC;xZ?`D&|V0#1QXWCDhz6ZHvG2>~{TS<0FIXCI}_N^89&+-#8V8<7C_3kldrh zH23UcdA2LtDoI%mSPp`+Q?fB2D8Y+J8cFd41$(0O+P3hA>wX%4vbjTRibg^~6e9yk zH8ynQjMlWfQ9m=&Ym^rF6~8ST6mpt#L9Cch;rX!n;ZAQf2kSb z3lV=M89|Dup80A~N(10ac|!PhdY)8qUA3)x=|bmK^QxS)d^rxctVo8Q)QsSu8fiNn z?bv%b)^fNdajLabYfUAJwlU}#1#ah@8A@60HIBJU7rL&VUg{`-ajZ;8HLe;x-SNT3 zW6_p<|Bf9!(w1!L4;dXPW+YM{#`__m6o^lpK1ym~M+&VqCF%X#=a5q1j1hMxQ*&8U z&r9Q+?rKUQ@l0w5a9o3-iQgN>QWTLg#`FDn>bG&Rm%C + * + * 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