/* 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 "mdaPianoData.h" #include "mdaPiano.h" #include "lv2/lv2plug.in/ns/ext/atom/util.h" #include #include //#include "AEffEditor.hpp" ////for GUI AudioEffect *createEffectInstance(audioMasterCallback audioMaster) { return new mdaPiano(audioMaster); } mdaPianoProgram::mdaPianoProgram() { param[0] = 0.50f; //Decay param[1] = 0.50f; //Release param[2] = 0.50f; //Hardness param[3] = 0.50f; //Vel>Hard param[4] = 1.00f; //Muffle param[5] = 0.50f; //Vel>Muff param[6] = 0.33f; //Vel Curve param[7] = 0.50f; //Stereo param[8] = 0.33f; //Max Poly param[9] = 0.50f; //Tune param[10] = 0.00f; //Random param[11] = 0.50f; //Stretch strcpy (name, "MDA Piano"); } mdaPiano::mdaPiano(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, NPROGS, NPARAMS) { Fs = 44100.0f; iFs = 1.0f/Fs; cmax = 0x7F; //just in case... programs = new mdaPianoProgram[NPROGS]; if(programs) { //fill patches... int32_t i=0; fillpatch(i++, "MDA Piano", 0.500f, 0.500f, 0.500f, 0.5f, 0.803f, 0.251f, 0.376f, 0.500f, 0.330f, 0.500f, 0.246f, 0.500f); fillpatch(i++, "Plain Piano", 0.500f, 0.500f, 0.500f, 0.5f, 0.751f, 0.000f, 0.452f, 0.000f, 0.000f, 0.500f, 0.000f, 0.500f); fillpatch(i++, "Compressed Piano", 0.902f, 0.399f, 0.623f, 0.5f, 1.000f, 0.331f, 0.299f, 0.499f, 0.330f, 0.500f, 0.000f, 0.500f); fillpatch(i++, "Dance Piano", 0.399f, 0.251f, 1.000f, 0.5f, 0.672f, 0.124f, 0.127f, 0.249f, 0.330f, 0.500f, 0.283f, 0.667f); fillpatch(i++, "Concert Piano", 0.648f, 0.500f, 0.500f, 0.5f, 0.298f, 0.602f, 0.550f, 0.850f, 0.356f, 0.500f, 0.339f, 0.660f); fillpatch(i++, "Dark Piano", 0.500f, 0.602f, 0.000f, 0.5f, 0.304f, 0.200f, 0.336f, 0.651f, 0.330f, 0.500f, 0.317f, 0.500f); fillpatch(i++, "School Piano", 0.450f, 0.598f, 0.626f, 0.5f, 0.603f, 0.500f, 0.174f, 0.331f, 0.330f, 0.500f, 0.421f, 0.801f); fillpatch(i++, "Broken Piano", 0.050f, 0.957f, 0.500f, 0.5f, 0.299f, 1.000f, 0.000f, 0.500f, 0.330f, 0.450f, 0.718f, 0.000f); setProgram(0); } setUniqueID("mdaPiano"); if(audioMaster) { setNumInputs(0); setNumOutputs(NOUTS); canProcessReplacing(); isSynth(); } waves = pianoData; //Waveform data and keymapping is hard-wired in *this* version kgrp[ 0].root = 36; kgrp[ 0].high = 37; kgrp[ 0].pos = 0; kgrp[ 0].end = 36275; kgrp[ 0].loop = 14774; kgrp[ 1].root = 40; kgrp[ 1].high = 41; kgrp[ 1].pos = 36278; kgrp[ 1].end = 83135; kgrp[ 1].loop = 16268; kgrp[ 2].root = 43; kgrp[ 2].high = 45; kgrp[ 2].pos = 83137; kgrp[ 2].end = 146756; kgrp[ 2].loop = 33541; kgrp[ 3].root = 48; kgrp[ 3].high = 49; kgrp[ 3].pos = 146758; kgrp[ 3].end = 204997; kgrp[ 3].loop = 21156; kgrp[ 4].root = 52; kgrp[ 4].high = 53; kgrp[ 4].pos = 204999; kgrp[ 4].end = 244908; kgrp[ 4].loop = 17191; kgrp[ 5].root = 55; kgrp[ 5].high = 57; kgrp[ 5].pos = 244910; kgrp[ 5].end = 290978; kgrp[ 5].loop = 23286; kgrp[ 6].root = 60; kgrp[ 6].high = 61; kgrp[ 6].pos = 290980; kgrp[ 6].end = 342948; kgrp[ 6].loop = 18002; kgrp[ 7].root = 64; kgrp[ 7].high = 65; kgrp[ 7].pos = 342950; kgrp[ 7].end = 391750; kgrp[ 7].loop = 19746; kgrp[ 8].root = 67; kgrp[ 8].high = 69; kgrp[ 8].pos = 391752; kgrp[ 8].end = 436915; kgrp[ 8].loop = 22253; kgrp[ 9].root = 72; kgrp[ 9].high = 73; kgrp[ 9].pos = 436917; kgrp[ 9].end = 468807; kgrp[ 9].loop = 8852; kgrp[10].root = 76; kgrp[10].high = 77; kgrp[10].pos = 468809; kgrp[10].end = 492772; kgrp[10].loop = 9693; kgrp[11].root = 79; kgrp[11].high = 81; kgrp[11].pos = 492774; kgrp[11].end = 532293; kgrp[11].loop = 10596; kgrp[12].root = 84; kgrp[12].high = 85; kgrp[12].pos = 532295; kgrp[12].end = 560192; kgrp[12].loop = 6011; kgrp[13].root = 88; kgrp[13].high = 89; kgrp[13].pos = 560194; kgrp[13].end = 574121; kgrp[13].loop = 3414; kgrp[14].root = 93; kgrp[14].high = 999; kgrp[14].pos = 574123; kgrp[14].end = 586343; kgrp[14].loop = 2399; //initialise... for(int32_t v=0; v 0.03f) width = 0.03f; poly = 8 + (int32_t)(24.9f * param[8]); } void mdaPiano::setSampleRate(float rate) { AudioEffectX::setSampleRate(rate); Fs = rate; iFs = 1.0f / Fs; if(Fs > 64000.0f) cmax = 0xFF; else cmax = 0x7F; } void mdaPiano::resume() { memset(comb, 0, sizeof(float) * 256); DECLARE_LVZ_DEPRECATED (wantEvents) (); } mdaPiano::~mdaPiano () //destroy any buffers... { if(programs) delete [] programs; if(comb) delete[] comb; } void mdaPiano::setProgram(int32_t program) { curProgram = program; update(); // TODO: guiUpdate ??? } void mdaPiano::setParameter(int32_t index, float value) { programs[curProgram].param[index] = value; update(); // if(editor) editor->postUpdate(); //For GUI guiUpdate = index + 0x100 + (guiUpdate & 0xFFFF00); } void mdaPiano::fillpatch(int32_t 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) { 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; } float mdaPiano::getParameter(int32_t index) { return programs[curProgram].param[index]; } void mdaPiano::setProgramName(char *name) { strcpy(programs[curProgram].name, name); } void mdaPiano::getProgramName(char *name) { strcpy(name, programs[curProgram].name); } void mdaPiano::setBlockSize(int32_t blockSize) { AudioEffectX::setBlockSize(blockSize); } bool mdaPiano::getEffectName(char* name) { strcpy(name, "Piano"); return true; } bool mdaPiano::getVendorString(char* text) { strcpy(text, "mda"); return true; } bool mdaPiano::getProductString(char* text) { strcpy(text, "MDA Piano"); return true; } bool mdaPiano::getOutputProperties(int32_t index, LvzPinProperties* properties) { if(indexlabel, "Piano R"); else sprintf(properties->label, "Piano L"); properties->flags = kLvzPinIsActive; if(index<2) properties->flags |= kLvzPinIsStereo; //make channel 1+2 stereo return true; } return false; } bool mdaPiano::getProgramNameIndexed(int32_t category, int32_t index, char* text) { if ((unsigned int)index < NPROGS) { strcpy(text, programs[index].name); return true; } return false; } bool mdaPiano::copyProgram(int32_t destination) { if(destinationf0); l = 0.0f; } if(!(r > -2.0f) || !(r < 2.0f)) { r = 0.0f; } V++; } comb[cpos] = l + r; ++cpos &= cmax; x = cdep * comb[cpos]; //stereo simulator *out0++ = l + x; *out1++ = r - x; } if(!end) { processEvent(ev); ev = lv2_atom_sequence_next(ev); } } for(v=0; v0) { if(activevoices < poly) //add a note { vl = activevoices; activevoices++; } else //steal a note { for(v=0; v 60) l += stretch * (float)k; //stretch s = size; if(velocity > 40) s += (int32_t)(sizevel * (float)(velocity - 40)); k = 0; while(note > (kgrp[k].high + s)) k++; //find keygroup l += (float)(note - kgrp[k].root); //pitch l = 22050.0f * iFs * (float)exp(0.05776226505 * l); voice[vl].delta = (int32_t)(65536.0f * l); voice[vl].frac = 0; voice[vl].pos = kgrp[k].pos; voice[vl].end = kgrp[k].end; voice[vl].loop = kgrp[k].loop; voice[vl].env = (0.5f + velsens) * (float)pow(0.0078f * velocity, velsens); //velocity l = 50.0f + param[4] * param[4] * muff + muffvel * (float)(velocity - 64); //muffle if(l < (55.0f + 0.25f * (float)note)) l = 55.0f + 0.25f * (float)note; if(l > 210.0f) l = 210.0f; voice[vl].ff = l * l * iFs; voice[vl].f0 = voice[vl].f1 = 0.0f; voice[vl].note = note; //note->pan if(note < 12) note = 12; if(note > 108) note = 108; l = volume * trim; voice[vl].outr = l + l * width * (float)(note - 60); voice[vl].outl = l + l - voice[vl].outr; if(note < 44) note = 44; //limit max decay length l = 2.0f * param[0]; if(l < 1.0f) l += 0.25f - 0.5f * param[0]; voice[vl].dec = (float)exp(-iFs * exp(-0.6 + 0.033 * (double)note - l)); } else //note off { for(v=0; vbody.type != midiEventType) return 0; const uint8_t* midiData = (const uint8_t*)LV2_ATOM_BODY_CONST(&ev->body); switch(midiData[0] & 0xf0) //status byte (all channels) { case 0x80: //note off noteOn(midiData[1] & 0x7F, 0); break; case 0x90: //note on noteOn(midiData[1] & 0x7F, midiData[2] & 0x7F); break; case 0xB0: //controller switch(midiData[1]) { case 0x01: //mod wheel case 0x43: //soft pedal muff = 0.01f * (float)((127 - midiData[2]) * (127 - midiData[2])); break; case 0x07: //volume volume = 0.00002f * (float)(midiData[2] * midiData[2]); break; case 0x40: //sustain pedal case 0x42: //sustenuto pedal sustain = midiData[2] & 0x40; if(sustain==0) { noteOn(SUSTAIN, 0); //end all sustained notes } break; default: //all notes off if(midiData[1]>0x7A) { for(int32_t v=0; v