/* Copyright 2008-2011 David Robillard Copyright 1999-2000 Paul Kellett (Maxim Digital Audio) This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this software. If not, see . */ #include "mdaDX10.h" #include #include //rand() #include AudioEffect *createEffectInstance(audioMasterCallback audioMaster) { return new mdaDX10(audioMaster); } mdaDX10::mdaDX10(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, NPROGS, NPARAMS) { LvzInt32 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 rate) { AudioEffectX::setSampleRate(rate); Fs = rate; } 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) { curProgram = program; update(); } void mdaDX10::setParameter(LvzInt32 index, float value) { programs[curProgram].param[index] = value; update(); } void mdaDX10::fillpatch(LvzInt32 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 programs[curProgram].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 ((unsigned int)index < NPROGS) { strcpy(text, programs[index].name); return true; } return false; } bool mdaDX10::copyProgram(LvzInt32 destination) { if(destination0 || 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(LvzInt32 note, LvzInt32 velocity) { float * param = programs[curProgram].param; float l = 1.0f; LvzInt32 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(LvzInt32 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; }