aboutsummaryrefslogtreecommitdiffstats
path: root/src/mdaDX10.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mdaDX10.cpp')
-rw-r--r--src/mdaDX10.cpp594
1 files changed, 594 insertions, 0 deletions
diff --git a/src/mdaDX10.cpp b/src/mdaDX10.cpp
new file mode 100644
index 0000000..f533bfe
--- /dev/null
+++ b/src/mdaDX10.cpp
@@ -0,0 +1,594 @@
+//
+// Plug-in: "mda mdaDX10" v1.0
+//
+// Copyright(c)1999-2000 Paul Kellett (maxim digital audio)
+//
+
+#include "mdaDX10.h"
+
+#include <stdio.h>
+#include <stdlib.h> //rand()
+#include <math.h>
+
+AudioEffect *createEffectInstance(audioMasterCallback audioMaster)
+{
+ return new mdaDX10(audioMaster);
+}
+
+
+mdaDX10::mdaDX10(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, NPROGS, NPARAMS)
+{
+ long i=0;
+ Fs = 44100.0f;
+
+ programs = new mdaDX10Program[NPROGS];
+ if(programs)
+ { //Att Dec Rel | Rat C Rat F Att Dec Sus Rel Vel | Vib Oct Fine Rich Thru LFO
+ fillpatch(i++, "Bright E.Piano", 0.000f, 0.650f, 0.441f, 0.842f, 0.329f, 0.230f, 0.800f, 0.050f, 0.800f, 0.900f, 0.000f, 0.500f, 0.500f, 0.447f, 0.000f, 0.414f);
+ fillpatch(i++, "Jazz E.Piano", 0.000f, 0.500f, 0.100f, 0.671f, 0.000f, 0.441f, 0.336f, 0.243f, 0.800f, 0.500f, 0.000f, 0.500f, 0.500f, 0.178f, 0.000f, 0.500f);
+ fillpatch(i++, "E.Piano Pad", 0.000f, 0.700f, 0.400f, 0.230f, 0.184f, 0.270f, 0.474f, 0.224f, 0.800f, 0.974f, 0.250f, 0.500f, 0.500f, 0.428f, 0.836f, 0.500f);
+ fillpatch(i++, "Fuzzy E.Piano", 0.000f, 0.700f, 0.400f, 0.320f, 0.217f, 0.599f, 0.670f, 0.309f, 0.800f, 0.500f, 0.263f, 0.507f, 0.500f, 0.276f, 0.638f, 0.526f);
+ fillpatch(i++, "Soft Chimes", 0.400f, 0.600f, 0.650f, 0.760f, 0.000f, 0.390f, 0.250f, 0.160f, 0.900f, 0.500f, 0.362f, 0.500f, 0.500f, 0.401f, 0.296f, 0.493f);
+ fillpatch(i++, "Harpsichord", 0.000f, 0.342f, 0.000f, 0.280f, 0.000f, 0.880f, 0.100f, 0.408f, 0.740f, 0.000f, 0.000f, 0.600f, 0.500f, 0.842f, 0.651f, 0.500f);
+ fillpatch(i++, "Funk Clav", 0.000f, 0.400f, 0.100f, 0.360f, 0.000f, 0.875f, 0.160f, 0.592f, 0.800f, 0.500f, 0.000f, 0.500f, 0.500f, 0.303f, 0.868f, 0.500f);
+ fillpatch(i++, "Sitar", 0.000f, 0.500f, 0.704f, 0.230f, 0.000f, 0.151f, 0.750f, 0.493f, 0.770f, 0.500f, 0.000f, 0.400f, 0.500f, 0.421f, 0.632f, 0.500f);
+ fillpatch(i++, "Chiff Organ", 0.600f, 0.990f, 0.400f, 0.320f, 0.283f, 0.570f, 0.300f, 0.050f, 0.240f, 0.500f, 0.138f, 0.500f, 0.500f, 0.283f, 0.822f, 0.500f);
+ fillpatch(i++, "Tinkle", 0.000f, 0.500f, 0.650f, 0.368f, 0.651f, 0.395f, 0.550f, 0.257f, 0.900f, 0.500f, 0.300f, 0.800f, 0.500f, 0.000f, 0.414f, 0.500f);
+ fillpatch(i++, "Space Pad", 0.000f, 0.700f, 0.520f, 0.230f, 0.197f, 0.520f, 0.720f, 0.280f, 0.730f, 0.500f, 0.250f, 0.500f, 0.500f, 0.336f, 0.428f, 0.500f);
+ fillpatch(i++, "Koto", 0.000f, 0.240f, 0.000f, 0.390f, 0.000f, 0.880f, 0.100f, 0.600f, 0.740f, 0.500f, 0.000f, 0.500f, 0.500f, 0.526f, 0.480f, 0.500f);
+ fillpatch(i++, "Harp", 0.000f, 0.500f, 0.700f, 0.160f, 0.000f, 0.158f, 0.349f, 0.000f, 0.280f, 0.900f, 0.000f, 0.618f, 0.500f, 0.401f, 0.000f, 0.500f);
+ fillpatch(i++, "Jazz Guitar", 0.000f, 0.500f, 0.100f, 0.390f, 0.000f, 0.490f, 0.250f, 0.250f, 0.800f, 0.500f, 0.000f, 0.500f, 0.500f, 0.263f, 0.145f, 0.500f);
+ fillpatch(i++, "Steel Drum", 0.000f, 0.300f, 0.507f, 0.480f, 0.730f, 0.000f, 0.100f, 0.303f, 0.730f, 1.000f, 0.000f, 0.600f, 0.500f, 0.579f, 0.000f, 0.500f);
+ fillpatch(i++, "Log Drum", 0.000f, 0.300f, 0.500f, 0.320f, 0.000f, 0.467f, 0.079f, 0.158f, 0.500f, 0.500f, 0.000f, 0.400f, 0.500f, 0.151f, 0.020f, 0.500f);
+ fillpatch(i++, "Trumpet", 0.000f, 0.990f, 0.100f, 0.230f, 0.000f, 0.000f, 0.200f, 0.450f, 0.800f, 0.000f, 0.112f, 0.600f, 0.500f, 0.711f, 0.000f, 0.401f);
+ fillpatch(i++, "Horn", 0.280f, 0.990f, 0.280f, 0.230f, 0.000f, 0.180f, 0.400f, 0.300f, 0.800f, 0.500f, 0.000f, 0.400f, 0.500f, 0.217f, 0.480f, 0.500f);
+ fillpatch(i++, "Reed 1", 0.220f, 0.990f, 0.250f, 0.170f, 0.000f, 0.240f, 0.310f, 0.257f, 0.900f, 0.757f, 0.000f, 0.500f, 0.500f, 0.697f, 0.803f, 0.500f);
+ fillpatch(i++, "Reed 2", 0.220f, 0.990f, 0.250f, 0.450f, 0.070f, 0.240f, 0.310f, 0.360f, 0.900f, 0.500f, 0.211f, 0.500f, 0.500f, 0.184f, 0.000f, 0.414f);
+ fillpatch(i++, "Violin", 0.697f, 0.990f, 0.421f, 0.230f, 0.138f, 0.750f, 0.390f, 0.513f, 0.800f, 0.316f, 0.467f, 0.678f, 0.500f, 0.743f, 0.757f, 0.487f);
+ fillpatch(i++, "Chunky Bass", 0.000f, 0.400f, 0.000f, 0.280f, 0.125f, 0.474f, 0.250f, 0.100f, 0.500f, 0.500f, 0.000f, 0.400f, 0.500f, 0.579f, 0.592f, 0.500f);
+ fillpatch(i++, "E.Bass", 0.230f, 0.500f, 0.100f, 0.395f, 0.000f, 0.388f, 0.092f, 0.250f, 0.150f, 0.500f, 0.200f, 0.200f, 0.500f, 0.178f, 0.822f, 0.500f);
+ fillpatch(i++, "Clunk Bass", 0.000f, 0.600f, 0.400f, 0.230f, 0.000f, 0.450f, 0.320f, 0.050f, 0.900f, 0.500f, 0.000f, 0.200f, 0.500f, 0.520f, 0.105f, 0.500f);
+ fillpatch(i++, "Thick Bass", 0.000f, 0.600f, 0.400f, 0.170f, 0.145f, 0.290f, 0.350f, 0.100f, 0.900f, 0.500f, 0.000f, 0.400f, 0.500f, 0.441f, 0.309f, 0.500f);
+ fillpatch(i++, "Sine Bass", 0.000f, 0.600f, 0.490f, 0.170f, 0.151f, 0.099f, 0.400f, 0.000f, 0.900f, 0.500f, 0.000f, 0.400f, 0.500f, 0.118f, 0.013f, 0.500f);
+ fillpatch(i++, "Square Bass", 0.000f, 0.600f, 0.100f, 0.320f, 0.000f, 0.350f, 0.670f, 0.100f, 0.150f, 0.500f, 0.000f, 0.200f, 0.500f, 0.303f, 0.730f, 0.500f);
+ fillpatch(i++, "Upright Bass 1", 0.300f, 0.500f, 0.400f, 0.280f, 0.000f, 0.180f, 0.540f, 0.000f, 0.700f, 0.500f, 0.000f, 0.400f, 0.500f, 0.296f, 0.033f, 0.500f);
+ fillpatch(i++, "Upright Bass 2", 0.300f, 0.500f, 0.400f, 0.360f, 0.000f, 0.461f, 0.070f, 0.070f, 0.700f, 0.500f, 0.000f, 0.400f, 0.500f, 0.546f, 0.467f, 0.500f);
+ fillpatch(i++, "Harmonics", 0.000f, 0.500f, 0.500f, 0.280f, 0.000f, 0.330f, 0.200f, 0.000f, 0.700f, 0.500f, 0.000f, 0.500f, 0.500f, 0.151f, 0.079f, 0.500f);
+ fillpatch(i++, "Scratch", 0.000f, 0.500f, 0.000f, 0.000f, 0.240f, 0.580f, 0.630f, 0.000f, 0.000f, 0.500f, 0.000f, 0.600f, 0.500f, 0.816f, 0.243f, 0.500f);
+ fillpatch(i++, "Syn Tom", 0.000f, 0.355f, 0.350f, 0.000f, 0.105f, 0.000f, 0.000f, 0.200f, 0.500f, 0.500f, 0.000f, 0.645f, 0.500f, 1.000f, 0.296f, 0.500f);
+
+ setProgram(0);
+ }
+
+ if(audioMaster)
+ {
+ setNumInputs(0);
+ setNumOutputs(NOUTS);
+ canProcessReplacing();
+ isSynth();
+ setUniqueID("MDAx"); ///
+ }
+
+ //initialise...
+ for(i=0; i<NVOICES; i++)
+ {
+ voice[i].env = 0.0f;
+ voice[i].car = voice[i].dcar = 0.0f;
+ voice[i].mod0 = voice[i].mod1 = voice[i].dmod = 0.0f;
+ voice[i].cdec = 0.99f; //all notes off
+ }
+ notes[0] = EVENTS_DONE;
+ lfo0 = dlfo = modwhl = 0.0f;
+ lfo1 = pbend = 1.0f;
+ volume = 0.0035f;
+ sustain = activevoices = 0;
+ K = 0;
+
+ update();
+ suspend();
+}
+
+
+void mdaDX10::update() //parameter change //if multitimbral would have to move all this...
+{
+ float ifs = 1.0f / Fs;
+
+ tune = (float)(8.175798915644 * ifs * pow(2.0, floor(param[11] * 6.9) - 2.0));
+
+ rati = param[3];
+ rati = (float)floor(40.1f * rati * rati);
+ if(param[4]<0.5f)
+ ratf = 0.2f * param[4] * param[4];
+ else
+ switch((long)(8.9f * param[4]))
+ {
+ case 4: ratf = 0.25f; break;
+ case 5: ratf = 0.33333333f; break;
+ case 6: ratf = 0.50f; break;
+ case 7: ratf = 0.66666667f; break;
+ default: ratf = 0.75f;
+ }
+ ratio = 1.570796326795f * (rati + ratf);
+
+ depth = 0.0002f * param[5] * param[5];
+ dept2 = 0.0002f * param[7] * param[7];
+
+ velsens = param[9];
+ vibrato = 0.001f * param[10] * param[10];
+
+ catt = 1.0f - (float)exp(-ifs * exp(8.0 - 8.0 * param[0]));
+ if(param[1]>0.98f) cdec = 1.0f; else
+ cdec = (float)exp(-ifs * exp(5.0 - 8.0 * param[1]));
+ crel = (float)exp(-ifs * exp(5.0 - 5.0 * param[2]));
+ mdec = 1.0f - (float)exp(-ifs * exp(6.0 - 7.0 * param[6]));
+ mrel = 1.0f - (float)exp(-ifs * exp(5.0 - 8.0 * param[8]));
+
+ rich = 0.50f - 3.0f * param[13] * param[13];
+ //rich = -1.0f + 2 * param[13];
+ modmix = 0.25f * param[14] * param[14];
+ dlfo = 628.3f * ifs * 25.0f * param[15] * param[15]; //these params not in original DX10
+}
+
+
+void mdaDX10::setSampleRate(float sampleRate)
+{
+ AudioEffectX::setSampleRate(sampleRate);
+ Fs = sampleRate;
+}
+
+
+void mdaDX10::resume()
+{
+ DECLARE_LVZ_DEPRECATED (wantEvents) ();
+ lfo0 = 0.0f;
+ lfo1 = 1.0f; //reset LFO phase
+}
+
+
+mdaDX10::~mdaDX10 () //destroy any buffers...
+{
+ if(programs) delete [] programs;
+}
+
+
+void mdaDX10::setProgram(LvzInt32 program)
+{
+ long i;
+
+ mdaDX10Program *p = &programs[program];
+ curProgram = program;
+ for(i=0; i<NPARAMS; i++) param[i] = p->param[i];
+ update();
+}
+
+
+void mdaDX10::setParameter(LvzInt32 index, float value)
+{
+ mdaDX10Program *p = &programs[curProgram];
+ param[index] = p->param[index] = value;
+ update();
+}
+
+
+void mdaDX10::fillpatch(long p, const char *name,
+ float p0, float p1, float p2, float p3, float p4, float p5,
+ float p6, float p7, float p8, float p9, float p10, float p11,
+ float p12, float p13, float p14, float p15)
+{
+ strcpy(programs[p].name, name);
+ programs[p].param[0] = p0; programs[p].param[1] = p1;
+ programs[p].param[2] = p2; programs[p].param[3] = p3;
+ programs[p].param[4] = p4; programs[p].param[5] = p5;
+ programs[p].param[6] = p6; programs[p].param[7] = p7;
+ programs[p].param[8] = p8; programs[p].param[9] = p9;
+ programs[p].param[10] = p10; programs[p].param[11] = p11;
+ programs[p].param[12] = p12; programs[p].param[13] = p13;
+ programs[p].param[14] = p14; programs[p].param[15] = p15;
+}
+
+
+float mdaDX10::getParameter(LvzInt32 index) { return param[index]; }
+void mdaDX10::setProgramName(char *name) { strcpy(programs[curProgram].name, name); }
+void mdaDX10::getProgramName(char *name) { strcpy(name, programs[curProgram].name); }
+void mdaDX10::setBlockSize(LvzInt32 blockSize) { AudioEffectX::setBlockSize(blockSize); }
+bool mdaDX10::getEffectName(char* name) { strcpy(name, "DX10"); return true; }
+bool mdaDX10::getVendorString(char* text) { strcpy(text, "mda"); return true; }
+bool mdaDX10::getProductString(char* text) { strcpy(text, "mda DX10"); return true; }
+
+
+bool mdaDX10::getOutputProperties(LvzInt32 index, LvzPinProperties* properties)
+{
+ if(index<NOUTS)
+ {
+ sprintf(properties->label, "DX10");
+ properties->flags = kLvzPinIsActive;
+ if(index<2) properties->flags |= kLvzPinIsStereo; //make channel 1+2 stereo
+ return true;
+ }
+ return false;
+}
+
+
+bool mdaDX10::getProgramNameIndexed(LvzInt32 category, LvzInt32 index, char* text)
+{
+ if(index<NPROGS)
+ {
+ strcpy(text, programs[index].name);
+ return true;
+ }
+ return false;
+}
+
+
+bool mdaDX10::copyProgram(LvzInt32 destination)
+{
+ if(destination<NPROGS)
+ {
+ programs[destination] = programs[curProgram];
+ return true;
+ }
+ return false;
+}
+
+
+LvzInt32 mdaDX10::canDo(char* text)
+{
+ if(strcmp(text, "receiveLvzEvents") == 0) return 1;
+ if(strcmp(text, "receiveLvzMidiEvent") == 0) return 1;
+ return -1;
+}
+
+
+void mdaDX10::getParameterName(LvzInt32 index, char *label)
+{
+ switch (index)
+ {
+ case 0: strcpy(label, "Attack "); break;
+ case 1: strcpy(label, "Decay "); break;
+ case 2: strcpy(label, "Release "); break;
+ case 3: strcpy(label, "Coarse "); break;
+ case 4: strcpy(label, "Fine "); break;
+ case 5: strcpy(label, "Mod Init"); break;
+ case 6: strcpy(label, "Mod Dec "); break;
+ case 7: strcpy(label, "Mod Sus "); break;
+ case 8: strcpy(label, "Mod Rel "); break;
+ case 9: strcpy(label, "Mod Vel "); break;
+ case 10: strcpy(label, "Vibrato "); break;
+ case 11: strcpy(label, "Octave "); break;
+ case 12: strcpy(label, "FineTune"); break;
+ case 13: strcpy(label, "Waveform"); break;
+ case 14: strcpy(label, "Mod Thru"); break;
+ default: strcpy(label, "LFO Rate");
+ }
+}
+
+
+void mdaDX10::getParameterDisplay(LvzInt32 index, char *text)
+{
+ char string[16];
+
+ switch(index)
+ {
+ case 3: sprintf(string, "%.0f", rati); break;
+ case 4: sprintf(string, "%.3f", ratf); break;
+ case 11: sprintf(string, "%ld", (long)(param[index] * 6.9f) - 3); break;
+ case 12: sprintf(string, "%.0f", 200.0f * param[index] - 100.0f); break;
+ case 15: sprintf(string, "%.2f", 25.0f * param[index] * param[index]); break;
+ default: sprintf(string, "%.0f", 100.0f * param[index]);
+ }
+ string[8] = 0;
+ strcpy(text, (char *)string);
+}
+
+
+void mdaDX10::getParameterLabel(LvzInt32 index, char *label)
+{
+ switch(index)
+ {
+ case 3:
+ case 4: strcpy(label, "ratio"); break;
+ case 11: strcpy(label, ""); break;
+ case 12: strcpy(label, "cents"); break;
+ case 15: strcpy(label, "Hz"); break;
+ default: strcpy(label, "%");
+ }
+}
+
+
+void mdaDX10::process(float **inputs, float **outputs, LvzInt32 sampleFrames)
+{
+ float* out1 = outputs[0];
+ float* out2 = outputs[1];
+ long event=0, frame=0, frames, v;
+ float o, x, e, mw=MW, w=rich, m=modmix;
+ long k=K;
+
+ if(activevoices>0 || notes[event]<sampleFrames) //detect & bypass completely empty blocks
+ {
+ while(frame<sampleFrames)
+ {
+ frames = notes[event++];
+ if(frames>sampleFrames) frames = sampleFrames;
+ frames -= frame;
+ frame += frames;
+
+ while(--frames>=0) //would be faster with voice loop outside frame loop!
+ { //but then each voice would need it's own LFO...
+ VOICE *V = voice;
+ o = 0.0f;
+
+ if(--k<0)
+ {
+ lfo0 += dlfo * lfo1; //sine LFO
+ lfo1 -= dlfo * lfo0;
+ mw = lfo1 * (modwhl + vibrato);
+ k=100;
+ }
+
+ for(v=0; v<NVOICES; v++) //for each voice
+ {
+ e = V->env;
+ if(e > SILENCE) //**** this is the synth ****
+ {
+ V->env = e * V->cdec; //decay & release
+ V->cenv += V->catt * (e - V->cenv); //attack
+
+ x = V->dmod * V->mod0 - V->mod1; //could add more modulator blocks like
+ V->mod1 = V->mod0; //this for a wider range of FM sounds
+ V->mod0 = x;
+ V->menv += V->mdec * (V->mlev - V->menv);
+
+ x = V->car + V->dcar + x * V->menv + mw; //carrier phase
+ while(x > 1.0f) x -= 2.0f; //wrap phase
+ while(x < -1.0f) x += 2.0f;
+ V->car = x;
+ o += V->cenv * (m * V->mod1 + (x + x * x * x * (w * x * x - 1.0f - w)));
+ } //amp env //mod thru-mix //5th-order sine approximation
+ V++;
+ }
+ *out1++ += o;
+ *out2++ += o;
+ }
+
+ if(frame<sampleFrames) //next note on/off
+ {
+ long note = notes[event++];
+ long vel = notes[event++];
+ noteOn(note, vel);
+ }
+ }
+
+ activevoices = NVOICES;
+ for(v=0; v<NVOICES; v++)
+ {
+ if(voice[v].env < SILENCE) //choke voices that have finished
+ {
+ voice[v].env = voice[v].cenv = 0.0f;
+ activevoices--;
+ }
+ if(voice[v].menv < SILENCE) voice[v].menv = voice[v].mlev = 0.0f;
+ }
+ }
+
+ K=k; MW=mw; //remember these so vibrato speed not buffer size dependant!
+ notes[0] = EVENTS_DONE;
+}
+
+
+void mdaDX10::processReplacing(float **inputs, float **outputs, LvzInt32 sampleFrames)
+{
+ float* out1 = outputs[0];
+ float* out2 = outputs[1];
+ long event=0, frame=0, frames, v;
+ float o, x, e, mw=MW, w=rich, m=modmix;
+ long k=K;
+
+ if(activevoices>0 || notes[event]<sampleFrames) //detect & bypass completely empty blocks
+ {
+ while(frame<sampleFrames)
+ {
+ frames = notes[event++];
+ if(frames>sampleFrames) frames = sampleFrames;
+ frames -= frame;
+ frame += frames;
+
+ while(--frames>=0) //would be faster with voice loop outside frame loop!
+ { //but then each voice would need it's own LFO...
+ VOICE *V = voice;
+ o = 0.0f;
+
+ if(--k<0)
+ {
+ lfo0 += dlfo * lfo1; //sine LFO
+ lfo1 -= dlfo * lfo0;
+ mw = lfo1 * (modwhl + vibrato);
+ k=100;
+ }
+
+ for(v=0; v<NVOICES; v++) //for each voice
+ {
+ e = V->env;
+ if(e > SILENCE) //**** this is the synth ****
+ {
+ V->env = e * V->cdec; //decay & release
+ V->cenv += V->catt * (e - V->cenv); //attack
+
+ x = V->dmod * V->mod0 - V->mod1; //could add more modulator blocks like
+ V->mod1 = V->mod0; //this for a wider range of FM sounds
+ V->mod0 = x;
+ V->menv += V->mdec * (V->mlev - V->menv);
+
+ x = V->car + V->dcar + x * V->menv + mw; //carrier phase
+ while(x > 1.0f) x -= 2.0f; //wrap phase
+ while(x < -1.0f) x += 2.0f;
+ V->car = x;
+ o += V->cenv * (m * V->mod1 + (x + x * x * x * (w * x * x - 1.0f - w)));
+ } //amp env //mod thru-mix //5th-order sine approximation
+
+ /// xx = x * x;
+ /// x + x + x * xx * (xx - 3.0f);
+
+ V++;
+ }
+ *out1++ = o;
+ *out2++ = o;
+ }
+
+ if(frame<sampleFrames) //next note on/off
+ {
+ long note = notes[event++];
+ long vel = notes[event++];
+ noteOn(note, vel);
+ }
+ }
+
+ activevoices = NVOICES;
+ for(v=0; v<NVOICES; v++)
+ {
+ if(voice[v].env < SILENCE) //choke voices that have finished
+ {
+ voice[v].env = voice[v].cenv = 0.0f;
+ activevoices--;
+ }
+ if(voice[v].menv < SILENCE) voice[v].menv = voice[v].mlev = 0.0f;
+ }
+ }
+ else //completely empty block
+ {
+ while(--sampleFrames >= 0)
+ {
+ *out1++ = 0.0f;
+ *out2++ = 0.0f;
+ }
+ }
+ K=k; MW=mw; //remember these so vibrato speed not buffer size dependant!
+ notes[0] = EVENTS_DONE;
+}
+
+
+void mdaDX10::noteOn(long note, long velocity)
+{
+ float l = 1.0f;
+ long v, vl=0;
+
+ if(velocity>0)
+ {
+ for(v=0; v<NVOICES; v++) //find quietest voice
+ {
+ if(voice[v].env<l) { l=voice[v].env; vl=v; }
+ }
+
+ l = (float)exp(0.05776226505f * ((float)note + param[12] + param[12] - 1.0f));
+ voice[vl].note = note; //fine tuning
+ voice[vl].car = 0.0f;
+ voice[vl].dcar = tune * pbend * l; //pitch bend not updated during note as a bit tricky...
+
+ if(l>50.0f) l = 50.0f; //key tracking
+ l *= (64.0f + velsens * (velocity - 64)); //vel sens
+ voice[vl].menv = depth * l;
+ voice[vl].mlev = dept2 * l;
+ voice[vl].mdec = mdec;
+
+ voice[vl].dmod = ratio * voice[vl].dcar; //sine oscillator
+ voice[vl].mod0 = 0.0f;
+ voice[vl].mod1 = (float)sin(voice[vl].dmod);
+ voice[vl].dmod = 2.0f * (float)cos(voice[vl].dmod);
+ //scale volume with richness
+ voice[vl].env = (1.5f - param[13]) * volume * (velocity + 10);
+ voice[vl].catt = catt;
+ voice[vl].cenv = 0.0f;
+ voice[vl].cdec = cdec;
+ }
+ else //note off
+ {
+ for(v=0; v<NVOICES; v++) if(voice[v].note==note) //any voices playing that note?
+ {
+ if(sustain==0)
+ {
+ voice[v].cdec = crel; //release phase
+ voice[v].env = voice[v].cenv;
+ voice[v].catt = 1.0f;
+ voice[v].mlev = 0.0f;
+ voice[v].mdec = mrel;
+ }
+ else voice[v].note = SUSTAIN;
+ }
+ }
+}
+
+
+LvzInt32 mdaDX10::processEvents(LvzEvents* ev)
+{
+ long npos=0;
+
+ for (long i=0; i<ev->numEvents; i++)
+ {
+ if((ev->events[i])->type != kLvzMidiType) continue;
+ LvzMidiEvent* event = (LvzMidiEvent*)ev->events[i];
+ char* midiData = event->midiData;
+
+ switch(midiData[0] & 0xf0) //status byte (all channels)
+ {
+ case 0x80: //note off
+ notes[npos++] = event->deltaFrames; //delta
+ notes[npos++] = midiData[1] & 0x7F; //note
+ notes[npos++] = 0; //vel
+ break;
+
+ case 0x90: //note on
+ notes[npos++] = event->deltaFrames; //delta
+ notes[npos++] = midiData[1] & 0x7F; //note
+ notes[npos++] = midiData[2] & 0x7F; //vel
+ break;
+
+ case 0xB0: //controller
+ switch(midiData[1])
+ {
+ case 0x01: //mod wheel
+ modwhl = 0.00000005f * (float)(midiData[2] * midiData[2]);
+ break;
+
+ case 0x07: //volume
+ volume = 0.00000035f * (float)(midiData[2] * midiData[2]);
+ break;
+
+ case 0x40: //sustain
+ sustain = midiData[2] & 0x40;
+ if(sustain==0)
+ {
+ notes[npos++] = event->deltaFrames;
+ notes[npos++] = SUSTAIN; //end all sustained notes
+ notes[npos++] = 0;
+ }
+ break;
+
+ default: //all notes off
+ if(midiData[1]>0x7A)
+ {
+ for(long v=0; v<NVOICES; v++) voice[v].cdec=0.99f;
+ sustain = 0;
+ }
+ break;
+ }
+ break;
+
+ case 0xC0: //program change
+ if(midiData[1]<NPROGS) setProgram(midiData[1]);
+ break;
+
+ case 0xE0: //pitch bend
+ pbend = (float)(midiData[1] + 128 * midiData[2] - 8192);
+ if(pbend>0.0f) pbend = 1.0f + 0.000014951f * pbend;
+ else pbend = 1.0f + 0.000013318f * pbend;
+ break;
+
+ default: break;
+ }
+
+ if(npos>EVENTBUFFER) npos -= 3; //discard events if buffer full!!
+ event++;
+ }
+ notes[npos] = EVENTS_DONE;
+ return 1;
+}
+