diff options
author | David Robillard <d@drobilla.net> | 2008-08-08 22:45:58 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2008-08-08 22:45:58 +0000 |
commit | e360047054117d63fb579ec9231e9dc77c99f12a (patch) | |
tree | 4a497365f6ecd30449e2c66c1fe77c816bd1fe4a /src/mdaDX10.cpp | |
download | mda.lv2-e360047054117d63fb579ec9231e9dc77c99f12a.tar.gz mda.lv2-e360047054117d63fb579ec9231e9dc77c99f12a.tar.bz2 mda.lv2-e360047054117d63fb579ec9231e9dc77c99f12a.zip |
Add preliminary (library side only) LV2 port of MDA (open-sourced VST plugins).
git-svn-id: http://svn.drobilla.net/lad/mda-lv2@1321 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/mdaDX10.cpp')
-rw-r--r-- | src/mdaDX10.cpp | 594 |
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; +} + |