void PADnote::setup(float freq, float velocity, int portamento_, int midinote, bool legato) { portamento = portamento_; this->velocity = velocity; finished_ = false; if(pars->Pfixedfreq == 0) basefreq = freq; else { basefreq = 440.0f; int fixedfreqET = pars->PfixedfreqET; if(fixedfreqET != 0) { //if the frequency varies according the keyboard note float tmp = (midinote - 69.0f) / 12.0f * (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f); if(fixedfreqET <= 64) basefreq *= powf(2.0f, tmp); else basefreq *= powf(3.0f, tmp); } } firsttime = true; released = false; realfreq = basefreq; if(!legato) NoteGlobalPar.Detune = getdetune(pars->PDetuneType, pars->PCoarseDetune, pars->PDetune); //find out the closest note float logfreq = logf(basefreq * powf(2.0f, NoteGlobalPar.Detune / 1200.0f)); float mindist = fabs(logfreq - logf(pars->sample[0].basefreq + 0.0001f)); nsample = 0; for(int i = 1; i < PAD_MAX_SAMPLES; ++i) { if(pars->sample[i].smp == NULL) break; float dist = fabs(logfreq - logf(pars->sample[i].basefreq + 0.0001f)); if(dist < mindist) { nsample = i; mindist = dist; } } int size = pars->sample[nsample].size; if(size == 0) size = 1; if(!legato) { //not sure poshi_l = (int)(RND * (size - 1)); if(pars->PStereo != 0) poshi_r = (poshi_l + size / 2) % size; else poshi_r = poshi_l; poslo = 0.0f; } if(pars->PPanning == 0) NoteGlobalPar.Panning = RND; else NoteGlobalPar.Panning = pars->PPanning / 128.0f; NoteGlobalPar.FilterCenterPitch = pars->GlobalFilter->getfreq() //center freq + pars->PFilterVelocityScale / 127.0f * 6.0f //velocity sensing * (VelF(velocity, pars-> PFilterVelocityScaleFunction) - 1); if(!legato) { if(pars->PPunchStrength != 0) { NoteGlobalPar.Punch.Enabled = 1; NoteGlobalPar.Punch.t = 1.0f; //start from 1.0f and to 0.0f NoteGlobalPar.Punch.initialvalue = ((powf(10, 1.5f * pars->PPunchStrength / 127.0f) - 1.0f) * VelF(velocity, pars->PPunchVelocitySensing)); float time = powf(10, 3.0f * pars->PPunchTime / 127.0f) / 10000.0f; //0.1f .. 100 ms float stretch = powf(440.0f / freq, pars->PPunchStretch / 64.0f); NoteGlobalPar.Punch.dt = 1.0f / (time * synth->samplerate_f * stretch); } else NoteGlobalPar.Punch.Enabled = 0; NoteGlobalPar.FreqEnvelope = new Envelope(pars->FreqEnvelope, basefreq); NoteGlobalPar.FreqLfo = new LFO(pars->FreqLfo, basefreq); NoteGlobalPar.AmpEnvelope = new Envelope(pars->AmpEnvelope, basefreq); NoteGlobalPar.AmpLfo = new LFO(pars->AmpLfo, basefreq); } NoteGlobalPar.Volume = 4.0f * powf(0.1f, 3.0f * (1.0f - pars->PVolume / 96.0f)) //-60 dB .. 0 dB * VelF(velocity, pars->PAmpVelocityScaleFunction); //velocity sensing NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output globaloldamplitude = globalnewamplitude = NoteGlobalPar.Volume * NoteGlobalPar.AmpEnvelope-> envout_dB() * NoteGlobalPar.AmpLfo->amplfoout(); if(!legato) { NoteGlobalPar.GlobalFilterL = Filter::generate(pars->GlobalFilter); NoteGlobalPar.GlobalFilterR = Filter::generate(pars->GlobalFilter); NoteGlobalPar.FilterEnvelope = new Envelope(pars->FilterEnvelope, basefreq); NoteGlobalPar.FilterLfo = new LFO(pars->FilterLfo, basefreq); } NoteGlobalPar.FilterQ = pars->GlobalFilter->getq(); NoteGlobalPar.FilterFreqTracking = pars->GlobalFilter->getfreqtracking( basefreq); if(pars->sample[nsample].smp == NULL) { finished_ = true; return; } }
void SUBnote::setup(float freq, float velocity, int portamento_, int midinote, bool legato) { this->velocity = velocity; portamento = portamento_; NoteEnabled = ON; volume = powf(0.1f, 3.0f * (1.0f - pars.PVolume / 96.0f)); //-60 dB .. 0 dB volume *= VelF(velocity, pars.PAmpVelocityScaleFunction); if(pars.PPanning != 0) panning = pars.PPanning / 127.0f; else panning = RND; if(!legato) { numstages = pars.Pnumstages; stereo = pars.Pstereo; start = pars.Pstart; firsttick = 1; } int pos[MAX_SUB_HARMONICS]; if(pars.Pfixedfreq == 0) basefreq = freq; else { basefreq = 440.0f; int fixedfreqET = pars.PfixedfreqET; if(fixedfreqET) { //if the frequency varies according the keyboard note float tmp = (midinote - 69.0f) / 12.0f * (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f); if(fixedfreqET <= 64) basefreq *= powf(2.0f, tmp); else basefreq *= powf(3.0f, tmp); } } int BendAdj = pars.PBendAdjust - 64; if (BendAdj % 24 == 0) BendAdjust = BendAdj / 24; else BendAdjust = BendAdj / 24.0f; float offset_val = (pars.POffsetHz - 64)/64.0f; OffsetHz = 15.0f*(offset_val * sqrtf(fabsf(offset_val))); float detune = getdetune(pars.PDetuneType, pars.PCoarseDetune, pars.PDetune); basefreq *= powf(2.0f, detune / 1200.0f); //detune // basefreq*=ctl.pitchwheel.relfreq;//pitch wheel //global filter GlobalFilterCenterPitch = pars.GlobalFilter->getfreq() //center freq + (pars.PGlobalFilterVelocityScale / 127.0f * 6.0f) //velocity sensing * (VelF(velocity, pars.PGlobalFilterVelocityScaleFunction) - 1); if(!legato) { GlobalFilterL = NULL; GlobalFilterR = NULL; GlobalFilterEnvelope = NULL; } int harmonics = 0; //select only harmonics that desire to compute for(int n = 0; n < MAX_SUB_HARMONICS; ++n) { if(pars.Phmag[n] == 0) continue; pos[harmonics++] = n; } if(!legato) firstnumharmonics = numharmonics = harmonics; else { if(harmonics > firstnumharmonics) numharmonics = firstnumharmonics; else numharmonics = harmonics; } if(numharmonics == 0) { NoteEnabled = OFF; return; } if(!legato) { lfilter = memory.valloc<bpfilter>(numstages * numharmonics); if(stereo) rfilter = memory.valloc<bpfilter>(numstages * numharmonics); } //how much the amplitude is normalised (because the harmonics) float reduceamp = 0.0f; for(int n = 0; n < numharmonics; ++n) { float freq = basefreq * pars.POvertoneFreqMult[pos[n]]; overtone_freq[n] = freq; overtone_rolloff[n] = computerolloff(freq); //the bandwidth is not absolute(Hz); it is relative to frequency float bw = powf(10, (pars.Pbandwidth - 127.0f) / 127.0f * 4) * numstages; //Bandwidth Scale bw *= powf(1000 / freq, (pars.Pbwscale - 64.0f) / 64.0f * 3.0f); //Relative BandWidth bw *= powf(100, (pars.Phrelbw[pos[n]] - 64.0f) / 64.0f); if(bw > 25.0f) bw = 25.0f; //try to keep same amplitude on all freqs and bw. (empirically) float gain = sqrt(1500.0f / (bw * freq)); float hmagnew = 1.0f - pars.Phmag[pos[n]] / 127.0f; float hgain; switch(pars.Phmagtype) { case 1: hgain = expf(hmagnew * logf(0.01f)); break; case 2: hgain = expf(hmagnew * logf(0.001f)); break; case 3: hgain = expf(hmagnew * logf(0.0001f)); break; case 4: hgain = expf(hmagnew * logf(0.00001f)); break; default: hgain = 1.0f - hmagnew; } gain *= hgain; reduceamp += hgain; for(int nph = 0; nph < numstages; ++nph) { float amp = 1.0f; if(nph == 0) amp = gain; initfilter(lfilter[nph + n * numstages], freq + OffsetHz, bw, amp, hgain); if(stereo) initfilter(rfilter[nph + n * numstages], freq + OffsetHz, bw, amp, hgain); } } if(reduceamp < 0.001f) reduceamp = 1.0f; volume /= reduceamp; oldpitchwheel = 0; oldbandwidth = 64; if(!legato) { if(pars.Pfixedfreq == 0) initparameters(basefreq); else initparameters(basefreq / 440.0f * freq); } else { if(pars.Pfixedfreq == 0) freq = basefreq; else freq *= basefreq / 440.0f; if(pars.PGlobalFilterEnabled) { globalfiltercenterq = pars.GlobalFilter->getq(); GlobalFilterFreqTracking = pars.GlobalFilter->getfreqtracking( basefreq); } } oldamplitude = newamplitude; }
void SUBnote::update_parameters_realtime() //Update the parameters in real time ;) //by VDX { if (pars) { //SUBsynth GLOBAL Parameters of the Instrument //Global Stuff if (pars->b_changed) { volume=pow(0.1,3.0*(1.0-pars->PVolume/96.0));//-60 dB .. 0 dB volume*=VelF(velocity,pars->PAmpVelocityScaleFunction); if (pars->PPanning!=0) panning=pars->PPanning/127.0; else panning=RND; pars->b_changed --; }; if (pars->b_changed_bw) { reduceamp=0.0; for (int n=0;n<numharmonics;n++) { REALTYPE freq=basefreq*(pos[n]+1); //the bandwidth is not absolute(Hz); it is relative to frequency REALTYPE bw=pow(10,(pars->Pbandwidth-127.0)/127.0*4)*numstages; //Bandwidth Scale bw*=pow(1000/freq,(float)((pars->Pbwscale-64.0)/64.0*3.0)); //Relative BandWidth bw*=pow(100,(float)((pars->Phrelbw[pos[n]]-64.0)/64.0)); if (bw>25.0) bw=25.0; //try to keep same amplitude on all freqs and bw. (empirically) gain=sqrt(1500.0/(bw*freq)); hmagnew=1.0-pars->Phmag[pos[n]]/127.0; switch (pars->Phmagtype) { case 1: hgain=exp(hmagnew*log(0.01)); break; case 2: hgain=exp(hmagnew*log(0.001)); break; case 3: hgain=exp(hmagnew*log(0.0001)); break; case 4: hgain=exp(hmagnew*log(0.00001)); break; default: hgain=1.0-hmagnew; }; gain*=hgain; reduceamp+=hgain; for (int nph=0;nph<numstages;nph++) { REALTYPE amp=1.0; if (nph==0) amp=gain; initfilter_rl(lfilter[nph+n*numstages],freq,bw,amp,hgain); if (stereo!=0) initfilter_rl(rfilter[nph+n*numstages],freq,bw,amp,hgain); }; }; if (reduceamp<0.001) reduceamp=1.0; //volume/=reduceamp; oldpitchwheel=0; oldbandwidth=64; //if (pars->Pfixedfreq==0) initparameters(basefreq); //else initparameters(basefreq/440.0*freq); oldamplitude=newamplitude; ready=1; pars->b_changed_bw --; }; //Filter parameters if (pars->GlobalFilter) if (pars->GlobalFilter->b_changed) { //update central frequency GlobalFilterCenterPitch = pars->GlobalFilter->getfreq() + pars->PGlobalFilterVelocityScale/127.0*6.0* (VelF(velocity,pars->PGlobalFilterVelocityScaleFunction)-1); //update Q globalfiltercenterq = pars->GlobalFilter->getq(); //update freq tracking GlobalFilterFreqTracking = pars->GlobalFilter->getfreqtracking(basefreq); //update gain GlobalFilterL->update_gain(pars->GlobalFilter); GlobalFilterR->update_gain(pars->GlobalFilter); //velocity stuff //o->init(pars->GlobalPar.GlobalFilter,&pars->GlobalPar.PFilterVelocityScale,&pars->GlobalPar.PFilterVelocityScaleFunction); //this is already implemented while updating the central freq pars->GlobalFilter->b_changed--; } } //if pars }
void PADnote::setup(float freq, float velocity_, int portamento_, int midinote, bool legato, WatchManager *wm, const char *prefix) { portamento = portamento_; velocity = velocity_; finished_ = false; if(!pars.Pfixedfreq) basefreq = freq; else { basefreq = 440.0f; int fixedfreqET = pars.PfixedfreqET; if(fixedfreqET != 0) { //if the frequency varies according the keyboard note float tmp = (midinote - 69.0f) / 12.0f * (powf(2.0f, (fixedfreqET - 1) / 63.0f) - 1.0f); if(fixedfreqET <= 64) basefreq *= powf(2.0f, tmp); else basefreq *= powf(3.0f, tmp); } } int BendAdj = pars.PBendAdjust - 64; if (BendAdj % 24 == 0) BendAdjust = BendAdj / 24; else BendAdjust = BendAdj / 24.0f; float offset_val = (pars.POffsetHz - 64)/64.0f; OffsetHz = 15.0f*(offset_val * sqrtf(fabsf(offset_val))); firsttime = true; realfreq = basefreq; if(!legato) NoteGlobalPar.Detune = getdetune(pars.PDetuneType, pars.PCoarseDetune, pars.PDetune); //find out the closest note float logfreq = logf(basefreq * powf(2.0f, NoteGlobalPar.Detune / 1200.0f)); float mindist = fabs(logfreq - logf(pars.sample[0].basefreq + 0.0001f)); nsample = 0; for(int i = 1; i < PAD_MAX_SAMPLES; ++i) { if(pars.sample[i].smp == NULL) break; float dist = fabs(logfreq - logf(pars.sample[i].basefreq + 0.0001f)); if(dist < mindist) { nsample = i; mindist = dist; } } int size = pars.sample[nsample].size; if(size == 0) size = 1; if(!legato) { //not sure poshi_l = (int)(RND * (size - 1)); if(pars.PStereo) poshi_r = (poshi_l + size / 2) % size; else poshi_r = poshi_l; poslo = 0.0f; } if(pars.PPanning == 0) NoteGlobalPar.Panning = RND; else NoteGlobalPar.Panning = pars.PPanning / 128.0f; if(!legato) { NoteGlobalPar.Fadein_adjustment = pars.Fadein_adjustment / (float)FADEIN_ADJUSTMENT_SCALE; NoteGlobalPar.Fadein_adjustment *= NoteGlobalPar.Fadein_adjustment; if(pars.PPunchStrength != 0) { NoteGlobalPar.Punch.Enabled = 1; NoteGlobalPar.Punch.t = 1.0f; //start from 1.0f and to 0.0f NoteGlobalPar.Punch.initialvalue = ((powf(10, 1.5f * pars.PPunchStrength / 127.0f) - 1.0f) * VelF(velocity, pars.PPunchVelocitySensing)); const float time = powf(10, 3.0f * pars.PPunchTime / 127.0f) / 10000.0f; //0.1f .. 100 ms const float stretch = powf(440.0f / freq, pars.PPunchStretch / 64.0f); NoteGlobalPar.Punch.dt = 1.0f / (time * synth.samplerate_f * stretch); } else NoteGlobalPar.Punch.Enabled = 0; ScratchString pre = prefix; NoteGlobalPar.FreqEnvelope = memory.alloc<Envelope>(*pars.FreqEnvelope, basefreq, synth.dt(), wm, (pre+"FreqEnvelope/").c_str); NoteGlobalPar.FreqLfo = memory.alloc<LFO>(*pars.FreqLfo, basefreq, time, wm, (pre+"FreqLfo/").c_str); NoteGlobalPar.AmpEnvelope = memory.alloc<Envelope>(*pars.AmpEnvelope, basefreq, synth.dt(), wm, (pre+"AmpEnvelope/").c_str); NoteGlobalPar.AmpLfo = memory.alloc<LFO>(*pars.AmpLfo, basefreq, time, wm, (pre+"AmpLfo/").c_str); } NoteGlobalPar.Volume = 4.0f * powf(0.1f, 3.0f * (1.0f - pars.PVolume / 96.0f)) //-60 dB .. 0 dB * VelF(velocity, pars.PAmpVelocityScaleFunction); //velocity sensing NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output globaloldamplitude = globalnewamplitude = NoteGlobalPar.Volume * NoteGlobalPar.AmpEnvelope-> envout_dB() * NoteGlobalPar.AmpLfo->amplfoout(); if(!legato) { ScratchString pre = prefix; auto &flt = NoteGlobalPar.GlobalFilter; auto &env = NoteGlobalPar.FilterEnvelope; auto &lfo = NoteGlobalPar.FilterLfo; assert(flt == nullptr); flt = memory.alloc<ModFilter>(*pars.GlobalFilter, synth, time, memory, true, basefreq); //setup mod env = memory.alloc<Envelope>(*pars.FilterEnvelope, basefreq, synth.dt(), wm, (pre+"FilterEnvelope/").c_str); lfo = memory.alloc<LFO>(*pars.FilterLfo, basefreq, time, wm, (pre+"FilterLfo/").c_str); flt->addMod(*env); flt->addMod(*lfo); } { auto &flt = *NoteGlobalPar.GlobalFilter; flt.updateSense(velocity, pars.PFilterVelocityScale, pars.PFilterVelocityScaleFunction); flt.updateNoteFreq(basefreq); } if(!pars.sample[nsample].smp) { finished_ = true; return; } }
SUBnote::SUBnote(SUBnoteParameters *parameters, Controller *ctl_, REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool besilent) { ready=0; tmpsmp=new REALTYPE[SOUND_BUFFER_SIZE]; tmprnd=new REALTYPE[SOUND_BUFFER_SIZE]; this->velocity=velocity; this->freq = freq; // Initialise some legato-specific vars Legato.msg=LM_Norm; Legato.fade.length=(int)(SAMPLE_RATE*0.005);// 0.005 seems ok. if (Legato.fade.length<1) Legato.fade.length=1;// (if something's fishy) Legato.fade.step=(1.0/Legato.fade.length); Legato.decounter=-10; Legato.param.freq=freq; Legato.param.vel=velocity; Legato.param.portamento=portamento_; Legato.param.midinote=midinote; Legato.silent=besilent; pars=parameters; ctl=ctl_; portamento=portamento_; NoteEnabled=ON; volume=pow(0.1,3.0*(1.0-pars->PVolume/96.0));//-60 dB .. 0 dB volume*=VelF(velocity,pars->PAmpVelocityScaleFunction); if (pars->PPanning!=0) panning=pars->PPanning/127.0; else panning=RND; numstages=pars->Pnumstages; stereo=pars->Pstereo; start=pars->Pstart; firsttick=1; //int pos[MAX_SUB_HARMONICS]; if (pars->Pfixedfreq==0) basefreq=freq; else { basefreq=440.0; int fixedfreqET=pars->PfixedfreqET; if (fixedfreqET!=0) {//if the frequency varies according the keyboard note REALTYPE tmp=(midinote-69.0)/12.0*(pow(2.0,(fixedfreqET-1)/63.0)-1.0); if (fixedfreqET<=64) basefreq*=pow(2.0f,tmp); else basefreq*=pow(3.0f,tmp); }; }; REALTYPE detune=getdetune(pars->PDetuneType,pars->PCoarseDetune,pars->PDetune); basefreq*=pow(2.0,detune/1200.0);//detune // basefreq*=ctl->pitchwheel.relfreq;//pitch wheel //global filter GlobalFilterCenterPitch=pars->GlobalFilter->getfreq()+//center freq (pars->PGlobalFilterVelocityScale/127.0*6.0)* //velocity sensing (VelF(velocity,pars->PGlobalFilterVelocityScaleFunction)-1); GlobalFilterL=NULL; GlobalFilterR=NULL; GlobalFilterEnvelope=NULL; //select only harmonics that desire to compute numharmonics=0; for (int n=0;n<MAX_SUB_HARMONICS;n++) { if (pars->Phmag[n]==0)continue; if (n*basefreq>SAMPLE_RATE/2.0) break;//remove the freqs above the Nyquist freq pos[numharmonics++]=n; }; firstnumharmonics=numharmonics;//(gf)Useful in legato mode. if (numharmonics==0) { NoteEnabled=OFF; return; }; lfilter=new bpfilter[numstages*numharmonics]; if (stereo!=0) rfilter=new bpfilter[numstages*numharmonics]; //how much the amplitude is normalised (because the harmonics) reduceamp=0.0; for (int n=0;n<numharmonics;n++) { REALTYPE freq=basefreq*(pos[n]+1); //the bandwidth is not absolute(Hz); it is relative to frequency REALTYPE bw=pow(10,(pars->Pbandwidth-127.0)/127.0*4)*numstages; //Bandwidth Scale bw*=pow(1000/freq,(float)((pars->Pbwscale-64.0)/64.0*3.0)); //Relative BandWidth bw*=pow(100,(float)((pars->Phrelbw[pos[n]]-64.0)/64.0)); if (bw>25.0) bw=25.0; //try to keep same amplitude on all freqs and bw. (empirically) gain=sqrt(1500.0/(bw*freq)); hmagnew=1.0-pars->Phmag[pos[n]]/127.0; //hgain; switch (pars->Phmagtype) { case 1: hgain=exp(hmagnew*log(0.01)); break; case 2: hgain=exp(hmagnew*log(0.001)); break; case 3: hgain=exp(hmagnew*log(0.0001)); break; case 4: hgain=exp(hmagnew*log(0.00001)); break; default: hgain=1.0-hmagnew; }; gain*=hgain; reduceamp+=hgain; for (int nph=0;nph<numstages;nph++) { REALTYPE amp=1.0; if (nph==0) amp=gain; initfilter(lfilter[nph+n*numstages],freq,bw,amp,hgain); if (stereo!=0) initfilter(rfilter[nph+n*numstages],freq,bw,amp,hgain); }; }; if (reduceamp<0.001) reduceamp=1.0; volume/=reduceamp; oldpitchwheel=0; oldbandwidth=64; if (pars->Pfixedfreq==0) initparameters(basefreq); else initparameters(basefreq/440.0*freq); oldamplitude=newamplitude; ready=1; };
// SUBlegatonote: This function is (mostly) a copy of SUBnote(...) and // initparameters(...) stuck together with some lines removed so that // it only alter the already playing note (to perform legato). It is // possible I left stuff that is not required for this. void SUBnote::SUBlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool externcall) { //SUBnoteParameters *parameters=pars; //Controller *ctl_=ctl; // Manage legato stuff if (externcall) Legato.msg=LM_Norm; if (Legato.msg!=LM_CatchUp) { Legato.lastfreq=Legato.param.freq; Legato.param.freq=freq; Legato.param.vel=velocity; Legato.param.portamento=portamento_; Legato.param.midinote=midinote; if (Legato.msg==LM_Norm) { if (Legato.silent) { Legato.fade.m=0.0; Legato.msg=LM_FadeIn; } else { Legato.fade.m=1.0; Legato.msg=LM_FadeOut; return; } } if (Legato.msg==LM_ToNorm) Legato.msg=LM_Norm; } portamento=portamento_; this->freq = freq; volume=pow(0.1,3.0*(1.0-pars->PVolume/96.0));//-60 dB .. 0 dB volume*=VelF(velocity,pars->PAmpVelocityScaleFunction); if (pars->PPanning!=0) panning=pars->PPanning/127.0; else panning=RND; ///start=pars->Pstart; //int pos[MAX_SUB_HARMONICS]; if (pars->Pfixedfreq==0) basefreq=freq; else { basefreq=440.0; int fixedfreqET=pars->PfixedfreqET; if (fixedfreqET!=0) {//if the frequency varies according the keyboard note REALTYPE tmp=(midinote-69.0)/12.0*(pow(2.0,(fixedfreqET-1)/63.0)-1.0); if (fixedfreqET<=64) basefreq*=pow(2.0f,tmp); else basefreq*=pow(3.0f,tmp); }; }; REALTYPE detune=getdetune(pars->PDetuneType,pars->PCoarseDetune,pars->PDetune); basefreq*=pow(2.0,detune/1200.0);//detune //global filter GlobalFilterCenterPitch=pars->GlobalFilter->getfreq()+//center freq (pars->PGlobalFilterVelocityScale/127.0*6.0)* //velocity sensing (VelF(velocity,pars->PGlobalFilterVelocityScaleFunction)-1); int legatonumharmonics=0; for (int n=0;n<MAX_SUB_HARMONICS;n++) { if (pars->Phmag[n]==0)continue; if (n*basefreq>SAMPLE_RATE/2.0) break;//remove the freqs above the Nyquist freq pos[legatonumharmonics++]=n; }; if (legatonumharmonics>firstnumharmonics) numharmonics=firstnumharmonics; else numharmonics=legatonumharmonics; if (numharmonics==0) { NoteEnabled=OFF; return; }; //how much the amplitude is normalised (because the harmonics) reduceamp=0.0; for (int n=0;n<numharmonics;n++) { REALTYPE freq=basefreq*(pos[n]+1); //the bandwidth is not absolute(Hz); it is relative to frequency REALTYPE bw=pow(10,(pars->Pbandwidth-127.0)/127.0*4)*numstages; //Bandwidth Scale bw*=pow(1000/freq,(float)((pars->Pbwscale-64.0)/64.0*3.0)); //Relative BandWidth bw*=pow(100,(float)((pars->Phrelbw[pos[n]]-64.0)/64.0)); if (bw>25.0) bw=25.0; //try to keep same amplitude on all freqs and bw. (empirically) gain=sqrt(1500.0/(bw*freq)); hmagnew=1.0-pars->Phmag[pos[n]]/127.0; switch (pars->Phmagtype) { case 1: hgain=exp(hmagnew*log(0.01)); break; case 2: hgain=exp(hmagnew*log(0.001)); break; case 3: hgain=exp(hmagnew*log(0.0001)); break; case 4: hgain=exp(hmagnew*log(0.00001)); break; default: hgain=1.0-hmagnew; }; gain*=hgain; reduceamp+=hgain; for (int nph=0;nph<numstages;nph++) { REALTYPE amp=1.0; if (nph==0) amp=gain; initfilter(lfilter[nph+n*numstages],freq,bw,amp,hgain); if (stereo!=0) initfilter(rfilter[nph+n*numstages],freq,bw,amp,hgain); }; }; if (reduceamp<0.001) reduceamp=1.0; volume/=reduceamp; oldpitchwheel=0; oldbandwidth=64; if (pars->Pfixedfreq==0) freq=basefreq; else freq*=basefreq/440.0; /////////////// // Altered initparameters(...) content: if (pars->PGlobalFilterEnabled!=0) { globalfiltercenterq=pars->GlobalFilter->getq(); GlobalFilterFreqTracking=pars->GlobalFilter->getfreqtracking(basefreq); }; // end of the altered initparameters function content. /////////////// oldamplitude=newamplitude; // End of the SUBlegatonote function. };
PADnote::PADnote(PADnoteParameters *parameters, Controller *ctl_, REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool besilent) { ready = 0; // Initialise some legato-specific vars Legato.msg = LM_Norm; Legato.fade.length = (int)(SAMPLE_RATE * 0.005); // 0.005 seems ok. if(Legato.fade.length < 1) Legato.fade.length = 1; // (if something's fishy) Legato.fade.step = (1.0 / Legato.fade.length); Legato.decounter = -10; Legato.param.freq = freq; Legato.param.vel = velocity; Legato.param.portamento = portamento_; Legato.param.midinote = midinote; Legato.silent = besilent; pars = parameters; portamento = portamento_; ctl = ctl_; this->velocity = velocity; finished_ = false; if(pars->Pfixedfreq == 0) basefreq = freq; else { basefreq = 440.0; int fixedfreqET = pars->PfixedfreqET; if(fixedfreqET != 0) { //if the frequency varies according the keyboard note REALTYPE tmp = (midinote - 69.0) / 12.0 * (pow(2.0, (fixedfreqET - 1) / 63.0) - 1.0); if(fixedfreqET <= 64) basefreq *= pow(2.0, tmp); else basefreq *= pow(3.0, tmp); } } firsttime = true; released = false; realfreq = basefreq; NoteGlobalPar.Detune = getdetune(pars->PDetuneType, pars->PCoarseDetune, pars->PDetune); //find out the closest note REALTYPE logfreq = log(basefreq * pow(2.0, NoteGlobalPar.Detune / 1200.0)); REALTYPE mindist = fabs(logfreq - log(pars->sample[0].basefreq + 0.0001)); nsample = 0; for(int i = 1; i < PAD_MAX_SAMPLES; i++) { if(pars->sample[i].smp == NULL) break; REALTYPE dist = fabs(logfreq - log(pars->sample[i].basefreq + 0.0001)); // printf("(mindist=%g) %i %g %g\n",mindist,i,dist,pars->sample[i].basefreq); if(dist < mindist) { nsample = i; mindist = dist; } } int size = pars->sample[nsample].size; if(size == 0) size = 1; poshi_l = (int)(RND * (size - 1)); if(pars->PStereo != 0) poshi_r = (poshi_l + size / 2) % size; else poshi_r = poshi_l; poslo = 0.0; tmpwave = new REALTYPE [SOUND_BUFFER_SIZE]; if(pars->PPanning == 0) NoteGlobalPar.Panning = RND; else NoteGlobalPar.Panning = pars->PPanning / 128.0; NoteGlobalPar.FilterCenterPitch = pars->GlobalFilter->getfreq() //center freq + pars->PFilterVelocityScale / 127.0 * 6.0 //velocity sensing * (VelF(velocity, pars-> PFilterVelocityScaleFunction) - 1); if(pars->PPunchStrength != 0) { NoteGlobalPar.Punch.Enabled = 1; NoteGlobalPar.Punch.t = 1.0; //start from 1.0 and to 0.0 NoteGlobalPar.Punch.initialvalue = ((pow(10, 1.5 * pars->PPunchStrength / 127.0) - 1.0) * VelF(velocity, pars->PPunchVelocitySensing)); REALTYPE time = pow(10, 3.0 * pars->PPunchTime / 127.0) / 10000.0; //0.1 .. 100 ms REALTYPE stretch = pow(440.0 / freq, pars->PPunchStretch / 64.0); NoteGlobalPar.Punch.dt = 1.0 / (time * SAMPLE_RATE * stretch); } else NoteGlobalPar.Punch.Enabled = 0; NoteGlobalPar.FreqEnvelope = new Envelope(pars->FreqEnvelope, basefreq); NoteGlobalPar.FreqLfo = new LFO(pars->FreqLfo, basefreq); NoteGlobalPar.AmpEnvelope = new Envelope(pars->AmpEnvelope, basefreq); NoteGlobalPar.AmpLfo = new LFO(pars->AmpLfo, basefreq); NoteGlobalPar.Volume = 4.0 * pow(0.1, 3.0 * (1.0 - pars->PVolume / 96.0)) //-60 dB .. 0 dB * VelF(velocity, pars->PAmpVelocityScaleFunction); //velocity sensing NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output globaloldamplitude = globalnewamplitude = NoteGlobalPar.Volume * NoteGlobalPar.AmpEnvelope-> envout_dB() * NoteGlobalPar.AmpLfo->amplfoout(); NoteGlobalPar.GlobalFilterL = new Filter(pars->GlobalFilter); NoteGlobalPar.GlobalFilterR = new Filter(pars->GlobalFilter); NoteGlobalPar.FilterEnvelope = new Envelope(pars->FilterEnvelope, basefreq); NoteGlobalPar.FilterLfo = new LFO(pars->FilterLfo, basefreq); NoteGlobalPar.FilterQ = pars->GlobalFilter->getq(); NoteGlobalPar.FilterFreqTracking = pars->GlobalFilter->getfreqtracking( basefreq); ready = 1; ///sa il pun pe asta doar cand e chiar gata if(parameters->sample[nsample].smp == NULL) { finished_ = true; return; } }
// PADlegatonote: This function is (mostly) a copy of PADnote(...) // with some lines removed so that it only alter the already playing // note (to perform legato). It is possible I left stuff that is not // required for this. void PADnote::PADlegatonote(REALTYPE freq, REALTYPE velocity, int portamento_, int midinote, bool externcall) { PADnoteParameters *parameters = pars; //Controller *ctl_=ctl; // Manage legato stuff if(externcall) Legato.msg = LM_Norm; if(Legato.msg != LM_CatchUp) { Legato.lastfreq = Legato.param.freq; Legato.param.freq = freq; Legato.param.vel = velocity; Legato.param.portamento = portamento_; Legato.param.midinote = midinote; if(Legato.msg == LM_Norm) { if(Legato.silent) { Legato.fade.m = 0.0; Legato.msg = LM_FadeIn; } else { Legato.fade.m = 1.0; Legato.msg = LM_FadeOut; return; } } if(Legato.msg == LM_ToNorm) Legato.msg = LM_Norm; } portamento = portamento_; this->velocity = velocity; finished_ = false; if(pars->Pfixedfreq == 0) basefreq = freq; else { basefreq = 440.0; int fixedfreqET = pars->PfixedfreqET; if(fixedfreqET != 0) { //if the frequency varies according the keyboard note REALTYPE tmp = (midinote - 69.0) / 12.0 * (pow(2.0, (fixedfreqET - 1) / 63.0) - 1.0); if(fixedfreqET <= 64) basefreq *= pow(2.0, tmp); else basefreq *= pow(3.0, tmp); } } released = false; realfreq = basefreq; getdetune(pars->PDetuneType, pars->PCoarseDetune, pars->PDetune); //find out the closest note REALTYPE logfreq = log(basefreq * pow(2.0, NoteGlobalPar.Detune / 1200.0)); REALTYPE mindist = fabs(logfreq - log(pars->sample[0].basefreq + 0.0001)); nsample = 0; for(int i = 1; i < PAD_MAX_SAMPLES; i++) { if(pars->sample[i].smp == NULL) break; REALTYPE dist = fabs(logfreq - log(pars->sample[i].basefreq + 0.0001)); if(dist < mindist) { nsample = i; mindist = dist; } } int size = pars->sample[nsample].size; if(size == 0) size = 1; if(pars->PPanning == 0) NoteGlobalPar.Panning = RND; else NoteGlobalPar.Panning = pars->PPanning / 128.0; NoteGlobalPar.FilterCenterPitch = pars->GlobalFilter->getfreq() //center freq + pars->PFilterVelocityScale / 127.0 * 6.0 //velocity sensing * (VelF(velocity, pars-> PFilterVelocityScaleFunction) - 1); NoteGlobalPar.Volume = 4.0 * pow(0.1, 3.0 * (1.0 - pars->PVolume / 96.0)) //-60 dB .. 0 dB * VelF(velocity, pars->PAmpVelocityScaleFunction); //velocity sensing NoteGlobalPar.AmpEnvelope->envout_dB(); //discard the first envelope output globaloldamplitude = globalnewamplitude = NoteGlobalPar.Volume * NoteGlobalPar.AmpEnvelope-> envout_dB() * NoteGlobalPar.AmpLfo->amplfoout(); NoteGlobalPar.FilterQ = pars->GlobalFilter->getq(); NoteGlobalPar.FilterFreqTracking = pars->GlobalFilter->getfreqtracking( basefreq); if(parameters->sample[nsample].smp == NULL) { finished_ = true; return; } // End of the PADlegatonote function. }
void PADnote::update_parameters_realtime() //Update the parameters in real time ;) //by VDX { if (pars) { //PADsynth GLOBAL Parameters of the Instrument //Global Stuff if (pars->b_changed) { NoteGlobalPar.Volume=4.0*pow(0.1,3.0*(1.0-pars->PVolume/96.0))//-60 dB .. 0 dB *VelF(velocity,pars->PAmpVelocityScaleFunction);//velocity sensing if (pars->PPanning==0) NoteGlobalPar.Panning=RND; else NoteGlobalPar.Panning=pars->PPanning/128.0; pars->b_changed --; }; //Frequency LFO if (pars->FreqLfo) if (pars->FreqLfo->b_changed) { NoteGlobalPar.FreqLfo->init(pars->FreqLfo,basefreq); pars->FreqLfo->b_changed --; }; //Amplitude LFO if (pars->AmpLfo) if (pars->AmpLfo->b_changed) { NoteGlobalPar.AmpLfo->init(pars->AmpLfo,basefreq); pars->AmpLfo->b_changed --; }; //Filter LFO if (pars->FilterLfo) if (pars->FilterLfo->b_changed) { NoteGlobalPar.FilterLfo->init(pars->FilterLfo,basefreq); pars->FilterLfo->b_changed --; } //Filter parameters if (pars->GlobalFilter) if (pars->GlobalFilter->b_changed) { //update central frequency NoteGlobalPar.FilterCenterPitch = pars->GlobalFilter->getfreq() + pars->PFilterVelocityScale/127.0*6.0* (VelF(velocity,pars->PFilterVelocityScaleFunction)-1); //update Q NoteGlobalPar.FilterQ=pars->GlobalFilter->getq(); //update freq tracking NoteGlobalPar.FilterFreqTracking=pars->GlobalFilter->getfreqtracking(basefreq); //update gain NoteGlobalPar.GlobalFilterL->update_gain(pars->GlobalFilter); NoteGlobalPar.GlobalFilterR->update_gain(pars->GlobalFilter); //velocity stuff //o->init(pars->GlobalPar.GlobalFilter,&pars->GlobalPar.PFilterVelocityScale,&pars->GlobalPar.PFilterVelocityScaleFunction); //this is already implemented while updating the central freq pars->GlobalFilter->b_changed--; } } //if pars };