summaryrefslogtreecommitdiff
path: root/muse2/synti/vam/vam.cpp
diff options
context:
space:
mode:
authorRobert Jonsson <spamatica@gmail.com>2010-10-13 19:34:22 +0000
committerRobert Jonsson <spamatica@gmail.com>2010-10-13 19:34:22 +0000
commit8a2c2824a59d7644e13bc52c9a0ecbd641f21f95 (patch)
tree064ad3f2bf8daab0ad27b128abd86a9bbdb1e496 /muse2/synti/vam/vam.cpp
parenta27706d9629e8b592cca4659f865b70adef24e6d (diff)
new branch muse2, first checkin
Diffstat (limited to 'muse2/synti/vam/vam.cpp')
-rw-r--r--muse2/synti/vam/vam.cpp1050
1 files changed, 1050 insertions, 0 deletions
diff --git a/muse2/synti/vam/vam.cpp b/muse2/synti/vam/vam.cpp
new file mode 100644
index 00000000..95b80c13
--- /dev/null
+++ b/muse2/synti/vam/vam.cpp
@@ -0,0 +1,1050 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+//
+// Parts of this file taken from:
+// The analogue oscillator from Steve Harris plugin collection.
+// Werner Schweer's organ softsynth for MusE.
+// The music-dsp source archive.
+//
+// (C) Copyright 2002 Jotsif Lindman H�nlund (jotsif@linux.nu)
+// (C) Copyright 2005 Robert Jonsson (rj@spamatica.se)
+//
+// 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 or point your web browser to http://www.gnu.org.
+//=========================================================
+
+#include <assert.h>
+#include <cmath>
+#include <stdio.h>
+#include <list>
+
+#include "libsynti/mess.h"
+#include "muse/midi.h"
+#include "muse/midictrl.h"
+
+#include "vam.h"
+#include "vamgui.h"
+#include "libsynti/mono.h"
+
+// Denormalise floats, only actually needed for PIII and very recent PowerPC
+#define DENORMALISE(fv) (((*(unsigned int*)&(fv))&0x7f800000)==0)?0.0f:(fv)
+
+// A fast, truncating towards 0 modulo function. ANSI C doesn't define
+// which % will do, most truncate towards -inf
+#define MOD(v,m) (v<0?v+m:(v>m?v-m:v))
+
+// Limit values
+#define LIMIT(v,l,u) (v<l?l:(v>u?u:v))
+
+#define PI M_PI
+
+//---------------------------------------------------------
+// Oscillator
+//---------------------------------------------------------
+
+struct Oscillator {
+float phase;
+float pitchmod;
+float detune;
+float freq;
+float pwm;
+float pw;
+float fm;
+int waveform;
+bool on;
+};
+
+struct LPFilter {
+float out[4];
+float in[4];
+};
+
+//---------------------------------------------------------
+// Envelope
+//---------------------------------------------------------
+
+struct EnvelopeGenerator {
+static const int onStates = 2;
+static const int offStates = 1;
+
+struct Segment {
+ int ticks;
+ double incr;
+};
+Segment segment[onStates + offStates];
+
+int state;
+double env;
+int tick;
+
+int attack;
+int decay;
+float sustain;
+int release;
+
+EnvelopeGenerator() {
+ segment[0].ticks = 441;
+ segment[0].incr = 1.0/441.0;
+ segment[1].ticks = 0;
+ segment[1].incr = 0.0;
+ segment[2].ticks = 441;
+ segment[2].incr = -(1.0/441.0);
+}
+
+void setSegment(int seg, int ticks, double incr) {
+ segment[seg].ticks = ticks;
+ segment[seg].incr = incr;
+}
+
+void keyOn() {
+// env = 0.0;
+ state = 0;
+ if(env) segment[state].incr = (1.0 - env) / segment[state].ticks;
+ else env = 0.0;
+ tick = segment[state].ticks;
+}
+void keyOff() {
+ state = onStates;
+ tick = segment[state].ticks;
+}
+bool isOff() {
+ return state == (onStates+offStates);
+}
+bool step() {
+ if(state >= onStates+offStates)
+ return false;
+ if (tick == 0)
+ return true;
+ env +=segment[state].incr;
+ if(env < 0.0)
+ env = 0.0;
+ --tick;
+ while(tick == 0) {
+ ++state;
+ if(state >= onStates+offStates)
+ return false;
+ if(state == onStates)
+ return true;
+ tick = segment[state].ticks;
+ }
+ return true;
+}
+};
+
+//---------------------------------------------------------
+// VAM
+//---------------------------------------------------------
+
+class VAM : public MessMono {
+ static int useCount;
+ static const int CB_AMP_SIZE = 961;
+ static const int LIN2EXP_SIZE = 256;
+
+ static double cb2amp_tab[CB_AMP_SIZE];
+ static double cb2amp(double cb);
+
+ static float lin2exp[LIN2EXP_SIZE];
+
+ /* Synthvariables */
+ static float *sin_tbl, *tri_tbl, *saw_tbl, *squ_tbl;
+ bool isOn;
+ int pitch, channel;
+ float velocity;
+
+ //int idata[NUM_CONTROLLER]; // buffer for init data
+ int *idata;
+
+ EnvelopeGenerator dco1_env;
+ EnvelopeGenerator dco2_env;
+ EnvelopeGenerator filt_env;
+
+ LPFilter dco1_filter;
+ LPFilter dco2_filter;
+
+ Oscillator dco1;
+ Oscillator dco2;
+ Oscillator lfo;
+
+ bool filt_invert, filt_keytrack;
+ double filt_env_mod, filt_res, filt_cutoff, keytrack_cutoff;
+
+ int controller[NUM_CONTROLLER];
+ void noteoff(int channel, int pitch);
+ void setController(int ctrl, int data);
+ float *wave_tbl(int wave);
+ double lowpass_filter(double cutoff, double resonance, double input, LPFilter *f);
+
+
+ VAMGui* gui;
+
+ public:
+ virtual int getControllerInfo(int, const char**, int*, int*, int*, int*) const;
+ virtual void getInitData(int* n, const unsigned char**p) const;
+ virtual bool guiVisible() const;
+ virtual void showGui(bool);
+ virtual bool hasGui() const { return true; }
+ virtual void getGeometry(int* x, int* y, int* w, int* h) const;
+ virtual void setGeometry(int x, int y, int w, int h);
+ virtual void processMessages();
+ virtual void process(float**, int, int);
+ virtual void note(int channel, int pitch, int velo);
+ virtual bool setController(int channel, int ctrl, int val);
+ virtual bool sysex(int, const unsigned char*);
+ VAM(int sr);
+ ~VAM();
+ bool init(const char* name);
+};
+
+float* VAM::sin_tbl;
+float* VAM::tri_tbl;
+float* VAM::saw_tbl;
+float* VAM::squ_tbl;
+int VAM::useCount = 0;
+double VAM::cb2amp_tab[VAM::CB_AMP_SIZE];
+float VAM::lin2exp[VAM::LIN2EXP_SIZE];
+
+
+//---------------------------------------------------------
+// VAM
+//---------------------------------------------------------
+
+VAM::VAM(int sr)
+ : MessMono()
+ {
+ idata = new int[NUM_CONTROLLER];
+ setSampleRate(sr);
+ gui = 0;
+ }
+
+//---------------------------------------------------------
+// ~VAM
+//---------------------------------------------------------
+
+VAM::~VAM()
+ {
+ --useCount;
+ if (useCount == 0) {
+ delete[] sin_tbl;
+ delete[] tri_tbl;
+ delete[] saw_tbl;
+ delete[] squ_tbl;
+ }
+ }
+
+//---------------------------------------------------------
+// curTime
+//---------------------------------------------------------
+
+double VAM::cb2amp(double cb)
+ {
+ if(cb < 0.0)
+ return 1.0;
+ if(cb > 960.0)
+ return 0.0;
+ return cb2amp_tab[int(cb)];
+ }
+
+double VAM::lowpass_filter(double cutoff, double resonance, double input, LPFilter *f)
+ {
+ double output;
+ cutoff *= 1.16;
+
+ input -= f->out[3] * (resonance * 4.0) * (1.0 - 0.15 * cutoff * cutoff);
+ input *= 0.35013 * cutoff * cutoff * cutoff * cutoff;
+
+ f->out[0] = input + 0.3 * f->in[0] + (1.0 - cutoff) * f->out[0]; // Pole 1
+ f->in[0] = input;
+ f->out[1] = f->out[0] + 0.3 * f->in[1] + (1.0 - cutoff) * f->out[1]; // Pole 2
+ f->in[1] = f->out[0];
+ f->out[2] = f->out[1] + 0.3 * f->in[2] + (1.0 - cutoff) * f->out[2]; // Pole 3
+ f->in[2] = f->out[1];
+ f->out[3] = f->out[2] + 0.3 * f->in[3] + (1.0 - cutoff) * f->out[3]; // Pole 4
+ f->in[3] = f->out[2];
+
+ // if(f.out[3] > 1.0) f.out[3] = 1.0;
+
+ output = f->out[3];
+
+
+ return output;
+ }
+
+float *VAM::wave_tbl(int wave)
+ {
+ if (wave == 0) {
+ return sin_tbl;
+ }
+ else if (wave == 1) {
+ return squ_tbl;
+ }
+ else if (wave == 2) {
+ return saw_tbl;
+ }
+ else if (wave == 3) {
+ return tri_tbl;
+ }
+ return sin_tbl;
+ }
+
+//---------------------------------------------------------
+// init
+//---------------------------------------------------------
+
+bool VAM::init(const char* name)
+ {
+ gui = new VAMGui;
+ gui->setCaption(QString(name));
+ gui->show();
+
+ if (useCount == 0) {
+ int i;
+ float tmp;
+ for(i = 0; i < CB_AMP_SIZE; i++) {
+ cb2amp_tab[i] = pow(10.0, double(i) / -300.0);
+ //cb2amp_tab[i] = 1.0 - i/(float)CB_AMP_SIZE;
+ }
+ for(i = 0; i < LIN2EXP_SIZE; i++) {
+ tmp = i/255.0;
+ lin2exp[i] = 1.5 * tmp * tmp * tmp - 0.69 * tmp * tmp + 0.16 * tmp;
+ }
+ int sr = sampleRate();
+ /* Build up denormalised oscilator wavetables, these are sample_rate
+ long, costs more RAM to create them but makes freqency calcs much
+ cheaper, and means that interpolation isn't that neccesary, esp if
+ you use integer frequncies */
+
+ float *tmp_tbl = new float[sr];
+ const int lag = sr/50;
+ sin_tbl = new float[sr];
+ for (i = 0; i < sr; i++) {
+ tmp = sin(i * 2.0 * PI / sr);
+ sin_tbl[i] = DENORMALISE(tmp);
+ }
+ tri_tbl = new float[sr];
+ for (i = 0; i < sr; i++) {
+ tmp = acos(cos(i * 2.0 * PI / sr)) / PI * 2.0 - 1.0;
+ tri_tbl[i] = DENORMALISE(tmp);
+ }
+ squ_tbl = new float[sr];
+ for (i = 0; i < sr/2; i++) {
+ tmp_tbl[i] = -1.0f;
+ }
+ for (i = sr/2; i < sr; i++) {
+ tmp_tbl[i] = +1.0f;
+ }
+ tmp = -1.0f;
+ for (i = (sr/2)-lag; i < (sr/2)+lag; i++) {
+ tmp_tbl[i] = tmp;
+ tmp += 1.0/(lag * 2.0);
+ }
+ for (i = 0; i < sr; i++) {
+ squ_tbl[i] = (tmp_tbl[MOD(i-lag, sr)] +
+ tmp_tbl[MOD(i+lag, sr)]) * 0.5;
+ }
+ saw_tbl = new float[sr];
+ for (i = 0; i < sr; i++) {
+ tmp = ((2.0 * i) - (float)sr) / (float)sr;
+ tmp_tbl[i] = DENORMALISE(tmp);
+ }
+ for (i = 0; i < sr; i++) {
+ saw_tbl[i] = (tmp_tbl[MOD(i-lag, sr)] +
+ tmp_tbl[MOD(i+lag, sr)]) * 0.5;
+ }
+ delete[] tmp_tbl;
+ }
+
+ dco1_filter.out[0] = dco1_filter.out[1] = dco1_filter.out[2] = dco1_filter.out[3] = 0.0;
+ dco1_filter.in[0] = dco1_filter.in[1] = dco1_filter.in[2] = dco1_filter.in[3] = 0.0;
+ dco2_filter.out[0] = dco2_filter.out[1] = dco2_filter.out[2] = dco2_filter.out[3] = 0.0;
+ dco2_filter.in[0] = dco2_filter.in[1] = dco2_filter.in[2] = dco2_filter.in[3] = 0.0;
+
+ ++useCount;
+ dco1.phase = 0.0;
+ dco2.phase = 0.0;
+ lfo.phase = 0.0;
+
+ memset(controller, 0, sizeof(controller));
+
+ int maxval = 128*128-1;
+
+ setController(0, DCO1_PITCHMOD, 8191);
+ setController(0, DCO2_PITCHMOD, 8191);
+ setController(0, DCO1_WAVEFORM, 1);
+ setController(0, DCO2_WAVEFORM, 1);
+ setController(0, DCO1_FM, 0);
+ setController(0, DCO2_FM, 0);
+ setController(0, DCO1_PWM, 0);
+ setController(0, DCO2_PWM, 0);
+ setController(0, DCO1_ATTACK, 0);
+ setController(0, DCO2_ATTACK, 0);
+ setController(0, DCO1_DECAY, 0);
+ setController(0, DCO2_DECAY, 0);
+ setController(0, DCO1_SUSTAIN, maxval - 255);
+ setController(0, DCO2_SUSTAIN, maxval - 255);
+ setController(0, DCO1_RELEASE, 0);
+ setController(0, DCO2_RELEASE, 0);
+ setController(0, LFO_FREQ, 0);
+ setController(0, LFO_WAVEFORM, 0);
+ setController(0, FILT_ENV_MOD, 0);
+ setController(0, FILT_KEYTRACK, 0);
+ setController(0, FILT_RES, 0);
+ setController(0, FILT_ATTACK, 0);
+ setController(0, FILT_DECAY, 0);
+ setController(0, FILT_SUSTAIN, maxval);
+ setController(0, FILT_RELEASE, 3);
+ setController(0, DCO2ON, 0);
+ setController(0, FILT_INVERT, 0);
+ setController(0, FILT_CUTOFF, 15000);
+ setController(0, DCO1_DETUNE, 8191);
+ setController(0, DCO2_DETUNE, 8191);
+ setController(0, DCO1_PW, 0);
+ setController(0, DCO2_PW, 0);
+
+ isOn = false;
+ return false;
+ }
+
+//---------------------------------------------------------
+// processMessages
+// Called from host always, even if output path is unconnected.
+//---------------------------------------------------------
+
+void VAM::processMessages()
+{
+ //Process messages from the gui
+ //
+ // get and process all pending events from the
+ // synthesizer GUI
+ //
+ while (gui->fifoSize())
+ {
+ MidiPlayEvent ev = gui->readEvent();
+ if (ev.type() == ME_CONTROLLER)
+ {
+ // process local?
+ setController(ev.dataA() & 0xfff, ev.dataB());
+ sendEvent(ev);
+ }
+ else
+ printf("VAM::process(): unknown event\n");
+ }
+}
+
+//---------------------------------------------------------
+// process
+// Called from host, ONLY if output path is connected.
+//---------------------------------------------------------
+
+void VAM::process(float** ports, int offset, int sampleCount)
+ {
+ /*
+ //
+ // get and process all pending events from the
+ // synthesizer GUI
+ //
+ while (gui->fifoSize()) {
+ MidiPlayEvent ev = gui->readEvent();
+ if (ev.type() == ME_CONTROLLER) {
+ // process local?
+ setController(ev.dataA() & 0xfff, ev.dataB());
+ sendEvent(ev);
+ }
+ else
+ printf("VAM::process(): unknown event\n");
+ }
+ */
+
+ float* buffer = *ports + offset;
+ if (!isOn)
+ return;
+
+ float sample, osc, lfol, *dco1_tbl, *dco2_tbl, *lfo_tbl, pw;
+ float cutoff;
+ int sr = sampleRate();
+
+ dco1_tbl = wave_tbl(dco1.waveform);
+ dco2_tbl = wave_tbl(dco2.waveform);
+ lfo_tbl = wave_tbl(lfo.waveform);
+
+ cutoff = filt_keytrack ? (dco1.freq /500.0 + filt_cutoff)/2 : filt_cutoff;
+ cutoff = LIMIT(cutoff, 0.0, 1.0);
+
+ for (int i = 0; i < sampleCount; i++) {
+ if(!(dco1_env.step() + dco2_env.step())) {
+ isOn = false;
+ break;
+ }
+ filt_env.step();
+
+ /* DCO 1 */
+ lfol = lfo_tbl[(int)lfo.phase];
+ pw = dco1.pw + dco1.pwm * lfol * 0.5;
+ pw = LIMIT(pw, 0.0, 1.0);
+ if(dco1.phase < sr/2 * ( 1.0 - pw))
+ osc = dco1_tbl[int(dco1.phase / (1.0 - pw))];
+ else
+ osc = dco1_tbl[int(dco1.phase / (1.0 + pw))];
+ lfol = lfo_tbl[(int)lfo.phase];
+ dco1.phase += dco1.freq + dco1.fm * lfol * 1500.0;
+ lfo.phase += lfo.freq * 50.0;
+ if(!filt_invert)
+ sample = lowpass_filter((cb2amp(960.0 * (1.0 - filt_env_mod * filt_env.env))
+ + 1.0 - filt_env_mod) * cutoff,
+ filt_res, osc, &dco1_filter) * cb2amp(960.0 * (1.0 - dco1_env.env));
+ else
+ sample = lowpass_filter((cb2amp(960.0 * (1.0 - filt_env_mod * (1.0 - filt_env.env)))
+ + 1.0 - filt_env_mod) * cutoff,
+ filt_res, osc, &dco1_filter) * cb2amp(960.0 * (1.0 - dco1_env.env));
+ while(dco1.phase > sr)
+ dco1.phase -= sr;
+ while(dco1.phase < 0.0)
+ dco1.phase += sr;
+
+ /* DCO 2 */
+ if(dco2.on) {
+ pw = dco2.pw + dco2.pwm * lfol * 0.5;
+ pw = LIMIT(pw, 0.0, 1.0);
+ if(dco2.phase < sr/2 * (1 - pw))
+ osc = dco2_tbl[int(dco2.phase / (1.0 - pw))];
+ else
+ osc = dco2_tbl[int(dco2.phase / (1.0 + pw))];
+ dco2.phase += dco2.freq + dco2.fm * lfol * 1500.0;
+ if(!filt_invert)
+ sample += lowpass_filter((cb2amp(960.0 * (1.0 - filt_env_mod * filt_env.env)) + 1.0 - filt_env_mod) * cutoff,
+ filt_res, osc, &dco2_filter) * cb2amp(960.0 * (1.0 - dco2_env.env));
+ else sample += lowpass_filter((cb2amp(960.0 * (1.0 - filt_env_mod * (1.0 - filt_env.env))) + 1.0 - filt_env_mod)
+ * cutoff, filt_res, osc, &dco2_filter) * cb2amp(960.0 * (1.0 - dco2_env.env));
+
+ while (dco2.phase > sr) dco2.phase -= sr;
+ while (dco2.phase < 0.0) dco2.phase += sr;
+ }
+ while(lfo.phase > sr)
+ lfo.phase -= sr;
+ while(lfo.phase < 0.0)
+ lfo.phase += sr;
+ sample *= velocity * 0.5;
+ sample = LIMIT(sample, -1.0, 1.0);
+
+ //if(sample > 1.0) fprintf(stderr, "oooops %f\n", sample);
+ buffer[i] = sample;
+ }
+ }
+
+//---------------------------------------------------------
+// note
+//---------------------------------------------------------
+
+void VAM::note(int chan, int newpitch, int velo)
+ {
+ if (velo == 0) {
+ noteoff(chan, newpitch);
+ return;
+ }
+ isOn = true;
+ channel = chan;
+ pitch = newpitch;
+ velocity = velo / 127.0;
+ dco1.freq = 8.176 * exp(float(pitch + dco1.pitchmod + dco1.detune)*log(2.0)/12.0);
+ dco2.freq = 8.176 * exp(float(pitch + dco2.pitchmod + dco2.detune)*log(2.0)/12.0);
+ keytrack_cutoff = 16.0 * dco1.freq / sampleRate();
+ if(keytrack_cutoff > 1.0) keytrack_cutoff = 1.0;
+ dco1_env.setSegment(0, dco1_env.attack, 1.0/dco1_env.attack);
+ dco1_env.setSegment(1, dco1_env.decay, -((1.0-dco1_env.sustain)/dco1_env.decay));
+ dco2_env.setSegment(0, dco2_env.attack, 1.0/dco2_env.attack);
+ dco2_env.setSegment(1, dco2_env.decay, -((1.0-dco2_env.sustain)/dco2_env.decay));
+ filt_env.setSegment(0, filt_env.attack, 1.0/filt_env.attack);
+ filt_env.setSegment(1, filt_env.decay, -((1.0-filt_env.sustain)/filt_env.decay));
+ dco1_env.keyOn();
+ dco2_env.keyOn();
+ filt_env.env = 0.0;
+ filt_env.keyOn();
+ // dco1.phase = 0.0;
+ // dco2.phase = 0.0;
+ // lfo.phase = 0.0;
+ }
+
+//---------------------------------------------------------
+// noteoff
+//---------------------------------------------------------
+
+void VAM::noteoff(int chan, int offpitch)
+ {
+ if(isOn && (pitch == offpitch) && (channel == chan)) {
+ dco1_env.keyOff();
+ dco2_env.keyOff();
+ filt_env.keyOff();
+ }
+ }
+
+int VAM::getControllerInfo(int id, const char** name, int* controller,
+ int* min, int* max, int* initval) const
+ {
+ return gui->getControllerInfo(id, name, controller, min, max, initval);
+ }
+
+//---------------------------------------------------------
+// setController
+//---------------------------------------------------------
+
+bool VAM::setController(int /*channel*/, int ctrl, int data)
+ {
+ setController(ctrl & 0xfff, data);
+ MidiPlayEvent ev(0, 0, channel, ME_CONTROLLER, ctrl, data);
+ gui->writeEvent(ev);
+ return false;
+ }
+
+void VAM::setController(int ctrl, int data)
+ {
+ // fprintf(stderr, "ctrl: %d data: %d\n", ctrl, data);
+ int maxval = 128*128-1;
+ double normval = double(data) / double(maxval);
+ switch (ctrl) {
+ case DCO1_PITCHMOD:
+ dco1.pitchmod = (data - 8191) / 341.333;
+ break;
+ case DCO1_WAVEFORM:
+ dco1.waveform = data;
+ break;
+ case DCO1_FM:
+ dco1.fm = lin2exp[int(normval * 255.0)];
+ break;
+ case DCO1_PWM:
+ dco1.pwm = normval;
+ break;
+ case DCO1_ATTACK:
+ dco1_env.attack = int(lin2exp[int(normval * 255.0)] * 5.0 * sampleRate()) + 1;
+ break;
+ case DCO1_DECAY:
+ dco1_env.decay = (data * sampleRate() * 5) / maxval + 1;
+ break;
+ case DCO1_SUSTAIN:
+ dco1_env.sustain = normval;
+ break;
+ case DCO1_RELEASE:
+ dco1_env.release = int(lin2exp[int(normval * 255.0)] * 10.0 * sampleRate()) + 1;
+ dco1_env.setSegment(2, dco1_env.release, -(1.0/dco1_env.release));
+ break;
+
+ case DCO2_PITCHMOD:
+ dco2.pitchmod = (data - 8191) / 341.333;
+ break;
+ case DCO2_WAVEFORM:
+ dco2.waveform = data;
+ break;
+ case DCO2_FM:
+ dco2.fm = normval;
+ break;
+ case DCO2_PWM:
+ dco2.pwm = normval;
+ break;
+ case DCO2_ATTACK:
+ dco2_env.attack = int(lin2exp[int(normval * 255.0)] * 5.0 * sampleRate()) + 1;
+ break;
+ case DCO2_DECAY:
+ dco2_env.decay = (data * sampleRate() * 5) / maxval + 1;
+ break;
+ case DCO2_SUSTAIN:
+ dco2_env.sustain = normval;
+ break;
+ case DCO2_RELEASE:
+ dco2_env.release = int(lin2exp[int(normval * 255.0)] * 10.0 * sampleRate()) + 1;
+ dco2_env.setSegment(2, dco2_env.release, -(1.0/dco2_env.release));
+ break;
+ case LFO_FREQ:
+ lfo.freq = lin2exp[int(normval * 255.0)];
+ //fprintf(stderr, "%f\n", lfo.freq);
+ break;
+ case LFO_WAVEFORM:
+ lfo.waveform = data;
+ break;
+ case FILT_ENV_MOD:
+ filt_env_mod = 1.0 - lin2exp[int(255.0 - normval * 255.0)];
+ break;
+ case FILT_KEYTRACK:
+ filt_keytrack = data;
+ break;
+ case FILT_RES:
+ filt_res = normval;
+ break;
+ case FILT_ATTACK:
+ //filt_env.attack = int(lin2exp[int(normval * 255.0)] * 5.0 * sampleRate());
+ filt_env.attack = int(lin2exp[int(normval * 255.0)] * 5.0 * sampleRate()) + 1;
+ break;
+ case FILT_DECAY:
+ filt_env.decay = (data * sampleRate() * 5) / maxval + 1;
+ break;
+ case FILT_SUSTAIN:
+ filt_env.sustain = normval;
+ break;
+ case FILT_RELEASE:
+ filt_env.release = int(lin2exp[int(normval * 255.0)] * 10.0 * sampleRate()) + 1;
+ filt_env.setSegment(2, filt_env.release, -(1.0/filt_env.release));
+ break;
+ case DCO2ON:
+ dco2.on = data;
+ break;
+ case FILT_INVERT:
+ filt_invert = data;
+ break;
+ case FILT_CUTOFF:
+ filt_cutoff = normval;
+ //fprintf(stderr, "%f\n", filt_cutoff);
+ break;
+ case DCO1_DETUNE:
+ dco1.detune = (data - 8191) / 16384.0;
+ break;
+ case DCO2_DETUNE:
+ dco2.detune = (data - 8191) / 16384.0;
+ break;
+ case DCO1_PW:
+ dco1.pw = normval;
+ if(dco1.pw == 1.0)
+ dco1.pw = 0.99;
+ break;
+ case DCO2_PW:
+ dco2.pw = normval;
+ if(dco2.pw == 1.0) dco2.pw = 0.99;
+ break;
+ default:
+ printf("VAM: set unknown Ctrl 0x%x to 0x%x\n", ctrl, data);
+ break;
+ }
+ controller[ctrl] = data;
+ }
+
+//---------------------------------------------------------
+// getInitData
+//---------------------------------------------------------
+
+void VAM::getInitData(int* n, const unsigned char**p) const
+ {
+ //int i;//prevent of compiler warning: unused variable
+ int* d = idata;
+ //int maxval = 128*128-1; //prevent of compiler warning: unused variable
+ *n = NUM_CONTROLLER * sizeof(int);
+
+// // setController(0, DCO1_PITCHMOD, p++);
+// *d++ = int(dco1.pitchmod+8191*341.333);
+ *d++ = gui->getController(DCO1_PITCHMOD);
+
+// // setController(0, DCO2_PITCHMOD, p++);
+// *d++ = int(dco2.pitchmod+8191*341.333);
+ *d++ = gui->getController(DCO2_PITCHMOD);
+
+// // setController(0, DCO1_WAVEFORM, p++);
+// *d++ = dco1.waveform;
+ *d++ = gui->getController(DCO1_WAVEFORM);
+
+// // setController(0, DCO2_WAVEFORM, p++);
+// *d++ = dco2.waveform;
+ *d++ = gui->getController(DCO2_WAVEFORM);
+
+// // setController(0, DCO1_FM, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs((lin2exp[i] == dco1.fm)) < 0.1)
+// break;
+// }
+// *d++ = int(i/255.0*double(maxval));
+ *d++ = gui->getController(DCO1_FM);
+
+//
+//
+// // setController(0, DCO2_FM, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs((lin2exp[i] - dco2.fm)) < 0.1)
+// break;
+// }
+// *d++ = int(i/255.0*double(maxval));
+ *d++ = gui->getController(DCO2_FM);
+
+//
+// // setController(0, DCO1_PWM, p++);
+// *d++ = int(dco1.pwm*double(maxval));
+ *d++ = gui->getController(DCO1_PWM);
+
+//
+// // setController(0, DCO2_PWM, p++);
+// *d++ = int(dco2.pwm*double(maxval));
+ *d++ = gui->getController(DCO2_PWM);
+
+//
+// // setController(0, DCO1_ATTACK, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs(lin2exp[i] -( (dco1_env.attack-1)/5.0/sampleRate())) < 0.1)
+// break;
+// }
+// *d++ = int(i/255.0*double(maxval));
+ *d++ = gui->getController(DCO1_ATTACK);
+//
+// // setController(0, DCO2_ATTACK, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs(lin2exp[i] -( (dco2_env.attack-1)/5.0/sampleRate())) < 0.1)
+// break;
+// }
+// *d++ = int(i/255.0*double(maxval));
+ *d++ = gui->getController(DCO2_ATTACK);
+
+//
+// // setController(0, DCO1_DECAY, p++);
+// *d++ = int((dco1_env.decay-1)/sampleRate()/5 * maxval);
+ *d++ = gui->getController(DCO1_DECAY);
+
+//
+// // setController(0, DCO2_DECAY, p++);
+// *d++ = int((dco2_env.decay-1)/sampleRate()/5 * maxval);
+ *d++ = gui->getController(DCO2_DECAY);
+
+//
+// // setController(0, DCO1_SUSTAIN, p++ );
+// *d++ = int(dco1_env.sustain*double(maxval));
+ *d++ = gui->getController(DCO1_SUSTAIN);
+
+//
+// // setController(0, DCO2_SUSTAIN, p++ );
+// *d++ = int(dco2_env.sustain*double(maxval));
+ *d++ = gui->getController(DCO2_SUSTAIN);
+//
+// // setController(0, DCO1_RELEASE, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs(lin2exp[i] -( (dco1_env.release-1)/10.0/sampleRate())) < 0.1)
+// break;
+// }
+// *d++ = int(i/255.0*double(maxval));
+ *d++ = gui->getController(DCO1_RELEASE);
+
+//
+// // setController(0, DCO2_RELEASE, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs(lin2exp[i] -( (dco2_env.release-1)/10.0/sampleRate())) < 0.1)
+// break;
+// }
+// *d++ = int(i/255.0*double(maxval));
+ *d++ = gui->getController(DCO2_RELEASE);
+
+//
+// // setController(0, LFO_FREQ, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs((lin2exp[i] - lfo.freq)) < 0.1)
+// break;
+// }
+// *d++ = int(i/255.0*double(maxval));
+ *d++ = gui->getController(LFO_FREQ);
+
+//
+// // setController(0, LFO_WAVEFORM, p++);
+// *d++ = lfo.waveform;
+ *d++ = gui->getController(LFO_WAVEFORM);
+
+//
+// // setController(0, FILT_ENV_MOD, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs((lin2exp[i] - (1 - filt_env_mod))) < 0.1)
+// break;
+// }
+// *d++ = int((255-i)/255.0*double(maxval));
+ *d++ = gui->getController(FILT_ENV_MOD);
+
+//
+// // setController(0, FILT_KEYTRACK, p++);
+// *d++ = filt_keytrack;
+ *d++ = gui->getController(FILT_KEYTRACK);
+
+//
+// // setController(0, FILT_RES, p++);
+// *d++ = int(filt_res*double(maxval));
+ *d++ = gui->getController(FILT_RES);
+
+//
+// // setController(0, FILT_ATTACK, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs(lin2exp[i] -( (filt_env.attack-1)/5.0/sampleRate())) < 0.1)
+// break;
+// }
+// *d++ = int(i/255.0*double(maxval));
+ *d++ = gui->getController(FILT_ATTACK);
+
+//
+// // setController(0, FILT_DECAY, p++);
+// *d++ = int((filt_env.decay-1)/sampleRate()*double(maxval)/5);
+ *d++ = gui->getController(FILT_DECAY);
+
+//
+// // setController(0, FILT_SUSTAIN, p++);
+// *d++ = int(filt_env.sustain*double(maxval));
+ *d++ = gui->getController(FILT_SUSTAIN);
+
+//
+// // setController(0, FILT_RELEASE, p++);
+// for (i = 0;i<LIN2EXP_SIZE;i++) {
+// if (fabs(lin2exp[i] -( (filt_env.release-1)/10.0/sampleRate())) < 0.1)
+// break;
+// }
+// *d++ = int(i/255.0*double(maxval));
+ *d++ = gui->getController(FILT_RELEASE);
+
+//
+// // setController(0, DCO2ON, p++);
+// *d++ = dco2.on;
+ *d++ = gui->getController(DCO2ON);
+
+//
+// // setController(0, FILT_INVERT, p++);
+// *d++ = filt_invert;
+ *d++ = gui->getController(FILT_INVERT);
+
+//
+// // setController(0, FILT_CUTOFF, p++);
+// *d++ = int(filt_cutoff*double(maxval));
+ *d++ = gui->getController(FILT_CUTOFF);
+
+//
+// // setController(0, DCO1_DETUNE, p++);
+// *d++ = int(dco1.detune *16834 + 8191);
+ *d++ = gui->getController(DCO1_DETUNE);
+
+//
+// // setController(0, DCO2_DETUNE, p++);
+// *d++ = int(dco2.detune *16834 + 8191);
+ *d++ = gui->getController(DCO2_DETUNE);
+
+//
+// // setController(0, DCO1_PW, p++);
+// *d++ = int(dco1.pw*double(maxval));
+ *d++ = gui->getController(DCO1_PW);
+
+//
+// // setController(0, DCO2_PW, p++);
+// *d++ = int(dco2.pw*double(maxval));
+ *d++ = gui->getController(DCO2_PW);
+
+ *p = (unsigned char*)idata;
+ }
+
+//---------------------------------------------------------
+// sysex
+//---------------------------------------------------------
+
+bool VAM::sysex(int n, const unsigned char* data)
+ {
+ n=n; // remove warning of unused variable
+ int *p= (int*)data;
+ setController(0, DCO1_PITCHMOD, *p++);
+ setController(0, DCO2_PITCHMOD, *p++);
+ setController(0, DCO1_WAVEFORM, *p++);
+ setController(0, DCO2_WAVEFORM, *p++);
+ setController(0, DCO1_FM, *p++);
+ setController(0, DCO2_FM, *p++);
+ setController(0, DCO1_PWM, *p++);
+ setController(0, DCO2_PWM, *p++);
+ setController(0, DCO1_ATTACK, *p++);
+ setController(0, DCO2_ATTACK, *p++);
+ setController(0, DCO1_DECAY, *p++);
+ setController(0, DCO2_DECAY, *p++);
+ setController(0, DCO1_SUSTAIN, *p++ );
+ setController(0, DCO2_SUSTAIN, *p++ );
+ setController(0, DCO1_RELEASE, *p++);
+ setController(0, DCO2_RELEASE, *p++);
+ setController(0, LFO_FREQ, *p++);
+ setController(0, LFO_WAVEFORM, *p++);
+ setController(0, FILT_ENV_MOD, *p++);
+ setController(0, FILT_KEYTRACK, *p++);
+ setController(0, FILT_RES, *p++);
+ setController(0, FILT_ATTACK, *p++);
+ setController(0, FILT_DECAY, *p++);
+ setController(0, FILT_SUSTAIN, *p++);
+ setController(0, FILT_RELEASE, *p++);
+ setController(0, DCO2ON, *p++);
+ setController(0, FILT_INVERT, *p++);
+ setController(0, FILT_CUTOFF, *p++);
+ setController(0, DCO1_DETUNE, *p++);
+ setController(0, DCO2_DETUNE, *p++);
+ setController(0, DCO1_PW, *p++);
+ setController(0, DCO2_PW, *p++);
+
+ return false;
+ }
+
+//---------------------------------------------------------
+// guiVisible
+//---------------------------------------------------------
+
+bool VAM::guiVisible() const
+ {
+ return gui->isVisible();
+ }
+
+//---------------------------------------------------------
+// showGui
+//---------------------------------------------------------
+
+void VAM::showGui(bool val)
+ {
+ gui->setShown(val);
+ }
+
+//---------------------------------------------------------
+// getGeometry
+//---------------------------------------------------------
+
+void VAM::getGeometry(int* x, int* y, int* w, int* h) const
+ {
+ QPoint pos(gui->pos());
+ QSize size(gui->size());
+ *x = pos.x();
+ *y = pos.y();
+ *w = size.width();
+ *h = size.height();
+ }
+
+//---------------------------------------------------------
+// setGeometry
+//---------------------------------------------------------
+
+void VAM::setGeometry(int x, int y, int w, int h)
+ {
+ gui->resize(QSize(w, h));
+ gui->move(QPoint(x, y));
+ }
+
+//---------------------------------------------------------
+// inst
+//---------------------------------------------------------
+
+class QWidget;
+
+static Mess* instantiate(int sr, QWidget*, QString*, const char* name)
+ {
+ VAM* vam = new VAM(sr);
+ if (vam->init(name)) {
+ delete vam;
+ return 0;
+ }
+ return vam;
+ }
+
+extern "C" {
+ static MESS descriptor = {
+ "vam",
+ "vam soft synth",
+ "0.1", // version string
+ MESS_MAJOR_VERSION, MESS_MINOR_VERSION,
+ instantiate,
+ };
+
+ const MESS* mess_descriptor() { return &descriptor; }
+ }
+