summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2011-09-20 20:29:47 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2011-09-20 20:29:47 +0000
commitd4433b9ab384196bb5b8876890863d7939339ee2 (patch)
tree669f503a04696c7869a14d5c5f6239024ba43e76
parente09e0035a62ce9f8876b6204682bbb3db474d477 (diff)
(native) Linux VST support from LinuxDSP
git-svn-id: svn://localhost/ardour2/branches/3.0@10101 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/export_range_markers_dialog.cc2
-rwxr-xr-xgtk2_ardour/lxvst_plugin_ui.h69
-rwxr-xr-xgtk2_ardour/lxvst_pluginui.cc277
-rw-r--r--gtk2_ardour/midi_region_view.cc6
-rw-r--r--gtk2_ardour/plugin_selector.cc19
-rw-r--r--gtk2_ardour/plugin_selector.h1
-rw-r--r--gtk2_ardour/plugin_ui.cc38
-rw-r--r--gtk2_ardour/plugin_ui.h2
-rw-r--r--gtk2_ardour/wscript9
-rw-r--r--libs/ardour/ardour/audioengine.h2
-rw-r--r--libs/ardour/ardour/buffer_set.h6
-rw-r--r--libs/ardour/ardour/jack_port.h1
-rwxr-xr-xlibs/ardour/ardour/lxvst_plugin.h123
-rw-r--r--libs/ardour/ardour/plugin_manager.h9
-rw-r--r--libs/ardour/ardour/rc_configuration_vars.h1
-rw-r--r--libs/ardour/ardour/session.h9
-rw-r--r--libs/ardour/ardour/sndfile_helpers.h7
-rw-r--r--libs/ardour/ardour/types.h3
-rwxr-xr-xlibs/ardour/ardour/vestige/aeffectx.h316
-rwxr-xr-xlibs/ardour/ardour/vstfx.h176
-rw-r--r--libs/ardour/audio_diskstream.cc15
-rw-r--r--libs/ardour/audioengine.cc7
-rw-r--r--libs/ardour/buffer_set.cc11
-rw-r--r--libs/ardour/globals.cc17
-rwxr-xr-xlibs/ardour/lxvst_plugin.cc830
-rw-r--r--libs/ardour/plugin.cc19
-rw-r--r--libs/ardour/plugin_insert.cc21
-rw-r--r--libs/ardour/plugin_manager.cc159
-rw-r--r--libs/ardour/route.cc2
-rw-r--r--libs/ardour/session.cc19
-rwxr-xr-xlibs/ardour/session_lxvst.cc364
-rw-r--r--libs/ardour/sndfile_helpers.cc41
-rw-r--r--libs/ardour/utils.cc2
-rwxr-xr-xlibs/ardour/vstfx.cc32
-rwxr-xr-xlibs/ardour/vstfxinfofile.cc382
-rwxr-xr-xlibs/ardour/vstfxwin.cc1399
-rw-r--r--libs/ardour/wscript5
-rw-r--r--wscript15
38 files changed, 4346 insertions, 70 deletions
diff --git a/gtk2_ardour/export_range_markers_dialog.cc b/gtk2_ardour/export_range_markers_dialog.cc
index 06f590758c..c6bf578a32 100644
--- a/gtk2_ardour/export_range_markers_dialog.cc
+++ b/gtk2_ardour/export_range_markers_dialog.cc
@@ -76,7 +76,7 @@ ExportRangeMarkersDialog::process_range_markers_export(Locations::LocationList&
string filepath = get_target_filepath(
get_selected_file_name(),
currentLocation->name(),
- sndfile_file_ending_from_string(get_selected_header_format()));
+ get_selected_header_format());
initSpec(filepath);
diff --git a/gtk2_ardour/lxvst_plugin_ui.h b/gtk2_ardour/lxvst_plugin_ui.h
new file mode 100755
index 0000000000..fc46ede8a3
--- /dev/null
+++ b/gtk2_ardour/lxvst_plugin_ui.h
@@ -0,0 +1,69 @@
+#ifndef __lxvst_plugin_ui_h__
+#define __lxvst_plugin_ui_h__
+
+#include <vector>
+#include <map>
+#include <list>
+
+#include <sigc++/signal.h>
+#include <gtkmm/widget.h>
+
+#include <ardour_dialog.h>
+#include <ardour/types.h>
+#include "plugin_ui.h"
+
+#ifdef LXVST_SUPPORT
+
+namespace ARDOUR {
+ class PluginInsert;
+ class LXVSTPlugin;
+}
+
+class LXVSTPluginUI : public PlugUIBase, public Gtk::VBox
+{
+ public:
+ LXVSTPluginUI (boost::shared_ptr<ARDOUR::PluginInsert>, boost::shared_ptr<ARDOUR::LXVSTPlugin>);
+ ~LXVSTPluginUI ();
+
+ gint get_preferred_height ();
+ gint get_preferred_width ();
+ bool start_updating(GdkEventAny*);
+ bool stop_updating(GdkEventAny*);
+
+ int package (Gtk::Window&);
+ void forward_key_event (GdkEventKey *);
+ bool non_gtk_gui() const { return true; }
+
+ private:
+ boost::shared_ptr<ARDOUR::LXVSTPlugin> lxvst;
+ Gtk::Socket socket;
+ Gtk::HBox preset_box;
+ Gtk::VBox vpacker;
+
+ sigc::connection _screen_update_connection;
+
+ bool configure_handler (GdkEventConfigure*, Gtk::Socket*);
+ void save_plugin_setting ();
+
+ struct PresetModelColumns : public Gtk::TreeModel::ColumnRecord {
+ PresetModelColumns() {
+ add (name);
+ add (number);
+ }
+ Gtk::TreeModelColumn<Glib::ustring> name;
+ Gtk::TreeModelColumn<int> number;
+ };
+
+ PresetModelColumns preset_columns;
+ Glib::RefPtr<Gtk::ListStore> preset_model;
+ Gtk::ComboBox lxvst_preset_combo;
+
+ void create_preset_store ();
+ void preset_chosen ();
+ void preset_selected ();
+ void resize_callback();
+};
+
+#endif //LXVST_SUPPORT
+
+#endif
diff --git a/gtk2_ardour/lxvst_pluginui.cc b/gtk2_ardour/lxvst_pluginui.cc
new file mode 100755
index 0000000000..dc62d907ae
--- /dev/null
+++ b/gtk2_ardour/lxvst_pluginui.cc
@@ -0,0 +1,277 @@
+/*
+ Copyright (C) 2004 Paul Davis
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/******************************************************************/
+/*linuxDSP - pluginui variant for LXVST (native Linux VST) Plugins*/
+/******************************************************************/
+
+#include <ardour/vstfx.h>
+#include <gtk/gtk.h>
+#include <gtk/gtksocket.h>
+#include <ardour/processor.h>
+#include <ardour/lxvst_plugin.h>
+
+#include "ardour_ui.h"
+#include "plugin_ui.h"
+#include "lxvst_plugin_ui.h"
+
+#include <gdk/gdkx.h>
+
+#define LXVST_H_FIDDLE 40
+
+using namespace Gtk;
+using namespace ARDOUR;
+using namespace PBD;
+
+LXVSTPluginUI::LXVSTPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<LXVSTPlugin> lxvp)
+ : PlugUIBase (pi),
+ lxvst (lxvp)
+{
+ create_preset_store ();
+
+ vstfx_run_editor (lxvst->vstfx());
+
+ preset_box.set_spacing (6);
+ preset_box.set_border_width (6);
+ preset_box.pack_end (bypass_button, false, false, 10);
+ preset_box.pack_end (save_button, false, false);
+ preset_box.pack_end (lxvst_preset_combo, false, false);
+
+ lxvst_preset_combo.signal_changed().connect (mem_fun (*this, &LXVSTPluginUI::preset_chosen));
+
+ bypass_button.set_active (!insert->active());
+
+ pack_start (preset_box, false, false);
+ pack_start (socket, true, true);
+}
+
+LXVSTPluginUI::~LXVSTPluginUI ()
+{
+
+ _screen_update_connection.disconnect();
+
+ // plugin destructor destroys the custom GUI, via the vstfx engine,
+ // and then our PluginUIWindow does the rest
+}
+
+
+bool
+LXVSTPluginUI::start_updating (GdkEventAny* ignored)
+{
+ _screen_update_connection.disconnect();
+ _screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
+ (mem_fun(*this, &LXVSTPluginUI::resize_callback));
+ return false;
+}
+
+bool
+LXVSTPluginUI::stop_updating (GdkEventAny* ignored)
+{
+ _screen_update_connection.disconnect();
+ return false;
+}
+
+
+void
+LXVSTPluginUI::resize_callback()
+{
+ /*We could maybe use this to resize the plugin GTK parent window
+ if required*/
+
+ if(lxvst->vstfx()->want_resize)
+ {
+ int new_height = lxvst->vstfx()->height;
+ int new_width = lxvst->vstfx()->width;
+
+ void* gtk_parent_window = lxvst->vstfx()->extra_data;
+
+ if(gtk_parent_window)
+ ((Gtk::Window*)gtk_parent_window)->resize(new_width, new_height + LXVST_H_FIDDLE);
+
+ lxvst->vstfx()->want_resize = 0;
+ }
+}
+
+void
+LXVSTPluginUI::preset_selected ()
+{
+ socket.grab_focus ();
+ PlugUIBase::preset_selected ();
+}
+
+void
+LXVSTPluginUI::preset_chosen ()
+{
+ // we can't dispatch directly here, too many plugins only expects one GUI thread.
+
+ lxvst->vstfx()->want_program = lxvst_preset_combo.get_active_row_number ();
+ socket.grab_focus ();
+}
+
+int
+LXVSTPluginUI::get_preferred_height ()
+{
+ /*FIXME*/
+
+ /*We have to return the required height of the plugin UI window + a fiddle factor
+ because we can't know how big the preset menu bar is until the window is realised
+ and we can't realise it until we have told it how big we would like it to be
+ which we can't do until it is realised etc*/
+
+ return (lxvst->vstfx()->height) + LXVST_H_FIDDLE; //May not be 40 for all screen res etc
+}
+
+int
+LXVSTPluginUI::get_preferred_width ()
+{
+ return lxvst->vstfx()->width;
+}
+
+int
+LXVSTPluginUI::package (Gtk::Window& win)
+{
+ /* forward configure events to plugin window */
+
+ win.signal_configure_event().connect (bind (mem_fun (*this, &LXVSTPluginUI::configure_handler), &socket), false);
+
+ /*Map the UI start and stop updating events to 'Map' events on the Window*/
+
+ win.signal_map_event().connect (mem_fun (*this, &LXVSTPluginUI::start_updating));
+ win.signal_unmap_event().connect (mem_fun (*this, &LXVSTPluginUI::stop_updating));
+
+ /* this assumes that the window's owner understands the XEmbed protocol. */
+
+ socket.add_id (vstfx_get_XID (lxvst->vstfx()));
+
+ vstfx_move_window_into_view (lxvst->vstfx());
+
+ lxvst->vstfx()->extra_data = (void*)(&win);
+ lxvst->vstfx()->want_resize = 0;
+
+ return 0;
+}
+
+bool
+LXVSTPluginUI::configure_handler (GdkEventConfigure* ev, Gtk::Socket *socket)
+{
+ XEvent event;
+ gint x, y;
+ GdkWindow* w;
+
+ if (socket == 0 || ((w = socket->gobj()->plug_window) == 0)) {
+ return false;
+ }
+
+ event.xconfigure.type = ConfigureNotify;
+ event.xconfigure.event = GDK_WINDOW_XWINDOW (w);
+ event.xconfigure.window = GDK_WINDOW_XWINDOW (w);
+
+ /* The ICCCM says that synthetic events should have root relative
+ * coordinates. We still aren't really ICCCM compliant, since
+ * we don't send events when the real toplevel is moved.
+ */
+ gdk_error_trap_push ();
+ gdk_window_get_origin (w, &x, &y);
+ gdk_error_trap_pop ();
+
+ event.xconfigure.x = x;
+ event.xconfigure.y = y;
+ event.xconfigure.width = GTK_WIDGET(socket->gobj())->allocation.width;
+ event.xconfigure.height = GTK_WIDGET(socket->gobj())->allocation.height;
+
+ event.xconfigure.border_width = 0;
+ event.xconfigure.above = None;
+ event.xconfigure.override_redirect = False;
+
+ gdk_error_trap_push ();
+ XSendEvent (GDK_WINDOW_XDISPLAY (w), GDK_WINDOW_XWINDOW (w), False, StructureNotifyMask, &event);
+ gdk_error_trap_pop ();
+
+ return false;
+}
+
+void
+LXVSTPluginUI::forward_key_event (GdkEventKey* ev)
+{
+ std::cerr << "LXVSTPluginUI : keypress forwarding to linuxVSTs unsupported" << std::endl;
+}
+
+
+void
+LXVSTPluginUI::create_preset_store ()
+{
+ VSTFX* vstfx = lxvst->vstfx();
+
+ int vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, NULL, 0.0f);
+
+ preset_model = ListStore::create (preset_columns);
+
+ for (int i = 0; i < vstfx->plugin->numPrograms; ++i) {
+ char buf[100];
+ TreeModel::Row row = *(preset_model->append());
+
+ snprintf (buf, 90, "preset %d", i);
+
+ if (vst_version >= 2) {
+ vstfx->plugin->dispatcher (vstfx->plugin, 29, i, 0, buf, 0.0);
+ }
+
+ row[preset_columns.name] = buf;
+ row[preset_columns.number] = i;
+ }
+
+ if (vstfx->plugin->numPrograms > 0) {
+ vstfx->plugin->dispatcher( vstfx->plugin, effSetProgram, 0, 0, NULL, 0.0 );
+ }
+
+ lxvst_preset_combo.set_model (preset_model);
+
+ CellRenderer* renderer = manage (new CellRendererText());
+ lxvst_preset_combo.pack_start (*renderer, true);
+ lxvst_preset_combo.add_attribute (*renderer, "text", 0);
+
+ if (lxvst->vstfx()->current_program != -1) {
+ lxvst_preset_combo.set_active (lxvst->vstfx()->current_program);
+ } else {
+ lxvst_preset_combo.set_active (0);
+ }
+}
+
+typedef int (*error_handler_t)( Display *, XErrorEvent *);
+static Display *the_gtk_display;
+static error_handler_t vstfx_error_handler;
+static error_handler_t gtk_error_handler;
+
+static int
+gtk_xerror_handler( Display *disp, XErrorEvent *ev )
+{
+ std::cerr << "** ERROR ** LXVSTPluginUI : Trapped an X Window System Error" << std::endl;
+
+ return 0;
+}
+
+void
+gui_init (int *argc, char **argv[])
+{
+ vstfx_error_handler = XSetErrorHandler (NULL);
+ gtk_init (argc, argv);
+ the_gtk_display = gdk_x11_display_get_xdisplay (gdk_display_get_default());
+ gtk_error_handler = XSetErrorHandler( gtk_xerror_handler );
+}
+
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 8fb14796e0..e6ffe1bd51 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -1547,12 +1547,16 @@ MidiRegionView::update_note (CanvasNote* ev, bool update_ghost_regions)
{
boost::shared_ptr<NoteType> note = ev->note();
+ cerr << "Note " << *note << " @ region frames " << source_beats_to_region_frames (note->time()) << endl;
+
const double x = trackview.editor().frame_to_pixel (source_beats_to_region_frames (note->time()));
const double y1 = midi_stream_view()->note_to_y(note->note());
ev->property_x1() = x;
ev->property_y1() = y1;
+ cerr << "\t" << x << " ... ";
+
/* trim note display to not overlap the end of its region */
if (note->length() > 0) {
@@ -1562,6 +1566,8 @@ MidiRegionView::update_note (CanvasNote* ev, bool update_ghost_regions)
ev->property_x2() = trackview.editor().frame_to_pixel (_region->length());
}
+ cerr << ev->property_x2() << endl;
+
ev->property_y2() = y1 + floor(midi_stream_view()->note_height());
if (note->length() == 0) {
diff --git a/gtk2_ardour/plugin_selector.cc b/gtk2_ardour/plugin_selector.cc
index 07ab3fd9f5..1b00c56fd9 100644
--- a/gtk2_ardour/plugin_selector.cc
+++ b/gtk2_ardour/plugin_selector.cc
@@ -240,6 +240,9 @@ PluginSelector::show_this_plugin (const PluginInfoPtr& info, const std::string&
case VST:
compstr = X_("VST");
break;
+ case LXVST:
+ compstr = X_("LXVST");
+ break;
}
} else if (mode == _("Author contains")) {
@@ -285,6 +288,7 @@ PluginSelector::refill ()
ladspa_refiller (filterstr);
lv2_refiller (filterstr);
vst_refiller (filterstr);
+ lxvst_refiller (filterstr);
au_refiller (filterstr);
in_row_change = false;
@@ -358,6 +362,18 @@ PluginSelector::vst_refiller (const std::string&)
}
void
+#ifdef LXVST_SUPPORT
+PluginSelector::lxvst_refiller (const std::string& filterstr)
+#else
+PluginSelector::lxvst_refiller (const std::string&)
+#endif
+{
+#ifdef LXVST_SUPPORT
+ refiller (manager->lxvst_plugin_info(), filterstr, "LXVST");
+#endif
+}
+
+void
#ifdef HAVE_AUDIOUNITS
PluginSelector::au_refiller (const std::string& filterstr)
#else
@@ -585,6 +601,9 @@ PluginSelector::build_plugin_menu ()
#ifdef VST_SUPPORT
all_plugs.insert (all_plugs.end(), manager->vst_plugin_info().begin(), manager->vst_plugin_info().end());
#endif
+#ifdef LXVST_SUPPORT
+ all_plugs.insert (all_plugs.end(), manager->lxvst_plugin_info().begin(), manager->lxvst_plugin_info().end());
+#endif
#ifdef HAVE_AUDIOUNITS
all_plugs.insert (all_plugs.end(), manager->au_plugin_info().begin(), manager->au_plugin_info().end());
#endif
diff --git a/gtk2_ardour/plugin_selector.h b/gtk2_ardour/plugin_selector.h
index 0c7d9f4211..3635b71a76 100644
--- a/gtk2_ardour/plugin_selector.h
+++ b/gtk2_ardour/plugin_selector.h
@@ -112,6 +112,7 @@ class PluginSelector : public ArdourDialog
void ladspa_refiller (const std::string&);
void lv2_refiller (const std::string&);
void vst_refiller (const std::string&);
+ void lxvst_refiller (const std::string&);
void au_refiller (const std::string&);
Gtk::Menu* _plugin_menu;
diff --git a/gtk2_ardour/plugin_ui.cc b/gtk2_ardour/plugin_ui.cc
index beb070c150..f6a97a1cf1 100644
--- a/gtk2_ardour/plugin_ui.cc
+++ b/gtk2_ardour/plugin_ui.cc
@@ -50,6 +50,10 @@
#include "ardour/vst_plugin.h"
#include "vst_pluginui.h"
#endif
+#ifdef LXVST_SUPPORT
+#include "ardour/lxvst_plugin.h"
+#include "lxvst_plugin_ui.h"
+#endif
#ifdef LV2_SUPPORT
#include "ardour/lv2_plugin.h"
#include "lv2_plugin_ui.h"
@@ -98,6 +102,10 @@ PluginUIWindow::PluginUIWindow (
case ARDOUR::VST:
have_gui = create_vst_editor (insert);
break;
+
+ case ARDOUR::LXVST:
+ have_gui = create_lxvst_editor (insert);
+ break;
case ARDOUR::AudioUnit:
have_gui = create_audiounit_editor (insert);
@@ -275,6 +283,36 @@ PluginUIWindow::create_vst_editor(boost::shared_ptr<PluginInsert>)
}
bool
+#ifdef LXVST_SUPPORT
+PluginUIWindow::create_lxvst_editor(boost::shared_ptr<PluginInsert> insert)
+#else
+PluginUIWindow::create_lxvst_editor(boost::shared_ptr<PluginInsert>)
+#endif
+{
+#ifndef LXVST_SUPPORT
+ return false;
+#else
+
+ boost::shared_ptr<LXVSTPlugin> lxvp;
+
+ if ((lxvp = boost::dynamic_pointer_cast<LXVSTPlugin> (insert->plugin())) == 0) {
+ error << _("unknown type of editor-supplying plugin (note: no linuxVST support in this version of ardour)")
+ << endmsg;
+ throw failed_constructor ();
+ } else {
+ LXVSTPluginUI* lxvpu = new LXVSTPluginUI (insert, lxvp);
+
+ _pluginui = lxvpu;
+ _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
+ add (*lxvpu);
+ lxvpu->package (*this);
+ }
+
+ return true;
+#endif
+}
+
+bool
#ifdef GTKOSX
PluginUIWindow::create_audiounit_editor (boost::shared_ptr<PluginInsert> insert)
#else
diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h
index 7c88b01bbd..e060907986 100644
--- a/gtk2_ardour/plugin_ui.h
+++ b/gtk2_ardour/plugin_ui.h
@@ -53,6 +53,7 @@ namespace ARDOUR {
class PluginInsert;
class Plugin;
class VSTPlugin;
+ class LXVSTPlugin;
class IOProcessor;
class AUPlugin;
}
@@ -298,6 +299,7 @@ class PluginUIWindow : public Gtk::Window
void plugin_going_away ();
bool create_vst_editor (boost::shared_ptr<ARDOUR::PluginInsert>);
+ bool create_lxvst_editor(boost::shared_ptr<ARDOUR::PluginInsert>);
bool create_audiounit_editor (boost::shared_ptr<ARDOUR::PluginInsert>);
bool create_lv2_editor (boost::shared_ptr<ARDOUR::PluginInsert>);
};
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index fb30400017..dd7d2f544b 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -305,6 +305,7 @@ def build(bld):
obj.includes = ['.']
obj.source = gtk2_ardour_sources
obj.name = 'gtk2_ardour'
+ obj.linkflags = []
if bld.env['VST_SUPPORT']:
obj.target = 'gtk2_ardour'
obj.includes += ['../libs/fst']
@@ -343,6 +344,12 @@ def build(bld):
if bld.env['VST_SUPPORT']:
obj.source += [ 'vst_pluginui.cc' ]
obj.defines += [ 'VST_SUPPORT' ]
+ bld.env.append ('LINKFLAGS', '-lX11')
+
+ if bld.env['LXVST_SUPPORT']:
+ obj.source += [ 'lxvst_pluginui.cc' ]
+ obj.defines += [ 'LXVST_SUPPORT' ]
+ obj.linkflags += [ '-lX11' ]
if bld.env['PHONE_HOME']:
obj.defines += [ 'PHONE_HOME' ]
@@ -365,7 +372,7 @@ def build(bld):
'''
obj.includes = '../libs/fst'
obj.target = 'ardour-3.0-vst'
- obj.linkflags = ['-mwindows', '-Wl,--export-dynamic', '-lpthread']
+ obj.linkflags += ['-mwindows', '-Wl,--export-dynamic', '-lpthread']
obj.defines = ['_POSIX_SOURCE', 'USE_WS_PREFIX']
obj.uselib = 'ALSA'
obj.uselib_local = ['libpbd','libmidipp','libtaglib','libardour',
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index 68daadd674..05ca38e43b 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -189,8 +189,6 @@ public:
void get_physical_outputs (DataType type, std::vector<std::string>&);
void get_physical_inputs (DataType type, std::vector<std::string>&);
- void update_total_latencies ();
-
Port *get_port_by_name (const std::string &);
enum TransportState {
diff --git a/libs/ardour/ardour/buffer_set.h b/libs/ardour/ardour/buffer_set.h
index 724eef6a24..930d708989 100644
--- a/libs/ardour/ardour/buffer_set.h
+++ b/libs/ardour/ardour/buffer_set.h
@@ -29,7 +29,7 @@
#include "ardour/data_type.h"
#include "ardour/types.h"
-#ifdef VST_SUPPORT
+#if defined VST_SUPPORT || defined LXVST_SUPPORT
#include "evoral/MIDIEvent.hpp"
struct VstEvents;
struct VstMidiEvent;
@@ -118,7 +118,7 @@ public:
void flush_lv2_midi(bool input, size_t i);
#endif
-#ifdef VST_SUPPORT
+#if defined VST_SUPPORT || defined LXVST_SUPPORT
VstEvents* get_vst_midi (size_t);
#endif
@@ -176,7 +176,7 @@ private:
LV2Buffers _lv2_buffers;
#endif
-#ifdef VST_SUPPORT
+#if defined VST_SUPPORT || defined LXVST_SUPPORT
class VSTBuffer {
public:
VSTBuffer (size_t);
diff --git a/libs/ardour/ardour/jack_port.h b/libs/ardour/ardour/jack_port.h
index 0bb0752d55..edbabaae04 100644
--- a/libs/ardour/ardour/jack_port.h
+++ b/libs/ardour/ardour/jack_port.h
@@ -104,7 +104,6 @@ class JackPort : public virtual Port, public PortConnectableByName {
jack_port_t* _port;
int disconnect ();
- void recompute_total_latency() const;
std::set<std::string> _named_connections;
};
diff --git a/libs/ardour/ardour/lxvst_plugin.h b/libs/ardour/ardour/lxvst_plugin.h
new file mode 100755
index 0000000000..092a786f95
--- /dev/null
+++ b/libs/ardour/ardour/lxvst_plugin.h
@@ -0,0 +1,123 @@
+/*
+ Copyright (C) 2004 Paul Davis
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_lxvst_plugin_h__
+#define __ardour_lxvst_plugin_h__
+
+#include <list>
+#include <map>
+#include <set>
+#include <vector>
+#include <string>
+#include <dlfcn.h>
+
+#include "pbd/stateful.h"
+#include "ardour/plugin.h"
+
+struct _VSTFXHandle;
+struct _VSTFX;
+typedef struct _VSTFXHandle VSTFXHandle;
+typedef struct _VSTFX VSTFX;
+class AEffect;
+
+namespace ARDOUR {
+class AudioEngine;
+class Session;
+
+class LXVSTPlugin : public ARDOUR::Plugin
+{
+ public:
+ LXVSTPlugin (ARDOUR::AudioEngine&, ARDOUR::Session&, VSTFXHandle* handle);
+ LXVSTPlugin (const LXVSTPlugin &);
+ ~LXVSTPlugin ();
+
+ /* Plugin interface */
+
+ std::string unique_id() const;
+ const char * label() const;
+ const char * name() const;
+ const char * maker() const;
+ uint32_t parameter_count() const;
+ float default_value (uint32_t port);
+ framecnt_t signal_latency() const;
+ void set_parameter (uint32_t port, float val);
+ float get_parameter (uint32_t port) const;
+ int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
+ std::set<Evoral::Parameter> automatable() const;
+ uint32_t nth_parameter (uint32_t port, bool& ok) const;
+ void activate ();
+ void deactivate ();
+ int set_block_size (pframes_t);
+
+ int connect_and_run (BufferSet&,
+ ChanMapping in, ChanMapping out,
+ pframes_t nframes, framecnt_t offset);
+
+ std::string describe_parameter (Evoral::Parameter);
+ std::string state_node_name() const { return "lxvst"; }
+ void print_parameter (uint32_t, char*, uint32_t len) const;
+
+ bool parameter_is_audio(uint32_t i) const { return false; }
+ bool parameter_is_control(uint32_t i) const { return true; }
+ bool parameter_is_input(uint32_t i) const { return true; }
+ bool parameter_is_output(uint32_t i) const { return false; }
+
+ bool load_preset (PresetRecord);
+ int first_user_preset_index () const;
+
+ bool has_editor () const;
+
+ int set_state (XMLNode const &, int);
+
+ AEffect * plugin () const { return _plugin; }
+ VSTFX * vstfx () const { return _vstfx; }
+
+private:
+
+ void do_remove_preset (std::string name);
+ std::string do_save_preset (std::string name);
+ gchar* get_chunk (bool) const;
+ int set_chunk (gchar const *, bool);
+ XMLTree * presets_tree () const;
+ std::string presets_file () const;
+ void find_presets ();
+ bool load_user_preset (PresetRecord);
+ bool load_plugin_preset (PresetRecord);
+ void add_state (XMLNode *) const;
+
+ VSTFXHandle* handle;
+ VSTFX* _vstfx;
+ AEffect* _plugin;
+ bool been_resumed;
+};
+
+class LXVSTPluginInfo : public PluginInfo
+{
+ public:
+ LXVSTPluginInfo ();
+ ~LXVSTPluginInfo () {}
+
+ PluginPtr load (Session& session);
+};
+
+typedef boost::shared_ptr<LXVSTPluginInfo> LXVSTPluginInfoPtr;
+
+} // namespace ARDOUR
+
+#endif /* __ardour_lxvst_plugin_h__ */
diff --git a/libs/ardour/ardour/plugin_manager.h b/libs/ardour/ardour/plugin_manager.h
index 9ba3d8324e..ae534837ce 100644
--- a/libs/ardour/ardour/plugin_manager.h
+++ b/libs/ardour/ardour/plugin_manager.h
@@ -43,6 +43,7 @@ class PluginManager : public boost::noncopyable {
~PluginManager ();
ARDOUR::PluginInfoList &vst_plugin_info ();
+ ARDOUR::PluginInfoList &lxvst_plugin_info ();
ARDOUR::PluginInfoList &ladspa_plugin_info ();
ARDOUR::PluginInfoList &lv2_plugin_info ();
ARDOUR::PluginInfoList &au_plugin_info ();
@@ -51,6 +52,7 @@ class PluginManager : public boost::noncopyable {
int add_ladspa_directory (std::string dirpath);
int add_vst_directory (std::string dirpath);
+ int add_lxvst_directory (std::string dirpath);
static PluginManager* the_manager() { return _manager; }
@@ -95,6 +97,7 @@ class PluginManager : public boost::noncopyable {
ARDOUR::PluginInfoList _empty_plugin_info;
ARDOUR::PluginInfoList* _vst_plugin_info;
+ ARDOUR::PluginInfoList* _lxvst_plugin_info;
ARDOUR::PluginInfoList* _ladspa_plugin_info;
ARDOUR::PluginInfoList* _lv2_plugin_info;
ARDOUR::PluginInfoList* _au_plugin_info;
@@ -103,13 +106,16 @@ class PluginManager : public boost::noncopyable {
std::string ladspa_path;
std::string vst_path;
+ std::string lxvst_path;
void ladspa_refresh ();
void vst_refresh ();
+ void lxvst_refresh ();
void add_lrdf_data (const std::string &path);
void add_ladspa_presets ();
void add_vst_presets ();
+ void add_lxvst_presets ();
void add_presets (std::string domain);
void au_refresh ();
@@ -118,6 +124,9 @@ class PluginManager : public boost::noncopyable {
int vst_discover_from_path (std::string path);
int vst_discover (std::string path);
+
+ int lxvst_discover_from_path (std::string path);
+ int lxvst_discover (std::string path);
int ladspa_discover_from_path (std::string path);
int ladspa_discover (std::string path);
diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h
index 5693bac890..0ec31e3e1b 100644
--- a/libs/ardour/ardour/rc_configuration_vars.h
+++ b/libs/ardour/ardour/rc_configuration_vars.h
@@ -140,6 +140,7 @@ CONFIG_VARIABLE (bool, hiding_groups_deactivates_groups, "hiding-groups-deactiva
CONFIG_VARIABLE (bool, verify_remove_last_capture, "verify-remove-last-capture", true)
CONFIG_VARIABLE (bool, no_new_session_dialog, "no-new-session-dialog", false)
CONFIG_VARIABLE (bool, use_vst, "use-vst", true)
+CONFIG_VARIABLE (bool, use_lxvst, "use-lxvst", true)
CONFIG_VARIABLE (bool, save_history, "save-history", true)
CONFIG_VARIABLE (int32_t, saved_history_depth, "save-history-depth", 20)
CONFIG_VARIABLE (int32_t, history_depth, "history-depth", 20)
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 68cf66bd25..2dbb2f08ac 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -741,6 +741,15 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
long value,
void* ptr,
float opt);
+
+ /*Native linuxVST support*/
+
+ static long lxvst_callback (AEffect* effect,
+ long opcode,
+ long index,
+ long value,
+ void* ptr,
+ float opt);
static PBD::Signal0<void> SendFeedback;
diff --git a/libs/ardour/ardour/sndfile_helpers.h b/libs/ardour/ardour/sndfile_helpers.h
index ed84820b8d..02f486a975 100644
--- a/libs/ardour/ardour/sndfile_helpers.h
+++ b/libs/ardour/ardour/sndfile_helpers.h
@@ -42,10 +42,9 @@ extern const char * const sndfile_endian_formats_strings[SNDFILE_ENDIAN_FORMATS+
extern int sndfile_endian_formats[SNDFILE_ENDIAN_FORMATS];
-int sndfile_bitdepth_format_from_string (std::string);
-int sndfile_header_format_from_string (std::string);
-int sndfile_endian_format_from_string (std::string);
-std::string sndfile_file_ending_from_string (std::string);
+int sndfile_bitdepth_format_by_index (int);
+int sndfile_header_format_by_index (int);
+int sndfile_endian_format_by_index (int);
int sndfile_data_width (int format);
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index e21c588c62..9579c87b7b 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -449,7 +449,8 @@ namespace ARDOUR {
AudioUnit,
LADSPA,
LV2,
- VST
+ VST,
+ LXVST,
};
enum RunContext {
diff --git a/libs/ardour/ardour/vestige/aeffectx.h b/libs/ardour/ardour/vestige/aeffectx.h
new file mode 100755
index 0000000000..dda128f45e
--- /dev/null
+++ b/libs/ardour/ardour/vestige/aeffectx.h
@@ -0,0 +1,316 @@
+/*
+ * aeffectx.h - simple header to allow VeSTige compilation and eventually work
+ *
+ * Copyright (c) 2006 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
+ *
+ * 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 _AEFFECTX_H
+#define _AEFFECTX_H
+
+#include <stdint.h>
+
+#define audioMasterAutomate 0
+#define audioMasterVersion 1
+#define audioMasterCurrentId 2
+#define audioMasterIdle 3
+#define audioMasterPinConnected 4
+// unsupported? 5
+#define audioMasterWantMidi 6
+#define audioMasterGetTime 7
+#define audioMasterProcessEvents 8
+#define audioMasterSetTime 9
+#define audioMasterTempoAt 10
+#define audioMasterGetNumAutomatableParameters 11
+#define audioMasterGetParameterQuantization 12
+#define audioMasterIOChanged 13
+#define audioMasterNeedIdle 14
+#define audioMasterSizeWindow 15
+#define audioMasterGetSampleRate 16
+#define audioMasterGetBlockSize 17
+#define audioMasterGetInputLatency 18
+#define audioMasterGetOutputLatency 19
+#define audioMasterGetPreviousPlug 20
+#define audioMasterGetNextPlug 21
+#define audioMasterWillReplaceOrAccumulate 22
+#define audioMasterGetCurrentProcessLevel 23
+#define audioMasterGetAutomationState 24
+#define audioMasterOfflineStart 25
+#define audioMasterOfflineRead 26
+#define audioMasterOfflineWrite 27
+#define audioMasterOfflineGetCurrentPass 28
+#define audioMasterOfflineGetCurrentMetaPass 29
+#define audioMasterSetOutputSampleRate 30
+// unsupported? 31
+#define audioMasterGetSpeakerArrangement 31 // deprecated in 2.4?
+#define audioMasterGetVendorString 32
+#define audioMasterGetProductString 33
+#define audioMasterGetVendorVersion 34
+#define audioMasterVendorSpecific 35
+#define audioMasterSetIcon 36
+#define audioMasterCanDo 37
+#define audioMasterGetLanguage 38
+#define audioMasterOpenWindow 39
+#define audioMasterCloseWindow 40
+#define audioMasterGetDirectory 41
+#define audioMasterUpdateDisplay 42
+#define audioMasterBeginEdit 43
+#define audioMasterEndEdit 44
+#define audioMasterOpenFileSelector 45
+#define audioMasterCloseFileSelector 46// currently unused
+#define audioMasterEditFile 47// currently unused
+#define audioMasterGetChunkFile 48// currently unused
+#define audioMasterGetInputSpeakerArrangement 49 // currently unused
+
+#define effFlagsHasEditor 1
+// very likely
+#define effFlagsCanReplacing (1 << 4)
+// currently unused
+#define effFlagsIsSynth (1 << 8)
+
+#define effOpen 0
+//currently unused
+#define effClose 1
+// currently unused
+#define effSetProgram 2
+// currently unused
+#define effGetProgram 3
+// currently unused
+#define effGetProgramName 5
+#define effGetParamLabel 6
+// currently unused
+#define effGetParamName 8
+// this is a guess
+#define effSetSampleRate 10
+#define effSetBlockSize 11
+#define effMainsChanged 12
+#define effEditGetRect 13
+#define effEditOpen 14
+#define effEditClose 15
+#define effEditIdle 19
+#define effProcessEvents 25
+#define effGetEffectName 45
+// missing
+#define effGetParameterProperties 47
+#define effGetVendorString 47
+#define effGetProductString 48
+#define effGetVendorVersion 49
+// currently unused
+#define effCanDo 51
+// currently unused
+#define effGetVstVersion 58
+
+#ifdef WORDS_BIGENDIAN
+// "VstP"
+#define kEffectMagic 0x50747356
+#else
+// "PtsV"
+#define kEffectMagic 0x56737450
+#endif
+
+#define kVstLangEnglish 1
+#define kVstMidiType 1
+#define kVstTransportPlaying (1 << 1)
+
+/* validity flags for a VstTimeINfo structure this info comes from the web */
+
+#define kVstNanosValid (1 << 8)
+#define kVstPpqPosValid (1 << 9)
+#define kVstTempoValid (1 << 10)
+#define kVstBarsValid (1 << 11)
+#define kVstCyclePosValid (1 << 12)
+#define kVstTimeSigValid (1 << 13)
+#define kVstSmpteValid (1 << 14)
+#define kVstClockValid (1 << 15)
+
+#define kVstTransportChanged 1
+
+typedef struct VstMidiEvent
+{
+ // 00
+ int type;
+ // 04
+ int byteSize;
+ // 08
+ int deltaFrames;
+ // 0c?
+ int flags;
+ // 10?
+ int noteLength;
+ // 14?
+ int noteOffset;
+ // 18
+ char midiData[4];
+ // 1c?
+ char detune;
+ // 1d?
+ char noteOffVelocity;
+ // 1e?
+ char reserved1;
+ // 1f?
+ char reserved2;
+
+} VstMidiEvent;
+
+
+
+
+typedef struct VstEvent
+{
+ char dump[sizeof( VstMidiEvent )];
+
+} VstEvent ;
+
+
+
+
+typedef struct VstEvents
+{
+ // 00
+ int numEvents;
+ // 04
+ int reserved;
+ // 08
+ VstEvent * events[];
+} VstEvents;
+
+/* constants from http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=3740&sid=183f74631fee71a493316735e2b9f28b */
+
+enum Vestige2StringConstants
+{
+ VestigeMaxNameLen = 64,
+ VestigeMaxLabelLen = 64,
+ VestigeMaxShortLabelLen = 8,
+ VestigeMaxCategLabelLen = 24,
+ VestigeMaxFileNameLen = 100
+};
+
+/* this struct taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */
+struct VstParameterProperties
+{
+ float stepFloat; /* float step */
+ float smallStepFloat; /* small float step */
+ float largeStepFloat; /* large float step */
+ char label[VestigeMaxLabelLen]; /* parameter label */
+ int32_t flags; /* @see VstParameterFlags */
+ int32_t minInteger; /* integer minimum */
+ int32_t maxInteger; /* integer maximum */
+ int32_t stepInteger; /* integer step */
+ int32_t largeStepInteger; /* large integer step */
+ char shortLabel[VestigeMaxShortLabelLen]; /* short label, recommended: 6 + delimiter */
+ int16_t displayIndex; /* index where this parameter should be displayed (starting with 0) */
+ int16_t category; /* 0: no category, else group index + 1 */
+ int16_t numParametersInCategory; /* number of parameters in category */
+ int16_t reserved; /* zero */
+ char categoryLabel[VestigeMaxCategLabelLen]; /* category label, e.g. "Osc 1" */
+ char future[16]; /* reserved for future use */
+};
+
+/* this enum taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */
+enum VstParameterFlags
+{
+ kVstParameterIsSwitch = 1 << 0, /* parameter is a switch (on/off) */
+ kVstParameterUsesIntegerMinMax = 1 << 1, /* minInteger, maxInteger valid */
+ kVstParameterUsesFloatStep = 1 << 2, /* stepFloat, smallStepFloat, largeStepFloat valid */
+ kVstParameterUsesIntStep = 1 << 3, /* stepInteger, largeStepInteger valid */
+ kVstParameterSupportsDisplayIndex = 1 << 4, /* displayIndex valid */
+ kVstParameterSupportsDisplayCategory = 1 << 5, /* category, etc. valid */
+ kVstParameterCanRamp = 1 << 6 /* set if parameter value can ramp up/down */
+};
+
+typedef struct AEffect
+{
+ // Never use c++!!!
+ // 00-03
+ int magic;
+ // dispatcher 04-07
+ int (* dispatcher)( struct AEffect * , int , int , int , void * , float );
+ // process, quite sure 08-0b
+ void (* process)( struct AEffect * , float * * , float * * , int );
+ // setParameter 0c-0f
+ void (* setParameter)( struct AEffect * , int , float );
+ // getParameter 10-13
+ float (* getParameter)( struct AEffect * , int );
+ // programs 14-17
+ int numPrograms;
+ // Params 18-1b
+ int numParams;
+ // Input 1c-1f
+ int numInputs;
+ // Output 20-23
+ int numOutputs;
+ // flags 24-27
+ int flags;
+ // Fill somewhere 28-2b
+ void * user;
+ // Zeroes 2c-2f 30-33 34-37 38-3b
+ char empty3[4 + 4 + 4 + 4];
+ // 1.0f 3c-3f
+ float unkown_float;
+ // An object? pointer 40-43
+ char empty4[4];
+ // Zeroes 44-47
+ char empty5[4];
+ // Id 48-4b
+ char unused_id[4];
+ // Don't know 4c-4f
+ char unknown1[4];
+ // processReplacing 50-53
+ void (* processReplacing)( struct AEffect * , float * * , float * * , int );
+
+ int uniqueID;
+
+} AEffect;
+
+
+
+
+typedef struct VstTimeInfo
+{
+ /* info from online documentation of VST provided by Steinberg */
+
+ double samplePos;
+ double sampleRate;
+ double nanoSeconds;
+ double ppqPos;
+ double tempo;
+ double barStartPos;
+ double cycleStartPos;
+ double cycleEndPos;
+ double timeSigNumerator;
+ double timeSigDenominator;
+ long smpteOffset;
+ long smpteFrameRate;
+ long samplesToNextClock;
+ long flags;
+
+} VstTimeInfo;
+
+
+typedef long int (* audioMasterCallback)( AEffect * , long int , long int ,
+ long int , void * , float );
+// we don't use it, may be noise
+#define VSTCALLBACK
+
+
+
+
+#endif
diff --git a/libs/ardour/ardour/vstfx.h b/libs/ardour/ardour/vstfx.h
new file mode 100755
index 0000000000..e59998dd99
--- /dev/null
+++ b/libs/ardour/ardour/vstfx.h
@@ -0,0 +1,176 @@
+#ifndef __vstfx_h__
+#define __vstfx_h__
+
+#include <setjmp.h>
+#include <signal.h>
+#include <pthread.h>
+#include <stdio.h>
+
+/******************************************************************************************/
+/*VSTFX - an engine to manage native linux VST plugins - derived from FST for Windows VSTs*/
+/******************************************************************************************/
+
+extern void (*vstfx_error_callback)(const char *msg);
+
+void vstfx_set_error_function (void (*func)(const char *));
+
+void vstfx_error (const char *fmt, ...);
+
+/*We will use the vestige headers*/
+
+#define VESTIGE_HEADER
+
+#include <ardour/vestige/aeffectx.h>
+
+typedef struct _VSTFX VSTFX;
+typedef struct _VSTFXHandle VSTFXHandle;
+typedef struct _VSTFXInfo VSTFXInfo;
+typedef struct _VSTFXKey VSTFXKey;
+
+
+/*Struct to contain the info about a plugin*/
+
+struct _VSTFXInfo
+{
+ char *name;
+ char *creator;
+ int UniqueID;
+ char *Category;
+
+ int numInputs;
+ int numOutputs;
+ int numParams;
+
+ int wantMidi;
+ int wantEvents;
+ int hasEditor;
+ int canProcessReplacing;
+
+ /* i think we should save the parameter Info Stuff soon. */
+ // struct VstParameterInfo *infos;
+ char **ParamNames;
+ char **ParamLabels;
+};
+
+/*The AEffect which contains the info about a plugin instance*/
+
+typedef struct AEffect * (*main_entry_t)(audioMasterCallback);
+
+/*A handle used to identify a plugin to vstfx*/
+
+struct _VSTFXHandle
+{
+ void* dll;
+ char* name;
+ char* nameptr; /* ptr returned from strdup() etc. */
+
+ //struct AEffect* (*main_entry)(audioMasterCallback);
+
+ main_entry_t main_entry;
+
+ int plugincnt;
+};
+
+/*No key forwarding enabled in vstfx at the moment - maybe
+not required*/
+
+
+struct _VSTFXKey
+{
+ /** virtual-key code, or 0 if this _VSTFXKey is a `character' key */
+ int special;
+ /** `character' key, or 0 if this _VSTFXKey is a virtual-key */
+ int character;
+};
+
+
+
+/*Structure used to describe the instance of VSTFX responsible for
+a particular plugin instance. These are connected together in a
+linked list*/
+
+struct _VSTFX
+{
+ struct AEffect* plugin;
+ int window; /* The plugin's parent X11 XWindow */
+ int plugin_ui_window; /*The ID of the plugin UI window created by the plugin*/
+ int xid; /* X11 XWindow */
+
+ int want_resize; /*Set to signal the plugin resized its UI*/
+ void* extra_data; /*Pointer to any extra data*/
+
+ void* event_callback_thisptr;
+ void (*eventProc) (void* event);
+
+ VSTFXHandle* handle;
+
+ int width;
+ int height;
+ int wantIdle;
+ int destroy;
+ int vst_version;
+ int has_editor;
+
+ int program_set_without_editor;
+
+ int want_program;
+ int want_chunk;
+ int n_pending_keys;
+unsigned char* wanted_chunk;
+ int wanted_chunk_size;
+ int current_program;
+ float *want_params;
+ float *set_params;
+
+ VSTFXKey pending_keys[16];
+
+ int dispatcher_wantcall;
+ int dispatcher_opcode;
+ int dispatcher_index;
+ int dispatcher_val;
+ void * dispatcher_ptr;
+ float dispatcher_opt;
+ int dispatcher_retval;
+
+ struct _VSTFX* next;
+ pthread_mutex_t lock;
+ pthread_cond_t window_status_change;
+ pthread_cond_t plugin_dispatcher_called;
+ pthread_cond_t window_created;
+ int been_activated;
+};
+
+/*API to vstfx*/
+
+extern int vstfx_launch_editor(VSTFX* vstfx);
+
+extern int vstfx_init (void* possible_hmodule);
+extern void vstfx_exit ();
+
+extern VSTFXHandle* vstfx_load (const char*);
+extern int vstfx_unload (VSTFXHandle*);
+
+extern VSTFX* vstfx_instantiate (VSTFXHandle*, audioMasterCallback amc, void* userptr);
+extern void vstfx_close (VSTFX*);
+
+extern int vstfx_create_editor (VSTFX* vstfx);
+extern int vstfx_run_editor (VSTFX*);
+extern void vstfx_destroy_editor (VSTFX*);
+extern int vstfx_get_XID (VSTFX*);
+extern void vstfx_move_window_into_view (VSTFX*);
+
+extern VSTFXInfo* vstfx_get_info (char *dllpathname);
+extern void vstfx_free_info (VSTFXInfo *info);
+extern void vstfx_event_loop_remove_plugin (VSTFX* fst);
+extern int vstfx_call_dispatcher(VSTFX *vstfx, int opcode, int index, int val, void *ptr, float opt );
+
+/** Load a plugin state from a file.**/
+
+extern int vstfx_load_state (VSTFX* vstfx, char * filename);
+
+/** Save a plugin state to a file.**/
+
+extern int vstfx_save_state (VSTFX* vstfx, char * filename);
+
+
+#endif /* __vstfx_h__ */
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 81fb700d3c..f64a325138 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -490,7 +490,20 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, bool ca
AudioPort* const ap = _io->audio (n);
assert(ap);
assert(rec_nframes <= (framecnt_t) ap->get_audio_buffer(nframes).capacity());
- memcpy (chaninfo->current_capture_buffer, ap->get_audio_buffer (nframes).data(rec_offset), sizeof (Sample) * rec_nframes);
+
+ Sample *bbuf = ap->get_audio_buffer (nframes).data(rec_offset);
+
+
+ for (jack_nframes_t _xx = 0; _xx != rec_nframes; ++_xx) {
+ if (bbuf[_xx] != 0.0) {
+ cerr << name() << " @ " << transport_frame << " + " << _xx << " = " << bbuf[_xx]
+ << endl;
+ break;
+ }
+ }
+
+
+ memcpy (chaninfo->current_capture_buffer, bbuf, sizeof (Sample) * rec_nframes);
} else {
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 89f3e94bfb..ae71817679 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -1414,13 +1414,6 @@ AudioEngine::request_buffer_size (pframes_t nframes)
return jack_set_buffer_size (_priv_jack, nframes);
}
-void
-AudioEngine::update_total_latencies ()
-{
- GET_PRIVATE_JACK_POINTER (_jack);
- jack_recompute_total_latencies (_priv_jack);
-}
-
string
AudioEngine::make_port_name_relative (string portname) const
{
diff --git a/libs/ardour/buffer_set.cc b/libs/ardour/buffer_set.cc
index 56245882d6..6061d360f9 100644
--- a/libs/ardour/buffer_set.cc
+++ b/libs/ardour/buffer_set.cc
@@ -41,6 +41,10 @@
#include "vestige/aeffectx.h"
#endif
+#ifdef LXVST_SUPPORT
+#include "ardour/vestige/aeffectx.h"
+#endif
+
namespace ARDOUR {
/** Create a new, empty BufferSet */
@@ -77,13 +81,14 @@ BufferSet::clear()
_count.reset();
_available.reset();
-#ifdef VST_SUPPORT
+#if defined VST_SUPPORT || defined LXVST_SUPPORT
for (VSTBuffers::iterator i = _vst_buffers.begin(); i != _vst_buffers.end(); ++i) {
delete *i;
}
_vst_buffers.clear ();
#endif
+
}
/** Set up this BufferSet so that its data structures mirror a PortSet's buffers.
@@ -192,7 +197,7 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac
}
#endif
-#ifdef VST_SUPPORT
+#if defined VST_SUPPORT || defined LXVST_SUPPORT
// As above but for VST
if (type == DataType::MIDI) {
while (_vst_buffers.size() < _buffers[type].size()) {
@@ -299,7 +304,7 @@ BufferSet::flush_lv2_midi(bool input, size_t i)
#endif /* LV2_SUPPORT */
-#ifdef VST_SUPPORT
+#if defined VST_SUPPORT || defined LXVST_SUPPORT
VstEvents*
BufferSet::get_vst_midi (size_t b)
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index d8f06d9a8a..48a7dc0da0 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -33,6 +33,10 @@
#include <fst.h>
#endif
+#ifdef LXVST_SUPPORT
+#include "ardour/vstfx.h"
+#endif
+
#ifdef HAVE_AUDIOUNITS
#include "ardour/audio_unit.h"
#endif
@@ -290,6 +294,9 @@ ARDOUR::init (bool use_vst, bool try_optimization)
}
Config->set_use_vst (use_vst);
+#ifdef LXVST_SUPPORT
+ Config->set_use_lxvst(true);
+#endif
Profile = new RuntimeProfile;
@@ -300,6 +307,12 @@ ARDOUR::init (bool use_vst, bool try_optimization)
}
#endif
+#ifdef LXVST_SUPPORT
+ if (Config->get_use_lxvst() && vstfx_init (0)) {
+ return -1;
+ }
+#endif
+
#ifdef HAVE_AUDIOUNITS
AUPluginInfo::load_cached_info ();
#endif
@@ -372,6 +385,10 @@ ARDOUR::cleanup ()
#ifdef VST_SUPPORT
fst_exit ();
#endif
+
+#ifdef LXVST_SUPPOR
+ vstfx_exit();
+#endif
return 0;
}
diff --git a/libs/ardour/lxvst_plugin.cc b/libs/ardour/lxvst_plugin.cc
new file mode 100755
index 0000000000..cd352dc49e
--- /dev/null
+++ b/libs/ardour/lxvst_plugin.cc
@@ -0,0 +1,830 @@
+/*
+ Copyright (C) 2004 Paul Davis
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/**********************************************************************/
+/*Native linuxVST (LXVST) variant of vst_plugin.cc etc */
+/**********************************************************************/
+
+
+#include <algorithm>
+#include <vector>
+#include <string>
+#include <cctype>
+
+#include <cstdlib>
+#include <cstdio> // so libraptor doesn't complain
+#include <cmath>
+#include <dirent.h>
+#include <cstring> // for memmove
+#include <sys/stat.h>
+#include <cerrno>
+
+#include <glibmm/miscutils.h>
+
+#include <lrdf.h>
+
+/*Include for the new native vst engine - vstfx.h*/
+
+#include <ardour/vstfx.h>
+
+#include "pbd/compose.h"
+#include "pbd/error.h"
+#include "pbd/pathscanner.h"
+#include "pbd/xml++.h"
+
+#include "ardour/session.h"
+#include "ardour/audioengine.h"
+#include "ardour/filesystem_paths.h"
+#include "ardour/lxvst_plugin.h"
+#include "ardour/buffer_set.h"
+#include "ardour/audio_buffer.h"
+#include "ardour/midi_buffer.h"
+
+#include "pbd/stl_delete.h"
+
+#include "i18n.h"
+#include <locale.h>
+
+using namespace std;
+using namespace ARDOUR;
+using namespace PBD;
+using std::min;
+using std::max;
+
+LXVSTPlugin::LXVSTPlugin (AudioEngine& e, Session& session, VSTFXHandle* h)
+ : Plugin (e, session)
+{
+ handle = h;
+
+ /*Instantiate the plugin and return a VSTFX* */
+
+ if ((_vstfx = vstfx_instantiate (handle, Session::lxvst_callback, this)) == 0)
+ {
+ throw failed_constructor();
+ }
+
+ /*Call into vstfx to get a pointer to the instance of the VST plugin*/
+
+ _plugin = _vstfx->plugin;
+ _plugin->user = this;
+
+ /* set rate and blocksize */
+
+ _plugin->dispatcher (_plugin, effSetSampleRate, 0, 0, NULL, (float) session.frame_rate());
+
+ _plugin->dispatcher (_plugin, effSetBlockSize, 0, session.get_block_size(), NULL, 0.0f);
+
+ /* set program to zero */
+
+ _plugin->dispatcher (_plugin, effSetProgram, 0, 0, NULL, 0.0f);
+
+ // Plugin::setup_controls ();
+}
+
+LXVSTPlugin::LXVSTPlugin (const LXVSTPlugin &other)
+ : Plugin (other)
+{
+ handle = other.handle;
+
+ if ((_vstfx = vstfx_instantiate (handle, Session::lxvst_callback, this)) == 0)
+ {
+ throw failed_constructor();
+ }
+ _plugin = _vstfx->plugin;
+
+ // Plugin::setup_controls ();
+}
+
+LXVSTPlugin::~LXVSTPlugin ()
+{
+ deactivate ();
+ vstfx_close (_vstfx);
+}
+
+int LXVSTPlugin::set_block_size (pframes_t nframes)
+{
+ deactivate ();
+ _plugin->dispatcher (_plugin, effSetBlockSize, 0, nframes, NULL, 0.0f);
+ activate ();
+ return 0;
+}
+
+float LXVSTPlugin::default_value (uint32_t port)
+{
+ return 0;
+}
+
+void LXVSTPlugin::set_parameter (uint32_t which, float val)
+{
+ _plugin->setParameter (_plugin, which, val);
+
+ if (_vstfx->want_program == -1 && _vstfx->want_chunk == 0)
+ {
+ /* Heinous hack: Plugin::set_parameter below updates the `modified' status of the
+ current preset, but if _vstfx->want_program is not -1 then there is a preset
+ setup pending or in progress, which we don't want any `modified' updates
+ to happen for. So we only do this if _vstfx->want_program is -1.
+ */
+ Plugin::set_parameter (which, val);
+ }
+}
+
+float LXVSTPlugin::get_parameter (uint32_t which) const
+{
+ return _plugin->getParameter (_plugin, which);
+
+}
+
+uint32_t LXVSTPlugin::nth_parameter (uint32_t n, bool& ok) const
+{
+ ok = true;
+ return n;
+}
+
+/** Get VST chunk as base64-encoded data.
+ * @param single true for single program, false for all programs.
+ * @return 0-terminated base64-encoded data; must be passed to g_free () by caller.
+ */
+gchar *LXVSTPlugin::get_chunk (bool single) const
+{
+ guchar* data;
+ int32_t data_size = _plugin->dispatcher (_plugin, 23 /* effGetChunk */, single ? 1 : 0, 0, &data, 0);
+ if (data_size == 0)
+ {
+ return 0;
+ }
+
+ return g_base64_encode (data, data_size);
+}
+
+/** Set VST chunk from base64-encoded data.
+ * @param 0-terminated base64-encoded data.
+ * @param single true for single program, false for all programs.
+ * @return 0 on success, non-0 on failure
+ */
+int LXVSTPlugin::set_chunk (gchar const * data, bool single)
+{
+ gsize size = 0;
+ guchar* raw_data = g_base64_decode (data, &size);
+ int const r = _plugin->dispatcher (_plugin, 24 /* effSetChunk */, single ? 1 : 0, size, raw_data, 0);
+ g_free (raw_data);
+ return r;
+}
+
+void LXVSTPlugin::add_state (XMLNode* root) const
+{
+ LocaleGuard lg (X_("POSIX"));
+
+ if (_vstfx->current_program != -1)
+ {
+ char buf[32];
+ snprintf (buf, sizeof (buf), "%d", _vstfx->current_program);
+ root->add_property ("current-program", buf);
+ }
+
+ if (_plugin->flags & 32 /* effFlagsProgramsChunks */)
+ {
+ gchar* data = get_chunk (false);
+ if (data == 0)
+ {
+ return;
+ }
+
+ /* store information */
+
+ XMLNode* chunk_node = new XMLNode (X_("chunk"));
+
+ chunk_node->add_content (data);
+ g_free (data);
+
+ root->add_child_nocopy (*chunk_node);
+
+ }
+ else
+ {
+ XMLNode* parameters = new XMLNode ("parameters");
+
+ for (int32_t n = 0; n < _plugin->numParams; ++n)
+ {
+ char index[64];
+ char val[32];
+ snprintf (index, sizeof (index), "param_%d", n);
+ snprintf (val, sizeof (val), "%.12g", _plugin->getParameter (_plugin, n));
+ parameters->add_property (index, val);
+ }
+
+ root->add_child_nocopy (*parameters);
+ }
+}
+
+int LXVSTPlugin::set_state (const XMLNode& node, int version)
+{
+ LocaleGuard lg (X_("POSIX"));
+
+ if (node.name() != state_node_name())
+ {
+ error << _("Bad node sent to VSTPlugin::set_state") << endmsg;
+ return 0;
+ }
+
+ const XMLProperty* prop;
+
+ if ((prop = node.property ("current-program")) != 0)
+ {
+ _vstfx->want_program = atoi (prop->value().c_str());
+ }
+
+ XMLNode* child;
+ int ret = -1;
+
+ if ((child = find_named_node (node, X_("chunk"))) != 0)
+ {
+ XMLPropertyList::const_iterator i;
+ XMLNodeList::const_iterator n;
+ int ret = -1;
+
+ for (n = child->children ().begin (); n != child->children ().end (); ++n)
+ {
+ if ((*n)->is_content ())
+ {
+ /* XXX: this may be dubious for the same reasons that we delay
+ execution of load_preset.
+ */
+ ret = set_chunk ((*n)->content().c_str(), false);
+ }
+ }
+
+ }
+ else if ((child = find_named_node (node, X_("parameters"))) != 0)
+ {
+ XMLPropertyList::const_iterator i;
+
+ for (i = child->properties().begin(); i != child->properties().end(); ++i)
+ {
+ int32_t param;
+ float val;
+
+ sscanf ((*i)->name().c_str(), "param-%d", &param); //This was param_%d (from vst_plugin) which caused all sorts of odd behaviour
+ sscanf ((*i)->value().c_str(), "%f", &val);
+
+ _plugin->setParameter (_plugin, param, val);
+ }
+
+ /* program number is not knowable */
+
+ _vstfx->current_program = -1;
+
+ ret = 0;
+ }
+
+ Plugin::set_state (node, version);
+ return ret;
+}
+
+int LXVSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc) const
+{
+ VstParameterProperties prop;
+
+ desc.min_unbound = false;
+ desc.max_unbound = false;
+ prop.flags = 0;
+
+ /* old style */
+
+ char label[64];
+ label[0] = '\0';
+
+ _plugin->dispatcher (_plugin, effGetParamName, which, 0, label, 0);
+
+ desc.label = label;
+ desc.integer_step = false;
+ desc.lower = 0.0f;
+ desc.upper = 1.0f;
+ desc.step = 0.01f;
+ desc.smallstep = 0.005f;
+ desc.largestep = 0.1f;
+ desc.toggled = false;
+ desc.logarithmic = false;
+ desc.sr_dependent = false;
+
+ return 0;
+}
+
+bool LXVSTPlugin::load_preset (PresetRecord r)
+{
+ bool s;
+
+ if (r.user)
+ {
+ s = load_user_preset (r);
+ }
+ else
+ {
+ s = load_plugin_preset (r);
+ }
+
+ if (s)
+ {
+ Plugin::load_preset (r);
+ }
+
+ return s;
+}
+
+bool LXVSTPlugin::load_plugin_preset (PresetRecord r)
+{
+ /* This is a plugin-provided preset.
+ We can't dispatch directly here; too many plugins expects only one GUI thread.
+ */
+
+ /* Extract the index of this preset from the URI */
+ int id;
+ int index;
+ int const p = sscanf (r.uri.c_str(), "VST:%d:%d", &id, &index);
+ assert (p == 2);
+
+ _vstfx->want_program = index;
+ return true;
+}
+
+bool LXVSTPlugin::load_user_preset (PresetRecord r)
+{
+ /* This is a user preset; we load it, and this code also knows about the
+ non-direct-dispatch thing.
+ */
+
+ boost::shared_ptr<XMLTree> t (presets_tree ());
+ if (t == 0)
+ {
+ return false;
+ }
+
+ XMLNode* root = t->root ();
+
+ for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i)
+ {
+ XMLProperty* uri = (*i)->property (X_("uri"));
+ XMLProperty* label = (*i)->property (X_("label"));
+
+ assert (uri);
+ assert (label);
+
+ if (label->value() != r.label)
+ {
+ continue;
+ }
+
+ if (_plugin->flags & 32 /* effFlagsProgramsChunks */)
+ {
+
+ /* Load a user preset chunk from our XML file and send it via a circuitous route to the plugin */
+
+ if (_vstfx->wanted_chunk)
+ {
+ g_free (_vstfx->wanted_chunk);
+ }
+
+ for (XMLNodeList::const_iterator j = (*i)->children().begin(); j != (*i)->children().end(); ++j)
+ {
+ if ((*j)->is_content ())
+ {
+ /* we can't dispatch directly here; too many plugins expect only one GUI thread */
+ gsize size = 0;
+ guchar* raw_data = g_base64_decode ((*j)->content().c_str(), &size);
+ _vstfx->wanted_chunk = raw_data;
+ _vstfx->wanted_chunk_size = size;
+ _vstfx->want_chunk = 1;
+ return true;
+ }
+ }
+
+ return false;
+
+ }
+ else
+ {
+ for (XMLNodeList::const_iterator j = (*i)->children().begin(); j != (*i)->children().end(); ++j)
+ {
+ if ((*j)->name() == X_("Parameter"))
+ {
+ XMLProperty* index = (*j)->property (X_("index"));
+ XMLProperty* value = (*j)->property (X_("value"));
+
+ assert (index);
+ assert (value);
+
+ set_parameter (atoi (index->value().c_str()), atof (value->value().c_str ()));
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+string LXVSTPlugin::do_save_preset (string name)
+{
+ boost::shared_ptr<XMLTree> t (presets_tree ());
+ if (t == 0)
+ {
+ return "";
+ }
+
+ XMLNode* p = 0;
+ /* XXX: use of _presets.size() + 1 for the unique ID here is dubious at best */
+ string const uri = string_compose (X_("VST:%1:%2"), unique_id (), _presets.size() + 1);
+
+ if (_plugin->flags & 32 /* effFlagsProgramsChunks */)
+ {
+
+ p = new XMLNode (X_("ChunkPreset"));
+ p->add_property (X_("uri"), uri);
+ p->add_property (X_("label"), name);
+ gchar* data = get_chunk (true);
+ p->add_content (string (data));
+ g_free (data);
+
+ }
+ else
+ {
+
+ p = new XMLNode (X_("Preset"));
+ p->add_property (X_("uri"), uri);
+ p->add_property (X_("label"), name);
+
+ for (uint32_t i = 0; i < parameter_count(); ++i)
+ {
+ if (parameter_is_input (i))
+ {
+ XMLNode* c = new XMLNode (X_("Parameter"));
+ c->add_property (X_("index"), string_compose ("%1", i));
+ c->add_property (X_("value"), string_compose ("%1", get_parameter (i)));
+ p->add_child_nocopy (*c);
+ }
+ }
+ }
+
+ t->root()->add_child_nocopy (*p);
+
+ sys::path f = ARDOUR::user_config_directory ();
+ f /= "presets";
+ f /= presets_file ();
+
+ t->write (f.to_string ());
+ return uri;
+}
+
+void LXVSTPlugin::do_remove_preset (string name)
+{
+ boost::shared_ptr<XMLTree> t (presets_tree ());
+ if (t == 0)
+ {
+ return;
+ }
+
+ t->root()->remove_nodes_and_delete (X_("label"), name);
+
+ sys::path f = ARDOUR::user_config_directory ();
+ f /= "presets";
+ f /= presets_file ();
+
+ t->write (f.to_string ());
+}
+
+string LXVSTPlugin::describe_parameter (Evoral::Parameter param)
+{
+ char name[64] = "Unkown";
+ _plugin->dispatcher (_plugin, effGetParamName, param.id(), 0, name, 0);
+ return name;
+}
+
+framecnt_t LXVSTPlugin::signal_latency () const
+{
+ if (_user_latency)
+ {
+ return _user_latency;
+ }
+
+#ifdef VESTIGE_HEADER
+ return *((framecnt_t *) (((char *) &_plugin->flags) + 12)); /* initialDelay */
+#else
+ return _plugin->initial_delay;
+#endif
+}
+
+set<Evoral::Parameter> LXVSTPlugin::automatable () const
+{
+ set<Evoral::Parameter> ret;
+
+ for (uint32_t i = 0; i < parameter_count(); ++i)
+ {
+ ret.insert (ret.end(), Evoral::Parameter(PluginAutomation, 0, i));
+ }
+
+ return ret;
+}
+
+int LXVSTPlugin::connect_and_run (BufferSet& bufs,
+ ChanMapping in_map, ChanMapping out_map,
+ pframes_t nframes, framecnt_t offset)
+{
+ Plugin::connect_and_run (bufs, in_map, out_map, nframes, offset);
+
+ float *ins[_plugin->numInputs];
+ float *outs[_plugin->numOutputs];
+ int32_t i;
+
+ const uint32_t nbufs = bufs.count().n_audio();
+
+ int in_index = 0;
+ for (i = 0; i < (int32_t) _plugin->numInputs; ++i)
+ {
+ ins[i] = bufs.get_audio(min((uint32_t) in_index, nbufs - 1)).data() + offset;
+ in_index++;
+ }
+
+ int out_index = 0;
+ for (i = 0; i < (int32_t) _plugin->numOutputs; ++i)
+ {
+ outs[i] = bufs.get_audio(min((uint32_t) out_index, nbufs - 1)).data() + offset;
+ out_index++;
+ }
+
+ if (bufs.count().n_midi() > 0)
+ {
+ VstEvents* v = bufs.get_vst_midi (0);
+ _plugin->dispatcher (_plugin, effProcessEvents, 0, 0, v, 0);
+ }
+
+ /* we already know it can support processReplacing */
+
+#ifdef LXVST_32BIT
+ _plugin->processReplacing (_plugin, ins, outs, nframes);
+#endif
+
+#if defined LXVST_64BIT && defined VESTIGE_HEADER
+
+ /*Vestige doesn't work for 64Bit - some of the AEffect struct member types
+ appear not to be correct which throws the data alignment. We have two choices
+
+ 1) Fix Vestige - preferable from a technical standpoint, but perhaps
+ not viable without affecting its 'clean room' status
+
+ 2) Correct for the alignment error - a bit of a kludge, but it can work,
+ assuming the following data types / sizes on x86-64
+
+ char 1Byte : Byte aligned
+ int 4Bytes : 4Byte aligned
+ long 8Bytes : 8Byte aligned
+ pointers 8Bytes : 8Byte aligned
+
+ This gives an offset of 8 Bytes - inclusive of padding
+ to translate to the correct address for processReplacing*/
+
+ ((AEffect*)(((char*)(_plugin)) + 8))->processReplacing(_plugin, ins, outs, nframes);
+
+#elif defined LXVST_64BIT
+
+ _plugin->processReplacing(_plugin, ins, outs, nframes);
+
+#endif
+
+ return 0;
+}
+
+void LXVSTPlugin::deactivate ()
+{
+ _plugin->dispatcher (_plugin, effMainsChanged, 0, 0, NULL, 0.0f);
+}
+
+void LXVSTPlugin::activate ()
+{
+ _plugin->dispatcher (_plugin, effMainsChanged, 0, 1, NULL, 0.0f);
+}
+
+string LXVSTPlugin::unique_id() const
+{
+ char buf[32];
+
+#if defined LXVST_64BIT && defined VESTIGE_HEADER
+
+ /*The vestige header appears not to have correct data
+ alignment in AEffect struct for 64Bit, possibly due
+ to incorrect data types - see previous comments*/
+
+ snprintf (buf, sizeof (buf), "%d", *((int32_t*) &((AEffect*)(((char*)(_plugin)) + 12))->unused_id));
+
+#elif defined LXVST_32BIT && defined VESTIGE_HEADER
+
+ snprintf (buf, sizeof (buf), "%d", *((int32_t*) &_plugin->unused_id));
+
+#else
+
+ snprintf (buf, sizeof (buf), "%d", _plugin->uniqueID);
+
+#endif
+
+ return string (buf);
+}
+
+
+const char * LXVSTPlugin::name () const
+{
+ return handle->name;
+}
+
+const char * LXVSTPlugin::maker () const
+{
+ return _info->creator.c_str();
+}
+
+const char * LXVSTPlugin::label () const
+{
+ return handle->name;
+}
+
+uint32_t LXVSTPlugin::parameter_count() const
+{
+ return _plugin->numParams;
+}
+
+bool LXVSTPlugin::has_editor () const
+{
+ return _plugin->flags & effFlagsHasEditor;
+}
+
+void LXVSTPlugin::print_parameter (uint32_t param, char *buf, uint32_t len) const
+{
+ char *first_nonws;
+
+ _plugin->dispatcher (_plugin, 7 /* effGetParamDisplay */, param, 0, buf, 0);
+
+ if (buf[0] == '\0')
+ {
+ return;
+ }
+
+ first_nonws = buf;
+ while (*first_nonws && isspace (*first_nonws))
+ {
+ first_nonws++;
+ }
+ if (*first_nonws == '\0')
+ {
+ return;
+ }
+
+ memmove (buf, first_nonws, strlen (buf) - (first_nonws - buf) + 1);
+}
+
+PluginPtr LXVSTPluginInfo::load (Session& session)
+{
+ try {
+ PluginPtr plugin;
+
+ if (Config->get_use_lxvst())
+ {
+ VSTFXHandle* handle;
+
+ handle = vstfx_load(path.c_str());
+
+ if (handle == NULL)
+ {
+ error << string_compose(_("LXVST: cannot load module from \"%1\""), path) << endmsg;
+ }
+ else
+ {
+ plugin.reset (new LXVSTPlugin (session.engine(), session, handle));
+ }
+ }
+ else
+ {
+ error << _("You asked ardour to not use any LXVST plugins") << endmsg;
+ return PluginPtr ((Plugin*) 0);
+ }
+
+ plugin->set_info(PluginInfoPtr(new LXVSTPluginInfo(*this)));
+ return plugin;
+ }
+
+ catch (failed_constructor &err)
+ {
+ return PluginPtr ((Plugin*) 0);
+ }
+}
+
+void LXVSTPlugin::find_presets ()
+{
+ /* Built-in presets */
+
+ int const vst_version = _plugin->dispatcher (_plugin, effGetVstVersion, 0, 0, NULL, 0);
+ for (int i = 0; i < _plugin->numPrograms; ++i)
+ {
+ PresetRecord r (string_compose (X_("LXVST:%1:%2"), unique_id (), i), "", false);
+
+ if (vst_version >= 2)
+ {
+ char buf[256];
+ if (_plugin->dispatcher (_plugin, 29, i, 0, buf, 0) == 1)
+ {
+ r.label = buf;
+ }
+ else
+ {
+ r.label = string_compose (_("Preset %1"), i);
+ }
+ }
+ else
+ {
+ r.label = string_compose (_("Preset %1"), i);
+ }
+
+ _presets.insert (make_pair (r.uri, r));
+ }
+
+ /* User presets from our XML file */
+
+ boost::shared_ptr<XMLTree> t (presets_tree ());
+
+ if (t)
+ {
+ XMLNode* root = t->root ();
+ for (XMLNodeList::const_iterator i = root->children().begin(); i != root->children().end(); ++i)
+ {
+ XMLProperty* uri = (*i)->property (X_("uri"));
+ XMLProperty* label = (*i)->property (X_("label"));
+
+ assert (uri);
+ assert (label);
+
+ PresetRecord r (uri->value(), label->value(), true);
+ _presets.insert (make_pair (r.uri, r));
+ }
+ }
+}
+
+/** @return XMLTree with our user presets; could be a new one if no existing
+ * one was found, or 0 if one was present but badly-formatted.
+ */
+XMLTree * LXVSTPlugin::presets_tree () const
+{
+ XMLTree* t = new XMLTree;
+
+ sys::path p = ARDOUR::user_config_directory ();
+ p /= "presets";
+
+ if (!is_directory (p))
+ {
+ create_directory (p);
+ }
+
+ p /= presets_file ();
+
+ if (!exists (p))
+ {
+ t->set_root (new XMLNode (X_("LXVSTPresets")));
+ return t;
+ }
+
+ t->set_filename (p.to_string ());
+ if (!t->read ())
+ {
+ delete t;
+ return 0;
+ }
+
+ return t;
+}
+
+/** @return Index of the first user preset in our lists */
+int LXVSTPlugin::first_user_preset_index () const
+{
+ return _plugin->numPrograms;
+}
+
+string LXVSTPlugin::presets_file () const
+{
+ return string_compose ("lxvst-%1", unique_id ());
+}
+
+LXVSTPluginInfo::LXVSTPluginInfo()
+{
+ type = ARDOUR::LXVST;
+}
+
diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc
index 90e9146af1..153c624a5a 100644
--- a/libs/ardour/plugin.cc
+++ b/libs/ardour/plugin.cc
@@ -139,6 +139,12 @@ ARDOUR::find_plugin(Session& session, string identifier, PluginType type)
break;
#endif
+#ifdef LXVST_SUPPORT
+ case ARDOUR::LXVST:
+ plugs = mgr->lxvst_plugin_info();
+ break;
+#endif
+
#ifdef HAVE_AUDIOUNITS
case ARDOUR::AudioUnit:
plugs = mgr->au_plugin_info();
@@ -170,6 +176,19 @@ ARDOUR::find_plugin(Session& session, string identifier, PluginType type)
}
#endif
+#ifdef LXVST_SUPPORT
+ /* hmm, we didn't find it. could be because in older versions of Ardour.
+ we used to store the name of a VST plugin, not its unique ID. so try
+ again.
+ */
+
+ for (i = plugs.begin(); i != plugs.end(); ++i) {
+ if (identifier == (*i)->name){
+ return (*i)->load (session);
+ }
+ }
+#endif
+
return PluginPtr ((Plugin*) 0);
}
diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc
index 268d551116..0260f7d3aa 100644
--- a/libs/ardour/plugin_insert.cc
+++ b/libs/ardour/plugin_insert.cc
@@ -45,6 +45,10 @@
#include "ardour/vst_plugin.h"
#endif
+#ifdef LXVST_SUPPORT
+#include "ardour/lxvst_plugin.h"
+#endif
+
#ifdef HAVE_AUDIOUNITS
#include "ardour/audio_unit.h"
#endif
@@ -570,6 +574,9 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
#ifdef VST_SUPPORT
boost::shared_ptr<VSTPlugin> vp;
#endif
+#ifdef LXVST_SUPPORT
+ boost::shared_ptr<LXVSTPlugin> lxvp;
+#endif
#ifdef HAVE_AUDIOUNITS
boost::shared_ptr<AUPlugin> ap;
#endif
@@ -584,6 +591,10 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
} else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
#endif
+#ifdef LXVST_SUPPORT
+ } else if ((lxvp = boost::dynamic_pointer_cast<LXVSTPlugin> (other)) != 0) {
+ return boost::shared_ptr<Plugin> (new LXVSTPlugin (*lxvp));
+#endif
#ifdef HAVE_AUDIOUNITS
} else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
@@ -852,6 +863,8 @@ PluginInsert::set_state(const XMLNode& node, int version)
type = ARDOUR::LV2;
} else if (prop->value() == X_("vst")) {
type = ARDOUR::VST;
+ } else if (prop->value() == X_("lxvst")) {
+ type = ARDOUR::LXVST;
} else if (prop->value() == X_("audiounit")) {
type = ARDOUR::AudioUnit;
} else {
@@ -872,6 +885,14 @@ PluginInsert::set_state(const XMLNode& node, int version)
prop = node.property ("id");
}
#endif
+
+#ifdef LXVST_SUPPORT
+ /*There shouldn't be any older sessions with linuxVST support.. but anyway..*/
+
+ if (type == ARDOUR::LXVST) {
+ prop = node.property ("id");
+ }
+#endif
/* recheck */
if (prop == 0) {
diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc
index 912fc20dcd..6279140795 100644
--- a/libs/ardour/plugin_manager.cc
+++ b/libs/ardour/plugin_manager.cc
@@ -36,6 +36,12 @@
#include <cstring>
#endif // VST_SUPPORT
+#ifdef LXVST_SUPPORT
+#include <ardour/vstfx.h>
+#include <pbd/basename.h>
+#include <cstring>
+#endif //LXVST_SUPPORT
+
#include <glibmm/miscutils.h>
#include "pbd/pathscanner.h"
@@ -56,6 +62,10 @@
#include "ardour/vst_plugin.h"
#endif
+#ifdef LXVST_SUPPORT
+#include "ardour/lxvst_plugin.h"
+#endif
+
#ifdef HAVE_AUDIOUNITS
#include "ardour/audio_unit.h"
#include <Carbon/Carbon.h>
@@ -74,6 +84,7 @@ PluginManager* PluginManager::_manager = 0;
PluginManager::PluginManager ()
: _vst_plugin_info(0)
+ , _lxvst_plugin_info(0)
, _ladspa_plugin_info(0)
, _lv2_plugin_info(0)
, _au_plugin_info(0)
@@ -107,6 +118,12 @@ PluginManager::PluginManager ()
}
#endif /* VST_SUPPORT */
+#ifdef LXVST_SUPPORT
+ if (Config->get_use_lxvst()) {
+ add_lxvst_presets();
+ }
+#endif /* Native LinuxVST support*/
+
if ((s = getenv ("LADSPA_PATH"))) {
ladspa_path = s;
}
@@ -117,6 +134,12 @@ PluginManager::PluginManager ()
vst_path = s;
}
+ if ((s = getenv ("LXVST_PATH"))) {
+ vst_path = s;
+ } else if ((s = getenv ("LXVST_PLUGINS"))) {
+ vst_path = s;
+ }
+
if (_manager == 0) {
_manager = this;
}
@@ -154,6 +177,13 @@ PluginManager::refresh ()
vst_refresh ();
}
#endif // VST_SUPPORT
+
+#ifdef LXVST_SUPPORT
+ if(Config->get_use_lxvst()) {
+ lxvst_refresh();
+ }
+#endif //Native linuxVST SUPPORT
+
#ifdef HAVE_AUDIOUNITS
au_refresh ();
#endif
@@ -268,6 +298,13 @@ PluginManager::add_vst_presets()
{
add_presets ("vst");
}
+
+void
+PluginManager::add_lxvst_presets()
+{
+ add_presets ("lxvst");
+}
+
void
PluginManager::add_presets(string domain)
{
@@ -586,6 +623,111 @@ PluginManager::vst_discover (string path)
#endif // VST_SUPPORT
+#ifdef LXVST_SUPPORT
+
+void
+PluginManager::lxvst_refresh ()
+{
+ if (_lxvst_plugin_info)
+ _lxvst_plugin_info->clear ();
+ else
+ _lxvst_plugin_info = new ARDOUR::PluginInfoList();
+
+ if (lxvst_path.length() == 0) {
+ lxvst_path = "/usr/local/lib/lxvst:/usr/lib/lxvst";
+ }
+
+ lxvst_discover_from_path (lxvst_path);
+}
+
+int
+PluginManager::add_lxvst_directory (string path)
+{
+ if (lxvst_discover_from_path (path) == 0) {
+ lxvst_path += ':';
+ lxvst_path += path;
+ return 0;
+ }
+ return -1;
+}
+
+static bool lxvst_filter (const string& str, void *arg)
+{
+ /* Not a dotfile, has a prefix before a period, suffix is "so" */
+
+ return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
+}
+
+int
+PluginManager::lxvst_discover_from_path (string path)
+{
+ PathScanner scanner;
+ vector<string *> *plugin_objects;
+ vector<string *>::iterator x;
+ int ret = 0;
+
+ info << "Discovering linuxVST plugins along " << path << endmsg;
+
+ plugin_objects = scanner (lxvst_path, lxvst_filter, 0, true, true);
+
+ if (plugin_objects) {
+ for (x = plugin_objects->begin(); x != plugin_objects->end (); ++x) {
+ lxvst_discover (**x);
+ }
+ }
+
+ info << "Done linuxVST discover" << endmsg;
+
+ vector_delete (plugin_objects);
+ return ret;
+}
+
+int
+PluginManager::lxvst_discover (string path)
+{
+ VSTFXInfo* finfo;
+ char buf[32];
+
+ if ((finfo = vstfx_get_info (const_cast<char *> (path.c_str()))) == 0) {
+ warning << "Cannot get linuxVST information from " << path << endmsg;
+ return -1;
+ }
+
+ if (!finfo->canProcessReplacing) {
+ warning << string_compose (_("linuxVST plugin %1 does not support processReplacing, and so cannot be used in ardour at this time"),
+ finfo->name)
+ << endl;
+ }
+
+ PluginInfoPtr info(new LXVSTPluginInfo);
+
+ if (!strcasecmp ("The Unnamed plugin", finfo->name)) {
+ info->name = PBD::basename_nosuffix (path);
+ } else {
+ info->name = finfo->name;
+ }
+
+
+ snprintf (buf, sizeof (buf), "%d", finfo->UniqueID);
+ info->unique_id = buf;
+ info->category = "linuxVSTs";
+ info->path = path;
+ info->creator = finfo->creator;
+ info->index = 0;
+ info->n_inputs.set_audio (finfo->numInputs);
+ info->n_outputs.set_audio (finfo->numOutputs);
+ info->n_inputs.set_midi (finfo->wantMidi ? 1 : 0);
+ info->type = ARDOUR::LXVST;
+
+ _lxvst_plugin_info->push_back (info);
+ vstfx_free_info (finfo);
+
+ return 0;
+}
+
+#endif // LXVST_SUPPORT
+
+
PluginManager::PluginStatusType
PluginManager::get_status (const PluginInfoPtr& pi)
{
@@ -625,6 +767,9 @@ PluginManager::save_statuses ()
case VST:
ofs << "VST";
break;
+ case LXVST:
+ ofs << "LXVST";
+ break;
}
ofs << ' ';
@@ -709,6 +854,8 @@ PluginManager::load_statuses ()
type = LV2;
} else if (stype == "VST") {
type = VST;
+ } else if (stype == "LXVST") {
+ type = LXVST;
} else {
error << string_compose (_("unknown plugin type \"%1\" - ignored"), stype)
<< endmsg;
@@ -749,6 +896,18 @@ PluginManager::vst_plugin_info ()
}
ARDOUR::PluginInfoList&
+PluginManager::lxvst_plugin_info ()
+{
+#ifdef LXVST_SUPPORT
+ if (!_lxvst_plugin_info)
+ lxvst_refresh();
+ return *_lxvst_plugin_info;
+#else
+ return _empty_plugin_info;
+#endif
+}
+
+ARDOUR::PluginInfoList&
PluginManager::ladspa_plugin_info ()
{
if (!_ladspa_plugin_info)
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 06ca70c9e9..11f510126a 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -970,6 +970,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
prop->value() == "vst" ||
+ prop->value() == "lxvst" ||
prop->value() == "audiounit") {
processor.reset (new PluginInsert (_session));
@@ -2382,6 +2383,7 @@ Route::set_processor_state (const XMLNode& node)
} else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
prop->value() == "lv2" ||
prop->value() == "vst" ||
+ prop->value() == "lxvst" ||
prop->value() == "audiounit") {
processor.reset (new PluginInsert(_session));
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index c5b32b943b..d5eb687497 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -685,6 +685,8 @@ Session::hookup_io ()
/* Tell all IO objects to connect themselves together */
+ cerr << "Enable IO connections, state = " << _state_of_the_state << endl;
+
IO::enable_connecting ();
MIDI::Port::MakeConnections ();
@@ -4336,6 +4338,7 @@ Session::update_latency (bool playback)
if (playback) {
/* reverse the list so that we work backwards from the last route to run to the first */
reverse (r->begin(), r->end());
+ cerr << "\n!!! I JUST REVERSED THE ROUTE LIST (" << r->size() << ")!!!\n\n";
}
/* compute actual latency values for the given direction and store them all in per-port
@@ -4378,14 +4381,15 @@ Session::post_playback_latency ()
set_worst_playback_latency ();
boost::shared_ptr<RouteList> r = routes.reader ();
+
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->is_hidden() && ((*i)->active())) {
_worst_track_latency = max (_worst_track_latency, (*i)->update_signal_latency ());
}
+ }
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- (*i)->set_latency_compensation (_worst_track_latency);
- }
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ (*i)->set_latency_compensation (_worst_track_latency);
}
}
@@ -4485,15 +4489,6 @@ Session::update_latency_compensation (bool force_whole_graph)
DEBUG_TRACE (DEBUG::Latency, string_compose ("worst signal processing latency: %1 (changed ? %2)\n", _worst_track_latency,
(some_track_latency_changed ? "yes" : "no")));
- if (force_whole_graph || some_track_latency_changed) {
- /* trigger a full recompute of latency numbers for the graph.
- everything else that we need to do will be done in the latency
- callback.
- */
- _engine.update_total_latencies ();
- return; // everything else will be done in the latency callback
- }
-
DEBUG_TRACE(DEBUG::Latency, "---------------------------- DONE update latency compensation\n\n")
}
diff --git a/libs/ardour/session_lxvst.cc b/libs/ardour/session_lxvst.cc
new file mode 100755
index 0000000000..17c81e753f
--- /dev/null
+++ b/libs/ardour/session_lxvst.cc
@@ -0,0 +1,364 @@
+/*
+ Copyright (C) 2004
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/******************************************************/
+/*The big 'audio master' callback for linuxVST plugins*/
+/******************************************************/
+
+
+#include <stdbool.h>
+#include <cstdio>
+
+#include <ardour/vstfx.h>
+#include <ardour/vestige/aeffectx.h>
+
+#include <ardour/session.h>
+#include <ardour/tempo.h>
+#include <ardour/lxvst_plugin.h>
+
+#include "i18n.h"
+
+#define DEBUG_CALLBACKS
+static int debug_callbacks = -1;
+
+#ifdef DEBUG_CALLBACKS
+#define SHOW_CALLBACK if (debug_callbacks) printf
+#else
+#define SHOW_CALLBACK(...)
+#endif
+
+using namespace ARDOUR;
+
+long Session::lxvst_callback (AEffect* effect,
+ long opcode,
+ long index,
+ long value,
+ void* ptr,
+ float opt)
+{
+ static VstTimeInfo _timeInfo;
+ LXVSTPlugin* plug;
+ Session* session;
+
+ if (debug_callbacks < 0)
+ {
+ debug_callbacks = (getenv ("ARDOUR_DEBUG_VST_CALLBACKS") != 0);
+ }
+
+ if (effect && effect->user)
+ {
+ plug = (LXVSTPlugin*) (effect->user);
+ session = &plug->session();
+ SHOW_CALLBACK ("am callback 0x%x, opcode = %ld, plugin = \"%s\" ", (unsigned int)pthread_self(), opcode, plug->name());
+ }
+ else
+ {
+ plug = 0;
+ session = 0;
+ SHOW_CALLBACK ("am callback 0x%x, opcode = %ld", (unsigned int)pthread_self(), opcode);
+ }
+
+ switch(opcode){
+
+ case audioMasterAutomate:
+ SHOW_CALLBACK ("amc: audioMasterAutomate\n");
+
+ // index, value, returns 0
+ if (effect) {
+ effect->setParameter (effect, index, opt);
+ }
+ return 0;
+
+ case audioMasterVersion:
+ SHOW_CALLBACK ("amc: audioMasterVersion\n");
+ // vst version, currently 2 (0 for older)
+ return 2;
+
+ case audioMasterCurrentId:
+ SHOW_CALLBACK ("amc: audioMasterCurrentId\n");
+ // returns the unique id of a plug that's currently
+ // loading
+ return 0;
+
+ case audioMasterIdle:
+ SHOW_CALLBACK ("amc: audioMasterIdle\n");
+ // call application idle routine (this will
+ // call effEditIdle for all open editors too)
+ if (effect) {
+ effect->dispatcher(effect, effEditIdle, 0, 0, NULL, 0.0f);
+ }
+ return 0;
+
+ case audioMasterPinConnected:
+ SHOW_CALLBACK ("amc: audioMasterPinConnected\n");
+ // inquire if an input or output is beeing connected;
+ // index enumerates input or output counting from zero:
+ // value is 0 for input and != 0 otherwise. note: the
+ // return value is 0 for <true> such that older versions
+ // will always return true.
+ return 1;
+
+ case audioMasterWantMidi:
+ SHOW_CALLBACK ("amc: audioMasterWantMidi\n");
+ // <value> is a filter which is currently ignored
+ return 0;
+
+ case audioMasterGetTime:
+ SHOW_CALLBACK ("amc: audioMasterGetTime\n");
+ // returns const VstTimeInfo* (or 0 if not supported)
+ // <value> should contain a mask indicating which fields are required
+ // (see valid masks above), as some items may require extensive
+ // conversions
+ memset(&_timeInfo, 0, sizeof(_timeInfo));
+ if (session) {
+ _timeInfo.samplePos = session->transport_frame();
+ _timeInfo.sampleRate = session->frame_rate();
+ _timeInfo.flags = 0;
+
+ if (value & (kVstTempoValid)) {
+ const Tempo& t (session->tempo_map().tempo_at (session->transport_frame()));
+ _timeInfo.tempo = t.beats_per_minute ();
+ _timeInfo.flags |= (kVstTempoValid);
+ }
+ if (value & (kVstBarsValid)) {
+ const Meter& m (session->tempo_map().meter_at (session->transport_frame()));
+ _timeInfo.timeSigNumerator = m.beats_per_bar ();
+ _timeInfo.timeSigDenominator = m.note_divisor ();
+ _timeInfo.flags |= (kVstBarsValid);
+ }
+
+ if (session->transport_speed() != 0.0f) {
+ _timeInfo.flags |= kVstTransportPlaying;
+ }
+ }
+
+ return (long)&_timeInfo;
+
+ case audioMasterProcessEvents:
+ SHOW_CALLBACK ("amc: audioMasterProcessEvents\n");
+ // VstEvents* in <ptr>
+ return 0;
+
+ case audioMasterSetTime:
+ SHOW_CALLBACK ("amc: audioMasterSetTime\n");
+ // VstTimenfo* in <ptr>, filter in <value>, not supported
+
+ case audioMasterTempoAt:
+ SHOW_CALLBACK ("amc: audioMasterTempoAt\n");
+ // returns tempo (in bpm * 10000) at sample frame location passed in <value>
+ if (session) {
+ const Tempo& t (session->tempo_map().tempo_at (value));
+ return t.beats_per_minute() * 1000;
+ } else {
+ return 0;
+ }
+ break;
+
+ case audioMasterGetNumAutomatableParameters:
+ SHOW_CALLBACK ("amc: audioMasterGetNumAutomatableParameters\n");
+ return 0;
+
+ case audioMasterGetParameterQuantization:
+ SHOW_CALLBACK ("amc: audioMasterGetParameterQuantization\n");
+ // returns the integer value for +1.0 representation,
+ // or 1 if full single float precision is maintained
+ // in automation. parameter index in <value> (-1: all, any)
+ return 0;
+
+ case audioMasterIOChanged:
+ SHOW_CALLBACK ("amc: audioMasterIOChanged\n");
+ // numInputs and/or numOutputs has changed
+ return 0;
+
+ case audioMasterNeedIdle:
+ SHOW_CALLBACK ("amc: audioMasterNeedIdle\n");
+ // plug needs idle calls (outside its editor window)
+ if (plug) {
+ plug->vstfx()->wantIdle = 1;
+ }
+ return 0;
+
+ case audioMasterSizeWindow:
+ SHOW_CALLBACK ("amc: audioMasterSizeWindow\n");
+ // index: width, value: height
+ return 0;
+
+ case audioMasterGetSampleRate:
+ SHOW_CALLBACK ("amc: audioMasterGetSampleRate\n");
+ if (session) {
+ return session->frame_rate();
+ }
+ return 0;
+
+ case audioMasterGetBlockSize:
+ SHOW_CALLBACK ("amc: audioMasterGetBlockSize\n");
+ if (session) {
+ return session->get_block_size();
+ }
+ return 0;
+
+ case audioMasterGetInputLatency:
+ SHOW_CALLBACK ("amc: audioMasterGetInputLatency\n");
+ return 0;
+
+ case audioMasterGetOutputLatency:
+ SHOW_CALLBACK ("amc: audioMasterGetOutputLatency\n");
+ return 0;
+
+ case audioMasterGetPreviousPlug:
+ SHOW_CALLBACK ("amc: audioMasterGetPreviousPlug\n");
+ // input pin in <value> (-1: first to come), returns cEffect*
+ return 0;
+
+ case audioMasterGetNextPlug:
+ SHOW_CALLBACK ("amc: audioMasterGetNextPlug\n");
+ // output pin in <value> (-1: first to come), returns cEffect*
+
+ case audioMasterWillReplaceOrAccumulate:
+ SHOW_CALLBACK ("amc: audioMasterWillReplaceOrAccumulate\n");
+ // returns: 0: not supported, 1: replace, 2: accumulate
+ return 0;
+
+ case audioMasterGetCurrentProcessLevel:
+ SHOW_CALLBACK ("amc: audioMasterGetCurrentProcessLevel\n");
+ // returns: 0: not supported,
+ // 1: currently in user thread (gui)
+ // 2: currently in audio thread (where process is called)
+ // 3: currently in 'sequencer' thread (midi, timer etc)
+ // 4: currently offline processing and thus in user thread
+ // other: not defined, but probably pre-empting user thread.
+ return 0;
+
+ case audioMasterGetAutomationState:
+ SHOW_CALLBACK ("amc: audioMasterGetAutomationState\n");
+ // returns 0: not supported, 1: off, 2:read, 3:write, 4:read/write
+ // offline
+ return 0;
+
+ case audioMasterOfflineStart:
+ SHOW_CALLBACK ("amc: audioMasterOfflineStart\n");
+ case audioMasterOfflineRead:
+ SHOW_CALLBACK ("amc: audioMasterOfflineRead\n");
+ // ptr points to offline structure, see below. return 0: error, 1 ok
+ return 0;
+
+ case audioMasterOfflineWrite:
+ SHOW_CALLBACK ("amc: audioMasterOfflineWrite\n");
+ // same as read
+ return 0;
+
+ case audioMasterOfflineGetCurrentPass:
+ SHOW_CALLBACK ("amc: audioMasterOfflineGetCurrentPass\n");
+ case audioMasterOfflineGetCurrentMetaPass:
+ SHOW_CALLBACK ("amc: audioMasterOfflineGetCurrentMetaPass\n");
+ return 0;
+
+ case audioMasterSetOutputSampleRate:
+ SHOW_CALLBACK ("amc: audioMasterSetOutputSampleRate\n");
+ // for variable i/o, sample rate in <opt>
+ return 0;
+
+ case audioMasterGetSpeakerArrangement:
+ SHOW_CALLBACK ("amc: audioMasterGetSpeakerArrangement\n");
+ // (long)input in <value>, output in <ptr>
+ return 0;
+
+ case audioMasterGetVendorString:
+ SHOW_CALLBACK ("amc: audioMasterGetVendorString\n");
+ // fills <ptr> with a string identifying the vendor (max 64 char)
+ strcpy ((char*) ptr, "Linux Audio Systems");
+ return 0;
+
+ case audioMasterGetProductString:
+ SHOW_CALLBACK ("amc: audioMasterGetProductString\n");
+ // fills <ptr> with a string with product name (max 64 char)
+ strcpy ((char*) ptr, "Ardour");
+ return 0;
+
+ case audioMasterGetVendorVersion:
+ SHOW_CALLBACK ("amc: audioMasterGetVendorVersion\n");
+ // returns vendor-specific version
+ return 900;
+
+ case audioMasterVendorSpecific:
+ SHOW_CALLBACK ("amc: audioMasterVendorSpecific\n");
+ // no definition, vendor specific handling
+ return 0;
+
+ case audioMasterSetIcon:
+ SHOW_CALLBACK ("amc: audioMasterSetIcon\n");
+ // void* in <ptr>, format not defined yet
+ return 0;
+
+ case audioMasterCanDo:
+ SHOW_CALLBACK ("amc: audioMasterCanDo\n");
+ // string in ptr, see below
+ return 0;
+
+ case audioMasterGetLanguage:
+ SHOW_CALLBACK ("amc: audioMasterGetLanguage\n");
+ // see enum
+ return 0;
+
+ case audioMasterOpenWindow:
+ SHOW_CALLBACK ("amc: audioMasterOpenWindow\n");
+ // returns platform specific ptr
+ return 0;
+
+ case audioMasterCloseWindow:
+ SHOW_CALLBACK ("amc: audioMasterCloseWindow\n");
+ // close window, platform specific handle in <ptr>
+ return 0;
+
+ case audioMasterGetDirectory:
+ SHOW_CALLBACK ("amc: audioMasterGetDirectory\n");
+ // get plug directory, FSSpec on MAC, else char*
+ return 0;
+
+ case audioMasterUpdateDisplay:
+ SHOW_CALLBACK ("amc: audioMasterUpdateDisplay\n");
+ // something has changed, update 'multi-fx' display
+ if (effect) {
+ effect->dispatcher(effect, effEditIdle, 0, 0, NULL, 0.0f);
+ }
+ return 0;
+
+ case audioMasterBeginEdit:
+ SHOW_CALLBACK ("amc: audioMasterBeginEdit\n");
+ // begin of automation session (when mouse down), parameter index in <index>
+ return 0;
+
+ case audioMasterEndEdit:
+ SHOW_CALLBACK ("amc: audioMasterEndEdit\n");
+ // end of automation session (when mouse up), parameter index in <index>
+ return 0;
+
+ case audioMasterOpenFileSelector:
+ SHOW_CALLBACK ("amc: audioMasterOpenFileSelector\n");
+ // open a fileselector window with VstFileSelect* in <ptr>
+ return 0;
+
+ default:
+ SHOW_CALLBACK ("LXVST master dispatcher: undefed: %d\n", (int)opcode);
+ break;
+ }
+
+ return 0;
+}
+
diff --git a/libs/ardour/sndfile_helpers.cc b/libs/ardour/sndfile_helpers.cc
index aa54f648a5..07281e6901 100644
--- a/libs/ardour/sndfile_helpers.cc
+++ b/libs/ardour/sndfile_helpers.cc
@@ -92,55 +92,32 @@ int sndfile_endian_formats[SNDFILE_ENDIAN_FORMATS] = {
};
int
-sndfile_header_format_from_string (string str)
+sndfile_header_format_by_index (int index)
{
- for (int n = 0; sndfile_header_formats_strings[n]; ++n) {
- if (str == sndfile_header_formats_strings[n]) {
- return sndfile_header_formats[n];
- }
+ if (index >= 0 && index < SNDFILE_HEADER_FORMATS) {
+ return sndfile_header_formats[index];
}
return -1;
}
int
-sndfile_bitdepth_format_from_string (string str)
+sndfile_bitdepth_format_by_index (int index)
{
- for (int n = 0; sndfile_bitdepth_formats_strings[n]; ++n) {
- if (str == sndfile_bitdepth_formats_strings[n]) {
- return sndfile_bitdepth_formats[n];
- }
+ if (index >= 0 && index < SNDFILE_BITDEPTH_FORMATS) {
+ return sndfile_bitdepth_formats[index];
}
return -1;
}
int
-sndfile_endian_format_from_string (string str)
+sndfile_endian_format_by_index (int index)
{
- for (int n = 0; sndfile_endian_formats_strings[n]; ++n) {
- if (str == sndfile_endian_formats_strings[n]) {
- return sndfile_endian_formats[n];
- }
+ if (index >= 0 && index < SNDFILE_ENDIAN_FORMATS) {
+ return sndfile_endian_formats[index];
}
return -1;
}
-string
-sndfile_file_ending_from_string (string str)
-{
- static vector<string> file_endings;
-
- if (file_endings.empty()) {
- file_endings = I18N((const char **) sndfile_file_endings_strings);
- }
-
- for (int n = 0; sndfile_header_formats_strings[n]; ++n) {
- if (str == sndfile_header_formats_strings[n]) {
- return file_endings[n];
- }
- }
- return 0;
-}
-
int
sndfile_data_width (int format)
{
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index 3a5ea0084a..c86f62de0b 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -75,7 +75,7 @@ legalize_for_path (const string& str)
pos += 1;
}
- return legal;
+ return string (legal);
}
string
diff --git a/libs/ardour/vstfx.cc b/libs/ardour/vstfx.cc
new file mode 100755
index 0000000000..8c5192eb22
--- /dev/null
+++ b/libs/ardour/vstfx.cc
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <ardour/vstfx.h>
+
+/***********************************************************/
+/* VSTFX - A set of modules for managing linux VST plugins */
+/* vstfx.cc, vstfxwin.cc and vstfxinfofile.cc */
+/***********************************************************/
+
+
+/*Simple error handler stuff for VSTFX*/
+
+void vstfx_error (const char *fmt, ...)
+{
+ va_list ap;
+ char buffer[512];
+
+ va_start (ap, fmt);
+ vsnprintf (buffer, sizeof(buffer), fmt, ap);
+ vstfx_error_callback (buffer);
+ va_end (ap);
+}
+
+/*default error handler callback*/
+
+void default_vstfx_error_callback (const char *desc)
+{
+ fprintf(stderr, "%s\n", desc);
+}
+
+void (*vstfx_error_callback)(const char *desc) = &default_vstfx_error_callback;
diff --git a/libs/ardour/vstfxinfofile.cc b/libs/ardour/vstfxinfofile.cc
new file mode 100755
index 0000000000..2d54f4d1cd
--- /dev/null
+++ b/libs/ardour/vstfxinfofile.cc
@@ -0,0 +1,382 @@
+/***********************************************************/
+/*vstfx infofile - module to manage info files */
+/*containing cached information about a plugin. e.g. its */
+/*name, creator etc etc */
+/***********************************************************/
+
+/*This is largely unmodified from the original (C code) FST vstinfofile module*/
+
+#include "ardour/vstfx.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <libgen.h>
+
+#define MAX_STRING_LEN 256
+
+#define FALSE 0
+#define TRUE !FALSE
+
+static char* read_string(FILE *fp)
+{
+ char buf[MAX_STRING_LEN];
+
+ fgets( buf, MAX_STRING_LEN, fp );
+
+ if(strlen(buf) < MAX_STRING_LEN)
+ {
+ if(strlen(buf))
+ buf[strlen(buf)-1] = 0;
+
+ return strdup(buf);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+static VSTFXInfo* load_vstfx_info_file(char *filename)
+{
+ VSTFXInfo *info = (VSTFXInfo*) malloc(sizeof(VSTFXInfo));
+ FILE *fp;
+ int i;
+
+ if(info == NULL)
+ return NULL;
+
+ fp = fopen(filename, "r");
+
+ if(fp == NULL)
+ {
+ free( info );
+ return NULL;
+ }
+
+ if((info->name = read_string(fp)) == NULL) goto error;
+ if((info->creator = read_string(fp)) == NULL) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->UniqueID)) goto error;
+ if((info->Category = read_string(fp)) == NULL) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->numInputs)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->numOutputs)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->numParams)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->wantMidi)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->hasEditor)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->canProcessReplacing)) goto error;
+
+ if((info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams)) == NULL) goto error;
+ for(i=0; i<info->numParams; i++)
+ {
+ if((info->ParamNames[i] = read_string(fp)) == NULL) goto error;
+ }
+ if((info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams)) == NULL) goto error;
+
+ for(i=0; i < info->numParams; i++)
+ {
+ if((info->ParamLabels[i] = read_string(fp)) == NULL) goto error;
+ }
+
+ fclose( fp );
+ return info;
+
+error:
+ fclose( fp );
+ free( info );
+ return NULL;
+}
+
+static int save_vstfx_info_file(VSTFXInfo *info, char *filename)
+{
+ FILE *fp;
+ int i;
+
+ if(info == NULL)
+ {
+ vstfx_error("** ERROR ** VSTFXinfofile : info ptr is NULL\n");
+ return TRUE;
+ }
+
+ fp = fopen(filename, "w");
+
+ if(fp == NULL)
+ {
+ vstfx_error("** WARNING ** VSTFX : Can't write info file %s\n", filename);
+ return TRUE;
+ }
+
+ fprintf( fp, "%s\n", info->name );
+ fprintf( fp, "%s\n", info->creator );
+ fprintf( fp, "%d\n", info->UniqueID );
+ fprintf( fp, "%s\n", info->Category );
+ fprintf( fp, "%d\n", info->numInputs );
+ fprintf( fp, "%d\n", info->numOutputs );
+ fprintf( fp, "%d\n", info->numParams );
+ fprintf( fp, "%d\n", info->wantMidi );
+ fprintf( fp, "%d\n", info->hasEditor );
+ fprintf( fp, "%d\n", info->canProcessReplacing );
+
+ for(i=0; i < info->numParams; i++)
+ {
+ fprintf(fp, "%s\n", info->ParamNames[i]);
+ }
+
+ for(i=0; i < info->numParams; i++)
+ {
+ fprintf(fp, "%s\n", info->ParamLabels[i]);
+ }
+
+ fclose( fp );
+
+ return FALSE;
+}
+
+static char* vstfx_dllpath_to_infopath(char *dllpath)
+{
+ char* retval;
+ char* dir_path;
+ char* base_name;
+
+ if(strstr(dllpath, ".so" ) == NULL)
+ return NULL;
+
+ /*Allocate space for the filename - need strlen + 1 for the terminating'0', +1 because .so is three
+ chars, and .fsi is four chars and +1 because we have a '.' at the beginning*/
+
+ retval = (char*)malloc(strlen(dllpath) + 3);
+
+ dir_path = strdup(dllpath);
+ base_name = strdup(dllpath);
+
+ sprintf(retval, "%s/.%s", dirname(dir_path), basename(base_name));
+ sprintf(retval + strlen(retval) - 3, ".fsi");
+
+ free(dir_path);
+ free(base_name);
+
+ return retval;
+}
+
+static int vstfx_info_file_is_valid(char *dllpath)
+{
+ struct stat dllstat;
+ struct stat vstfxstat;
+
+ char *vstfxpath = vstfx_dllpath_to_infopath(dllpath);
+
+ if(!vstfxpath)
+ return FALSE;
+
+ if(stat(dllpath, &dllstat))
+ {
+ vstfx_error( "** ERROR ** VSTFXinfofile : .so path %s invalid\n", dllpath );
+ return TRUE;
+ }
+
+ if(stat(vstfxpath, &vstfxstat))
+ return FALSE;
+
+ free(vstfxpath);
+
+ if(dllstat.st_mtime > vstfxstat.st_mtime)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+static int vstfx_can_midi(VSTFX *vstfx)
+{
+ struct AEffect *plugin = vstfx->plugin;
+
+ int vst_version = plugin->dispatcher (plugin, effGetVstVersion, 0, 0, NULL, 0.0f);
+
+ if (vst_version >= 2)
+ {
+ /* should we send it VST events (i.e. MIDI) */
+
+ if ((plugin->flags & effFlagsIsSynth) || (plugin->dispatcher (plugin, effCanDo, 0, 0,(void*) "receiveVstEvents", 0.0f) > 0))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static VSTFXInfo* vstfx_info_from_plugin(VSTFX *vstfx)
+{
+
+ VSTFXInfo* info = (VSTFXInfo*) malloc(sizeof(VSTFXInfo));
+
+ struct AEffect *plugin;
+ int i;
+
+ /*We need to init the creator because some plugins
+ fail to implement getVendorString, and so won't stuff the
+ string with any name*/
+
+ char creator[65] = "Unknown\0";
+
+ if(!vstfx)
+ {
+ vstfx_error( "** ERROR ** VSTFXinfofile : vstfx ptr is NULL\n" );
+ return NULL;
+ }
+
+ if(!info)
+ return NULL;
+
+ plugin = vstfx->plugin;
+
+ info->name = strdup(vstfx->handle->name );
+
+ /*If the plugin doesn't bother to implement GetVendorString we will
+ have pre-stuffed the string with 'Unkown' */
+
+ plugin->dispatcher (plugin, effGetVendorString, 0, 0, creator, 0);
+
+ /*Some plugins DO implement GetVendorString, but DON'T put a name in it
+ so if its just a zero length string we replace it with 'Unknown' */
+
+ if (strlen(creator) == 0)
+ {
+ info->creator = strdup("Unknown");
+ }
+ else
+ {
+ info->creator = strdup (creator);
+ }
+
+#if defined LXVST_64BIT && defined VESTIGE_HEADER
+
+ /*On 64Bit the data alignment in AEffect struct is
+ incorrect using vestige. see lxvst_plugin.cc*/
+
+ info->UniqueID = *((int32_t *) &((AEffect*)(((char*)(plugin)) + 12))->unused_id);
+
+#elif defined LXVST_32BIT && defined VESTIGE_HEADER
+
+ info->UniqueID = *((int32_t *) &plugin->unused_id);
+
+#else
+
+ info->UniqueID = plugin->uniqueID;
+
+#endif
+
+ info->Category = strdup("None"); // FIXME:
+ info->numInputs = plugin->numInputs;
+ info->numOutputs = plugin->numOutputs;
+ info->numParams = plugin->numParams;
+ info->wantMidi = vstfx_can_midi(vstfx);
+ info->hasEditor = plugin->flags & effFlagsHasEditor ? TRUE : FALSE;
+ info->canProcessReplacing = plugin->flags & effFlagsCanReplacing ? TRUE : FALSE;
+ info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams);
+ info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams);
+ for(i=0; i < info->numParams; i++)
+ {
+ char name[64];
+ char label[64];
+
+ /*Not all plugins give parameters labels as well as names*/
+
+ strcpy(name, "No Name");
+ strcpy(label, "No Label");
+
+ plugin->dispatcher (plugin, effGetParamName, i, 0, name, 0);
+ info->ParamNames[i] = strdup(name);
+
+ plugin->dispatcher (plugin, effGetParamLabel, i, 0, label, 0);
+ info->ParamLabels[i] = strdup(label);
+ }
+ return info;
+}
+
+/* A simple 'dummy' audiomaster callback which should be ok,
+we will only be instantiating the plugin in order to get its info*/
+
+static long simple_master_callback(struct AEffect *fx, long opcode, long index, long value, void *ptr, float opt)
+{
+
+ if(opcode == audioMasterVersion)
+ return 2;
+ else
+ return 0;
+}
+
+/*Try to get plugin info - first by looking for a .fsi cache of the
+data, and if that doesn't exist, load the plugin, get its data and
+then cache it for future ref*/
+
+VSTFXInfo *vstfx_get_info(char *dllpath)
+{
+ if( vstfx_info_file_is_valid(dllpath))
+ {
+ VSTFXInfo *info;
+ char *vstfxpath = vstfx_dllpath_to_infopath(dllpath);
+
+ info = load_vstfx_info_file(vstfxpath);
+ free(vstfxpath);
+
+ return info;
+ }
+ else
+ {
+ VSTFXHandle *h;
+ VSTFX *vstfx;
+ VSTFXInfo *info;
+
+ char *vstfxpath;
+
+ if(!(h = vstfx_load(dllpath)))
+ return NULL;
+
+ if(!(vstfx = vstfx_instantiate(h, simple_master_callback, NULL)))
+ {
+ vstfx_unload(h);
+ vstfx_error( "** ERROR ** VSTFXinfofile : Instantiate failed\n" );
+ return NULL;
+ }
+
+ vstfxpath = vstfx_dllpath_to_infopath(dllpath);
+
+ if(!vstfxpath)
+ {
+ vstfx_close(vstfx);
+ vstfx_unload(h);
+ vstfx_error( "** ERROR ** VSTFXinfofile : get vstfx filename failed\n" );
+ return NULL;
+ }
+
+ info = vstfx_info_from_plugin(vstfx);
+
+ save_vstfx_info_file(info, vstfxpath);
+
+ free(vstfxpath);
+
+ vstfx_close(vstfx);
+ vstfx_unload(h);
+
+ return info;
+ }
+}
+
+void vstfx_free_info(VSTFXInfo *info )
+{
+ int i;
+
+ for(i=0; i < info->numParams; i++)
+ {
+ free(info->ParamNames[i]);
+ free(info->ParamLabels[i]);
+ }
+
+ free(info->name);
+ free(info->creator);
+ free(info->Category);
+ free(info);
+}
+
+
diff --git a/libs/ardour/vstfxwin.cc b/libs/ardour/vstfxwin.cc
new file mode 100755
index 0000000000..a1a7d73909
--- /dev/null
+++ b/libs/ardour/vstfxwin.cc
@@ -0,0 +1,1399 @@
+/******************************************************************/
+/** VSTFX - An engine based on FST for handling linuxVST plugins **/
+/******************************************************************/
+
+/*This is derived from the original FST (C code) with some tweaks*/
+
+
+/** EDITOR tab stops at 4 **/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <jack/jack.h>
+#include <jack/thread.h>
+#include <libgen.h>
+
+#include <pthread.h>
+#include <signal.h>
+#include <glib.h>
+
+#include <ardour/vstfx.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <pthread.h>
+
+struct ERect{
+ short top;
+ short left;
+ short bottom;
+ short right;
+};
+
+static pthread_mutex_t plugin_mutex;
+
+static VSTFX* vstfx_first = NULL;
+
+const char magic[] = "VSTFX Plugin State v002";
+
+int gui_thread_id = 0;
+static int gui_quit = 0;
+
+/*This will be our connection to X*/
+
+Display* LXVST_XDisplay = NULL;
+
+/*The thread handle for the GUI event loop*/
+
+pthread_t LXVST_gui_event_thread;
+
+#define DELAYED_WINDOW 1
+
+/*Util functions to get the value of a property attached to an XWindow*/
+
+bool LXVST_xerror;
+
+int TempErrorHandler(Display *display, XErrorEvent *e)
+{
+ LXVST_xerror = true;
+
+ return 0;
+}
+
+#ifdef LXVST_32BIT
+
+int getXWindowProperty(Window window, Atom atom)
+{
+ int result = 0;
+ int userSize;
+ unsigned long bytes;
+ unsigned long userCount;
+ unsigned char *data;
+ Atom userType;
+ LXVST_xerror = false;
+
+ /*Use our own Xerror handler while we're in here - in an
+ attempt to stop the brain dead default Xerror behaviour of
+ qutting the entire application because of e.g. an invalid
+ window ID*/
+
+ XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
+
+ XGetWindowProperty( LXVST_XDisplay, //The display
+ window, //The Window
+ atom, //The property
+ 0, //Offset into the data
+ 1, //Number of 32Bit chunks of data
+ false, //false = don't delete the property
+ AnyPropertyType, //Required property type mask
+ &userType, //Actual type returned
+ &userSize, //Actual format returned
+ &userCount, //Actual number of items stored in the returned data
+ &bytes, //Number of bytes remaining if a partial read
+ &data); //The actual data read
+
+ if(LXVST_xerror == false && userCount == 1)
+ result = *(int*)data;
+
+ XSetErrorHandler(olderrorhandler);
+
+ /*Hopefully this will return zero if the property is not set*/
+
+ return result;
+}
+
+#endif
+
+#ifdef LXVST_64BIT
+
+/********************************************************************/
+/* This is untested - have no 64Bit plugins which use this */
+/* system of passing an eventProc address */
+/********************************************************************/
+
+long getXWindowProperty(Window window, Atom atom)
+{
+ long result = 0;
+ int userSize;
+ unsigned long bytes;
+ unsigned long userCount;
+ unsigned char *data;
+ Atom userType;
+ LXVST_xerror = false;
+
+ /*Use our own Xerror handler while we're in here - in an
+ attempt to stop the brain dead default Xerror behaviour of
+ qutting the entire application because of e.g. an invalid
+ window ID*/
+
+ XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
+
+ XGetWindowProperty( LXVST_XDisplay,
+ window,
+ atom,
+ 0,
+ 2,
+ false,
+ AnyPropertyType,
+ &userType,
+ &userSize,
+ &userCount,
+ &bytes,
+ &data);
+
+ if(LXVST_xerror == false && userCount == 1)
+ result = *(long*)data;
+
+ XSetErrorHandler(olderrorhandler);
+
+ /*Hopefully this will return zero if the property is not set*/
+
+ return result;
+}
+
+#endif
+
+/*The event handler - called from within the main GUI thread to
+dispatch events to any VST UIs which have callbacks stuck to them*/
+
+static void dispatch_x_events(XEvent* event, VSTFX* vstfx)
+{
+ /*Handle some of the Events we might be interested in*/
+
+ switch(event->type)
+ {
+ /*Configure event - when the window is resized or first drawn*/
+
+ case ConfigureNotify:
+ {
+ Window window = event->xconfigure.event;
+
+ int width = event->xconfigure.width;
+ int height = event->xconfigure.height;
+
+ /*If we get a config notify on the parent window XID then we need to see
+ if the size has been changed - some plugins re-size their UI window e.g.
+ when opening a preset manager (you might think that should be spawned as a new window...) */
+
+ /*if the size has changed, we flag this so that in lxvst_pluginui.cc we can make the
+ change to the GTK parent window in ardour, from its UI thread*/
+
+ if(window == (Window)(vstfx->window))
+ {
+ if((width!=vstfx->width) || (height!=vstfx->height))
+ {
+ vstfx->width = width;
+ vstfx->height = height;
+ vstfx->want_resize = 1;
+
+ /*QUIRK : Loomer plugins not only resize the UI but throw it into some random
+ position at the same time. We need to re-position the window at the origin of
+ the parent window*/
+
+ if(vstfx->plugin_ui_window)
+ XMoveWindow(LXVST_XDisplay, vstfx->plugin_ui_window, 0, 0);
+ }
+ }
+
+ break;
+
+ }
+
+ /*Reparent Notify - when the plugin UI is reparented into
+ our Host Window we will get an event here... probably... */
+
+ case ReparentNotify:
+ {
+ Window ParentWindow = event->xreparent.parent;
+
+ /*If the ParentWindow matches the window for the vstfx instance then
+ the Child window must be the XID of the pluginUI window created by the
+ plugin, so we need to see if it has a callback stuck to it, and if so
+ set that up in the vstfx */
+
+ /***********************************************************/
+ /* 64Bit --- This mechanism is not 64Bit compatible at the */
+ /* present time */
+ /***********************************************************/
+
+ if(ParentWindow == (Window)(vstfx->window))
+ {
+ Window PluginUIWindowID = event->xreparent.window;
+
+ vstfx->plugin_ui_window = PluginUIWindowID;
+#ifdef LXVST_32BIT
+ int result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
+
+ if(result == 0)
+ vstfx->eventProc = NULL;
+ else
+ vstfx->eventProc = (void (*) (void* event))result;
+#endif
+#ifdef LXVST_64BIT
+ long result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
+
+ if(result == 0)
+ vstfx->eventProc = NULL;
+ else
+ vstfx->eventProc = (void (*) (void* event))result;
+#endif
+ }
+ break;
+ }
+
+ case ClientMessage:
+ {
+ Window window = event->xany.window;
+ Atom message_type = event->xclient.message_type;
+
+ /*The only client message we are interested in is to signal
+ that the plugin parent window is now valid and can be passed
+ to effEditOpen when the editor is launched*/
+
+ if(window == (Window)(vstfx->window))
+ {
+ char* message = XGetAtomName(LXVST_XDisplay, message_type);
+
+ if(strcmp(message,"LaunchEditor") == 0)
+ {
+
+ if(event->xclient.data.l[0] == 0x0FEEDBAC)
+ vstfx_launch_editor(vstfx);
+ }
+
+ XFree(message);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ /* Some VSTs built with toolkits e.g. JUCE will manager their own UI
+ autonomously in the plugin, running the UI in its own thread, so once
+ we have created a parent window for the plugin, its UI takes care of
+ itself.*/
+
+ /*Other types register a callback as an Xwindow property on the plugin
+ UI window after they create it. If that is the case, we need to call it
+ here, passing the XEvent into it*/
+
+ if(vstfx->eventProc == NULL)
+ return;
+
+ vstfx->eventProc((void*)event);
+}
+
+
+/*Create and return a pointer to a new vstfx instance*/
+
+static VSTFX* vstfx_new ()
+{
+ VSTFX* vstfx = (VSTFX*) calloc (1, sizeof (VSTFX));
+
+ /*Mutexes*/
+
+ pthread_mutex_init (&vstfx->lock, NULL);
+ pthread_cond_init (&vstfx->window_status_change, NULL);
+ pthread_cond_init (&vstfx->plugin_dispatcher_called, NULL);
+ pthread_cond_init (&vstfx->window_created, NULL);
+
+ /*Safe values*/
+
+ vstfx->want_program = -1;
+ vstfx->want_chunk = 0;
+ vstfx->current_program = -1;
+ vstfx->n_pending_keys = 0;
+ vstfx->has_editor = 0;
+ vstfx->program_set_without_editor = 0;
+ vstfx->window = 0;
+ vstfx->plugin_ui_window = 0;
+ vstfx->eventProc = NULL;
+ vstfx->extra_data = NULL;
+ vstfx->want_resize = 0;
+
+ return vstfx;
+}
+
+/*Create and return a pointer to a new VSTFX handle*/
+
+static VSTFXHandle* vstfx_handle_new()
+{
+ VSTFXHandle* vstfx = (VSTFXHandle*)calloc(1, sizeof (VSTFXHandle));
+ return vstfx;
+}
+
+/** This is the main gui event loop for the plugin, we also need to pass
+any Xevents to all the UI callbacks plugins 'may' have registered on their
+windows, that is if they don't manage their own UIs **/
+
+void* gui_event_loop (void* ptr)
+{
+
+ VSTFX* vstfx;
+ int LXVST_sched_event_timer = 0;
+ int LXVST_sched_timer_interval = 50; //ms
+ XEvent event;
+
+ /*The 'Forever' loop - runs the plugin UIs etc - based on the FST gui event loop*/
+
+ while (!gui_quit)
+ {
+ /* handle window creation requests, destroy requests,
+ and run idle callbacks */
+
+ /*Look at the XEvent queue - if there are any XEvents we need to handle them,
+ including passing them to all the plugin (eventProcs) we are currently managing*/
+
+ if(LXVST_XDisplay)
+ {
+ /*See if there are any events in the queue*/
+
+ int num_events = XPending(LXVST_XDisplay);
+
+ /*process them if there are any*/
+
+ while(num_events)
+ {
+ XNextEvent(LXVST_XDisplay, &event);
+
+ /*Call dispatch events, with the event, for each plugin in the linked list*/
+
+ for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
+ {
+ pthread_mutex_lock(&vstfx->lock);
+
+ dispatch_x_events(&event, vstfx);
+
+ pthread_mutex_unlock(&vstfx->lock);
+ }
+
+ num_events--;
+ }
+ }
+
+ /*We don't want to use all the CPU.. */
+
+ usleep(1000);
+
+ LXVST_sched_event_timer++;
+
+ LXVST_sched_event_timer = LXVST_sched_event_timer & 0x00FFFFFF;
+
+ /*See if its time for us to do a scheduled event pass on all the plugins*/
+
+ if((LXVST_sched_timer_interval!=0) && (!(LXVST_sched_event_timer% LXVST_sched_timer_interval)))
+ {
+ pthread_mutex_lock (&plugin_mutex);
+
+again:
+ /*Parse through the linked list of plugins*/
+
+ for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
+ {
+ pthread_mutex_lock (&vstfx->lock);
+
+ /*Window scheduled for destruction*/
+
+ if (vstfx->destroy)
+ {
+ if (vstfx->window)
+ {
+ vstfx->plugin->dispatcher( vstfx->plugin, effEditClose, 0, 0, NULL, 0.0 );
+
+ XDestroyWindow (LXVST_XDisplay, vstfx->window);
+ vstfx->window = 0; //FIXME - probably safe to assume we never have an XID of 0 but not explicitly true
+ vstfx->destroy = FALSE;
+ }
+
+ vstfx_event_loop_remove_plugin (vstfx);
+ vstfx->been_activated = FALSE;
+ pthread_cond_signal (&vstfx->window_status_change);
+ pthread_mutex_unlock (&vstfx->lock);
+
+ goto again;
+ }
+
+ /*Window does not yet exist - scheduled for creation*/
+
+ if (vstfx->window == 0) //FIXME - probably safe to assume 0 is not a valid XID but not explicitly true
+ {
+ if (vstfx_create_editor (vstfx))
+ {
+ vstfx_error ("** ERROR ** VSTFX : Cannot create editor for plugin %s", vstfx->handle->name);
+ vstfx_event_loop_remove_plugin (vstfx);
+ pthread_cond_signal (&vstfx->window_status_change);
+ pthread_mutex_unlock (&vstfx->lock);
+ goto again;
+ }
+ else
+ {
+ /* condition/unlock: it was signalled & unlocked in fst_create_editor() */
+ }
+ }
+
+ /*Scheduled for setting a new program*/
+
+ if (vstfx->want_program != -1 )
+ {
+ if (vstfx->vst_version >= 2)
+ {
+ vstfx->plugin->dispatcher (vstfx->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
+ }
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effSetProgram, 0, vstfx->want_program, NULL, 0);
+
+ if (vstfx->vst_version >= 2)
+ {
+ vstfx->plugin->dispatcher (vstfx->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
+ }
+
+ /* did it work? */
+
+ vstfx->current_program = vstfx->plugin->dispatcher (vstfx->plugin, 3, /* effGetProgram */ 0, 0, NULL, 0);
+ vstfx->want_program = -1;
+ }
+
+ /*scheduled call to dispatcher*/
+
+ if(vstfx->dispatcher_wantcall)
+ {
+ vstfx->dispatcher_retval = vstfx->plugin->dispatcher( vstfx->plugin,
+ vstfx->dispatcher_opcode,
+ vstfx->dispatcher_index,
+ vstfx->dispatcher_val,
+ vstfx->dispatcher_ptr,
+ vstfx->dispatcher_opt );
+ vstfx->dispatcher_wantcall = 0;
+ pthread_cond_signal (&vstfx->plugin_dispatcher_called);
+ }
+
+ /*Call the editor Idle function in the plugin*/
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effEditIdle, 0, 0, NULL, 0);
+
+ if(vstfx->wantIdle)
+ vstfx->plugin->dispatcher (vstfx->plugin, 53, 0, 0, NULL, 0);
+
+ pthread_mutex_unlock (&vstfx->lock);
+ }
+ pthread_mutex_unlock (&plugin_mutex);
+ }
+ }
+
+ /*Drop out to here if we set gui_quit to 1 */
+
+ return NULL;
+}
+
+/*The VSTFX Init function - this needs to be called before the VSTFX engine
+can be accessed, it gets the UI thread running, opens a connection to X etc
+normally started in globals.cc*/
+
+int vstfx_init (void* ptr)
+{
+
+ int thread_create_result;
+
+ pthread_attr_t thread_attributes;
+
+ /*Init the attribs to defaults*/
+
+ pthread_attr_init(&thread_attributes);
+
+ /*Make sure the thread is joinable - this should be the default anyway -
+ so we can join to it on vstfx_exit*/
+
+ pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
+
+
+ /*This is where we need to open a connection to X, and start the GUI thread*/
+
+ /*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
+ will talk to X down this connection - X cannot handle multi-threaded access via
+ the same Display* */
+
+ if(LXVST_XDisplay==NULL)
+ LXVST_XDisplay = XOpenDisplay(NULL); //We might be able to make this open a specific screen etc
+
+ /*Drop out and report the error if we fail to connect to X */
+
+ if(LXVST_XDisplay==NULL)
+ {
+ vstfx_error ("** ERROR ** VSTFX: Failed opening connection to X");
+
+ return -1;
+ }
+
+ /*We have a connection to X - so start the gui event loop*/
+
+ /*Create the thread - use default attrs for now, don't think we need anything special*/
+
+ thread_create_result = pthread_create(&LXVST_gui_event_thread, NULL, gui_event_loop, NULL);
+
+ if(thread_create_result!=0)
+ {
+ /*There was a problem starting the GUI event thread*/
+
+ vstfx_error ("** ERROR ** VSTFX: Failed starting GUI event thread");
+
+ XCloseDisplay(LXVST_XDisplay);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*The vstfx Quit function*/
+
+void vstfx_exit()
+{
+ gui_quit = 1;
+
+ /*We need to pthread_join the gui_thread here so
+ we know when it has stopped*/
+
+ pthread_join(LXVST_gui_event_thread, NULL);
+}
+
+/*Adds a new plugin (VSTFX) instance to the linked list*/
+
+int vstfx_run_editor (VSTFX* vstfx)
+{
+ pthread_mutex_lock (&plugin_mutex);
+
+ /*Add the new VSTFX instance to the linked list*/
+
+ if (vstfx_first == NULL)
+ {
+ vstfx_first = vstfx;
+ }
+ else
+ {
+ VSTFX* p = vstfx_first;
+
+ while (p->next)
+ {
+ p = p->next;
+ }
+ p->next = vstfx;
+
+ /*Mark the new end of the list*/
+
+ vstfx->next = NULL;
+ }
+
+ pthread_mutex_unlock (&plugin_mutex);
+
+ /* wait for the plugin editor window to be created (or not) */
+
+ pthread_mutex_lock (&vstfx->lock);
+
+ if (!vstfx->window)
+ {
+ pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
+ }
+
+ pthread_mutex_unlock (&vstfx->lock);
+
+ if (!vstfx->window)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*Set up a call to the plugins 'dispatcher' function*/
+
+int vstfx_call_dispatcher (VSTFX *vstfx, int opcode, int index, int val, void *ptr, float opt)
+{
+ pthread_mutex_lock (&vstfx->lock);
+
+ /*Set up the opcode and parameters*/
+
+ vstfx->dispatcher_opcode = opcode;
+ vstfx->dispatcher_index = index;
+ vstfx->dispatcher_val = val;
+ vstfx->dispatcher_ptr = ptr;
+ vstfx->dispatcher_opt = opt;
+
+ /*Signal that we want the call to happen*/
+
+ vstfx->dispatcher_wantcall = 1;
+
+ /*Wait for the call to happen*/
+
+ pthread_cond_wait (&vstfx->plugin_dispatcher_called, &vstfx->lock);
+ pthread_mutex_unlock (&vstfx->lock);
+
+ /*Return the result*/
+
+ return vstfx->dispatcher_retval;
+}
+
+/*Creates an editor for the plugin - normally called from within the gui event loop
+after run_editor has added the plugin (editor) to the linked list*/
+
+int vstfx_create_editor (VSTFX* vstfx)
+{
+ Window parent_window;
+
+ int x_size = 1;
+ int y_size = 1;
+
+ /* Note: vstfx->lock is held while this function is called */
+
+ if (!(vstfx->plugin->flags & effFlagsHasEditor))
+ {
+ vstfx_error ("** ERROR ** VSTFX: Plugin \"%s\" has no editor", vstfx->handle->name);
+ return -1;
+ }
+
+
+ /*Create an XWindow for the plugin to inhabit*/
+
+ parent_window = XCreateSimpleWindow(LXVST_XDisplay,
+ DefaultRootWindow(LXVST_XDisplay),
+ 0,
+ 0,
+ x_size,
+ y_size,
+ 0,
+ 0,
+ 0);
+
+ /*Select the events we are interested in receiving - we need Substructure notify so that
+ if the plugin resizes its window - e.g. Loomer Manifold then we get a message*/
+
+ XSelectInput(LXVST_XDisplay,
+ parent_window,
+ SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
+
+ vstfx->window = parent_window;
+
+ vstfx->xid = parent_window; //vstfx->xid will be referenced to connect to GTK UI in ardour later
+
+ /*Because the plugin may be operating on a different Display* to us, and therefore
+ the two event queues can be asynchronous, although we have created the window on
+ our display, we can't guarantee it exists in the server yet, which will
+ cause BadWindow crashes if the plugin tries to use it.
+
+ It would be nice to use CreateNotify events here, but they don't get
+ through on all window managers, so instead we pass a client message
+ into out queue, after the XCreateWindow. When this message pops out
+ in our event handler, it will trigger the second stage of plugin
+ Editor instantiation, and by then the Window should be valid...*/
+
+ XClientMessageEvent event;
+
+ /*Create an atom to identify our message (only if it doesn't already exist)*/
+
+ Atom WindowActiveAtom = XInternAtom(LXVST_XDisplay, "LaunchEditor", false);
+
+ event.type = ClientMessage;
+ event.send_event = true;
+ event.window = parent_window;
+ event.message_type = WindowActiveAtom;
+
+ event.format = 32; //Data format
+ event.data.l[0] = 0x0FEEDBAC; //Something we can recognize later
+
+ /*Push the event into the queue on our Display*/
+
+ XSendEvent(LXVST_XDisplay, parent_window, FALSE, NoEventMask, (XEvent*)&event);
+
+ /*Unlock - and we are done for the first part of staring the Editor...*/
+
+ pthread_mutex_unlock (&vstfx->lock);
+
+ return 0;
+}
+
+int vstfx_launch_editor(VSTFX* vstfx)
+{
+ /*This is the second stage of launching the editor (see vstfx_create editor)
+ we get called here in response to receiving the ClientMessage on our Window,
+ therefore it's about as safe (as can be) to assume that the Window we created
+ is now valid in the XServer and can be passed to the plugin in effEditOpen
+ without generating BadWindow errors when the plugin reparents itself into our
+ parent window*/
+
+ if(vstfx->been_activated)
+ return 0;
+
+ Window parent_window;
+ struct ERect* er;
+
+ int x_size = 1;
+ int y_size = 1;
+
+ parent_window = vstfx->window;
+
+ /*Open the editor - Bah! we have to pass the int windowID as a void pointer - yuck
+ it gets cast back to an int as the parent window XID in the plugin - and we have to pass the
+ Display* as a long */
+
+ /**************************************************************/
+ /* 64Bit --- parent window is an int passed as a void* so */
+ /* that should be ok for 64Bit machines */
+ /* */
+ /* Display is passed in as a long - ok on arch's where sizeof */
+ /* long = 8 */
+ /* */
+ /* Most linux VST plugins open a connection to X on their own */
+ /* Display anyway so it may not matter */
+ /* */
+ /* linuxDSP VSTs don't use the host Display* at all */
+ /**************************************************************/
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effEditOpen, 0, (long)LXVST_XDisplay, (void*)(parent_window), 0 );
+
+ /*QUIRK - some plugins need a slight delay after opening the editor before you can
+ ask the window size or they might return zero - specifically discoDSP */
+
+ usleep(100000);
+
+ /*Now we can find out how big the parent window should be (and try) to resize it*/
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effEditGetRect, 0, 0, &er, 0 );
+
+ x_size = er->right - er->left;
+ y_size = er->bottom - er->top;
+
+ vstfx->width = x_size;
+ vstfx->height = y_size;
+
+ XResizeWindow(LXVST_XDisplay, parent_window, x_size, y_size);
+
+ XFlush (LXVST_XDisplay);
+
+ /*Not sure if we need to map the window or if the plugin will do it for us
+ it should be ok because XReparentWindow generates a Map event*/
+
+ /*mark the editor as activated - mainly so that vstfx_get_XID
+ will know it is valid*/
+
+ vstfx->been_activated = TRUE;
+
+ pthread_cond_signal (&vstfx->window_status_change);
+ return 0;
+}
+
+/*May not be needed in the XLib version*/
+
+void vstfx_move_window_into_view (VSTFX* vstfx)
+{
+
+ /*This is probably the equivalent of Mapping an XWindow
+ but we most likely don't need it because the window
+ will be Mapped by XReparentWindow*/
+
+}
+
+/*Destroy the editor window*/
+
+void vstfx_destroy_editor (VSTFX* vstfx)
+{
+ pthread_mutex_lock (&vstfx->lock);
+ if (vstfx->window)
+ {
+ vstfx->destroy = TRUE;
+ pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
+ }
+ pthread_mutex_unlock (&vstfx->lock);
+}
+
+/*Remove a vstfx instance from the linked list parsed by the
+event loop*/
+
+void vstfx_event_loop_remove_plugin (VSTFX* vstfx)
+{
+ /*This only ever gets called from within our GUI thread
+ so we don't need to lock here - if we did there would be
+ a deadlock anyway*/
+
+ VSTFX* p;
+ VSTFX* prev;
+
+ for(p = vstfx_first, prev = NULL; p; prev = p, p = p->next)
+ {
+ if(p == vstfx)
+ {
+ if(prev)
+ {
+ prev->next = p->next;
+ break;
+ }
+ }
+ }
+
+ if (vstfx_first == vstfx)
+ vstfx_first = vstfx_first->next;
+}
+
+/*This loads the plugin shared library*/
+
+void* vstfx_load_vst_library(const char* path)
+{
+ void* dll;
+ char* full_path;
+ char* envdup;
+ char* lxvst_path;
+ size_t len1;
+ size_t len2;
+
+ /*Try and load the shared library pointed to by the path -
+ NOTE: You have to give RTLD_LAZY or RTLD_NOW to dlopen or
+ you get some occasional failures to load - dlerror reports
+ invalid arguments*/
+
+ if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
+ return dll;
+
+ /*We didn't find the library so try and get the path specified in the
+ env variable LXVST_PATH*/
+
+ envdup = getenv ("LXVST_PATH");
+
+ /*Path not specified - not much more we can do*/
+
+ if (envdup == NULL)
+ return NULL;
+
+ /*Copy the path into envdup*/
+
+ envdup = strdup (envdup);
+
+ if (envdup == NULL)
+ return NULL;
+
+ len2 = strlen(path);
+
+ /*Try all the possibilities in the path - deliminated by : */
+
+ lxvst_path = strtok (envdup, ":");
+
+ while (lxvst_path != NULL)
+ {
+ vstfx_error ("\"%s\"", lxvst_path);
+ len1 = strlen(lxvst_path);
+
+ full_path = (char*)malloc(len1 + 1 + len2 + 1);
+ memcpy(full_path, lxvst_path, len1);
+ full_path[len1] = '/';
+ memcpy(full_path + len1 + 1, path, len2);
+ full_path[len1 + 1 + len2] = '\0';
+
+ /*Try and load the library*/
+
+ if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
+ {
+ /*Succeeded */
+ break;
+ }
+
+ /*Try again*/
+
+ lxvst_path = strtok (NULL, ":");
+ }
+
+ /*Free the path*/
+
+ free(envdup);
+
+ return dll;
+}
+
+/*This loads up a plugin, given the path to its .so file and
+ finds its main entry point etc*/
+
+VSTFXHandle* vstfx_load (const char *path)
+{
+ char* buf = NULL;
+ VSTFXHandle* fhandle;
+ int i;
+
+ /*Create a new handle we can use to reference the plugin*/
+
+ fhandle = vstfx_handle_new();
+
+ /*See if we have .so appended to the path - if not we need to make sure it is added*/
+
+ if (strstr (path, ".so") == NULL)
+ {
+
+ /*Append the .so to the path - Make sure the path has enough space*/
+
+ buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
+
+ sprintf (buf, "%s.so", path);
+
+ fhandle->nameptr = strdup (path);
+
+ }
+ else
+ {
+ /*We already have .so appened to the filename*/
+
+ buf = strdup(path);
+
+ fhandle->nameptr = strdup (path);
+ }
+
+ /*Use basename to shorten the path and then strip off the .so - the old VST problem,
+ we don't know anything about its name until we load and instantiate the plugin
+ which we don't want to do at this point*/
+
+ for(i=0; i < (int)strlen(fhandle->nameptr); i++)
+ {
+ if(fhandle->nameptr[i] == '.')
+ fhandle->nameptr[i] = 0;
+ }
+
+
+ fhandle->name = basename (fhandle->nameptr);
+
+ /*call load_vstfx_library to actually load the .so into memory*/
+
+ if ((fhandle->dll = vstfx_load_vst_library (buf)) == NULL)
+ {
+ vstfx_unload (fhandle);
+
+ free(buf);
+
+ return NULL;
+ }
+
+ /*Find the main entry point into the plugin*/
+
+ if ((fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main")) == NULL)
+ {
+ /*If it can't be found, unload the plugin and return a NULL handle*/
+
+ vstfx_unload (fhandle);
+
+ free(buf);
+
+ return NULL;
+ }
+
+ free(buf);
+
+ /*return the handle of the plugin*/
+
+ return fhandle;
+}
+
+/*This unloads a plugin*/
+
+int vstfx_unload (VSTFXHandle* fhandle)
+{
+ if (fhandle->plugincnt)
+ {
+ /*Still have plugin instances - can't unload the library
+ - actually dlclose keeps an instance count anyway*/
+
+ return -1;
+ }
+
+ /*Valid plugin loaded?*/
+
+ if (fhandle->dll)
+ {
+ dlclose(fhandle->dll);
+ fhandle->dll = NULL;
+ }
+
+ if (fhandle->nameptr)
+ {
+ free (fhandle->nameptr);
+ fhandle->name = NULL;
+ }
+
+ /*Don't need the plugin handle any more*/
+
+ free (fhandle);
+ return 0;
+}
+
+/*This instantiates a plugin*/
+
+VSTFX* vstfx_instantiate (VSTFXHandle* fhandle, audioMasterCallback amc, void* userptr)
+{
+ VSTFX* vstfx = vstfx_new ();
+
+ if(fhandle == NULL)
+ {
+ vstfx_error( "** ERROR ** VSTFX : The handle was NULL\n" );
+ return NULL;
+ }
+
+ if ((vstfx->plugin = fhandle->main_entry (amc)) == NULL)
+ {
+ vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
+ free (vstfx);
+ return NULL;
+ }
+
+ vstfx->handle = fhandle;
+ vstfx->plugin->user = userptr;
+
+ if (vstfx->plugin->magic != kEffectMagic)
+ {
+ vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
+ free (vstfx);
+ return NULL;
+ }
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
+
+ /*May or May not need to 'switch the plugin on' here - unlikely
+ since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
+
+ //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, NULL, 0);
+
+ vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
+
+ vstfx->handle->plugincnt++;
+ vstfx->wantIdle = 0;
+
+ return vstfx;
+}
+
+/*Close a vstfx instance*/
+
+void vstfx_close (VSTFX* vstfx)
+{
+ vstfx_destroy_editor(vstfx);
+
+ if(vstfx->plugin)
+ {
+ vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, NULL, 0);
+
+ /*Calling dispatcher with effClose will cause the plugin's destructor to
+ be called, which will also remove the editor if it exists*/
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
+ }
+
+ if (vstfx->handle->plugincnt)
+ vstfx->handle->plugincnt--;
+
+ /*vstfx_unload will unload the dll if the instance count allows -
+ we need to do this because some plugins keep their own instance count
+ and (JUCE) manages the plugin UI in its own thread. When the plugins
+ internal instance count reaches zero, JUCE stops the UI thread and won't
+ restart it until the next time the library is loaded. If we don't unload
+ the lib JUCE will never restart*/
+
+
+ if (vstfx->handle->plugincnt)
+ {
+ return;
+ }
+
+ /*Valid plugin loaded - so we can unload it and NULL the pointer
+ to it. We can't free the handle here because we don't know what else
+ might need it. It should be / is freed when the plugin is deleted*/
+
+ if (vstfx->handle->dll)
+ {
+ dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
+ vstfx->handle->dll = NULL;
+ }
+}
+
+
+/*Get the XID of the plugin editor window*/
+
+int vstfx_get_XID (VSTFX* vstfx)
+{
+ int id;
+
+ /*Wait for the lock to become free - otherwise
+ the window might be in the process of being
+ created and we get bad Window errors when trying
+ to embed it in the GTK UI*/
+
+ pthread_mutex_lock(&vstfx->lock);
+
+ /*The Window may be scheduled for creation
+ but not actually created by the gui_event_loop yet -
+
+ spin here until it has been activated. Possible
+ deadlock if the window never gets activated but
+ should not be called here if the window doesn't
+ exist or will never exist*/
+
+ while(!(vstfx->been_activated))
+ usleep(1000);
+
+ id = vstfx->xid;
+
+ pthread_mutex_unlock(&vstfx->lock);
+
+ /*Finally it might be safe to return the ID -
+ problems will arise if we return either a zero ID
+ and GTK tries to socket it or if we return an ID
+ which hasn't yet become real to the server*/
+
+ return id;
+}
+
+float htonf (float v)
+{
+ float result;
+ char * fin = (char*)&v;
+ char * fout = (char*)&result;
+ fout[0] = fin[3];
+ fout[1] = fin[2];
+ fout[2] = fin[1];
+ fout[3] = fin[0];
+ return result;
+}
+
+
+/*load_state and save_state do not appear to be needed (yet) in ardour
+- untested at the moment, these are just replicas of the fst code*/
+
+
+#if 0
+int vstfx_load_state (VSTFX* vstfx, char * filename)
+{
+ FILE* f = fopen (filename, "rb");
+ if(f)
+ {
+ char testMagic[sizeof (magic)];
+ fread (&testMagic, sizeof (magic), 1, f);
+ if (strcmp (testMagic, magic))
+ {
+ printf ("File corrupt\n");
+ return FALSE;
+ }
+
+ char productString[64];
+ char vendorString[64];
+ char effectName[64];
+ char testString[64];
+ unsigned length;
+ int success;
+
+ fread (&length, sizeof (unsigned), 1, f);
+ length = htonl (length);
+ fread (productString, length, 1, f);
+ productString[length] = 0;
+ printf ("Product string: %s\n", productString);
+
+ success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, testString, 0);
+
+ if (success == 1)
+ {
+ if (strcmp (testString, productString) != 0)
+ {
+ printf ("Product string mismatch! Plugin has: %s\n", testString);
+ fclose (f);
+ return FALSE;
+ }
+ }
+ else if (length != 0)
+ {
+ printf ("Product string mismatch! Plugin has none.\n", testString);
+ fclose (f);
+ return FALSE;
+ }
+
+ fread (&length, sizeof (unsigned), 1, f);
+ length = htonl (length);
+ fread (effectName, length, 1, f);
+ effectName[length] = 0;
+ printf ("Effect name: %s\n", effectName);
+
+ success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, testString, 0);
+
+ if(success == 1)
+ {
+ if(strcmp(testString, effectName)!= 0)
+ {
+ printf ("Effect name mismatch! Plugin has: %s\n", testString);
+ fclose (f);
+ return FALSE;
+ }
+ }
+ else if(length != 0)
+ {
+ printf ("Effect name mismatch! Plugin has none.\n", testString);
+ fclose (f);
+ return FALSE;
+ }
+
+ fread (&length, sizeof (unsigned), 1, f);
+ length = htonl (length);
+ fread (vendorString, length, 1, f);
+ vendorString[length] = 0;
+
+ printf ("Vendor string: %s\n", vendorString);
+
+ success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, testString, 0);
+ if(success == 1)
+ {
+ if (strcmp(testString, vendorString)!= 0)
+ {
+ printf ("Vendor string mismatch! Plugin has: %s\n", testString);
+ fclose (f);
+ return FALSE;
+ }
+ }
+ else if(length != 0)
+ {
+ printf ("Vendor string mismatch! Plugin has none.\n", testString);
+ fclose (f);
+ return FALSE;
+ }
+
+ int numParam;
+ unsigned i;
+ fread (&numParam, sizeof (int), 1, f);
+ numParam = htonl (numParam);
+
+ for (i = 0; i < numParam; ++i)
+ {
+ float val;
+ fread (&val, sizeof (float), 1, f);
+ val = htonf (val);
+
+ pthread_mutex_lock(&vstfx->lock );
+ vstfx->plugin->setParameter(vstfx->plugin, i, val);
+ pthread_mutex_unlock(&vstfx->lock );
+ }
+
+ int bytelen;
+
+ fread (&bytelen, sizeof (int), 1, f);
+ bytelen = htonl (bytelen);
+
+ if (bytelen)
+ {
+ char * buf = malloc (bytelen);
+ fread (buf, bytelen, 1, f);
+
+ vstfx_call_dispatcher(vstfx, 24, 0, bytelen, buf, 0);
+ free (buf);
+ }
+ }
+ else
+ {
+ printf ("Could not open state file\n");
+ return FALSE;
+ }
+ return TRUE;
+
+}
+#endif
+
+int vstfx_save_state (VSTFX* vstfx, char * filename)
+{
+ FILE* f = fopen (filename, "wb");
+ if (f)
+ {
+ int bytelen;
+ int numParams = vstfx->plugin->numParams;
+ int i;
+ char productString[64];
+ char effectName[64];
+ char vendorString[64];
+ int success;
+
+ /* write header */
+
+ fprintf(f, "<plugin_state>\n");
+
+ success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, productString, 0);
+
+ if(success == 1)
+ {
+ fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
+ }
+ else
+ {
+ printf ("No product string\n");
+ }
+
+ success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, effectName, 0);
+
+ if(success == 1)
+ {
+ fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
+ printf ("Effect name: %s\n", effectName);
+ }
+ else
+ {
+ printf ("No effect name\n");
+ }
+
+ success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, vendorString, 0);
+
+ if( success == 1 )
+ {
+ fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
+ printf ("Vendor string: %s\n", vendorString);
+ }
+ else
+ {
+ printf ("No vendor string\n");
+ }
+
+
+ if(vstfx->plugin->flags & 32 )
+ {
+ numParams = 0;
+ }
+
+ for(i=0; i < numParams; i++)
+ {
+ float val;
+
+ pthread_mutex_lock( &vstfx->lock );
+ val = vstfx->plugin->getParameter(vstfx->plugin, i );
+ pthread_mutex_unlock( &vstfx->lock );
+ fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
+ }
+
+ if(vstfx->plugin->flags & 32 )
+ {
+ printf( "getting chunk...\n" );
+ void * chunk;
+ bytelen = vstfx_call_dispatcher(vstfx, 23, 0, 0, &chunk, 0 );
+ printf( "got tha chunk..\n" );
+ if( bytelen )
+ {
+ if( bytelen < 0 )
+ {
+ printf( "Chunke len < 0 !!! Not saving chunk.\n" );
+ }
+ else
+ {
+ //char *encoded = g_base64_encode( chunk, bytelen );
+ //fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
+ //g_free( encoded );
+ }
+ }
+ }
+
+ fprintf( f, "</plugin_state>\n" );
+ fclose( f );
+ }
+ else
+ {
+ printf ("Could not open state file\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index e4d435c0a9..b347e73e7e 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -396,6 +396,11 @@ def build(bld):
obj.source += [ 'vst_plugin.cc', 'session_vst.cc' ]
obj.includes += [ '../fst' ]
obj.defines += [ 'VST_SUPPORT' ]
+
+ if bld.env['LXVST_SUPPORT']:
+ obj.source += [ 'lxvst_plugin.cc', 'session_lxvst.cc', 'vstfx.cc', 'vstfxwin.cc', 'vstfxinfofile.cc' ]
+ obj.defines += [ 'LXVST_SUPPORT' ]
+
if bld.env['COREAUDIO']:
obj.source += [ 'coreaudiosource.cc', 'caimportable.cc' ]
diff --git a/wscript b/wscript
index 237c077868..14e62f94e3 100644
--- a/wscript
+++ b/wscript
@@ -246,7 +246,14 @@ def set_compiler_flags (conf,opt):
print("\nIt is theoretically possible to build a 32 bit host on a 64 bit system.")
print("However, this is tricky and not recommended for beginners.")
sys.exit (-1)
-
+
+ if conf.env['build_target'] == 'x86_64' and opt.lxvst:
+ print("\n\n********************************************************")
+ print("* Building with 64Bit linuxVST support is experimental *")
+ print("********************************************************\n\n")
+ conf.env.append_value('CXXFLAGS', "-DLXVST_64BIT")
+ else:
+ conf.env.append_value('CXXFLAGS', "-DLXVST_32BIT")
#
# a single way to test if we're on OS X
#
@@ -362,6 +369,8 @@ def set_options(opt):
help='Compile for use with gprofile')
opt.add_option('--lv2', action='store_true', default=False, dest='lv2',
help='Compile with support for LV2 (if SLV2 or Lilv+Suil is available)')
+ opt.add_option('--lxvst', action='store_true', default=False, dest='lxvst',
+ help='Compile with support for linuxVST plugins')
opt.add_option('--nls', action='store_true', default=True, dest='nls',
help='Enable i18n (native language support) (default)')
opt.add_option('--no-nls', action='store_false', dest='nls')
@@ -531,6 +540,9 @@ def configure(conf):
conf.define('VST_SUPPORT', 1)
conf.env.append_value('CPPPATH', Options.options.wine_include)
autowaf.check_header(conf, 'windows.h', mandatory = True)
+ if opts.lxvst:
+ conf.define('LXVST_SUPPORT', 1)
+ conf.env['LXVST_SUPPORT'] = True
if bool(conf.env['JACK_SESSION']):
conf.define ('HAVE_JACK_SESSION', 1)
if opts.wiimote:
@@ -572,6 +584,7 @@ const char* const ardour_config_info = "\\n\\
write_config_text('JACK session support', bool(conf.env['JACK_SESSION']))
write_config_text('LV2 UI embedding', bool(conf.env['HAVE_SUIL']))
write_config_text('LV2 support', bool(conf.env['LV2_SUPPORT']))
+ write_config_text('LXVST support', bool(conf.env['LXVST_SUPPORT']))
write_config_text('OGG', bool(conf.env['HAVE_OGG']))
write_config_text('Phone home', bool(conf.env['PHONE_HOME']))
write_config_text('Program name', opts.program_name)