ViPERBass: Initial implementation

This commit is contained in:
Iscle 2022-09-19 02:36:53 +02:00
parent a04a1c0f71
commit 340908ba75
9 changed files with 142 additions and 59 deletions

View File

@ -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();

View File

@ -1,16 +1,93 @@
#include <cmath>
#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, bassFactor * 2.5f);
this->subwoofer->SetBassGain(this->samplingRate, this->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);
}
}

View File

@ -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;
};

View File

@ -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;

View File

@ -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;
};

View File

@ -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() {

View File

@ -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);

View File

@ -3,34 +3,34 @@
#include <cmath>
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);
}

View File

@ -1,6 +1,5 @@
#pragma once
#include <cstdint>
#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];