// // Plug-in: "mda mdaDX10" v1.0 // // Copyright(c)1999-2000 Paul Kellett (maxim digital audio) // #include "mdaDX10.h" #include #include //rand() #include 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); } setUniqueID("mdaDX10"); if(audioMaster) { setNumInputs(0); setNumOutputs(NOUTS); canProcessReplacing(); isSynth(); } //initialise... for(i=0; i0.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; iparam[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(indexlabel, "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(index0 || notes[event]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; venv; 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(frame0 || notes[event]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; venv; 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= 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; v50.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; 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.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; v0.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; }