diff --git a/build.sh b/build.sh index b83a0a3..6310843 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,45 @@ -rm -rf build -mkdir build -cd build -cmake .. -make -j$(nproc) -./SubWave \ No newline at end of file +#!/usr/bin/env bash +set -e + +clean() { + echo "cleaning build dir" + rm -rf build +} + +incremental_build() { + mkdir -p ../build + cd build + cmake .. + make -j"$(nproc)" +} + +clean_build() { + clean + mkdir build + cd build + cmake .. + make -j"$(nproc)" +} + +run_executable() { + ./build/SubWave +} + +case "${1:-build}" in + clean|c) + clean + ;; + build|incremental|ib) + incremental_build + ;; + cleanbuild|cb) + clean_build + ;; + run|exec|r) + run_executable + ;; + *) + echo "Usage: $0 {build|clean|cleanbuild|cb}" + exit 1 + ;; +esac \ No newline at end of file diff --git a/src/engine/AudioBuffer.h b/src/engine/AudioBuffer.h index cad5ce8..a0c41cf 100644 --- a/src/engine/AudioBuffer.h +++ b/src/engine/AudioBuffer.h @@ -1,6 +1,5 @@ #pragma once #include -#include namespace engine { diff --git a/src/engine/AudioEngine.cpp b/src/engine/AudioEngine.cpp index 0be69a7..2aa2914 100644 --- a/src/engine/AudioEngine.cpp +++ b/src/engine/AudioEngine.cpp @@ -3,8 +3,6 @@ #include "engine/EqProcessor.h" #include "engine/SpectrumAnalyzer.h" -#include -#include #include #include #include diff --git a/src/engine/EqProcessor.cpp b/src/engine/EqProcessor.cpp index f1b0417..54d7fab 100644 --- a/src/engine/EqProcessor.cpp +++ b/src/engine/EqProcessor.cpp @@ -1,7 +1,6 @@ #include "EqProcessor.h" #include #include -#include #include namespace engine { @@ -33,51 +32,66 @@ void EqProcessor::reset() { std::memset(m_state, 0, sizeof(m_state)); } -void EqProcessor::process(AudioBuffer &buf) { - const int channels = buf.channels; - const int count = buf.sampleCount(); - float *samples = buf.samples.data(); + +void EqProcessor::process(AudioBuffer &a_buf) { + const int channels = a_buf.channels; + const int count = a_buf.sampleCount(); + float *samples = a_buf.samples.data(); for (int band = 0; band < BANDS; ++band) { - if (std::abs(m_gainDb[band]) < 0.01f) continue; + if (std::abs(m_gainDb[band]) < 0.01f) {continue;} + + const auto& c = m_coeff[band]; - const float b0 = m_coeff[band][0], b1 = m_coeff[band][1], b2 = m_coeff[band][2]; - const float a1 = m_coeff[band][3], a2 = m_coeff[band][4]; + for (int idx = 0; idx < count; ++idx) { + const int ch = idx % channels; + + auto &s = m_state[band][ch]; - for (int i = 0; i < count; ++i) { - const int ch = i % channels; - float &z1 = m_state[band][ch][0]; - float &z2 = m_state[band][ch][1]; + const float x = samples[idx]; + const float y = c.b0 * x + s.z1; - float x = samples[i]; - float y = b0 * x + z1; - z1 = b1 * x - a1 * y + z2; - z2 = b2 * x - a2 * y; - samples[i] = y; + s.z1 = c.b1 * x - c.a1 * y + s.z2; + s.z2 = c.b2 * x - c.a2 * y; + + samples[idx] = y; } + } } void EqProcessor::recomputeBiquad(int band) { - const float sr = static_cast(m_sampleRate); - const float f0 = FREQS[band]; - const float dBg = m_gainDb[band]; - const float Q = 1.41421356f; // sqrt(2) , Butterworth Q - const float A = std::pow(10.f, dBg / 40.f); - const double w0 = 2.0 * std::numbers::pi * f0 / sr; - const double cW = std::cos(w0); - const double sW = std::sin(w0); - const double alp = sW / (2.0 * Q); + const double sampleRate = static_cast(m_sampleRate); + const double frequency = FREQS[band]; + const double gainDb = m_gainDb[band]; + constexpr double Q = std::numbers::sqrt2; - // Peaking EQ biquad - const double b0 = 1 + alp * A, b1 = -2 * cW, b2 = 1 - alp * A; - const double a0 = 1 + alp / A, a1 = -2 * cW, a2 = 1 - alp / A; + // RBJ peaking EQ gain factor + const double A = std::pow(10.0, gainDb / 40.0); + const double omega = 2.0 * std::numbers::pi * frequency / sampleRate; + const double sinW = std::sin(omega); + const double cosW = std::cos(omega); - m_coeff[band][0] = float(b0 / a0); - m_coeff[band][1] = float(b1 / a0); - m_coeff[band][2] = float(b2 / a0); - m_coeff[band][3] = float(a1 / a0); - m_coeff[band][4] = float(a2 / a0); + const double alpha = sinW / (2.0 * Q); + + // rbj audio eq cookbook + const double b0 = 1.0 + alpha * A; + const double b1 = -2.0 * cosW; + const double b2 = 1.0 - alpha * A; + + const double a0 = 1.0 + alpha / A; + const double a1 = -2.0 * cosW; + const double a2 = 1.0 - alpha / A; + + const double invA0 = 1.0 / a0; + + auto &c = m_coeff[band]; + + c.b0 = static_cast(b0 * invA0); + c.b1 = static_cast(b1 * invA0); + c.b2 = static_cast(b2 * invA0); + c.a1 = static_cast(a1 * invA0); + c.a2 = static_cast(a2 * invA0); } } // namespace engine diff --git a/src/engine/EqProcessor.h b/src/engine/EqProcessor.h index df150cc..dcea34b 100644 --- a/src/engine/EqProcessor.h +++ b/src/engine/EqProcessor.h @@ -1,5 +1,4 @@ #pragma once -#include #include "AudioBuffer.h" namespace engine { @@ -28,10 +27,23 @@ private: int m_sampleRate { 44100 }; float m_gainDb[BANDS] {}; - float m_coeff[BANDS][5] {}; + struct BiquadCoefficients { + float b0 {}; + float b1 {}; + float b2 {}; + float a1 {}; + float a2 {}; + }; + + BiquadCoefficients m_coeff[BANDS]; + + struct BiquadState { + float z1; + float z2; + }; static constexpr int MAX_CH = 8; - float m_state[BANDS][MAX_CH][2] {}; + BiquadState m_state[BANDS][MAX_CH] {}; }; } // namespace engine \ No newline at end of file