New directory tree, with preprocessor/ inside interpretor/.
[Faustine.git] / interpretor / preprocessor / faust-0.9.47mr3 / architecture / dssi.cpp
diff --git a/interpretor/preprocessor/faust-0.9.47mr3/architecture/dssi.cpp b/interpretor/preprocessor/faust-0.9.47mr3/architecture/dssi.cpp
new file mode 100644 (file)
index 0000000..9aef8af
--- /dev/null
@@ -0,0 +1,1262 @@
+/************************************************************************
+       IMPORTANT NOTE : this file contains two clearly delimited
+       sections : the ARCHITECTURE section (in two parts) and the
+       USER section. Each section is governed by its own copyright
+       and license. Please check individually each section for
+       license and copyright information.
+*************************************************************************/
+
+/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
+
+/************************************************************************
+    FAUST Architecture File
+       Copyright (C) 2011 Michael J. Wilson
+
+    ---------------------------------------------------------------------
+    This Architecture section 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 3 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, see <http://www.gnu.org/licenses/>.
+
+    EXCEPTION : As a special exception, you may create a larger work
+    that contains this FAUST architecture section and distribute that
+    work under terms of your choice, so long as this FAUST
+    architecture section is not modified.
+    ---------------------------------------------------------------------
+
+************************************************************************/
+
+/********************************************************************
+ * dssi.cpp - Polyphonic dssi wrapper for the FAUST language.
+ *
+ * Usage: faust -a dssi.cpp myfaustprog.dsp
+ *
+ * By Michael J. Wilson (mwilson@alumni.caltech.edu)
+ *
+ * Made with reference to:
+ *   - vsti-mono.cpp by Julius Smith (http://ccrma.stanford.edu/~jos/)
+ *   - ladspa.cpp by GRAME, Centre National de Creation Musicale
+ *   - karplong.cpp by Chris Cannam, Steve Harris, Sean Bolton
+ *
+ * Because of the inclusion of code from ladspa.cpp, this architecture
+ * file is also released under the GNU General Public Licenses version
+ * 3.  Sections which were taken from ladspa.cpp are clearly marked
+ * below, in order to trace the GPL dependency.
+ * As with faust2pd and vsti-mono.cpp, to obtain MIDI control via
+ * NoteOn/Off, Velocity, and KeyNumber, there must be a button named
+ * "gate" and sliders (or numeric entries) named "gain" and "freq" in
+ * the Faust patch specified in myfaustprog.dsp.
+ *
+ * FAUST
+ * Copyright (C) 2003-2007 GRAME, Centre National de Creation Musicale
+ * http://www.grame.fr/
+ *
+ ********************************************************************/
+
+#include "dssi.h"
+#include "ladspa.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stack>
+#include <string>
+#include <map>
+#include <vector>
+#include <list>
+
+// On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
+// flags to avoid costly denormals
+#ifdef __SSE__
+    #include <xmmintrin.h>
+    #ifdef __SSE2__
+        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+    #else
+        #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+    #endif
+#else
+    #warning *** dssi.cpp: NO SSE FLAG (denormals may slow things down) ***
+    #define AVOIDDENORMALS
+#endif
+
+struct Meta : std::map<const char*, const char*>
+{
+    void declare (const char* key, const char* value) { (*this)[key]=value; }
+};
+
+#define max(x,y) (((x)>(y)) ? (x) : (y))
+#define min(x,y) (((x)<(y)) ? (x) : (y))
+
+#define sym(name) xsym(name)
+#define xsym(name) #name
+
+inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
+inline int int2pow2 (int x) { int r=0; while ((1<<r)<x) r++; return r; }
+
+/******************************************************************************
+*******************************************************************************
+
+VECTOR INTRINSICS
+
+*******************************************************************************
+*******************************************************************************/
+
+<<includeIntrinsic>>
+
+//---------------------Abstract User Interface--------------------
+//
+// Abstract definition of a User Interface to be passed to the
+// buildUserInterface method of a Faust Signal Processor
+//
+//----------------------------------------------------------------
+class UI
+{
+    bool fStopped;
+
+public:
+    UI() : fStopped(false) {}
+    virtual ~UI() {}
+
+    virtual void addButton(const char* label, float* zone) = 0;
+    virtual void addToggleButton(const char* label, float* zone) = 0;
+    virtual void addCheckButton(const char* label, float* zone) = 0;
+    virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
+    virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
+    virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
+
+    // -- passive widgets
+    virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
+    virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) = 0;
+    virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
+    virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
+
+    // -- frames and labels
+    virtual void openFrameBox(const char* label) = 0;
+    virtual void openTabBox(const char* label) = 0;
+    virtual void openHorizontalBox(const char* label) = 0;
+    virtual void openVerticalBox(const char* label) = 0;
+    virtual void closeBox() = 0;
+
+    virtual void show() = 0;
+    virtual void run() = 0;
+
+    void stop()                { fStopped = true; }
+    bool stopped()     { return fStopped; }
+
+    virtual void declare(float* zone, const char* key, const char* value) {}
+};
+
+//------------------Abstract Signal Processor---------------------
+//
+//  Abstract definition of a Faust Signal Processor
+//
+//----------------------------------------------------------------
+class dsp
+{
+protected:
+    int fSamplingFreq;
+public:
+    dsp() {}
+    virtual ~dsp() {}
+    virtual int getNumInputs() = 0;
+    virtual int getNumOutputs() = 0;
+    virtual void buildUserInterface(UI* interface) = 0;
+    virtual void init(int samplingRate) = 0;
+    virtual void compute(int len, float** inputs, float** outputs)= 0;
+};
+
+/********************END ARCHITECTURE SECTION (part 1/2)****************/
+
+/**************************BEGIN USER SECTION **************************/
+
+<<includeclass>>
+
+/***************************END USER SECTION ***************************/
+
+/*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
+
+////////////////////////////////////////////////////////////////////////////////
+// Forward declarations
+////////////////////////////////////////////////////////////////////////////////
+class Plugin;
+class DescriptorUI;
+class Voice;
+
+////////////////////////////////////////////////////////////////////////////////
+// Global data
+////////////////////////////////////////////////////////////////////////////////
+// Maximum polyphony, must be at least 1 (TODO make this configurable at compile / runtime?)
+const int MAX_POLYPHONY = 64;
+// Descriptor
+DSSI_Descriptor* g_dssi_descriptor;
+// Additional data for descriptor:
+LADSPA_Descriptor* g_ladspa_descriptor;
+// Program descriptor:
+DSSI_Program_Descriptor g_program_descriptor;
+
+// Global data for the descriptor:
+std::vector<LADSPA_PortDescriptor> g_port_descriptors;
+std::vector<LADSPA_PortRangeHint> g_port_range_hints;
+std::vector<const char*> g_port_names;
+std::string g_name;
+
+////////////////////////////////////////////////////////////////////////////////
+// The enclosed code is from ladspa.cpp 
+// TODO groups of port names
+static const char* inames[] =
+{
+    "input00", "input01", "input02", "input03", "input04",
+    "input05", "input06", "input07", "input08", "input09",
+    "input10", "input11", "input12", "input13", "input14",
+    "input15", "input16", "input17", "input18", "input19",
+    "input20", "input21", "input22", "input23", "input24",
+    "input25", "input26", "input27", "input28", "input29",
+    "input30", "input31", "input32", "input33", "input34",
+    "input35", "input36", "input37", "input38", "input39"
+};
+static const char* onames[] =
+{
+    "output00", "output01", "output02", "output03", "output04",
+    "output05", "output06", "output07", "output08", "output09",
+    "output10", "output11", "output12", "output13", "output14",
+    "output15", "output16", "output17", "output18", "output19",
+    "output20", "output21", "output22", "output23", "output24",
+    "output25", "output26", "output27", "output28", "output29",
+    "output30", "output31", "output32", "output33", "output34",
+    "output35", "output36", "output37", "output38", "output39"
+};
+// END code from ladspa.cpp
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Global helper functions
+////////////////////////////////////////////////////////////////////////////////
+char* get_metadata_if_exists(const char* key, const char* default_string)
+{
+    // TODO probably want to free these somehow.  Currently only used for ladspa descriptor
+    Meta meta;
+    mydsp::metadata(&meta);
+    if(meta.find(key) != meta.end())
+    {
+        return strdup(meta[key]);
+    }
+    else
+    {
+        return strdup(default_string);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// The enclosed code is from ladspa.cpp 
+std::string simplify(const std::string& src)
+{
+    int                i=0;
+    int                level=2;
+    std::string        dst;
+
+    while (src[i] ) {
+
+        switch (level) {
+
+        case 0 :
+        case 1 :
+        case 2 :
+            // Skip the begin of the label "--foo-"
+            // until 3 '-' have been read
+            if (src[i]=='-') { level++; }
+            break;
+
+        case 3 :
+            // copy the content, but skip non alphnum
+            // and content in parenthesis
+            switch (src[i]) {
+            case '(' :
+            case '[' :
+                level++;
+                break;
+
+            case '-' :
+                dst += '-';
+                break;
+
+            default :
+                if (isalnum(src[i])) {
+                    dst+= tolower(src[i]);
+                }
+
+            }
+            break;
+
+        default :
+            // here we are inside parenthesis and
+            // we skip the content until we are back to
+            // level 3
+            switch (src[i]) {
+
+            case '(' :
+            case '[' :
+                level++;
+                break;
+
+            case ')' :
+            case ']' :
+                level--;
+                break;
+
+            default :
+                break;
+            }
+        }
+        i++;
+    }
+    return (dst.size() > 0) ? dst :src;
+}
+// END code from ladspa.cpp
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Single voice; use multiple for polyphony
+////////////////////////////////////////////////////////////////////////////////
+class Voice : public UI
+{
+public:
+    Voice(int sampleRate);
+    ~Voice();
+
+    // UI methods:
+    // TODO don't hardcode these so hard maybe
+    void setFreq(float val);
+    void setGate(float val);
+    void setGain(float val);
+
+    virtual void addButton(const char* label, float* zone);
+    virtual void addToggleButton(const char* label, float* zone);
+    virtual void addCheckButton(const char* label, float* zone);
+    virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step);
+    virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step);
+    virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step);
+
+    virtual void addNumDisplay(const char* label, float* zone, int precision);
+    virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max);
+    virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max);
+    virtual void addVerticalBargraph(const char* label, float* zone, float min, float max);
+
+    virtual void openFrameBox(const char* label);
+    virtual void openTabBox(const char* label);
+    virtual void openHorizontalBox(const char* label);
+    virtual void openVerticalBox(const char* label);
+    virtual void closeBox();
+
+    virtual void show();
+    virtual void run();
+
+    // Internal control (to Faust DSP)
+    std::vector<float*> m_controls;
+
+    // TODO maybe don't make this public eventually
+    mydsp* m_mydsp;
+
+private:
+    // Helpers for UI building:
+    // TODO organize this a bit better later...
+    bool ckAnyMatch(const char* label, const char* indexName, float **zone, float* newZone);
+    bool ckAllMatches(const char* label, float* zone);
+    void addZone(float* zone);
+
+    int m_samplerate;
+
+    float* m_freq_zone;
+    float* m_gate_zone;
+    float* m_gain_zone;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Plugin class to handle DSSI methods:
+////////////////////////////////////////////////////////////////////////////////
+class Plugin : public UI
+{
+public:
+    // LADSPA methods:
+    static LADSPA_Handle instantiate(const LADSPA_Descriptor *, unsigned long);
+    static void connectPort(LADSPA_Handle, unsigned long, LADSPA_Data *);
+    static void activate(LADSPA_Handle);
+    static void run(LADSPA_Handle, unsigned long);
+    static void cleanup(LADSPA_Handle);
+
+    // DSSI methods:
+    static const DSSI_Program_Descriptor* getProgram(LADSPA_Handle, unsigned long);
+    static void selectProgram(LADSPA_Handle, unsigned long, unsigned long);
+    static int getMidiController(LADSPA_Handle, unsigned long);
+    static void runSynth(LADSPA_Handle, unsigned long, snd_seq_event_t *, unsigned long);
+
+    // UI methods:
+    // TODO don't hardcode these so hard maybe
+    void setFreq(float val, int voice = 0);
+    void setGate(float val, int voice = 0);
+    void setGain(float val, int voice = 0);
+
+    virtual void addButton(const char* label, float* zone);
+    virtual void addToggleButton(const char* label, float* zone);
+    virtual void addCheckButton(const char* label, float* zone);
+    virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step);
+    virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step);
+    virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step);
+
+    virtual void addNumDisplay(const char* label, float* zone, int precision);
+    virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max);
+    virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max);
+    virtual void addVerticalBargraph(const char* label, float* zone, float min, float max);
+
+    virtual void openFrameBox(const char* label);
+    virtual void openTabBox(const char* label);
+    virtual void openHorizontalBox(const char* label);
+    virtual void openVerticalBox(const char* label);
+    virtual void closeBox();
+
+    virtual void show();
+    virtual void run();
+
+private:
+    Plugin(int sampleRate);
+    ~Plugin();
+
+    // Helper methods:
+    void updateControlZones();
+    void runImpl(unsigned long, snd_seq_event_t *, unsigned long);
+    void addSamples(int);
+
+    // Helpers for UI building:
+    // TODO organize this a bit better later...
+    bool ckAnyMatch(const char* label, const char* indexName);
+    bool ckAllMatches(const char* label);
+    void add_control_with_default(float default_value);
+
+    int m_samplerate;
+
+    // Voice allocation memebers (TODO maybe break voice allocator into separate class later)
+    // Note each voice is playing
+    std::vector<int> voice_notes;
+    // Queue of free voices
+    std::list<size_t> voice_free;
+
+    // Voices for polyphony
+    std::vector<Voice*> m_voices;
+
+    // Top-level inputs (from DSSI host)
+    std::vector<float*> m_inputs;
+    // Top-level outputs (to DSSI host)
+    std::vector<float*> m_outputs;
+    // Temp vector for collecting outputs TODO this is an ugly way to do it...
+    std::vector<std::vector<float> > m_temp_outputs;
+    // External control (from DSSI host)
+    std::vector<float*> m_controls;
+
+    // Control default values
+    std::vector<float> m_control_defaults;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// UI class to build descriptor, analogous to ladspa.cpp's portCollector
+////////////////////////////////////////////////////////////////////////////////
+const int ICONTROL = LADSPA_PORT_INPUT|LADSPA_PORT_CONTROL;
+const int OCONTROL = LADSPA_PORT_OUTPUT|LADSPA_PORT_CONTROL;
+
+class DescriptorUI : public UI
+{
+public:
+    DescriptorUI(int ins, int outs);
+
+    virtual void addButton(const char* label, float* zone) {
+        if (!ckAnyMatch(label, "gate"))
+        {
+            addPortDescr(ICONTROL, label, LADSPA_HINT_TOGGLED);
+        }
+    }
+    virtual void addToggleButton(const char* label, float* zone) {
+        addPortDescr(ICONTROL, label, LADSPA_HINT_TOGGLED);
+    }
+    virtual void addCheckButton(const char* label, float* zone) {
+        addPortDescr(ICONTROL, label, LADSPA_HINT_TOGGLED);
+    }
+    virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) {
+        if (!ckAllMatches(label))
+        {
+            addPortDescr(ICONTROL, label, LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, min, max);
+        }
+    }
+    virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) {
+        if (!ckAllMatches(label))
+        {
+            addPortDescr(ICONTROL, label, LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, min, max);
+        }
+    }
+    virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) {
+        if (!ckAllMatches(label))
+        {
+            addPortDescr(ICONTROL, label, LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, min, max);
+        }
+    }
+    virtual void addNumDisplay(const char* label, float* zone, int precision) {
+        addPortDescr(OCONTROL, label, 0, -10000, +10000);
+    }
+    virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) {
+        addPortDescr(OCONTROL, label, LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, min, max);
+    }
+    virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) {
+        addPortDescr(OCONTROL, label, LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, min, max);
+    }
+    virtual void addVerticalBargraph(const char* label, float* zone, float min, float max){
+        addPortDescr(OCONTROL, label, LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, min, max);
+    }
+
+    virtual void openFrameBox(const char* label) { openAnyBox(label); }
+    virtual void openTabBox(const char* label) { openAnyBox(label); }
+    virtual void openHorizontalBox(const char* label) { openAnyBox(label); }
+    virtual void openVerticalBox(const char* label) { openAnyBox(label); }
+
+    virtual void closeBox() { fPrefix.pop(); }
+
+    virtual void show() {}
+    virtual void run() {}
+
+private:
+    std::stack<std::string> fPrefix;
+
+    void addPortDescr(int type, const char* label, int hint, float min=0.0, float max=0.0);
+
+    void openAnyBox(const char* label);
+
+    bool ckAnyMatch(const char* label, const char* indexName)
+        {
+            // TODO do case-insensitive here...
+            if (strcmp(label,indexName)==0)
+            {
+                // Don't set values in the DescriptorUI
+                // TODO consolidate this later
+                return true;
+            }
+            return false;
+        }
+    bool ckAllMatches(const char* label)
+        {
+            bool result = false;
+            result = result || ckAnyMatch(label,"gain");
+            result = result || ckAnyMatch(label,"gate");
+            result = result || ckAnyMatch(label,"freq");
+            return result;
+        }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// DescriptorUI methods
+////////////////////////////////////////////////////////////////////////////////
+DescriptorUI::DescriptorUI(int ins, int outs)
+{
+    // Note inputs and outputs
+    for (int i = 0; i < ins; i++)
+    {
+        g_port_descriptors.push_back(LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO);
+        LADSPA_PortRangeHint temp;
+        temp.HintDescriptor = 0;
+        temp.LowerBound = 0;
+        temp.UpperBound = 0;
+        g_port_range_hints.push_back(temp);
+        g_port_names.push_back(inames[i]);
+    }
+    for (int j = 0; j < outs; j++)
+    {
+        g_port_descriptors.push_back(LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO);
+        LADSPA_PortRangeHint temp;
+        temp.HintDescriptor = 0;
+        temp.LowerBound = 0;
+        temp.UpperBound = 0;
+        g_port_range_hints.push_back(temp);
+        g_port_names.push_back(onames[j]);
+    }
+}
+
+void DescriptorUI::addPortDescr(int type, const char* label, int hint, float min, float max)
+{
+////////////////////////////////////////////////////////////////////////////////
+// The enclosed code is derived from ladspa.cpp 
+    std::string fullname = simplify(fPrefix.top() + "-" + label);
+    // TODO for debugging, I'm just using the label for now instead of the full name (since fullname can get long)
+//    char * str = strdup(fullname.c_str());
+    char * str = strdup(label);
+// END code from ladspa.cpp
+////////////////////////////////////////////////////////////////////////////////
+
+    g_port_descriptors.push_back(type);
+    LADSPA_PortRangeHint temp;
+    temp.HintDescriptor = hint;
+    temp.LowerBound = min;
+    temp.UpperBound = max;
+    g_port_range_hints.push_back(temp);
+    g_port_names.push_back(str); // TODO memory leak; need to free
+}
+
+void DescriptorUI::openAnyBox(const char* label)
+{
+////////////////////////////////////////////////////////////////////////////////
+// The enclosed code is from ladspa.cpp 
+    if (fPrefix.size() == 0)
+    {
+        // top level label is used as plugin name
+        g_name = label;
+        fPrefix.push(label);
+    }
+    else
+    {
+        std::string s;
+        if (label && label[0])
+        {
+            s = fPrefix.top() + "-" + label;
+        }
+        else
+        {
+            s = fPrefix.top();
+        }
+        fPrefix.push(s);
+    }
+// END code from ladspa.cpp
+////////////////////////////////////////////////////////////////////////////////
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Plugin methods
+////////////////////////////////////////////////////////////////////////////////
+Plugin::Plugin(int sampleRate) :
+    m_samplerate(sampleRate)
+{
+    int i;
+
+    mydsp temp_mydsp;
+
+    for (i = 0; i < MAX_POLYPHONY; i++)
+    {
+        m_voices.push_back(new Voice(m_samplerate));
+
+        // Voice parameters:
+        voice_free.push_back(i);
+        // TODO using -1 to represent nothing; think of a more clear way to do this
+        voice_notes.push_back(-1);
+    }
+    for (i = 0; i < temp_mydsp.getNumInputs(); i++)
+    {
+        m_inputs.push_back(0);
+    }
+    for (i = 0; i < temp_mydsp.getNumOutputs(); i++)
+    {
+        m_outputs.push_back(0);
+        std::vector<float> temp;
+        temp.push_back(0.0);
+        m_temp_outputs.push_back(temp);
+    }
+}
+
+Plugin::~Plugin()
+{
+    size_t i;
+    for (i = 0; i < m_voices.size(); i++)
+    {
+        delete m_voices[i];
+    }
+}
+
+LADSPA_Handle Plugin::instantiate(const LADSPA_Descriptor *, unsigned long rate)
+{
+    Plugin *plugin = new Plugin(rate);
+    size_t i;
+
+    mydsp* temp_mydsp = new mydsp();
+    temp_mydsp->buildUserInterface(plugin);
+    delete temp_mydsp;
+
+    for (i = 0; i < plugin->m_voices.size(); i++)
+    {
+        plugin->m_voices[i]->m_mydsp->buildUserInterface(plugin->m_voices[i]);
+    }
+    return plugin;
+}
+
+void Plugin::connectPort(LADSPA_Handle handle, unsigned long port, LADSPA_Data *location)
+{
+    Plugin *plugin = (Plugin *)handle;
+
+    // Map inputs, then outputs, then controls:
+    if (port < plugin->m_inputs.size())
+    {
+        *(&plugin->m_inputs[port]) = (float *)location;
+    }
+    else if (port < plugin->m_inputs.size() + plugin->m_outputs.size())
+    {
+        *(&plugin->m_outputs[port - plugin->m_inputs.size()]) = (float *)location;
+    }
+    else
+    {
+        plugin->m_controls[port - plugin->m_inputs.size() - plugin->m_outputs.size()] = (float *)location;
+    }
+}
+
+void Plugin::activate(LADSPA_Handle handle)
+{
+    Plugin *plugin = (Plugin *)handle;
+    for (size_t i = 0; i < plugin->m_voices.size(); i++)
+    {
+        plugin->m_voices[i]->m_mydsp->init(plugin->m_samplerate);
+    }
+}
+
+void Plugin::run(LADSPA_Handle handle, unsigned long samples)
+{
+    runSynth(handle, samples, 0, 0);
+}
+
+void Plugin::cleanup(LADSPA_Handle handle)
+{
+    delete (Plugin *)handle;
+}
+
+const DSSI_Program_Descriptor* Plugin::getProgram(LADSPA_Handle handle, unsigned long index)
+{
+    if (index == 0)
+    {
+        return &g_program_descriptor;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+void Plugin::selectProgram(LADSPA_Handle handle, unsigned long bank, unsigned long program)
+{
+    Plugin *plugin = (Plugin *)handle;
+    for (size_t i = 0; i < plugin->m_controls.size(); i++)
+    {
+        *(plugin->m_controls[i]) = plugin->m_control_defaults[i];
+    }
+}
+
+int Plugin::getMidiController(LADSPA_Handle, unsigned long port)
+{
+    // TODO this is where we need to map MIDI controllers to ports
+    return DSSI_NONE;
+}
+
+void Plugin::updateControlZones()
+{
+    for (size_t i = 0; i < m_controls.size(); i++)
+    {
+        for (size_t j = 0; j < m_voices.size(); j++)
+        {
+            *(m_voices[j]->m_controls[i]) = *(m_controls[i]);
+        }
+    }
+}
+
+void Plugin::runSynth(LADSPA_Handle handle, unsigned long samples, snd_seq_event_t *events, unsigned long eventCount)
+{
+    Plugin *plugin = (Plugin *)handle;
+    plugin->updateControlZones();
+    plugin->runImpl(samples, events, eventCount);
+}
+
+void Plugin::runImpl(unsigned long sampleCount, snd_seq_event_t *events, unsigned long eventCount)
+{
+    unsigned long pos;
+    unsigned long count;
+    unsigned long eventPos;
+    snd_seq_ev_note_t n;
+
+    size_t voice_index;
+
+    pos = 0;
+    eventPos = 0;
+    while (pos < sampleCount)
+    {
+       while ((eventPos < eventCount) &&
+              (pos >= events[eventPos].time.tick))
+        {
+            switch (events[eventPos].type)
+            {
+           case SND_SEQ_EVENT_NOTEON:
+               n = events[eventPos].data.note;
+               if (n.velocity > 0)
+                {
+                    // Look for the next free voice:
+                    if (!voice_free.empty())
+                    {
+                        // Get the index of the first free string and remove it from the list
+                        voice_index = voice_free.front();
+                        voice_free.pop_front();
+
+                        // Play the note on that voice
+                        voice_notes[voice_index] = n.note;
+                        float freq = 440.0f * powf(2.0f,(((float)n.note)-69.0f)/12.0f);
+                        float gain = n.velocity/127.0f;
+                        setFreq(freq, voice_index); // Hz - requires Faust control-signal "freq"
+                        setGain(gain, voice_index); // 0-1 - requires Faust control-signal "gain"
+                        setGate(1.0f, voice_index); // 0 or 1 - requires Faust button-signal "gate"
+                    }
+               }
+               break;
+           case SND_SEQ_EVENT_NOTEOFF:
+                for (voice_index = 0; voice_index < voice_notes.size(); voice_index++)
+                {
+                    if (voice_notes[voice_index] == events[eventPos].data.note.note)
+                    {
+                        setGate(0, voice_index);
+                        // TODO using -1 to represent nothing; think of a more clear way to do this
+                        voice_notes[voice_index] = -1;
+                        voice_free.push_back(voice_index);
+                    }
+                }
+               break;
+           default:
+               break;
+           }
+           ++eventPos;
+       }
+
+       if ((eventPos < eventCount) && (events[eventPos].time.tick < sampleCount))
+        {
+           count = events[eventPos].time.tick - pos;
+       }
+        else
+        {
+            count = sampleCount - pos;
+        }
+
+        addSamples(count);
+       pos += count;
+    }
+}
+
+void Plugin::addSamples(int samples)
+{
+    size_t i;
+    int j;
+    size_t v;
+
+    // TODO this isn't very efficient right now...
+
+    // Grow temp buffers to appropriate size / zero them:
+    for (i = 0; i < m_temp_outputs.size(); i++)
+    {
+        for (j = 0; j < samples; j++)
+        {
+            if (m_temp_outputs[i].size() < (j+1))
+            {
+                m_temp_outputs[i].push_back(0.0);
+            }
+            else
+            {
+                m_temp_outputs[i][j] = 0.0;
+            }
+        }
+    }
+
+    AVOIDDENORMALS;
+
+    // Add all voices together
+    for (v = 0; v < m_voices.size(); v++)
+    {
+        m_voices[v]->m_mydsp->compute(samples, &m_inputs[0], &m_outputs[0]);
+
+        // Accumulate in temp buffer
+        for (i = 0; i < m_outputs.size(); i++)
+        {
+            for (j = 0; j < samples; j++)
+            {
+                m_temp_outputs[i][j] += m_outputs[i][j];
+            }
+        }
+    }
+
+    // Transfer accumulator to actual outputs
+    for (i = 0; i < m_outputs.size(); i++)
+    {
+        for (j = 0; j < samples; j++)
+        {
+            // TODO find a better way to protect against clipping.
+            m_outputs[i][j] = m_temp_outputs[i][j] / (float)MAX_POLYPHONY;
+        }
+    }
+}
+
+void Plugin::setFreq(float val, int voice)
+{
+    m_voices[voice]->setFreq(val);
+}
+
+void Plugin::setGate(float val, int voice)
+{
+    m_voices[voice]->setGate(val);
+}
+
+void Plugin::setGain(float val, int voice)
+{
+    m_voices[voice]->setGain(val);
+}
+
+void Plugin::addButton(const char* label, float* zone)
+{
+    if (!ckAnyMatch(label, "gate"))
+    {
+        add_control_with_default(0);
+    }
+}
+
+void Plugin::addToggleButton(const char* label, float* zone)
+{
+    add_control_with_default(0);
+}
+
+void Plugin::addCheckButton(const char* label, float* zone)
+{
+    add_control_with_default(0);
+}
+
+void Plugin::addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
+{
+    if (!ckAllMatches(label))
+    {
+        add_control_with_default(init);
+    }
+}
+void Plugin::addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
+{
+    if (!ckAllMatches(label))
+    {
+        add_control_with_default(init);
+    }
+}
+void Plugin::addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
+{
+    if (!ckAllMatches(label))
+    {
+        add_control_with_default(init);
+    }
+}
+
+void Plugin::addNumDisplay(const char* label, float* zone, int precision)
+{
+    add_control_with_default(0);
+}
+void Plugin::addTextDisplay(const char* label, float* zone, char* names[], float min, float max)
+{
+    add_control_with_default(0);
+}
+void Plugin::addHorizontalBargraph(const char* label, float* zone, float min, float max)
+{
+    add_control_with_default(min);
+}
+void Plugin::addVerticalBargraph(const char* label, float* zone, float min, float max)
+{
+    add_control_with_default(min);
+}
+
+void Plugin::openFrameBox(const char* label)
+{
+}
+void Plugin::openTabBox(const char* label)
+{
+}
+void Plugin::openHorizontalBox(const char* label)
+{
+}
+void Plugin::openVerticalBox(const char* label)
+{
+}
+void Plugin::closeBox()
+{
+}
+
+void Plugin::show()
+{
+}
+void Plugin::run()
+{
+}
+
+bool Plugin::ckAnyMatch(const char* label, const char* indexName)
+{
+    // TODO do case-insensitive here...
+    if (strcmp(label,indexName)==0)
+    {
+        return true;
+    }
+    return false;
+}
+bool Plugin::ckAllMatches(const char* label)
+{
+    bool result = false;
+    result = result || ckAnyMatch(label,"gain");
+    result = result || ckAnyMatch(label,"gate");
+    result = result || ckAnyMatch(label,"freq");
+    return result;
+}
+void Plugin::add_control_with_default(float default_value)
+{
+    // TODO may need to consider different things for input and output controls...
+    m_controls.push_back(0);
+    m_control_defaults.push_back(default_value);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Voice methods
+////////////////////////////////////////////////////////////////////////////////
+Voice::Voice(int sampleRate) :
+    m_samplerate(sampleRate),
+    m_freq_zone(0),
+    m_gate_zone(0),
+    m_gain_zone(0)
+{
+    m_mydsp = new mydsp();
+}
+
+Voice::~Voice()
+{
+    delete m_mydsp;
+}
+
+void Voice::setFreq(float val)
+{
+    if (m_freq_zone)
+    {
+        *m_freq_zone = val;
+    }
+}
+
+void Voice::setGate(float val)
+{
+    if (m_gate_zone)
+    {
+        *m_gate_zone = val;
+    }
+}
+
+void Voice::setGain(float val)
+{
+    if (m_gain_zone)
+    {
+        *m_gain_zone = val;
+    }
+}
+
+void Voice::addButton(const char* label, float* zone)
+{
+    if (!ckAnyMatch(label, "gate", &m_gate_zone, zone))
+    {
+        addZone(zone);
+    }
+}
+
+void Voice::addToggleButton(const char* label, float* zone)
+{
+    addZone(zone);
+}
+
+void Voice::addCheckButton(const char* label, float* zone)
+{
+    addZone(zone);
+}
+
+void Voice::addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
+{
+    if (!ckAllMatches(label, zone))
+    {
+        addZone(zone);
+    }
+}
+void Voice::addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
+{
+    if (!ckAllMatches(label, zone))
+    {
+        addZone(zone);
+    }
+}
+void Voice::addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
+{
+    if (!ckAllMatches(label, zone))
+    {
+        addZone(zone);
+    }
+}
+
+void Voice::addNumDisplay(const char* label, float* zone, int precision)
+{
+    addZone(zone);
+}
+void Voice::addTextDisplay(const char* label, float* zone, char* names[], float min, float max)
+{
+    addZone(zone);
+}
+void Voice::addHorizontalBargraph(const char* label, float* zone, float min, float max)
+{
+    addZone(zone);
+}
+void Voice::addVerticalBargraph(const char* label, float* zone, float min, float max)
+{
+    addZone(zone);
+}
+
+void Voice::openFrameBox(const char* label)
+{
+}
+void Voice::openTabBox(const char* label)
+{
+}
+void Voice::openHorizontalBox(const char* label)
+{
+}
+void Voice::openVerticalBox(const char* label)
+{
+}
+void Voice::closeBox()
+{
+}
+
+void Voice::show()
+{
+}
+void Voice::run()
+{
+}
+
+bool Voice::ckAnyMatch(const char* label, const char* indexName, float **zone, float* newZone)
+{
+    // TODO do case-insensitive here...
+    if (strcmp(label,indexName)==0)
+    {
+        *zone = newZone;
+        return true;
+    }
+    return false;
+}
+bool Voice::ckAllMatches(const char* label, float* zone)
+{
+    bool result = false;
+    result = result || ckAnyMatch(label,"gain", &m_gain_zone, zone);
+    result = result || ckAnyMatch(label,"gate", &m_gate_zone, zone);
+    result = result || ckAnyMatch(label,"freq", &m_freq_zone, zone);
+    return result;
+}
+void Voice::addZone(float* zone)
+{
+    m_controls.push_back(zone);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Shared object hooks
+////////////////////////////////////////////////////////////////////////////////
+extern "C"
+{
+
+#ifdef __GNUC__
+    __attribute__((constructor)) void init(void)
+#else
+    void _init(void)
+#endif
+    {
+        AVOIDDENORMALS;
+
+        if (g_dssi_descriptor == 0)
+        {
+            g_ladspa_descriptor = new LADSPA_Descriptor();
+            g_dssi_descriptor = new DSSI_Descriptor();
+
+            mydsp* temp_mydsp = new mydsp();
+            DescriptorUI* temp_descriptor_ui = new DescriptorUI(temp_mydsp->getNumInputs(), temp_mydsp->getNumOutputs());
+            temp_mydsp->buildUserInterface(temp_descriptor_ui);
+
+            // Fill the descriptors:
+            // TODO figure out strdup with const strings
+            g_ladspa_descriptor->UniqueID = 0;
+            g_ladspa_descriptor->Label = get_metadata_if_exists("name", g_name.c_str());
+            g_ladspa_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
+            g_ladspa_descriptor->Name = get_metadata_if_exists("name", g_name.c_str());
+            g_ladspa_descriptor->Maker = get_metadata_if_exists("author", "Maker");
+            g_ladspa_descriptor->Copyright = get_metadata_if_exists("copyright", "Copyright");
+            g_ladspa_descriptor->PortCount = g_port_descriptors.size();
+            g_ladspa_descriptor->PortDescriptors = &g_port_descriptors[0];
+            g_ladspa_descriptor->PortNames = &g_port_names[0];
+            g_ladspa_descriptor->PortRangeHints = &g_port_range_hints[0];
+            g_ladspa_descriptor->ImplementationData = 0;
+            g_ladspa_descriptor->instantiate = Plugin::instantiate;
+            g_ladspa_descriptor->connect_port = Plugin::connectPort;
+            g_ladspa_descriptor->activate = Plugin::activate;
+            g_ladspa_descriptor->run = Plugin::run;
+            g_ladspa_descriptor->run_adding = 0;
+            g_ladspa_descriptor->set_run_adding_gain = 0;
+            g_ladspa_descriptor->deactivate = 0;
+            g_ladspa_descriptor->cleanup = Plugin::cleanup;
+
+            g_dssi_descriptor->DSSI_API_Version = 1;
+            g_dssi_descriptor->LADSPA_Plugin = g_ladspa_descriptor;
+            g_dssi_descriptor->configure = 0;
+            g_dssi_descriptor->get_program = Plugin::getProgram;
+            g_dssi_descriptor->select_program = Plugin::selectProgram;
+            g_dssi_descriptor->get_midi_controller_for_port = Plugin::getMidiController;
+            g_dssi_descriptor->run_synth = Plugin::runSynth;
+            g_dssi_descriptor->run_synth_adding = 0;
+            g_dssi_descriptor->run_multiple_synths = 0;
+            g_dssi_descriptor->run_multiple_synths_adding = 0;
+
+            // Program description (TODO if we eventually support multiple programs we will need to handle this differently)
+            g_program_descriptor.Bank = 0;
+            g_program_descriptor.Program = 0;
+            g_program_descriptor.Name = get_metadata_if_exists("name", g_name.c_str());
+
+            delete temp_mydsp;
+            delete temp_descriptor_ui;
+        }
+    }
+
+#ifdef __GNUC__
+    __attribute__((destructor)) void fini(void)
+#else
+    void _fini()
+#endif
+    {
+        if (g_ladspa_descriptor)
+        {
+            delete g_ladspa_descriptor;
+        }
+        if (g_dssi_descriptor)
+        {
+            delete g_dssi_descriptor;
+        }
+    }
+
+    const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
+    {
+        return 0;
+    }
+
+    const DSSI_Descriptor *dssi_descriptor(unsigned long index)
+    {
+        if (index == 0)
+        {
+            return g_dssi_descriptor;
+        }
+        else
+        {
+            return NULL;
+        }
+    }
+}
+
+/********************END ARCHITECTURE SECTION (part 2/2)****************/