|
- /*
- 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 the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- */
-
- #include "LFO.h"
- #include "../Params/LFOParams.h"
- #include "../Misc/Util.h"
-
- #include <cstdlib>
- #include <cstdio>
- #include <cmath>
-
- namespace zyncarla {
-
- LFO::LFO(const LFOParams &lfopars, float basefreq, const AbsTime &t, WatchManager *m,
- const char *watch_prefix)
- :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),
- watchOut(m, watch_prefix, "out")
- {
- 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();
- }
-
- float watch_data[2] = {phase, out};
- watchOut(watch_data, 2);
-
- 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);
- }
-
- }
|