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.
 
 

183 lines
4.8 KiB

#pragma once
#ifndef DSY_RESONATOR_H
#define DSY_RESONATOR_H
#include <stdint.h>
#include <stddef.h>
#include "Utility/dsp.h"
#ifdef __cplusplus
/** @file resonator.h */
namespace daisysp
{
// We render 4 modes simultaneously since there are enough registers to hold
// all state variables.
/**
@brief SVF for use in the Resonator Class \n
@author Ported by Ben Sergentanis
@date Jan 2021
Ported from pichenettes/eurorack/plaits/dsp/physical_modelling/resonator.h \n
to an independent module. \n
Original code written by Emilie Gillet in 2016. \n
*/
template <int batch_size>
class ResonatorSvf
{
public:
enum FilterMode
{
LOW_PASS,
BAND_PASS,
BAND_PASS_NORMALIZED,
HIGH_PASS
};
ResonatorSvf() {}
~ResonatorSvf() {}
void Init()
{
for(int i = 0; i < batch_size; ++i)
{
state_1_[i] = state_2_[i] = 0.0f;
}
}
template <FilterMode mode, bool add>
void Process(const float* f,
const float* q,
const float* gain,
const float in,
float* out)
{
float g[batch_size];
float r[batch_size];
float r_plus_g[batch_size];
float h[batch_size];
float state_1[batch_size];
float state_2[batch_size];
float gains[batch_size];
for(int i = 0; i < batch_size; ++i)
{
g[i] = fasttan(f[i]);
r[i] = 1.0f / q[i];
h[i] = 1.0f / (1.0f + r[i] * g[i] + g[i] * g[i]);
r_plus_g[i] = r[i] + g[i];
state_1[i] = state_1_[i];
state_2[i] = state_2_[i];
gains[i] = gain[i];
}
float s_in = in;
float s_out = 0.0f;
for(int i = 0; i < batch_size; ++i)
{
const float hp
= (s_in - r_plus_g[i] * state_1[i] - state_2[i]) * h[i];
const float bp = g[i] * hp + state_1[i];
state_1[i] = g[i] * hp + bp;
const float lp = g[i] * bp + state_2[i];
state_2[i] = g[i] * bp + lp;
s_out += gains[i] * ((mode == LOW_PASS) ? lp : bp);
}
if(add)
{
*out++ += s_out;
}
else
{
*out++ = s_out;
}
for(int i = 0; i < batch_size; ++i)
{
state_1_[i] = state_1[i];
state_2_[i] = state_2[i];
}
}
private:
static constexpr float kPiPow3 = PI_F * PI_F * PI_F;
static constexpr float kPiPow5 = kPiPow3 * PI_F * PI_F;
static inline float fasttan(float f)
{
const float a = 3.260e-01 * kPiPow3;
const float b = 1.823e-01 * kPiPow5;
float f2 = f * f;
return f * (PI_F + f2 * (a + b * f2));
}
float state_1_[batch_size];
float state_2_[batch_size];
};
/**
@brief Resonant Body Simulation
@author Ported by Ben Sergentanis
@date Jan 2021
Ported from pichenettes/eurorack/plaits/dsp/physical_modelling/resonator.h \n
to an independent module. \n
Original code written by Emilie Gillet in 2016. \n
*/
class Resonator
{
public:
Resonator() {}
~Resonator() {}
/** Initialize the module
\param position Offset the phase of the amplitudes. 0-1
\param resolution Quality vs speed scalar
\param sample_rate Samplerate of the audio engine being run.
*/
void Init(float position, int resolution, float sample_rate);
/** Get the next sample_rate
\param in The signal to excited the resonant body
*/
float Process(const float in);
/** Resonator frequency.
\param freq Frequency in Hz.
*/
void SetFreq(float freq);
/** Changes the general charater of the resonator (stiffness, brightness)
\param structure Works best from 0-1
*/
void SetStructure(float structure);
/** Set the brighness of the resonator
\param brightness Works best 0-1
*/
void SetBrightness(float brightness);
/** How long the resonant body takes to decay.
\param damping Works best 0-1
*/
void SetDamping(float damping);
private:
int resolution_;
float frequency_, brightness_, structure_, damping_;
static constexpr int kMaxNumModes = 24;
static constexpr int kModeBatchSize = 4;
static constexpr float ratiofrac_ = 1.f / 12.f;
static constexpr float stiff_frac_ = 1.f / 64.f;
static constexpr float stiff_frac_2 = 1.f / .6f;
float sample_rate_;
float CalcStiff(float sig);
float mode_amplitude_[kMaxNumModes];
ResonatorSvf<kModeBatchSize> mode_filters_[kMaxNumModes / kModeBatchSize];
};
} // namespace daisysp
#endif
#endif