more advanced build script, refactor eqprocessor.cpps functions: process and recomputeBiquad, which were not nice to read. now nicer to read. no need to compile, compile at more major change
This commit is contained in:
@@ -1,6 +1,45 @@
|
||||
#!/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)
|
||||
./SubWave
|
||||
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
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace engine {
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#include "engine/EqProcessor.h"
|
||||
#include "engine/SpectrumAnalyzer.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
#include <algorithm>
|
||||
#include <QThread>
|
||||
#include <QMediaDevices>
|
||||
|
||||
+48
-34
@@ -1,7 +1,6 @@
|
||||
#include "EqProcessor.h"
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
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 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];
|
||||
const auto& c = m_coeff[band];
|
||||
|
||||
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];
|
||||
for (int idx = 0; idx < count; ++idx) {
|
||||
const int ch = idx % channels;
|
||||
|
||||
float x = samples[i];
|
||||
float y = b0 * x + z1;
|
||||
z1 = b1 * x - a1 * y + z2;
|
||||
z2 = b2 * x - a2 * y;
|
||||
samples[i] = y;
|
||||
auto &s = m_state[band][ch];
|
||||
|
||||
const float x = samples[idx];
|
||||
const float y = c.b0 * x + s.z1;
|
||||
|
||||
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<float>(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<double>(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<float>(b0 * invA0);
|
||||
c.b1 = static_cast<float>(b1 * invA0);
|
||||
c.b2 = static_cast<float>(b2 * invA0);
|
||||
c.a1 = static_cast<float>(a1 * invA0);
|
||||
c.a2 = static_cast<float>(a2 * invA0);
|
||||
}
|
||||
|
||||
} // namespace engine
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
#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
|
||||
Reference in New Issue
Block a user