From e360047054117d63fb579ec9231e9dc77c99f12a Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 8 Aug 2008 22:45:58 +0000 Subject: 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 --- src/mdaJX10.cpp | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1000 insertions(+) create mode 100644 src/mdaJX10.cpp (limited to 'src/mdaJX10.cpp') diff --git a/src/mdaJX10.cpp b/src/mdaJX10.cpp new file mode 100644 index 0000000..4014d5c --- /dev/null +++ b/src/mdaJX10.cpp @@ -0,0 +1,1000 @@ +// +// Plug-in: "mda JX10" v1.1 +// +// Copyright(c)1999-2001 Paul Kellett (maxim digital audio) +// + +#include "mdaJX10.h" + +#include +#include //rand() +#include + + +AudioEffect *createEffectInstance(audioMasterCallback audioMaster) +{ + return new mdaJX10(audioMaster); +} + + +mdaJX10Program::mdaJX10Program() +{ + param[0] = 0.00f; //OSC Mix + param[1] = 0.25f; //OSC Tune + param[2] = 0.50f; //OSC Fine + + param[3] = 0.00f; //OSC Mode + param[4] = 0.35f; //OSC Rate + param[5] = 0.50f; //OSC Bend + + param[6] = 1.00f; //VCF Freq + param[7] = 0.15f; //VCF Reso + param[8] = 0.75f; //VCF param[i]; + update(); +} //may want all notes off here - but this stops use of patches as snapshots! + + +void mdaJX10::setParameter(LvzInt32 index, float value) +{ + mdaJX10Program *p = &programs[curProgram]; + param[index] = p->param[index] = value; + update(); + + ///if(editor) editor->postUpdate(); +} + + +void mdaJX10::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, float p16, float p17, + float p18, float p19, float p20, float p21, float p22, float p23) +{ + 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; + programs[p].param[16] = p16; programs[p].param[17] = p17; + programs[p].param[18] = p18; programs[p].param[19] = p19; + programs[p].param[20] = p20; programs[p].param[21] = p21; + programs[p].param[22] = p22; programs[p].param[23] = p23; +} + + +float mdaJX10::getParameter(LvzInt32 index) { return param[index]; } +void mdaJX10::setProgramName(char *name) { strcpy(programs[curProgram].name, name); } +void mdaJX10::getProgramName(char *name) { strcpy(name, programs[curProgram].name); } +void mdaJX10::setBlockSize(LvzInt32 blockSize) { AudioEffectX::setBlockSize(blockSize); } +bool mdaJX10::getEffectName(char* name) { strcpy(name, "mda JX10 Synth"); return true; } +bool mdaJX10::getVendorString(char* text) { strcpy(text, "maxim digital audio"); return true; } +bool mdaJX10::getProductString(char* text) { strcpy(text, "mda JX10 Synth"); return true; } + + +bool mdaJX10::getOutputProperties(LvzInt32 index, LvzPinProperties* properties) +{ + if(indexlabel, "JX10%d", index + 1); + properties->flags = kLvzPinIsActive; + if(index<2) properties->flags |= kLvzPinIsStereo; //make channel 1+2 stereo + return true; + } + return false; +} + + +bool mdaJX10::getProgramNameIndexed(LvzInt32 category, LvzInt32 index, char* text) +{ + if(index0 || notes[event]sampleFrames) frames = sampleFrames; + frames -= frame; + frame += frames; + + while(--frames>=0) + { + VOICE *V = voice; + o = 0.0f; + + noise = (noise * 196314165) + 907633515; + r = (noise & 0x7FFFFF) + 0x40000000; //generate noise + fast convert to float + w = *(float *)&r; + w = ww * (w - 3.0f); + + if(--k<0) + { + lfo += dlfo; + if(lfo>PI) lfo -= TWOPI; + vib = (float)sin(lfo); + ff = filtf + filtwhl + (filtlfo + press) * vib; + pwm = 1.0f + vib * (modwhl + pwmdep); + vib = 1.0f + vib * (modwhl + vibrato); + k = KMAX; + } + + for(v=0; venv; + if(e > SILENCE) + { //Sinc-Loop Oscillator + x = V->p + V->dp; + if(x > min) + { + if(x > V->pmax) + { + x = V->pmax + V->pmax - x; + V->dp = -V->dp; + } + V->p = x; + x = V->sin0 * V->sinx - V->sin1; //sine osc + V->sin1 = V->sin0; + V->sin0 = x; + x = x / V->p; + } + else + { + V->p = x = - x; + V->dp = V->period * vib * pb; //set period for next cycle + V->pmax = (float)floor(0.5f + V->dp) - 0.5f; + V->dc = -0.5f * V->lev / V->pmax; + V->pmax *= PI; + V->dp = V->pmax / V->dp; + V->sin0 = V->lev * (float)sin(x); + V->sin1 = V->lev * (float)sin(x - V->dp); + V->sinx = 2.0f * (float)cos(V->dp); + if(x*x > .1f) x = V->sin0 / x; else x = V->lev; //was 0.01f; + } + + y = V->p2 + V->dp2; //osc2 + if(y > min) + { + if(y > V->pmax2) + { + y = V->pmax2 + V->pmax2 - y; + V->dp2 = -V->dp2; + } + V->p2 = y; + y = V->sin02 * V->sinx2 - V->sin12; + V->sin12 = V->sin02; + V->sin02 = y; + y = y / V->p2; + } + else + { + V->p2 = y = - y; + V->dp2 = V->period * V->detune * pwm * pb; + V->pmax2 = (float)floor(0.5f + V->dp2) - 0.5f; + V->dc2 = -0.5f * V->lev2 / V->pmax2; + V->pmax2 *= PI; + V->dp2 = V->pmax2 / V->dp2; + V->sin02 = V->lev2 * (float)sin(y); + V->sin12 = V->lev2 * (float)sin(y - V->dp2); + V->sinx2 = 2.0f * (float)cos(V->dp2); + if(y*y > .1f) y = V->sin02 / y; else y = V->lev2; + } + V->saw = V->saw * hpf + V->dc + x - V->dc2 - y; //integrated sinc = saw + x = V->saw + w; + V->env += V->envd * (V->envl - V->env); + + if(k==KMAX) //filter freq update at LFO rate + { + if((V->env+V->envl)>3.0f) { V->envd=dec; V->envl=sus; } //envelopes + V->fenv += V->fenvd * (V->fenvl - V->fenv); + if((V->fenv+V->fenvl)>3.0f) { V->fenvd=fdec; V->fenvl=fsus; } + + fz += 0.005f * (ff - fz); //filter zipper noise filter + y = V->fc * (float)exp(fz + fe * V->fenv) * ipb; //filter cutoff + if(y<0.005f) y=0.005f; + V->ff = y; + + V->period += gl * (V->target - V->period); //glide + if(V->target < V->period) V->period += gl * (V->target - V->period); + } + + if(V->ff > fx) V->ff = fx; //stability limit + + V->f0 += V->ff * V->f1; //state-variable filter + V->f1 -= V->ff * (V->f0 + fq * V->f1 - x - V->f2); + V->f1 -= 0.2f * V->f1 * V->f1 * V->f1; //soft limit //was 0.08f + V->f2 = x; + + o += V->env * V->f0; + } + V++; + } + + *out1++ += o; + *out2++ += o; + } + + if(frame0 || notes[event]sampleFrames) frames = sampleFrames; + frames -= frame; + frame += frames; + + while(--frames>=0) + { + VOICE *V = voice; + o = 0.0f; + + noise = (noise * 196314165) + 907633515; + r = (noise & 0x7FFFFF) + 0x40000000; //generate noise + fast convert to float + w = *(float *)&r; + w = ww * (w - 3.0f); + + if(--k<0) + { + lfo += dlfo; + if(lfo>PI) lfo -= TWOPI; + vib = (float)sin(lfo); + ff = filtf + filtwhl + (filtlfo + press) * vib; + pwm = 1.0f + vib * (modwhl + pwmdep); + vib = 1.0f + vib * (modwhl + vibrato); + k = KMAX; + } + + for(v=0; venv; + if(e > SILENCE) + { //Sinc-Loop Oscillator + x = V->p + V->dp; + if(x > min) + { + if(x > V->pmax) + { + x = V->pmax + V->pmax - x; + V->dp = -V->dp; + } + V->p = x; + x = V->sin0 * V->sinx - V->sin1; //sine osc + V->sin1 = V->sin0; + V->sin0 = x; + x = x / V->p; + } + else + { + V->p = x = - x; + V->dp = V->period * vib * pb; //set period for next cycle + V->pmax = (float)floor(0.5f + V->dp) - 0.5f; + V->dc = -0.5f * V->lev / V->pmax; + V->pmax *= PI; + V->dp = V->pmax / V->dp; + V->sin0 = V->lev * (float)sin(x); + V->sin1 = V->lev * (float)sin(x - V->dp); + V->sinx = 2.0f * (float)cos(V->dp); + if(x*x > .1f) x = V->sin0 / x; else x = V->lev; //was 0.01f; + } + + y = V->p2 + V->dp2; //osc2 + if(y > min) + { + if(y > V->pmax2) + { + y = V->pmax2 + V->pmax2 - y; + V->dp2 = -V->dp2; + } + V->p2 = y; + y = V->sin02 * V->sinx2 - V->sin12; + V->sin12 = V->sin02; + V->sin02 = y; + y = y / V->p2; + } + else + { + V->p2 = y = - y; + V->dp2 = V->period * V->detune * pwm * pb; + V->pmax2 = (float)floor(0.5f + V->dp2) - 0.5f; + V->dc2 = -0.5f * V->lev2 / V->pmax2; + V->pmax2 *= PI; + V->dp2 = V->pmax2 / V->dp2; + V->sin02 = V->lev2 * (float)sin(y); + V->sin12 = V->lev2 * (float)sin(y - V->dp2); + V->sinx2 = 2.0f * (float)cos(V->dp2); + if(y*y > .1f) y = V->sin02 / y; else y = V->lev2; + } + V->saw = V->saw * hpf + V->dc + x - V->dc2 - y; //integrated sinc = saw + x = V->saw + w; + V->env += V->envd * (V->envl - V->env); + + if(k==KMAX) //filter freq update at LFO rate + { + if((V->env+V->envl)>3.0f) { V->envd=dec; V->envl=sus; } //envelopes + V->fenv += V->fenvd * (V->fenvl - V->fenv); + if((V->fenv+V->fenvl)>3.0f) { V->fenvd=fdec; V->fenvl=fsus; } + + fz += 0.005f * (ff - fz); //filter zipper noise filter + y = V->fc * (float)exp(fz + fe * V->fenv) * ipb; //filter cutoff + if(y<0.005f) y=0.005f; + V->ff = y; + + V->period += gl * (V->target - V->period); //glide + if(V->target < V->period) V->period += gl * (V->target - V->period); + } + + if(V->ff > fx) V->ff = fx; //stability limit + + V->f0 += V->ff * V->f1; //state-variable filter + V->f1 -= V->ff * (V->f0 + fq * V->f1 - x - V->f2); + V->f1 -= 0.2f * V->f1 * V->f1 * V->f1; //soft limit + + V->f2 = x; + + o += V->env * V->f0; + } + V++; + } + + *out1++ = o; + *out2++ = o; + } + + if(frame= 0) + { + *out1++ = 0.0f; + *out2++ = 0.0f; + } + } + notes[0] = EVENTS_DONE; //mark events buffer as done + fzip = fz; + K = k; +} + + +void mdaJX10::noteOn(long note, long velocity) +{ + float p, l=100.0f; //louder than any envelope! + long v=0, tmp, held=0; + + if(velocity>0) //note on + { + if(veloff) velocity = 80; + + if(mode & 4) //monophonic + { + if(voice[0].note > 0) //legato pitch change + { + for(tmp=(NVOICES-1); tmp>0; tmp--) //queue any held notes + { + voice[tmp].note = voice[tmp - 1].note; + } + p = tune * (float)exp(-0.05776226505 * ((double)note + ANALOG * (double)v)); + while(p<3.0f || (p * detune)<3.0f) p += p; + voice[v].target = p; + if((mode & 2)==0) voice[v].period = p; + voice[v].fc = (float)exp(filtvel * (float)(velocity - 64)) / p; + voice[v].env += SILENCE + SILENCE; ///was missed out below if returned? + voice[v].note = note; + return; + } + } + else //polyphonic + { + for(tmp=0; tmp 0) held++; + if(voice[tmp].env0.0f) + { + p = voice[v].pmax + voice[v].pmax - voice[v].p; + voice[v].dp2 = -voice[v].dp; + } + else + { + p = voice[v].p; + voice[v].dp2 = voice[v].dp; + } + voice[v].p2 = voice[v].pmax2 = p + PI * voice[v].period; + + voice[v].dc2 = 0.0f; + voice[v].sin02 = voice[v].sin12 = voice[v].sinx2 = 0.0f; + } + + if(mode & 4) //monophonic retriggering + { + voice[v].env += SILENCE + SILENCE; + } + else + { + //if(param[15] < 0.28f) + //{ + // voice[v].f0 = voice[v].f1 = voice[v].f2 = 0.0f; //reset filter + // voice[v].env = SILENCE + SILENCE; + // voice[v].fenv = 0.0f; + //} + //else + voice[v].env += SILENCE + SILENCE; //anti-glitching trick + } + voice[v].envl = 2.0f; + voice[v].envd = att; + voice[v].fenvl = 2.0f; + voice[v].fenvd = fatt; + } + else //note off + { + if((mode & 4) && (voice[0].note==note)) //monophonic (and current note) + { + for(v=(NVOICES-1); v>0; v--) + { + if(voice[v].note>0) held = v; //any other notes queued? + } + if(held>0) + { + voice[v].note = voice[held].note; + voice[held].note = 0; + + p = tune * (float)exp(-0.05776226505 * ((double)voice[v].note + ANALOG * (double)v)); + while(p<3.0f || (p * detune)<3.0f) p += p; + voice[v].target = p; + if((mode & 2)==0) voice[v].period = p; + voice[v].fc = 1.0f / p; + } + else + { + voice[v].envl = 0.0f; + voice[v].envd = rel; + voice[v].fenvl = 0.0f; + voice[v].fenvd = frel; + voice[v].note = 0; + } + } + else //polyphonic + { + for(v=0; vnumEvents; 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.000005f * (float)(midiData[2] * midiData[2]); + break; + case 0x02: //filter + + case 0x4A: + filtwhl = 0.02f * (float)(midiData[2]); + break; + case 0x03: //filter - + filtwhl = -0.03f * (float)(midiData[2]); + break; + + case 0x07: //volume + volume = 0.00000005f * (float)(midiData[2] * midiData[2]); + break; + + case 0x10: //resonance + case 0x47: + rezwhl = 0.0065f * (float)(154 - 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; vEVENTBUFFER) npos -= 3; //discard events if buffer full!! + event++; + } + notes[npos] = EVENTS_DONE; + return 1; +} + -- cgit v1.2.1