mirror of
https://github.com/TomHarte/CLK.git
synced 2026-01-23 01:16:10 +00:00
Add textbook filter construction.
This commit is contained in:
@@ -81,7 +81,7 @@ void SID::write(const Numeric::SizedInt<5> address, const uint8_t value) {
|
||||
}
|
||||
|
||||
void SID::update_filter() {
|
||||
|
||||
// TODO!
|
||||
}
|
||||
|
||||
uint8_t SID::read(const Numeric::SizedInt<5> address) {
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
|
||||
namespace SignalProcessing {
|
||||
|
||||
class BiquadFilter {
|
||||
@@ -17,6 +20,126 @@ public:
|
||||
coefficients_[0] = int16_t(1 << 15);
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
LowPass,
|
||||
HighPass,
|
||||
BandPass,
|
||||
Notch,
|
||||
AllPass,
|
||||
Peaking,
|
||||
LowShelf,
|
||||
HighShelf
|
||||
};
|
||||
BiquadFilter(
|
||||
const Type type,
|
||||
const float sample_rate,
|
||||
const float frequency,
|
||||
const float resonance,
|
||||
const float gain,
|
||||
const bool normalise
|
||||
) {
|
||||
const float w0 = 2.0f * std::numbers::pi_v<float> * frequency / sample_rate;
|
||||
const float alpha = std::sin(w0) / (2.0f * resonance);
|
||||
const float cos_w0 = std::cos(w0);
|
||||
|
||||
float coefficients[5];
|
||||
float magnitude = 1.0f;
|
||||
switch(type) {
|
||||
case Type::LowPass:
|
||||
coefficients[0] = (1.0f - cos_w0) / 2.0f;
|
||||
coefficients[1] = 1.0f + cos_w0;
|
||||
coefficients[2] = (1.0f - cos_w0) / 2.0f;
|
||||
magnitude = 1.0f + alpha;
|
||||
coefficients[3] = -2.0f * cos_w0;
|
||||
coefficients[4] = 1.0f - alpha;
|
||||
break;
|
||||
|
||||
case Type::HighPass:
|
||||
coefficients[0] = (1.0f - cos_w0) / 2.0f;
|
||||
coefficients[1] = -(1.0f + cos_w0);
|
||||
coefficients[2] = (1.0f - cos_w0) / 2.0f;
|
||||
magnitude = 1.0f + alpha;
|
||||
coefficients[3] = -2.0f * cos_w0;
|
||||
coefficients[4] = 1.0f - alpha;
|
||||
break;
|
||||
|
||||
case Type::BandPass:
|
||||
coefficients[0] = alpha;
|
||||
coefficients[1] = 0.0f;
|
||||
coefficients[2] = -alpha;
|
||||
magnitude = 1.0f + alpha;
|
||||
coefficients[3] = -2.0f * cos_w0;
|
||||
coefficients[0] = 1.0f - alpha;
|
||||
break;
|
||||
|
||||
case Type::Notch:
|
||||
coefficients[0] = 1.0f;
|
||||
coefficients[1] = -2.0f * cos_w0;
|
||||
coefficients[2] = 1.0f;
|
||||
magnitude = 1.0f + alpha;
|
||||
coefficients[3] = -2.0f * cos_w0;
|
||||
coefficients[4] = 1.0f - alpha;
|
||||
break;
|
||||
|
||||
case Type::AllPass:
|
||||
coefficients[0] = 1.0f - alpha;
|
||||
coefficients[1] = -2.0f * cos_w0;
|
||||
coefficients[2] = 1.0f + alpha;
|
||||
magnitude = 1.0f + alpha;
|
||||
coefficients[3] = -2.0f * cos_w0;
|
||||
coefficients[4] = 1.0f - alpha;
|
||||
break;
|
||||
|
||||
case Type::Peaking: {
|
||||
const float a = std::pow(10.0f, gain / 40.0f);
|
||||
|
||||
coefficients[0] = 1.0f + (alpha * a);
|
||||
coefficients[1] = -2.0f * cos_w0;
|
||||
coefficients[2] = 1.0f - (alpha * a);
|
||||
magnitude = 1.0f + (alpha / a);
|
||||
coefficients[3] = -2.0f * cos_w0;
|
||||
coefficients[4] = 1.0f - (alpha / a);
|
||||
} break;
|
||||
|
||||
case Type::LowShelf: {
|
||||
const float a_ls = std::pow(10.0f, gain / 40.0f);
|
||||
const float sqrt_a = std::sqrt(a_ls);
|
||||
const float alpha_ls =
|
||||
std::sin(w0) / 2.0f * std::sqrt((a_ls + 1.0f / a_ls) * (1.0f / resonance - 1.0f) + 2.0f);
|
||||
|
||||
coefficients[0] = a_ls * ((a_ls + 1.0f) - (a_ls - 1.0f) * cos_w0 + 2.0f * sqrt_a * alpha_ls);
|
||||
coefficients[1] = 2.0f * a_ls * ((a_ls - 1.0f) - (a_ls + 1.0f) * cos_w0);
|
||||
coefficients[2] = a_ls * ((a_ls + 1.0f) - (a_ls - 1.0f) * cos_w0 - 2.0f * sqrt_a * alpha_ls);
|
||||
magnitude = (a_ls + 1.0f) + (a_ls - 1.0f) * cos_w0 + 2.0f * sqrt_a * alpha_ls;
|
||||
coefficients[3] = -2.0f * ((a_ls - 1) + (a_ls + 1) * cos_w0);
|
||||
coefficients[4] = (a_ls + 1.0f) + (a_ls - 1.0f) * cos_w0 - 2.0f * sqrt_a * alpha_ls;
|
||||
} break;
|
||||
|
||||
case Type::HighShelf: {
|
||||
const float a_hs = std::pow(10.0f, gain / 40.0f);
|
||||
const float sqrt_a_hs = std::sqrt(a_hs);
|
||||
const float alpha_hs =
|
||||
std::sin(w0) / 2.0f * std::sqrt((a_hs + 1.0f / a_hs) * (1.0f / resonance - 1.0f) + 2.0f);
|
||||
|
||||
coefficients[0] = a_hs * ((a_hs + 1.0f) + (a_hs - 1.0f) * cos_w0 + 2.0f * sqrt_a_hs * alpha_hs);
|
||||
coefficients[1] = -2.0f * a_hs * ((a_hs - 1.0f) + (a_hs + 1.0f) * cos_w0);
|
||||
coefficients[2] = a_hs * ((a_hs + 1.0f) + (a_hs - 1.0f) * cos_w0 - 2.0f * sqrt_a_hs * alpha_hs);
|
||||
magnitude = (a_hs + 1.0f) - (a_hs - 1.0f) * cos_w0 + 2.0f * sqrt_a_hs * alpha_hs;
|
||||
coefficients[3] = 2.0f * ((a_hs - 1.0f) - (a_hs + 1.0f) * cos_w0);
|
||||
coefficients[4] = (a_hs + 1.0f) - (a_hs - 1.0f) * cos_w0 - 2.0f * sqrt_a_hs * alpha_hs;
|
||||
} break;
|
||||
}
|
||||
|
||||
if(normalise) {
|
||||
for(int c = 0; c < 5; c++) {
|
||||
coefficients[c] /= magnitude;
|
||||
}
|
||||
}
|
||||
for(int c = 0; c < 5; c++) {
|
||||
coefficients_[c] = int16_t(coefficients[c] * 32767.0f);
|
||||
}
|
||||
}
|
||||
|
||||
int16_t apply(const int16_t input) {
|
||||
const int16_t output = (
|
||||
coefficients_[0] * input +
|
||||
|
||||
Reference in New Issue
Block a user