// // 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; }