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.

202 lines
5.2 KiB

4 years ago
#include "../utility/dsp.h"
#include "synthsnaredrum.h"
#include <math.h>
#include <stdlib.h>
using namespace daisysp;
void SyntheticSnareDrum::Init(float sample_rate)
{
sample_rate_ = sample_rate;
phase_[0] = 0.0f;
phase_[1] = 0.0f;
drum_amplitude_ = 0.0f;
snare_amplitude_ = 0.0f;
fm_ = 0.0f;
hold_counter_ = 0;
sustain_gain_ = 0.0f;
SetSustain(false);
SetAccent(.6f);
SetFreq(200.f);
SetFmAmount(.1f);
SetDecay(.3f);
SetSnappy(.7f);
trig_ = false;
drum_lp_.Init(sample_rate_);
snare_hp_.Init(sample_rate_);
snare_lp_.Init(sample_rate_);
}
inline float SyntheticSnareDrum::DistortedSine(float phase)
{
float triangle = (phase < 0.5f ? phase : 1.0f - phase) * 4.0f - 1.3f;
return 2.0f * triangle / (1.0f + fabsf(triangle));
}
bool even = true;
float SyntheticSnareDrum::Process(bool trigger)
{
const float decay_xt = decay_ * (1.0f + decay_ * (decay_ - 1.0f));
const float drum_decay
= 1.0f
- 1.0f / (0.015f * sample_rate_)
* powf(2.f,
kOneTwelfth
* (-decay_xt * 72.0f - fm_amount_ * 12.0f
+ snappy_ * 7.0f));
const float snare_decay
= 1.0f
- 1.0f / (0.01f * sample_rate_)
* powf(2.f, kOneTwelfth * (-decay_ * 60.0f - snappy_ * 7.0f));
const float fm_decay = 1.0f - 1.0f / (0.007f * sample_rate_);
float snappy = snappy_ * 1.1f - 0.05f;
snappy = fclamp(snappy, 0.0f, 1.0f);
const float drum_level = sqrtf(1.0f - snappy);
const float snare_level = sqrtf(snappy);
const float snare_f_min = fmin(10.0f * f0_, 0.5f);
const float snare_f_max = fmin(35.0f * f0_, 0.5f);
snare_hp_.SetFreq(snare_f_min * sample_rate_);
snare_lp_.SetFreq(snare_f_max * sample_rate_);
snare_lp_.SetRes(0.5f + 2.0f * snappy);
drum_lp_.SetFreq(3.0f * f0_ * sample_rate_);
if(trigger || trig_)
{
trig_ = false;
snare_amplitude_ = drum_amplitude_ = 0.3f + 0.7f * accent_;
fm_ = 1.0f;
phase_[0] = phase_[1] = 0.0f;
hold_counter_
= static_cast<int>((0.04f + decay_ * 0.03f) * sample_rate_);
}
even = !even;
if(sustain_)
{
sustain_gain_ = snare_amplitude_ = accent_ * decay_;
drum_amplitude_ = snare_amplitude_;
fm_ = 0.0f;
}
else
{
// Compute all D envelopes.
// The envelope for the drum has a very long tail.
// The envelope for the snare has a "hold" stage which lasts between
// 40 and 70 ms
drum_amplitude_
*= (drum_amplitude_ > 0.03f || even) ? drum_decay : 1.0f;
if(hold_counter_)
{
--hold_counter_;
}
else
{
snare_amplitude_ *= snare_decay;
}
fm_ *= fm_decay;
}
// The 909 circuit has a funny kind of oscillator coupling - the signal
// leaving Q40's collector and resetting all oscillators allow some
// intermodulation.
float reset_noise = 0.0f;
float reset_noise_amount = (0.125f - f0_) * 8.0f;
reset_noise_amount = fclamp(reset_noise_amount, 0.0f, 1.0f);
reset_noise_amount *= reset_noise_amount;
reset_noise_amount *= fm_amount_;
reset_noise += phase_[0] > 0.5f ? -1.0f : 1.0f;
reset_noise += phase_[1] > 0.5f ? -1.0f : 1.0f;
reset_noise *= reset_noise_amount * 0.025f;
float f = f0_ * (1.0f + fm_amount_ * (4.0f * fm_));
phase_[0] += f;
phase_[1] += f * 1.47f;
if(reset_noise_amount > 0.1f)
{
if(phase_[0] >= 1.0f + reset_noise)
{
phase_[0] = 1.0f - phase_[0];
}
if(phase_[1] >= 1.0f + reset_noise)
{
phase_[1] = 1.0f - phase_[1];
}
}
else
{
if(phase_[0] >= 1.0f)
{
phase_[0] -= 1.0f;
}
if(phase_[1] >= 1.0f)
{
phase_[1] -= 1.0f;
}
}
float drum = -0.1f;
drum += DistortedSine(phase_[0]) * 0.60f;
drum += DistortedSine(phase_[1]) * 0.25f;
drum *= drum_amplitude_ * drum_level;
drum_lp_.Process(drum);
drum = drum_lp_.Low();
float noise = rand() * kRandFrac;
snare_lp_.Process(noise);
float snare = snare_lp_.Low();
snare_hp_.Process(snare);
snare = snare_hp_.High();
snare = (snare + 0.1f) * (snare_amplitude_ + fm_) * snare_level;
return snare + drum; // It's a snare, it's a drum, it's a snare drum.
}
void SyntheticSnareDrum::Trig()
{
trig_ = true;
}
void SyntheticSnareDrum::SetSustain(bool sustain)
{
sustain_ = sustain;
}
void SyntheticSnareDrum::SetAccent(float accent)
{
accent_ = fclamp(accent, 0.f, 1.f);
}
void SyntheticSnareDrum::SetFreq(float f0)
{
f0 /= sample_rate_;
f0_ = fclamp(f0, 0.f, 1.f);
}
void SyntheticSnareDrum::SetFmAmount(float fm_amount)
{
fm_amount = fclamp(fm_amount, 0.f, 1.f);
fm_amount_ = fm_amount * fm_amount;
}
void SyntheticSnareDrum::SetDecay(float decay)
{
decay_ = fmax(decay, 0.f);
}
void SyntheticSnareDrum::SetSnappy(float snappy)
{
snappy_ = fclamp(snappy, 0.f, 1.f);
}