clear up some stupid thinking in Amp regarding the way the underlying AutomationContr...
[ardour.git] / libs / ardour / vst_plugin.cc
index 130c43ede656e51935ee640eca773ff3100975bc..5c9c94bdac9a5d303570bc81729125201bf1f10f 100644 (file)
 
 */
 
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
+
+#include "pbd/floating.h"
 #include "pbd/locale_guard.h"
 #include "pbd/pathscanner.h"
+
 #include "ardour/vst_plugin.h"
 #include "ardour/vestige/aeffectx.h"
 #include "ardour/session.h"
@@ -56,10 +64,6 @@ VSTPlugin::set_plugin (AEffect* e)
 
        _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);
 }
 
 void
@@ -96,10 +100,22 @@ VSTPlugin::get_parameter (uint32_t which) const
 }
 
 void 
-VSTPlugin::set_parameter (uint32_t which, float val)
+VSTPlugin::set_parameter (uint32_t which, float newval)
 {
-       _plugin->setParameter (_plugin, which, val);
-       Plugin::set_parameter (which, val);
+       float oldval = get_parameter (which);
+
+       if (PBD::floateq (oldval, newval, 1)) {
+               return;
+       }
+
+       _plugin->setParameter (_plugin, which, newval);
+       
+       float curval = get_parameter (which);
+
+       if (!PBD::floateq (curval, oldval, 1)) {
+               /* value has changed, follow rest of the notification path */
+               Plugin::set_parameter (which, newval);
+       }
 }
 
 uint32_t
@@ -181,14 +197,15 @@ int
 VSTPlugin::set_state (const XMLNode& node, int version)
 {
        LocaleGuard lg (X_("POSIX"));
+       int ret = -1;
 
        if (node.name() != state_node_name()) {
                error << _("Bad node sent to VSTPlugin::set_state") << endmsg;
                return 0;
        }
 
+#ifndef NO_PLUGIN_STATE
        XMLNode* child;
-       int ret = -1;
 
        if ((child = find_named_node (node, X_("chunk"))) != 0) {
 
@@ -221,6 +238,7 @@ VSTPlugin::set_state (const XMLNode& node, int version)
                ret = 0;
 
        }
+#endif
 
        Plugin::set_state (node, version);
        return ret;
@@ -238,8 +256,6 @@ VSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
 
        if (_plugin->dispatcher (_plugin, effGetParameterProperties, which, 0, &prop, 0)) {
 
-#ifdef VESTIGE_COMPLETE
-
                /* i have yet to find or hear of a VST plugin that uses this */
 
                if (prop.flags & kVstParameterUsesIntegerMinMax) {
@@ -275,17 +291,17 @@ VSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc)
                desc.logarithmic = false;
                desc.sr_dependent = false;
                desc.label = prop.label;
-#endif
 
        } else {
 
                /* old style */
 
                char label[64];
-               label[0] = '\0';
+               /* some VST plugins expect this buffer to be zero-filled */
+               memset (label, 0, sizeof (label));
 
                _plugin->dispatcher (_plugin, effGetParamName, which, 0, label, 0);
-
+               
                desc.label = label;
                desc.integer_step = false;
                desc.lower = 0.0f;
@@ -385,8 +401,8 @@ VSTPlugin::load_user_preset (PresetRecord r)
 
                        return false;
 
-               }
-               else {
+               } 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"));
@@ -425,8 +441,7 @@ VSTPlugin::do_save_preset (string name)
                p->add_content (string (data));
                g_free (data);
 
-       }
-       else {
+       } else {
 
                p = new XMLNode (X_("Preset"));
                p->add_property (X_("uri"), uri);
@@ -444,11 +459,10 @@ VSTPlugin::do_save_preset (string name)
 
        t->root()->add_child_nocopy (*p);
 
-       sys::path f = ARDOUR::user_config_directory ();
-       f /= "presets";
-       f /= presets_file ();
+       std::string f = Glib::build_filename (ARDOUR::user_config_directory (), "presets");
+       f = Glib::build_filename (f, presets_file ());
 
-       t->write (f.to_string ());
+       t->write (f);
        return uri;
 }
 
@@ -462,18 +476,26 @@ VSTPlugin::do_remove_preset (string name)
 
        t->root()->remove_nodes_and_delete (X_("label"), name);
 
-       sys::path f = ARDOUR::user_config_directory ();
-       f /= "presets";
-       f /= presets_file ();
+       std::string f = Glib::build_filename (ARDOUR::user_config_directory (), "presets");
+       f = Glib::build_filename (f, presets_file ());
 
-       t->write (f.to_string ());
+       t->write (f);
 }
 
 string 
 VSTPlugin::describe_parameter (Evoral::Parameter param)
 {
-       char name[64] = "Unkown";
+       char name[64];
+       memset (name, 0, sizeof (name));
+
+       /* some VST plugins expect this buffer to be zero-filled */
+
        _plugin->dispatcher (_plugin, effGetParamName, param.id(), 0, name, 0);
+
+       if (name[0] == '\0') {
+               strcpy (name, _("Unknown"));
+       }
+
        return name;
 }
 
@@ -506,22 +528,44 @@ VSTPlugin::connect_and_run (BufferSet& bufs,
 {
        Plugin::connect_and_run (bufs, in_map, out_map, nframes, offset);
 
-       float *ins[_plugin->numInputs];
-       float *outs[_plugin->numOutputs];
-       int32_t i;
+       ChanCount bufs_count;
+       bufs_count.set(DataType::AUDIO, 1);
+       bufs_count.set(DataType::MIDI, 1);
+
+       BufferSet& silent_bufs  = _session.get_silent_buffers(bufs_count);
+       BufferSet& scratch_bufs = _session.get_scratch_buffers(bufs_count);
 
-       const uint32_t nbufs = bufs.count().n_audio();
+       /* VC++ doesn't support the C99 extension that allows 
+
+          typeName foo[variableDefiningSize];
+          
+          Use alloca instead of dynamic array (rather than std::vector which
+          allocs on the heap) because this is realtime code.
+       */
+          
+       float** ins = (float**)alloca(_plugin->numInputs*sizeof(float*));
+       float** outs = (float**)alloca(_plugin->numInputs*sizeof(float*));
+
+       int32_t i;
 
-       int in_index = 0;
+       uint32_t 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++;
+               uint32_t  index;
+               bool      valid = false;
+               index = in_map.get(DataType::AUDIO, in_index++, &valid);
+               ins[i] = (valid)
+                                       ? bufs.get_audio(index).data(offset)
+                                       : silent_bufs.get_audio(0).data(offset);
        }
 
-       int out_index = 0;
+       uint32_t 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++;
+               uint32_t  index;
+               bool      valid = false;
+               index = out_map.get(DataType::AUDIO, out_index++, &valid);
+               outs[i] = (valid)
+                                       ? bufs.get_audio(index).data(offset)
+                                       : scratch_bufs.get_audio(0).data(offset);
        }
 
        if (bufs.count().n_midi() > 0) {
@@ -530,7 +574,7 @@ VSTPlugin::connect_and_run (BufferSet& bufs,
        }
 
        /* we already know it can support processReplacing */
-       _plugin->processReplacing (_plugin, ins, outs, nframes);
+       _plugin->processReplacing (_plugin, &ins[0], &outs[0], nframes);
 
        return 0;
 }
@@ -606,7 +650,7 @@ VSTPlugin::find_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_("VST:%1:%2"), unique_id (), i), "", false);
+               PresetRecord r (string_compose (X_("VST:%1:%2"), unique_id (), i), "", -1, false);
 
                if (vst_version >= 2) {
                        char buf[256];
@@ -636,7 +680,7 @@ VSTPlugin::find_presets ()
                        assert (uri);
                        assert (label);
 
-                       PresetRecord r (uri->value(), label->value(), true);
+                       PresetRecord r (uri->value(), label->value(), -1, true);
                        _presets.insert (make_pair (r.uri, r));
                }
        }
@@ -651,21 +695,22 @@ VSTPlugin::presets_tree () const
 {
        XMLTree* t = new XMLTree;
 
-       sys::path p = ARDOUR::user_config_directory ();
-       p /= "presets";
+       std::string p = Glib::build_filename (ARDOUR::user_config_directory (), "presets");
 
-       if (!is_directory (p)) {
-               create_directory (p);
+       if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {
+               if (g_mkdir_with_parents (p.c_str(), 0755) != 0) {
+                       error << _("Unable to make VST presets directory") << endmsg;
+               };
        }
 
-       p /= presets_file ();
+       p = Glib::build_filename (p, presets_file ());
 
-       if (!exists (p)) {
+       if (!Glib::file_test (p, Glib::FILE_TEST_EXISTS)) {
                t->set_root (new XMLNode (X_("VSTPresets")));
                return t;
        }
 
-       t->set_filename (p.to_string ());
+       t->set_filename (p);
        if (!t->read ()) {
                delete t;
                return 0;