diff --git a/CMakeLists.txt b/CMakeLists.txt index a670c03..d3fb69c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ set(FILES # Effects src/effects/Cure.cpp + src/effects/DynamicSystem.cpp src/effects/Reverberation.cpp src/effects/TubeSimulator.cpp @@ -29,6 +30,7 @@ set(FILES src/utils/CRevModel.cpp src/utils/Crossfeed.cpp src/utils/DepthSurround.cpp + src/utils/DynamicBass.cpp src/utils/FixedBiquad.cpp src/utils/IIR_1st.cpp src/utils/IIR_NOrder_BW_BP.cpp diff --git a/src/effects/DynamicSystem.cpp b/src/effects/DynamicSystem.cpp new file mode 100644 index 0000000..6a520fb --- /dev/null +++ b/src/effects/DynamicSystem.cpp @@ -0,0 +1,49 @@ +// +// Created by mart on 7/28/21. +// + +#include "DynamicSystem.h" +#include "../constants.h" + +DynamicSystem::DynamicSystem() { + this->enabled = false; + this->samplerate = DEFAULT_SAMPLERATE; + this->bass.SetSamplingRate(this->samplerate); + this->bass.Reset(); +} + +void DynamicSystem::Process(float* samples, uint32_t size) { + if (this->enabled) { + this->bass.FilterSamples(samples, size); + } +} + +void DynamicSystem::Reset() { + this->bass.SetSamplingRate(this->samplerate); + this->bass.Reset(); +} + +void DynamicSystem::SetBassGain(float gain) { + this->bass.SetBassGain(gain); +} + +void DynamicSystem::SetEnable(bool enable) { + this->enabled = enable; +} + +void DynamicSystem::SetSideGain(float gainX, float gainY) { + this->bass.SetSideGain(gainX, gainY); +} + +void DynamicSystem::SetXCoeffs(uint32_t low, uint32_t high) { + this->bass.SetFilterXPassFrequency(low, high); +} + +void DynamicSystem::SetYCoeffs(uint32_t low, uint32_t high) { + this->bass.SetFilterYPassFrequency(low, high); +} + +void DynamicSystem::SetSamplingRate(uint32_t samplerate) { + this->samplerate = samplerate; + this->bass.SetSamplingRate(samplerate); +} diff --git a/src/effects/DynamicSystem.h b/src/effects/DynamicSystem.h new file mode 100644 index 0000000..80dcf9a --- /dev/null +++ b/src/effects/DynamicSystem.h @@ -0,0 +1,29 @@ +// +// Created by mart on 7/28/21. +// + +#pragma once + +#include +#include "../utils/DynamicBass.h" + +class DynamicSystem { +public: + DynamicSystem(); + + void Process(float* samples, uint32_t size); + void Reset(); + + void SetBassGain(float gain); + void SetEnable(bool enable); + void SetSideGain(float gainX, float gainY); + void SetXCoeffs(uint32_t low, uint32_t high); + void SetYCoeffs(uint32_t low, uint32_t high); + void SetSamplingRate(uint32_t samplerate); + + DynamicBass bass; + uint32_t samplerate; + bool enabled; +}; + + diff --git a/src/utils/DynamicBass.cpp b/src/utils/DynamicBass.cpp new file mode 100644 index 0000000..9b8355e --- /dev/null +++ b/src/utils/DynamicBass.cpp @@ -0,0 +1,91 @@ +// +// Created by mart on 7/28/21. +// + +#include "DynamicBass.h" +#include "../constants.h" + +DynamicBass::DynamicBass() { + this->qPeak = 0; + SetSamplingRate(DEFAULT_SAMPLERATE); + this->bassGain = 1.f; + this->sideGainX = 1.f; + this->sideGainY = 1.f; + this->lowFreqX = 120; + this->highFreqX = 80; + this->lowFreqY = 40; + this->highFreqY = this->samplerate / 4.f; + + this->filterX.SetPassFilter(this->lowFreqX, this->highFreqX); + this->filterY.SetPassFilter(this->lowFreqY, this->highFreqY); + this->lowPass.SetLowPassParameter(55.f, this->samplerate, this->qPeak / 666.f + 0.5f) +} + +void DynamicBass::Reset() { + this->filterX.Reset(); + this->filterY.Reset(); + this->lowPass.SetLowPassParameter(55.f, this->samplerate, this->qPeak / 666.f + 0.5f) +} + +void DynamicBass::FilterSamples(float *samples, uint32_t size) { + if (this->lowFreqX <= 120) { + for (int i = 0; i < size; i++) { + int left = samples[2*i]; + int right = samples[2*i+1]; + int avg = this->lowPass.ProcessSample(left + right); + samples[2*i] = left + avg; + samples[2*i+1] = right + avg; + } + } else { + for (int i = 0; i < size; i++) { + float x1, x2, x3, x4, x5, x6, y1, y2, y3, y4, y5, y6; + + this->filterX.DoFilterLeft(samples[2*i], &x1, &x2, &x3); + this->filterX.DoFilterRight(samples[2*i+1], &x4, &x5, &x6); + this->filterY.DoFilterLeft(this->bassGain * x1, &y1, &y2, &y3); + this->filterY.DoFilterRight(this->bassGain * x4, &y4, &y5, &y6); + + samples[2*i] = x2 + y3 + this->sideGainX * y2 + this->sideGainY * y1 + x3; + samples[2*i+1] = x5 + y6 + this->sideGainX * y5 + this->sideGainY * y4 + x6; + } + } +} + +void DynamicBass::SetBassGain(float gain) { + this->bassGain = gain; + this->qPeak = (gain - 1.f) / 20.f * 1600.f; + if (this->qPeak > 1600.f) { + this->qPeak = 1600.f; + } + this->lowPass.SetLowPassParameter(55.f, this->samplerate, this->qPeak / 666.f + 0.5f); +} + +void DynamicBass::SetSideGain(float gainX, float gainY) { + this->sideGainX = gainX; + this->sideGainY = gainY; +} + +void DynamicBass::SetFilterXPassFrequency(uint32_t low, uint32_t high) { + this->lowFreqX = low; + this->highFreqX = high; + + this->filterX.SetPassFilter(low, high); + this->filterX.SetSamplingRate(this->samplerate); + this->lowPass.SetLowPassParameter(55.f, this->samplerate, this->qPeak / 666.f + 0.5f); +} + +void DynamicBass::SetFilterYPassFrequency(uint32_t low, uint32_t high) { + this->lowFreqY = low; + this->highFreqY = high; + + this->filterY.SetPassFilter(low, high); + this->filterY.SetSamplingRate(this->samplerate); + this->lowPass.SetLowPassParameter(55.f, this->samplerate, this->qPeak / 666.f + 0.5f); +} + +void DynamicBass::SetSamplingRate(uint32_t samplerate) { + this->samplerate = samplerate; + this->filterX.SetSamplingRate(samplerate); + this->filterY.SetSamplingRate(samplerate); + this->lowPass.SetLowPassParameter(55.f, samplerate, this->qPeak / 666.f + 0.5f); +} diff --git a/src/utils/DynamicBass.h b/src/utils/DynamicBass.h new file mode 100644 index 0000000..f4d5a91 --- /dev/null +++ b/src/utils/DynamicBass.h @@ -0,0 +1,33 @@ +// +// Created by mart on 7/28/21. +// + +#pragma once + +#include +#include "PolesFilter.h" +#include "FixedBiquad.h" + +class DynamicBass { +public: + DynamicBass(); + + void FilterSamples(float* samples, uint32_t size); + void Reset(); + void SetBassGain(float gain); + void SetFilterXPassFrequency(uint32_t low, uint32_t high); + void SetFilterYPassFrequency(uint32_t low, uint32_t high); + void SetSamplingRate(uint32_t samplerate); + void SetSideGain(float gainX, float gainY); + + uint32_t lowFreqX, highFreqX; + uint32_t lowFreqY, highFreqY; + uint32_t samplerate; + uint32_t qPeak; + float bassGain; + float sideGainX, sideGainY; + + PolesFilter filterX; + PolesFilter filterY; + FixedBiquad lowPass; +}; diff --git a/src/utils/PolesFilter.cpp b/src/utils/PolesFilter.cpp index 1e94ac5..8a4b1a8 100644 --- a/src/utils/PolesFilter.cpp +++ b/src/utils/PolesFilter.cpp @@ -29,24 +29,24 @@ void PolesFilter::UpdateCoeff() { } inline void DoFilterSide(channel* side, float sample, float* out1, float* out2, float* out3) { - float oldestSampleIn = this->in[2]; - this->in[2] = this->in[1]; - this->in[1] = this->in[0]; - this->in[0] = sample; + float oldestSampleIn = side->in[2]; + side->in[2] = side->in[1]; + side->in[1] = side->in[0]; + side->in[0] = sample; - channel->x[0] += channel->lower_angle * (sample - channel->x[0]); - channel->x[1] += channel->lower_angle * (channel->x[0] - channel->x[1]); - channel->x[2] += channel->lower_angle * (channel->x[1] - channel->x[2]); - channel->x[3] += channel->lower_angle * (channel->x[2] - channel->x[3]); + side->x[0] += side->lower_angle * (sample - side->x[0]); + side->x[1] += side->lower_angle * (side->x[0] - side->x[1]); + side->x[2] += side->lower_angle * (side->x[1] - side->x[2]); + side->x[3] += side->lower_angle * (side->x[2] - side->x[3]); - channel->y[0] += channel->upper_angle * (sample - channel->y[0]); - channel->y[1] += channel->upper_angle * (channel->y[0] - channel->y[1]); - channel->y[2] += channel->upper_angle * (channel->y[1] - channel->y[2]); - channel->y[3] += channel->upper_angle * (channel->y[2] - channel->y[3]); + side->y[0] += side->upper_angle * (sample - side->y[0]); + side->y[1] += side->upper_angle * (side->y[0] - side->y[1]); + side->y[2] += side->upper_angle * (side->y[1] - side->y[2]); + side->y[3] += side->upper_angle * (side->y[2] - side->y[3]); - *out1 = channel->x[3]; - *out2 = oldestSampleIn - channel->y[3]; - *out3 = channel->y[3] - channel->x[3]; + *out1 = side->x[3]; + *out2 = oldestSampleIn - side->y[3]; + *out3 = side->y[3] - side->x[3]; } void PolesFilter::DoFilterLeft(float sample, float *out1, float *out2, float *out3) {