From 6f5ee7c4293c43486d48bac00fdcdba90dabb17d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 11 Jul 2010 21:55:11 +0000 Subject: [PATCH] Fix up VST build and add basic support for VSTi git-svn-id: svn://localhost/ardour2/branches/3.0@7403 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/plugin_ui.h | 15 +++++ gtk2_ardour/vst_pluginui.cc | 2 +- gtk2_ardour/wscript | 42 +++++++++++-- libs/ardour/ardour/buffer_set.h | 35 +++++++++++ libs/ardour/ardour/vst_plugin.h | 2 +- libs/ardour/buffer_set.cc | 101 +++++++++++++++++++++++++++++++- libs/ardour/plugin_manager.cc | 1 + libs/ardour/session_vst.cc | 9 ++- libs/ardour/vst_plugin.cc | 13 +++- libs/ardour/wscript | 4 +- vst/ardevst | 4 +- 11 files changed, 213 insertions(+), 15 deletions(-) diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h index 7b5e77ec18..bfd23fab6b 100644 --- a/gtk2_ardour/plugin_ui.h +++ b/gtk2_ardour/plugin_ui.h @@ -298,9 +298,24 @@ class VSTPluginUI : public PlugUIBase, public Gtk::VBox Gtk::Socket socket; Gtk::HBox preset_box; Gtk::VBox vpacker; + Gtk::ComboBoxText vst_preset_combo; + Glib::RefPtr preset_model; + + struct PresetModelColumns : public Gtk::TreeModel::ColumnRecord { + PresetModelColumns() { + add (name); + add (number); + } + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn number; + }; + + PresetModelColumns preset_columns; bool configure_handler (GdkEventConfigure*, Gtk::Socket*); void save_plugin_setting (); + void create_preset_store (); + void preset_chosen (); }; #endif // VST_SUPPORT diff --git a/gtk2_ardour/vst_pluginui.cc b/gtk2_ardour/vst_pluginui.cc index bd678dd72d..6c1b359fd4 100644 --- a/gtk2_ardour/vst_pluginui.cc +++ b/gtk2_ardour/vst_pluginui.cc @@ -20,7 +20,7 @@ #include #include #include -#include "ardour/insert.h" +#include "ardour/plugin_insert.h" #include "ardour/vst_plugin.h" #include "plugin_ui.h" diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index ddae851127..940d43d5b4 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -237,13 +237,29 @@ def configure(conf): autowaf.check_header(conf, 'boost/shared_ptr.hpp') autowaf.check_header(conf, 'boost/weak_ptr.hpp') +# Add a waf `feature' to allow compilation of things using winegcc +from TaskGen import feature +@feature("wine") +def set_winegcc(self): + self.env.LINK_CXX = self.env.LINK_CC = 'wineg++' + self.env.CC = 'winegcc' + def build(bld): - # Program - obj = bld.new_task_gen(features = 'cxx cc cprogram') + # GTK front-end; if we're using VST we build this as a shared library, otherwise + # it's a normal executabale + if bld.env['VST_SUPPORT']: + obj = bld.new_task_gen(features = 'cxx cc cshlib') + else: + obj = bld.new_task_gen(features = 'cxx cc cprogram') + obj.includes = ['.'] obj.source = gtk2_ardour_sources obj.name = 'gtk2_ardour' - obj.target = 'ardour-3.0' + if bld.env['VST_SUPPORT']: + obj.target = 'gtk2_ardour' + obj.includes += ['../libs/fst'] + else: + obj.target = 'ardour-3.0' obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3') obj.uselib = 'UUID FLAC GLIBMM GTHREAD GTK GNOMECANVAS OGG ALSA' obj.uselib += ' GTKMM GNOMECANVASMM OSX GTKOSX COREAUDIO' @@ -266,7 +282,7 @@ def build(bld): if bld.env['FREESOUND']: obj.source += [ 'sfdb_freesound_mootcher.cc' ] - if bld.env['VST']: + if bld.env['VST_SUPPORT']: obj.source += [ 'vst_pluginui.cc' ] obj.cxxflags += [ '-DVST_SUPPORT' ] @@ -281,6 +297,24 @@ def build(bld): else: obj.source += [ 'x11.cc' ] + if bld.env['VST_SUPPORT']: + # If we require VST support we build a stub main() and the FST library here using + # winegcc, and link it to the GTK front-end library + obj = bld.new_task_gen (features = 'cxx cc cprogram wine') + obj.source = ''' + ../libs/fst/fst.c + ../libs/fst/fstinfofile.c + ../libs/fst/vsti.c + ../libs/fst/vstwin.c + ../vst/winmain.c + ''' + obj.includes = '../libs/fst' + obj.target = 'ardour-3.0-vst' + obj.linkflags = ['-mwindows', '-Wl,--export-dynamic'] + obj.defines = ['_POSIX_SOURCE', 'USE_WS_PREFIX'] + obj.uselib = 'ALSA' + obj.uselib_local = '''libpbd libmidipp libtaglib libardour libardour_cp libgtkmm2ext libtaglib gtk2_ardour''' + # Wrappers wrapper_subst_dict = { diff --git a/libs/ardour/ardour/buffer_set.h b/libs/ardour/ardour/buffer_set.h index 278496ffbc..711e2350fd 100644 --- a/libs/ardour/ardour/buffer_set.h +++ b/libs/ardour/ardour/buffer_set.h @@ -29,6 +29,12 @@ #include "ardour/data_type.h" #include "ardour/types.h" +#ifdef VST_SUPPORT +#include "evoral/MIDIEvent.hpp" +struct VstEvents; +struct VstMidiEvent; +#endif + namespace ARDOUR { class Buffer; @@ -105,6 +111,10 @@ public: void flush_lv2_midi(bool input, size_t i); #endif +#ifdef VST_SUPPORT + VstEvents* get_vst_midi (size_t); +#endif + void read_from(const BufferSet& in, nframes_t nframes); void merge_from(const BufferSet& in, nframes_t nframes); @@ -159,6 +169,31 @@ private: LV2Buffers _lv2_buffers; #endif +#ifdef VST_SUPPORT + class VSTBuffer { + public: + VSTBuffer (size_t); + ~VSTBuffer (); + + void clear (); + void push_back (Evoral::MIDIEvent const &); + VstEvents* events () const { + return _events; + } + + private: + /* prevent copy construction */ + VSTBuffer (VSTBuffer const &); + + VstEvents* _events; /// the parent VSTEvents struct + VstMidiEvent* _midi_events; ///< storage area for VSTMidiEvents + size_t _capacity; + }; + + typedef std::vector VSTBuffers; + VSTBuffers _vst_buffers; +#endif + /// Use counts (there may be more actual buffers than this) ChanCount _count; diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h index cfc5a117a0..07417baa81 100644 --- a/libs/ardour/ardour/vst_plugin.h +++ b/libs/ardour/ardour/vst_plugin.h @@ -85,7 +85,7 @@ class VSTPlugin : public ARDOUR::Plugin bool has_editor () const; XMLNode& get_state(); - int set_state(const XMLNode& node); + int set_state (XMLNode const &, int); AEffect* plugin() const { return _plugin; } FST* fst() const { return _fst; } diff --git a/libs/ardour/buffer_set.cc b/libs/ardour/buffer_set.cc index c97a47e42b..b0f5563564 100644 --- a/libs/ardour/buffer_set.cc +++ b/libs/ardour/buffer_set.cc @@ -33,6 +33,9 @@ #include "ardour/lv2_plugin.h" #include "ardour/lv2_event_buffer.h" #endif +#ifdef VST_SUPPORT +#include "vestige/aeffectx.h" +#endif namespace ARDOUR { @@ -69,6 +72,14 @@ BufferSet::clear() _buffers.clear(); _count.reset(); _available.reset(); + +#ifdef VST_SUPPORT + for (VSTBuffers::iterator i = _vst_buffers.begin(); i != _vst_buffers.end(); ++i) { + delete *i; + } + + _vst_buffers.clear (); +#endif } /** Make this BufferSet a direct mirror of a PortSet's buffers. @@ -147,6 +158,15 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac } #endif +#ifdef VST_SUPPORT + // As above but for VST + if (type == DataType::MIDI) { + while (_vst_buffers.size() < _buffers[type].size()) { + _vst_buffers.push_back (new VSTBuffer (buffer_capacity)); + } + } +#endif + // Post-conditions assert(bufs[0]->type() == type); assert(bufs.size() >= num_buffers); @@ -288,7 +308,86 @@ BufferSet::flush_lv2_midi(bool input, size_t i) } } -#endif +#endif /* HAVE_SLV2 */ + +#ifdef VST_SUPPORT + +VstEvents* +BufferSet::get_vst_midi (size_t b) +{ + MidiBuffer& m = get_midi (b); + VSTBuffer* vst = _vst_buffers[b]; + + vst->clear (); + + for (MidiBuffer::iterator i = m.begin(); i != m.end(); ++i) { + vst->push_back (*i); + } + + return vst->events(); +} + +BufferSet::VSTBuffer::VSTBuffer (size_t c) + : _capacity (c) +{ + _events = static_cast (malloc (sizeof (VstEvents) + _capacity * sizeof (VstEvent *))); + _midi_events = static_cast (malloc (sizeof (VstMidiEvent) * _capacity)); + + if (_events == 0 || _midi_events == 0) { + free (_events); + free (_midi_events); + throw failed_constructor (); + } + + _events->numEvents = 0; + _events->reserved = 0; +} + +BufferSet::VSTBuffer::~VSTBuffer () +{ + free (_events); + free (_midi_events); +} + +void +BufferSet::VSTBuffer::clear () +{ + _events->numEvents = 0; +} + +void +BufferSet::VSTBuffer::push_back (Evoral::MIDIEvent const & ev) +{ + if (ev.size() > 3) { + /* XXX: this will silently drop MIDI messages longer than 3 bytes, so + they won't be passed to VST plugins or VSTis + */ + return; + } + int const n = _events->numEvents; + assert (n < (int) _capacity); + + _events->events[n] = reinterpret_cast (_midi_events + n); + VstMidiEvent* v = reinterpret_cast (_events->events[n]); + + v->type = kVstMidiType; + v->byteSize = sizeof (VstMidiEvent); + v->deltaFrames = ev.time (); + + v->flags = 0; + v->detune = 0; + v->noteLength = 0; + v->noteOffset = 0; + v->reserved1 = 0; + v->reserved2 = 0; + v->noteOffVelocity = 0; + memcpy (v->midiData, ev.buffer(), ev.size()); + v->midiData[3] = 0; + + _events->numEvents++; +} + +#endif /* VST_SUPPORT */ void BufferSet::read_from (const BufferSet& in, nframes_t nframes) diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index ebf0ecab3c..5597fac9e8 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -558,6 +558,7 @@ PluginManager::vst_discover (string path) 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::VST; _vst_plugin_info->push_back (info); diff --git a/libs/ardour/session_vst.cc b/libs/ardour/session_vst.cc index 7f13d3e18b..85b5f13c4c 100644 --- a/libs/ardour/session_vst.cc +++ b/libs/ardour/session_vst.cc @@ -58,11 +58,11 @@ long Session::vst_callback (AEffect* effect, if (effect && effect->user) { plug = (VSTPlugin*) (effect->user); session = &plug->session(); - SHOW_CALLBACK ("am callback 0x%x, opcode = %ld, plugin = \"%s\" ", pthread_self(), opcode, plug->name()); + SHOW_CALLBACK ("am callback 0x%x, opcode = %ld, plugin = \"%s\" ", (int) pthread_self(), opcode, plug->name()); } else { plug = 0; session = 0; - SHOW_CALLBACK ("am callback 0x%x, opcode = %ld", pthread_self(), opcode); + SHOW_CALLBACK ("am callback 0x%x, opcode = %ld", (int) pthread_self(), opcode); } switch(opcode){ @@ -107,6 +107,9 @@ long Session::vst_callback (AEffect* effect, case audioMasterWantMidi: SHOW_CALLBACK ("amc: audioMasterWantMidi\n"); // is a filter which is currently ignored + if (plug) { + plug->get_info()->n_inputs.set_midi (1); + } return 0; case audioMasterGetTime: @@ -345,7 +348,7 @@ long Session::vst_callback (AEffect* effect, return 0; default: - SHOW_CALLBACK ("VST master dispatcher: undefed: %d\n", opcode); + SHOW_CALLBACK ("VST master dispatcher: undefed: %ld\n", opcode); break; } diff --git a/libs/ardour/vst_plugin.cc b/libs/ardour/vst_plugin.cc index 7fb5289f9c..a270c5ba91 100644 --- a/libs/ardour/vst_plugin.cc +++ b/libs/ardour/vst_plugin.cc @@ -49,12 +49,14 @@ #include "ardour/vst_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 +using namespace std; using namespace ARDOUR; using namespace PBD; using std::min; @@ -192,7 +194,7 @@ VSTPlugin::get_state() } int -VSTPlugin::set_state(const XMLNode& node) +VSTPlugin::set_state(const XMLNode& node, int) { LocaleGuard lg (X_("POSIX")); @@ -204,7 +206,7 @@ VSTPlugin::set_state(const XMLNode& node) const XMLProperty* prop; if ((prop = node.property ("current-program")) != 0) { - _fst->current_program = atoi (prop->value()); + _fst->current_program = atoi (prop->value().c_str()); } XMLNode* child; @@ -392,11 +394,13 @@ VSTPlugin::connect_and_run (BufferSet& bufs, 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; @@ -410,6 +414,11 @@ VSTPlugin::connect_and_run (BufferSet& bufs, } + 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 */ _plugin->processReplacing (_plugin, ins, outs, nframes); diff --git a/libs/ardour/wscript b/libs/ardour/wscript index e9bdd644ba..c859a2e88d 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -312,8 +312,10 @@ def build(bld): obj.source += [ 'lv2_plugin.cc', 'lv2_event_buffer.cc', 'uri_map.cc' ] obj.uselib += ' SLV2 ' - if bld.env['VST']: + if bld.env['VST_SUPPORT']: obj.source += [ 'vst_plugin.cc', 'session_vst.cc' ] + obj.includes += [ '../fst' ] + obj.cxxflags += [ '-DVST_SUPPORT' ] if bld.env['HAVE_COREAUDIO'] and bld.env['COREAUDIO']: obj.source += [ 'coreaudiosource.cc', 'caimportable.cc' ] diff --git a/vst/ardevst b/vst/ardevst index f254f908c7..bb7474b8fb 100755 --- a/vst/ardevst +++ b/vst/ardevst @@ -1,5 +1,5 @@ #!/bin/sh . `dirname "$0"`/../build/default/gtk2_ardour/ardev_common_waf.sh -export LD_LIBRARY_PATH=$TOP/gtk2_ardour:$LD_LIBRARY_PATH -exec wine $TOP/vst/ardour_vst.exe.so "$@" +export LD_LIBRARY_PATH=$libs/../gtk2_ardour:$LD_LIBRARY_PATH +exec wine $libs/../gtk2_ardour/ardour-3.0-vst.so "$@"