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.
193 lines
4.6 KiB
193 lines
4.6 KiB
4 years ago
|
#include "../utility/dsp.h"
|
||
|
#include "analogbassdrum.h"
|
||
|
#include <cmath>
|
||
|
|
||
|
using namespace daisysp;
|
||
|
|
||
|
void AnalogBassDrum::Init(float sample_rate)
|
||
|
{
|
||
|
sample_rate_ = sample_rate;
|
||
|
|
||
|
trig_ = false;
|
||
|
|
||
|
pulse_remaining_samples_ = 0;
|
||
|
fm_pulse_remaining_samples_ = 0;
|
||
|
pulse_ = 0.0f;
|
||
|
pulse_height_ = 0.0f;
|
||
|
pulse_lp_ = 0.0f;
|
||
|
fm_pulse_lp_ = 0.0f;
|
||
|
retrig_pulse_ = 0.0f;
|
||
|
lp_out_ = 0.0f;
|
||
|
tone_lp_ = 0.0f;
|
||
|
sustain_gain_ = 0.0f;
|
||
|
phase_ = 0.f;
|
||
|
|
||
|
|
||
|
SetSustain(false);
|
||
|
SetAccent(.1f);
|
||
|
SetFreq(50.f);
|
||
|
SetTone(.1f);
|
||
|
SetDecay(.3f);
|
||
|
SetSelfFmAmount(1.f);
|
||
|
SetAttackFmAmount(.5f);
|
||
|
|
||
|
resonator_.Init(sample_rate_);
|
||
|
}
|
||
|
|
||
|
inline float AnalogBassDrum::Diode(float x)
|
||
|
{
|
||
|
if(x >= 0.0f)
|
||
|
{
|
||
|
return x;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
x *= 2.0f;
|
||
|
return 0.7f * x / (1.0f + fabsf(x));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float AnalogBassDrum::Process(bool trigger)
|
||
|
{
|
||
|
const int kTriggerPulseDuration = static_cast<int>(1.0e-3f * sample_rate_);
|
||
|
const int kFMPulseDuration = static_cast<int>(6.0e-3f * sample_rate_);
|
||
|
const float kPulseDecayTime = 0.2e-3f * sample_rate_;
|
||
|
const float kPulseFilterTime = 0.1e-3f * sample_rate_;
|
||
|
const float kRetrigPulseDuration = 0.05f * sample_rate_;
|
||
|
|
||
|
const float scale = 0.001f / f0_;
|
||
|
const float q = 1500.0f * powf(2.f, kOneTwelfth * decay_ * 80.0f);
|
||
|
const float tone_f
|
||
|
= fmin(4.0f * f0_ * powf(2.f, kOneTwelfth * tone_ * 108.0f), 1.0f);
|
||
|
const float exciter_leak = 0.08f * (tone_ + 0.25f);
|
||
|
|
||
|
|
||
|
if(trigger || trig_)
|
||
|
{
|
||
|
trig_ = false;
|
||
|
|
||
|
pulse_remaining_samples_ = kTriggerPulseDuration;
|
||
|
fm_pulse_remaining_samples_ = kFMPulseDuration;
|
||
|
pulse_height_ = 3.0f + 7.0f * accent_;
|
||
|
lp_out_ = 0.0f;
|
||
|
}
|
||
|
|
||
|
// Q39 / Q40
|
||
|
float pulse = 0.0f;
|
||
|
if(pulse_remaining_samples_)
|
||
|
{
|
||
|
--pulse_remaining_samples_;
|
||
|
pulse = pulse_remaining_samples_ ? pulse_height_ : pulse_height_ - 1.0f;
|
||
|
pulse_ = pulse;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pulse_ *= 1.0f - 1.0f / kPulseDecayTime;
|
||
|
pulse = pulse_;
|
||
|
}
|
||
|
if(sustain_)
|
||
|
{
|
||
|
pulse = 0.0f;
|
||
|
}
|
||
|
|
||
|
// C40 / R163 / R162 / D83
|
||
|
fonepole(pulse_lp_, pulse, 1.0f / kPulseFilterTime);
|
||
|
pulse = Diode((pulse - pulse_lp_) + pulse * 0.044f);
|
||
|
|
||
|
// Q41 / Q42
|
||
|
float fm_pulse = 0.0f;
|
||
|
if(fm_pulse_remaining_samples_)
|
||
|
{
|
||
|
--fm_pulse_remaining_samples_;
|
||
|
fm_pulse = 1.0f;
|
||
|
// C39 / C52
|
||
|
retrig_pulse_ = fm_pulse_remaining_samples_ ? 0.0f : -0.8f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// C39 / R161
|
||
|
retrig_pulse_ *= 1.0f - 1.0f / kRetrigPulseDuration;
|
||
|
}
|
||
|
if(sustain_)
|
||
|
{
|
||
|
fm_pulse = 0.0f;
|
||
|
}
|
||
|
fonepole(fm_pulse_lp_, fm_pulse, 1.0f / kPulseFilterTime);
|
||
|
|
||
|
// Q43 and R170 leakage
|
||
|
float punch = 0.7f + Diode(10.0f * lp_out_ - 1.0f);
|
||
|
|
||
|
// Q43 / R165
|
||
|
float attack_fm = fm_pulse_lp_ * 1.7f * attack_fm_amount_;
|
||
|
float self_fm = punch * 0.08f * self_fm_amount_;
|
||
|
float f = f0_ * (1.0f + attack_fm + self_fm);
|
||
|
f = fclamp(f, 0.0f, 0.4f);
|
||
|
|
||
|
float resonator_out;
|
||
|
if(sustain_)
|
||
|
{
|
||
|
sustain_gain_ = accent_ * decay_;
|
||
|
phase_ += f;
|
||
|
phase_ = phase_ >= 1.f ? phase_ - 1.f : phase_;
|
||
|
|
||
|
resonator_out = sin(TWOPI_F * phase_) * sustain_gain_;
|
||
|
lp_out_ = cos(TWOPI_F * phase_) * sustain_gain_;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
resonator_.SetFreq(f * sample_rate_);
|
||
|
//resonator_.SetRes(1.0f + q * f);
|
||
|
resonator_.SetRes(.4f * q * f);
|
||
|
|
||
|
resonator_.Process((pulse - retrig_pulse_ * 0.2f) * scale);
|
||
|
resonator_out = resonator_.Band();
|
||
|
lp_out_ = resonator_.Low();
|
||
|
}
|
||
|
|
||
|
fonepole(tone_lp_, pulse * exciter_leak + resonator_out, tone_f);
|
||
|
|
||
|
return tone_lp_;
|
||
|
}
|
||
|
|
||
|
void AnalogBassDrum::Trig()
|
||
|
{
|
||
|
trig_ = true;
|
||
|
}
|
||
|
|
||
|
void AnalogBassDrum::SetSustain(bool sustain)
|
||
|
{
|
||
|
sustain_ = sustain;
|
||
|
}
|
||
|
|
||
|
void AnalogBassDrum::SetAccent(float accent)
|
||
|
{
|
||
|
accent_ = fclamp(accent, 0.f, 1.f);
|
||
|
}
|
||
|
|
||
|
void AnalogBassDrum::SetFreq(float f0)
|
||
|
{
|
||
|
f0 /= sample_rate_;
|
||
|
f0_ = fclamp(f0, 0.f, .5f);
|
||
|
}
|
||
|
|
||
|
void AnalogBassDrum::SetTone(float tone)
|
||
|
{
|
||
|
tone_ = fclamp(tone, 0.f, 1.f);
|
||
|
}
|
||
|
|
||
|
void AnalogBassDrum::SetDecay(float decay)
|
||
|
{
|
||
|
decay_ = decay * .1f;
|
||
|
decay_ -= .1f;
|
||
|
}
|
||
|
|
||
|
void AnalogBassDrum::SetAttackFmAmount(float attack_fm_amount)
|
||
|
{
|
||
|
attack_fm_amount_ = attack_fm_amount * 50.f;
|
||
|
}
|
||
|
|
||
|
void AnalogBassDrum::SetSelfFmAmount(float self_fm_amount)
|
||
|
{
|
||
|
self_fm_amount_ = self_fm_amount * 50.f;
|
||
|
}
|