/* ZynAddSubFX - a software synthesizer LFO.cpp - LFO implementation Copyright (C) 2002-2005 Nasca Octavian Paul Author: Nasca Octavian Paul This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program 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 (version 2 or later) for more details. You should have received a copy of the GNU General Public License (version 2) along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "LFO.h" #include "../Params/LFOParams.h" #include "../Misc/Util.h" #include #include #include LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t) :delayTime(t, lfopars.Pdelay / 127.0f * 4.0f), //0..4 sec waveShape(lfopars.PLFOtype), deterministic(!lfopars.Pfreqrand), dt_(t.dt()), lfopars_(lfopars), basefreq_(basefreq) { int stretch = lfopars.Pstretch; if(stretch == 0) stretch = 1; //max 2x/octave const float lfostretch = powf(basefreq / 440.0f, (stretch - 64.0f) / 63.0f); const float lfofreq = (powf(2, lfopars.Pfreq * 10.0f) - 1.0f) / 12.0f * lfostretch; phaseInc = fabs(lfofreq) * t.dt(); if(!lfopars.Pcontinous) { if(lfopars.Pstartphase == 0) phase = RND; else phase = fmod((lfopars.Pstartphase - 64.0f) / 127.0f + 1.0f, 1.0f); } else { const float tmp = fmod(t.time() * phaseInc, 1.0f); phase = fmod((lfopars.Pstartphase - 64.0f) / 127.0f + 1.0f + tmp, 1.0f); } //Limit the Frequency(or else...) if(phaseInc > 0.49999999f) phaseInc = 0.499999999f; lfornd = limit(lfopars.Prandomness / 127.0f, 0.0f, 1.0f); lfofreqrnd = powf(lfopars.Pfreqrand / 127.0f, 2.0f) * 4.0f; switch(lfopars.fel) { case 1: lfointensity = lfopars.Pintensity / 127.0f; break; case 2: lfointensity = lfopars.Pintensity / 127.0f * 4.0f; break; //in octave default: lfointensity = powf(2, lfopars.Pintensity / 127.0f * 11.0f) - 1.0f; //in centi phase -= 0.25f; //chance the starting phase break; } amp1 = (1 - lfornd) + lfornd * RND; amp2 = (1 - lfornd) + lfornd * RND; incrnd = nextincrnd = 1.0f; computeNextFreqRnd(); computeNextFreqRnd(); //twice because I want incrnd & nextincrnd to be random } LFO::~LFO() {} float LFO::baseOut(const char waveShape, const float phase) const { switch(waveShape) { case LFO_TRIANGLE: if(phase >= 0.0f && phase < 0.25f) return 4.0f * phase; else if(phase > 0.25f && phase < 0.75f) return 2 - 4 * phase; else return 4.0f * phase - 4.0f; break; case LFO_SQUARE: if(phase < 0.5f) return -1; else return 1; break; case LFO_RAMPUP: return (phase - 0.5f) * 2.0f; case LFO_RAMPDOWN: return (0.5f - phase) * 2.0f; case LFO_EXP_DOWN1: return powf(0.05f, phase) * 2.0f - 1.0f; case LFO_EXP_DOWN2: return powf(0.001f, phase) * 2.0f - 1.0f; default: return cosf(phase * 2.0f * PI); //LFO_SINE } } float LFO::lfoout() { //update internals XXX TODO cleanup { waveShape = lfopars_.PLFOtype; int stretch = lfopars_.Pstretch; if(stretch == 0) stretch = 1; const float lfostretch = powf(basefreq_ / 440.0f, (stretch - 64.0f) / 63.0f); float lfofreq = (powf(2, lfopars_.Pfreq * 10.0f) - 1.0f) / 12.0f * lfostretch; phaseInc = fabs(lfofreq) * dt_; switch(lfopars_.fel) { case 1: lfointensity = lfopars_.Pintensity / 127.0f; break; case 2: lfointensity = lfopars_.Pintensity / 127.0f * 4.0f; break; //in octave default: lfointensity = powf(2, lfopars_.Pintensity / 127.0f * 11.0f) - 1.0f; //in centi //x -= 0.25f; //chance the starting phase break; } } float out = baseOut(waveShape, phase); if(waveShape == LFO_SINE || waveShape == LFO_TRIANGLE) out *= lfointensity * (amp1 + phase * (amp2 - amp1)); else out *= lfointensity * amp2; if(delayTime.inFuture()) return out; //Start oscillating if(deterministic) phase += phaseInc; else { const float tmp = (incrnd * (1.0f - phase) + nextincrnd * phase); phase += phaseInc * limit(tmp, 0.0f, 1.0f); } if(phase >= 1) { phase = fmod(phase, 1.0f); amp1 = amp2; amp2 = (1 - lfornd) + lfornd * RND; computeNextFreqRnd(); } return out; } /* * LFO out (for amplitude) */ float LFO::amplfoout() { return limit(1.0f - lfointensity + lfoout(), -1.0f, 1.0f); } void LFO::computeNextFreqRnd() { if(deterministic) return; incrnd = nextincrnd; nextincrnd = powf(0.5f, lfofreqrnd) + RND * (powf(2.0f, lfofreqrnd) - 1.0f); }