Fix up VST build and add basic support for VSTi
authorCarl Hetherington <carl@carlh.net>
Sun, 11 Jul 2010 21:55:11 +0000 (21:55 +0000)
committerCarl Hetherington <carl@carlh.net>
Sun, 11 Jul 2010 21:55:11 +0000 (21:55 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@7403 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/plugin_ui.h
gtk2_ardour/vst_pluginui.cc
gtk2_ardour/wscript
libs/ardour/ardour/buffer_set.h
libs/ardour/ardour/vst_plugin.h
libs/ardour/buffer_set.cc
libs/ardour/plugin_manager.cc
libs/ardour/session_vst.cc
libs/ardour/vst_plugin.cc
libs/ardour/wscript
vst/ardevst

index 7b5e77ec18132bb34ff2f6ecdb0452c243fb32bb..bfd23fab6b91965a2f0988dc78605fc7ad3495d9 100644 (file)
@@ -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<Gtk::ListStore> preset_model;
+
+       struct PresetModelColumns : public Gtk::TreeModel::ColumnRecord {
+           PresetModelColumns() { 
+                   add (name);
+                   add (number);
+           }
+           Gtk::TreeModelColumn<Glib::ustring> name;
+           Gtk::TreeModelColumn<int> number;
+       };
+
+       PresetModelColumns preset_columns;
 
        bool configure_handler (GdkEventConfigure*, Gtk::Socket*);
        void save_plugin_setting ();
+       void create_preset_store ();
+       void preset_chosen ();
 };
 #endif // VST_SUPPORT
 
index bd678dd72d7016ebc887e508bca742bca23ae503..6c1b359fd4b0e232e0728d24d49d840257bb1714 100644 (file)
@@ -20,7 +20,7 @@
 #include <fst.h>
 #include <gtk/gtk.h>
 #include <gtk/gtksocket.h>
-#include "ardour/insert.h"
+#include "ardour/plugin_insert.h"
 #include "ardour/vst_plugin.h"
 
 #include "plugin_ui.h"
index ddae851127e33039f132ec941ab962c937639f82..940d43d5b42133762bd8524a9fb0a25ca1ee7dfa 100644 (file)
@@ -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 = {
index 278496ffbc84d741252434c25308e3c5e75480f6..711e2350fddcc4f6d0286f3534f29b2ddfbe73eb 100644 (file)
 #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<nframes_t> 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<VSTBuffer*> VSTBuffers;
+       VSTBuffers _vst_buffers;
+#endif 
+
        /// Use counts (there may be more actual buffers than this)
        ChanCount _count;
 
index cfc5a117a0fb71561cc00705565df9076f1ed5a1..07417baa8184bdd881314aa7efd8f45c55def487 100644 (file)
@@ -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; }
index c97a47e42bbb9ef97a907831946fa93a586b375a..b0f5563564e5d66a55f8061bc03e1271652c934d 100644 (file)
@@ -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<VstEvents*> (malloc (sizeof (VstEvents) + _capacity * sizeof (VstEvent *)));
+       _midi_events = static_cast<VstMidiEvent*> (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<nframes_t> 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<VstEvent*> (_midi_events + n);
+       VstMidiEvent* v = reinterpret_cast<VstMidiEvent*> (_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)
index ebf0ecab3cd83636259e406a10ef5865b6d62690..5597fac9e8802beba71e86644b161ee63a128cbd 100644 (file)
@@ -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);
index 7f13d3e18bfebf47fd74d08b25a82caeee9b68a5..85b5f13c4c95c1622dfda130c4bc0b5ac6891b18 100644 (file)
@@ -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");
                // <value> 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;
        }
 
index 7fb5289f9c6156f0d0c2f91301f8199a475ab650..a270c5ba91319afe561011f6145f7bb8bc40eb7f 100644 (file)
 #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 <locale.h>
 
+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);
index e9bdd644bae4042bac8988339e3080ecd70c4110..c859a2e88dc7887fb13dafd304c492d0bab1f486 100644 (file)
@@ -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' ]
index f254f908c7f4ace4ec8e045a030ba97ae94e26ec..bb7474b8fb195393a507c70c3c883777dcf5ecc0 100755 (executable)
@@ -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 "$@"