Hello all!
Some time ago I've started implementing lv2 support for muse 2. Now
it's working in alpha state!
I hope that there are those who would like to test it and submit reports :).
*What works now:*
-Enumerating LV2 plugins and synths.
-Supporting all commonly used LV2 features
-Instantiate synth LV2 tracks
-Instantiate LV2 plugins as inserts in tracks and aux busses (yes, this
required some hacking muse2 code, but not so much)
-Playing live midi events from midi tracks inputs (like hardware midi
keyboard, etc.)
-Playing midi tracks sequencer events
*What does not work now:
*-GUIs. Though auto-generated guis for insert plugins are working, but
with some bugs
-Saving plugin's parameters on on song save - no ability to restore LV2
plugin and synth settings on song load
-No controller automation support yet
-(May be something else :) )
Now I'm working on GUIs and settings saving. After that - controller
automation.
*Instructions for applying **patch:
*(I assume that you saved included patch file to location like
/path/to/0001-Initial-alpha-lv2-support-for-muse2.patch)
*NOTE: to build LV2 support you will need lilv library version 0.18.0 or
later and all it's dependences. This library is used in ardour 3, so
it's likely that your distro already have it in repos.* *It's home site
is **http://drobilla.net/software/lilv/*
*git clone https://github.com/muse-sequencer/muse.git**
**cd muse**
**git apply /path/to/0001-Initial-alpha-lv2-support-for-muse2.patch*
ignore warnings
then build as usual, but check that LV2 support is on when running cmake:
*mkdir build**
cd build
**cmake ../muse2/ -DCMAKE_INSTALL_PREFIX=~/muse2*
/The following components will be built://
//-----------------------------------------------//
// Lash support//
// OSC (Liblo) support//
// DSSI support//
// LV2 support//<---- this must be present
// Native VST support//
// Fluidsynth support//
/
*make**
**make install*
run and test it :)
*~/muse2/bin/muse2*
What worked for me:
Calf plugins (synths and effects)
Linux Sampler LV2 plugin
mda series of synths
.. and many others :)
Good luck!
WBR, Andrew.
>From 245ffe870921968bdd581c52463522126861136e Mon Sep 17 00:00:00 2001
From: Andrew Deryabin <andrewderya...@gmail.com>
Date: Mon, 29 Sep 2014 23:58:44 +0000
Subject: [PATCH] Initial alpha lv2 support for muse2
---
muse2/CMakeLists.txt | 48 +-
muse2/config.h.in | 1 +
muse2/muse/CMakeLists.txt | 5 +
muse2/muse/globals.cpp | 1 +
muse2/muse/globals.h | 1 +
muse2/muse/lv2host.cpp | 1617 +++++++++++++++++++++++++++++++++++++++++
muse2/muse/lv2host.h | 618 ++++++++++++++++
muse2/muse/main.cpp | 22 +
muse2/muse/plugin.cpp | 36 +-
muse2/muse/plugin.h | 47 +-
muse2/muse/synth.cpp | 2 +-
muse2/muse/synth.h | 3 +-
muse2/share/locale/muse_ru.ts | 10 +-
13 files changed, 2357 insertions(+), 54 deletions(-)
create mode 100644 muse2/muse/lv2host.cpp
create mode 100644 muse2/muse/lv2host.h
diff --git a/muse2/CMakeLists.txt b/muse2/CMakeLists.txt
index 66a2ea1..1ce41f6 100644
--- a/muse2/CMakeLists.txt
+++ b/muse2/CMakeLists.txt
@@ -51,7 +51,7 @@ if (NOT LIB_INSTALL_DIR)
endif (NOT LIB_INSTALL_DIR)
if (LIB_SUFFIX)
- message(" Install libraries to: " ${LIB_INSTALL_DIR} )
+ message(" Install libraries to: " ${LIB_INSTALL_DIR} )
endif (LIB_SUFFIX)
IF(NOT DEFINED SHARE_INSTALL_PREFIX)
@@ -62,7 +62,7 @@ ENDIF(NOT DEFINED SHARE_INSTALL_PREFIX)
#set(CMAKE_BUILD_TYPE release)
# If no CMAKE_BUILD_TYPE is given on the command line,
-# cmake either uses the cached value, or 'empty' (plain un-opt build).
+# cmake either uses the cached value, or 'empty' (plain un-opt build).
# And yet the only way a user can reset a cached CMAKE_BUILD_TYPE
# is with "-DCMAKE_BUILD_TYPE=". So we cannot interfere with this.
# We should probably not attempt to do this at all.
@@ -132,6 +132,7 @@ option ( ENABLE_DSSI "Enable Disposable Soft Synth Interface (dssi) (OSC
option ( ENABLE_VST "Enable VST/win support (deprecated)" OFF)
option ( ENABLE_VST_NATIVE "Enable Native VST support (see ENABLE_VST_VESTIGE and VST_HEADER_PATH)" ON)
option ( ENABLE_VST_VESTIGE "Set VST header type is Vestige" ON)
+option ( ENABLE_LV2 "Enable LV2 plugins and synths support" ON)
option ( ENABLE_FLUID "Enable fluidsynth softsynth plugins." ON)
option ( ENABLE_EXPERIMENTAL "Enable building experimental features." OFF)
option ( ENABLE_PYTHON "Enable Python control support." OFF)
@@ -220,7 +221,7 @@ PKG_CHECK_MODULES(SAMPLERATE REQUIRED samplerate>=0.1.0)
include_directories(${SAMPLERATE_INCLUDE_DIRS})
##
-## find libuuid
+## find libuuid
##
PKG_CHECK_MODULES(UUID REQUIRED uuid>=0.0.1)
@@ -242,7 +243,7 @@ include_directories(${JACK_INCLUDE_DIRS})
##
##
-## find LASH
+## find LASH
##
if (ENABLE_LASH)
@@ -250,7 +251,7 @@ if (ENABLE_LASH)
if (LASH_FOUND)
include_directories(${LASH_INCLUDE_DIRS})
set(HAVE_LASH ON)
- endif (LASH_FOUND)
+ endif (LASH_FOUND)
else (ENABLE_LASH)
message("LASH disabled")
endif (ENABLE_LASH)
@@ -333,7 +334,7 @@ if (ENABLE_VST_NATIVE)
message("Native VST support enabled")
set (VST_NATIVE_SUPPORT TRUE)
endif (VST_HEADER_CHECK STREQUAL "VST_HEADER_CHECK-NOTFOUND")
-
+
else (ENABLE_VST_NATIVE)
message("Native VST support disabled")
endif (ENABLE_VST_NATIVE)
@@ -343,10 +344,24 @@ UNSET (VST_HEADER_CHECK CACHE)
if (ENABLE_VST_VESTIGE)
SET (VST_VESTIGE_SUPPORT TRUE)
-else (ENABLE_VST_VESTIGE)
+else (ENABLE_VST_VESTIGE)
SET (VST_VESTIGE_SUPPORT FALSE)
endif (ENABLE_VST_VESTIGE)
+## LV2 support
+## check for lilv >= 0.18.0
+##
+
+if (ENABLE_LV2)
+ PKG_CHECK_MODULES(LV2 lilv-0>=0.18.0)
+ if (LV2_FOUND)
+ include_directories(${LV2_INCLUDE_DIRS})
+ set(LV2_SUPPORT ON)
+ endif (LV2_FOUND)
+else (ENABLE_LV2)
+ message("LV2 disabled")
+endif (ENABLE_LV2)
+
##
## TODO
##
@@ -456,7 +471,7 @@ ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Winvalid-pch -fno-exceptions -fPIC ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -fomit-frame-pointer -ffast-math -fstrength-reduce -fPIC ${CMAKE_CXX_FLAGS_RELEASE}")
-set(CMAKE_CXX_FLAGS_DEBUG "-g -DQT_DEBUG -fPIC ${CMAKE_CXX_FLAGS_DEBUG}")
+set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -DQT_DEBUG -fPIC ${CMAKE_CXX_FLAGS_DEBUG}")
# NOTE: share/ directory needs to be at the end so that the translations
# are scanned before coming to share/locale
@@ -491,26 +506,26 @@ add_custom_target(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake")
##
-## Report errors and warnings and hints
+## Report errors and warnings and hints
##
message("\n")
if (NOT ALSA_FOUND)
message("** ERROR: alsa >= 0.9.0 is required, but development files were not found.")
-endif (NOT ALSA_FOUND)
+endif (NOT ALSA_FOUND)
if (NOT SNDFILE_FOUND)
message("** ERROR: sndfile >= 1.0.0 is required, but development files were not found.")
-endif (NOT SNDFILE_FOUND)
+endif (NOT SNDFILE_FOUND)
if (NOT SAMPLERATE_FOUND)
message("** ERROR: samplerate >= 0.1.0 is required, but development files were not found.")
-endif (NOT SAMPLERATE_FOUND)
+endif (NOT SAMPLERATE_FOUND)
if (NOT UUID_FOUND)
message("** ERROR: uuid >= 0.0.1 is required, but development files were not found.")
-endif (NOT UUID_FOUND)
+endif (NOT UUID_FOUND)
if (NOT JACK_FOUND)
message("** ERROR: jack >= 0.103 is required, but development files were not found.")
@@ -542,6 +557,10 @@ if (ENABLE_FLUID AND (NOT FLUIDSYN_FOUND))
message("** WARNING: fluidsynth (>= 0.9.0) was enabled, but development files were not found.")
endif (ENABLE_FLUID AND (NOT FLUIDSYN_FOUND))
+if (ENABLE_LV2 AND (NOT LV2_FOUND))
+ message("** WARNING: LV2 was enabled, but development files were not found (lilv>=0.18.0).")
+endif (ENABLE_LV2 AND (NOT LV2_FOUND))
+
message("")
## Show a summary of what we got
@@ -549,6 +568,7 @@ summary_add("Lash support" HAVE_LASH)
summary_add("OSC (Liblo) support" OSC_SUPPORT)
summary_add("Python support" PYTHON_SUPPORT)
summary_add("DSSI support" DSSI_SUPPORT)
+summary_add("LV2 support" LV2_SUPPORT)
#summary_add("VST support" VST_SUPPORT)
summary_add("Native VST support" VST_NATIVE_SUPPORT)
summary_add("Fluidsynth support" HAVE_FLUIDSYNTH)
@@ -565,7 +585,7 @@ endif ( MODULES_BUILD_STATIC )
if (NOT CMAKE_BUILD_TYPE)
message(" Build type: CMAKE_BUILD_TYPE is empty. Plain un-optimized build.")
else (NOT CMAKE_BUILD_TYPE)
- message(" Build type: " ${CMAKE_BUILD_TYPE} )
+ message(" Build type: " ${CMAKE_BUILD_TYPE} )
endif (NOT CMAKE_BUILD_TYPE)
message("")
diff --git a/muse2/config.h.in b/muse2/config.h.in
index 7dc31c5..903c1f9 100644
--- a/muse2/config.h.in
+++ b/muse2/config.h.in
@@ -23,6 +23,7 @@
#cmakedefine HAVE_LASH
#cmakedefine OSC_SUPPORT
#cmakedefine DSSI_SUPPORT
+#cmakedefine LV2_SUPPORT
#cmakedefine VST_SUPPORT
#cmakedefine VST_NATIVE_SUPPORT
#cmakedefine VST_VESTIGE_SUPPORT
diff --git a/muse2/muse/CMakeLists.txt b/muse2/muse/CMakeLists.txt
index 6a346bd..4116e05 100644
--- a/muse2/muse/CMakeLists.txt
+++ b/muse2/muse/CMakeLists.txt
@@ -91,6 +91,7 @@ file (GLOB core_source_files
ctrl.cpp
dialogs.cpp
dssihost.cpp
+ lv2host.cpp
event.cpp
eventlist.cpp
exportmidi.cpp
@@ -263,6 +264,10 @@ if(OSC_SUPPORT)
target_link_libraries(core ${LIBLO_LIBRARIES})
endif(OSC_SUPPORT)
+if(LV2_SUPPORT)
+ target_link_libraries(core ${LV2_LIBRARIES})
+endif(LV2_SUPPORT)
+
target_link_libraries(muse
midiedit
core
diff --git a/muse2/muse/globals.cpp b/muse2/muse/globals.cpp
index 700b0a9..cf117cc 100644
--- a/muse2/muse/globals.cpp
+++ b/muse2/muse/globals.cpp
@@ -113,6 +113,7 @@ bool loadPlugins = true;
bool loadVST = true;
bool loadNativeVST = true;
bool loadDSSI = true;
+bool loadLV2 = true;
bool usePythonBridge = false;
bool useLASH = true;
bool useAlsaWithJack = false;
diff --git a/muse2/muse/globals.h b/muse2/muse/globals.h
index e84c2ce..31f0dca 100644
--- a/muse2/muse/globals.h
+++ b/muse2/muse/globals.h
@@ -90,6 +90,7 @@ extern bool loadNativeVST;
extern bool loadDSSI;
extern bool usePythonBridge;
extern bool useLASH;
+extern bool loadLV2;
extern bool useAlsaWithJack;
extern bool noAutoStartJack;
diff --git a/muse2/muse/lv2host.cpp b/muse2/muse/lv2host.cpp
new file mode 100644
index 0000000..95e6dd8
--- /dev/null
+++ b/muse2/muse/lv2host.cpp
@@ -0,0 +1,1617 @@
+//=============================================================================
+// MusE
+// Linux Music Editor
+//
+// lv2host.cpp
+// Copyright (C) 2014-2014 by Deryabin Andrew <andrewderya...@gmail.com>
+//
+// 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; 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; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//=============================================================================
+
+#include "config.h"
+#ifdef LV2_SUPPORT
+
+#define LV2_HOST_CPP
+
+#include <string>
+#include <string.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <iostream>
+
+#include <QDir>
+#include <QFileInfo>
+
+#include "lv2host.h"
+#include "synth.h"
+#include "audio.h"
+#include "jackaudio.h"
+#include "midi.h"
+#include "midiport.h"
+#include "stringparam.h"
+#include "plugin.h"
+#include "controlfifo.h"
+#include "xml.h"
+#include "song.h"
+#include "ctrl.h"
+
+#include "app.h"
+#include "globals.h"
+#include "globaldefs.h"
+#include "gconfig.h"
+#include "popupmenu.h"
+#include <ladspa.h>
+
+#include <math.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
+#include "lv2/lv2plug.in/ns/ext/midi/midi.h"
+#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
+#include "lv2/lv2plug.in/ns/ext/event/event.h"
+#include "lv2/lv2plug.in/ns/ext/options/options.h"
+#include "lv2/lv2plug.in/ns/ext/parameters/parameters.h"
+#include "lv2/lv2plug.in/ns/ext/patch/patch.h"
+#include "lv2/lv2plug.in/ns/ext/port-groups/port-groups.h"
+#include "lv2/lv2plug.in/ns/ext/presets/presets.h"
+#include "lv2/lv2plug.in/ns/ext/state/state.h"
+#include "lv2/lv2plug.in/ns/ext/time/time.h"
+#include "lv2/lv2plug.in/ns/ext/uri-map/uri-map.h"
+#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
+#include "lv2/lv2plug.in/ns/ext/worker/worker.h"
+#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
+
+//uncomment to print debugging information for lv2 host
+#define DEBUG_LV2
+
+namespace MusECore
+{
+
+#define NS_EXT "http://lv2plug.in/ns/ext/"
+#define NS_LV2CORE "http://lv2plug.in/ns/lv2core"
+
+#define LV2_INSTRUMENT_CLASS NS_LV2CORE "#InstrumentPlugin"
+#define LV2_F_BOUNDED_BLOCK_LENGTH LV2_BUF_SIZE__boundedBlockLength
+#define LV2_F_FIXED_BLOCK_LENGTH LV2_BUF_SIZE__fixedBlockLength
+#define LV2_P_SEQ_SIZE LV2_BUF_SIZE__sequenceSize
+#define LV2_P_MAX_BLKLEN LV2_BUF_SIZE__maxBlockLength
+#define LV2_P_MIN_BLKLEN LV2_BUF_SIZE__minBlockLength
+#define LV2_P_SAMPLE_RATE LV2_PARAMETERS__sampleRate
+#define LV2_F_OPTIONS LV2_OPTIONS__options
+#define LV2_F_URID_MAP LV2_URID__map
+#define LV2_F_URID_UNMAP LV2_URID__unmap
+#define LV2_F_URI_MAP LV2_URI_MAP_URI
+
+LilvWorld *lilvWorld = 0;
+static int uniqueID = 1;
+
+//uri cache structure. Taken from jalv host source
+typedef struct
+{
+ LilvNode *atom_AtomPort;
+ LilvNode *atom_Chunk;
+ LilvNode *atom_Sequence;
+ LilvNode *ev_EventPort;
+ LilvNode *lv2_AudioPort;
+ LilvNode *lv2_ControlPort;
+ LilvNode *lv2_InputPort;
+ LilvNode *lv2_OutputPort;
+ LilvNode *lv2_connectionOptional;
+ LilvNode *lv2_control;
+ LilvNode *lv2_name;
+ LilvNode *midi_MidiEvent;
+ LilvNode *pg_group;
+ LilvNode *pset_Preset;
+ LilvNode *rdfs_label;
+ LilvNode *work_interface;
+ LilvNode *work_schedule;
+ LilvNode *end; ///< NULL terminator for easy freeing of entire structure
+} CacheNodes;
+
+
+LV2_URID Synth_Urid_Map(LV2_URID_Unmap_Handle _host_data, const char *uri)
+{
+ LV2Synth *_synth = reinterpret_cast<LV2Synth *>(_host_data);
+
+ if(_synth == NULL) //broken plugin
+ {
+ return 0;
+ }
+
+ return _synth->mapUrid(uri);
+}
+
+const char *Synth_Urid_Unmap(LV2_URID_Unmap_Handle _host_data, LV2_URID id)
+{
+ LV2Synth *_synth = reinterpret_cast<LV2Synth *>(_host_data);
+
+ if(_synth == NULL) //broken plugin
+ {
+ return NULL;
+ }
+
+ return _synth->unmapUrid(id);
+}
+
+LV2_URID Synth_Uri_Map(LV2_URI_Map_Callback_Data _host_data, const char *, const char *uri)
+{
+ LV2Synth *_synth = reinterpret_cast<LV2Synth *>(_host_data);
+
+ if(_synth == NULL) //broken plugin
+ {
+ return 0;
+ }
+
+ return _synth->mapUrid(uri);
+}
+
+
+static CacheNodes lv2CacheNodes;
+
+LV2_URID_Map LV2_SynthIF_Urid_Map = {NULL /* must fill later */, Synth_Urid_Map};
+LV2_URID_Unmap LV2_SynthIF_Urid_Unmap = {NULL /* must fill later */, Synth_Urid_Unmap};
+LV2_URI_Map_Feature LV2_SynthIF_Uri_Map = {NULL /* must fill later */, Synth_Uri_Map};
+
+LV2_Feature lv2Features [] =
+{
+ {LV2_F_URID_MAP, &LV2_SynthIF_Urid_Map},
+ {LV2_F_URID_UNMAP, &LV2_SynthIF_Urid_Unmap},
+ {LV2_F_URID_UNMAP, &LV2_SynthIF_Urid_Unmap},
+ {LV2_F_URI_MAP, &LV2_SynthIF_Uri_Map},
+ {LV2_F_BOUNDED_BLOCK_LENGTH, NULL},
+ {LV2_F_FIXED_BLOCK_LENGTH, NULL},
+ {LV2_F_OPTIONS, NULL}
+};
+
+std::vector<LV2Synth *> synthsToFree;
+
+
+
+#define SIZEOF_ARRAY(x) sizeof(x)/sizeof(x[0])
+
+void initLV2()
+{
+ std::set<std::string> supportedFeatures;
+ uint32_t i = 0;
+
+ for(i = 0; i < SIZEOF_ARRAY(lv2Features); i++)
+ {
+ supportedFeatures.insert(lv2Features [i].URI);
+ }
+
+ lilvWorld = lilv_world_new();
+
+ // taken from jalv.c
+ /* Cache URIs for concepts we'll use */
+ lv2CacheNodes.atom_AtomPort = lilv_new_uri(lilvWorld, LV2_ATOM__AtomPort);
+ lv2CacheNodes.atom_Chunk = lilv_new_uri(lilvWorld, LV2_ATOM__Chunk);
+ lv2CacheNodes.atom_Sequence = lilv_new_uri(lilvWorld, LV2_ATOM__Sequence);
+ lv2CacheNodes.ev_EventPort = lilv_new_uri(lilvWorld, LV2_EVENT__EventPort);
+ lv2CacheNodes.lv2_AudioPort = lilv_new_uri(lilvWorld, LV2_CORE__AudioPort);
+ lv2CacheNodes.lv2_ControlPort = lilv_new_uri(lilvWorld, LV2_CORE__ControlPort);
+ lv2CacheNodes.lv2_InputPort = lilv_new_uri(lilvWorld, LV2_CORE__InputPort);
+ lv2CacheNodes.lv2_OutputPort = lilv_new_uri(lilvWorld, LV2_CORE__OutputPort);
+ lv2CacheNodes.lv2_connectionOptional = lilv_new_uri(lilvWorld, LV2_CORE__connectionOptional);
+ lv2CacheNodes.lv2_control = lilv_new_uri(lilvWorld, LV2_CORE__control);
+ lv2CacheNodes.lv2_name = lilv_new_uri(lilvWorld, LV2_CORE__name);
+ lv2CacheNodes.midi_MidiEvent = lilv_new_uri(lilvWorld, LV2_MIDI__MidiEvent);
+ lv2CacheNodes.pg_group = lilv_new_uri(lilvWorld, LV2_PORT_GROUPS__group);
+ lv2CacheNodes.pset_Preset = lilv_new_uri(lilvWorld, LV2_PRESETS__Preset);
+ lv2CacheNodes.rdfs_label = lilv_new_uri(lilvWorld, LILV_NS_RDFS "label");
+ lv2CacheNodes.work_interface = lilv_new_uri(lilvWorld, LV2_WORKER__interface);
+ lv2CacheNodes.work_schedule = lilv_new_uri(lilvWorld, LV2_WORKER__schedule);
+ lv2CacheNodes.end = NULL;
+
+ lilv_world_load_all(lilvWorld);
+ const LilvPlugins *plugins = lilv_world_get_all_plugins(lilvWorld);
+ LilvIter *pit = lilv_plugins_begin(plugins);
+
+ while(true)
+ {
+ if(lilv_plugins_is_end(plugins, pit))
+ {
+ break;
+ }
+
+ const LilvPlugin *plugin = lilv_plugins_get(plugins, pit);
+
+ if(lilv_plugin_is_replaced(plugin))
+ {
+ continue;
+ }
+
+ bool shouldLoad = true;
+
+ LilvNode *nameNode = lilv_plugin_get_name(plugin);
+ const LilvNode *uriNode = lilv_plugin_get_uri(plugin);
+
+ if(lilv_node_is_string(nameNode))
+ {
+ const char *pluginName = lilv_node_as_string(nameNode);
+ const char *pluginUri = lilv_node_as_string(uriNode);
+#ifdef DEBUG_LV2
+ std::cerr << "Found LV2 plugin: " << pluginName << std::endl;
+#endif
+ const char *lfp = lilv_uri_to_path(lilv_node_as_string(lilv_plugin_get_library_uri(plugin)));
+#ifdef DEBUG_LV2
+ std::cerr << "Library path: " << lfp << std::endl;
+#endif
+ const LilvPluginClass *cls = lilv_plugin_get_class(plugin);
+ const LilvNode *ncuri = lilv_plugin_class_get_uri(cls);
+ const char *clsname = lilv_node_as_uri(ncuri);
+ bool isSynth = false;
+#ifdef DEBUG_LV2
+ std::cerr << "Plugin class: " << clsname << std::endl;
+#endif
+
+ if(strcmp(clsname, LV2_INSTRUMENT_CLASS) == 0)
+ {
+ isSynth = true;
+ }
+
+#ifdef DEBUG_LV2
+
+ if(isSynth)
+ {
+ std::cerr << "Plugin is synth" << std::endl;
+ }
+
+#endif
+
+#ifdef DEBUG_LV2
+ std::cerr << "\tRequired features (by uri):" << std::endl;
+#endif
+ LilvNodes *fts = lilv_plugin_get_required_features(plugin);
+ LilvIter *nit = lilv_nodes_begin(fts);
+
+ while(true)
+ {
+ if(lilv_nodes_is_end(fts, nit))
+ {
+ break;
+ }
+
+ const LilvNode *fnode = lilv_nodes_get(fts, nit);
+ const char *uri = lilv_node_as_uri(fnode);
+ bool isSupported = (supportedFeatures.find(uri) != supportedFeatures.end());
+#ifdef DEBUG_LV2
+ std::cerr << "\t - " << uri << " (" << (isSupported ? "supported" : "not supported") << ")" << std::endl;
+#endif
+
+ if(!isSupported)
+ {
+ shouldLoad = false;
+ }
+
+ nit = lilv_nodes_next(fts, nit);
+
+ }
+
+ lilv_nodes_free(fts);
+
+
+
+ //if (shouldLoad && isSynth)
+ if(shouldLoad) //load all plugins for now, not only synths
+ {
+ QFileInfo fi(lfp);
+ QString name = QString(pluginName) + QString(" LV2");
+ QString label = QString(pluginUri) + QString("_LV2");
+ // Make sure it doesn't already exist.
+ std::vector<Synth *>::iterator is;
+
+ for(is = MusEGlobal::synthis.begin(); is != MusEGlobal::synthis.end(); ++is)
+ {
+ Synth *s = *is;
+
+ if(s->name() == label && s->baseName() == fi.completeBaseName())
+ {
+ break;
+ }
+ }
+
+ if(is == MusEGlobal::synthis.end())
+ {
+ LV2Synth *s = new LV2Synth(fi, name, name, plugin, isSynth);
+ if(isSynth)
+ MusEGlobal::synthis.push_back(s);
+ else
+ synthsToFree.push_back(s);
+
+ if(s->inPorts() > 0 && s->outPorts() > 0) // insert to plugin list
+ {
+ MusEGlobal::plugins.push_back(new LV2PluginWrapper(s));
+
+ }
+
+ }
+ }
+ }
+
+ if(nameNode != NULL)
+ {
+ lilv_node_free(nameNode);
+ }
+
+ pit = lilv_plugins_next(plugins, pit);
+ }
+
+}
+
+void deinitLV2()
+{
+ for(size_t i = 0; i < synthsToFree.size(); i++)
+ {
+ delete synthsToFree [i];
+ }
+ free(lilvWorld);
+}
+
+LV2Synth::LV2Synth(const QFileInfo &fi, QString label, QString name, const LilvPlugin *_plugin, bool isSynth)
+ : Synth(fi, label, name, QString(""), QString("")),
+ _handle(_plugin), _isSynth(isSynth)
+{
+
+ //fake id for LV2PluginWrapper functionality
+ _uniqueID = uniqueID++;
+
+ _midi_event_id = uridBiMap.map(LV2_MIDI__MidiEvent);
+
+ //prepare features and options arrays
+ LV2_Options_Option _tmpl_options [] =
+ {
+ {LV2_OPTIONS_INSTANCE, 0, uridBiMap.map(LV2_P_SAMPLE_RATE), sizeof(int32_t), uridBiMap.map(LV2_ATOM__Int), &MusEGlobal::sampleRate},
+ {LV2_OPTIONS_INSTANCE, 0, uridBiMap.map(LV2_P_MIN_BLKLEN), sizeof(int32_t), uridBiMap.map(LV2_ATOM__Int), &MusEGlobal::segmentSize},
+ {LV2_OPTIONS_INSTANCE, 0, uridBiMap.map(LV2_P_MAX_BLKLEN), sizeof(int32_t), uridBiMap.map(LV2_ATOM__Int), &MusEGlobal::segmentSize},
+ {LV2_OPTIONS_INSTANCE, 0, uridBiMap.map(LV2_P_SEQ_SIZE), sizeof(int32_t), uridBiMap.map(LV2_ATOM__Int), &MusEGlobal::segmentSize},
+ {LV2_OPTIONS_INSTANCE, 0, 0, 0, 0, NULL}
+
+ };
+
+ _options = new LV2_Options_Option[SIZEOF_ARRAY(_tmpl_options)]; // last option is NULLs
+
+ for(uint32_t i = 0; i < SIZEOF_ARRAY(_tmpl_options); i++)
+ {
+ _options [i] = _tmpl_options [i];
+ }
+
+ _features = new LV2_Feature[SIZEOF_ARRAY(lv2Features)];
+ _ppfeatures = new LV2_Feature *[SIZEOF_ARRAY(lv2Features) + 1];
+ uint32_t i;
+
+ for(i = 0; i < SIZEOF_ARRAY(lv2Features); i++)
+ {
+ _features [i] = lv2Features [i];
+
+ if(_features [i].URI == NULL)
+ {
+ break;
+ }
+
+ if(std::string(LV2_F_URID_MAP) == _features [i].URI)
+ {
+ (reinterpret_cast<LV2_URID_Map *>(_features [i].data))->handle = this;
+ }
+ else if(std::string(LV2_F_URID_UNMAP) == _features [i].URI)
+ {
+ (reinterpret_cast<LV2_URID_Unmap *>(_features [i].data))->handle = this;
+ }
+ else if(std::string(LV2_F_URI_MAP) == _features [i].URI)
+ {
+ (reinterpret_cast<LV2_URI_Map_Feature *>(_features [i].data))->callback_data = this;
+ }
+ else if(std::string(LV2_F_OPTIONS) == _features [i].URI)
+ {
+ _features [i].data = _options;
+ }
+
+ _ppfeatures [i] = &_features [i];
+ }
+
+ _ppfeatures [i] = 0;
+
+ //enum plugin ports;
+ uint32_t numPorts = lilv_plugin_get_num_ports(_handle);
+
+ for(uint32_t i = 0; i < numPorts; i++)
+ {
+ const LilvPort *_port = lilv_plugin_get_port_by_index(_handle, i);
+ LilvNode *_nPname = lilv_port_get_name(_handle, _port);
+ std::string _portName;
+
+ if(_nPname != 0)
+ {
+ _portName = lilv_node_as_string(_nPname);
+ }
+
+ const bool optional = lilv_port_has_property(_handle, _port, lv2CacheNodes.lv2_connectionOptional);
+
+ LV2_MIDI_PORTS *mPorts = &_midiOutPorts;
+ LV2_CONTROL_PORTS *cPorts = &_controlOutPorts;
+ LV2_AUDIO_PORTS *aPorts = &_audioOutPorts;
+
+ if(lilv_port_is_a(_handle, _port, lv2CacheNodes.lv2_InputPort))
+ {
+ mPorts = &_midiInPorts;
+ cPorts = &_controlInPorts;
+ aPorts = &_audioInPorts;
+ }
+ else if(!lilv_port_is_a(_handle, _port, lv2CacheNodes.lv2_OutputPort))
+ {
+#ifdef DEBUG_LV2
+ std::cerr << "plugin has port with unknown direction - ignoring" << std::endl;
+#endif
+ continue;
+ }
+
+ if(lilv_port_is_a(_handle, _port, lv2CacheNodes.lv2_ControlPort))
+ {
+ cPorts->push_back(LV2ControlPort(_port, i, 0.0f, _portName));
+ //lilv_instance_connect_port(_handle, i, &_PluginControls [i]);
+
+ }
+ else if(lilv_port_is_a(_handle, _port, lv2CacheNodes.lv2_AudioPort))
+ {
+ aPorts->push_back(LV2AudioPort(_port, i, NULL, _portName));
+ }
+ else if(lilv_port_is_a(_handle, _port, lv2CacheNodes.ev_EventPort))
+ {
+
+ mPorts->push_back(LV2MidiPort(_port, i, _portName, true /* old api is on */, NULL));
+ //lilv_instance_connect_port(_handle, i, NULL);
+ }
+ else if(lilv_port_is_a(_handle, _port, lv2CacheNodes.atom_AtomPort))
+ {
+ mPorts->push_back(LV2MidiPort(_port, i, _portName, false /* old api is off */, NULL));
+ //lilv_instance_connect_port(_handle, i, NULL);
+ }
+ else if(!optional)
+ {
+#ifdef DEBUG_LV2
+ std::cerr << "plugin has port with unknown type - ignoring" << std::endl;
+#endif
+ }
+
+
+
+ }
+
+}
+
+LV2Synth::~LV2Synth()
+{
+ if(_ppfeatures)
+ {
+ delete [] _ppfeatures;
+ _ppfeatures = NULL;
+ }
+
+ if(_features)
+ {
+ delete [] _features;
+ _features = NULL;
+ }
+
+ if(_options)
+ {
+ delete [] _options;
+ _options = NULL;
+ }
+
+}
+
+
+SynthIF *LV2Synth::createSIF(SynthI *synthi)
+{
+ ++_instances;
+ LV2SynthIF *sif = new LV2SynthIF(synthi);
+
+ if(!sif->init(this))
+ {
+ delete sif;
+ sif = NULL;
+ }
+
+ return sif;
+}
+
+LV2_URID LV2Synth::mapUrid(const char *uri)
+{
+ return uridBiMap.map(uri);
+}
+
+const char *LV2Synth::unmapUrid(LV2_URID id)
+{
+ return uridBiMap.unmap(id);
+}
+
+
+LV2SynthIF::~LV2SynthIF()
+{
+ if(_handle)
+ {
+ lilv_instance_free(_handle);
+ _handle = NULL;
+ }
+
+ LV2_AUDIO_PORTS::iterator _itA = _audioInPorts.begin();
+
+ for(; _itA != _audioInPorts.end(); _itA++)
+ {
+ free((*_itA).buffer);
+ }
+
+ _itA = _audioOutPorts.begin();
+
+ for(; _itA != _audioOutPorts.end(); _itA++)
+ {
+ free((*_itA).buffer);
+ }
+
+ if(_audioInBuffers)
+ {
+ delete [] _audioInBuffers;
+ _audioInBuffers = NULL;
+ }
+
+ if(_audioOutBuffers)
+ {
+ delete [] _audioOutBuffers;
+ _audioOutBuffers = NULL;
+ }
+
+ if(_PluginControls)
+ {
+ delete _PluginControls;
+ _PluginControls = NULL;
+ }
+
+ if(_midiEvent)
+ {
+ snd_midi_event_free(_midiEvent);
+ }
+
+
+
+
+}
+
+LV2SynthIF::LV2SynthIF(SynthI *s): SynthIF(s)
+{
+ _synth = NULL;
+ _handle = NULL;
+ _audioInBuffers = NULL;
+ _audioOutBuffers = NULL;
+ _hasGui = false;
+ _inports = 0;
+ _outports = 0;
+ _controls = NULL;
+ _controlsOut = NULL;
+ _PluginControls = NULL;
+ _midiEvent = NULL;
+}
+
+bool LV2SynthIF::init(LV2Synth *s)
+{
+ _synth = s;
+ _handle = lilv_plugin_instantiate(_synth->_handle, (double)MusEGlobal::sampleRate, _synth->_ppfeatures);
+
+ if(_handle == NULL)
+ {
+ return false;
+ }
+
+ if(snd_midi_event_new(MusEGlobal::segmentSize * 10, &_midiEvent) != 0)
+ {
+ return false;
+ }
+
+ snd_midi_event_no_status(_midiEvent, 1);
+
+ uint32_t numPorts = lilv_plugin_get_num_ports(_synth->_handle);
+ _PluginControls = new float [numPorts];
+ lilv_plugin_get_port_ranges_float(_synth->_handle, NULL, NULL, _PluginControls);
+
+ _midiInPorts = s->_midiInPorts;
+ _midiOutPorts = s->_midiOutPorts;
+ _audioInPorts = s->_audioInPorts;
+ _audioOutPorts = s->_audioOutPorts;
+ _controlInPorts = s->_controlInPorts;
+ _controlOutPorts = s->_controlOutPorts;
+
+ //connect midi and control ports
+ for(size_t i = 0; i < _midiInPorts.size(); i++)
+ {
+ LV2EvBuf *buffer = new LV2EvBuf(MusEGlobal::segmentSize * 12,
+ _midiInPorts [i].old_api ? LV2EvBuf::LV2_EVBUF_EVENT : LV2EvBuf::LV2_EVBUF_ATOM,
+ _synth->mapUrid(lilv_node_as_string(lv2CacheNodes.atom_Chunk)),
+ _synth->mapUrid(lilv_node_as_string(lv2CacheNodes.atom_Sequence))
+ );
+ _midiInPorts [i].buffer = buffer;
+ lilv_instance_connect_port(_handle, _midiInPorts [i].index, (void *)buffer->lv2_evbuf_get_buffer());
+ }
+
+ for(size_t i = 0; i < _midiOutPorts.size(); i++)
+ {
+ LV2EvBuf *buffer = new LV2EvBuf(MusEGlobal::segmentSize * 12,
+ _midiOutPorts [i].old_api ? LV2EvBuf::LV2_EVBUF_EVENT : LV2EvBuf::LV2_EVBUF_ATOM,
+ _synth->mapUrid(lilv_node_as_string(lv2CacheNodes.atom_Chunk)),
+ _synth->mapUrid(lilv_node_as_string(lv2CacheNodes.atom_Sequence))
+ );
+ _midiOutPorts [i].buffer = buffer;
+ lilv_instance_connect_port(_handle, _midiOutPorts [i].index, (void *)buffer->lv2_evbuf_get_buffer());
+ }
+
+ for(size_t i = 0; i < _controlInPorts.size(); i++)
+ {
+ uint32_t idx = _controlInPorts [i].index;
+ lilv_instance_connect_port(_handle, idx, &_PluginControls[idx]);
+ }
+
+ for(size_t i = 0; i < _controlOutPorts.size(); i++)
+ {
+ uint32_t idx = _controlOutPorts [i].index;
+ lilv_instance_connect_port(_handle, idx, &_PluginControls[idx]);
+ }
+
+
+ int rv = posix_memalign((void **)&_audioInSilenceBuf, 16, sizeof(float) * MusEGlobal::segmentSize);
+
+ if(rv != 0)
+ {
+ fprintf(stderr, "ERROR: LV2SynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
+ abort();
+ }
+
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ {
+ _audioInSilenceBuf[q] = MusEGlobal::denormalBias;
+ }
+ }
+ else
+ {
+ memset(_audioInSilenceBuf, 0, sizeof(float) * MusEGlobal::segmentSize);
+ }
+
+ //cache number of ports
+ _inports = _audioInPorts.size();
+ _outports = _audioOutPorts.size();
+
+
+ if(_inports > 0)
+ {
+ _audioInBuffers = new float*[_inports];
+
+ for(int i = 0; i < _inports; i++)
+ {
+ int rv = posix_memalign((void **)&_audioInBuffers [i], 16, sizeof(float) * MusEGlobal::segmentSize);
+
+ if(rv != 0)
+ {
+ fprintf(stderr, "ERROR: LV2SynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
+ abort();
+ }
+
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ {
+ _audioInBuffers [i][q] = MusEGlobal::denormalBias;
+ }
+ }
+ else
+ {
+ memset(_audioInBuffers [i], 0, sizeof(float) * MusEGlobal::segmentSize);
+ }
+
+ _iUsedIdx.push_back(false);
+
+ _audioInPorts [i].buffer = _audioInBuffers [i];
+ lilv_instance_connect_port(_handle, _audioInPorts [i].index, _audioInBuffers [i]);
+ }
+ }
+
+ if(_outports > 0)
+ {
+ _audioOutBuffers = new float*[_outports];
+
+ for(int i = 0; i < _outports; i++)
+ {
+ int rv = posix_memalign((void **)&_audioOutBuffers [i], 16, sizeof(float) * MusEGlobal::segmentSize);
+
+ if(rv != 0)
+ {
+ fprintf(stderr, "ERROR: LV2SynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
+ abort();
+ }
+
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ {
+ _audioOutBuffers [i][q] = MusEGlobal::denormalBias;
+ }
+ }
+ else
+ {
+ memset(_audioOutBuffers [i], 0, sizeof(float) * MusEGlobal::segmentSize);
+ }
+
+ _audioOutPorts [i].buffer = _audioOutBuffers [i];
+ lilv_instance_connect_port(_handle, _audioOutPorts [i].index, _audioOutBuffers [i]);
+ }
+ }
+
+ activate();
+ _hasGui = false;
+
+ return true;
+
+}
+
+int LV2SynthIF::channels() const
+{
+ return (_outports) > MAX_CHANNELS ? MAX_CHANNELS : (_outports) ;
+
+}
+
+int LV2SynthIF::totalInChannels() const
+{
+ return _inports;
+}
+
+int LV2SynthIF::totalOutChannels() const
+{
+ return _outports;
+}
+
+void LV2SynthIF::activate()
+{
+ if(_handle)
+ {
+ lilv_instance_activate(_handle);
+ }
+}
+
+
+void LV2SynthIF::deactivate()
+{
+ if(_handle)
+ {
+ lilv_instance_deactivate(_handle);
+ }
+
+}
+
+void LV2SynthIF::deactivate3()
+{
+ deactivate();
+}
+
+int LV2SynthIF::eventsPending() const
+{
+ //TODO: what's this?
+ return 0;
+}
+
+int LV2SynthIF::getControllerInfo(int , const char **, int *, int *, int *, int *)
+{
+ //TODO: add controller supported
+ return 0;
+
+}
+
+bool LV2SynthIF::processEvent(const MidiPlayEvent &e, snd_seq_event_t *event)
+{
+
+ int chn = e.channel();
+ int a = e.dataA();
+ int b = e.dataB();
+
+ int len = e.len();
+ char ca[len + 2];
+
+ ca[0] = 0xF0;
+ memcpy(ca + 1, (const char *)e.data(), len);
+ ca[len + 1] = 0xF7;
+
+ len += 2;
+
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::processEvent midi event type:%d chn:%d a:%d b:%d\n", e.type(), chn, a, b);
+#endif
+
+ switch(e.type())
+ {
+ case ME_NOTEON:
+#ifdef DSSI_DEBUG
+ fprintf(stderr, "LV2SynthIF::processEvent midi event is ME_NOTEON\n");
+#endif
+
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
+
+ if(b)
+ {
+ snd_seq_ev_set_noteon(event, chn, a, b);
+ }
+ else
+ {
+ snd_seq_ev_set_noteoff(event, chn, a, 0);
+ }
+
+ break;
+
+ case ME_NOTEOFF:
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::processEvent midi event is ME_NOTEOFF\n");
+#endif
+
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
+ snd_seq_ev_set_noteoff(event, chn, a, 0);
+ break;
+
+ case ME_PROGRAM:
+ {
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::processEvent midi event is ME_PROGRAM\n");
+#endif
+
+ int bank = (a >> 8) & 0xff;
+ int prog = a & 0xff;
+ synti->_curBankH = 0;
+ synti->_curBankL = bank;
+ synti->_curProgram = prog;
+ // Event pointer not filled. Return false.
+ return false;
+ }
+ break;
+
+ case ME_CONTROLLER:
+ {
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::processEvent midi event is ME_CONTROLLER\n");
+#endif
+
+ if((a == 0) || (a == 32))
+ {
+ return false;
+ }
+
+ if(a == CTRL_PROGRAM)
+ {
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_PROGRAM\n");
+#endif
+
+ int bank = (b >> 8) & 0xff;
+ int prog = b & 0xff;
+
+ synti->_curBankH = 0;
+ synti->_curBankL = bank;
+ synti->_curProgram = prog;
+
+ // Event pointer not filled. Return false.
+ return false;
+ }
+
+ if(a == CTRL_PITCH)
+ {
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_PITCH\n");
+#endif
+
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
+ snd_seq_ev_set_pitchbend(event, chn, b);
+ // Event pointer filled. Return true.
+ return true;
+ }
+
+ if(a == CTRL_AFTERTOUCH)
+ {
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_AFTERTOUCH\n");
+#endif
+
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
+ snd_seq_ev_set_chanpress(event, chn, b);
+ // Event pointer filled. Return true.
+ return true;
+ }
+
+ if((a | 0xff) == CTRL_POLYAFTER)
+ {
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_POLYAFTER\n");
+#endif
+
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
+ snd_seq_ev_set_keypress(event, chn, a & 0x7f, b & 0x7f);
+ // Event pointer filled. Return true.
+ return true;
+ }
+
+
+ // Since we absorbed the message as a ladspa control change, return false - the event is not filled.
+ return false;
+ }
+ break;
+
+ case ME_PITCHBEND:
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
+ snd_seq_ev_set_pitchbend(event, chn, a);
+ break;
+
+ case ME_AFTERTOUCH:
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
+ snd_seq_ev_set_chanpress(event, chn, a);
+ break;
+
+ case ME_POLYAFTER:
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
+ snd_seq_ev_set_keypress(event, chn, a & 0x7f, b & 0x7f);
+ break;
+
+ default:
+ if(MusEGlobal::debugMsg)
+ {
+ fprintf(stderr, "LV2SynthIF::processEvent midi event unknown type:%d\n", e.type());
+ }
+
+ // Event not filled.
+ return false;
+ break;
+ }
+
+ return true;
+
+}
+
+
+iMPEvent LV2SynthIF::getData(MidiPort *, MPEventList *el, iMPEvent start_event, unsigned int pos, int ports, unsigned int nframes, float **buffer)
+{
+ // We may not be using ev_buf_sz all at once - this will be just the maximum.
+ const unsigned long ev_buf_sz = el->size() + synti->eventFifo.getSize();
+ snd_seq_event_t events[ev_buf_sz];
+
+ const int frameOffset = MusEGlobal::audio->getFrameOffset();
+ //const unsigned long syncFrame = MusEGlobal::audio->curSyncFrame();
+ // All ports must be connected to something!
+ //const unsigned long nop = ((unsigned long) ports) > _synth->outPorts() ? _synth->outPorts() : ((unsigned long) ports);
+ //const bool usefixedrate = false;
+ //const unsigned long min_per = (usefixedrate || MusEGlobal::config.minControlProcessPeriod > nframes) ? nframes : MusEGlobal::config.minControlProcessPeriod;
+ //const unsigned long min_per_mask = min_per - 1; // min_per must be power of 2
+
+ unsigned long sample = 0;
+ AudioTrack *atrack = track();
+
+ if(ports != 0)
+ {
+
+ if(!atrack->noInRoute())
+ {
+ RouteList *irl = atrack->inRoutes();
+
+ for(iRoute i = irl->begin(); i != irl->end(); i++)
+ {
+ if(!i->track->isMidiTrack())
+ {
+ const int ch = i->channel == -1 ? 0 : i->channel;
+ const int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
+ const int chs = i->channels == -1 ? 0 : i->channels;
+ assert(remch <= _inports);
+
+ if((unsigned)ch < _inports && (unsigned)(ch + chs) <= _inports)
+ {
+ const bool u1 = _iUsedIdx[remch];
+
+ if(chs >= 2)
+ {
+ const bool u2 = _iUsedIdx[remch + 1];
+
+ if(u1 && u2)
+ {
+ ((AudioTrack *)i->track)->addData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
+ }
+ else if(!u1 && !u2)
+ {
+ ((AudioTrack *)i->track)->copyData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
+ }
+ else
+ {
+ if(u1)
+ {
+ ((AudioTrack *)i->track)->addData(pos, 1, ch, 1, nframes, &_audioInBuffers[remch]);
+ }
+ else
+ {
+ ((AudioTrack *)i->track)->copyData(pos, 1, ch, 1, nframes, &_audioInBuffers[remch]);
+ }
+
+ if(u2)
+ {
+ ((AudioTrack *)i->track)->addData(pos, 1, ch + 1, 1, nframes, &_audioInBuffers[remch + 1]);
+ }
+ else
+ {
+ ((AudioTrack *)i->track)->copyData(pos, 1, ch + 1, 1, nframes, &_audioInBuffers[remch + 1]);
+ }
+ }
+ }
+ else
+ {
+ if(u1)
+ {
+ ((AudioTrack *)i->track)->addData(pos, 1, ch, -1, nframes, &_audioInBuffers[remch]);
+ }
+ else
+ {
+ ((AudioTrack *)i->track)->copyData(pos, 1, ch, -1, nframes, &_audioInBuffers[remch]);
+ }
+ }
+
+ const int h = remch + chs;
+
+ for(int j = remch; j < h; ++j)
+ {
+ _iUsedIdx[j] = true;
+ }
+ }
+
+ }
+ }
+ }
+
+
+ }
+
+
+ for(size_t j = 0; j < _midiInPorts.size(); j++)
+ {
+ _midiInPorts [j].buffer->lv2_evbuf_reset(true);
+ }
+
+ for(size_t j = 0; j < _midiOutPorts.size(); j++)
+ {
+ _midiOutPorts [j].buffer->lv2_evbuf_reset(false);
+ }
+
+ int cur_slice = 0;
+
+ while(sample < nframes)
+ {
+ unsigned long nsamp = nframes - sample;
+ //const unsigned long slice_frame = pos + sample;
+
+
+ //bool found = false;
+ //unsigned long frame = 0;
+ //unsigned long index = 0;
+ //unsigned long evframe;
+
+
+ if(sample + nsamp > nframes) // Safety check.
+ {
+ nsamp = nframes - sample;
+ }
+
+ // TODO: Don't allow zero-length runs. This could/should be checked in the control loop instead.
+ // Note this means it is still possible to get stuck in the top loop (at least for a while).
+ if(nsamp != 0)
+ {
+ unsigned long nevents = 0;
+
+ if(ports != 0) // Don't bother if not 'running'.
+ {
+ // Process event list events...
+ for(; start_event != el->end(); ++start_event)
+ {
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::getData eventlist event time:%d pos:%u sample:%lu nsamp:%lu frameOffset:%d\n", start_event->time(), pos, sample, nsamp, frameOffset);
+#endif
+
+ if(start_event->time() >= (pos + sample + nsamp + frameOffset)) // frameOffset? Test again...
+ {
+#ifdef LV2_DEBUG
+ fprintf(stderr, " event is for future:%lu, breaking loop now\n", start_event->time() - frameOffset - pos - sample);
+#endif
+ break;
+ }
+
+ // Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values.
+ // Same code as in MidiPort::sendEvent()
+ if(synti->midiPort() != -1)
+ {
+ MidiPort *mp = &MusEGlobal::midiPorts[synti->midiPort()];
+
+ if(start_event->type() == ME_CONTROLLER)
+ {
+ int da = start_event->dataA();
+ int db = start_event->dataB();
+ db = mp->limitValToInstrCtlRange(da, db);
+
+ if(!mp->setHwCtrlState(start_event->channel(), da, db))
+ {
+ continue;
+ }
+ }
+ else if(start_event->type() == ME_PITCHBEND)
+ {
+ int da = mp->limitValToInstrCtlRange(CTRL_PITCH, start_event->dataA());
+
+ if(!mp->setHwCtrlState(start_event->channel(), CTRL_PITCH, da))
+ {
+ continue;
+ }
+ }
+ else if(start_event->type() == ME_AFTERTOUCH)
+ {
+ int da = mp->limitValToInstrCtlRange(CTRL_AFTERTOUCH, start_event->dataA());
+
+ if(!mp->setHwCtrlState(start_event->channel(), CTRL_AFTERTOUCH, da))
+ {
+ continue;
+ }
+ }
+ else if(start_event->type() == ME_POLYAFTER)
+ {
+ int ctl = (CTRL_POLYAFTER & ~0xff) | (start_event->dataA() & 0x7f);
+ int db = mp->limitValToInstrCtlRange(ctl, start_event->dataB());
+
+ if(!mp->setHwCtrlState(start_event->channel(), ctl , db))
+ {
+ continue;
+ }
+ }
+ else if(start_event->type() == ME_PROGRAM)
+ {
+ if(!mp->setHwCtrlState(start_event->channel(), CTRL_PROGRAM, start_event->dataA()))
+ {
+ continue;
+ }
+ }
+ }
+
+ // Returns false if the event was not filled. It was handled, but some other way.
+ if(processEvent(*start_event, &events[nevents]))
+ {
+ // Time-stamp the event.
+ int ft = start_event->time() - frameOffset - pos - sample;
+
+ if(ft < 0)
+ {
+ ft = 0;
+ }
+
+ if(ft >= int(nsamp))
+ {
+ fprintf(stderr, "LV2SynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", start_event->time(), pos, frameOffset, ft, sample, nsamp);
+ ft = nsamp - 1;
+ }
+
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::getData eventlist: ft:%d current nevents:%lu\n", ft, nevents);
+#endif
+
+ // "Each event is timestamped relative to the start of the block, (mis)using the ALSA "tick time" field as a frame count.
+ // The host is responsible for ensuring that events with differing timestamps are already ordered by time." - From dssi.h
+ events[nevents].time.tick = ft;
+
+ ++nevents;
+ }
+ }
+ }
+
+ // Now process putEvent events...
+ while(!synti->eventFifo.isEmpty())
+ {
+ MidiPlayEvent e = synti->eventFifo.peek();
+
+#ifdef LV2_DEBUG
+ fprintf(stderr, "LV2SynthIF::getData eventFifo event time:%d\n", e.time());
+#endif
+
+ if(e.time() >= (pos + sample + nsamp + frameOffset))
+ {
+ break;
+ }
+
+ synti->eventFifo.remove(); // Done with ring buffer's event. Remove it.
+
+ if(ports != 0) // Don't bother if not 'running'.
+ {
+ // Returns false if the event was not filled. It was handled, but some other way.
+ if(processEvent(e, &events[nevents]))
+ {
+ // Time-stamp the event.
+ int ft = e.time() - frameOffset - pos - sample;
+
+ if(ft < 0)
+ {
+ ft = 0;
+ }
+
+ if(ft >= int(nsamp))
+ {
+ fprintf(stderr, "LV2SynthIF::getData: eventFifo event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", e.time(), pos, frameOffset, ft, sample, nsamp);
+ ft = nsamp - 1;
+ }
+
+ // "Each event is timestamped relative to the start of the block, (mis)using the ALSA "tick time" field as a frame count.
+ // The host is responsible for ensuring that events with differing timestamps are already ordered by time." - From dssi.h
+ events[nevents].time.tick = ft;
+
+ ++nevents;
+ }
+ }
+ }
+
+ if(ports != 0) // Don't bother if not 'running'.
+ {
+ if(_midiInPorts.size() > 0)
+ {
+ //convert snd_seq_event_t[] to raw midi data
+ snd_midi_event_reset_decode(_midiEvent);
+ uint8_t resMidi [1024];
+ LV2EvBuf *rawMidiBuffer = _midiInPorts [0].buffer;
+ LV2EvBuf::LV2_Evbuf_Iterator iter = rawMidiBuffer->lv2_evbuf_begin();
+
+ for(int i = 0; i < nevents; i++)
+ {
+ uint32_t stamp = events[i].time.tick;
+ uint32_t size = snd_midi_event_decode(_midiEvent, resMidi, sizeof(resMidi), &events [i]);
+ rawMidiBuffer->lv2_evbuf_write(iter,
+ stamp,
+ 0,
+ _synth->_midi_event_id,
+ size, resMidi);
+
+
+ }
+ }
+
+ //connect ports
+ for(int j = 0; j < _inports; ++j)
+ {
+ if(_iUsedIdx [j])
+ {
+ lilv_instance_connect_port(_handle, _audioInPorts [j].index, _audioInBuffers [j] + sample);
+ }
+ else
+ {
+ lilv_instance_connect_port(_handle, _audioInPorts [j].index, _audioInSilenceBuf + sample);
+ }
+
+ _iUsedIdx[j] = false;
+ }
+
+ for(int j = 0; j < ports; ++j)
+ {
+ lilv_instance_connect_port(_handle, _audioOutPorts [j].index, buffer [j] + sample);
+ }
+
+ for(int j = ports; j < _outports; j++)
+ {
+ lilv_instance_connect_port(_handle, _audioOutPorts [j].index, _audioOutBuffers [j] + sample);
+ }
+
+ lilv_instance_run(_handle, nsamp);
+
+
+ }
+
+ sample += nsamp;
+ }
+
+ ++cur_slice; // Slice is done. Moving on to any next slice now...
+ }
+
+
+
+
+ return start_event;
+}
+
+
+void LV2SynthIF::getGeometry(int *x, int *y, int *w, int *h) const
+{
+ *x = *y = *w = *h = 0;
+
+ if(_hasGui)
+ {
+
+ }
+
+ return;
+}
+
+void LV2SynthIF::getNativeGeometry(int *x, int *y, int *w, int *h) const
+{
+ *x = *y = *w = *h = 0;
+ return;
+}
+
+float LV2SynthIF::getParameter(long unsigned int) const
+{
+ //TODO: implement this
+ return .0f;
+}
+
+QString LV2SynthIF::getPatchName(int, int , bool) const
+{
+ //TODO: implement this
+ return "?";
+}
+
+void LV2SynthIF::guiHeartBeat()
+{
+
+}
+
+
+bool LV2SynthIF::guiVisible() const
+{
+ //TODO: implement this
+ return false;
+}
+
+
+bool LV2SynthIF::hasGui() const
+{
+ return _hasGui;
+}
+
+bool LV2SynthIF::hasNativeGui() const
+{
+ return _hasGui;
+}
+
+bool LV2SynthIF::initGui()
+{
+ //TODO: implement this
+ return true;
+}
+
+bool LV2SynthIF::nativeGuiVisible() const
+{
+ //TODO: implement this
+ return false;
+}
+
+void LV2SynthIF::populatePatchPopup(MusEGui::PopupMenu *menu, int, bool)
+{
+ //TODO: implement this
+ menu->clear();
+}
+
+void LV2SynthIF::preProcessAlways()
+{
+
+}
+
+bool LV2SynthIF::putEvent(const MidiPlayEvent &ev)
+{
+#ifdef DEBUG_LV2
+ fprintf(stderr, "LV2SynthIF::putEvent midi event time:%d chn:%d a:%d b:%d\n", ev.time(), ev.channel(), ev.dataA(), ev.dataB());
+#endif
+
+ if(MusEGlobal::midiOutputTrace)
+ {
+ ev.dump();
+ }
+
+ return synti->eventFifo.put(ev);
+}
+
+MidiPlayEvent LV2SynthIF::receiveEvent()
+{
+ return MidiPlayEvent();
+
+}
+
+void LV2SynthIF::setGeometry(int , int , int , int)
+{
+ //TODO: implement this
+
+}
+
+void LV2SynthIF::setNativeGeometry(int , int , int , int)
+{
+ //TODO: implement this
+
+}
+
+void LV2SynthIF::setParameter(long unsigned int idx, float value)
+{
+ addScheduledControlEvent(idx, value, MusEGlobal::audio->curFrame());
+}
+
+void LV2SynthIF::showGui(bool)
+{
+ //TODO: implement this
+}
+
+void LV2SynthIF::showNativeGui(bool)
+{
+ //TODO: implement this
+}
+
+void LV2SynthIF::write(int , Xml &) const
+{
+ //TODO: implement this
+}
+
+LV2PluginWrapper::LV2PluginWrapper(LV2Synth *s)
+{
+ _synth = s;
+
+ _fakeLd.Label = _synth->name().toUtf8().constData();
+ _fakeLd.Name = _synth->name().toUtf8().constData();
+ _fakeLd.UniqueID = _synth->_uniqueID;
+ _fakeLd.Maker = _synth->maker().toUtf8().constData();
+ _fakeLd.Copyright = _synth->version().toUtf8().constData();
+ _isLV2Plugin = true;
+ _isLV2Synth = s->_isSynth;
+ int numPorts = _synth->_audioInPorts.size()
+ + _synth->_audioOutPorts.size()
+ + _synth->_controlInPorts.size()
+ + _synth->_controlOutPorts.size()
+ + _synth->_midiInPorts.size()
+ + _synth->_midiOutPorts.size();
+ _fakeLd.PortCount = numPorts;
+ _fakePds = new LADSPA_PortDescriptor [numPorts];
+ memset(_fakePds, 0, sizeof(int) * numPorts);
+
+ for(size_t i = 0; i < _synth->_audioInPorts.size(); i++)
+ {
+ _fakePds [_synth->_audioInPorts [i].index] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
+ }
+
+ for(size_t i = 0; i < _synth->_audioOutPorts.size(); i++)
+ {
+ _fakePds [_synth->_audioOutPorts [i].index] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
+ }
+
+ for(size_t i = 0; i < _synth->_controlInPorts.size(); i++)
+ {
+ _fakePds [_synth->_controlInPorts [i].index] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
+ }
+
+ for(size_t i = 0; i < _synth->_controlOutPorts.size(); i++)
+ {
+ _fakePds [_synth->_controlOutPorts [i].index] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL;
+ }
+
+ _PluginControlsDefault = new float [numPorts];
+ _PluginControlsMin = new float [numPorts];
+ _PluginControlsMax = new float [numPorts];
+ memset(_PluginControlsDefault, 0, sizeof(float));
+ memset(_PluginControlsMin, 0, sizeof(float));
+ memset(_PluginControlsMax, 0, sizeof(float));
+ lilv_plugin_get_port_ranges_float(_synth->_handle, _PluginControlsMin, _PluginControlsMax, _PluginControlsDefault);
+
+ _fakeLd.PortNames = NULL;
+ _fakeLd.PortRangeHints = NULL;
+ _fakeLd.PortDescriptors = _fakePds;
+ _fakeLd.Properties = 0;
+ plugin = &_fakeLd;
+ _isDssi = false;
+ _isDssiSynth = false;
+
+#ifdef DSSI_SUPPORT
+ dssi_descr = NULL;
+#endif
+
+ fi = _synth->info;
+ ladspa = NULL;
+ _handle = 0;
+ _references = 0;
+ _instNo = 0;
+ _label = _synth->name();
+ _name = _synth->name();
+ _uniqueID = plugin->UniqueID;
+ _maker = _synth->maker();
+ _copyright = _synth->version();
+
+ _portCount = plugin->PortCount;
+
+ _inports = 0;
+ _outports = 0;
+ _controlInPorts = 0;
+ _controlOutPorts = 0;
+
+ for(unsigned long k = 0; k < _portCount; ++k)
+ {
+ LADSPA_PortDescriptor pd = plugin->PortDescriptors[k];
+
+ if(pd & LADSPA_PORT_AUDIO)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ {
+ ++_inports;
+ }
+ else if(pd & LADSPA_PORT_OUTPUT)
+ {
+ ++_outports;
+ }
+ }
+ else if(pd & LADSPA_PORT_CONTROL)
+ {
+ if(pd & LADSPA_PORT_INPUT)
+ {
+ ++_controlInPorts;
+ }
+ else if(pd & LADSPA_PORT_OUTPUT)
+ {
+ ++_controlOutPorts;
+ }
+ }
+ }
+
+ _inPlaceCapable = !LADSPA_IS_INPLACE_BROKEN(plugin->Properties);
+
+
+
+}
+
+LV2PluginWrapper::~LV2PluginWrapper()
+{
+ delete [] _fakePds;
+ delete [] _PluginControlsDefault;
+ delete [] _PluginControlsMin;
+ delete [] _PluginControlsMax;
+}
+
+LADSPA_Handle LV2PluginWrapper::instantiate()
+{
+ LilvInstance *handle = lilv_plugin_instantiate(_synth->_handle, (double)MusEGlobal::sampleRate, _synth->_ppfeatures);
+ return (LADSPA_Handle)handle;
+
+}
+
+void LV2PluginWrapper::connectPort(LADSPA_Handle handle, long unsigned int port, float *value)
+{
+ lilv_instance_connect_port((LilvInstance *)handle, port, (void *)value);
+}
+
+}
+
+#else //LV2_SUPPORT
+namespace MusECore
+{
+void initLV2() {}
+}
+#endif
+
+
+
+
+
diff --git a/muse2/muse/lv2host.h b/muse2/muse/lv2host.h
new file mode 100644
index 0000000..88aefc2
--- /dev/null
+++ b/muse2/muse/lv2host.h
@@ -0,0 +1,618 @@
+//=============================================================================
+// MusE
+// Linux Music Editor
+//
+// lv2host.h
+// Copyright (C) 1999-2011 by Deryabin Andrew <andrewderya...@gmail.com>
+//
+// 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; 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; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//=============================================================================
+
+#ifndef __LV2HOST_H__
+#define __LV2HOST_H__
+
+#include "config.h"
+
+#ifdef LV2_SUPPORT
+
+#include "lilv/lilv.h"
+#include "lv2/lv2plug.in/ns/ext/options/options.h"
+#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
+#include "lv2/lv2plug.in/ns/ext/event/event.h"
+
+
+#include <vector>
+#include <map>
+#include <string>
+#include <utility>
+#include <QMutex>
+#include <assert.h>
+
+#include <alsa/asoundlib.h>
+#include "midictrl.h"
+#include "synth.h"
+#include "stringparam.h"
+
+#include "plugin.h"
+
+#endif
+
+namespace MusECore
+{
+
+#ifdef LV2_SUPPORT
+
+/* LV2EvBuf class is based of lv2_evbuf_* functions
+ * from jalv lv2 plugin host
+ *
+ * Copyright 2008-2012 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+class LV2EvBuf
+{
+
+public:
+
+ /**
+ Format of actual buffer.
+ */
+ typedef enum {
+ /**
+ An (old) ev:EventBuffer (LV2_Event_Buffer).
+ */
+ LV2_EVBUF_EVENT,
+
+ /**
+ A (new) atom:Sequence (LV2_Atom_Sequence).
+ */
+ LV2_EVBUF_ATOM
+ } LV2_Evbuf_Type;
+
+ typedef struct {
+ LV2_Evbuf_Type type;
+ uint32_t capacity;
+ uint32_t atom_Chunk;
+ uint32_t atom_Sequence;
+ union {
+ LV2_Event_Buffer event;
+ LV2_Atom_Sequence atom;
+ } buf;
+ } LV2_Evbuf;
+
+ /**
+ An iterator over an LV2_Evbuf.
+ */
+ class LV2_Evbuf_Iterator
+ {
+ private:
+ LV2EvBuf *lv2evbuf;
+
+ public:
+ uint32_t offset;
+ LV2_Evbuf_Iterator ( LV2EvBuf *a, uint32_t b ) : lv2evbuf ( a ), offset ( b ) {
+
+ }
+ bool
+ lv2_evbuf_is_valid () {
+ return offset < lv2evbuf->lv2_evbuf_get_size ();
+ }
+ LV2EvBuf *operator *() {
+ return lv2evbuf;
+ }
+ LV2_Evbuf_Iterator &operator++ () {
+ if ( !lv2_evbuf_is_valid () ) {
+ return *this;
+ }
+
+ LV2_Evbuf *_evbuf = lv2evbuf->evbuf;
+ uint32_t _offset = offset;
+ uint32_t _size;
+ switch ( _evbuf->type ) {
+ case LV2_EVBUF_EVENT:
+ _size = ( ( LV2_Event * ) ( _evbuf->buf.event.data + _offset ) )->size;
+ _offset += LV2EvBuf::lv2_evbuf_pad_size ( sizeof ( LV2_Event ) + _size );
+ break;
+ case LV2_EVBUF_ATOM:
+ _size = ( ( LV2_Atom_Event * )
+ ( ( char * ) LV2_ATOM_CONTENTS ( LV2_Atom_Sequence, &_evbuf->buf.atom )
+ + _offset ) )->body.size;
+ _offset += LV2EvBuf::lv2_evbuf_pad_size ( sizeof ( LV2_Atom_Event ) + _size );
+ break;
+ }
+ offset = _offset;
+ return *this;
+ }
+ LV2_Event *event() {
+ LV2_Event_Buffer *ebuf = &lv2evbuf->evbuf->buf.event;
+ return ( LV2_Event * ) ( ( char * ) ebuf->data + offset );
+ }
+
+ LV2_Atom_Event *aevent() {
+ LV2_Atom_Sequence *aseq = ( LV2_Atom_Sequence * ) &lv2evbuf->evbuf->buf.atom;
+ return ( LV2_Atom_Event * ) (
+ ( char * ) LV2_ATOM_CONTENTS ( LV2_Atom_Sequence, aseq )
+ + offset );
+ }
+ };
+
+ LV2_Evbuf *evbuf;
+
+ static inline uint32_t
+ lv2_evbuf_pad_size ( uint32_t size ) {
+ return ( size + 7 ) & ( ~7 );
+ }
+
+ LV2EvBuf ( uint32_t capacity,
+ LV2_Evbuf_Type type,
+ uint32_t atom_Chunk,
+ uint32_t atom_Sequence ) {
+
+ int rv = posix_memalign ( ( void ** ) &evbuf, 8, sizeof ( LV2_Evbuf ) + sizeof ( LV2_Atom_Sequence ) + capacity );
+
+ if ( rv != 0 ) {
+ fprintf ( stderr, "ERROR: LV2EvBuf::LV2EvBuf: posix_memalign returned error:%d. Aborting!\n", rv );
+ abort();
+ }
+ evbuf->capacity = capacity;
+ evbuf->atom_Chunk = atom_Chunk;
+ evbuf->atom_Sequence = atom_Sequence;
+ lv2_evbuf_set_type ( type );
+ lv2_evbuf_reset ( true );
+ }
+
+ ~LV2EvBuf() {
+ free ( evbuf );
+ }
+
+ void
+ lv2_evbuf_set_type ( LV2_Evbuf_Type type ) {
+ evbuf->type = type;
+ switch ( type ) {
+ case LV2_EVBUF_EVENT:
+ evbuf->buf.event.data = ( uint8_t * ) ( evbuf + 1 );
+ evbuf->buf.event.capacity = evbuf->capacity;
+ break;
+ case LV2_EVBUF_ATOM:
+ break;
+ }
+ lv2_evbuf_reset ( true );
+ }
+
+ void
+ lv2_evbuf_reset ( bool input ) {
+ switch ( evbuf->type ) {
+ case LV2_EVBUF_EVENT:
+ evbuf->buf.event.header_size = sizeof ( LV2_Event_Buffer );
+ evbuf->buf.event.stamp_type = LV2_EVENT_AUDIO_STAMP;
+ evbuf->buf.event.event_count = 0;
+ evbuf->buf.event.size = 0;
+ break;
+ case LV2_EVBUF_ATOM:
+ if ( input ) {
+ evbuf->buf.atom.atom.size = sizeof ( LV2_Atom_Sequence_Body );
+ evbuf->buf.atom.atom.type = evbuf->atom_Sequence;
+ } else {
+ evbuf->buf.atom.atom.size = evbuf->capacity;
+ evbuf->buf.atom.atom.type = evbuf->atom_Chunk;
+ }
+ }
+ }
+
+ uint32_t
+ lv2_evbuf_get_size () {
+ switch ( evbuf->type ) {
+ case LV2_EVBUF_EVENT:
+ return evbuf->buf.event.size;
+ case LV2_EVBUF_ATOM:
+ assert ( evbuf->buf.atom.atom.type != evbuf->atom_Sequence
+ || evbuf->buf.atom.atom.size >= sizeof ( LV2_Atom_Sequence_Body ) );
+ return evbuf->buf.atom.atom.type == evbuf->atom_Sequence
+ ? evbuf->buf.atom.atom.size - sizeof ( LV2_Atom_Sequence_Body )
+ : 0;
+ }
+ return 0;
+ }
+
+ void *
+ lv2_evbuf_get_buffer () {
+ switch ( evbuf->type ) {
+ case LV2_EVBUF_EVENT:
+ return &evbuf->buf.event;
+ case LV2_EVBUF_ATOM:
+ return &evbuf->buf.atom;
+ }
+ return NULL;
+ }
+
+ LV2_Evbuf_Iterator
+ lv2_evbuf_begin () {
+ LV2_Evbuf_Iterator iter ( this, 0 );
+ return iter;
+ }
+
+ LV2_Evbuf_Iterator
+ lv2_evbuf_end () {
+ const uint32_t size = lv2_evbuf_get_size ();
+ const LV2_Evbuf_Iterator iter ( this, lv2_evbuf_pad_size ( size ) );
+ return iter;
+ }
+
+ bool
+ lv2_evbuf_get ( LV2_Evbuf_Iterator &iter,
+ uint32_t *frames,
+ uint32_t *subframes,
+ uint32_t *type,
+ uint32_t *size,
+ uint8_t **data ) {
+ *frames = *subframes = *type = *size = 0;
+ *data = NULL;
+
+ if ( !iter.lv2_evbuf_is_valid() ) {
+ return false;
+ }
+
+ LV2_Event *ev;
+ LV2_Atom_Event *aev;
+ switch ( ( *iter )->evbuf->type ) {
+ case LV2_EVBUF_EVENT:
+ ev = iter.event();
+ *frames = ev->frames;
+ *subframes = ev->subframes;
+ *type = ev->type;
+ *size = ev->size;
+ *data = ( uint8_t * ) ev + sizeof ( LV2_Event );
+ break;
+ case LV2_EVBUF_ATOM:
+ aev = iter.aevent();
+ *frames = aev->time.frames;
+ *subframes = 0;
+ *type = aev->body.type;
+ *size = aev->body.size;
+ *data = ( uint8_t * ) LV2_ATOM_BODY ( &aev->body );
+ break;
+ }
+
+ return true;
+ }
+
+ bool
+ lv2_evbuf_write ( LV2_Evbuf_Iterator &iter,
+ uint32_t frames,
+ uint32_t subframes,
+ uint32_t type,
+ uint32_t size,
+ const uint8_t *data ) {
+ LV2_Event_Buffer *ebuf;
+ LV2_Event *ev;
+ LV2_Atom_Sequence *aseq;
+ LV2_Atom_Event *aev;
+ switch ( ( *iter )->evbuf->type ) {
+ case LV2_EVBUF_EVENT:
+ ebuf = & ( *iter )->evbuf->buf.event;
+ if ( ebuf->capacity - ebuf->size < sizeof ( LV2_Event ) + size ) {
+ return false;
+ }
+
+ ev = ( LV2_Event * ) ( ebuf->data + iter.offset );
+ ev->frames = frames;
+ ev->subframes = subframes;
+ ev->type = type;
+ ev->size = size;
+ memcpy ( ( uint8_t * ) ev + sizeof ( LV2_Event ), data, size );
+
+ size = lv2_evbuf_pad_size ( sizeof ( LV2_Event ) + size );
+ ebuf->size += size;
+ ebuf->event_count += 1;
+ iter.offset += size;
+ break;
+ case LV2_EVBUF_ATOM:
+ aseq = ( LV2_Atom_Sequence * ) & ( *iter )->evbuf->buf.atom;
+ if ( ( *iter )->evbuf->capacity - sizeof ( LV2_Atom ) - aseq->atom.size
+ < sizeof ( LV2_Atom_Event ) + size ) {
+ return false;
+ }
+
+ aev = ( LV2_Atom_Event * ) (
+ ( char * ) LV2_ATOM_CONTENTS ( LV2_Atom_Sequence, aseq )
+ + iter.offset );
+ aev->time.frames = frames;
+ aev->body.type = type;
+ aev->body.size = size;
+ memcpy ( LV2_ATOM_BODY ( &aev->body ), data, size );
+
+ size = lv2_evbuf_pad_size ( sizeof ( LV2_Atom_Event ) + size );
+ aseq->atom.size += size;
+ iter.offset += size;
+ break;
+ }
+
+ return true;
+ }
+
+
+};
+
+
+
+struct LV2MidiPort {
+ LV2MidiPort ( const LilvPort *_p, uint32_t _i, std::string _n, bool _f, LV2EvBuf *_b ) :
+ port ( _p ), index ( _i ), name ( _n ), old_api ( _f ), buffer ( _b ) {};
+ const LilvPort *port;
+ uint32_t index; //plugin real port index
+ std::string name;
+ bool old_api; //true for LV2_Event port
+ LV2EvBuf *buffer;
+ ~LV2MidiPort() {
+ std::cerr << "~LV2MidiPort()" << std::endl;
+ delete buffer;
+ }
+};
+
+struct LV2ControlPort {
+ LV2ControlPort ( const LilvPort *_p, uint32_t _i, float _c, std::string _n ) :
+ port ( _p ), index ( _i ), control ( _c ), name ( _n ) {};
+ const LilvPort *port;
+ uint32_t index; //plugin real port index
+ float control; //default control value
+ std::string name;
+};
+
+struct LV2AudioPort {
+ LV2AudioPort ( const LilvPort *_p, uint32_t _i, float *_b, std::string _n ) :
+ port ( _p ), index ( _i ), buffer ( _b ), name ( _n ) {};
+ const LilvPort *port;
+ uint32_t index; //plugin real port index
+ float *buffer; //audio buffer
+ std::string name;
+};
+
+typedef std::vector<LV2MidiPort> LV2_MIDI_PORTS;
+typedef std::vector<LV2ControlPort> LV2_CONTROL_PORTS;
+typedef std::vector<LV2AudioPort> LV2_AUDIO_PORTS;
+typedef std::map<std::string, uint32_t> LV2_SYNTH_URID_MAP;
+typedef std::map<uint32_t, std::string> LV2_SYNTH_URID_RMAP;
+
+class LV2UridBiMap
+{
+private:
+ LV2_SYNTH_URID_MAP _map;
+ LV2_SYNTH_URID_RMAP _rmap;
+ uint32_t nextId;
+ QMutex idLock;
+public:
+ LV2UridBiMap() : nextId ( 1 ) {};
+ LV2_URID map ( const char *uri ) {
+ std::pair<LV2_SYNTH_URID_MAP::iterator, bool> p;
+ uint32_t id;
+ idLock.lock();
+ p = _map.insert ( std::make_pair ( uri, nextId ) );
+ if ( p.second ) {
+ _rmap.insert ( std::make_pair ( nextId, uri ) );
+ nextId++;
+ }
+
+ id = p.first->second;
+ idLock.unlock();
+ return id;
+
+ };
+ const char *unmap ( uint32_t id ) {
+ LV2_SYNTH_URID_RMAP::iterator it = _rmap.find ( id );
+ if ( it != _rmap.end() ) {
+ return it->second.c_str();
+ }
+
+ return NULL;
+ }
+};
+
+
+class LV2SynthIF;
+
+class LV2Synth : public Synth
+{
+private:
+ const LilvPlugin *_handle;
+ LV2UridBiMap uridBiMap;
+ LV2_Feature *_features;
+ LV2_Feature **_ppfeatures;
+ LV2_Options_Option *_options;
+ bool _isSynth;
+ int _uniqueID;
+ uint32_t _midi_event_id;
+
+ //templates for LV2SynthIF and LV2PluginWrapper instantiation
+ LV2_MIDI_PORTS _midiInPorts;
+ LV2_MIDI_PORTS _midiOutPorts;
+ LV2_CONTROL_PORTS _controlInPorts;
+ LV2_CONTROL_PORTS _controlOutPorts;
+ LV2_AUDIO_PORTS _audioInPorts;
+ LV2_AUDIO_PORTS _audioOutPorts;
+
+public:
+ virtual Type synthType() const {
+ return LV2_SYNTH;
+ }
+ LV2Synth ( const QFileInfo &fi, QString label, QString name, const LilvPlugin *_plugin, bool isSynth );
+ virtual ~LV2Synth();
+ virtual SynthIF *createSIF ( SynthI * );
+
+ //own public functions
+ LV2_URID mapUrid ( const char *uri );
+ const char *unmapUrid ( LV2_URID id );
+ size_t inPorts() {
+ return _audioInPorts.size();
+ };
+ size_t outPorts() {
+ return _audioOutPorts.size();
+ };
+
+
+ friend class LV2SynthIF;
+ friend class LV2PluginWrapper;
+
+
+};
+
+class LV2SynthIF : public SynthIF
+{
+private:
+ LV2Synth *_synth;
+ LilvInstance *_handle;
+ LV2_MIDI_PORTS _midiInPorts;
+ LV2_MIDI_PORTS _midiOutPorts;
+ LV2_CONTROL_PORTS _controlInPorts;
+ LV2_CONTROL_PORTS _controlOutPorts;
+ LV2_AUDIO_PORTS _audioInPorts;
+ LV2_AUDIO_PORTS _audioOutPorts;
+ Port *_controls;
+ Port *_controlsOut;
+ float *_PluginControls;
+ bool _hasGui;
+ bool init ( LV2Synth *s );
+ int _inports;
+ int _outports;
+ float **_audioInBuffers;
+ float **_audioOutBuffers;
+ float *_audioInSilenceBuf; // Just all zeros all the time, so we don't have to clear for silence.
+ std::vector<unsigned long> _iUsedIdx; // During process, tells whether an audio input port was used by any input routes.
+ snd_midi_event_t *_midiEvent;
+ bool processEvent ( const MidiPlayEvent &, snd_seq_event_t * );
+public:
+ LV2SynthIF ( SynthI *s );
+ virtual ~LV2SynthIF();
+
+ //virtual methods from SynthIF
+ virtual bool initGui();
+ virtual void guiHeartBeat();
+ virtual bool guiVisible() const;
+ virtual void showGui ( bool v );
+ virtual bool hasGui() const;
+ virtual bool nativeGuiVisible() const;
+ virtual void showNativeGui ( bool v );
+ virtual bool hasNativeGui() const;
+ virtual void getGeometry ( int *, int *, int *, int * ) const;
+ virtual void setGeometry ( int, int, int, int );
+ virtual void getNativeGeometry ( int *, int *, int *, int * ) const;
+ virtual void setNativeGeometry ( int, int, int, int );
+ virtual void preProcessAlways();
+ virtual iMPEvent getData ( MidiPort *, MPEventList *, iMPEvent, unsigned pos, int ports, unsigned n, float **buffer );
+ virtual bool putEvent ( const MidiPlayEvent &ev );
+ virtual MidiPlayEvent receiveEvent();
+ virtual int eventsPending() const;
+
+ virtual int channels() const;
+ virtual int totalOutChannels() const;
+ virtual int totalInChannels() const;
+ void activate();
+ virtual void deactivate();
+ virtual void deactivate3();
+ virtual QString getPatchName ( int, int, bool ) const;
+ virtual void populatePatchPopup ( MusEGui::PopupMenu *, int, bool );
+ virtual void write ( int level, Xml &xml ) const;
+ virtual float getParameter ( unsigned long idx ) const;
+ virtual void setParameter ( unsigned long idx, float value );
+ virtual int getControllerInfo ( int id, const char **name, int *ctrl, int *min, int *max, int *initval );
+
+ friend class LV2Synth;
+ friend class LV2PluginWrapper;
+
+};
+
+class LV2PluginWrapper: public Plugin
+{
+private:
+ LV2Synth *_synth;
+ LADSPA_Descriptor _fakeLd;
+ LADSPA_PortDescriptor *_fakePds;
+ float *_PluginControlsDefault;
+ float *_PluginControlsMin;
+ float *_PluginControlsMax;
+public:
+ LV2PluginWrapper ( LV2Synth *s );
+ virtual ~LV2PluginWrapper();
+ virtual LADSPA_Handle instantiate();
+ virtual int incReferences ( int ref ) {
+ _synth->incInstances ( ref );
+ return _synth->instances();
+ }
+ virtual void activate ( LADSPA_Handle handle ) {
+ lilv_instance_activate ( ( LilvInstance * ) handle );
+ }
+ virtual void deactivate ( LADSPA_Handle handle ) {
+ lilv_instance_deactivate ( ( LilvInstance * ) handle );
+ }
+ virtual void cleanup ( LADSPA_Handle handle ) {
+ lilv_instance_free ( ( LilvInstance * ) handle );
+ }
+ virtual void connectPort ( LADSPA_Handle handle, unsigned long port, float *value );
+ virtual void apply ( LADSPA_Handle handle, unsigned long n ) {
+ lilv_instance_run ( ( LilvInstance * ) handle, n );
+ }
+ virtual LADSPA_PortDescriptor portd ( unsigned long k ) const {
+ return _fakeLd.PortDescriptors[k];
+ }
+
+ virtual LADSPA_PortRangeHint range ( unsigned long i ) {
+ // FIXME:
+ //return plugin ? plugin->PortRangeHints[i] : 0; DELETETHIS
+ LADSPA_PortRangeHint hint;
+ hint.HintDescriptor = 0;
+ hint.LowerBound = _PluginControlsMin [i];
+ hint.UpperBound = _PluginControlsMax [i];
+ return hint;
+ }
+ virtual void range ( unsigned long i, float *min, float *max ) const {
+ *min = _PluginControlsMin [i];
+ *max = _PluginControlsMax [i];
+ }
+
+ virtual float defaultValue ( unsigned long port ) const {
+ return _PluginControlsDefault [port];
+ }
+ virtual const char *portName ( unsigned long i ) {
+ return lilv_node_as_string ( lilv_port_get_name ( _synth->_handle, lilv_plugin_get_port_by_index ( _synth->_handle, i ) ) );
+ }
+
+ virtual CtrlValueType ctrlValueType ( unsigned long ) const {
+ return VAL_LINEAR;
+ }
+ virtual CtrlList::Mode ctrlMode ( unsigned long ) const {
+ return CtrlList::INTERPOLATE;
+ }
+};
+
+#endif // LV2_SUPPORT
+
+extern void initLV2();
+
+} // namespace MusECore
+
+#endif
+
+
+
diff --git a/muse2/muse/main.cpp b/muse2/muse/main.cpp
index 2d2165d..c05f8bd 100644
--- a/muse2/muse/main.cpp
+++ b/muse2/muse/main.cpp
@@ -59,6 +59,7 @@
#include "minstrument.h"
#include "midiport.h"
#include "mididev.h"
+#include "plugin.h"
#ifdef HAVE_LASH
#include <lash/lash.h>
@@ -74,6 +75,8 @@ extern void initVST();
extern void initVST_Native();
extern void initPlugins();
extern void initDSSI();
+extern void initLV2();
+extern void deinitLV2();
extern void readConfiguration();
extern void initMidiSequencer();
@@ -248,6 +251,9 @@ static void usage(const char* prog, const char* txt)
#ifdef DSSI_SUPPORT
fprintf(stderr, " -I Don't load DSSI plugins\n");
#endif
+#ifdef LV2_SUPPORT
+ fprintf(stderr, " -2 Don't load LV2 plugins\n");
+#endif
#ifdef HAVE_LASH
fprintf(stderr, " -L Don't use LASH\n");
#endif
@@ -384,6 +390,9 @@ int main(int argc, char* argv[])
#ifdef HAVE_LASH
optstr += QString("L");
#endif
+#ifdef LV2_SUPPORT
+ optstr += QString("2");
+#endif
bool noAudio = false;
int i;
@@ -427,6 +436,7 @@ int main(int argc, char* argv[])
case 'N': MusEGlobal::loadNativeVST = false; break;
case 'I': MusEGlobal::loadDSSI = false; break;
case 'L': MusEGlobal::useLASH = false; break;
+ case '2': MusEGlobal::loadLV2 = false; break;
case 'y': MusEGlobal::usePythonBridge = true; break;
case 'l': locale_override = QString(optarg); break;
case 'h': usage(argv[0], argv[1]);
@@ -684,6 +694,9 @@ int main(int argc, char* argv[])
if(MusEGlobal::loadDSSI)
MusECore::initDSSI();
+
+ if(MusEGlobal::loadLV2)
+ MusECore::initLV2();
MusECore::initOSC();
@@ -737,6 +750,15 @@ int main(int argc, char* argv[])
int rv = app.exec();
if(MusEGlobal::debugMsg)
printf("app.exec() returned:%d\nDeleting main MusE object\n", rv);
+
+ if (MusEGlobal::loadPlugins)
+ {
+ for (MusECore::iPlugin i = MusEGlobal::plugins.begin(); i != MusEGlobal::plugins.end(); ++i)
+ delete (*i);
+ }
+ if(MusEGlobal::loadLV2)
+ MusECore::deinitLV2();
+
delete MusEGlobal::muse;
if(MusEGlobal::debugMsg)
diff --git a/muse2/muse/plugin.cpp b/muse2/muse/plugin.cpp
index f42a62b..e45ee06 100644
--- a/muse2/muse/plugin.cpp
+++ b/muse2/muse/plugin.cpp
@@ -1151,8 +1151,8 @@ void initPlugins()
Plugin* PluginList::find(const QString& file, const QString& name)
{
for (iPlugin i = begin(); i != end(); ++i) {
- if ((file == i->lib()) && (name == i->label()))
- return &*i;
+ if ((file == (*i)->lib()) && (name == (*i)->label()))
+ return *i;
}
return 0;
@@ -3239,13 +3239,13 @@ void PluginDialog::fillPlugs()
for (MusECore::iPlugin i = MusEGlobal::plugins.begin(); i != MusEGlobal::plugins.end(); ++i)
if (selectedGroup==0 || MusEGlobal::plugin_groups.get(*i).contains(selectedGroup))
{
- unsigned long ai = i->inports();
- unsigned long ao = i->outports();
- unsigned long ci = i->controlInPorts();
- unsigned long co = i->controlOutPorts();
+ unsigned long ai = (*i)->inports();
+ unsigned long ao = (*i)->outports();
+ unsigned long ci = (*i)->controlInPorts();
+ unsigned long co = (*i)->controlOutPorts();
bool found = false;
QString sb_txt = sortBox->currentText().toLower();
- if(sb_txt.isEmpty() || i->label().toLower().contains(sb_txt) || i->name().toLower().contains(sb_txt))
+ if(sb_txt.isEmpty() || (*i)->label().toLower().contains(sb_txt) || (*i)->name().toLower().contains(sb_txt))
found = true;
bool addFlag = false;
@@ -3271,24 +3271,28 @@ void PluginDialog::fillPlugs()
}
if (found && addFlag) {
QTreeWidgetItem* item = new QTreeWidgetItem;
- if(i->isDssiSynth())
+ if((*i)->isDssiSynth())
type_name = tr("dssi synth");
- else if(i->isDssiPlugin())
+ else if((*i)->isDssiPlugin())
type_name = tr("dssi effect");
+ else if((*i)->isLV2Synth())
+ type_name = tr("LV2 synth");
+ else if((*i)->isLV2Plugin())
+ type_name = tr("LV2 effect");
else
type_name = tr("ladspa");
item->setText(0, type_name);
- item->setText(1, i->lib());
- item->setText(2, i->label());
- item->setText(3, i->name());
+ item->setText(1, (*i)->lib());
+ item->setText(2, (*i)->label());
+ item->setText(3, (*i)->name());
item->setText(4, QString().setNum(ai));
item->setText(5, QString().setNum(ao));
item->setText(6, QString().setNum(ci));
item->setText(7, QString().setNum(co));
- item->setText(8, QString().setNum(i->inPlaceCapable()));
- item->setText(9, QString().setNum(i->id()));
- item->setText(10, i->maker());
- item->setText(11, i->copyright());
+ item->setText(8, QString().setNum((*i)->inPlaceCapable()));
+ item->setText(9, QString().setNum((*i)->id()));
+ item->setText(10, (*i)->maker());
+ item->setText(11, (*i)->copyright());
pList->addTopLevelItem(item);
}
}
diff --git a/muse2/muse/plugin.h b/muse2/muse/plugin.h
index e168256..d5b2c39 100644
--- a/muse2/muse/plugin.h
+++ b/muse2/muse/plugin.h
@@ -100,6 +100,8 @@ class Plugin {
bool _isDssiSynth;
bool _isDssi;
+ bool _isLV2Synth;
+ bool _isLV2Plugin;
// Hack: Special flag required.
bool _isDssiVst;
@@ -117,10 +119,11 @@ class Plugin {
bool _inPlaceCapable;
public:
+ Plugin() {}; //empty constructor for LV2PluginWrapper
Plugin(QFileInfo* f, const LADSPA_Descriptor* d, bool isDssi = false, bool isDssiSynth = false);
- ~Plugin();
+ virtual ~Plugin();
- QString label() const { return _label; }
+ virtual QString label() const { return _label; }
QString name() const { return _name; }
unsigned long id() const { return _uniqueID; }
QString maker() const { return _maker; }
@@ -130,30 +133,32 @@ class Plugin {
QString filePath() const { return fi.filePath(); }
QString fileName() const { return fi.fileName(); }
int references() const { return _references; }
- int incReferences(int);
+ virtual int incReferences(int);
int instNo() { return _instNo++; }
bool isDssiPlugin() const { return _isDssi; }
- bool isDssiSynth() const { return _isDssiSynth; }
+ bool isDssiSynth() const { return _isDssiSynth; }
+ bool isLV2Plugin() const { return _isLV2Plugin; }
+ bool isLV2Synth() const { return _isLV2Synth; }
- LADSPA_Handle instantiate();
- void activate(LADSPA_Handle handle) {
+ virtual LADSPA_Handle instantiate();
+ virtual void activate(LADSPA_Handle handle) {
if (plugin && plugin->activate)
plugin->activate(handle);
}
- void deactivate(LADSPA_Handle handle) {
+ virtual void deactivate(LADSPA_Handle handle) {
if (plugin && plugin->deactivate)
plugin->deactivate(handle);
}
- void cleanup(LADSPA_Handle handle) {
+ virtual void cleanup(LADSPA_Handle handle) {
if (plugin && plugin->cleanup)
plugin->cleanup(handle);
}
- void connectPort(LADSPA_Handle handle, unsigned long port, float* value) {
+ virtual void connectPort(LADSPA_Handle handle, unsigned long port, float* value) {
if(plugin)
plugin->connect_port(handle, port, value);
}
- void apply(LADSPA_Handle handle, unsigned long n) {
+ virtual void apply(LADSPA_Handle handle, unsigned long n) {
if(plugin)
plugin->run(handle, n);
}
@@ -164,22 +169,22 @@ class Plugin {
unsigned long ports() { return _portCount; }
- LADSPA_PortDescriptor portd(unsigned long k) const {
+ virtual LADSPA_PortDescriptor portd(unsigned long k) const {
return plugin ? plugin->PortDescriptors[k] : 0;
}
- LADSPA_PortRangeHint range(unsigned long i) {
+ virtual LADSPA_PortRangeHint range(unsigned long i) {
// FIXME:
//return plugin ? plugin->PortRangeHints[i] : 0; DELETETHIS
return plugin->PortRangeHints[i];
}
- float defaultValue(unsigned long port) const;
- void range(unsigned long i, float*, float*) const;
- CtrlValueType ctrlValueType(unsigned long i) const;
- CtrlList::Mode ctrlMode(unsigned long i) const;
+ virtual float defaultValue(unsigned long port) const;
+ virtual void range(unsigned long i, float*, float*) const;
+ virtual CtrlValueType ctrlValueType(unsigned long i) const;
+ virtual CtrlList::Mode ctrlMode(unsigned long i) const;
- const char* portName(unsigned long i) {
+ virtual const char* portName(unsigned long i) {
return plugin ? plugin->PortNames[i] : 0;
}
@@ -192,14 +197,14 @@ class Plugin {
const std::vector<unsigned long>* getRpIdx() { return &rpIdx; }
};
-typedef std::list<Plugin>::iterator iPlugin;
+typedef std::list<Plugin *>::iterator iPlugin;
class PluginGroups : public QMap< QPair<QString, QString>, QSet<int> >
{
public:
QSet<int>& get(QString a, QString b) { return (*this)[(QPair<QString,QString>(a,b))]; }
- QSet<int>& get(const Plugin& p) { return (*this)[(QPair<QString,QString>(p.lib(),p.label()))]; }
+ QSet<int>& get(const Plugin *p) { return (*this)[(QPair<QString,QString>(p->lib(),p->label()))]; }
void shift_left(int first, int last);
void shift_right(int first, int last);
@@ -214,11 +219,11 @@ class PluginGroups : public QMap< QPair<QString, QString>, QSet<int> >
// PluginList
//---------------------------------------------------------
-class PluginList : public std::list<Plugin> {
+class PluginList : public std::list<Plugin *> {
public:
void add(QFileInfo* fi, const LADSPA_Descriptor* d, bool isDssi = false, bool isDssiSynth = false)
{
- push_back(Plugin(fi, d, isDssi, isDssiSynth));
+ push_back(new Plugin(fi, d, isDssi, isDssiSynth));
}
Plugin* find(const QString&, const QString&);
diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp
index 32568e3..95e78e2 100644
--- a/muse2/muse/synth.cpp
+++ b/muse2/muse/synth.cpp
@@ -62,7 +62,7 @@ namespace MusECore {
extern void connectNodes(AudioTrack*, AudioTrack*);
bool SynthI::_isVisible=false;
-const char* synthTypes[] = { "METRONOME", "MESS", "DSSI", "VST", "VST_NATIVE", "UNKNOWN" };
+const char* synthTypes[] = { "METRONOME", "MESS", "DSSI", "VST", "VST_NATIVE", "LV2", "UNKNOWN" };
QString synthType2String(Synth::Type type) { return QString(synthTypes[type]); }
Synth::Type string2SynthType(const QString& type)
diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h
index 273e314..7ea2e5e 100644
--- a/muse2/muse/synth.h
+++ b/muse2/muse/synth.h
@@ -68,7 +68,7 @@ class Synth {
QString _version;
public:
- enum Type { METRO_SYNTH=0, MESS_SYNTH, DSSI_SYNTH, VST_SYNTH, VST_NATIVE_SYNTH, SYNTH_TYPE_END };
+ enum Type { METRO_SYNTH=0, MESS_SYNTH, DSSI_SYNTH, VST_SYNTH, VST_NATIVE_SYNTH, LV2_SYNTH, SYNTH_TYPE_END };
Synth(const QFileInfo& fi, QString label, QString descr, QString maker, QString ver);
@@ -245,6 +245,7 @@ class SynthI : public AudioTrack, public MidiDevice,
friend class SynthIF;
friend class MessSynthIF;
friend class DssiSynthIF;
+ friend class LV2SynthIF;
friend class VstSynthIF;
friend class VstNativeSynthIF;
diff --git a/muse2/share/locale/muse_ru.ts b/muse2/share/locale/muse_ru.ts
index 0c2d011..75170f0 100644
--- a/muse2/share/locale/muse_ru.ts
+++ b/muse2/share/locale/muse_ru.ts
@@ -8783,9 +8783,17 @@ Likely the selected track is the wrong type.</source>
<translation>dssi ÑÑÑекÑ</translation>
</message>
<message>
+ <source>LV2 synth</source>
+ <translation>LV2 ÑинÑ</translation>
+ </message>
+ <message>
+ <source>LV2 effect</source>
+ <translation>LV2 ÑÑÑекÑ</translation>
+ </message>
+ <message>
<source>ladspa</source>
<translation>ladspa</translation>
- </message>
+ </message>
<message>
<source>Show plugs:</source>
<translation>ÐоказаÑÑ Ð¿Ð»Ð°Ð³Ð¸Ð½Ñ:</translation>
--
2.1.1
------------------------------------------------------------------------------
Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer
Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports
Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper
Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer
http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk
_______________________________________________
Lmuse-user mailing list
Lmuse-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lmuse-user