mirror of
https://github.com/AndroidAudioMods/ViPERFX_RE.git
synced 2025-06-08 02:29:40 +08:00
ViPERBass: Initial implementation
This commit is contained in:
parent
a04a1c0f71
commit
340908ba75
@ -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();
|
||||
|
||||
|
@ -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, 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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];
|
||||
|
Loading…
x
Reference in New Issue
Block a user