diff --git a/src/cpp/viper/ViPER.cpp b/src/cpp/viper/ViPER.cpp index 2fb4744..627a832 100644 --- a/src/cpp/viper/ViPER.cpp +++ b/src/cpp/viper/ViPER.cpp @@ -63,7 +63,6 @@ ViPER::ViPER() { this->dynamicSystem->Reset(); this->viperBass = new ViPERBass(); - this->viperBass->SetEnable(false); this->viperBass->SetSamplingRate(this->sampleRate); this->viperBass->Reset(); diff --git a/src/cpp/viper/effects/ViPERBass.cpp b/src/cpp/viper/effects/ViPERBass.cpp index 57c37de..bf8144c 100644 --- a/src/cpp/viper/effects/ViPERBass.cpp +++ b/src/cpp/viper/effects/ViPERBass.cpp @@ -1,16 +1,93 @@ -#include #include "ViPERBass.h" +#include "../constants.h" ViPERBass::ViPERBass() { + this->samplingRate = DEFAULT_SAMPLERATE; + this->speaker = 60; + this->invertedSamplingRate = 1.0f / DEFAULT_SAMPLERATE; + this->unknown1 = 0.0; + this->processMode = NATURAL_BASS; + this->bassFactor = 0.0f; + this->polyphase = new Polyphase(2); + this->biquad = new Biquad(); + this->subwoofer = new Subwoofer(); + this->waveBuffer = new WaveBuffer(1, 0x1000); + this->biquad->Reset(); + this->biquad->SetLowPassParameter(this->speaker, this->samplingRate, 0.53); + this->subwoofer->SetBassGain(this->samplingRate, 0.0); + this->Reset(); } ViPERBass::~ViPERBass() { + delete this->polyphase; + this->polyphase = nullptr; + delete this->biquad; + this->biquad = nullptr; + + delete this->subwoofer; + this->subwoofer = nullptr; + + delete this->waveBuffer; + this->waveBuffer = nullptr; } void ViPERBass::Process(float *samples, uint32_t size) { + if (size == 0) { + return; + } + // Anti-pop mechanism? this->unknown1 is zeroed in Reset() + if (this->unknown1 < 1.0) { + for (uint32_t i = 0; i < size * 2; i += 2) { + samples[i] *= this->unknown1; + samples[i + 1] *= this->unknown1; + + float x = this->unknown1 + this->invertedSamplingRate; + if (x > 1.0) { + x = 1.0; + } + this->unknown1 = x; + } + } + + switch (this->processMode) { + case NATURAL_BASS: { + for (uint32_t i = 0; i < size * 2; i += 2) { + double sample = ((double) samples[i] + (double) samples[i + 1]) / 2.0; + auto x = (float) this->biquad->ProcessSample(sample); + samples[i] += x; + samples[i + 1] += x; + } + break; + } + case PURE_BASS_PLUS: { + if (this->waveBuffer->PushSamples(samples, size) != 0) { + float *buffer = this->waveBuffer->GetBuffer(); + uint32_t bufferOffset = this->waveBuffer->GetBufferOffset(); + + for (uint32_t i = 0; i < size * 2; i += 2) { + double sample = ((double) samples[i] + (double) samples[i + 1]) / 2.0; + auto x = (float) this->biquad->ProcessSample(sample); + buffer[bufferOffset - size + i / 2] = x; + } + + if (this->polyphase->Process(samples, size) == size) { + for (uint32_t i = 0; i < size; i++) { + samples[i] += buffer[i] * this->bassFactor; + samples[i + 1] += buffer[i] * this->bassFactor; + } + this->waveBuffer->PopSamples(size, true); + } + } + break; + } + case SUBWOOFER: { + this->subwoofer->Process(samples, size); + break; + } + } } void ViPERBass::Reset() { @@ -19,35 +96,38 @@ void ViPERBass::Reset() { this->waveBuffer->Reset(); this->waveBuffer->PushZeros(this->polyphase->GetLatency()); this->subwoofer->SetBassGain(this->samplingRate, this->bassFactor * 2.5f); - this->fixedBiquad->SetLowPassParameter(this->speaker, this->samplingRate, 0.53); + this->biquad->SetLowPassParameter(this->speaker, this->samplingRate, 0.53); this->unknown1 = 0.0f; + this->invertedSamplingRate = 1.0f / (float) this->samplingRate; } void ViPERBass::SetBassFactor(float bassFactor) { - if (abs(this->bassFactor - bassFactor) <= 0.01) { - return; + if (this->bassFactor != bassFactor) { + this->bassFactor = bassFactor; + this->subwoofer->SetBassGain(this->samplingRate, this->bassFactor * 2.5f); } - - this->bassFactor = bassFactor; - this->subwoofer->SetBassGain(this->samplingRate, bassFactor * 2.5f); } -void ViPERBass::SetEnable(bool enable) { - -} - -void ViPERBass::SetProcessMode(int processMode) { - +void ViPERBass::SetProcessMode(ProcessMode processMode) { + if (processMode < MAX_PROCESS_MODE && this->processMode != processMode) { + this->processMode = processMode; + this->Reset(); + } } void ViPERBass::SetSamplingRate(uint32_t samplingRate) { - + if (this->samplingRate != samplingRate) { + this->samplingRate = samplingRate; + this->invertedSamplingRate = 1.0f / (float) samplingRate; + this->polyphase->SetSamplingRate(samplingRate); + this->biquad->SetLowPassParameter(this->speaker, samplingRate, 0.53); + this->subwoofer->SetBassGain(samplingRate, this->bassFactor * 2.5); + } } -void ViPERBass::SetSpeaker(float speaker) { +void ViPERBass::SetSpeaker(uint32_t speaker) { if (this->speaker != speaker) { this->speaker = speaker; - Reset(); + this->biquad->SetLowPassParameter(this->speaker, this->samplingRate, 0.53); } - } diff --git a/src/cpp/viper/effects/ViPERBass.h b/src/cpp/viper/effects/ViPERBass.h index 5896fec..9378987 100644 --- a/src/cpp/viper/effects/ViPERBass.h +++ b/src/cpp/viper/effects/ViPERBass.h @@ -8,28 +8,33 @@ class ViPERBass { public: + enum ProcessMode { + NATURAL_BASS = 0, + PURE_BASS_PLUS = 1, + SUBWOOFER = 2, + MAX_PROCESS_MODE + }; + ViPERBass(); ~ViPERBass(); void Process(float *samples, uint32_t size); void Reset(); void SetBassFactor(float bassFactor); - void SetEnable(bool enable); - void SetProcessMode(int processMode); + void SetProcessMode(ProcessMode processMode); void SetSamplingRate(uint32_t samplingRate); - void SetSpeaker(float speaker); + void SetSpeaker(uint32_t speaker); private: Polyphase *polyphase; - Biquad *fixedBiquad; + Biquad *biquad; Subwoofer *subwoofer; WaveBuffer *waveBuffer; - bool enable; - bool initOk; - int processMode; + ProcessMode processMode; uint32_t samplingRate; + float invertedSamplingRate; float unknown1; - float speaker; + uint32_t speaker; float bassFactor; }; diff --git a/src/cpp/viper/utils/MultiBiquad.cpp b/src/cpp/viper/utils/MultiBiquad.cpp index a27db02..ca1ceed 100644 --- a/src/cpp/viper/utils/MultiBiquad.cpp +++ b/src/cpp/viper/utils/MultiBiquad.cpp @@ -13,8 +13,8 @@ MultiBiquad::MultiBiquad() { this->a2 = 0; } -float MultiBiquad::ProcessSample(float sample) { - float out = sample * this->b0 + this->x_1 * this->b1 + this->x_2 * this->b2 + this->y_1 * this->a1 + +double MultiBiquad::ProcessSample(double sample) { + double out = sample * this->b0 + this->x_1 * this->b1 + this->x_2 * this->b2 + this->y_1 * this->a1 + this->y_2 * this->a2; this->y_2 = this->y_1; this->y_1 = out; @@ -24,7 +24,7 @@ float MultiBiquad::ProcessSample(float sample) { } void -MultiBiquad::RefreshFilter(FilterType type, float gainAmp, float freq, float samplerate, float qFactor, bool param_7) { +MultiBiquad::RefreshFilter(FilterType type, double gainAmp, double freq, double samplingRate, double qFactor, bool param_7) { bool uVar1; double dVar4; double dVar5; @@ -42,7 +42,7 @@ MultiBiquad::RefreshFilter(FilterType type, float gainAmp, float freq, float sam double b2; dVar10 = pow(10.0, gainAmp / 40.0); - dVar4 = (freq * 2 * M_PI) / samplerate; + dVar4 = (freq * 2 * M_PI) / samplingRate; dVar5 = sin(dVar4); dVar11 = cos(dVar4); uVar1 = type == HIGHSHELF; diff --git a/src/cpp/viper/utils/MultiBiquad.h b/src/cpp/viper/utils/MultiBiquad.h index 8803b1e..c8c6319 100644 --- a/src/cpp/viper/utils/MultiBiquad.h +++ b/src/cpp/viper/utils/MultiBiquad.h @@ -15,12 +15,12 @@ class MultiBiquad { public: MultiBiquad(); - float ProcessSample(float sample); + double ProcessSample(double sample); - void RefreshFilter(FilterType type, float gainAmp, float freq, float samplerate, float qFactor, bool param_7); + void RefreshFilter(FilterType type, double gainAmp, double freq, double samplingRate, double qFactor, bool param_7); - float y_2, y_1, x_2, x_1; - float b0, b1, b2, a1, a2; + double y_2, y_1, x_2, x_1; + double b0, b1, b2, a1, a2; }; diff --git a/src/cpp/viper/utils/Polyphase.cpp b/src/cpp/viper/utils/Polyphase.cpp index 4715b3b..1e88aac 100644 --- a/src/cpp/viper/utils/Polyphase.cpp +++ b/src/cpp/viper/utils/Polyphase.cpp @@ -1,6 +1,6 @@ #include "Polyphase.h" -Polyphase::Polyphase() { +Polyphase::Polyphase(int unknown1) { } @@ -12,8 +12,8 @@ uint32_t Polyphase::GetLatency() { return 63; } -void Polyphase::Process(float *samples, uint32_t size) { - +uint32_t Polyphase::Process(float *samples, uint32_t size) { + return 0; } void Polyphase::Reset() { diff --git a/src/cpp/viper/utils/Polyphase.h b/src/cpp/viper/utils/Polyphase.h index 436e709..86076a6 100644 --- a/src/cpp/viper/utils/Polyphase.h +++ b/src/cpp/viper/utils/Polyphase.h @@ -6,11 +6,11 @@ class Polyphase { public: - Polyphase(); + Polyphase(int unknown1); ~Polyphase(); uint32_t GetLatency(); - void Process(float *samples, uint32_t size); + uint32_t Process(float *samples, uint32_t size); void Reset(); void SetSamplingRate(uint32_t samplingRate); diff --git a/src/cpp/viper/utils/Subwoofer.cpp b/src/cpp/viper/utils/Subwoofer.cpp index a74831c..49c1e8a 100644 --- a/src/cpp/viper/utils/Subwoofer.cpp +++ b/src/cpp/viper/utils/Subwoofer.cpp @@ -3,34 +3,34 @@ #include Subwoofer::Subwoofer() { - float samplerate = (float) DEFAULT_SAMPLERATE; - this->peak[0].RefreshFilter(FilterType::PEAK, 0.f, 37.f, samplerate, 1.f, false); - this->peak[1].RefreshFilter(FilterType::PEAK, 0.f, 37.f, samplerate, 1.f, false); - this->peakLow[0].RefreshFilter(FilterType::PEAK, 0.f, 75.f, samplerate, 1.f, false); - this->peakLow[1].RefreshFilter(FilterType::PEAK, 0.f, 75.f, samplerate, 1.f, false); - this->lowpass[0].RefreshFilter(FilterType::LOWPASS, 0.f, 200.f, samplerate, 1.f, false); - this->lowpass[1].RefreshFilter(FilterType::LOWPASS, 0.f, 200.f, samplerate, 1.f, false); + uint32_t samplingRate = DEFAULT_SAMPLERATE; + this->peak[0].RefreshFilter(FilterType::PEAK, 0.0, 37.0, samplingRate, 1.0, false); + this->peak[1].RefreshFilter(FilterType::PEAK, 0.0, 37.0, samplingRate, 1.0, false); + this->peakLow[0].RefreshFilter(FilterType::PEAK, 0.0, 75.0, samplingRate, 1.0, false); + this->peakLow[1].RefreshFilter(FilterType::PEAK, 0.0, 75.0, samplingRate, 1.0, false); + this->lowpass[0].RefreshFilter(FilterType::LOWPASS, 0.0, 200.0, samplingRate, 1.0, false); + this->lowpass[1].RefreshFilter(FilterType::LOWPASS, 0.0, 200.0, samplingRate, 1.0, false); } void Subwoofer::Process(float *samples, uint32_t size) { for (int i = 0; i < size * 2; i++) { - float sample = samples[i]; + auto sample = (double) samples[i]; int index = i % 2; - float tmp = this->peak[index].ProcessSample(sample); + double tmp = this->peak[index].ProcessSample(sample); tmp = this->peakLow[index].ProcessSample(tmp); tmp = this->lowpass[index].ProcessSample(tmp - sample); - samples[i] = (sample / 2.f) + (tmp * 0.6f); + samples[i] = (float) ((sample / 2.0) + (tmp * 0.6f)); } } void Subwoofer::SetBassGain(uint32_t samplerate, float gainDb) { - float gain = 20.f * log10f(gainDb); - float gainLower = 20.f * log10f(gainDb / 8.f); + double gain = 20.0 * log10( gainDb); + double gainLower = 20.0 * log10( gainDb / 8.0); - this->peak[0].RefreshFilter(FilterType::PEAK, gain, 44.f, (float) samplerate, 0.75, true); - this->peak[1].RefreshFilter(FilterType::PEAK, gain, 44.f, (float) samplerate, 0.75, true); - this->peakLow[0].RefreshFilter(FilterType::PEAK, gainLower, 80.f, (float) samplerate, 0.2, true); - this->peakLow[1].RefreshFilter(FilterType::PEAK, gainLower, 80.f, (float) samplerate, 0.2, true); - this->lowpass[0].RefreshFilter(FilterType::LOWPASS, 0.f, 380.f, (float) samplerate, 0.6, false); - this->lowpass[1].RefreshFilter(FilterType::LOWPASS, 0.f, 380.f, (float) samplerate, 0.6, false); + this->peak[0].RefreshFilter(FilterType::PEAK, gain, 44.0, (double) samplerate, 0.75, true); + this->peak[1].RefreshFilter(FilterType::PEAK, gain, 44.0, (double) samplerate, 0.75, true); + this->peakLow[0].RefreshFilter(FilterType::PEAK, gainLower, 80.0, (double) samplerate, 0.2, true); + this->peakLow[1].RefreshFilter(FilterType::PEAK, gainLower, 80.0, (double) samplerate, 0.2, true); + this->lowpass[0].RefreshFilter(FilterType::LOWPASS, 0.0, 380.0, (double) samplerate, 0.6, false); + this->lowpass[1].RefreshFilter(FilterType::LOWPASS, 0.0, 380.0, (double) samplerate, 0.6, false); } diff --git a/src/cpp/viper/utils/Subwoofer.h b/src/cpp/viper/utils/Subwoofer.h index 5cef040..83b5a4b 100644 --- a/src/cpp/viper/utils/Subwoofer.h +++ b/src/cpp/viper/utils/Subwoofer.h @@ -1,6 +1,5 @@ #pragma once - #include #include "MultiBiquad.h" @@ -9,9 +8,9 @@ public: Subwoofer(); void Process(float *samples, uint32_t size); - void SetBassGain(uint32_t samplerate, float gainDb); +private: MultiBiquad peak[2]; MultiBiquad peakLow[2]; MultiBiquad lowpass[2];