(native) Linux VST support from LinuxDSP

git-svn-id: svn://localhost/ardour2/branches/3.0@10101 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2011-09-20 20:29:47 +00:00
parent e09e0035a6
commit d4433b9ab3
38 changed files with 4346 additions and 70 deletions

View file

@ -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);

69
gtk2_ardour/lxvst_plugin_ui.h Executable file
View file

@ -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

277
gtk2_ardour/lxvst_pluginui.cc Executable file
View file

@ -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 );
}

View file

@ -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) {

View file

@ -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;
@ -357,6 +361,18 @@ PluginSelector::vst_refiller (const std::string&)
#endif
}
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)
@ -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

View file

@ -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;

View file

@ -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"
@ -99,6 +103,10 @@ PluginUIWindow::PluginUIWindow (
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);
break;
@ -274,6 +282,36 @@ PluginUIWindow::create_vst_editor(boost::shared_ptr<PluginInsert>)
#endif
}
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)

View file

@ -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>);
};

View file

@ -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',

View file

@ -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 {

View file

@ -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);

View file

@ -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;
};

123
libs/ardour/ardour/lxvst_plugin.h Executable file
View file

@ -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__ */

View file

@ -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 ();
@ -119,6 +125,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);

View file

@ -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)

View file

@ -742,6 +742,15 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
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;
/* Speakers */

View file

@ -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);

View file

@ -449,7 +449,8 @@ namespace ARDOUR {
AudioUnit,
LADSPA,
LV2,
VST
VST,
LXVST,
};
enum RunContext {

View file

@ -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

176
libs/ardour/ardour/vstfx.h Executable file
View file

@ -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__ */

View file

@ -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 {

View file

@ -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
{

View file

@ -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)

View file

@ -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;
}

830
libs/ardour/lxvst_plugin.cc Executable file
View file

@ -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;
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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;
@ -748,6 +895,18 @@ PluginManager::vst_plugin_info ()
#endif
}
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 ()
{

View file

@ -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));

View file

@ -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,16 +4381,17 @@ 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);
}
}
}
void
Session::post_capture_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")
}

364
libs/ardour/session_lxvst.cc Executable file
View file

@ -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;
}

View file

@ -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)
{

View file

@ -75,7 +75,7 @@ legalize_for_path (const string& str)
pos += 1;
}
return legal;
return string (legal);
}
string

32
libs/ardour/vstfx.cc Executable file
View file

@ -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;

382
libs/ardour/vstfxinfofile.cc Executable file
View file

@ -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);
}

1399
libs/ardour/vstfxwin.cc Executable file

File diff suppressed because it is too large Load diff

View file

@ -397,6 +397,11 @@ def build(bld):
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' ]
obj.uselib_local += ['libappleutility']

13
wscript
View file

@ -247,6 +247,13 @@ def set_compiler_flags (conf,opt):
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)