You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
3.3 KiB
157 lines
3.3 KiB
#include <math.h>
|
|
#include "adenv.h"
|
|
|
|
using namespace daisysp;
|
|
|
|
//#define EXPF expf
|
|
// This causes with infinity with certain curves,
|
|
// which then causes NaN erros...
|
|
#define EXPF expf_fast
|
|
|
|
// To resolve annoying bugs when using this you can:
|
|
// if (val != val)
|
|
// val = 0.0f; // This will un-NaN the value.
|
|
|
|
// Fast Exp approximation
|
|
// 8x multiply version
|
|
//inline float expf_fast(float x)
|
|
//{
|
|
// x = 1.0f + x / 256.0f;
|
|
// x *= x;
|
|
// x *= x;
|
|
// x *= x;
|
|
// x *= x;
|
|
// x *= x;
|
|
// x *= x;
|
|
// x *= x;
|
|
// x *= x;
|
|
// return x;
|
|
//}
|
|
|
|
// 10x multiply version
|
|
inline float expf_fast(float x)
|
|
{
|
|
x = 1.0f + x / 1024.0f;
|
|
x *= x;
|
|
x *= x;
|
|
x *= x;
|
|
x *= x;
|
|
x *= x;
|
|
x *= x;
|
|
x *= x;
|
|
x *= x;
|
|
x *= x;
|
|
x *= x;
|
|
return x;
|
|
}
|
|
|
|
// Private Functions
|
|
void AdEnv::Init(float sample_rate)
|
|
{
|
|
sample_rate_ = sample_rate;
|
|
current_segment_ = ADENV_SEG_IDLE;
|
|
curve_scalar_ = 0.0f; // full linear
|
|
phase_ = 0;
|
|
min_ = 0.0f;
|
|
max_ = 1.0f;
|
|
output_ = 0.0001f;
|
|
for(uint8_t i = 0; i < ADENV_SEG_LAST; i++)
|
|
{
|
|
segment_time_[i] = 0.05f;
|
|
}
|
|
}
|
|
|
|
float AdEnv::Process()
|
|
{
|
|
uint32_t time_samps;
|
|
float val, out, end, beg, inc;
|
|
|
|
// Handle Retriggering
|
|
if(trigger_)
|
|
{
|
|
trigger_ = 0;
|
|
current_segment_ = ADENV_SEG_ATTACK;
|
|
phase_ = 0;
|
|
curve_x_ = 0.0f;
|
|
retrig_val_ = output_;
|
|
}
|
|
|
|
time_samps = (uint32_t)(segment_time_[current_segment_] * sample_rate_);
|
|
|
|
// Fixed for now, but we could always make this a more flexible multi-segment envelope
|
|
switch(current_segment_)
|
|
{
|
|
case ADENV_SEG_ATTACK:
|
|
beg = retrig_val_;
|
|
end = 1.0f;
|
|
break;
|
|
case ADENV_SEG_DECAY:
|
|
beg = 1.0f;
|
|
end = 0.0f;
|
|
break;
|
|
case ADENV_SEG_IDLE:
|
|
default:
|
|
beg = 0;
|
|
end = 0;
|
|
break;
|
|
}
|
|
|
|
if(prev_segment_ != current_segment_)
|
|
{
|
|
//Reset at segment beginning
|
|
curve_x_ = 0;
|
|
phase_ = 0;
|
|
}
|
|
|
|
//recalculate increment value
|
|
if(curve_scalar_ == 0.0f)
|
|
{
|
|
c_inc_ = (end - beg) / time_samps;
|
|
}
|
|
else
|
|
{
|
|
c_inc_ = (end - beg) / (1.0f - EXPF(curve_scalar_));
|
|
}
|
|
|
|
|
|
// update output
|
|
val = output_;
|
|
inc = c_inc_;
|
|
out = val;
|
|
if(curve_scalar_ == 0.0f)
|
|
{
|
|
val += inc;
|
|
}
|
|
else
|
|
{
|
|
curve_x_ += (curve_scalar_ / time_samps);
|
|
val = beg + inc * (1.0f - EXPF(curve_x_));
|
|
if(val != val)
|
|
val = 0.0f; // NaN check
|
|
}
|
|
|
|
// Update Segment
|
|
phase_ += 1;
|
|
prev_segment_ = current_segment_;
|
|
if(current_segment_ != ADENV_SEG_IDLE)
|
|
{
|
|
if((out >= 1.f && current_segment_ == ADENV_SEG_ATTACK)
|
|
|| (out <= 0.f && current_segment_ == ADENV_SEG_DECAY))
|
|
{
|
|
// Advance segment
|
|
current_segment_++;
|
|
// TODO: Add Cycling feature here.
|
|
if(current_segment_ > ADENV_SEG_DECAY)
|
|
{
|
|
current_segment_ = ADENV_SEG_IDLE;
|
|
}
|
|
}
|
|
}
|
|
if(current_segment_ == ADENV_SEG_IDLE)
|
|
{
|
|
val = out = 0.0f;
|
|
}
|
|
output_ = val;
|
|
|
|
return out * (max_ - min_) + min_;
|
|
}
|
|
|