new cspot/bell

This commit is contained in:
philippe44
2023-05-06 23:50:26 +02:00
parent e0e7e718ba
commit 8bad480112
163 changed files with 6611 additions and 6739 deletions

View File

@@ -1,39 +1,44 @@
#include "AudioMixer.h"
#include <mutex> // for scoped_lock
using namespace bell;
AudioMixer::AudioMixer() {
}
AudioMixer::AudioMixer() {}
std::unique_ptr<StreamInfo> AudioMixer::process(std::unique_ptr<StreamInfo> info) {
std::scoped_lock lock(this->accessMutex);
if (info->numChannels != from) {
throw std::runtime_error("AudioMixer: Input channel count does not match configuration");
}
info->numChannels = to;
std::unique_ptr<StreamInfo> AudioMixer::process(
std::unique_ptr<StreamInfo> info) {
std::scoped_lock lock(this->accessMutex);
if (info->numChannels != from) {
throw std::runtime_error(
"AudioMixer: Input channel count does not match configuration");
}
info->numChannels = to;
for (auto &singleConf : mixerConfig) {
if (singleConf.source.size() == 1) {
if (singleConf.source[0] == singleConf.destination) {
continue;
}
// Copy channel
for (int i = 0; i < info->numSamples; i++) {
info->data[singleConf.destination][i] = info->data[singleConf.source[0]][i];
}
} else {
// Mix channels
float sample = 0.0f;
for (int i = 0; i < info->numSamples; i++) {
sample = 0.0;
for (auto &source : singleConf.source) {
sample += info->data[source][i];
}
info->data[singleConf.destination][i] = sample / (float) singleConf.source.size();
}
for (auto& singleConf : mixerConfig) {
if (singleConf.source.size() == 1) {
if (singleConf.source[0] == singleConf.destination) {
continue;
}
// Copy channel
for (int i = 0; i < info->numSamples; i++) {
info->data[singleConf.destination][i] =
info->data[singleConf.source[0]][i];
}
} else {
// Mix channels
float sample = 0.0f;
for (int i = 0; i < info->numSamples; i++) {
sample = 0.0;
for (auto& source : singleConf.source) {
sample += info->data[source][i];
}
}
return info;
info->data[singleConf.destination][i] =
sample / (float)singleConf.source.size();
}
}
}
return info;
}

View File

@@ -1,47 +1,53 @@
#include "AudioPipeline.h"
#include <iostream>
#include "BellLogger.h"
#include <type_traits> // for remove_extent_t
#include <utility> // for move
#include "AudioTransform.h" // for AudioTransform
#include "BellLogger.h" // for AbstractLogger, BELL_LOG
#include "TransformConfig.h" // for TransformConfig
using namespace bell;
AudioPipeline::AudioPipeline() {
AudioPipeline::AudioPipeline(){
// this->headroomGainTransform = std::make_shared<Gain>(Channels::LEFT_RIGHT);
// this->transforms.push_back(this->headroomGainTransform);
};
void AudioPipeline::addTransform(std::shared_ptr<AudioTransform> transform) {
transforms.push_back(transform);
recalculateHeadroom();
transforms.push_back(transform);
recalculateHeadroom();
}
void AudioPipeline::recalculateHeadroom() {
float headroom = 0.0f;
float headroom = 0.0f;
// Find largest headroom required by any transform down the chain, and apply it
for (auto transform : transforms) {
if (headroom < transform->calculateHeadroom()) {
headroom = transform->calculateHeadroom();
}
// Find largest headroom required by any transform down the chain, and apply it
for (auto transform : transforms) {
if (headroom < transform->calculateHeadroom()) {
headroom = transform->calculateHeadroom();
}
}
// headroomGainTransform->configure(-headroom);
// headroomGainTransform->configure(-headroom);
}
void AudioPipeline::volumeUpdated(int volume) {
BELL_LOG(debug, "AudioPipeline", "Requested");
std::scoped_lock lock(this->accessMutex);
for (auto transform : transforms) {
transform->config->currentVolume = volume;
transform->reconfigure();
}
BELL_LOG(debug, "AudioPipeline", "Volume applied, DSP reconfigured");
BELL_LOG(debug, "AudioPipeline", "Requested");
std::scoped_lock lock(this->accessMutex);
for (auto transform : transforms) {
transform->config->currentVolume = volume;
transform->reconfigure();
}
BELL_LOG(debug, "AudioPipeline", "Volume applied, DSP reconfigured");
}
std::unique_ptr<StreamInfo> AudioPipeline::process(std::unique_ptr<StreamInfo> data) {
std::scoped_lock lock(this->accessMutex);
for (auto &transform : transforms) {
data = transform->process(std::move(data));
}
std::unique_ptr<StreamInfo> AudioPipeline::process(
std::unique_ptr<StreamInfo> data) {
std::scoped_lock lock(this->accessMutex);
for (auto& transform : transforms) {
data = transform->process(std::move(data));
}
return data;
return data;
}

View File

@@ -1,6 +1,10 @@
#include "BellDSP.h"
#include <iostream>
#include "CentralAudioBuffer.h"
#include <type_traits> // for remove_extent_t
#include <utility> // for move
#include "AudioPipeline.h" // for CentralAudioBuffer
#include "CentralAudioBuffer.h" // for CentralAudioBuffer
using namespace bell;

View File

@@ -1,466 +1,439 @@
#include "Biquad.h"
#include <cmath> // for pow, cosf, sinf, M_PI, sqrtf, tanf, logf, sinh
using namespace bell;
Biquad::Biquad()
{
this->filterType = "biquad";
Biquad::Biquad() {
this->filterType = "biquad";
}
void Biquad::sampleRateChanged(uint32_t sampleRate)
{
this->sampleRate = sampleRate;
//this->configure(this->type, this->currentConfig);
void Biquad::sampleRateChanged(uint32_t sampleRate) {
this->sampleRate = sampleRate;
//this->configure(this->type, this->currentConfig);
}
void Biquad::configure(Type type, std::map<std::string, float> &newConf)
{
this->type = type;
this->currentConfig = newConf;
void Biquad::configure(Type type, std::map<std::string, float>& newConf) {
this->type = type;
this->currentConfig = newConf;
switch (type)
{
switch (type) {
case Type::Free:
coeffs[0] = newConf["a1"];
coeffs[1] = newConf["a2"];
coeffs[2] = newConf["b0"];
coeffs[3] = newConf["b1"];
coeffs[4] = newConf["b2"];
break;
coeffs[0] = newConf["a1"];
coeffs[1] = newConf["a2"];
coeffs[2] = newConf["b0"];
coeffs[3] = newConf["b1"];
coeffs[4] = newConf["b2"];
break;
case Type::Highpass:
highPassCoEffs(newConf["freq"], newConf["q"]);
break;
highPassCoEffs(newConf["freq"], newConf["q"]);
break;
case Type::HighpassFO:
highPassFOCoEffs(newConf["freq"]);
break;
highPassFOCoEffs(newConf["freq"]);
break;
case Type::Lowpass:
lowPassCoEffs(newConf["freq"], newConf["q"]);
break;
lowPassCoEffs(newConf["freq"], newConf["q"]);
break;
case Type::LowpassFO:
lowPassFOCoEffs(newConf["freq"]);
break;
lowPassFOCoEffs(newConf["freq"]);
break;
case Type::Highshelf:
// check if config has slope key
if (newConf.find("slope") != newConf.end())
{
highShelfCoEffsSlope(newConf["freq"], newConf["gain"], newConf["slope"]);
}
else
{
highShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
}
break;
// check if config has slope key
if (newConf.find("slope") != newConf.end()) {
highShelfCoEffsSlope(newConf["freq"], newConf["gain"],
newConf["slope"]);
} else {
highShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
}
break;
case Type::HighshelfFO:
highShelfFOCoEffs(newConf["freq"], newConf["gain"]);
break;
highShelfFOCoEffs(newConf["freq"], newConf["gain"]);
break;
case Type::Lowshelf:
// check if config has slope key
if (newConf.find("slope") != newConf.end())
{
lowShelfCoEffsSlope(newConf["freq"], newConf["gain"], newConf["slope"]);
}
else
{
lowShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
}
break;
// check if config has slope key
if (newConf.find("slope") != newConf.end()) {
lowShelfCoEffsSlope(newConf["freq"], newConf["gain"], newConf["slope"]);
} else {
lowShelfCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
}
break;
case Type::LowshelfFO:
lowShelfFOCoEffs(newConf["freq"], newConf["gain"]);
break;
lowShelfFOCoEffs(newConf["freq"], newConf["gain"]);
break;
case Type::Peaking:
// check if config has bandwidth key
if (newConf.find("bandwidth") != newConf.end())
{
peakCoEffsBandwidth(newConf["freq"], newConf["gain"], newConf["bandwidth"]);
}
else
{
peakCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
}
break;
// check if config has bandwidth key
if (newConf.find("bandwidth") != newConf.end()) {
peakCoEffsBandwidth(newConf["freq"], newConf["gain"],
newConf["bandwidth"]);
} else {
peakCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
}
break;
case Type::Notch:
if (newConf.find("bandwidth") != newConf.end())
{
notchCoEffsBandwidth(newConf["freq"], newConf["gain"], newConf["bandwidth"]);
}
else
{
notchCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
}
break;
if (newConf.find("bandwidth") != newConf.end()) {
notchCoEffsBandwidth(newConf["freq"], newConf["gain"],
newConf["bandwidth"]);
} else {
notchCoEffs(newConf["freq"], newConf["gain"], newConf["q"]);
}
break;
case Type::Bandpass:
if (newConf.find("bandwidth") != newConf.end())
{
bandPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]);
}
else
{
bandPassCoEffs(newConf["freq"], newConf["q"]);
}
break;
if (newConf.find("bandwidth") != newConf.end()) {
bandPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]);
} else {
bandPassCoEffs(newConf["freq"], newConf["q"]);
}
break;
case Type::Allpass:
if (newConf.find("bandwidth") != newConf.end())
{
allPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]);
}
else
{
allPassCoEffs(newConf["freq"], newConf["q"]);
}
break;
if (newConf.find("bandwidth") != newConf.end()) {
allPassCoEffsBandwidth(newConf["freq"], newConf["bandwidth"]);
} else {
allPassCoEffs(newConf["freq"], newConf["q"]);
}
break;
case Type::AllpassFO:
allPassFOCoEffs(newConf["freq"]);
break;
}
allPassFOCoEffs(newConf["freq"]);
break;
}
}
// coefficients for a high pass biquad filter
void Biquad::highPassCoEffs(float f, float q)
{
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2 * q);
void Biquad::highPassCoEffs(float f, float q) {
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2 * q);
float b0 = (1 + c) / 2;
float b1 = -(1 + c);
float b2 = b0;
float a0 = 1 + alpha;
float a1 = -2 * c;
float a2 = 1 - alpha;
float b0 = (1 + c) / 2;
float b1 = -(1 + c);
float b2 = b0;
float a0 = 1 + alpha;
float a1 = -2 * c;
float a2 = 1 - alpha;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
// coefficients for a high pass first order biquad filter
void Biquad::highPassFOCoEffs(float f)
{
float w0 = 2 * M_PI * f / this->sampleRate;
float k = tanf(w0 / 2.0);
void Biquad::highPassFOCoEffs(float f) {
float w0 = 2 * M_PI * f / this->sampleRate;
float k = tanf(w0 / 2.0);
float alpha = 1.0 + k;
float alpha = 1.0 + k;
float b0 = 1.0 / alpha;
float b1 = -1.0 / alpha;
float b2 = 0.0;
float a0 = 1.0;
float a1 = -(1.0 - k) / alpha;
float a2 = 0.0;
float b0 = 1.0 / alpha;
float b1 = -1.0 / alpha;
float b2 = 0.0;
float a0 = 1.0;
float a1 = -(1.0 - k) / alpha;
float a2 = 0.0;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
// coefficients for a low pass biquad filter
void Biquad::lowPassCoEffs(float f, float q)
{
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2 * q);
void Biquad::lowPassCoEffs(float f, float q) {
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2 * q);
float b0 = (1 - c) / 2;
float b1 = 1 - c;
float b2 = b0;
float a0 = 1 + alpha;
float a1 = -2 * c;
float a2 = 1 - alpha;
float b0 = (1 - c) / 2;
float b1 = 1 - c;
float b2 = b0;
float a0 = 1 + alpha;
float a1 = -2 * c;
float a2 = 1 - alpha;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
// coefficients for a low pass first order biquad filter
void Biquad::lowPassFOCoEffs(float f)
{
float w0 = 2 * M_PI * f / this->sampleRate;
float k = tanf(w0 / 2.0);
void Biquad::lowPassFOCoEffs(float f) {
float w0 = 2 * M_PI * f / this->sampleRate;
float k = tanf(w0 / 2.0);
float alpha = 1.0 + k;
float alpha = 1.0 + k;
float b0 = k / alpha;
float b1 = k / alpha;
float b2 = 0.0;
float a0 = 1.0;
float a1 = -(1.0 - k) / alpha;
float a2 = 0.0;
float b0 = k / alpha;
float b1 = k / alpha;
float b2 = 0.0;
float a0 = 1.0;
float a1 = -(1.0 - k) / alpha;
float a2 = 0.0;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
// coefficients for a peak biquad filter
void Biquad::peakCoEffs(float f, float gain, float q)
{
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2 * q);
void Biquad::peakCoEffs(float f, float gain, float q) {
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2 * q);
float ampl = std::pow(10.0f, gain / 40.0f);
float b0 = 1.0 + (alpha * ampl);
float b1 = -2.0 * c;
float b2 = 1.0 - (alpha * ampl);
float a0 = 1 + (alpha / ampl);
float a1 = -2 * c;
float a2 = 1 - (alpha / ampl);
float ampl = std::pow(10.0f, gain / 40.0f);
float b0 = 1.0 + (alpha * ampl);
float b1 = -2.0 * c;
float b2 = 1.0 - (alpha * ampl);
float a0 = 1 + (alpha / ampl);
float a1 = -2 * c;
float a2 = 1 - (alpha / ampl);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::peakCoEffsBandwidth(float f, float gain, float bandwidth)
{
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
void Biquad::peakCoEffsBandwidth(float f, float gain, float bandwidth) {
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
float ampl = std::pow(10.0f, gain / 40.0f);
float b0 = 1.0 + (alpha * ampl);
float b1 = -2.0 * c;
float b2 = 1.0 - (alpha * ampl);
float a0 = 1 + (alpha / ampl);
float a1 = -2 * c;
float a2 = 1 - (alpha / ampl);
float ampl = std::pow(10.0f, gain / 40.0f);
float b0 = 1.0 + (alpha * ampl);
float b1 = -2.0 * c;
float b2 = 1.0 - (alpha * ampl);
float a0 = 1 + (alpha / ampl);
float a1 = -2 * c;
float a2 = 1 - (alpha / ampl);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::highShelfCoEffs(float f, float gain, float q)
{
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2 * q);
float beta = s * sqrtf(A) / q;
float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta);
float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c);
float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta);
float a0 = (A + 1.0) - (A - 1.0) * c + beta;
float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c);
float a2 = (A + 1.0) - (A - 1.0) * c - beta;
void Biquad::highShelfCoEffs(float f, float gain, float q) {
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2 * q);
float beta = s * sqrtf(A) / q;
float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta);
float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c);
float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta);
float a0 = (A + 1.0) - (A - 1.0) * c + beta;
float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c);
float a2 = (A + 1.0) - (A - 1.0) * c - beta;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::highShelfCoEffsSlope(float f, float gain, float slope)
{
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha =
s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0);
float beta = 2.0 * sqrtf(A) * alpha;
float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta);
float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c);
float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta);
float a0 = (A + 1.0) - (A - 1.0) * c + beta;
float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c);
float a2 = (A + 1.0) - (A - 1.0) * c - beta;
void Biquad::highShelfCoEffsSlope(float f, float gain, float slope) {
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha =
s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0);
float beta = 2.0 * sqrtf(A) * alpha;
float b0 = A * ((A + 1.0) + (A - 1.0) * c + beta);
float b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * c);
float b2 = A * ((A + 1.0) + (A - 1.0) * c - beta);
float a0 = (A + 1.0) - (A - 1.0) * c + beta;
float a1 = 2.0 * ((A - 1.0) - (A + 1.0) * c);
float a2 = (A + 1.0) - (A - 1.0) * c - beta;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::highShelfFOCoEffs(float f, float gain)
{
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float tn = tanf(w0 / 2.0);
void Biquad::highShelfFOCoEffs(float f, float gain) {
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float tn = tanf(w0 / 2.0);
float b0 = A * tn + std::pow(A, 2);
float b1 = A * tn - std::pow(A, 2);
float b2 = 0.0;
float a0 = A * tn + 1.0;
float a1 = A * tn - 1.0;
float a2 = 0.0;
float b0 = A * tn + std::pow(A, 2);
float b1 = A * tn - std::pow(A, 2);
float b2 = 0.0;
float a0 = A * tn + 1.0;
float a1 = A * tn - 1.0;
float a2 = 0.0;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::lowShelfCoEffs(float f, float gain, float q) {
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float beta = s * sqrtf(A) / q;
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float beta = s * sqrtf(A) / q;
float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta);
float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c);
float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta);
float a0 = (A + 1.0) + (A - 1.0) * c + beta;
float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c);
float a2 = (A + 1.0) + (A - 1.0) * c - beta;
float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta);
float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c);
float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta);
float a0 = (A + 1.0) + (A - 1.0) * c + beta;
float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c);
float a2 = (A + 1.0) + (A - 1.0) * c - beta;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::lowShelfCoEffsSlope(float f, float gain, float slope) {
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha =
s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0);
float beta = 2.0 * sqrtf(A) * alpha;
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha =
s / 2.0 * sqrtf((A + 1.0 / A) * (1.0 / (slope / 12.0) - 1.0) + 2.0);
float beta = 2.0 * sqrtf(A) * alpha;
float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta);
float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c);
float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta);
float a0 = (A + 1.0) + (A - 1.0) * c + beta;
float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c);
float a2 = (A + 1.0) + (A - 1.0) * c - beta;
float b0 = A * ((A + 1.0) - (A - 1.0) * c + beta);
float b1 = 2.0 * A * ((A - 1.0) - (A + 1.0) * c);
float b2 = A * ((A + 1.0) - (A - 1.0) * c - beta);
float a0 = (A + 1.0) + (A - 1.0) * c + beta;
float a1 = -2.0 * ((A - 1.0) + (A + 1.0) * c);
float a2 = (A + 1.0) + (A - 1.0) * c - beta;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::lowShelfFOCoEffs(float f, float gain) {
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float tn = tanf(w0 / 2.0);
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float tn = tanf(w0 / 2.0);
float b0 = std::pow(A, 2) * tn + A;
float b1 = std::pow(A, 2) * tn - A;
float b2 = 0.0;
float a0 = tn + A;
float a1 = tn - A;
float a2 = 0.0;
float b0 = std::pow(A, 2) * tn + A;
float b1 = std::pow(A, 2) * tn - A;
float b2 = 0.0;
float a0 = tn + A;
float a1 = tn - A;
float a2 = 0.0;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::notchCoEffs(float f, float gain, float q) {
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2.0 * q);
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2.0 * q);
float b0 = 1.0;
float b1 = -2.0 * c;
float b2 = 1.0;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
float b0 = 1.0;
float b1 = -2.0 * c;
float b2 = 1.0;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::notchCoEffsBandwidth(float f, float gain, float bandwidth) {
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
float A = std::pow(10.0f, gain / 40.0f);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
float b0 = 1.0;
float b1 = -2.0 * c;
float b2 = 1.0;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
float b0 = 1.0;
float b1 = -2.0 * c;
float b2 = 1.0;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::bandPassCoEffs(float f, float q) {
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2.0 * q);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2.0 * q);
float b0 = alpha;
float b1 = 0.0;
float b2 = -alpha;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
float b0 = alpha;
float b1 = 0.0;
float b2 = -alpha;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::bandPassCoEffsBandwidth(float f, float bandwidth) {
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
float b0 = alpha;
float b1 = 0.0;
float b2 = -alpha;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
float b0 = alpha;
float b1 = 0.0;
float b2 = -alpha;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::allPassCoEffs(float f, float q) {
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2.0 * q);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s / (2.0 * q);
float b0 = 1.0 - alpha;
float b1 = -2.0 * c;
float b2 = 1.0 + alpha;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
float b0 = 1.0 - alpha;
float b1 = -2.0 * c;
float b2 = 1.0 + alpha;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::allPassCoEffsBandwidth(float f, float bandwidth) {
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
float w0 = 2 * M_PI * f / this->sampleRate;
float c = cosf(w0);
float s = sinf(w0);
float alpha = s * sinh(logf(2.0) / 2.0 * bandwidth * w0 / s);
float b0 = 1.0 - alpha;
float b1 = -2.0 * c;
float b2 = 1.0 + alpha;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
float b0 = 1.0 - alpha;
float b1 = -2.0 * c;
float b2 = 1.0 + alpha;
float a0 = 1.0 + alpha;
float a1 = -2.0 * c;
float a2 = 1.0 - alpha;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::allPassFOCoEffs(float f) {
float w0 = 2 * M_PI * f / this->sampleRate;
float tn = tanf(w0 / 2.0);
float w0 = 2 * M_PI * f / this->sampleRate;
float tn = tanf(w0 / 2.0);
float alpha = (tn + 1.0) / (tn - 1.0);
float alpha = (tn + 1.0) / (tn - 1.0);
float b0 = 1.0;
float b1 = alpha;
float b2 = 0.0;
float a0 = alpha;
float a1 = 1.0;
float a2 = 0.0;
float b0 = 1.0;
float b1 = alpha;
float b2 = 0.0;
float a0 = alpha;
float a1 = 1.0;
float a2 = 0.0;
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
this->normalizeCoEffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::normalizeCoEffs(float a0, float a1, float a2, float b0, float b1, float b2)
{
coeffs[0] = b0 / a0;
coeffs[1] = b1 / a0;
coeffs[2] = b2 / a0;
coeffs[3] = a1 / a0;
coeffs[4] = a2 / a0;
void Biquad::normalizeCoEffs(float a0, float a1, float a2, float b0, float b1,
float b2) {
coeffs[0] = b0 / a0;
coeffs[1] = b1 / a0;
coeffs[2] = b2 / a0;
coeffs[3] = a1 / a0;
coeffs[4] = a2 / a0;
}
std::unique_ptr<StreamInfo> Biquad::process(std::unique_ptr<StreamInfo> stream)
{
std::scoped_lock lock(accessMutex);
std::unique_ptr<StreamInfo> Biquad::process(
std::unique_ptr<StreamInfo> stream) {
std::scoped_lock lock(accessMutex);
auto input = stream->data[this->channel];
auto numSamples = stream->numSamples;
auto input = stream->data[this->channel];
auto numSamples = stream->numSamples;
#ifdef ESP_PLATFORM
dsps_biquad_f32_ae32(input, input, numSamples, coeffs, w);
dsps_biquad_f32_ae32(input, input, numSamples, coeffs, w);
#else
// Apply the set coefficients
for (int i = 0; i < numSamples; i++)
{
float d0 = input[i] - coeffs[3] * w[0] - coeffs[4] * w[1];
input[i] = coeffs[0] * d0 + coeffs[1] * w[0] + coeffs[2] * w[1];
w[1] = w[0];
w[0] = d0;
}
// Apply the set coefficients
for (int i = 0; i < numSamples; i++) {
float d0 = input[i] - coeffs[3] * w[0] - coeffs[4] * w[1];
input[i] = coeffs[0] * d0 + coeffs[1] * w[0] + coeffs[2] * w[1];
w[1] = w[0];
w[0] = d0;
}
#endif
return stream;
return stream;
};

View File

@@ -1,109 +1,89 @@
#include "BiquadCombo.h"
#include <stdio.h> // for printf
#include <cmath> // for sinf, M_PI
#include <utility> // for move
using namespace bell;
BiquadCombo::BiquadCombo()
{
BiquadCombo::BiquadCombo() {}
void BiquadCombo::sampleRateChanged(uint32_t sampleRate) {
for (auto& biquad : biquads) {
biquad->sampleRateChanged(sampleRate);
}
}
void BiquadCombo::sampleRateChanged(uint32_t sampleRate)
{
for (auto &biquad : biquads)
{
biquad->sampleRateChanged(sampleRate);
}
std::vector<float> BiquadCombo::calculateBWQ(int order) {
std::vector<float> qValues;
for (int n = 0; n < order / 2; n++) {
float q = 1.0f / (2.0f * sinf(M_PI / order * (((float)n) + 0.5)));
qValues.push_back(q);
}
if (order % 2 > 0) {
qValues.push_back(-1.0);
}
printf("%d\n", qValues.size());
return qValues;
}
std::vector<float> BiquadCombo::calculateBWQ(int order)
{
std::vector<float> BiquadCombo::calculateLRQ(int order) {
auto qValues = calculateBWQ(order / 2);
std::vector<float> qValues;
for (int n = 0; n < order / 2; n++)
{
float q = 1.0f / (2.0f * sinf(M_PI / order * (((float)n) + 0.5)));
qValues.push_back(q);
}
if (order % 4 > 0) {
qValues.pop_back();
qValues.insert(qValues.end(), qValues.begin(), qValues.end());
qValues.push_back(0.5);
} else {
qValues.insert(qValues.end(), qValues.begin(), qValues.end());
}
if (order % 2 > 0)
{
qValues.push_back(-1.0);
}
printf("%d\n", qValues.size());
return qValues;
return qValues;
}
std::vector<float> BiquadCombo::calculateLRQ(int order)
{
auto qValues = calculateBWQ(order / 2);
if (order % 4 > 0)
{
qValues.pop_back();
qValues.insert(qValues.end(), qValues.begin(), qValues.end());
qValues.push_back(0.5);
}
else
{
qValues.insert(qValues.end(), qValues.begin(), qValues.end());
}
return qValues;
void BiquadCombo::butterworth(float freq, int order, FilterType type) {
std::vector<float> qValues = calculateBWQ(order);
for (auto& q : qValues) {}
}
void BiquadCombo::butterworth(float freq, int order, FilterType type)
{
std::vector<float> qValues = calculateBWQ(order);
for (auto &q : qValues)
{
void BiquadCombo::linkwitzRiley(float freq, int order, FilterType type) {
std::vector<float> qValues = calculateLRQ(order);
for (auto& q : qValues) {
auto filter = std::make_unique<Biquad>();
filter->channel = channel;
auto config = std::map<std::string, float>();
config["freq"] = freq;
config["q"] = q;
if (q >= 0.0) {
if (type == FilterType::Highpass) {
filter->configure(Biquad::Type::Highpass, config);
} else {
filter->configure(Biquad::Type::Lowpass, config);
}
} else {
if (type == FilterType::Highpass) {
filter->configure(Biquad::Type::HighpassFO, config);
} else {
filter->configure(Biquad::Type::LowpassFO, config);
}
}
this->biquads.push_back(std::move(filter));
}
}
void BiquadCombo::linkwitzRiley(float freq, int order, FilterType type)
{
std::vector<float> qValues = calculateLRQ(order);
for (auto &q : qValues)
{
auto filter = std::make_unique<Biquad>();
filter->channel = channel;
std::unique_ptr<StreamInfo> BiquadCombo::process(
std::unique_ptr<StreamInfo> data) {
std::scoped_lock lock(this->accessMutex);
for (auto& transform : this->biquads) {
data = transform->process(std::move(data));
}
auto config = std::map<std::string, float>();
config["freq"] = freq;
config["q"] = q;
if (q >= 0.0)
{
if (type == FilterType::Highpass)
{
filter->configure(Biquad::Type::Highpass, config);
}
else
{
filter->configure(Biquad::Type::Lowpass, config);
}
}
else
{
if (type == FilterType::Highpass)
{
filter->configure(Biquad::Type::HighpassFO, config);
}
else
{
filter->configure(Biquad::Type::LowpassFO, config);
}
}
this->biquads.push_back(std::move(filter));
}
}
std::unique_ptr<StreamInfo> BiquadCombo::process(std::unique_ptr<StreamInfo> data) {
std::scoped_lock lock(this->accessMutex);
for (auto &transform : this->biquads) {
data = transform->process(std::move(data));
}
return data;
return data;
}

View File

@@ -1,5 +1,7 @@
#include "Compressor.h"
#include <cstdlib> // for abs
using namespace bell;
float log2f_approx(float X) {
@@ -19,11 +21,11 @@ float log2f_approx(float X) {
Compressor::Compressor() {}
void Compressor::sumChannels(std::unique_ptr<StreamInfo> &data) {
void Compressor::sumChannels(std::unique_ptr<StreamInfo>& data) {
tmp.resize(data->numSamples);
for (int i = 0; i < data->numSamples; i++) {
float sum = 0.0f;
for (auto &channel : channels) {
for (auto& channel : channels) {
sum += data->data[channel][i];
}
tmp[i] = sum;
@@ -31,7 +33,7 @@ void Compressor::sumChannels(std::unique_ptr<StreamInfo> &data) {
}
void Compressor::calLoudness() {
for (auto &value : tmp) {
for (auto& value : tmp) {
value = 20 * log10f_fast(std::abs(value) + 1.0e-9f);
if (value >= lastLoudness) {
value = attack * lastLoudness + (1.0 - attack) * value;
@@ -44,7 +46,7 @@ void Compressor::calLoudness() {
}
void Compressor::calGain() {
for (auto &value : tmp) {
for (auto& value : tmp) {
if (value > threshold) {
value = -(value - threshold) * (factor - 1.0) / factor;
} else {
@@ -58,9 +60,9 @@ void Compressor::calGain() {
}
}
void Compressor::applyGain(std::unique_ptr<StreamInfo> &data) {
void Compressor::applyGain(std::unique_ptr<StreamInfo>& data) {
for (int i = 0; i < data->numSamples; i++) {
for (auto &channel : channels) {
for (auto& channel : channels) {
data->data[channel][i] *= tmp[i];
}
}

View File

@@ -1,31 +1,29 @@
#include "Gain.h"
#include <cmath> // for pow
#include <string> // for string
using namespace bell;
Gain::Gain() : AudioTransform()
{
this->gainFactor = 1.0f;
this->filterType = "gain";
Gain::Gain() : AudioTransform() {
this->gainFactor = 1.0f;
this->filterType = "gain";
}
void Gain::configure(std::vector<int> channels, float gainDB)
{
this->channels = channels;
this->gainDb = gainDB;
this->gainFactor = std::pow(10.0f, gainDB / 20.0f);
void Gain::configure(std::vector<int> channels, float gainDB) {
this->channels = channels;
this->gainDb = gainDB;
this->gainFactor = std::pow(10.0f, gainDB / 20.0f);
}
std::unique_ptr<StreamInfo> Gain::process(std::unique_ptr<StreamInfo> data)
{
std::scoped_lock lock(this->accessMutex);
for (int i = 0; i < data->numSamples; i++)
{
// Apply gain to all channels
for (auto &channel : channels)
{
data->data[channel][i] *= gainFactor;
}
std::unique_ptr<StreamInfo> Gain::process(std::unique_ptr<StreamInfo> data) {
std::scoped_lock lock(this->accessMutex);
for (int i = 0; i < data->numSamples; i++) {
// Apply gain to all channels
for (auto& channel : channels) {
data->data[channel][i] *= gainFactor;
}
}
return data;
return data;
}

View File

@@ -1,89 +1,80 @@
#pragma once
#include <vector>
#include <algorithm>
#include <cJSON.h>
#include <cJSON.h> // for cJSON_GetObjectItem, cJSON, cJSON_IsArray
#include <stddef.h> // for NULL
#include <algorithm> // for find
#include <cstdint> // for uint8_t
#include <memory> // for unique_ptr
#include <stdexcept> // for invalid_argument
#include <vector> // for vector
#include "AudioTransform.h"
#include "AudioTransform.h" // for AudioTransform
#include "StreamInfo.h" // for StreamInfo
namespace bell
{
class AudioMixer : public bell::AudioTransform
{
public:
enum DownmixMode
{
DEFAULT
};
namespace bell {
class AudioMixer : public bell::AudioTransform {
public:
enum DownmixMode { DEFAULT };
struct MixerConfig
{
std::vector<int> source;
int destination;
};
struct MixerConfig {
std::vector<int> source;
int destination;
};
AudioMixer();
~AudioMixer(){};
// Amount of channels in the input
int from;
AudioMixer();
~AudioMixer(){};
// Amount of channels in the input
int from;
// Amount of channels in the output
int to;
// Amount of channels in the output
int to;
// Configuration of each channels in the mixer
std::vector<MixerConfig> mixerConfig;
// Configuration of each channels in the mixer
std::vector<MixerConfig> mixerConfig;
std::unique_ptr<StreamInfo> process(std::unique_ptr<StreamInfo> data) override;
std::unique_ptr<StreamInfo> process(
std::unique_ptr<StreamInfo> data) override;
void reconfigure() override
{
void reconfigure() override {}
void fromJSON(cJSON* json) {
cJSON* mappedChannels = cJSON_GetObjectItem(json, "mapped_channels");
if (mappedChannels == NULL || !cJSON_IsArray(mappedChannels)) {
throw std::invalid_argument("Mixer configuration invalid");
}
this->mixerConfig = std::vector<MixerConfig>();
cJSON* iterator = NULL;
cJSON_ArrayForEach(iterator, mappedChannels) {
std::vector<int> sources(0);
cJSON* iteratorNested = NULL;
cJSON_ArrayForEach(iteratorNested,
cJSON_GetObjectItem(iterator, "source")) {
sources.push_back(iteratorNested->valueint);
}
int destination = cJSON_GetObjectItem(iterator, "destination")->valueint;
this->mixerConfig.push_back(
MixerConfig{.source = sources, .destination = destination});
}
std::vector<uint8_t> sources(0);
for (auto& config : mixerConfig) {
for (auto& source : config.source) {
if (std::find(sources.begin(), sources.end(), source) ==
sources.end()) {
sources.push_back(source);
}
}
}
void fromJSON(cJSON *json)
{
cJSON *mappedChannels = cJSON_GetObjectItem(json, "mapped_channels");
if (mappedChannels == NULL || !cJSON_IsArray(mappedChannels))
{
throw std::invalid_argument("Mixer configuration invalid");
}
this->mixerConfig = std::vector<MixerConfig>();
cJSON *iterator = NULL;
cJSON_ArrayForEach(iterator, mappedChannels)
{
std::vector<int> sources(0);
cJSON *iteratorNested = NULL;
cJSON_ArrayForEach(iteratorNested, cJSON_GetObjectItem(iterator, "source"))
{
sources.push_back(iteratorNested->valueint);
}
int destination = cJSON_GetObjectItem(iterator, "destination")->valueint;
this->mixerConfig.push_back(MixerConfig{
.source = sources,
.destination = destination
});
}
std::vector<uint8_t> sources(0);
for (auto &config : mixerConfig)
{
for (auto &source : config.source)
{
if (std::find(sources.begin(), sources.end(), source) == sources.end())
{
sources.push_back(source);
}
}
}
this->from = sources.size();
this->to = mixerConfig.size();
}
};
}
this->from = sources.size();
this->to = mixerConfig.size();
}
};
} // namespace bell

View File

@@ -1,28 +1,29 @@
#pragma once
#include "AudioTransform.h"
#include "StreamInfo.h"
#include <memory>
#include "Gain.h"
#include <mutex>
#include <memory> // for shared_ptr, unique_ptr
#include <mutex> // for mutex
#include <vector> // for vector
namespace bell
{
class AudioPipeline
{
private:
std::shared_ptr<Gain> headroomGainTransform;
#include "StreamInfo.h" // for StreamInfo
public:
AudioPipeline();
~AudioPipeline(){};
namespace bell {
class AudioTransform;
class Gain;
std::mutex accessMutex;
std::vector<std::shared_ptr<AudioTransform>> transforms;
class AudioPipeline {
private:
std::shared_ptr<Gain> headroomGainTransform;
void recalculateHeadroom();
void addTransform(std::shared_ptr<AudioTransform> transform);
void volumeUpdated(int volume);
std::unique_ptr<StreamInfo> process(std::unique_ptr<StreamInfo> data);
};
}; // namespace bell
public:
AudioPipeline();
~AudioPipeline(){};
std::mutex accessMutex;
std::vector<std::shared_ptr<AudioTransform>> transforms;
void recalculateHeadroom();
void addTransform(std::shared_ptr<AudioTransform> transform);
void volumeUpdated(int volume);
std::unique_ptr<StreamInfo> process(std::unique_ptr<StreamInfo> data);
};
}; // namespace bell

View File

@@ -1,29 +1,28 @@
#pragma once
#include <memory>
#include <thread>
#include <mutex>
#include <thread>
#include "StreamInfo.h"
#include "TransformConfig.h"
namespace bell
{
class AudioTransform
{
protected:
std::mutex accessMutex;
namespace bell {
class AudioTransform {
protected:
std::mutex accessMutex;
public:
virtual std::unique_ptr<StreamInfo> process(std::unique_ptr<StreamInfo> data) = 0;
virtual void sampleRateChanged(uint32_t sampleRate){};
virtual float calculateHeadroom() { return 0; };
public:
virtual std::unique_ptr<StreamInfo> process(
std::unique_ptr<StreamInfo> data) = 0;
virtual void sampleRateChanged(uint32_t sampleRate){};
virtual float calculateHeadroom() { return 0; };
virtual void reconfigure() {};
virtual void reconfigure(){};
std::string filterType;
std::unique_ptr<TransformConfig> config;
std::string filterType;
std::unique_ptr<TransformConfig> config;
AudioTransform() = default;
virtual ~AudioTransform() = default;
};
};
AudioTransform() = default;
virtual ~AudioTransform() = default;
};
}; // namespace bell

View File

@@ -1,34 +1,43 @@
#pragma once
#include <memory>
#include <mutex>
#include <vector>
#include "AudioPipeline.h"
#include "CentralAudioBuffer.h"
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, uint8_t
#include <functional> // for function
#include <memory> // for shared_ptr, unique_ptr
#include <mutex> // for mutex
#include <vector> // for vector
#include "StreamInfo.h" // for BitWidth
namespace bell {
class AudioPipeline;
class CentralAudioBuffer;
#define MAX_INT16 32767
class BellDSP {
public:
BellDSP(std::shared_ptr<CentralAudioBuffer> centralAudioBuffer);
~BellDSP() {};
~BellDSP(){};
class AudioEffect {
public:
AudioEffect() = default;
~AudioEffect() = default;
size_t duration;
virtual void apply(float* sampleData, size_t samples, size_t relativePosition) = 0;
virtual void apply(float* sampleData, size_t samples,
size_t relativePosition) = 0;
};
class FadeEffect: public AudioEffect {
private:
class FadeEffect : public AudioEffect {
private:
std::function<void()> onFinish;
bool isFadeIn;
public:
FadeEffect(size_t duration, bool isFadeIn, std::function<void()> onFinish = nullptr);
~FadeEffect() {};
public:
FadeEffect(size_t duration, bool isFadeIn,
std::function<void()> onFinish = nullptr);
~FadeEffect(){};
void apply(float* sampleData, size_t samples, size_t relativePosition);
};
@@ -38,8 +47,8 @@ class BellDSP {
std::shared_ptr<AudioPipeline> getActivePipeline();
size_t process(uint8_t* data, size_t bytes, int channels,
uint32_t sampleRate, BitWidth bitWidth);
size_t process(uint8_t* data, size_t bytes, int channels, uint32_t sampleRate,
BitWidth bitWidth);
private:
std::shared_ptr<AudioPipeline> activePipeline;
@@ -48,7 +57,6 @@ class BellDSP {
std::vector<float> dataLeft = std::vector<float>(1024);
std::vector<float> dataRight = std::vector<float>(1024);
std::unique_ptr<AudioEffect> underflowEffect = nullptr;
std::unique_ptr<AudioEffect> startEffect = nullptr;
std::unique_ptr<AudioEffect> instantEffect = nullptr;

View File

@@ -1,158 +1,158 @@
#pragma once
#include <cmath>
#include <mutex>
#include <map>
#include <unordered_map>
#include <stdint.h> // for uint32_t
#include <map> // for map
#include <memory> // for unique_ptr, allocator
#include <mutex> // for scoped_lock
#include <stdexcept> // for invalid_argument
#include <string> // for string, operator<, hash, operator==
#include <unordered_map> // for operator!=, unordered_map, __hash_map_c...
#include <utility> // for pair
#include <vector> // for vector
#include "AudioTransform.h"
extern "C" int dsps_biquad_f32_ae32(const float *input, float *output, int len, float *coef, float *w);
#include "AudioTransform.h" // for AudioTransform
#include "StreamInfo.h" // for StreamInfo
#include "TransformConfig.h" // for TransformConfig
namespace bell
{
class Biquad : public bell::AudioTransform
{
public:
Biquad();
~Biquad(){};
extern "C" int dsps_biquad_f32_ae32(const float* input, float* output, int len,
float* coef, float* w);
enum class Type
{
Free,
Highpass,
Lowpass,
HighpassFO,
LowpassFO,
namespace bell {
class Biquad : public bell::AudioTransform {
public:
Biquad();
~Biquad(){};
Peaking,
Highshelf,
HighshelfFO,
Lowshelf,
LowshelfFO,
Notch,
Bandpass,
Allpass,
AllpassFO
};
enum class Type {
Free,
Highpass,
Lowpass,
HighpassFO,
LowpassFO,
std::map<std::string, float> currentConfig;
Peaking,
Highshelf,
HighshelfFO,
Lowshelf,
LowshelfFO,
Notch,
Bandpass,
Allpass,
AllpassFO
};
std::unordered_map<std::string, Type> const strMapType = {
{"free", Type::Free},
{"highpass", Type::Highpass},
{"lowpass", Type::Lowpass},
{"highpass_fo", Type::HighpassFO},
{"lowpass_fo", Type::LowpassFO},
{"peaking", Type::Peaking},
{"highshelf", Type::Highshelf},
{"highshelf_fo", Type::HighpassFO},
{"lowshelf", Type::Lowshelf},
{"lowshelf_fo", Type::LowpassFO},
{"notch", Type::Notch},
{"bandpass", Type::Bandpass},
{"allpass", Type::Allpass},
{"allpass_fo", Type::AllpassFO},
};
std::map<std::string, float> currentConfig;
float freq, q, gain;
int channel;
Biquad::Type type;
std::unordered_map<std::string, Type> const strMapType = {
{"free", Type::Free},
{"highpass", Type::Highpass},
{"lowpass", Type::Lowpass},
{"highpass_fo", Type::HighpassFO},
{"lowpass_fo", Type::LowpassFO},
{"peaking", Type::Peaking},
{"highshelf", Type::Highshelf},
{"highshelf_fo", Type::HighpassFO},
{"lowshelf", Type::Lowshelf},
{"lowshelf_fo", Type::LowpassFO},
{"notch", Type::Notch},
{"bandpass", Type::Bandpass},
{"allpass", Type::Allpass},
{"allpass_fo", Type::AllpassFO},
};
std::unique_ptr<StreamInfo> process(std::unique_ptr<StreamInfo> data) override;
float freq, q, gain;
int channel;
Biquad::Type type;
void configure(Type type, std::map<std::string, float> &config);
std::unique_ptr<StreamInfo> process(
std::unique_ptr<StreamInfo> data) override;
void sampleRateChanged(uint32_t sampleRate) override;
void configure(Type type, std::map<std::string, float>& config);
void reconfigure() override
{
std::scoped_lock lock(this->accessMutex);
std::map<std::string, float> biquadConfig;
this->channel = config->getChannels()[0];
void sampleRateChanged(uint32_t sampleRate) override;
float invalid = -0x7C;
void reconfigure() override {
std::scoped_lock lock(this->accessMutex);
std::map<std::string, float> biquadConfig;
this->channel = config->getChannels()[0];
auto type = config->getString("biquad_type");
float bandwidth = config->getFloat("bandwidth", false, invalid);
float slope = config->getFloat("slope", false, invalid);
float gain = config->getFloat("gain", false, invalid);
float frequency = config->getFloat("frequency", false, invalid);
float q = config->getFloat("q", false, invalid);
float invalid = -0x7C;
if (currentConfig["bandwidth"] == bandwidth &&
currentConfig["slope"] == slope &&
currentConfig["gain"] == gain &&
currentConfig["frequency"] == frequency &&
currentConfig["q"] == q)
{
return;
}
auto type = config->getString("biquad_type");
float bandwidth = config->getFloat("bandwidth", false, invalid);
float slope = config->getFloat("slope", false, invalid);
float gain = config->getFloat("gain", false, invalid);
float frequency = config->getFloat("frequency", false, invalid);
float q = config->getFloat("q", false, invalid);
if (bandwidth != invalid)
biquadConfig["bandwidth"] = bandwidth;
if (slope != invalid)
biquadConfig["slope"] = slope;
if (gain != invalid)
biquadConfig["gain"] = gain;
if (frequency != invalid)
biquadConfig["freq"] = frequency;
if (q != invalid)
biquadConfig["q"] = q;
if (currentConfig["bandwidth"] == bandwidth &&
currentConfig["slope"] == slope && currentConfig["gain"] == gain &&
currentConfig["frequency"] == frequency && currentConfig["q"] == q) {
return;
}
if (type == "free")
{
biquadConfig["a1"] = config->getFloat("a1");
biquadConfig["a2"] = config->getFloat("a2");
biquadConfig["b0"] = config->getFloat("b0");
biquadConfig["b1"] = config->getFloat("b1");
biquadConfig["b2"] = config->getFloat("b2");
}
if (bandwidth != invalid)
biquadConfig["bandwidth"] = bandwidth;
if (slope != invalid)
biquadConfig["slope"] = slope;
if (gain != invalid)
biquadConfig["gain"] = gain;
if (frequency != invalid)
biquadConfig["freq"] = frequency;
if (q != invalid)
biquadConfig["q"] = q;
auto typeElement = strMapType.find(type);
if (typeElement != strMapType.end())
{
this->configure(typeElement->second, biquadConfig);
}
else
{
throw std::invalid_argument("No biquad of type " + type);
}
}
if (type == "free") {
biquadConfig["a1"] = config->getFloat("a1");
biquadConfig["a2"] = config->getFloat("a2");
biquadConfig["b0"] = config->getFloat("b0");
biquadConfig["b1"] = config->getFloat("b1");
biquadConfig["b2"] = config->getFloat("b2");
}
private:
float coeffs[5];
float w[2] = {1.0, 1.0};
auto typeElement = strMapType.find(type);
if (typeElement != strMapType.end()) {
this->configure(typeElement->second, biquadConfig);
} else {
throw std::invalid_argument("No biquad of type " + type);
}
}
float sampleRate = 44100;
private:
float coeffs[5];
float w[2] = {1.0, 1.0};
// Generator methods for different filter types
void highPassCoEffs(float f, float q);
void highPassFOCoEffs(float f);
void lowPassCoEffs(float f, float q);
void lowPassFOCoEffs(float f);
float sampleRate = 44100;
void peakCoEffs(float f, float gain, float q);
void peakCoEffsBandwidth(float f, float gain, float bandwidth);
// Generator methods for different filter types
void highPassCoEffs(float f, float q);
void highPassFOCoEffs(float f);
void lowPassCoEffs(float f, float q);
void lowPassFOCoEffs(float f);
void highShelfCoEffs(float f, float gain, float q);
void highShelfCoEffsSlope(float f, float gain, float slope);
void highShelfFOCoEffs(float f, float gain);
void peakCoEffs(float f, float gain, float q);
void peakCoEffsBandwidth(float f, float gain, float bandwidth);
void lowShelfCoEffs(float f, float gain, float q);
void lowShelfCoEffsSlope(float f, float gain, float slope);
void lowShelfFOCoEffs(float f, float gain);
void highShelfCoEffs(float f, float gain, float q);
void highShelfCoEffsSlope(float f, float gain, float slope);
void highShelfFOCoEffs(float f, float gain);
void notchCoEffs(float f, float gain, float q);
void notchCoEffsBandwidth(float f, float gain, float bandwidth);
void lowShelfCoEffs(float f, float gain, float q);
void lowShelfCoEffsSlope(float f, float gain, float slope);
void lowShelfFOCoEffs(float f, float gain);
void bandPassCoEffs(float f, float q);
void bandPassCoEffsBandwidth(float f, float bandwidth);
void notchCoEffs(float f, float gain, float q);
void notchCoEffsBandwidth(float f, float gain, float bandwidth);
void allPassCoEffs(float f, float q);
void allPassCoEffsBandwidth(float f, float bandwidth);
void allPassFOCoEffs(float f);
void bandPassCoEffs(float f, float q);
void bandPassCoEffsBandwidth(float f, float bandwidth);
void normalizeCoEffs(float a0, float a1, float a2, float b0, float b1, float b2);
};
void allPassCoEffs(float f, float q);
void allPassCoEffsBandwidth(float f, float bandwidth);
void allPassFOCoEffs(float f);
}
void normalizeCoEffs(float a0, float a1, float a2, float b0, float b1,
float b2);
};
} // namespace bell

View File

@@ -1,85 +1,71 @@
#pragma once
#include <vector>
#include <memory>
#include <cmath>
#include <mutex>
#include <map>
#include <stdint.h> // for uint32_t
#include <map> // for map
#include <memory> // for unique_ptr, allocator
#include <mutex> // for scoped_lock
#include <stdexcept> // for invalid_argument
#include <string> // for string, operator==, char_traits, basic_...
#include <vector> // for vector
#include "Biquad.h"
#include "AudioTransform.h"
#include "AudioTransform.h" // for AudioTransform
#include "Biquad.h" // for Biquad
#include "StreamInfo.h" // for StreamInfo
#include "TransformConfig.h" // for TransformConfig
namespace bell
{
class BiquadCombo : public bell::AudioTransform
{
private:
std::vector<std::unique_ptr<bell::Biquad>> biquads;
namespace bell {
class BiquadCombo : public bell::AudioTransform {
private:
std::vector<std::unique_ptr<bell::Biquad>> biquads;
// Calculates Q values for Nth order Butterworth / Linkwitz-Riley filters
std::vector<float> calculateBWQ(int order);
std::vector<float> calculateLRQ(int order);
// Calculates Q values for Nth order Butterworth / Linkwitz-Riley filters
std::vector<float> calculateBWQ(int order);
std::vector<float> calculateLRQ(int order);
public:
BiquadCombo();
~BiquadCombo(){};
int channel;
public:
BiquadCombo();
~BiquadCombo(){};
int channel;
std::map<std::string, float> paramCache = {
{"order", 0.0f},
{"frequency", 0.0f}
};
std::map<std::string, float> paramCache = {{"order", 0.0f},
{"frequency", 0.0f}};
enum class FilterType
{
Highpass,
Lowpass
};
enum class FilterType { Highpass, Lowpass };
void linkwitzRiley(float freq, int order, FilterType type);
void butterworth(float freq, int order, FilterType type);
void linkwitzRiley(float freq, int order, FilterType type);
void butterworth(float freq, int order, FilterType type);
std::unique_ptr<StreamInfo> process(std::unique_ptr<StreamInfo> data) override;
void sampleRateChanged(uint32_t sampleRate) override;
std::unique_ptr<StreamInfo> process(
std::unique_ptr<StreamInfo> data) override;
void sampleRateChanged(uint32_t sampleRate) override;
void reconfigure() override
{
std::scoped_lock lock(this->accessMutex);
void reconfigure() override {
std::scoped_lock lock(this->accessMutex);
float freq = config->getFloat("frequency");
int order = config->getInt("order");
float freq = config->getFloat("frequency");
int order = config->getInt("order");
if (paramCache["frequency"] == freq && paramCache["order"] == order)
{
return;
} else {
paramCache["frequency"] = freq;
paramCache["order"] = order;
}
if (paramCache["frequency"] == freq && paramCache["order"] == order) {
return;
} else {
paramCache["frequency"] = freq;
paramCache["order"] = order;
}
this->channel = config->getChannels()[0];
this->biquads = std::vector<std::unique_ptr<bell::Biquad>>();
auto type = config->getString("combo_type");
if (type == "lr_lowpass")
{
this->linkwitzRiley(freq, order, FilterType::Lowpass);
}
else if (type == "lr_highpass")
{
this->linkwitzRiley(freq, order, FilterType::Highpass);
}
else if (type == "bw_highpass")
{
this->butterworth(freq, order, FilterType::Highpass);
}
else if (type == "bw_lowpass")
{
this->butterworth(freq, order, FilterType::Highpass);
}
else
{
throw std::invalid_argument("Invalid combo filter type");
}
}
};
};
this->channel = config->getChannels()[0];
this->biquads = std::vector<std::unique_ptr<bell::Biquad>>();
auto type = config->getString("combo_type");
if (type == "lr_lowpass") {
this->linkwitzRiley(freq, order, FilterType::Lowpass);
} else if (type == "lr_highpass") {
this->linkwitzRiley(freq, order, FilterType::Highpass);
} else if (type == "bw_highpass") {
this->butterworth(freq, order, FilterType::Highpass);
} else if (type == "bw_lowpass") {
this->butterworth(freq, order, FilterType::Highpass);
} else {
throw std::invalid_argument("Invalid combo filter type");
}
}
};
}; // namespace bell

View File

@@ -2,10 +2,10 @@
#include <atomic>
#include <cmath>
#include <functional>
#include <iostream>
#include <memory>
#include <mutex>
#include <functional>
#include "BellUtils.h"
#include "CircularBuffer.h"
@@ -70,9 +70,9 @@ class CentralAudioBuffer {
*/
void clearBuffer() {
std::scoped_lock lock(this->dataAccessMutex);
//size_t exceptSize = currentSampleRate + (sizeof(AudioChunk) - (currentSampleRate % sizeof(AudioChunk)));
hasChunk = false;
audioBuffer->emptyBuffer();
hasChunk = false;
}
void emptyCompletely() {
@@ -106,10 +106,10 @@ class CentralAudioBuffer {
}
}
AudioChunk currentChunk = { };
AudioChunk currentChunk = {};
bool hasChunk = false;
AudioChunk lastReadChunk = { };
AudioChunk lastReadChunk = {};
AudioChunk* readChunk() {
std::scoped_lock lock(this->dataAccessMutex);

View File

@@ -1,103 +1,102 @@
#pragma once
#include <vector>
#include <memory>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <iostream>
#include <mutex>
#include <map>
#include <math.h> // for expf
#include <stdint.h> // for uint32_t
#include <map> // for map
#include <memory> // for unique_ptr
#include <mutex> // for scoped_lock
#include <string> // for string, operator<
#include <vector> // for vector
#include "Biquad.h"
#include "AudioTransform.h"
#include "AudioTransform.h" // for AudioTransform
#include "StreamInfo.h" // for StreamInfo
#include "TransformConfig.h" // for TransformConfig
#define pow10f(x) expf(2.302585092994046f*x)
#define pow10f(x) expf(2.302585092994046f * x)
// This is a fast approximation to log2()
// Y = C[0]*F*F*F + C[1]*F*F + C[2]*F + C[3] + E;
float log2f_approx(float X);
float log2f_approx(float X);
#define log10f_fast(x) (log2f_approx(x)*0.3010299956639812f)
#define log10f_fast(x) (log2f_approx(x) * 0.3010299956639812f)
namespace bell
{
class Compressor : public bell::AudioTransform
{
private:
std::vector<int> channels;
std::vector<float> tmp;
namespace bell {
class Compressor : public bell::AudioTransform {
private:
std::vector<int> channels;
std::vector<float> tmp;
std::map<std::string, float> paramCache;
std::map<std::string, float> paramCache;
float attack;
float release;
float threshold;
float factor;
float clipLimit;
float makeupGain;
float attack;
float release;
float threshold;
float factor;
float clipLimit;
float makeupGain;
float lastLoudness = -100.0f;
float lastLoudness = -100.0f;
float sampleRate = 44100;
float sampleRate = 44100;
public:
Compressor();
~Compressor(){};
public:
Compressor();
~Compressor(){};
void configure(std::vector<int> channels, float attack, float release, float threshold, float factor, float makeupGain);
void configure(std::vector<int> channels, float attack, float release,
float threshold, float factor, float makeupGain);
void sumChannels(std::unique_ptr<StreamInfo> &data);
void calLoudness();
void calGain();
void sumChannels(std::unique_ptr<StreamInfo>& data);
void calLoudness();
void calGain();
void applyGain(std::unique_ptr<StreamInfo> &data);
void applyGain(std::unique_ptr<StreamInfo>& data);
void reconfigure() override
{
std::scoped_lock lock(this->accessMutex);
auto newChannels = config->getChannels();
float newAttack = config->getFloat("attack");
float newRelease = config->getFloat("release");
float newThreshold = config->getFloat("threshold");
float newFactor = config->getFloat("factor");
float newMakeupGain = config->getFloat("makeup_gain");
void reconfigure() override {
std::scoped_lock lock(this->accessMutex);
auto newChannels = config->getChannels();
if (paramCache["attack"] == newAttack &&
paramCache["release"] == newRelease &&
paramCache["threshold"] == newThreshold &&
paramCache["factor"] == newFactor &&
paramCache["makeup_gain"] == newMakeupGain)
{
return;
}
else
{
float newAttack = config->getFloat("attack");
float newRelease = config->getFloat("release");
float newThreshold = config->getFloat("threshold");
float newFactor = config->getFloat("factor");
float newMakeupGain = config->getFloat("makeup_gain");
paramCache["attack"] = newAttack;
paramCache["release"] = newRelease;
paramCache["threshold"] = newThreshold;
paramCache["factor"] = newFactor;
paramCache["makeup_gain"] = newMakeupGain;
}
if (paramCache["attack"] == newAttack &&
paramCache["release"] == newRelease &&
paramCache["threshold"] == newThreshold &&
paramCache["factor"] == newFactor &&
paramCache["makeup_gain"] == newMakeupGain) {
return;
} else {
this->configure(newChannels, newAttack, newRelease, newThreshold, newFactor, newMakeupGain);
}
paramCache["attack"] = newAttack;
paramCache["release"] = newRelease;
paramCache["threshold"] = newThreshold;
paramCache["factor"] = newFactor;
paramCache["makeup_gain"] = newMakeupGain;
}
// void fromJSON(cJSON* json) override {
// // get field channels
// channels = jsonGetChannels(json);
// float attack = jsonGetNumber<float>(json, "attack", false, 0);
// float release = jsonGetNumber<float>(json, "release", false, 0);
// float factor = jsonGetNumber<float>(json, "factor", false, 4);
// float makeupGain = jsonGetNumber<float>(json, "makeup_gain", false, 0);
// float threshold = jsonGetNumber<float>(json, "threshold", false, 0);
this->configure(newChannels, newAttack, newRelease, newThreshold, newFactor,
newMakeupGain);
}
// this->configure(attack, release, clipLimit, threshold, factor, makeupGain);
// }
// void fromJSON(cJSON* json) override {
// // get field channels
// channels = jsonGetChannels(json);
// float attack = jsonGetNumber<float>(json, "attack", false, 0);
// float release = jsonGetNumber<float>(json, "release", false, 0);
// float factor = jsonGetNumber<float>(json, "factor", false, 4);
// float makeupGain = jsonGetNumber<float>(json, "makeup_gain", false, 0);
// float threshold = jsonGetNumber<float>(json, "threshold", false, 0);
std::unique_ptr<StreamInfo> process(std::unique_ptr<StreamInfo> data) override;
void sampleRateChanged(uint32_t sampleRate) override { this->sampleRate = sampleRate; };
};
// this->configure(attack, release, clipLimit, threshold, factor, makeupGain);
// }
std::unique_ptr<StreamInfo> process(
std::unique_ptr<StreamInfo> data) override;
void sampleRateChanged(uint32_t sampleRate) override {
this->sampleRate = sampleRate;
};
};
}; // namespace bell

View File

@@ -1,40 +1,41 @@
#pragma once
#include <cmath>
#include <mutex>
#include <iostream>
#include <memory> // for unique_ptr
#include <mutex> // for scoped_lock
#include <vector> // for vector
#include "AudioTransform.h"
#include "AudioTransform.h" // for AudioTransform
#include "StreamInfo.h" // for StreamInfo
#include "TransformConfig.h" // for TransformConfig
namespace bell
{
class Gain : public bell::AudioTransform
{
private:
float gainFactor = 1.0f;
namespace bell {
class Gain : public bell::AudioTransform {
private:
float gainFactor = 1.0f;
std::vector<int> channels;
std::vector<int> channels;
public:
Gain();
~Gain() {};
float gainDb = 0.0;
void configure(std::vector<int> channels, float gainDB);
public:
Gain();
~Gain(){};
std::unique_ptr<StreamInfo> process(std::unique_ptr<StreamInfo> data) override;
float gainDb = 0.0;
void reconfigure() override {
std::scoped_lock lock(this->accessMutex);
float gain = config->getFloat("gain");
this->channels = config->getChannels();
void configure(std::vector<int> channels, float gainDB);
if (gainDb == gain) {
return;
}
std::unique_ptr<StreamInfo> process(
std::unique_ptr<StreamInfo> data) override;
this->configure(channels, gain);
}
};
}
void reconfigure() override {
std::scoped_lock lock(this->accessMutex);
float gain = config->getFloat("gain");
this->channels = config->getChannels();
if (gainDb == gain) {
return;
}
this->configure(channels, gain);
}
};
} // namespace bell

View File

@@ -3,108 +3,87 @@
#include "TransformConfig.h"
#include "cJSON.h"
namespace bell
{
class JSONTransformConfig : public bell::TransformConfig
{
private:
cJSON *json;
namespace bell {
class JSONTransformConfig : public bell::TransformConfig {
private:
cJSON* json;
public:
JSONTransformConfig(cJSON *body)
{
this->json = body;
};
~JSONTransformConfig(){};
public:
JSONTransformConfig(cJSON* body) { this->json = body; };
~JSONTransformConfig(){};
std::string rawGetString(const std::string &field) override
{
cJSON *value = cJSON_GetObjectItem(json, field.c_str());
std::string rawGetString(const std::string& field) override {
cJSON* value = cJSON_GetObjectItem(json, field.c_str());
if (value != NULL && cJSON_IsString(value))
{
return std::string(value->valuestring);
}
if (value != NULL && cJSON_IsString(value)) {
return std::string(value->valuestring);
}
return "invalid";
return "invalid";
}
std::vector<int> rawGetIntArray(const std::string& field) override {
std::vector<int> result;
cJSON* value = cJSON_GetObjectItem(json, field.c_str());
if (value != NULL && cJSON_IsArray(value)) {
for (int i = 0; i < cJSON_GetArraySize(value); i++) {
cJSON* item = cJSON_GetArrayItem(value, i);
if (item != NULL && cJSON_IsNumber(item)) {
result.push_back(item->valueint);
}
}
}
std::vector<int> rawGetIntArray(const std::string &field) override
{
std::vector<int> result;
return result;
}
cJSON *value = cJSON_GetObjectItem(json, field.c_str());
std::vector<float> rawGetFloatArray(const std::string& field) override {
std::vector<float> result;
if (value != NULL && cJSON_IsArray(value))
{
for (int i = 0; i < cJSON_GetArraySize(value); i++)
{
cJSON *item = cJSON_GetArrayItem(value, i);
if (item != NULL && cJSON_IsNumber(item))
{
result.push_back(item->valueint);
}
}
}
cJSON* value = cJSON_GetObjectItem(json, field.c_str());
return result;
if (value != NULL && cJSON_IsArray(value)) {
for (int i = 0; i < cJSON_GetArraySize(value); i++) {
cJSON* item = cJSON_GetArrayItem(value, i);
if (item != NULL && cJSON_IsNumber(item)) {
result.push_back(item->valuedouble);
}
}
}
std::vector<float> rawGetFloatArray(const std::string &field) override
{
std::vector<float> result;
return result;
}
cJSON *value = cJSON_GetObjectItem(json, field.c_str());
int rawGetInt(const std::string& field) override {
cJSON* value = cJSON_GetObjectItem(json, field.c_str());
if (value != NULL && cJSON_IsArray(value))
{
for (int i = 0; i < cJSON_GetArraySize(value); i++)
{
cJSON *item = cJSON_GetArrayItem(value, i);
if (item != NULL && cJSON_IsNumber(item))
{
result.push_back(item->valuedouble);
}
}
}
if (value != NULL && cJSON_IsNumber(value)) {
return (int)value->valueint;
}
return result;
}
return invalidInt;
}
int rawGetInt(const std::string &field) override
{
cJSON *value = cJSON_GetObjectItem(json, field.c_str());
bool isArray(const std::string& field) override {
cJSON* value = cJSON_GetObjectItem(json, field.c_str());
if (value != NULL && cJSON_IsNumber(value))
{
return (int)value->valueint;
}
if (value != NULL && cJSON_IsArray(value)) {
return true;
}
return invalidInt;
}
return false;
}
bool isArray(const std::string &field) override
{
cJSON *value = cJSON_GetObjectItem(json, field.c_str());
float rawGetFloat(const std::string& field) override {
cJSON* value = cJSON_GetObjectItem(json, field.c_str());
if (value != NULL && cJSON_IsArray(value))
{
return true;
}
if (value != NULL && cJSON_IsNumber(value)) {
return (float)value->valuedouble;
}
return false;
}
float rawGetFloat(const std::string &field) override
{
cJSON *value = cJSON_GetObjectItem(json, field.c_str());
if (value != NULL && cJSON_IsNumber(value))
{
return (float)value->valuedouble;
}
return invalidInt;
}
};
}
return invalidInt;
}
};
} // namespace bell

View File

@@ -1,36 +1,28 @@
#pragma once
#include <memory>
#include <vector>
#include <string>
#include <vector>
namespace bell
{
enum class Channels {
LEFT,
RIGHT,
LEFT_RIGHT
};
enum class SampleRate : uint32_t
{
SR_44100 = 44100,
SR_48000 = 48000,
};
namespace bell {
enum class Channels { LEFT, RIGHT, LEFT_RIGHT };
enum class BitWidth : uint32_t
{
BW_16 = 16,
BW_24 = 24,
BW_32 = 32,
};
enum class SampleRate : uint32_t {
SR_44100 = 44100,
SR_48000 = 48000,
};
typedef struct
{
float** data;
BitWidth bitwidth;
int numChannels;
SampleRate sampleRate;
size_t numSamples;
} StreamInfo;
};
enum class BitWidth : uint32_t {
BW_16 = 16,
BW_24 = 24,
BW_32 = 32,
};
typedef struct {
float** data;
BitWidth bitwidth;
int numChannels;
SampleRate sampleRate;
size_t numSamples;
} StreamInfo;
}; // namespace bell

View File

@@ -1,134 +1,112 @@
#pragma once
#include <memory>
#include <vector>
#include <string>
#include <variant>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <variant>
#include <vector>
namespace bell
{
class TransformConfig
{
protected:
int invalidInt = -0x7C;
std::string invalidString = "_invalid";
namespace bell {
class TransformConfig {
protected:
int invalidInt = -0x7C;
std::string invalidString = "_invalid";
public:
TransformConfig() = default;
virtual ~TransformConfig() = default;
public:
TransformConfig() = default;
virtual ~TransformConfig() = default;
int currentVolume = 60;
int currentVolume = 60;
virtual std::string rawGetString(const std::string &field) = 0;
virtual std::string rawGetString(const std::string& field) = 0;
virtual int rawGetInt(const std::string &field) = 0;
virtual bool isArray(const std::string &field) = 0;
virtual int rawGetInt(const std::string& field) = 0;
virtual bool isArray(const std::string& field) = 0;
virtual float rawGetFloat(const std::string &field) = 0;
virtual std::vector<float> rawGetFloatArray(const std::string &field) = 0;
virtual std::vector<int> rawGetIntArray(const std::string &field) = 0;
virtual float rawGetFloat(const std::string& field) = 0;
virtual std::vector<float> rawGetFloatArray(const std::string& field) = 0;
virtual std::vector<int> rawGetIntArray(const std::string& field) = 0;
typedef std::variant<int, float, std::string> Value;
std::map<std::string, std::vector<Value>> rawValues;
typedef std::variant<int, float, std::string> Value;
std::map<std::string, std::vector<Value>> rawValues;
Value getRawValue(const std::string &field)
{
int index = this->currentVolume * (rawValues[field].size()) / 100;
if (index >= rawValues[field].size())
index = rawValues[field].size() - 1;
return rawValues[field][index];
Value getRawValue(const std::string& field) {
int index = this->currentVolume * (rawValues[field].size()) / 100;
if (index >= rawValues[field].size())
index = rawValues[field].size() - 1;
return rawValues[field][index];
}
std::string getString(const std::string& field, bool isRequired = false,
std::string defaultValue = "") {
if (rawValues.count(field) == 0) {
rawValues[field] = std::vector<Value>({Value(rawGetString(field))});
}
auto val = std::get<std::string>(getRawValue(field));
if (val == invalidString) {
if (isRequired)
throw std::invalid_argument("Field " + field + " is required");
else
return defaultValue;
} else
return val;
}
int getInt(const std::string& field, bool isRequired = false,
int defaultValue = 0) {
if (rawValues.count(field) == 0) {
if (isArray(field)) {
rawValues[field] = std::vector<Value>();
for (auto f : rawGetIntArray(field)) {
rawValues[field].push_back(f);
}
} else {
rawValues[field] = std::vector<Value>({Value(rawGetInt(field))});
}
}
std::string getString(const std::string &field, bool isRequired = false, std::string defaultValue = "")
{
if (rawValues.count(field) == 0)
{
rawValues[field] = std::vector<Value>({Value(rawGetString(field))});
}
auto val = std::get<std::string>(getRawValue(field));
if (val == invalidString)
{
if (isRequired)
throw std::invalid_argument("Field " + field + " is required");
else
return defaultValue;
}
else
return val;
auto val = std::get<int>(getRawValue(field));
if (val == invalidInt) {
if (isRequired)
throw std::invalid_argument("Field " + field + " is required");
else
return defaultValue;
} else
return val;
}
float getFloat(const std::string& field, bool isRequired = false,
float defaultValue = 0) {
if (rawValues.count(field) == 0) {
if (isArray(field)) {
rawValues[field] = std::vector<Value>();
for (auto f : rawGetFloatArray(field)) {
rawValues[field].push_back(f);
}
} else {
rawValues[field] = std::vector<Value>({Value(rawGetFloat(field))});
}
}
auto val = std::get<float>(getRawValue(field));
if (val == invalidInt) {
if (isRequired)
throw std::invalid_argument("Field " + field + " is required");
else
return defaultValue;
} else
return val;
}
int getInt(const std::string &field, bool isRequired = false, int defaultValue = 0)
{
if (rawValues.count(field) == 0)
{
if (isArray(field))
{
rawValues[field] = std::vector<Value>();
for (auto f : rawGetIntArray(field))
{
rawValues[field].push_back(f);
}
}
else
{
rawValues[field] = std::vector<Value>({Value(rawGetInt(field))});
}
}
std::vector<int> getChannels() {
auto channel = getInt("channel", false, invalidInt);
auto val = std::get<int>(getRawValue(field));
if (val == invalidInt)
{
if (isRequired)
throw std::invalid_argument("Field " + field + " is required");
else
return defaultValue;
}
else
return val;
}
if (channel != invalidInt) {
return std::vector<int>({channel});
}
float getFloat(const std::string &field, bool isRequired = false, float defaultValue = 0)
{
if (rawValues.count(field) == 0)
{
if (isArray(field))
{
rawValues[field] = std::vector<Value>();
for (auto f : rawGetFloatArray(field))
{
rawValues[field].push_back(f);
}
}
else
{
rawValues[field] = std::vector<Value>({ Value(rawGetFloat(field)) });
}
}
auto val = std::get<float>(getRawValue(field));
if (val == invalidInt)
{
if (isRequired)
throw std::invalid_argument("Field " + field + " is required");
else
return defaultValue;
}
else
return val;
}
std::vector<int> getChannels()
{
auto channel = getInt("channel", false, invalidInt);
if (channel != invalidInt)
{
return std::vector<int>({channel});
}
return rawGetIntArray("channels");
}
};
}
return rawGetIntArray("channels");
}
};
} // namespace bell