From 779c172aa8306846470bf7784f1879ba5a5628e8 Mon Sep 17 00:00:00 2001 From: Martmists Date: Sat, 31 Jul 2021 16:00:35 +0200 Subject: [PATCH] hifi and clarity --- CMakeLists.txt | 2 + src/effects/ViPERClarity.cpp | 81 +++++++++++++++++++++++++++++++++++ src/effects/ViPERClarity.h | 34 +++++++++++++++ src/utils/HiFi.cpp | 82 ++++++++++++++++++++++++++++++++++++ src/utils/HiFi.h | 33 +++++++++++++++ src/utils/IIR_1st.h | 7 +++ src/utils/IIR_NOrder_BW_BP.h | 17 ++++++++ src/utils/IIR_NOrder_BW_LH.h | 7 +++ src/utils/PassFilter.cpp | 16 ++----- 9 files changed, 267 insertions(+), 12 deletions(-) create mode 100644 src/effects/ViPERClarity.cpp create mode 100644 src/effects/ViPERClarity.h create mode 100644 src/utils/HiFi.cpp create mode 100644 src/utils/HiFi.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fe1456a..3eb5c20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ set(FILES src/effects/SpeakerCorrection.cpp src/effects/SpectrumExtend.cpp src/effects/TubeSimulator.cpp + src/effects/ViPERClarity.cpp # Utils src/utils/CAllpassFilter.cpp @@ -37,6 +38,7 @@ set(FILES src/utils/DynamicBass.cpp src/utils/FixedBiquad.cpp src/utils/Harmonic.cpp + src/utils/HiFi.cpp src/utils/HighShelf.cpp src/utils/IIR_1st.cpp src/utils/IIR_NOrder_BW_BP.cpp diff --git a/src/effects/ViPERClarity.cpp b/src/effects/ViPERClarity.cpp new file mode 100644 index 0000000..628f97c --- /dev/null +++ b/src/effects/ViPERClarity.cpp @@ -0,0 +1,81 @@ +// +// Created by mart on 7/31/21. +// + +#include "ViPERClarity.h" +#include "../constants.h" + +ViPERClarity::ViPERClarity() { + for (int i = 0; i < 2; i++) { + this->hiShelf[i].SetFrequency(12000.f); + this->hiShelf[i].SetQuality(100.f); + this->hiShelf[i].SetGain(1.f); + this->hiShelf[i].SetSamplingRate(DEFAULT_SAMPLERATE); + } + + this->enabled = false; + this->processMode = 0; + this->clarityGainPercent = 0.f; + this->samplerate = DEFAULT_SAMPLERATE; + Reset(); +} + +void ViPERClarity::Process(float *samples, uint32_t size) { + if (this->enabled) { + if (this->processMode == 0) { + this->sharp.Process(samples, size); + } else if (this->processMode == 1) { + for (int i = 0; i < size * 2; i++) { + samples[i] = this->hiShelf[i % 2].Process(samples[i]); + } + } else { + this->hifi.Process(samples, size); + } + } +} + +void ViPERClarity::Reset() { + this->sharp.SetSamplingRate(this->samplerate); + this->sharp.Reset(); + SetClarityToFilter(); + for (int i = 0; i < 2; i++) { + this->hiShelf[i].SetFrequency(8250.f); + this->hiShelf[i].SetQuality(100.f); + this->hiShelf[i].SetSamplingRate(DEFAULT_SAMPLERATE); + } + this->hifi.SetSamplingRate(this->samplerate); + this->hifi.Reset(); +} + +void ViPERClarity::SetClarity(float gainPercent) { + this->clarityGainPercent = gainPercent; + if (this->processMode != 1) { + SetClarityToFilter(); + } else { + Reset(); + } +} + +void ViPERClarity::SetClarityToFilter() { + this->sharp.SetGain(this->clarityGainPercent); + this->hiShelf[0].SetGain(this->clarityGainPercent + 1.f); + this->hiShelf[1].SetGain(this->clarityGainPercent + 1.f); + this->hifi.SetClarity(this->clarityGainPercent + 1.f); +} + +void ViPERClarity::SetEnable(bool enabled) { + this->enabled = enabled; + if (this->enabled) { + Reset(); + } +} + +void ViPERClarity::SetProcessMode(int mode) { + this->processMode = mode; + Reset(); +} + +void ViPERClarity::SetSamplingRate(uint32_t samplerate) { + this->samplerate = samplerate; + Reset(); +} diff --git a/src/effects/ViPERClarity.h b/src/effects/ViPERClarity.h new file mode 100644 index 0000000..d1864a0 --- /dev/null +++ b/src/effects/ViPERClarity.h @@ -0,0 +1,34 @@ +// +// Created by mart on 7/31/21. +// + +#pragma once + + +#include "../utils/NoiseSharpening.h" +#include "../utils/HiFi.h" +#include "../utils/HighShelf.h" + +class ViPERClarity { +public: + ViPERClarity(); + + void Process(float* samples, uint32_t size); + void Reset(); + + void SetClarity(float gainPercent); + void SetClarityToFilter(); + void SetEnable(bool enabled); + void SetProcessMode(int mode); + void SetSamplingRate(uint32_t samplerate); + + NoiseSharpening sharp; + HighShelf hiShelf[2]; + HiFi hifi; + bool enabled; + int processMode; + uint32_t samplerate; + float clarityGainPercent; +}; + + diff --git a/src/utils/HiFi.cpp b/src/utils/HiFi.cpp new file mode 100644 index 0000000..bae2a99 --- /dev/null +++ b/src/utils/HiFi.cpp @@ -0,0 +1,82 @@ +// +// Created by mart on 7/31/21. +// + +#include "HiFi.h" +#include "../constants.h" + +HiFi::HiFi() { + this->gain = 1.f; + this->samplerate = DEFAULT_SAMPLERATE; + for (int i = 0; i < 2; i++) { + this->buffers[i] = new WaveBuffer_I32(2, 0x800); + this->filters[i].lowpass = new IIR_NOrder_BW_LH(1); + this->filters[i].highpass = new IIR_NOrder_BW_LH(3); + this->filters[i].bandpass = new IIR_NOrder_BW_BP(3); + } + Reset(); +} + +HiFi::~HiFi() { + for (int i = 0; i < 2; i++) { + delete this->buffers[i]; + delete this->filters[i].lowpass; + delete this->filters[i].highpass; + delete this->filters[i].bandpass; + } +} + +void HiFi::Process(float *samples, uint32_t size) { + if (size > 0) { + float* bpBuf = this->buffers[0]->PushZerosGetBuffer(size); + float* lpBuf = this->buffers[1]->PushZerosGetBuffer(size); + if (bpBuf == nullptr || lpBuf == nullptr) { + Reset(); + return; + } + + for (int i = 0; i < size*2; i++) { + int index = i % 2; + float out1 = do_filter_lh(this->filters[index].lowpass, samples[i]); + float out2 = do_filter_lh(this->filters[index].highpass, samples[i]); + float out3 = do_filter_bp(this->filters[index].bandpass, samples[i]); + samples[i] = out2; + lpBuf[i] = out1; + bpBuf[i] = out3; + } + float* bpOut = this->buffers[0]->GetCurrentBufferI32Ptr(); + float* lpOut = this->buffers[1]->GetCurrentBufferI32Ptr(); + for (int i = 0; i < size * 2; i++) { + float hp = samples[i] * this->gain * 1.2f; + float bp = bpOut[i] * this->gain; + samples[i] = hp + bp + lpOut[i]; + } + this->buffers[0]->PopSamples(size, false); + this->buffers[1]->PopSamples(size, false); + } +} + +void HiFi::Reset() { + for (int i = 0; i < 2; i++) { + this->filters[i].lowpass->setLPF(120.0, this->samplerate); + this->filters[i].lowpass->Mute(); + this->filters[i].highpass->setHPF(1200.0, this->samplerate); + this->filters[i].highpass->Mute(); + this->filters[i].bandpass->setBPF(120.f, 1200.f, this->samplerate); + this->filters[i].bandpass->Mute(); + } + this->buffers[0]->Reset(); + this->buffers[0]->PushZeros(this->samplerate/400); + this->buffers[1]->Reset(); + this->buffers[1]->PushZeros(this->samplerate/200); + +} + +void HiFi::SetClarity(float value) { + this->gain = value; +} + +void HiFi::SetSamplingRate(uint32_t samplerate) { + this->samplerate = samplerate; + Reset(); +} diff --git a/src/utils/HiFi.h b/src/utils/HiFi.h new file mode 100644 index 0000000..6fc4803 --- /dev/null +++ b/src/utils/HiFi.h @@ -0,0 +1,33 @@ +// +// Created by mart on 7/31/21. +// + +#pragma once + + +#include "IIR_NOrder_BW_LH.h" +#include "WaveBuffer_I32.h" +#include "IIR_NOrder_BW_BP.h" + +class HiFi { +public: + HiFi(); + ~HiFi(); + + void Process(float* samples, uint32_t size); + void Reset(); + + void SetClarity(float value); + void SetSamplingRate(uint32_t samplerate); + + WaveBuffer_I32* buffers[2]; + struct { + IIR_NOrder_BW_LH* lowpass; + IIR_NOrder_BW_LH* highpass; + IIR_NOrder_BW_BP* bandpass; + } filters[2]; + float gain; + uint32_t samplerate; +}; + + diff --git a/src/utils/IIR_1st.h b/src/utils/IIR_1st.h index 6b29f9b..fa53f75 100644 --- a/src/utils/IIR_1st.h +++ b/src/utils/IIR_1st.h @@ -30,3 +30,10 @@ public: float b0, b1, a1; float prevSample; }; + +inline float do_filter(IIR_1st* filter, float sample) { + float hist = sample * filter->b1; + sample = filter->prevSample + sample * filter->b0; + filter->prevSample = sample * filter->a1 + hist; + return sample; +} \ No newline at end of file diff --git a/src/utils/IIR_NOrder_BW_BP.h b/src/utils/IIR_NOrder_BW_BP.h index 602641a..2127dba 100644 --- a/src/utils/IIR_NOrder_BW_BP.h +++ b/src/utils/IIR_NOrder_BW_BP.h @@ -19,3 +19,20 @@ public: uint32_t order; }; +inline float do_filter_bplp(IIR_NOrder_BW_BP* filt, float sample) { + for (int idx = 0; idx < filt->order; idx++) { + sample = do_filter(&filt->lowpass[idx], sample); + } + return sample; +} + +inline float do_filter_bphp(IIR_NOrder_BW_BP* filt, float sample) { + for (int idx = 0; idx < filt->order; idx++) { + sample = do_filter(&filt->highpass[idx], sample); + } + return sample; +} + +inline float do_filter_bp(IIR_NOrder_BW_BP* filt, float sample) { + return do_filter_bphp(filt, do_filter_bplp(filt, sample)); +} diff --git a/src/utils/IIR_NOrder_BW_LH.h b/src/utils/IIR_NOrder_BW_LH.h index 5bf9590..73ce573 100644 --- a/src/utils/IIR_NOrder_BW_LH.h +++ b/src/utils/IIR_NOrder_BW_LH.h @@ -18,3 +18,10 @@ public: IIR_1st* filters; uint32_t order; }; + +inline float do_filter_lh(IIR_NOrder_BW_LH* filt, float sample) { + for (int idx = 0; idx < filt->order; idx++) { + sample = do_filter(&filt->filters[idx], sample); + } + return sample; +} diff --git a/src/utils/PassFilter.cpp b/src/utils/PassFilter.cpp index 20691a9..78b0164 100644 --- a/src/utils/PassFilter.cpp +++ b/src/utils/PassFilter.cpp @@ -40,23 +40,15 @@ void PassFilter::Reset() { this->filters[3]->Mute(); } -#define do_filter(filt, sample) \ -for (int idx = 0; idx < (filt)->order; idx++) {\ - IIR_1st filter = this->filters[2]->filters[idx];\ - float hist = (sample) * filter.b1;\ - left = filter.prevSample + (sample) * filter.b0;\ - filter.prevSample = (sample) * filter.a1 + hist;\ -} - void PassFilter::ProcessFrames(float *buffer, uint32_t size) { for (int x = 0; x < size; x++) { float left = buffer[2*x]; float right = buffer[2*x+1]; - do_filter(this->filters[2], left) - do_filter(this->filters[0], left) - do_filter(this->filters[3], right) - do_filter(this->filters[1], right) + left = do_filter_lh(this->filters[2], left); + left = do_filter_lh(this->filters[0], left); + right = do_filter_lh(this->filters[3], right); + right = do_filter_lh(this->filters[1], right); buffer[2*x] = left; buffer[2*x+1] = right;