From 4fb9cee28542aeac650c75d6402341199d9fdf50 Mon Sep 17 00:00:00 2001 From: Martijn Date: Fri, 30 Jul 2021 16:54:59 +0200 Subject: [PATCH] harmonics, analogx and spectrumextend --- CMakeLists.txt | 3 ++ src/effects/AnalogX.cpp | 90 ++++++++++++++++++++++++++++++++++ src/effects/AnalogX.h | 33 +++++++++++++ src/effects/SpectrumExtend.cpp | 80 ++++++++++++++++++++++++++++++ src/effects/SpectrumExtend.h | 32 ++++++++++++ src/utils/Harmonic.cpp | 65 ++++++++++++++++++++++++ src/utils/Harmonic.h | 28 +++++++++++ 7 files changed, 331 insertions(+) create mode 100644 src/effects/AnalogX.cpp create mode 100644 src/effects/AnalogX.h create mode 100644 src/effects/SpectrumExtend.cpp create mode 100644 src/effects/SpectrumExtend.h create mode 100644 src/utils/Harmonic.cpp create mode 100644 src/utils/Harmonic.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d5c2cb..b881a6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,9 +19,11 @@ set(FILES src/viper.cpp # Effects + src/effects/AnalogX.cpp src/effects/Cure.cpp src/effects/DynamicSystem.cpp src/effects/Reverberation.cpp + src/effects/SpectrumExtend.cpp src/effects/TubeSimulator.cpp # Utils @@ -32,6 +34,7 @@ set(FILES src/utils/DepthSurround.cpp src/utils/DynamicBass.cpp src/utils/FixedBiquad.cpp + src/utils/Harmonic.cpp src/utils/HighShelf.cpp src/utils/IIR_1st.cpp src/utils/IIR_NOrder_BW_BP.cpp diff --git a/src/effects/AnalogX.cpp b/src/effects/AnalogX.cpp new file mode 100644 index 0000000..eadeb3b --- /dev/null +++ b/src/effects/AnalogX.cpp @@ -0,0 +1,90 @@ +// +// Created by mart on 7/30/21. +// + +#include +#include "AnalogX.h" +#include "../constants.h" + +static float ANALOGX_HARMONICS[10] = { + 0.01f, + 0.02f, + 0.0001f, + 0.001f, + 0.f, + 0.f, + 0.f, + 0.f, + 0.f, + 0.f +}; + +AnalogX::AnalogX() { + this->samplerate = DEFAULT_SAMPLERATE; + this->processingModel = 0; + this->enabled = false; + Reset(); +} + +void AnalogX::Process(float *samples, uint32_t size) { + for (int i = 0; i < 2*size; i++) { + float sample = samples[i]; + int index = i % 2; + + float tmp = this->highpass[index].ProcessSample(sample); + tmp = this->harmonics[index].Process(tmp); + + tmp = this->lowpass[index].ProcessSample(sample + tmp * this->gain); + tmp = this->peak->ProcessSample(tmp * 0.8f); + + samples[i] = tmp; + } + + if (this->freqRange < this->samplerate / 4) { + this->freqRange += size; + memset(samples, 0, 2 * size * sizeof(float)); + } +} + +void AnalogX::Reset() { + this->highpass[0].RefreshFilter(FilterType::HIGHPASS, 0.f, 240.f, (float)this->samplerate, 0.717, false); + this->highpass[1].RefreshFilter(FilterType::HIGHPASS, 0.f, 240.f, (float)this->samplerate, 0.717, false); + + this->peak[0].RefreshFilter(FilterType::PEAK, 0.58f, 633.f, (float)this->samplerate, 6.28, true); + this->peak[1].RefreshFilter(FilterType::PEAK, 0.58f, 633.f, (float)this->samplerate, 6.28, true); + + this->harmonics[0].Reset(); + this->harmonics[1].Reset(); + + if (this->processingModel == 0) { + this->harmonics[0].SetHarmonics(ANALOGX_HARMONICS); + this->harmonics[1].SetHarmonics(ANALOGX_HARMONICS); + this->gain = 0.6f; + this->lowpass[0].RefreshFilter(FilterType::LOWPASS, 0.0, 18233.f, (float)this->samplerate, 0.717f, false); + this->lowpass[1].RefreshFilter(FilterType::LOWPASS, 0.0, 18233.f, (float)this->samplerate, 0.717f, false); + } else if (this->processingModel == 1) { + this->harmonics[0].SetHarmonics(ANALOGX_HARMONICS); + this->harmonics[1].SetHarmonics(ANALOGX_HARMONICS); + this->gain = 1.2f; + this->lowpass[0].RefreshFilter(FilterType::LOWPASS, 0.0, 19650.f, (float)this->samplerate, 0.717f, false); + this->lowpass[1].RefreshFilter(FilterType::LOWPASS, 0.0, 19650.f, (float)this->samplerate, 0.717f, false); + } else if (this->processingModel == 2) { + this->harmonics[0].SetHarmonics(ANALOGX_HARMONICS); + this->harmonics[1].SetHarmonics(ANALOGX_HARMONICS); + this->gain = 2.4f; + this->lowpass[0].RefreshFilter(FilterType::LOWPASS, 0.0, 16307.f, (float)this->samplerate, 0.717f, false); + this->lowpass[1].RefreshFilter(FilterType::LOWPASS, 0.0, 16307.f, (float)this->samplerate, 0.717f, false); + } + + this->freqRange = 0; +} + +void AnalogX::SetProcessingModel(int model) { + this->processingModel = model; + Reset(); +} + +void AnalogX::SetSamplingRate(uint32_t samplerate) { + this->samplerate = samplerate; + Reset(); +} diff --git a/src/effects/AnalogX.h b/src/effects/AnalogX.h new file mode 100644 index 0000000..48d053c --- /dev/null +++ b/src/effects/AnalogX.h @@ -0,0 +1,33 @@ +// +// Created by mart on 7/30/21. +// + +#pragma once + + +#include "../utils/Harmonic.h" +#include "../utils/MultiBiquad.h" + +class AnalogX { +public: + AnalogX(); + + void Process(float* samples, uint32_t size); + void Reset(); + + void SetProcessingModel(int model); + void SetSamplingRate(uint32_t samplerate); + + MultiBiquad highpass[2]; + Harmonic harmonics[2]; + MultiBiquad lowpass[2]; + MultiBiquad peak[2]; + + float gain; + uint32_t freqRange; + int processingModel; + uint32_t samplerate; + bool enabled; +}; + + diff --git a/src/effects/SpectrumExtend.cpp b/src/effects/SpectrumExtend.cpp new file mode 100644 index 0000000..c4aa9bd --- /dev/null +++ b/src/effects/SpectrumExtend.cpp @@ -0,0 +1,80 @@ +// +// Created by mart on 7/30/21. +// + +#include "SpectrumExtend.h" +#include "../constants.h" + +static float SPECTRUM_HARMONICS[10] = { + 0.02f, + 0.f, + 0.02f, + 0.f, + 0.02f, + 0.f, + 0.02f, + 0.f, + 0.02f, + 0.f, +}; + +SpectrumExtend::SpectrumExtend() { + this->samplerate = DEFAULT_SAMPLERATE; + this->referenceFreq = 7600; + this->enabled = false; + this->exciter = 0.f; + Reset(); +} + +SpectrumExtend::~SpectrumExtend() { + // empty? +} + +void SpectrumExtend::Process(float *samples, uint32_t size) { + for (int i = 0; i < size * 2; i++) { + float sample = samples[i]; + int index = i % 2; + float tmp = this->highpass[index].ProcessSample(sample); + tmp = this->harmonics[index].Process(tmp); + tmp = this->lowpass[index].ProcessSample(tmp * this->exciter); + samples[i] = samples[i] + tmp; + } +} + +void SpectrumExtend::Reset() { + this->highpass[0].RefreshFilter(FilterType::HIGHPASS, 0.0, (float)this->referenceFreq, (float)this->samplerate, 0.717, false); + this->highpass[1].RefreshFilter(FilterType::HIGHPASS, 0.0, (float)this->referenceFreq, (float)this->samplerate, 0.717, false); + + this->lowpass[0].RefreshFilter(FilterType::LOWPASS, 0.0, (float)this->referenceFreq / 2.f - 2000.f, (float)this->referenceFreq, 0.717, false); + this->lowpass[1].RefreshFilter(FilterType::LOWPASS, 0.0, (float)this->referenceFreq / 2.f - 2000.f, (float)this->referenceFreq, 0.717, false); + + this->harmonics[0].Reset(); + this->harmonics[1].Reset(); + + this->harmonics[0].SetHarmonics(SPECTRUM_HARMONICS); + this->harmonics[1].SetHarmonics(SPECTRUM_HARMONICS); +} + +void SpectrumExtend::SetEnable(bool enable) { + this->enabled = enable; +} + +void SpectrumExtend::SetExciter(float value) { + this->exciter = value; +} + +void SpectrumExtend::SetReferenceFrequency(uint32_t freq) { + if (this->samplerate / 2 - 100 < freq) { + freq = this->samplerate / 2 - 100; + } + this->referenceFreq = freq; + Reset(); +} + +void SpectrumExtend::SetSamplingRate(uint32_t samplerate) { + this->samplerate = samplerate; + if (this->samplerate / 2 - 100 < this->referenceFreq) { + this->referenceFreq = this->samplerate / 2 - 100; + } + Reset(); +} diff --git a/src/effects/SpectrumExtend.h b/src/effects/SpectrumExtend.h new file mode 100644 index 0000000..121c948 --- /dev/null +++ b/src/effects/SpectrumExtend.h @@ -0,0 +1,32 @@ +// +// Created by mart on 7/30/21. +// + +#pragma once + + +#include "../utils/Harmonic.h" +#include "../utils/MultiBiquad.h" + +class SpectrumExtend { +public: + SpectrumExtend(); + ~SpectrumExtend(); + + void Process(float* samples, uint32_t size); + void Reset(); + void SetEnable(bool enable); + void SetExciter(float value); + void SetReferenceFrequency(uint32_t freq); + void SetSamplingRate(uint32_t samplerate); + + MultiBiquad highpass[2]; + MultiBiquad lowpass[2]; + Harmonic harmonics[2]; + bool enabled; + uint32_t samplerate; + uint32_t referenceFreq; + float exciter; +}; + + diff --git a/src/utils/Harmonic.cpp b/src/utils/Harmonic.cpp new file mode 100644 index 0000000..5a28f42 --- /dev/null +++ b/src/utils/Harmonic.cpp @@ -0,0 +1,65 @@ +// +// Created by mart on 7/30/21. +// + +#include "Harmonic.h" + +static float HARMONIC_DEFAULT[10] = { + 1.f, + 0.f, + 0.f, + 0.f, + 0.f, + 0.f, + 0.f, + 0.f, + 0.f, + 0.f, +}; + +Harmonic::Harmonic() { + UpdateCoeffs(HARMONIC_DEFAULT); + Reset(); +} + +Harmonic::~Harmonic() { + +} + +float Harmonic::Process(float sample) { + float prevLast = this->lastProcessed; + this->lastProcessed = ( + sample * this->coeffs[0] + + sample * this->coeffs[1] + + sample * this->coeffs[2] + + sample * this->coeffs[3] + + sample * this->coeffs[4] + + sample * this->coeffs[5] + + sample * this->coeffs[6] + + sample * this->coeffs[7] + + sample * this->coeffs[8] + + sample * this->coeffs[9] + + sample * this->coeffs[10] + ); + this->prevOut = this->lastProcessed + this->prevOut * 0.999f - prevLast; + if (this->sampleCounter < this->buildup) { + this->sampleCounter++; + return 0; + } + return this->prevOut; +} + +void Harmonic::Reset() { + this->lastProcessed = 0.f; + this->prevOut = 0.f; + this->sampleCounter = 0.f; +} + +void Harmonic::SetHarmonics(float *coeffs) { + UpdateCoeffs(coeffs); + Reset(); +} + +void Harmonic::UpdateCoeffs(float *coeffs) { + // TODO +} diff --git a/src/utils/Harmonic.h b/src/utils/Harmonic.h new file mode 100644 index 0000000..437cfdd --- /dev/null +++ b/src/utils/Harmonic.h @@ -0,0 +1,28 @@ +// +// Created by mart on 7/30/21. +// + +#pragma once + + +#include + +class Harmonic { +public: + Harmonic(); + ~Harmonic(); + + float Process(float sample); + + void Reset(); + void SetHarmonics(float* coeffs); + void UpdateCoeffs(float* coeffs); + + float coeffs[11]; + float lastProcessed; + float prevOut; + int buildup; + int sampleCounter; +}; + +