forked from electro-smith/DaisySP
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AnalogBassDrum module (electro-smith#118)
* building * sample based * setters * comments and init * no bd. * double comment * trig * two consts * kOneTwelfth
- Loading branch information
Showing
4 changed files
with
299 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ MODULES = \ | |
adenv \ | ||
adsr \ | ||
allpass \ | ||
analogbassdrum \ | ||
autowah \ | ||
atone \ | ||
balance \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
#include "dsp.h" | ||
#include "analogbassdrum.h" | ||
#include <math.h> | ||
|
||
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 = 1.0e-3 * sample_rate_; | ||
const int kFMPulseDuration = 6.0e-3 * sample_rate_; | ||
const float kPulseDecayTime = 0.2e-3 * sample_rate_; | ||
const float kPulseFilterTime = 0.1e-3 * 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(.4 * 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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
#pragma once | ||
#ifndef DSY_ANALOG_BD_H | ||
#define DSY_ANALOG_BD_H | ||
|
||
#include <stdint.h> | ||
#ifdef __cplusplus | ||
|
||
#include "modules/oscillator.h" | ||
#include "modules/svf.h" | ||
|
||
/** @file analogbassdrum.h */ | ||
|
||
namespace daisysp | ||
{ | ||
/** | ||
@brief 808 bass drum model, revisited. | ||
@author Ben Sergentanis | ||
@date Jan 2021 | ||
Ported from pichenettes/eurorack/plaits/dsp/drums/analog_bass_drum.h \n | ||
to an independent module. \n | ||
Original code written by Emilie Gillet in 2016. \n | ||
*/ | ||
class AnalogBassDrum | ||
{ | ||
public: | ||
AnalogBassDrum() {} | ||
~AnalogBassDrum() {} | ||
|
||
/** Initialize the module | ||
\param sample_rate Audio engine sample rate | ||
*/ | ||
void Init(float sample_rate); | ||
|
||
/** Get the next sample. | ||
\param trigger True strikes the drum. Defaults to false. | ||
*/ | ||
float Process(bool trigger = false); | ||
|
||
/** Strikes the drum. */ | ||
void Trig(); | ||
|
||
/** Set the bassdrum to play infinitely | ||
\param sustain True = infinite length | ||
*/ | ||
void SetSustain(bool sustain); | ||
|
||
/** Set a small accent. | ||
\param accent Works 0-1 | ||
*/ | ||
void SetAccent(float accent); | ||
|
||
/** Set the drum's root frequency | ||
\param f0 Frequency in Hz | ||
*/ | ||
void SetFreq(float f0); | ||
|
||
/** Set the amount of click. | ||
\param tone Works 0-1. | ||
*/ | ||
void SetTone(float tone); | ||
|
||
/** Set the decay length of the drum. | ||
\param decay Works best 0-1. | ||
*/ | ||
void SetDecay(float decay); | ||
|
||
/** Set the amount of fm attack. Works together with self fm. | ||
\param attack_fm_amount Works best 0-1. | ||
*/ | ||
void SetAttackFmAmount(float attack_fm_amount); | ||
|
||
/**Set the amount of self fm. Also affects fm attack, and volume decay. | ||
\param self_fm_amount Works best 0-1. | ||
*/ | ||
void SetSelfFmAmount(float self_fm_amount); | ||
|
||
private: | ||
inline float Diode(float x); | ||
|
||
float sample_rate_; | ||
|
||
float accent_, f0_, tone_, decay_; | ||
float attack_fm_amount_, self_fm_amount_; | ||
|
||
bool trig_, sustain_; | ||
|
||
int pulse_remaining_samples_; | ||
int fm_pulse_remaining_samples_; | ||
float pulse_; | ||
float pulse_height_; | ||
float pulse_lp_; | ||
float fm_pulse_lp_; | ||
float retrig_pulse_; | ||
float lp_out_; | ||
float tone_lp_; | ||
float sustain_gain_; | ||
|
||
Svf resonator_; | ||
|
||
//for use in sin + cos osc. in sustain mode | ||
float phase_; | ||
}; | ||
} // namespace daisysp | ||
#endif | ||
#endif |