/*
Copyright (C) 2010-2012 Florian Jung
This file is part of flo's FM synth.
flo's FM synth 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.
flo's FM synth 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 flo's FM synth. If not, see .
*/
#include "envelope.h"
Envelope::Envelope(env_settings_t s, int frames)
{
level=0;
t=0;
state=ATTACK;
max=ONE;
nth_frame=frames;
set_ratefactor(1.0);
has_release_phase=(s.release>=0);
if (!has_release_phase)
s.hold=false;
set_attack(s.attack);
set_decay(s.decay);
set_sustain(s.sustain);
set_release(s.release);
set_hold(s.hold);
}
void Envelope::set_ratefactor(double factor)
{
ratefactor=ONE*factor;
set_attack(attack_orig);
set_decay(decay_orig);
set_release(release_orig);
}
void Envelope::set_attack(jack_nframes_t a)
{
attack_orig=a;
attack=(a*ratefactor >>SCALE)/nth_frame;
if (state==ATTACK)
t=attack*level >>SCALE;
}
void Envelope::set_decay(jack_nframes_t d)
{
decay_orig=d;
decay=(d*ratefactor >>SCALE)/nth_frame;
if ((state==DECAY) && (sustain!=ONE))
if (sustain>SCALE)/nth_frame;
if (state==RELEASE)
if (sustain>0) //to avoid a div. by zero
t=release*(sustain-level)/sustain;
}
void Envelope::set_hold(bool h)
{
hold=h;
if ((h==false) && (state==HOLD))
{
t=0;
state=RELEASE;
}
}
void Envelope::reattack()
{
state=ATTACK;
t=attack*level >>SCALE;
sustain=sustain_orig;
}
void Envelope::reset()
{
state=ATTACK;
sustain=sustain_orig;
level=0;
t=0;
}
void Envelope::release_key()
{
if (has_release_phase)
if ((state!=RELEASE) && (state!=DONE))
{
t=0;
state=RELEASE;
sustain=level;
}
//if (!has_release_phase) ignore();
}
bool Envelope::still_active()
{
return (state!=DONE);
}
fixed_t Envelope::get_level() //must be called each frame
{
switch (state)
{
case ATTACK:
if (t>=attack)
{
level=max;
state=DECAY;
t=0;
}
else //will only happen, if t < attack. so attack will
{ //always be greater than zero -> no div. by zero
level=max * t / attack ;
}
break;
case DECAY:
if (t>=decay)
{
level=max*sustain >>SCALE;
if (has_release_phase)
if (hold)
state=HOLD;
else
state=RELEASE;
else
state=DONE;
t=0;
}
else //will only happen, if t < decay. so decay will
{ //always be greater than zero -> no div. by zero
level=(ONE - (ONE-sustain)*t/decay)*max >>SCALE;
}
break;
case HOLD:
//does nothing. level must be set properly before entering HOLD state
break;
case RELEASE:
if (t>=release)
{
level=0;
state=DONE;
}
else //will only happen, if t < release. so release will
{ //always be greater than zero -> no div. by zero
level=(sustain - sustain * t/release)*max >>SCALE;
}
break;
case DONE:
//does nothing. level must be set properly before entering DONE state
break;
}
++t;
return level;
}