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.

198 lines
5.4 KiB

4 years ago
#include <cmath>
#include "../utility/dsp.h"
#include "KarplusString.h"
#include <stdlib.h>
using namespace daisysp;
void String::Init(float sample_rate)
{
sample_rate_ = sample_rate;
SetFreq(440.f);
non_linearity_amount_ = .5f;
brightness_ = .5f;
damping_ = .5f;
string_.Init();
stretch_.Init();
Reset();
SetFreq(440.f);
SetDamping(.8f);
SetNonLinearity(.1f);
SetBrightness(.5f);
crossfade_.Init();
}
void String::Reset()
{
string_.Reset();
stretch_.Reset();
iir_damping_filter_.Init(sample_rate_);
dc_blocker_.Init(sample_rate_);
dispersion_noise_ = 0.0f;
curved_bridge_ = 0.0f;
out_sample_[0] = out_sample_[1] = 0.0f;
src_phase_ = 0.0f;
}
float String::Process(const float in)
{
if(non_linearity_amount_ <= 0.0f)
{
non_linearity_amount_ *= -1;
float ret = ProcessInternal<NON_LINEARITY_CURVED_BRIDGE>(in);
non_linearity_amount_ *= -1;
return ret;
}
else
{
return ProcessInternal<NON_LINEARITY_DISPERSION>(in);
}
}
void String::SetFreq(float freq)
{
freq /= sample_rate_;
frequency_ = fclamp(freq, 0.f, .25f);
}
void String::SetNonLinearity(float non_linearity_amount)
{
non_linearity_amount_ = fclamp(non_linearity_amount, 0.f, 1.f);
}
void String::SetBrightness(float brightness)
{
brightness_ = fclamp(brightness, 0.f, 1.f);
}
void String::SetDamping(float damping)
{
damping_ = fclamp(damping, 0.f, 1.f);
}
template <String::StringNonLinearity non_linearity>
float String::ProcessInternal(const float in)
{
float brightness = brightness_;
float delay = 1.0f / frequency_;
delay = fclamp(delay, 4.f, kDelayLineSize - 4.0f);
// If there is not enough delay time in the delay line, we play at the
// lowest possible note and we upsample on the fly with a shitty linear
// interpolator. We don't care because it's a corner case (frequency_ < 11.7Hz)
float src_ratio = delay * frequency_;
if(src_ratio >= 0.9999f)
{
// When we are above 11.7 Hz, we make sure that the linear interpolator
// does not get in the way.
src_phase_ = 1.0f;
src_ratio = 1.0f;
}
float damping_cutoff
= fmin(12.0f + damping_ * damping_ * 60.0f + brightness * 24.0f, 84.0f);
float damping_f
= fmin(frequency_ * powf(2.f, damping_cutoff * kOneTwelfth), 0.499f);
// Crossfade to infinite decay.
if(damping_ >= 0.95f)
{
float to_infinite = 20.0f * (damping_ - 0.95f);
brightness += to_infinite * (1.0f - brightness);
damping_f += to_infinite * (0.4999f - damping_f);
damping_cutoff += to_infinite * (128.0f - damping_cutoff);
}
float temp_f = damping_f * sample_rate_;
iir_damping_filter_.SetFreq(temp_f);
float ratio = powf(2.f, damping_cutoff * kOneTwelfth);
float damping_compensation = 1.f - 2.f * atanf(1.f / ratio) / (TWOPI_F);
float stretch_point
= non_linearity_amount_ * (2.0f - non_linearity_amount_) * 0.225f;
float stretch_correction = (160.0f / sample_rate_) * delay;
stretch_correction = fclamp(stretch_correction, 1.f, 2.1f);
float noise_amount_sqrt = non_linearity_amount_ > 0.75f
? 4.0f * (non_linearity_amount_ - 0.75f)
: 0.0f;
float noise_amount = noise_amount_sqrt * noise_amount_sqrt * 0.1f;
float noise_filter = 0.06f + 0.94f * brightness * brightness;
float bridge_curving_sqrt = non_linearity_amount_;
float bridge_curving = bridge_curving_sqrt * bridge_curving_sqrt * 0.01f;
float ap_gain = -0.618f * non_linearity_amount_
/ (0.15f + fabsf(non_linearity_amount_));
src_phase_ += src_ratio;
if(src_phase_ > 1.0f)
{
src_phase_ -= 1.0f;
delay = delay * damping_compensation;
float s = 0.0f;
if(non_linearity == NON_LINEARITY_DISPERSION)
{
float noise = rand() * kRandFrac - 0.5f;
fonepole(dispersion_noise_, noise, noise_filter);
delay *= 1.0f + dispersion_noise_ * noise_amount;
}
else
{
delay *= 1.0f - curved_bridge_ * bridge_curving;
}
if(non_linearity == NON_LINEARITY_DISPERSION)
{
float ap_delay = delay * stretch_point;
float main_delay = delay
- ap_delay * (0.408f - stretch_point * 0.308f)
* stretch_correction;
if(ap_delay >= 4.0f && main_delay >= 4.0f)
{
s = string_.Read(main_delay);
s = stretch_.Allpass(s, ap_delay, ap_gain);
}
else
{
s = string_.ReadHermite(delay);
}
}
else
{
s = string_.ReadHermite(delay);
}
if(non_linearity == NON_LINEARITY_CURVED_BRIDGE)
{
float value = fabsf(s) - 0.025f;
float sign = s > 0.0f ? 1.0f : -1.5f;
curved_bridge_ = (fabsf(value) + value) * sign;
}
s += in;
s = fclamp(s, -20.f, +20.f);
s = dc_blocker_.Process(s);
s = iir_damping_filter_.Process(s);
string_.Write(s);
out_sample_[1] = out_sample_[0];
out_sample_[0] = s;
}
crossfade_.SetPos(src_phase_);
return crossfade_.Process(out_sample_[1], out_sample_[0]);
}