Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

Commit [b969e4] Maximize Restore History

* initial velocity sensitive envelope implementation

* optional GTK+ v2.x and PHAT support
* liblo 0.12+ support

Sean Bolton Sean Bolton 2004-11-10

changed src/gui_callbacks.c
changed src/gui_callbacks.h
changed src/gui_data.c
changed src/gui_friendly_patches.c
changed src/gui_interface.c
changed src/gui_interface.h
changed src/gui_main.c
changed src/gui_main.h
changed src/xsynth-dssi.c
changed src/xsynth_data.c
changed src/xsynth_ports.c
changed src/xsynth_ports.h
changed src/xsynth_synth.h
changed src/xsynth_voice.c
changed src/xsynth_voice.h
changed src/xsynth_voice_render.c
changed Makefile.am
changed configure.in
copied dssi.h -> src/xsynth_voice_render-original.c
src/gui_callbacks.c Diff Switch to side-by-side view
Loading...
src/gui_callbacks.h Diff Switch to side-by-side view
Loading...
src/gui_data.c Diff Switch to side-by-side view
Loading...
src/gui_friendly_patches.c Diff Switch to side-by-side view
Loading...
src/gui_interface.c Diff Switch to side-by-side view
Loading...
src/gui_interface.h Diff Switch to side-by-side view
Loading...
src/gui_main.c Diff Switch to side-by-side view
Loading...
src/gui_main.h Diff Switch to side-by-side view
Loading...
src/xsynth-dssi.c Diff Switch to side-by-side view
Loading...
src/xsynth_data.c Diff Switch to side-by-side view
Loading...
src/xsynth_ports.c Diff Switch to side-by-side view
Loading...
src/xsynth_ports.h Diff Switch to side-by-side view
Loading...
src/xsynth_synth.h Diff Switch to side-by-side view
Loading...
src/xsynth_voice.c Diff Switch to side-by-side view
Loading...
src/xsynth_voice.h Diff Switch to side-by-side view
Loading...
src/xsynth_voice_render.c Diff Switch to side-by-side view
Loading...
Makefile.am Diff Switch to side-by-side view
Loading...
configure.in Diff Switch to side-by-side view
Loading...
dssi.h to src/xsynth_voice_render-original.c
--- a/dssi.h
+++ b/src/xsynth_voice_render-original.c
@@ -1,389 +1,368 @@
-/* -*- c-basic-offset: 4 -*- */
-
-/* dssi.h
-
-   Disposable Soft Synth Interface version 0.4
-   Copyright (c) 2004 Chris Cannam, Steve Harris and Sean Bolton
-   
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public License
-   as published by the Free Software Foundation; either version 2.1 of
-   the License, or (at your option) any later version.
-   
-   This library 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
-   Lesser General Public License for more details.
-   
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-   USA.
-*/
-
-#ifndef DSSI_INCLUDED
-#define DSSI_INCLUDED
+/* Xsynth DSSI software synthesizer plugin
+ *
+ * Copyright (C) 2004 Sean Bolton and others.
+ *
+ * Most of this file comes from Steve Brookes' Xsynth,
+ * copyright (C) 1999 S. J. Brookes.
+ * Portions of this file may have come from Peter Hanappe's
+ * Fluidsynth, copyright (C) 2003 Peter Hanappe and others.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#define _BSD_SOURCE    1
+#define _SVID_SOURCE   1
+#define _ISOC99_SOURCE 1
+
+#include <math.h>
 
 #include <ladspa.h>
-#include <alsa/seq_event.h>
-
-#define DSSI_VERSION "0.4"
-#define DSSI_VERSION_MAJOR 0
-#define DSSI_VERSION_MINOR 4
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Rationale:
-
-   There is a need for an API that supports hosted MIDI soft synths
-   with GUIs in Linux audio applications.  We hope that in time the
-   GMPI initiative will comprehensively address this need, but the
-   requirement for Linux applications to be able to support simple
-   hosted synths is here now, and GMPI is not.  This proposal (the
-   "Disposable Soft Synth Interface" or DSSI, pronounced "dizzy") aims
-   to provide the simplest possible interim solution in a way that we
-   hope will prove compelling enough to support now, yet not so
-   compelling as to supplant GMPI or any other comprehensive future
-   proposal.
-
-   For simplicity and familiarity, this API is based as far as
-   possible on existing work -- the LADSPA plugin API for control
-   values and audio processing, and the ALSA sequencer event types for
-   MIDI event communication.  The GUI part of the proposal is quite
-   new, but may also be applicable retroactively to LADSPA plugins
-   that do not otherwise support this synth interface.
-*/
-
-typedef struct _DSSI_Program_Descriptor {
-
-    /** Bank number for this program.  Note that DSSI does not support
-        MIDI-style separation of bank LSB and MSB values.  There is no
-        restriction on the set of available banks: the numbers do not
-        need to be contiguous, there does not need to be a bank 0, etc */
-    unsigned long Bank;
-
-    /** Program number (unique within its bank) for this program.
-	There is no restriction on the set of available programs: the
-	numbers do not need to be contiguous, there does not need to
-	be a program 0, etc. */
-    unsigned long Program;
-
-    /** Name of the program.  This memory is allocated by the plugin
-	using malloc() and must be freed by the host when no longer
-	needed. */
-    const char * Name;
-
-} DSSI_Program_Descriptor;
-
-
-typedef struct _DSSI_Descriptor {
-
-    /**
-     * DSSI_API_Version
-     *
-     * This member indicates the DSSI API level used by this plugin.
-     * If we're lucky, this will never be needed.  For now all plugins
-     * must set it to 1.
-     */
-    int DSSI_API_Version;
-
-    /**
-     * LADSPA_Plugin
-     *
-     * A DSSI synth plugin consists of a LADSPA plugin plus an
-     * additional framework for controlling program settings and
-     * transmitting MIDI events.  A plugin must fully implement the
-     * LADSPA descriptor fields as well as the required LADSPA
-     * functions including instantiate() and (de)activate().  It
-     * should also implement run(), with the same behaviour as if
-     * run_synth() (below) were called with no synth events.
-     *
-     * In order to instantiate a synth the host calls the LADSPA
-     * instantiate function, passing in this LADSPA_Descriptor
-     * pointer.  The returned LADSPA_Handle is used as the argument
-     * for the DSSI functions below as well as for the LADSPA ones.
-     */
-    const LADSPA_Descriptor *LADSPA_Plugin;
-
-    /**
-     * configure()
-     *
-     * This member is a function pointer that sends a piece of
-     * configuration data to the plugin.  The key argument specifies
-     * some aspect of the synth's configuration that is to be changed,
-     * and the value argument specifies a new value for it.
-     *
-     * This call is intended to set some session-scoped aspect of a
-     * plugin's behaviour, for example to tell the plugin to load
-     * sample data from a particular file.  The plugin should act
-     * immediately on the request.  The call should return NULL on
-     * success, or an error string that may be shown to the user.  The
-     * host will free the returned value after use if it is non-NULL.
-     *
-     * Calls to configure() are not automated as timed events.
-     * Instead, a host should remember the last value associated with
-     * each key passed to configure() during a given session for a
-     * given plugin instance, and should call configure() with the
-     * correct value for each key the next time it instantiates the
-     * "same" plugin instance, for example on reloading a project in
-     * which the plugin was used before.  Plugins should note that a
-     * host may typically instantiate a plugin multiple times with the
-     * same configuration values, and should share data between
-     * instances where practical.
-     *
-     * Calling configure() completely invalidates the program and bank
-     * information last obtained from the plugin.
-     */
-     char *(*configure)(LADSPA_Handle Instance,
-			const char *Key,
-			const char *Value);
-
-    /**
-     * get_program()
-     *
-     * This member is a function pointer that provides a description
-     * of a program (named preset sound) available on this synth.  A
-     * plugin that does not support programs at all should set this
-     * member to NULL.
-     *
-     * The Index argument is an index into the plugin's list of
-     * programs, not a program number as represented by the Program
-     * field of the DSSI_Program_Descriptor.  (This distinction is
-     * needed to support synths that use non-contiguous program or
-     * bank numbers.)
-     *
-     * This function returns a DSSI_Program_Descriptor pointer that is
-     * guaranteed to be valid only until the next call to get_program,
-     * deactivate, or configure, on the same plugin instance.  This
-     * function must return NULL if passed an Index argument out of
-     * range, so that the host can use it to query the number of
-     * programs as well as their properties.
-     */
-    const DSSI_Program_Descriptor *(*get_program)(LADSPA_Handle Instance,
-						  unsigned long Index);
+
+#include "xsynth.h"
+#include "xsynth_synth.h"
+#include "xsynth_voice.h"
+
+ /********************************************************************
+ *                                                                   *
+ * What follows below is Steve Brookes' Xsynth code, nearly          *
+ * unmodified except to interface it with my DSSI plugin code. I     *
+ * chose his code because it's simple, and because I think he did a  *
+ * really good job of scaling the knobs to make it easy to get good  *
+ * sounds. It does need band-limited oscillators and a wad of        *
+ * optimization, though.  Since Xsynth-DSSI is intended primarily as *
+ * a demonstration plugin for the DSSI RFC, I've concentrated on     *
+ * implementing that and mostly resisted the temptation to fiddle    *
+ * with Steve's original code.  If you'd like to help with this,     *
+ * please do.  Oh, and Steve, wherever you are -- thanks.            *
+ *                                                                   *
+ ********************************************************************/
+
+#define VCF_FREQ_MAX  (0.825f)    /* filter only stable to this frequency */
+
+float        xsynth_pitch[128];
+
+static float sine_wave[WAVE_POINTS+1],
+             triangle_wave[WAVE_POINTS+1];
+
+void
+xsynth_init_waveforms(void)
+{
+    int i, qn, tqn;
+
+    for (i = 0; i <= WAVE_POINTS; ++i) {
+        sine_wave[i] = sin(2.0f * M_PI * (float)i / WAVE_POINTS);
+    }
+
+    qn = WAVE_POINTS / 4;
+    tqn = 3 * WAVE_POINTS / 4;
+
+    for (i = 0; i <= WAVE_POINTS; ++i) {
+        if (i < qn)
+            triangle_wave[i] = (float)i / (float)qn;
+        else if (i < tqn)
+            triangle_wave[i] = 1.0f - 2.0f * (float)(i - qn) / (float)(tqn - qn);
+        else
+            triangle_wave[i] = (float)(i - tqn) / (float)(WAVE_POINTS - tqn) - 1.0f;
+    }
+}
+
+#define ref_pitch 440.0
+#define ref_note 69
+
+void
+xsynth_pitch_init(void)
+{
+    int i;
+
+    float pexp;
+
+    for (i = 0; i < 128; ++i) {
+        pexp = (float)(i - ref_note) / 12.0f;
+        xsynth_pitch[i] = ref_pitch * pow(2.0f, pexp);
+    }
+}
+
+#define number_of_points 101
+#define number_of_points_m1 100
+
+static float factor[number_of_points];
+static float deriva[number_of_points];
+
+void
+xsynth_volume_init(void)
+{
+  int i;
+  float volume,volume_exponent=1./(2.*log10(2.));
+
+  for(i=0; i<number_of_points; ++i)
+  {
+    volume=(float)i/number_of_points_m1;
+    factor[i]=pow(volume,volume_exponent);
+  }
+
+  for(i=0; i<number_of_points_m1; ++i)
+  {
+    deriva[i]=factor[i+1]-factor[i];
+  }
+}
+
+static inline float
+volume(float level)
+{
+    unsigned char segment;
+    float fract;
+
+    segment = lrintf(floorf((float)number_of_points_m1 * level));
+    fract = (float)number_of_points_m1 * level - (float)segment;
+
+    if (segment == number_of_points_m1)
+        return 1.0f;
+    else
+        return factor[segment] + deriva[segment] * fract;
+}
+
+static inline float
+oscillator(float *pos, float omega, float deltat,
+           unsigned char waveform, float pw, unsigned char *sync)
+{
+    float wpos, f;
+    unsigned char i;
+
+    *pos += deltat * omega;
+
+    if (*pos >= 1.0f) {
+        *pos -= 1.0f;
+        *sync = 1;
+    }
+
+    switch (waveform) {
+      default:
+      case 0:                                                    /* sine wave */
+        wpos = *pos * WAVE_POINTS;
+        i = (unsigned char)lrintf(floorf(wpos));
+        f = wpos - (float)i;
+        return (sine_wave[i] + (sine_wave[i + 1] - sine_wave[i]) * f);
+
+      case 1:                                                /* triangle wave */
+        wpos = *pos * WAVE_POINTS;
+        i = (unsigned char)lrintf(floorf(wpos));
+        f = wpos - (float)i;
+        return (triangle_wave[i] + (triangle_wave[i + 1] - triangle_wave[i]) * f);
+
+      case 2:                                             /* up sawtooth wave */
+        return (*pos * 2.0f - 1.0f);
+
+      case 3:                                           /* down sawtooth wave */
+        return (1.0f - *pos * 2.0f);
+
+      case 4:                                                  /* square wave */
+        return ((*pos < 0.5f) ? 1.0f : -1.0f);
+
+      case 5:                                                   /* pulse wave */
+        return ((*pos < pw) ? 1.0f : -1.0f);
+    }
+}
+
+/*
+ * xsynth_voice_render
+ *
+ * generate the actual sound data for this voice
+ */
+void
+xsynth_voice_render(xsynth_synth_t *synth, xsynth_voice_t *voice,
+                    LADSPA_Data *out, unsigned long sample_count,
+                    int do_control_update)
+{
+    unsigned long sample;
+
+    /* state variables saved in voice */
+
+    float         lfo_pos    = voice->lfo_pos,
+                  eg1        = voice->eg1,
+                  eg2        = voice->eg2,
+                  osc1_pos   = voice->osc1_pos,
+                  osc2_pos   = voice->osc2_pos,
+                  delay1     = voice->delay1,
+                  delay2     = voice->delay2,
+                  delay3     = voice->delay3,
+                  delay4     = voice->delay4;
+    unsigned char eg1_phase  = voice->eg1_phase,
+                  eg2_phase  = voice->eg2_phase;
+
+    /* temporary variables used in calculating voice */
+
+    float fund_pitch;
+    float deltat = 1.0f / (float)synth->sample_rate;
+    float freq, freqkey, freqeg1, freqeg2;
+    float lfo, osc1, deltat2, omega2_t, osc2;
+    float input, freqcut, highpass, output;
+    unsigned char sync_flag1 = 0, sync_flag2 = 0, sync_flag3 = 0;
+
+    /* set up synthesis variables from patch */
+    float         omega1, omega2;
+    unsigned char osc1_waveform = lrintf(*(synth->osc1_waveform));
+    float         osc1_pw = *(synth->osc1_pulsewidth);
+    unsigned char osc2_waveform = lrintf(*(synth->osc2_waveform));
+    float         osc2_pw = *(synth->osc2_pulsewidth);
+    unsigned char osc_sync = (*(synth->osc_sync) > 0.0001f);
+    float         omega3 = *(synth->lfo_frequency);
+    unsigned char lfo_waveform = lrintf(*(synth->lfo_waveform));
+    float         lfo_amount_o = *(synth->lfo_amount_o);
+    float         lfo_amount_f = *(synth->lfo_amount_f);
+    float         eg1_rate_level[3], eg1_one_rate[3];
+    float         eg1_amount_o = *(synth->eg1_amount_o);
+    float         eg2_rate_level[3], eg2_one_rate[3];
+    float         eg2_amount_o = *(synth->eg2_amount_o);
+    float         qres = 0.005 + (1.995f - *(synth->vcf_qres)) * voice->pressure;
+    unsigned char pole4 = (*(synth->vcf_4pole) > 0.0001f);
+    float         balance1 = 1.0f - *(synth->osc_balance);
+    float         balance2 = *(synth->osc_balance);
+    float         vol_out = volume(*(synth->volume));
+
+    fund_pitch = *(synth->glide_time) * voice->target_pitch +
+                 (1.0f - *(synth->glide_time)) * voice->prev_pitch;    /* portamento */
+
+    voice->prev_pitch = fund_pitch;                                 /* save pitch for next time */
+    fund_pitch *= synth->pitch_bend;                                /* modify pitch after portamento */
     
-    /**
-     * select_program()
-     *
-     * This member is a function pointer that selects a new program
-     * for this synth.  The program change should take effect
-     * immediately at the start of the next run_synth() call.  (This
-     * means that a host providing the capability of changing programs
-     * between any two notes on a track must vary the block size so as
-     * to place the program change at the right place.  A host that
-     * wanted to avoid this would probably just instantiate a plugin
-     * for each program.)
-     * 
-     * A plugin that does not support programs at all should set this
-     * member NULL.  Plugins should ignore a select_program() call
-     * with an invalid bank or program.
-     *
-     * A plugin is not required to select any particular default
-     * program on activate(): it's the host's duty to set a program
-     * explicitly.  The current program is invalidated by any call to
-     * configure().
-     */
-    void (*select_program)(LADSPA_Handle Instance,
-			   unsigned long Bank,
-			   unsigned long Program);
-
-    /**
-     * get_midi_controller_for_port()
-     *
-     * This member is a function pointer that returns the MIDI
-     * controller number or NRPN that should be mapped to the given
-     * input control port.  If the given port should not have any MIDI
-     * controller mapped to it, the function should return DSSI_NONE.
-     * The behaviour of this function is undefined if the given port
-     * number does not correspond to an input control port.  A plugin
-     * that does not want MIDI controllers mapped to ports at all may
-     * set this member NULL.
-     *
-     * Correct values can be got using the macros DSSI_CC(num) and
-     * DSSI_NRPN(num) as appropriate, and values can be combined using
-     * bitwise OR: e.g. DSSI_CC(23) | DSSI_NRPN(1069) means the port
-     * should respond to CC #23 and NRPN #1069.
-     *
-     * The host is responsible for doing proper scaling from MIDI
-     * controller and NRPN value ranges to port ranges according to
-     * the plugin's LADSPA port hints.  Hosts should not deliver
-     * through run_synth any MIDI controller events that have already
-     * been mapped to control port values.
-     *
-     * A plugin should not attempt to request mappings from
-     * controllers 0 or 32 (MIDI Bank Select MSB and LSB).
-     */
-    int (*get_midi_controller_for_port)(LADSPA_Handle Instance,
-					unsigned long Port);
-
-    /**
-     * run_synth()
-     *
-     * This member is a function pointer that runs a synth for a
-     * block.  This is identical in function to the LADSPA run()
-     * function, except that it also supplies events to the synth.
-     *
-     * A plugin must provide either this function,
-     * run_multiple_synths() (see below), or both.  A plugin that does
-     * not provide this function must set this member to NULL.  Plugin
-     * authors are encouraged to provide this function if at all
-     * possible.
-     *
-     * The Events pointer points to a block of EventCount ALSA
-     * sequencer events, which is used to communicate MIDI and related
-     * events to the synth.  Each event is timestamped relative to the
-     * start of the block, (mis)using the ALSA "tick time" field as a
-     * frame count. The host is responsible for ensuring that events
-     * with differing timestamps are already ordered by time.
-     *
-     * See also the notes on activation, port connection etc in
-     * ladpsa.h, in the context of the LADSPA run() function.
-     *
-     * Note Events
-     * ~~~~~~~~~~~
-     * There are two minor requirements aimed at making the plugin
-     * writer's life as simple as possible:
-     * 
-     * 1. A host must never send events of type SND_SEQ_EVENT_NOTE.
-     * Notes should always be sent as separate SND_SEQ_EVENT_NOTE_ON
-     * and NOTE_OFF events.  A plugin should discard any one-point
-     * NOTE events it sees.
-     * 
-     * 2. A host must not attempt to switch notes off by sending
-     * zero-velocity NOTE_ON events.  It should always send true
-     * NOTE_OFFs.  It is the host's responsibility to remap events in
-     * cases where an external MIDI source has sent it zero-velocity
-     * NOTE_ONs.
-     *
-     * Bank and Program Events
-     * ~~~~~~~~~~~~~~~~~~~~~~~
-     * Hosts must map MIDI Bank Select MSB and LSB (0 and 32)
-     * controllers and MIDI Program Change events onto the banks and
-     * programs specified by the plugin, using the DSSI select_program
-     * call.  No host should ever deliver a program change or bank
-     * select controller to a plugin via run_synth.
-     */
-    void (*run_synth)(LADSPA_Handle    Instance,
-		      unsigned long    SampleCount,
-		      snd_seq_event_t *Events,
-		      unsigned long    EventCount);
-
-    /**
-     * run_synth_adding()
-     *
-     * This member is a function pointer that runs an instance of a
-     * synth for a block, adding its outputs to the values already
-     * present at the output ports.  This is provided for symmetry
-     * with LADSPA run_adding(), and is equally optional.  A plugin
-     * that does not provide it must set this member to NULL.
-     */
-    void (*run_synth_adding)(LADSPA_Handle    Instance,
-			     unsigned long    SampleCount,
-			     snd_seq_event_t *Events,
-			     unsigned long    EventCount);
-
-    /**
-     * run_multiple_synths()
-     *
-     * This member is a function pointer that runs multiple synth
-     * instances for a block.  This is very similar to run_synth(),
-     * except that Instances, Events, and EventCounts each point to
-     * arrays that hold the LADSPA handles, event buffers, and
-     * event counts for each of InstanceCount instances.  That is,
-     * Instances points to an array of InstanceCount pointers to
-     * DSSI plugin instantiations, Events points to an array of
-     * pointers to each instantiation's respective event list, and
-     * EventCounts points to an array containing each instantiation's
-     * respective event count.
-     *
-     * A host using this function must guarantee that ALL active
-     * instances of the plugin are represented in each call to the
-     * function -- that is, a host may not call run_multiple_synths()
-     * for some instances of a given plugin and then call run_synth()
-     * as well for others.  'All .. instances of the plugin' means
-     * every instance sharing the same LADSPA label and shared object
-     * (*.so) file (rather than every instance sharing the same *.so).
-     * 'Active' means any instance for which activate() has been called
-     * but deactivate() has not.
-     *
-     * A plugin must provide either this function, run_synths() (see
-     * above), or both.  A plugin that does not provide this function
-     * must set this member to NULL.  Plugin authors implementing
-     * run_multiple_synths are strongly encouraged to implement
-     * run_synth as well if at all possible, to aid simplistic hosts,
-     * even where it would be less efficient to use it.
-     */
-    void (*run_multiple_synths)(unsigned long     InstanceCount,
-                                LADSPA_Handle    *Instances,
-                                unsigned long     SampleCount,
-                                snd_seq_event_t **Events,
-                                unsigned long    *EventCounts);
-
-    /**
-     * run_multiple_synths_adding()
-     *
-     * This member is a function pointer that runs multiple synth
-     * instances for a block, adding each synth's outputs to the
-     * values already present at the output ports.  This is provided
-     * for symmetry with both the DSSI run_multiple_synths() and LADSPA
-     * run_adding() functions, and is equally optional.  A plugin
-     * that does not provide it must set this member to NULL.
-     */
-    void (*run_multiple_synths_adding)(unsigned long     InstanceCount,
-                                       LADSPA_Handle    *Instances,
-                                       unsigned long     SampleCount,
-                                       snd_seq_event_t **Events,
-                                       unsigned long    *EventCounts);
-} DSSI_Descriptor;
-
-/**
- * DSSI supports a plugin discovery method similar to that of LADSPA:
- *
- * - DSSI hosts may wish to locate DSSI plugin shared object files by
- *    searching the paths contained in the DSSI_PATH and LADSPA_PATH
- *    environment variables, if they are present.  Both are expected
- *    to be colon-separated lists of directories to be searched (in
- *    order), and DSSI_PATH should be searched first if both variables
- *    are set.
- *
- * - Each shared object file containing DSSI plugins must include a
- *   function dssi_descriptor(), with the following function prototype
- *   and C-style linkage.  Hosts may enumerate the plugin types
- *   available in the shared object file by repeatedly calling
- *   this function with successive Index values (beginning from 0),
- *   until a return value of NULL indicates no more plugin types are
- *   available.  Each non-NULL return is the DSSI_Descriptor
- *   of a distinct plugin type.
- */
-
-const DSSI_Descriptor *dssi_descriptor(unsigned long Index);
-  
-typedef const DSSI_Descriptor *(*DSSI_Descriptor_Function)(unsigned long Index);
-
-/*
- * Macros to specify particular MIDI controllers in return values from
- * get_midi_controller_for_port()
- */
-
-#define DSSI_CC_BITS			0x20000000
-#define DSSI_NRPN_BITS			0x40000000
-
-#define DSSI_NONE			-1
-#define DSSI_CONTROLLER_IS_SET(n)	(DSSI_NONE != (n))
-
-#define DSSI_CC(n)			(DSSI_CC_BITS | (n))
-#define DSSI_IS_CC(n)			(DSSI_CC_BITS & (n))
-#define DSSI_CC_NUMBER(n)		((n) & 0x7f)
-
-#define DSSI_NRPN(n)			(DSSI_NRPN_BITS | ((n) << 7))
-#define DSSI_IS_NRPN(n)			(DSSI_NRPN_BITS & (n))
-#define DSSI_NRPN_NUMBER(n)		(((n) >> 7) & 0x3fff)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* DSSI_INCLUDED */
-
+    omega1 = *(synth->osc1_pitch) * fund_pitch;
+    omega2 = *(synth->osc2_pitch) * fund_pitch;
+
+    eg1_rate_level[0] = *(synth->eg1_attack_time);
+    eg1_one_rate[0] = 1.0f - *(synth->eg1_attack_time);
+    eg1_rate_level[1] = *(synth->eg1_decay_time) * *(synth->eg1_sustain_level);
+    eg1_one_rate[1] = 1.0f - *(synth->eg1_decay_time);
+    eg1_rate_level[2] = 0.0f;
+    eg1_one_rate[2] = 1.0f - *(synth->eg1_release_time);
+    eg2_rate_level[0] = *(synth->eg2_attack_time);
+    eg2_one_rate[0] = 1.0f - *(synth->eg2_attack_time);
+    eg2_rate_level[1] = *(synth->eg2_decay_time) * *(synth->eg2_sustain_level);
+    eg2_one_rate[1] = 1.0f - *(synth->eg2_decay_time);
+    eg2_rate_level[2] = 0.0f;
+    eg2_one_rate[2] = 1.0f - *(synth->eg2_release_time);
+
+    freq = 2.0f * M_PI / (float)synth->sample_rate * fund_pitch * synth->mod_wheel;
+    freqkey = freq * *(synth->vcf_cutoff);
+    freqeg1 = freq * *(synth->eg1_amount_f);
+    freqeg2 = freq * *(synth->eg2_amount_f);
+
+    /* calculate voice */
+
+    for (sample = 0; sample < sample_count; sample++) {
+
+        /* --- LFO section */
+
+        lfo = oscillator(&lfo_pos, omega3, deltat, lfo_waveform, 0.25f, &sync_flag3);
+
+        /* --- EG1 section */
+
+        eg1 = eg1_rate_level[eg1_phase] + eg1_one_rate[eg1_phase] * eg1;
+
+        if (!eg1_phase && eg1 > 0.99f) eg1_phase = 1;  /* flip from attack to decay */
+
+        /* --- EG2 section */
+
+        eg2 = eg2_rate_level[eg2_phase] + eg2_one_rate[eg2_phase] * eg2;
+
+        if (!eg2_phase && eg2 > 0.99f) eg2_phase = 1;  /* flip from attack to decay */
+
+        /* --- VCO 1 section */
+
+        osc1 = oscillator(&osc1_pos, omega1, deltat, osc1_waveform, osc1_pw, &sync_flag1);
+
+        /* --- oscillator sync control */
+
+        if (osc_sync & sync_flag1) {
+            sync_flag1 = 0;
+            osc2_pos = 0.0f;
+            deltat2 = osc1_pos / omega1;
+        } else {
+            deltat2 = deltat;
+        }
+
+        /* --- VCO 2 section */
+
+        omega2_t = omega2 *
+                   (1.0f + eg1 * eg1_amount_o) *
+                   (1.0f + eg2 * eg2_amount_o) *
+                   (1.0f + lfo * lfo_amount_o);
+
+        osc2 = oscillator(&osc2_pos, omega2_t, deltat2, osc2_waveform, osc2_pw, &sync_flag2);
+
+        /* --- cross modulation */
+
+        /* --- mixer section */
+
+        input = balance1 * osc1 + balance2 * osc2;
+
+        /* --- VCF section - Hal Chamberlin's state variable filter */
+
+        freqcut = (freqkey + freqeg1 * eg1 + freqeg2 * eg2) * (1.0f + lfo * lfo_amount_f);
+
+        if (freqcut > VCF_FREQ_MAX) freqcut = VCF_FREQ_MAX;
+
+        delay2 = delay2 + freqcut * delay1;             /* delay2/4 = lowpass output */
+        highpass = input - delay2 - qres * delay1;
+        delay1 = freqcut * highpass + delay1;           /* delay1/3 = bandpass output */
+        output = delay2;
+
+        if (pole4) {  /* above gives 12db per octave, this gives 24db per octave */
+            delay4 = delay4 + freqcut * delay3;
+            highpass = output - delay4 - qres * delay3;
+            delay3 = freqcut * highpass + delay3;
+            output = delay4;
+        }
+
+        /* --- VCA section */
+
+        output *= eg1 * vol_out;
+
+        /* mix voice output into output buffer */
+        out[sample] += output;
+
+        /* update runtime parameters for next sample */
+    }
+
+    if (do_control_update) {
+        /* do those things should be done only once per control-calculation
+         * interval ("nugget"), such as voice check-for-dead, pitch envelope
+         * calculations, volume envelope phase transition checks, etc. */
+
+        /* check if we've decayed to nothing, turn off voice if so */
+        if (eg1_phase == 2 && eg1 < 1.0e-5f) {  /* sound has completed its release phase */
+
+            XDB_MESSAGE(XDB_NOTE, " xsynth_voice_render check for dead: killing note id %d\n", voice->note_id);
+            xsynth_voice_off(voice);
+            return; /* we're dead now, so return */
+        }
+    }
+
+    /* save things for next time around */
+
+    /* already saved prev_pitch above */
+    voice->lfo_pos    = lfo_pos;
+    voice->eg1        = eg1;
+    voice->eg1_phase  = eg1_phase;
+    voice->eg2        = eg2;
+    voice->eg2_phase  = eg2_phase;
+    voice->osc1_pos   = osc1_pos;
+    voice->osc2_pos   = osc2_pos;
+    voice->delay1     = delay1;
+    voice->delay2     = delay2;
+    voice->delay3     = delay3;
+    voice->delay4     = delay4;
+}
+