|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /*
- 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 <cstdlib>
- #include <cstdio>
- #include <cmath>
-
- LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t)
- :first_half(-1),
- 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)
- {
- 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;
- case LFO_RANDOM:
- if ((phase < 0.5) != first_half) {
- first_half = phase < 0.5;
- last_random = 2*RND-1;
- }
- return last_random;
- default: return cosf(phase * 2.0f * PI); //LFO_SINE
- }
- }
-
-
- float LFO::lfoout()
- {
- //update internals XXX TODO cleanup
- if ( ! lfopars_.time || lfopars_.last_update_timestamp == lfopars_.time->time())
- {
- 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);
- }
|