This commit is contained in:
Iscle
2022-10-25 03:30:21 +02:00
parent 346a33711f
commit c30f2f8c6f
100 changed files with 49 additions and 56 deletions

610
src/viper/ViPER.cpp Normal file
View File

@ -0,0 +1,610 @@
#include "ViPER.h"
#include <ctime>
#include <cstring>
#include "constants.h"
ViPER::ViPER() {
VIPER_LOGI("Welcome to ViPER FX");
VIPER_LOGI("Current version is %s %s", VERSION_STRING, VERSION_CODENAME);
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->adaptiveBuffer = new AdaptiveBuffer(2, 4096);
this->waveBuffer = new WaveBuffer(2, 4096);
this->convolver = new Convolver();
this->convolver->SetEnable(false);
this->convolver->SetSamplingRate(this->samplingRate);
this->convolver->Reset();
this->vhe = new VHE();
this->vhe->SetEnable(false);
this->vhe->SetSamplingRate(this->samplingRate);
this->vhe->Reset();
this->viperDdc = new ViPERDDC();
this->viperDdc->SetEnable(false);
this->viperDdc->SetSamplingRate(this->samplingRate);
this->viperDdc->Reset();
this->spectrumExtend = new SpectrumExtend();
this->spectrumExtend->SetEnable(false);
this->spectrumExtend->SetSamplingRate(this->samplingRate);
this->spectrumExtend->SetReferenceFrequency(7600);
this->spectrumExtend->SetExciter(0);
this->spectrumExtend->Reset();
this->iirFilter = new IIRFilter(10);
this->iirFilter->SetEnable(false);
this->iirFilter->SetSamplingRate(this->samplingRate);
this->iirFilter->Reset();
this->colorfulMusic = new ColorfulMusic();
this->colorfulMusic->SetEnable(false);
this->colorfulMusic->SetSamplingRate(this->samplingRate);
this->colorfulMusic->Reset();
this->reverberation = new Reverberation();
this->reverberation->SetEnable(false);
this->reverberation->Reset();
this->playbackGain = new PlaybackGain();
this->playbackGain->SetEnable(false);
this->playbackGain->SetSamplingRate(this->samplingRate);
this->playbackGain->Reset();
this->fetCompressor = new FETCompressor();
this->fetCompressor->SetParameter(FETCompressor::ENABLE, 0.0);
this->fetCompressor->SetSamplingRate(this->samplingRate);
this->fetCompressor->Reset();
this->dynamicSystem = new DynamicSystem();
this->dynamicSystem->SetEnable(false);
this->dynamicSystem->SetSamplingRate(this->samplingRate);
this->dynamicSystem->Reset();
this->viperBass = new ViPERBass();
this->viperBass->SetSamplingRate(this->samplingRate);
this->viperBass->Reset();
this->viperClarity = new ViPERClarity();
this->viperClarity->SetSamplingRate(this->samplingRate);
this->viperClarity->Reset();
this->diffSurround = new DiffSurround();
this->diffSurround->SetEnable(false);
this->diffSurround->SetSamplingRate(this->samplingRate);
this->diffSurround->Reset();
this->cure = new Cure();
this->cure->SetEnable(false);
this->cure->SetSamplingRate(this->samplingRate);
this->cure->Reset();
this->tubeSimulator = new TubeSimulator();
this->tubeSimulator->SetEnable(false);
this->tubeSimulator->Reset();
this->analogX = new AnalogX();
this->analogX->SetEnable(false);
this->analogX->SetSamplingRate(this->samplingRate);
this->analogX->SetProcessingModel(0);
this->analogX->Reset();
this->speakerCorrection = new SpeakerCorrection();
this->speakerCorrection->SetEnable(false);
this->speakerCorrection->SetSamplingRate(this->samplingRate);
this->speakerCorrection->Reset();
for (auto &softwareLimiter: this->softwareLimiters) {
softwareLimiter = new SoftwareLimiter();
softwareLimiter->ResetLimiter();
}
this->frameScale = 1.0;
this->leftPan = 1.0;
this->rightPan = 1.0;
this->updateProcessTime = false;
this->processTimeMs = 0;
this->enabled = false;
}
ViPER::~ViPER() {
delete this->adaptiveBuffer;
delete this->waveBuffer;
delete this->convolver;
delete this->vhe;
delete this->viperDdc;
delete this->spectrumExtend;
delete this->iirFilter;
delete this->colorfulMusic;
delete this->reverberation;
delete this->playbackGain;
delete this->fetCompressor;
delete this->dynamicSystem;
delete this->viperBass;
delete this->viperClarity;
delete this->diffSurround;
delete this->cure;
delete this->tubeSimulator;
delete this->analogX;
delete this->speakerCorrection;
for (auto &softwareLimiter: this->softwareLimiters) {
delete softwareLimiter;
}
}
// TODO: Return int
void ViPER::processBuffer(float *buffer, uint32_t size) {
if (!this->enabled) {
VIPER_LOGD("ViPER is disabled, skip processing");
return;
}
if (size == 0) {
VIPER_LOGD("Buffer size is 0, skip processing");
return;
}
if (this->updateProcessTime) {
struct timeval time{};
gettimeofday(&time, nullptr);
this->processTimeMs = time.tv_sec * 1000 + time.tv_usec / 1000;
}
uint32_t ret;
float *tmpBuf;
uint32_t tmpBufSize;
if (this->convolver->GetEnabled() || this->vhe->GetEnabled()) {
// VIPER_LOGD("Convolver or VHE is enable, use wave buffer");
if (!this->waveBuffer->PushSamples(buffer, size)) {
this->waveBuffer->Reset();
return;
}
float *ptr = this->waveBuffer->GetBuffer();
ret = this->convolver->Process(ptr, ptr, size);
ret = this->vhe->Process(ptr, ptr, ret);
this->waveBuffer->SetBufferOffset(ret);
if (!this->adaptiveBuffer->PushZero(ret)) {
this->waveBuffer->Reset();
this->adaptiveBuffer->FlushBuffer();
return;
}
ptr = this->adaptiveBuffer->GetBuffer();
ret = this->waveBuffer->PopSamples(ptr, ret, true);
this->adaptiveBuffer->SetBufferOffset(ret);
tmpBuf = ptr;
tmpBufSize = ret;
} else {
// VIPER_LOGD("Convolver and VHE are disabled, use adaptive buffer");
if (this->adaptiveBuffer->PushFrames(buffer, size)) {
this->adaptiveBuffer->SetBufferOffset(size);
tmpBuf = this->adaptiveBuffer->GetBuffer();
tmpBufSize = size;
} else {
this->adaptiveBuffer->FlushBuffer();
return;
}
}
// VIPER_LOGD("Process buffer size: %d", tmpBufSize);
if (tmpBufSize != 0) {
this->viperDdc->Process(tmpBuf, size);
this->spectrumExtend->Process(tmpBuf, size);
this->iirFilter->Process(tmpBuf, tmpBufSize);
this->colorfulMusic->Process(tmpBuf, tmpBufSize);
this->diffSurround->Process(tmpBuf, tmpBufSize);
this->reverberation->Process(tmpBuf, tmpBufSize);
this->speakerCorrection->Process(tmpBuf, tmpBufSize);
this->playbackGain->Process(tmpBuf, tmpBufSize);
this->fetCompressor->Process(tmpBuf, tmpBufSize); // TODO: enable check
this->dynamicSystem->Process(tmpBuf, tmpBufSize);
this->viperBass->Process(tmpBuf, tmpBufSize);
this->viperClarity->Process(tmpBuf, tmpBufSize);
this->cure->Process(tmpBuf, tmpBufSize);
this->tubeSimulator->TubeProcess(tmpBuf, size);
this->analogX->Process(tmpBuf, tmpBufSize);
if (this->frameScale != 1.0) {
this->adaptiveBuffer->ScaleFrames(this->frameScale);
}
if (this->leftPan < 1.0 || this->rightPan < 1.0) {
this->adaptiveBuffer->PanFrames(this->leftPan, this->rightPan);
}
for (uint32_t i = 0; i < tmpBufSize * 2; i += 2) {
tmpBuf[i] = this->softwareLimiters[0]->Process(tmpBuf[i]);
tmpBuf[i + 1] = this->softwareLimiters[1]->Process(tmpBuf[i + 1]);
}
if (!this->adaptiveBuffer->PopFrames(buffer, tmpBufSize)) {
this->adaptiveBuffer->FlushBuffer();
return;
}
if (size <= tmpBufSize) {
return;
}
}
memmove(buffer + (size - tmpBufSize) * 2, buffer, tmpBufSize * sizeof(float));
memset(buffer, 0, (size - tmpBufSize) * sizeof(float));
}
void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, uint32_t arrSize,
signed char *arr) {
VIPER_LOGD("Dispatch command: %d, %d, %d, %d, %d, %d, %p", param, val1, val2, val3, val4, arrSize, arr);
switch (param) {
case PARAM_SET_UPDATE_STATUS: {
this->updateProcessTime = val1 != 0;
break;
}
case PARAM_SET_RESET_STATUS: {
this->ResetAllEffects();
break;
}
case PARAM_CONVOLUTION_ENABLE: {
// this->convolver->SetEnabled(val1 != 0);
break;
} // 0x10002
case PARAM_CONVOLUTION_PREPARE_BUFFER: {
break;
} // 0x10004
case PARAM_CONVOLUTION_SET_BUFFER: {
break;
} // 0x10005
case PARAM_CONVOLUTION_COMMIT_BUFFER: {
break;
} // 0x10006
case PARAM_CONVOLUTION_CROSS_CHANNEL: {
this->convolver->SetCrossChannel((float) val1 / 100.0f);
break;
} // 0x10007
case PARAM_HEADPHONE_SURROUND_ENABLE: {
this->vhe->SetEnable(val1 != 0);
break;
} // 0x10008
case PARAM_HEADPHONE_SURROUND_STRENGTH: {
this->vhe->SetEffectLevel(val1);
break;
} // 0x10009
case PARAM_DDC_ENABLE: {
this->viperDdc->SetEnable(val1 != 0);
break;
} // 0x1000A
case PARAM_DDC_COEFFICIENTS: {
// TODO: Finish
//this->viperDdc->SetCoeffs();
break;
} // 0x1000B
case PARAM_SPECTRUM_EXTENSION_ENABLE: {
this->spectrumExtend->SetEnable(val1 != 0);
break;
} // 0x1000C
case PARAM_SPECTRUM_EXTENSION_BARK: {
this->spectrumExtend->SetReferenceFrequency(val1);
break;
} // 0x1000D
case PARAM_SPECTRUM_EXTENSION_BARK_RECONSTRUCT: {
this->spectrumExtend->SetExciter((float) val1 / 100.0f);
break;
} // 0x1000E
case PARAM_FIR_EQUALIZER_ENABLE: {
this->iirFilter->SetEnable(val1 != 0);
break;
} // 0x1000F
case PARAM_FIR_EQUALIZER_BAND_LEVEL: {
this->iirFilter->SetBandLevel(val1, (float) val2 / 100.0f);
break;
} // 0x10010
case PARAM_FIELD_SURROUND_ENABLE: {
this->colorfulMusic->SetEnable(val1 != 0);
break;
} // 0x10011
case PARAM_FIELD_SURROUND_WIDENING: {
this->colorfulMusic->SetWidenValue((float) val1 / 100.0f);
break;
} // 0x10012
case PARAM_FIELD_SURROUND_MID_IMAGE: {
this->colorfulMusic->SetMidImageValue((float) val1 / 100.0f);
break;
} // 0x10013
case PARAM_FIELD_SURROUND_DEPTH: {
this->colorfulMusic->SetDepthValue((short) val1);
break;
} // 0x10014
case PARAM_DIFFERENTIAL_SURROUND_ENABLE: {
this->diffSurround->SetEnable(val1 != 0);
break;
} // 0x10015
case PARAM_DIFFERENTIAL_SURROUND_DELAY: {
this->diffSurround->SetDelayTime((float) val1 / 100.0f);
break;
} // 0x10016
case PARAM_REVERBERATION_ENABLE: {
this->reverberation->SetEnable(val1 != 0);
break;
} // 0x10017
case PARAM_REVERBERATION_ROOM_SIZE: {
this->reverberation->SetRoomSize((float) val1 / 100.0f);
break;
} // 0x10018
case PARAM_REVERBERATION_ROOM_WIDTH: {
this->reverberation->SetWidth((float) val1 / 100.0f);
break;
} // 0x10019
case PARAM_REVERBERATION_ROOM_DAMPENING: {
this->reverberation->SetDamp((float) val1 / 100.0f);
break;
} // 0x1001A
case PARAM_REVERBERATION_ROOM_WET_SIGNAL: {
this->reverberation->SetWet((float) val1 / 100.0f);
break;
} // 0x1001B
case PARAM_REVERBERATION_ROOM_DRY_SIGNAL: {
this->reverberation->SetDry((float) val1 / 100.0f);
break;
} // 0x1001C
case PARAM_AUTOMATIC_GAIN_CONTROL_ENABLE: {
this->playbackGain->SetEnable(val1 != 0);
break;
} // 0x1001D
case PARAM_AUTOMATIC_GAIN_CONTROL_RATIO: {
this->playbackGain->SetRatio((float) val1 / 100.0f);
break;
} // 0x1001E
case PARAM_AUTOMATIC_GAIN_CONTROL_VOLUME: {
this->playbackGain->SetVolume((float) val1 / 100.0f);
break;
} // 0x1001F
case PARAM_AUTOMATIC_GAIN_CONTROL_MAX_SCALER: {
this->playbackGain->SetMaxGainFactor((float) val1 / 100.0f);
break;
} // 0x10020
case PARAM_DYNAMIC_SYSTEM_ENABLE: {
this->dynamicSystem->SetEnable(val1 != 0);
break;
} // 0x10021
case PARAM_DYNAMIC_SYSTEM_X_COEFFICIENTS: {
this->dynamicSystem->SetXCoeffs(val1, val2);
break;
} // 0x10022
case PARAM_DYNAMIC_SYSTEM_Y_COEFFICIENTS: {
this->dynamicSystem->SetYCoeffs(val1, val2);
break;
} // 0x10023
case PARAM_DYNAMIC_SYSTEM_SIDE_GAIN: {
this->dynamicSystem->SetSideGain((float) val1 / 100.0f, (float) val2 / 100.0f);
break;
} // 0x10024
case PARAM_DYNAMIC_SYSTEM_STRENGTH: {
this->dynamicSystem->SetBassGain((float) val1 / 100.0f);
break;
} // 0x10025
case PARAM_FIDELITY_BASS_ENABLE: {
this->viperBass->SetEnable(val1 != 0);
break;
} // 0x10026
case PARAM_FIDELITY_BASS_MODE: {
this->viperBass->SetProcessMode((ViPERBass::ProcessMode) val1);
break;
} // 0x10027
case PARAM_FIDELITY_BASS_FREQUENCY: {
this->viperBass->SetSpeaker(val1);
break;
} // 0x10028
case PARAM_FIDELITY_BASS_GAIN: {
this->viperBass->SetBassFactor((float) val1 / 100.0f);
break;
} // 0x10029
case PARAM_FIDELITY_CLARITY_ENABLE: {
this->viperClarity->SetEnable(val1 != 0);
break;
} // 0x1002A
case PARAM_FIDELITY_CLARITY_MODE: {
this->viperClarity->SetProcessMode((ViPERClarity::ClarityMode) val1);
break;
} // 0x1002B
case PARAM_FIDELITY_CLARITY_GAIN: {
this->viperClarity->SetClarity((float) val1 / 100.0f);
break;
} // 0x1002C
case PARAM_CURE_CROSS_FEED_ENABLED: {
this->cure->SetEnable(val1 != 0);
break;
} // 0x1002D
case PARAM_CURE_CROSS_FEED_STRENGTH: {
switch (val1) {
case 0:
// Cure_R::SetPreset(pCVar17,0x5f028a);
break;
case 1:
// Cure_R::SetPreset(pCVar17,0x3c02bc);
break;
case 2:
// Cure_R::SetPreset(pCVar17,0x2d02bc);
break;
}
break;
} // 0x1002E
case PARAM_TUBE_SIMULATOR_ENABLED: {
this->tubeSimulator->SetEnable(val1 != 0);
break;
} // 0x1002F
case PARAM_ANALOGX_ENABLE: {
this->analogX->SetEnable(val1 != 0);
break;
} // 0x10030
case PARAM_ANALOGX_MODE: {
this->analogX->SetProcessingModel(val1);
break;
} // 0x10031
case PARAM_GATE_OUTPUT_VOLUME: {
this->frameScale = (float) val1 / 100.0f;
break;
} // 0x10032
case PARAM_GATE_CHANNEL_PAN: {
float tmp = (float) val1 / 100.0f;
if (tmp < 0.0f) {
this->leftPan = 1.0f;
this->rightPan = 1.0f + tmp;
} else {
this->leftPan = 1.0f - tmp;
this->rightPan = 1.0f;
}
break;
} // 0x10033
case PARAM_GATE_LIMIT: {
this->softwareLimiters[0]->SetGate((float) val1 / 100.0f);
this->softwareLimiters[1]->SetGate((float) val1 / 100.0f);
break;
} // 0x10034
case PARAM_SPEAKER_OPTIMIZATION: {
this->speakerCorrection->SetEnable(val1 != 0);
break;
} // 0x10043
case PARAM_FET_COMPRESSOR_ENABLE: {
break;
} // 0x10049
case PARAM_FET_COMPRESSOR_THRESHOLD: {
break;
} // 0x1004A
case PARAM_FET_COMPRESSOR_RATIO: {
this->fetCompressor->SetParameter(FETCompressor::THRESHOLD, (float) val1 / 100.0f);
break;
} // 0x1004B
case PARAM_FET_COMPRESSOR_KNEE: {
break;
} // 0x1004C
case PARAM_FET_COMPRESSOR_AUTO_KNEE: {
break;
} // 0x1004D
case PARAM_FET_COMPRESSOR_GAIN: {
break;
} // 0x1004E
case PARAM_FET_COMPRESSOR_AUTO_GAIN: {
this->fetCompressor->SetParameter(FETCompressor::GAIN, (float) val1 / 100.0f);
break;
} // 0x1004F
case PARAM_FET_COMPRESSOR_ATTACK: {
break;
} // 0x10050
case PARAM_FET_COMPRESSOR_AUTO_ATTACK: {
break;
} // 0x10051
case PARAM_FET_COMPRESSOR_RELEASE: {
break;
} // 0x10052
case PARAM_FET_COMPRESSOR_AUTO_RELEASE: {
break;
} // 0x10053
case PARAM_FET_COMPRESSOR_KNEE_MULTI: {
break;
} // 0x10054
case PARAM_FET_COMPRESSOR_MAX_ATTACK: {
break;
} // 0x10055
case PARAM_FET_COMPRESSOR_MAX_RELEASE: {
this->fetCompressor->SetParameter(FETCompressor::MAX_ATTACK, (float) val1 / 100.0f);
break;
} // 0x10056
case PARAM_FET_COMPRESSOR_CREST: {
break;
} // 0x10057
case PARAM_FET_COMPRESSOR_ADAPT: {
break;
} // 0x10058
case PARAM_FET_COMPRESSOR_NO_CLIP: {
this->fetCompressor->SetParameter(FETCompressor::ADAPT, (float) val1 / 100.0f);
break;
} // 0x10059
}
}
void ViPER::ResetAllEffects() {
if (this->adaptiveBuffer != nullptr) {
this->adaptiveBuffer->FlushBuffer();
}
if (this->waveBuffer != nullptr) {
this->waveBuffer->Reset();
}
if (this->convolver != nullptr) {
this->convolver->SetSamplingRate(this->samplingRate);
this->convolver->Reset();
}
if (this->vhe != nullptr) {
this->vhe->SetSamplingRate(this->samplingRate);
this->vhe->Reset();
}
if (this->viperDdc != nullptr) {
this->viperDdc->SetSamplingRate(this->samplingRate);
this->viperDdc->Reset();
}
if (this->spectrumExtend != nullptr) {
this->spectrumExtend->SetSamplingRate(this->samplingRate);
this->spectrumExtend->Reset();
}
if (this->iirFilter != nullptr) {
this->iirFilter->SetSamplingRate(this->samplingRate);
this->iirFilter->Reset();
}
if (this->colorfulMusic != nullptr) {
this->colorfulMusic->SetSamplingRate(this->samplingRate);
this->colorfulMusic->Reset();
}
if (this->reverberation != nullptr) {
this->reverberation->Reset();
}
if (this->playbackGain != nullptr) {
this->playbackGain->SetSamplingRate(this->samplingRate);
this->playbackGain->Reset();
}
if (this->fetCompressor != nullptr) {
this->fetCompressor->SetSamplingRate(this->samplingRate);
this->fetCompressor->Reset();
}
if (this->dynamicSystem != nullptr) {
this->dynamicSystem->SetSamplingRate(this->samplingRate);
this->dynamicSystem->Reset();
}
if (this->viperBass != nullptr) {
this->viperBass->SetSamplingRate(this->samplingRate);
this->viperBass->Reset();
}
if (this->viperClarity != nullptr) {
this->viperClarity->SetSamplingRate(this->samplingRate);
this->viperClarity->Reset();
}
if (this->diffSurround != nullptr) {
this->diffSurround->SetSamplingRate(this->samplingRate);
this->diffSurround->Reset();
}
if (this->cure != nullptr) {
this->cure->SetSamplingRate(this->samplingRate);
this->cure->Reset();
}
if (this->tubeSimulator != nullptr) {
this->tubeSimulator->Reset();
}
if (this->analogX != nullptr) {
this->analogX->SetSamplingRate(this->samplingRate);
this->analogX->Reset();
}
if (this->speakerCorrection != nullptr) {
this->speakerCorrection->SetSamplingRate(this->samplingRate);
this->speakerCorrection->Reset();
}
for (auto &softwareLimiter: softwareLimiters) {
if (softwareLimiter != nullptr) {
softwareLimiter->ResetLimiter();
}
}
}

66
src/viper/ViPER.h Normal file
View File

@ -0,0 +1,66 @@
#pragma once
#include "utils/WaveBuffer.h"
#include "effects/SpectrumExtend.h"
#include "effects/Reverberation.h"
#include "effects/DynamicSystem.h"
#include "effects/ViPERClarity.h"
#include "effects/SpeakerCorrection.h"
#include "effects/AnalogX.h"
#include "effects/TubeSimulator.h"
#include "effects/Cure.h"
#include "effects/DiffSurround.h"
#include "effects/VHE.h"
#include "utils/AdaptiveBuffer.h"
#include "effects/Convolver.h"
#include "effects/ViPERDDC.h"
#include "effects/IIRFilter.h"
#include "effects/ColorfulMusic.h"
#include "effects/FETCompressor.h"
#include "effects/ViPERBass.h"
#include "effects/SoftwareLimiter.h"
#include "effects/PlaybackGain.h"
#include "../ViPER4Android.h"
class ViPER {
public:
ViPER();
~ViPER();
void processBuffer(float *buffer, uint32_t size);
// TODO: Parameter types/names
void DispatchCommand(int param, int val1, int val2, int val3, int val4, uint32_t arrSize, signed char *arr);
void ResetAllEffects();
//private:
bool updateProcessTime;
uint64_t processTimeMs;
bool enabled;
uint32_t samplingRate;
// Effects
AdaptiveBuffer *adaptiveBuffer;
WaveBuffer *waveBuffer;
Convolver *convolver;
VHE *vhe;
ViPERDDC *viperDdc;
SpectrumExtend *spectrumExtend;
IIRFilter *iirFilter;
ColorfulMusic *colorfulMusic;
Reverberation *reverberation;
PlaybackGain *playbackGain;
FETCompressor *fetCompressor;
DynamicSystem *dynamicSystem;
ViPERBass *viperBass;
ViPERClarity *viperClarity;
DiffSurround *diffSurround;
Cure *cure;
TubeSimulator *tubeSimulator;
AnalogX *analogX;
SpeakerCorrection *speakerCorrection;
SoftwareLimiter *softwareLimiters[2];
float frameScale;
float leftPan;
float rightPan;
};

16
src/viper/constants.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#ifdef ANDROID_TOOLCHAIN
#include <android/errno.h>
#else
#include <cerrno>
#endif
#include "../log.h" // TODO: Remove this dependency
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define VERSION_STRING "v" STR(VERSION_MAJOR) "." STR(VERSION_MINOR)
#define VIPER_DEFAULT_SAMPLING_RATE 44100
#define VIPER_AUTHORS "viper.WYF, Martmists, Iscle"

View File

@ -0,0 +1,117 @@
#include "AnalogX.h"
#include <cstring>
#include "../constants.h"
static const float ANALOGX_HARMONICS[] = {
0.01,
0.02,
0.0001,
0.001,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
};
AnalogX::AnalogX() {
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->processingModel = 0;
this->enable = false;
Reset();
}
void AnalogX::Process(float *samples, uint32_t size) {
if (this->enable) {
for (uint32_t i = 0; i < size * 2; i += 2) {
double inL = samples[i];
double outL = this->highPass[0].ProcessSample(inL);
outL = this->harmonic[0].Process(outL);
outL = this->lowPass[0].ProcessSample(inL + outL * this->gain);
outL = this->peak[0].ProcessSample(outL * 0.8);
samples[i] = (float) outL;
double inR = samples[i + 1];
double outR = this->highPass[1].ProcessSample(inR);
outR = this->harmonic[1].Process(outR);
outR = this->lowPass[1].ProcessSample(inR + outR * this->gain);
outR = this->peak[1].ProcessSample(outR * 0.8);
samples[i + 1] = (float) outR;
}
if (this->freqRange < this->samplingRate / 4) {
this->freqRange += size;
memset(samples, 0, size * 2 * sizeof(float));
}
}
}
void AnalogX::Reset() {
this->highPass[0].RefreshFilter(MultiBiquad::FilterType::HIGH_PASS, 0.0, 240.0, this->samplingRate, 0.717, false);
this->highPass[1].RefreshFilter(MultiBiquad::FilterType::HIGH_PASS, 0.0, 240.0, this->samplingRate, 0.717, false);
this->peak[0].RefreshFilter(MultiBiquad::FilterType::PEAK, 0.58, 633.0, this->samplingRate, 6.28, true);
this->peak[1].RefreshFilter(MultiBiquad::FilterType::PEAK, 0.58, 633.0, this->samplingRate, 6.28, true);
this->harmonic[0].Reset();
this->harmonic[1].Reset();
switch (this->processingModel) {
case 0: {
this->harmonic[0].SetHarmonics(ANALOGX_HARMONICS);
this->harmonic[1].SetHarmonics(ANALOGX_HARMONICS);
this->gain = 0.6;
this->lowPass[0].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 19650.0, this->samplingRate, 0.717, false);
this->lowPass[1].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 19650.0, this->samplingRate, 0.717, false);
break;
}
case 1: {
this->harmonic[0].SetHarmonics(ANALOGX_HARMONICS);
this->harmonic[1].SetHarmonics(ANALOGX_HARMONICS);
this->gain = 1.2;
this->lowPass[0].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 18233.0, this->samplingRate, 0.717, false);
this->lowPass[1].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 18233.0, this->samplingRate, 0.717, false);
break;
}
case 2: {
this->harmonic[0].SetHarmonics(ANALOGX_HARMONICS);
this->harmonic[1].SetHarmonics(ANALOGX_HARMONICS);
this->gain = 2.4;
this->lowPass[0].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 16307.0, this->samplingRate, 0.717, false);
this->lowPass[1].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 16307.0, this->samplingRate, 0.717, false);
break;
}
}
this->freqRange = 0;
}
void AnalogX::SetEnable(bool enable) {
if (this->enable != enable) {
if (!this->enable) {
Reset();
}
this->enable = enable;
}
}
void AnalogX::SetProcessingModel(int processingModel) {
if (this->processingModel != processingModel) {
this->processingModel = processingModel;
Reset();
}
}
void AnalogX::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
Reset();
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <cstdint>
#include "../utils/Harmonic.h"
#include "../utils/MultiBiquad.h"
class AnalogX {
public:
AnalogX();
void Process(float *samples, uint32_t size);
void Reset();
void SetEnable(bool enable);
void SetProcessingModel(int processingModel);
void SetSamplingRate(uint32_t samplingRate);
private:
MultiBiquad highPass[2];
Harmonic harmonic[2];
MultiBiquad lowPass[2];
MultiBiquad peak[2];
float gain;
uint32_t freqRange;
int processingModel;
uint32_t samplingRate;
bool enable;
};

View File

@ -0,0 +1,49 @@
#include "ColorfulMusic.h"
#include "../constants.h"
ColorfulMusic::ColorfulMusic() {
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->enabled = false;
this->stereo3dSurround.SetStereoWiden(0.0);
this->depthSurround.SetSamplingRate(this->samplingRate);
this->depthSurround.SetStrength(0);
}
void ColorfulMusic::Process(float *samples, uint32_t size) {
if (!this->enabled) return;
this->depthSurround.Process(samples, size);
this->stereo3dSurround.Process(samples, size);
}
void ColorfulMusic::Reset() {
this->depthSurround.SetSamplingRate(this->samplingRate);
}
void ColorfulMusic::SetDepthValue(short depthValue) {
this->depthSurround.SetStrength(depthValue);
}
void ColorfulMusic::SetEnable(bool enable) {
if (this->enabled != enable) {
if (!this->enabled) {
Reset();
}
this->enabled = enable;
}
}
void ColorfulMusic::SetMidImageValue(float midImageValue) {
this->stereo3dSurround.SetMiddleImage(midImageValue);
}
void ColorfulMusic::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
this->depthSurround.SetSamplingRate(this->samplingRate);
}
}
void ColorfulMusic::SetWidenValue(float widenValue) {
this->stereo3dSurround.SetStereoWiden(widenValue);
}

View File

@ -0,0 +1,27 @@
#pragma once
#include <cstdint>
#include "../utils/Stereo3DSurround.h"
#include "../utils/DepthSurround.h"
class ColorfulMusic {
public:
ColorfulMusic();
void Process(float *samples, uint32_t size);
void Reset();
void SetDepthValue(short depthValue);
void SetEnable(bool enable);
void SetMidImageValue(float midImageValue);
void SetSamplingRate(uint32_t samplingRate);
void SetWidenValue(float widenValue);
private:
Stereo3DSurround stereo3dSurround;
DepthSurround depthSurround;
uint32_t samplingRate;
bool enabled;
};

View File

@ -0,0 +1,63 @@
#include "Convolver.h"
Convolver::Convolver() {
}
Convolver::~Convolver() {
}
void Convolver::CommitKernelBuffer(uint32_t param_1, uint32_t param_2, uint32_t kernelId) {
}
bool Convolver::GetEnabled() {
return false;
}
uint32_t Convolver::GetKernelID() {
return 0;
}
void Convolver::PrepareKernelBuffer(uint32_t param_1, uint32_t param_2, int32_t kernelId) {
}
uint32_t Convolver::Process(float *source, float *dest, uint32_t frameSize) {
return frameSize;
}
void Convolver::Reset() {
}
void Convolver::SetCrossChannel(float param_1) {
}
void Convolver::SetEnable(bool enabled) {
}
void Convolver::SetKernel(float *param_1, uint32_t param_2) {
}
void Convolver::SetKernel(const char *param_1) {
}
void Convolver::SetKernelBuffer(uint32_t param_1, float *param_2, uint32_t param_3) {
}
void Convolver::SetKernelStereo(float *param_1, float *param_2, uint32_t param_3) {
}
void Convolver::SetSamplingRate(uint32_t param_1) {
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
class Convolver {
public:
Convolver();
~Convolver();
void CommitKernelBuffer(uint32_t param_1, uint32_t param_2, uint32_t kernelId);
bool GetEnabled();
uint32_t GetKernelID();
void PrepareKernelBuffer(uint32_t param_1, uint32_t param_2, int32_t kernelId);
uint32_t Process(float *source, float *dest, uint32_t frameSize);
void Reset();
void SetCrossChannel(float param_1);
void SetEnable(bool enabled);
void SetKernel(float *param_1, uint32_t param_2);
void SetKernel(const char *param_1);
void SetKernelBuffer(uint32_t param_1, float *param_2, uint32_t param_3);
void SetKernelStereo(float *param_1, float *param_2, uint32_t param_3);
void SetSamplingRate(uint32_t param_1);
};

View File

@ -0,0 +1,60 @@
#include "Cure.h"
Cure::Cure() {
this->enabled = false;
Reset();
}
uint16_t Cure::GetCutoff() {
return this->crossfeed.GetCutoff();
}
float Cure::GetFeedback() {
return this->crossfeed.GetFeedback();
}
float Cure::GetLevelDelay() {
return this->crossfeed.GetLevelDelay();
}
struct Crossfeed::Preset Cure::GetPreset() {
return this->crossfeed.GetPreset();
}
void Cure::Process(float *buffer, uint32_t size) {
if (this->enabled) {
this->crossfeed.ProcessFrames(buffer, size);
this->passFilter.ProcessFrames(buffer, size);
}
}
void Cure::Reset() {
this->crossfeed.Reset();
this->passFilter.Reset();
}
void Cure::SetCutoff(uint16_t cutoff) {
this->crossfeed.SetCutoff(cutoff);
}
void Cure::SetEnable(bool enabled) {
if (this->enabled != enabled) {
this->enabled = enabled;
if (enabled) {
Reset();
}
}
}
void Cure::SetFeedback(float feedback) {
this->crossfeed.SetFeedback(feedback);
}
void Cure::SetPreset(struct Crossfeed::Preset preset) {
this->crossfeed.SetPreset(preset);
}
void Cure::SetSamplingRate(uint32_t samplingRate) {
this->crossfeed.SetSamplingRate(samplingRate);
this->passFilter.SetSamplingRate(samplingRate);
}

27
src/viper/effects/Cure.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <cstdint>
#include "../utils/Crossfeed.h"
#include "../utils/PassFilter.h"
class Cure {
public:
Cure();
uint16_t GetCutoff();
float GetFeedback();
float GetLevelDelay();
struct Crossfeed::Preset GetPreset();
void Process(float *buffer, uint32_t size);
void Reset();
void SetCutoff(uint16_t cutoff);
void SetEnable(bool enabled);
void SetFeedback(float feedback);
void SetPreset(struct Crossfeed::Preset preset);
void SetSamplingRate(uint32_t samplingRate);
private:
Crossfeed crossfeed;
PassFilter passFilter;
bool enabled;
};

View File

@ -0,0 +1,73 @@
#include <cstring>
#include "DiffSurround.h"
#include "../constants.h"
DiffSurround::DiffSurround() {
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->delayTime = 0.0f;
this->enabled = false;
for (auto &buffer : this->buffers) {
buffer = new WaveBuffer(1, 0x1000);
}
Reset();
}
DiffSurround::~DiffSurround() {
for (auto &buffer : this->buffers) {
delete buffer;
}
}
void DiffSurround::Process(float *samples, uint32_t size) {
float *bufs[2];
float *outbufs[2];
if (this->enabled) {
bufs[0] = this->buffers[0]->PushZerosGetBuffer(size);
bufs[1] = this->buffers[1]->PushZerosGetBuffer(size);
for (uint32_t i = 0; i < size * 2; i++) {
bufs[i % 2][i / 2] = samples[i];
}
outbufs[0] = this->buffers[0]->GetBuffer();
outbufs[1] = this->buffers[1]->GetBuffer();
for (uint32_t i = 0; i < size * 2; i++) {
samples[i] = outbufs[i % 2][i / 2];
}
this->buffers[0]->PopSamples(size, false);
this->buffers[1]->PopSamples(size, false);
}
}
void DiffSurround::Reset() {
this->buffers[0]->Reset();
this->buffers[1]->Reset();
this->buffers[1]->PushZeros((uint32_t) ((double) this->delayTime / 1000.0 * (double) this->samplingRate));
}
void DiffSurround::SetDelayTime(float delayTime) {
if (this->delayTime != delayTime) {
this->delayTime = delayTime;
this->Reset();
}
}
void DiffSurround::SetEnable(bool enabled) {
if (this->enabled != enabled) {
if (!this->enabled) {
Reset();
}
this->enabled = enabled;
}
}
void DiffSurround::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
this->Reset();
}
}

View File

@ -0,0 +1,23 @@
#pragma once
#include <cstdint>
#include "../utils/WaveBuffer.h"
class DiffSurround {
public:
DiffSurround();
~DiffSurround();
void Process(float *samples, uint32_t size);
void Reset();
void SetDelayTime(float delayTime);
void SetEnable(bool enabled);
void SetSamplingRate(uint32_t samplingRate);
uint32_t samplingRate;
bool enabled;
float delayTime;
WaveBuffer *buffers[2];
};

View File

@ -0,0 +1,52 @@
#include "DynamicSystem.h"
#include "../constants.h"
DynamicSystem::DynamicSystem() {
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->enable = false;
this->dynamicBass.SetSamplingRate(this->samplingRate);
this->dynamicBass.Reset();
}
void DynamicSystem::Process(float *samples, uint32_t size) {
if (!this->enable) return;
this->dynamicBass.FilterSamples(samples, size);
}
void DynamicSystem::Reset() {
this->dynamicBass.SetSamplingRate(this->samplingRate);
this->dynamicBass.Reset();
}
void DynamicSystem::SetBassGain(float gain) {
this->dynamicBass.SetBassGain(gain);
}
void DynamicSystem::SetEnable(bool enable) {
if (this->enable != enable) {
if (!this->enable) {
Reset();
}
this->enable = enable;
}
}
void DynamicSystem::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
this->dynamicBass.SetSamplingRate(samplingRate);
}
}
void DynamicSystem::SetSideGain(float gainX, float gainY) {
this->dynamicBass.SetSideGain(gainX, gainY);
}
void DynamicSystem::SetXCoeffs(uint32_t low, uint32_t high) {
this->dynamicBass.SetFilterXPassFrequency(low, high);
}
void DynamicSystem::SetYCoeffs(uint32_t low, uint32_t high) {
this->dynamicBass.SetFilterYPassFrequency(low, high);
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
#include "../utils/DynamicBass.h"
class DynamicSystem {
public:
DynamicSystem();
void Process(float *samples, uint32_t size);
void Reset();
void SetBassGain(float gain);
void SetEnable(bool enable);
void SetSamplingRate(uint32_t samplingRate);
void SetSideGain(float gainX, float gainY);
void SetXCoeffs(uint32_t low, uint32_t high);
void SetYCoeffs(uint32_t low, uint32_t high);
private:
DynamicBass dynamicBass;
uint32_t samplingRate;
bool enable;
};

View File

@ -0,0 +1,267 @@
#include <cmath>
#include "FETCompressor.h"
#include "../constants.h"
static const float DEFAULT_FETCOMP_PARAMETERS[] = {
1.000000,
0.000000,
0.000000,
0.000000,
1.000000,
0.000000,
1.000000,
0.514679,
1.000000,
0.384311,
1.000000,
0.500000,
0.879450,
0.884311,
0.615689,
0.660964,
1.000000
};
static double calculate_exp_something(double param_1, double param_2) {
return 1.0 - exp(-1.0 / (param_2 * param_1));
}
FETCompressor::FETCompressor() {
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
for (uint32_t i = 0; i < 17; i++) {
SetParameter((FETCompressor::Parameter) i, GetParameterDefault((FETCompressor::Parameter) i));
}
Reset();
}
float FETCompressor::GetMeter(int param_1) {
if (param_1 != 0) {
return 0.0;
}
if (this->enable) {
float tmp = (6.907755 - this->unk28) / 6.907755;
if (tmp < 1.0) {
if (tmp < 0.0) {
tmp = 0.0;
}
return tmp;
}
}
return 1.0;
}
float FETCompressor::GetParameter(FETCompressor::Parameter parameter) {
return this->parameters[parameter];
}
float FETCompressor::GetParameterDefault(FETCompressor::Parameter parameter) {
if (parameter < 17) {
return DEFAULT_FETCOMP_PARAMETERS[parameter];
}
return 0.0;
}
void FETCompressor::Process(float *samples, uint32_t size) {
return;
if (size == 0) return;
for (uint32_t i = 0; i < size * 2; i += 2) {
double inL = abs(samples[i]);
double inR = abs(samples[i + 1]);
double in;
if (inL > inR) {
in = inL;
} else {
in = inR;
}
double out = ProcessSidechain(in);
if (this->enable) {
samples[i] *= (float) out;
samples[i + 1] *= (float) out;
}
this->unk23 = this->unk23 + (this->threshold - this->unk23) * this->unk22;
this->unk24 = this->unk24 + this->unk22 * (this->gain - this->unk24);
}
}
double FETCompressor::ProcessSidechain(double in) {
double in2 = pow(in, 2.0);
if (in2 < 0.000001) {
in2 = 0.000001;
}
float a = this->attack2;
float b = this->unk25 + this->crest2 * (in2 - this->unk25);
float c = this->unk26 + this->crest2 * (in2 - this->unk26);
float d = this->attack1;
if (in2 < b) {
in2 = b;
}
this->unk26 = c;
this->unk25 = in2;
in2 /= c;
if (this->autoAttack) {
}
if (this->autoRelease) {
}
if (in >= 0.000001) {
}
if (!this->autoKnee) {
} else {
}
if (this->autoGain) {
if (!this->noClip) {
} else {
}
// return exp(-a - fVar6); // FIXME: Change "a" and "fVar6" variable
}
return exp(this->unk24 - a); // FIXME: Change "a" variable
}
void FETCompressor::Reset() {
this->unk22 = calculate_exp_something(this->samplingRate, 0.05);
this->unk23 = this->threshold;
this->unk24 = this->gain;
this->unk25 = 0.000001;
this->unk26 = 0.000001;
this->unk27 = 0.0;
this->unk28 = 0.0;
this->unk29 = 0.0;
}
void FETCompressor::SetParameter(FETCompressor::Parameter parameter, float value) {
this->parameters[parameter] = value;
switch (parameter) {
case ENABLE: {
this->enable = value >= 0.5;
break;
}
case THRESHOLD: {
this->threshold = log(pow(10.0, (value * -60.0) / 20.0));
break;
}
case RATIO: {
this->ratio = -value;
break;
}
case KNEE: {
this->knee = log(pow(10.0, (value * 60.0) / 20));
break;
}
case AUTO_KNEE: {
this->autoKnee = value >= 0.5;
break;
}
case GAIN: {
this->gain = log(pow(10.0, (value * 60.0) / 20.0));
break;
}
case AUTO_GAIN: {
this->autoGain = value >= 0.5;
break;
}
case ATTACK: {
double tmp = exp(value * 7.600903 - 9.21034);
this->attack1 = tmp;
if (tmp <= 0.0) {
tmp = 1.0;
} else {
tmp = calculate_exp_something(this->samplingRate, tmp);
}
this->attack2 = tmp;
break;
}
case AUTO_ATTACK: {
this->autoAttack = value >= 0.5;
break;
}
case RELEASE: {
double tmp = exp(value * 5.991465 - 5.298317);
this->release1 = tmp;
if (tmp <= 0.0) {
tmp = 1.0;
} else {
tmp = calculate_exp_something(this->samplingRate, tmp);
}
this->release2 = tmp;
break;
}
case AUTO_RELEASE: {
this->autoRelease = value >= 0.5;
break;
}
case KNEE_MULTI: {
this->kneeMulti = value * 4.0;
break;
}
case MAX_ATTACK: {
this->maxAttack = exp(value * 7.600903 - 9.21034);
break;
}
case MAX_RELEASE: {
this->maxRelease = exp(value * 5.991465 - 5.298317);
break;
}
case CREST: {
double tmp = exp(value * 5.991465 - 5.298317);
this->crest1 = tmp;
if (tmp <= 0.0) {
tmp = 1.0;
} else {
tmp = calculate_exp_something(this->samplingRate, tmp);
}
this->crest2 = tmp;
break;
}
case ADAPT: {
double tmp = exp(value * 1.386294);
this->adapt1 = tmp;
if (tmp <= 0.0) {
tmp = 1.0;
} else {
tmp = calculate_exp_something(this->samplingRate, tmp);
}
this->adapt2 = tmp;
break;
}
case NO_CLIP: {
this->noClip = value >= 0.5;
break;
}
}
}
void FETCompressor::SetSamplingRate(uint32_t samplingRate) {
this->samplingRate = samplingRate;
for (uint32_t i = 0; i < 17; i++) {
SetParameter((FETCompressor::Parameter) i, GetParameter((FETCompressor::Parameter) i));
}
Reset();
}

View File

@ -0,0 +1,72 @@
#pragma once
#include <cstdint>
class FETCompressor {
public:
enum Parameter {
ENABLE = 0,
THRESHOLD,
RATIO,
KNEE,
AUTO_KNEE,
GAIN,
AUTO_GAIN,
ATTACK,
AUTO_ATTACK,
RELEASE,
AUTO_RELEASE,
KNEE_MULTI,
MAX_ATTACK,
MAX_RELEASE,
CREST,
ADAPT,
NO_CLIP
};
FETCompressor();
float GetMeter(int param_1);
float GetParameter(FETCompressor::Parameter parameter);
float GetParameterDefault(FETCompressor::Parameter parameter);
void Process(float *samples, uint32_t size);
double ProcessSidechain(double in);
void Reset();
void SetParameter(FETCompressor::Parameter parameter, float value);
void SetSamplingRate(uint32_t samplingRate);
private:
uint32_t samplingRate;
float parameters[17];
float unk22;
bool enable;
bool autoKnee;
bool autoGain;
bool autoAttack;
bool autoRelease;
float unk27;
float unk28;
float unk29;
float unk23;
float threshold;
float knee;
float unk24;
float gain;
float ratio;
float unk25;
float unk26;
float attack1;
float attack2;
float release1;
float release2;
float kneeMulti;
float maxAttack;
float maxRelease;
float crest1;
float crest2;
float adapt1;
float adapt2;
float noClip;
};

View File

@ -0,0 +1,2 @@
#include "FIREqualizer.h"
#include <cstring>

View File

@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
class FIREqualizer {
public:
FIREqualizer();
~FIREqualizer();
};

View File

@ -0,0 +1,91 @@
#include <cmath>
#include <cstring>
#include "IIRFilter.h"
#include "../constants.h"
IIRFilter::IIRFilter(uint32_t bands) {
this->enable = false;
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
if (bands == 10 || bands == 15 || bands == 25 || bands == 31) {
this->bands = bands;
this->minPhaseIirCoeffs.UpdateCoeffs(this->bands, this->samplingRate);
} else {
this->bands = 0;
}
for (auto &bandLevelWithQ : this->bandLevelsWithQ) {
bandLevelWithQ = 0.636;
}
Reset();
}
void IIRFilter::Process(float *samples, uint32_t size) {
if (!this->enable) return;
double *coeffs = this->minPhaseIirCoeffs.GetCoefficients();
if (coeffs == nullptr || size == 0) return;
for (uint32_t i = 0; i < size; i++) {
for (uint32_t j = 0; j < 2; j++) {
double sample = samples[i * 2 + j];
double accumulated = 0.0;
for (uint32_t k = 0; k < this->bands; k++) {
uint32_t bufIdx = this->unknown2 + j * 8 + k * 16;
this->buf[bufIdx] = sample;
double coeff1 = coeffs[k * 4];
double coeff2 = coeffs[k * 4 + 1];
double coeff3 = coeffs[k * 4 + 2];
double a = coeff3 * this->buf[bufIdx + ((this->unknown3 + 3) - this->unknown2)];
double b = coeff2 * (sample - this->buf[bufIdx + (unknown4 - unknown2)]);
double c = coeff1 * this->buf[bufIdx + ((unknown4 - unknown2) + 3)];
double tmp = (a + b) - c;
this->buf[bufIdx + 3] = tmp;
accumulated += tmp * this->bandLevelsWithQ[k];
}
samples[i * 2 + j] = (float) accumulated;
}
this->unknown2 = (this->unknown2 + 1) % 3;
this->unknown3 = (this->unknown3 + 1) % 3;
this->unknown4 = (this->unknown4 + 1) % 3;
}
}
void IIRFilter::Reset() {
memset(this->buf,0,sizeof(buf));
this->unknown2 = 2;
this->unknown3 = 1;
this->unknown4 = 0;
}
void IIRFilter::SetBandLevel(uint32_t band, float level) {
if (band > 30) return;
double bandLevel = pow(10.0, level / 20.0);
this->bandLevelsWithQ[band] = (float) (bandLevel * 0.636);
}
void IIRFilter::SetEnable(bool enable) {
if (this->enable != enable) {
this->enable = enable;
if (enable) {
this->Reset();
}
}
}
void IIRFilter::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
if (this->bands != 0) {
this->minPhaseIirCoeffs.UpdateCoeffs(this->bands, this->samplingRate);
}
this->Reset();
}
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
#include "../utils/MinPhaseIIRCoeffs.h"
class IIRFilter {
public:
IIRFilter(uint32_t bands);
void Process(float *samples, uint32_t size);
void Reset();
void SetBandLevel(uint32_t band, float level);
void SetEnable(bool enable);
void SetSamplingRate(uint32_t samplingRate);
private:
uint32_t bands;
uint32_t samplingRate;
bool enable;
MinPhaseIIRCoeffs minPhaseIirCoeffs;
double buf[496];
uint32_t unknown2;
uint32_t unknown3;
uint32_t unknown4;
float bandLevelsWithQ[31];
};

View File

@ -0,0 +1,62 @@
#include "PlaybackGain.h"
#include "../constants.h"
PlaybackGain::PlaybackGain() {
this->enable = false;
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->unknown1 = 0.4342945;
this->counterTo100 = 0;
this->ratio1 = 2.0;
this->ratio2 = 0.5;
this->volume = 1.0;
this->maxGainFactor = 1.0;
this->unknown2 = 1.0;
this->unknown3 = 1.0;
this->biquad1.SetBandPassParameter(2200.0,this->samplingRate,0.33);
this->biquad2.SetBandPassParameter(2200.0,this->samplingRate,0.33);
}
PlaybackGain::~PlaybackGain() {
}
void PlaybackGain::AnalyseWave() {
}
void PlaybackGain::Process(float *samples, uint32_t size) {
}
void PlaybackGain::Reset() {
this->biquad1.SetBandPassParameter(2200.0,this->samplingRate,0.33);
this->biquad2.SetBandPassParameter(2200.0,this->samplingRate,0.33);
this->unknown2 = 1.0;
this->counterTo100 = 0;
this->unknown3 = 1.0;
}
void PlaybackGain::SetEnable(bool enable) {
this->enable = enable;
if (enable) {
Reset();
}
}
void PlaybackGain::SetMaxGainFactor(float maxGainFactor) {
this->maxGainFactor = maxGainFactor;
}
void PlaybackGain::SetRatio(float ratio) {
this->ratio1 = ratio + 1.0f;
this->ratio2 = 1.0f / (ratio + 1.0f);
}
void PlaybackGain::SetSamplingRate(uint32_t samplingRate) {
this->samplingRate = samplingRate;
Reset();
}
void PlaybackGain::SetVolume(float volume) {
this->volume = volume;
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <cstdint>
#include "../utils/Biquad.h"
class PlaybackGain {
public:
PlaybackGain();
~PlaybackGain();
void AnalyseWave();
void Process(float *samples, uint32_t size);
void Reset();
void SetEnable(bool enable);
void SetMaxGainFactor(float maxGainFactor);
void SetRatio(float ratio);
void SetSamplingRate(uint32_t samplingRate);
void SetVolume(float volume);
private:
float ratio2;
float unknown1;
uint32_t counterTo100;
float ratio1;
float volume;
float maxGainFactor;
float unknown2;
float unknown3;
Biquad biquad1;
Biquad biquad2;
uint32_t samplingRate;
bool enable;
};

View File

@ -0,0 +1,52 @@
#include "Reverberation.h"
#include "../constants.h"
Reverberation::Reverberation() {
this->model.SetRoomSize(0.0);
this->model.SetWidth(0.0);
this->model.SetDamp(0.0);
this->model.SetWet(0.0);
this->model.SetDry(0.5);
this->model.Reset();
this->enable = false;
}
void Reverberation::Process(float *buffer, uint32_t size) {
if (this->enable) {
this->model.ProcessReplace(buffer, buffer + 1, size);
}
}
void Reverberation::Reset() {
this->model.Reset();
}
void Reverberation::SetDamp(float value) {
this->model.SetDamp(value);
}
void Reverberation::SetDry(float value) {
this->model.SetDry(value);
}
void Reverberation::SetEnable(bool enable) {
if (this->enable != enable) {
if (!this->enable) {
Reset();
}
this->enable = enable;
}
}
void Reverberation::SetRoomSize(float value) {
this->model.SetRoomSize(value);
}
void Reverberation::SetWet(float value) {
this->model.SetWet(value);
}
void Reverberation::SetWidth(float value) {
this->model.SetWidth(value);
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
#include "../utils/CRevModel.h"
class Reverberation {
public:
Reverberation();
void Process(float *buffer, uint32_t size);
void Reset();
void SetDamp(float value);
void SetDry(float value);
void SetEnable(bool enable);
void SetRoomSize(float value);
void SetWet(float value);
void SetWidth(float value);
private:
CRevModel model;
bool enable;
};

View File

@ -0,0 +1,29 @@
#include <cstring>
#include "SoftwareLimiter.h"
SoftwareLimiter::SoftwareLimiter() {
this->ready = false;
this->unknown4 = 0;
this->unknown2 = 1.0;
this->gate = 0.999999;
this->unknown3 = 1.0;
this->unknown1 = 1.0;
this->ResetLimiter();
}
float SoftwareLimiter::Process(float sample) {
return sample;
}
void SoftwareLimiter::ResetLimiter() {
memset(this->arr256, 0, 256);
memset(this->arr512, 0, 512);
this->ready = false;
this->unknown4 = 0;
this->unknown2 = 1.0;
this->unknown3 = 1.0;
}
void SoftwareLimiter::SetGate(float gate) {
this->gate = gate;
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <cstdint>
class SoftwareLimiter {
public:
SoftwareLimiter();
float Process(float sample);
void ResetLimiter();
void SetGate(float gate);
private:
float gate;
float unknown1;
float unknown2;
float unknown3;
float arr256[256];
float arr512[512];
uint32_t unknown4;
bool ready;
};

View File

@ -0,0 +1,58 @@
#include "SpeakerCorrection.h"
#include "../constants.h"
SpeakerCorrection::SpeakerCorrection() {
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->enable = false;
Reset();
}
void SpeakerCorrection::Process(float *samples, uint32_t size) {
if (!this->enable) return;
for (uint32_t i = 0; i < size * 2; i += 2) {
double outL = samples[i];
outL = this->lowPass[0].ProcessSample(outL);
outL = this->highPass[0].ProcessSample(outL);
outL /= 2.0;
outL += this->bandPass[0].ProcessSample(outL);
samples[i] = (float) outL;
double outR = samples[i + 1];
outR = this->lowPass[1].ProcessSample(outR);
outR = this->highPass[1].ProcessSample(outR);
outR /= 2.0;
outR += this->bandPass[1].ProcessSample(outR);
samples[i + 1] = (float) outR;
}
}
void SpeakerCorrection::Reset() {
this->lowPass[0].Reset();
this->lowPass[1].Reset();
this->bandPass[0].Reset();
this->bandPass[1].Reset();
this->highPass[0].RefreshFilter(MultiBiquad::FilterType::HIGH_PASS, 0.0, 80.0, this->samplingRate, 1.0, false);
this->highPass[1].RefreshFilter(MultiBiquad::FilterType::HIGH_PASS, 0.0, 80.0, this->samplingRate, 1.0, false);
this->lowPass[0].SetLowPassParameter(13500.0, this->samplingRate, 1.0);
this->lowPass[1].SetLowPassParameter(13500.0, this->samplingRate, 1.0);
this->bandPass[0].SetBandPassParameter(420.0, this->samplingRate, 3.88);
this->bandPass[1].SetBandPassParameter(420.0, this->samplingRate, 3.88);
}
void SpeakerCorrection::SetEnable(bool enable) {
if (this->enable != enable) {
if (!this->enable) {
Reset();
}
this->enable = enable;
}
}
void SpeakerCorrection::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
Reset();
}
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <cstdint>
#include "../utils/MultiBiquad.h"
#include "../utils/Biquad.h"
class SpeakerCorrection {
public:
SpeakerCorrection();
void Process(float *samples, uint32_t size);
void Reset();
void SetEnable(bool enable);
void SetSamplingRate(uint32_t samplingRate);
private:
uint32_t samplingRate;
bool enable;
MultiBiquad highPass[2];
Biquad lowPass[2];
Biquad bandPass[2];
};

View File

@ -0,0 +1,82 @@
#include "SpectrumExtend.h"
#include "../constants.h"
static const 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->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->referenceFreq = 7600;
this->enabled = false;
this->exciter = 0.f;
Reset();
}
SpectrumExtend::~SpectrumExtend() {
// empty?
}
void SpectrumExtend::Process(float *samples, uint32_t size) {
if (this->enabled) {
for (uint32_t 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(MultiBiquad::FilterType::HIGH_PASS, 0.0, (float) this->referenceFreq, (float) this->samplingRate,
0.717, false);
this->highpass[1].RefreshFilter(MultiBiquad::FilterType::HIGH_PASS, 0.0, (float) this->referenceFreq, (float) this->samplingRate,
0.717, false);
this->lowpass[0].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, (float) this->referenceFreq / 2.f - 2000.f,
(float) this->referenceFreq, 0.717, false);
this->lowpass[1].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 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->samplingRate / 2 - 100 < freq) {
freq = this->samplingRate / 2 - 100;
}
this->referenceFreq = freq;
Reset();
}
void SpectrumExtend::SetSamplingRate(uint32_t samplingRate) {
this->samplingRate = samplingRate;
if (this->samplingRate / 2 - 100 < this->referenceFreq) {
this->referenceFreq = this->samplingRate / 2 - 100;
}
Reset();
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
#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 samplingRate);
MultiBiquad highpass[2];
MultiBiquad lowpass[2];
Harmonic harmonics[2];
bool enabled;
uint32_t samplingRate;
uint32_t referenceFreq;
float exciter;
};

View File

@ -0,0 +1,37 @@
#include "TubeSimulator.h"
TubeSimulator::TubeSimulator() {
this->acc[0] = 0.f;
this->acc[1] = 0.f;
this->enable = false;
}
void TubeSimulator::Reset() {
this->acc[0] = 0.f;
this->acc[1] = 0.f;
this->enable = false;
}
void TubeSimulator::SetEnable(bool enable) {
if (this->enable != enable) {
if (!this->enable) {
Reset();
}
this->enable = enable;
}
}
void TubeSimulator::TubeProcess(float *buffer, uint32_t size) {
if (this->enable) {
for (uint32_t x = 0; x < size; x++) {
this->acc[0] = (this->acc[0] + buffer[2 * x]) / 2.f;
this->acc[1] = (this->acc[1] + buffer[2 * x + 1]) / 2.f;
buffer[2 * x] = this->acc[0];
buffer[2 * x + 1] = this->acc[1];
}
}
}
TubeSimulator::~TubeSimulator() {
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <cstdint>
class TubeSimulator {
public:
TubeSimulator();
~TubeSimulator();
void Reset();
void SetEnable(bool enable);
void TubeProcess(float *buffer, uint32_t size);
private:
float acc[2];
bool enable;
};

61
src/viper/effects/VHE.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "VHE.h"
#include "../constants.h"
VHE::VHE() {
enabled = false;
effectLevel = 0;
convSize = 0;
samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
bufA = new WaveBuffer(2, 0x1000);
bufB = new WaveBuffer(2, 0x1000);
Reset();
}
VHE::~VHE() {
delete bufA;
delete bufB;
}
uint32_t VHE::Process(float *source, float *dest, uint32_t frameSize) {
if (enabled && convLeft.InstanceUsable() && convRight.InstanceUsable()) {
if (bufA->PushSamples(source, frameSize) != 0) {
while (bufA->GetBufferOffset() > convSize) {
float *buffer = bufA->GetBuffer();
convLeft.ConvolveInterleaved(buffer, 0);
convRight.ConvolveInterleaved(buffer, 1);
bufB->PushSamples(buffer, convSize);
bufA->PopSamples(convSize, true);
}
return bufB->PopSamples(dest, frameSize, false);
}
}
return frameSize;
}
void VHE::Reset() {
// TODO
}
bool VHE::GetEnabled() {
return enabled;
}
void VHE::SetEffectLevel(uint32_t level) {
if (level < 5) {
this->effectLevel = level;
Reset();
}
}
void VHE::SetEnable(bool enabled) {
this->enabled = enabled;
if (enabled) {
Reset();
}
}
void VHE::SetSamplingRate(uint32_t srate) {
this->samplingRate = srate;
Reset();
}

27
src/viper/effects/VHE.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include <cstdint>
#include "../utils/PConvSingle_F32.h"
#include "../utils/WaveBuffer.h"
class VHE {
public:
VHE();
~VHE();
bool GetEnabled();
uint32_t Process(float *source, float *dest, uint32_t frameSize);
void Reset();
void SetEffectLevel(uint32_t level);
void SetEnable(bool enabled);
void SetSamplingRate(uint32_t srate);
PConvSingle_F32 convLeft, convRight;
WaveBuffer *bufA, *bufB;
uint32_t samplingRate;
bool enabled;
int effectLevel;
int convSize;
};

View File

@ -0,0 +1,140 @@
#include "ViPERBass.h"
#include "../constants.h"
ViPERBass::ViPERBass() {
this->enable = false;
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->speaker = 60;
this->samplingRatePeriod = 1.0 / VIPER_DEFAULT_SAMPLING_RATE;
this->antiPop = 0.0;
this->processMode = ProcessMode::NATURAL_BASS;
this->bassFactor = 0.0;
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((float) this->speaker, this->samplingRate, 0.53);
this->subwoofer->SetBassGain(this->samplingRate, 0.0);
this->Reset();
}
ViPERBass::~ViPERBass() {
delete this->polyphase;
delete this->biquad;
delete this->subwoofer;
delete this->waveBuffer;
}
void ViPERBass::Process(float *samples, uint32_t size) {
if (!this->enable) {
return;
}
if (size == 0) {
return;
}
if (this->antiPop < 1.0) {
for (uint32_t i = 0; i < size * 2; i += 2) {
samples[i] *= this->antiPop;
samples[i + 1] *= this->antiPop;
float x = this->antiPop + this->samplingRatePeriod;
if (x > 1.0) {
x = 1.0;
}
this->antiPop = x;
}
}
switch (this->processMode) {
case ProcessMode::NATURAL_BASS: {
for (uint32_t i = 0; i < size * 2; i += 2) {
double sample = ((double) samples[i] + (double) samples[i + 1]) / 2.0;
float x = (float) this->biquad->ProcessSample(sample) * this->bassFactor;
samples[i] += x;
samples[i + 1] += x;
}
break;
}
case ProcessMode::PURE_BASS_PLUS: {
if (this->waveBuffer->PushSamples(samples, size)) {
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 * 2; i += 2) {
float x = buffer[i / 2] * this->bassFactor;
samples[i] += x;
samples[i + 1] += x;
}
this->waveBuffer->PopSamples(size, true);
}
}
break;
}
case ProcessMode::SUBWOOFER: {
this->subwoofer->Process(samples, size);
break;
}
}
}
void ViPERBass::Reset() {
this->polyphase->SetSamplingRate(this->samplingRate);
this->polyphase->Reset();
this->waveBuffer->Reset();
this->waveBuffer->PushZeros(this->polyphase->GetLatency());
this->subwoofer->SetBassGain(this->samplingRate, this->bassFactor * 2.5f);
this->biquad->SetLowPassParameter((float) this->speaker, this->samplingRate, 0.53);
this->samplingRatePeriod = 1.0f / (float) this->samplingRate;
this->antiPop = 0.0f;
}
void ViPERBass::SetBassFactor(float bassFactor) {
if (this->bassFactor != bassFactor) {
this->bassFactor = bassFactor;
this->subwoofer->SetBassGain(this->samplingRate, this->bassFactor * 2.5f);
}
}
void ViPERBass::SetEnable(bool enable) {
if (this->enable != enable) {
if (!this->enable) {
Reset();
}
this->enable = enable;
}
}
void ViPERBass::SetProcessMode(ProcessMode processMode) {
if (this->processMode != processMode) {
this->processMode = processMode;
this->Reset();
}
}
void ViPERBass::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
this->samplingRatePeriod = 1.0f / (float) samplingRate;
this->polyphase->SetSamplingRate(this->samplingRate);
this->biquad->SetLowPassParameter((float) this->speaker, this->samplingRate, 0.53);
this->subwoofer->SetBassGain(this->samplingRate, this->bassFactor * 2.5f);
}
}
void ViPERBass::SetSpeaker(uint32_t speaker) {
if (this->speaker != speaker) {
this->speaker = speaker;
this->biquad->SetLowPassParameter((float) this->speaker, this->samplingRate, 0.53);
}
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <cstdint>
#include "../utils/Biquad.h"
#include "../utils/Subwoofer.h"
#include "../utils/WaveBuffer.h"
#include "../utils/Polyphase.h"
class ViPERBass {
public:
enum ProcessMode {
NATURAL_BASS = 0,
PURE_BASS_PLUS = 1,
SUBWOOFER = 2,
};
ViPERBass();
~ViPERBass();
void Process(float *samples, uint32_t size);
void Reset();
void SetBassFactor(float bassFactor);
void SetEnable(bool enable);
void SetProcessMode(ProcessMode processMode);
void SetSamplingRate(uint32_t samplingRate);
void SetSpeaker(uint32_t speaker);
private:
Polyphase *polyphase;
Biquad *biquad;
Subwoofer *subwoofer;
WaveBuffer *waveBuffer;
bool enable;
ProcessMode processMode;
uint32_t samplingRate;
float samplingRatePeriod;
float antiPop;
uint32_t speaker;
float bassFactor;
};

View File

@ -0,0 +1,90 @@
#include "ViPERClarity.h"
#include "../constants.h"
ViPERClarity::ViPERClarity() {
for (auto &highShelf : this->highShelf) {
highShelf.SetFrequency(12000.0);
highShelf.SetGain(1.0);
highShelf.SetSamplingRate(VIPER_DEFAULT_SAMPLING_RATE);
}
this->enable = false;
this->processMode = ClarityMode::NATURAL;
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->clarityGainPercent = 0.0;
Reset();
}
void ViPERClarity::Process(float *samples, uint32_t size) {
if (!this->enable) {
return;
}
switch (this->processMode) {
case ClarityMode::NATURAL: {
this->noiseSharpening.Process(samples, size);
break;
}
case ClarityMode::OZONE: {
for (uint32_t i = 0; i < size * 2; i++) {
samples[i] = (float) this->highShelf[i % 2].Process(samples[i]);
}
break;
}
case ClarityMode::XHIFI: {
this->hifi.Process(samples, size);
break;
}
}
}
void ViPERClarity::Reset() {
this->noiseSharpening.SetSamplingRate(this->samplingRate);
this->noiseSharpening.Reset();
this->SetClarityToFilter();
for (auto &highShelf : this->highShelf) {
highShelf.SetFrequency(8250.0);
highShelf.SetSamplingRate(this->samplingRate);
}
this->hifi.SetSamplingRate(this->samplingRate);
this->hifi.Reset();
}
void ViPERClarity::SetClarity(float gainPercent) {
this->clarityGainPercent = gainPercent;
if (this->processMode != ClarityMode::OZONE) {
this->SetClarityToFilter();
} else {
Reset();
}
}
void ViPERClarity::SetClarityToFilter() {
this->noiseSharpening.SetGain(this->clarityGainPercent);
this->highShelf[0].SetGain(this->clarityGainPercent + 1.0f);
this->highShelf[1].SetGain(this->clarityGainPercent + 1.0f);
this->hifi.SetClarity(this->clarityGainPercent + 1.0f);
}
void ViPERClarity::SetEnable(bool enable) {
if (this->enable != enable) {
if (!this->enable) {
Reset();
}
this->enable = enable;
}
}
void ViPERClarity::SetProcessMode(ClarityMode processMode) {
if (this->processMode != processMode) {
this->processMode = processMode;
Reset();
}
}
void ViPERClarity::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
Reset();
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <cstdint>
#include "../utils/NoiseSharpening.h"
#include "../utils/HiFi.h"
#include "../utils/HighShelf.h"
class ViPERClarity {
public:
enum ClarityMode {
NATURAL,
OZONE,
XHIFI
};
ViPERClarity();
void Process(float *samples, uint32_t size);
void Reset();
void SetClarity(float gainPercent);
void SetClarityToFilter();
void SetEnable(bool enable);
void SetProcessMode(ClarityMode processMode);
void SetSamplingRate(uint32_t samplingRate);
private:
NoiseSharpening noiseSharpening;
HighShelf highShelf[2];
HiFi hifi;
bool enable;
ClarityMode processMode;
uint32_t samplingRate;
float clarityGainPercent;
};

View File

@ -0,0 +1,33 @@
#include "ViPERDDC.h"
ViPERDDC::ViPERDDC() {
}
ViPERDDC::~ViPERDDC() {
}
void ViPERDDC::Process(float *samples, uint32_t size) {
}
void ViPERDDC::ReleaseResources() {
}
void ViPERDDC::Reset() {
}
void ViPERDDC::SetCoeffs() {
}
void ViPERDDC::SetEnable(bool enable) {
}
void ViPERDDC::SetSamplingRate(uint32_t samplingRate) {
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <cstdint>
class ViPERDDC {
public:
ViPERDDC();
~ViPERDDC();
void Process(float *samples, uint32_t size);
void ReleaseResources();
void Reset();
void SetCoeffs();
void SetEnable(bool enable);
void SetSamplingRate(uint32_t samplingRate);
};

View File

@ -0,0 +1,117 @@
#include <cstring>
#include "AdaptiveBuffer.h"
AdaptiveBuffer::AdaptiveBuffer(uint32_t channels, uint32_t length) {
this->channels = channels;
this->buffer = nullptr;
this->length = 0;
this->offset = 0;
if (channels != 0) {
this->buffer = new float[channels * length];
this->length = length;
}
}
AdaptiveBuffer::~AdaptiveBuffer() {
delete this->buffer;
}
void AdaptiveBuffer::FlushBuffer() {
this->offset = 0;
}
uint32_t AdaptiveBuffer::GetBufferLength() const {
return this->length;
}
uint32_t AdaptiveBuffer::GetBufferOffset() const {
return this->offset;
}
float *AdaptiveBuffer::GetBuffer() const {
return this->buffer;
}
uint32_t AdaptiveBuffer::GetChannels() const {
return this->channels;
}
void AdaptiveBuffer::PanFrames(float left, float right) {
if (this->buffer != nullptr && this->channels == 2) {
for (uint32_t i = 0; i < this->offset * this->channels; i++) {
if (i % 2 == 0) {
this->buffer[i] = this->buffer[i] * left;
} else {
this->buffer[i] = this->buffer[i] * right;
}
}
}
}
int AdaptiveBuffer::PopFrames(float *frames, uint32_t length) {
if (this->buffer == nullptr || this->offset < length) {
return 0;
}
if (length != 0) {
memcpy(frames, this->buffer, length * this->channels * sizeof(*frames));
this->offset = this->offset - length;
if (this->offset != 0) {
memmove(this->buffer, this->buffer + (length * this->channels), this->offset * this->channels * sizeof(float));
}
}
return 1;
}
int AdaptiveBuffer::PushFrames(const float *frames, uint32_t length) {
if (this->buffer == nullptr) {
return 0;
}
if (length != 0) {
if (this->offset + length > this->length) {
auto tmp = new float[(this->offset + length) * this->channels];
memcpy(tmp, this->buffer, this->offset * this->channels * sizeof(float));
delete this->buffer;
this->buffer = tmp;
this->length = this->offset + length;
}
memcpy(this->buffer + (this->offset * this->channels), frames, length * this->channels * sizeof(float));
this->offset = this->offset + length;
}
return 1;
}
int AdaptiveBuffer::PushZero(uint32_t length) {
if (this->buffer == nullptr) {
return 0;
}
if (this->offset + length > this->length) {
auto tmp = new float[(this->offset + length) * this->channels];
memcpy(tmp, this->buffer, this->offset * this->channels * sizeof(float));
delete this->buffer;
this->buffer = tmp;
this->length = this->offset + length;
}
memset(this->buffer + (this->offset * this->channels), 0, length * this->channels * sizeof(float));
this->offset = this->offset + length;
return 1;
}
void AdaptiveBuffer::ScaleFrames(float scale) {
if (this->buffer != nullptr) {
for (uint32_t i = 0; i < this->offset * this->channels; i++) {
this->buffer[i] = this->buffer[i] * scale;
}
}
}
void AdaptiveBuffer::SetBufferOffset(uint32_t offset) {
this->offset = offset;
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <cstdint>
class AdaptiveBuffer {
public:
AdaptiveBuffer(uint32_t channels, uint32_t length);
~AdaptiveBuffer();
void FlushBuffer();
uint32_t GetBufferLength() const;
uint32_t GetBufferOffset() const;
float *GetBuffer() const;
uint32_t GetChannels() const;
void PanFrames(float left, float right);
int PopFrames(float *frames, uint32_t length);
int PushFrames(const float *frames, uint32_t length);
int PushZero(uint32_t length);
void ScaleFrames(float scale);
void SetBufferOffset(uint32_t offset);
private:
float *buffer;
uint32_t length;
uint32_t offset;
uint32_t channels;
};

112
src/viper/utils/Biquad.cpp Normal file
View File

@ -0,0 +1,112 @@
#include "Biquad.h"
#include <cmath>
// Some variable names RE'd with help from https://github.com/wooters/miniDSP/blob/master/biquad.c
Biquad::Biquad() {
Reset();
SetCoeffs(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
}
double Biquad::ProcessSample(double sample) {
double out =
sample * this->b0 +
this->x1 * this->b1 +
this->x2 * this->b2 +
this->y1 * this->a1 +
this->y2 * this->a2;
this->x2 = this->x1;
this->x1 = sample;
this->y2 = this->y1;
this->y1 = out;
return out;
}
void Biquad::Reset() {
this->a1 = 0.0;
this->a2 = 0.0;
this->b0 = 0.0;
this->b1 = 0.0;
this->b2 = 0.0;
this->x1 = 0.0;
this->x2 = 0.0;
this->y1 = 0.0;
this->y2 = 0.0;
}
void Biquad::SetBandPassParameter(float frequency, uint32_t samplingRate, float qFactor) {
double omega = (2.0 * M_PI * (double) frequency) / (double) samplingRate;
double sinOmega = sin(omega);
double cosOmega = cos(omega);
double alpha = sinOmega / (2.0 * (double) qFactor);
double a0 = 1.0 + alpha;
double a1 = -2.0 * cosOmega;
double a2 = 1.0 - alpha;
double b0 = sinOmega / 2.0; // Reference biquad implementation would use alpha here
double b1 = 0.0;
double b2 = -sinOmega / 2.0; // Reference biquad implementation would use -alpha here
SetCoeffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::SetCoeffs(double a0, double a1, double a2, double b0, double b1, double b2) {
this->x2 = 0.0;
this->x1 = 0.0;
this->y2 = 0.0;
this->y1 = 0.0;
this->a1 = -a1 / a0;
this->a2 = -a2 / a0;
this->b0 = b0 / a0;
this->b1 = b1 / a0;
this->b2 = b2 / a0;
}
// TODO: Check
void
Biquad::SetHighPassParameter(float frequency, uint32_t samplingRate, double dbGain, float qFactor, double param_6) {
double omega = (2.0 * M_PI * (double) frequency) / (double) samplingRate;
double sinX = sin(omega);
double cosX = cos(omega);
double A = pow(10.0, dbGain / 40.0);
double sqrtY = sqrt(A);
double z = sinX / 2.0 * sqrt((1.0 / A + A) * (1.0 / (double) qFactor - 1.0) + 2.0);
double a = (A - 1.0) * cosX;
double b = (A + 1.0) + a;
double c = (A + 1.0) * cosX;
double d = (A + 1.0) - a;
double e = pow(10.0, param_6 / 20.0);
double f = (A - 1.0) - c;
double a0 = d + (sqrtY * 2.0) * z;
double a1 = f * 2.0;
double a2 = d - (sqrtY * 2.0) * z;
double b0 = (b + (sqrtY * 2.0) * z) * A * e;
double b1 = A * -2.0 * ((A - 1.0) + c) * e;
double b2 = (b - (sqrtY * 2.0) * z) * A * e;
SetCoeffs(a0, a1, a2, b0, b1, b2);
}
void Biquad::SetLowPassParameter(float frequency, uint32_t samplingRate, float qFactor) {
double omega = (2.0 * M_PI * (double) frequency) / (double) samplingRate;
double sinOmega = sin(omega);
double cosOmega = cos(omega);
double alpha = sinOmega / (2.0 * (double) qFactor);
double a0 = 1.0 + alpha;
double a1 = -2.0 * cosOmega;
double a2 = 1.0 - alpha;
double b0 = (1.0 - cosOmega) / 2.0;
double b1 = 1.0 - cosOmega;
double b2 = (1.0 - cosOmega) / 2.0;
SetCoeffs(a0, a1, a2, b0, b1, b2);
}

26
src/viper/utils/Biquad.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
class Biquad {
public:
Biquad();
double ProcessSample(double sample);
void Reset();
void SetBandPassParameter(float frequency, uint32_t samplingRate, float qFactor);
void SetCoeffs(double a0, double a1, double a2, double b0, double b1, double b2);
void SetHighPassParameter(float frequency, uint32_t samplingRate, double dbGain, float qFactor, double param_6);
void SetLowPassParameter(float frequency, uint32_t samplingRate, float qFactor);
private:
double x1;
double x2;
double y1;
double y2;
double a1;
double a2;
double b0;
double b1;
double b2;
};

View File

@ -0,0 +1,37 @@
#include "CAllpassFilter.h"
#include <cstring>
CAllpassFilter::CAllpassFilter() {
this->buffer = nullptr;
this->feedback = 0.0;
this->bufferIndex = 0;
this->bufferSize = 0;
}
float CAllpassFilter::GetFeedback() {
return this->feedback;
}
void CAllpassFilter::Mute() {
memset(this->buffer, 0, this->bufferSize * sizeof(float));
}
float CAllpassFilter::Process(float sample) {
float outSample = this->buffer[this->bufferIndex];
this->buffer[this->bufferIndex] = sample + outSample * this->feedback;
this->bufferIndex++;
if (this->bufferIndex >= this->bufferSize) {
this->bufferIndex = 0;
}
return outSample - sample;
}
void CAllpassFilter::SetBuffer(float *buffer, uint32_t size) {
this->buffer = buffer;
this->bufferSize = size;
this->bufferIndex = 0;
}
void CAllpassFilter::SetFeedback(float feedback) {
this->feedback = feedback;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <cstdint>
class CAllpassFilter {
public:
CAllpassFilter();
float GetFeedback();
void Mute();
float Process(float sample);
void SetBuffer(float *buffer, uint32_t size);
void SetFeedback(float feedback);
private:
float feedback;
float *buffer;
uint32_t bufferSize;
uint32_t bufferIndex;
};

View File

@ -0,0 +1,50 @@
#include "CCombFilter.h"
#include <cstring>
CCombFilter::CCombFilter() {
this->feedback = 0.0;
this->buffer = nullptr;
this->bufferSize = 0;
this->bufferIndex = 0;
this->filterStore = 0.0;
this->damp = 0;
this->damp2 = 0;
}
float CCombFilter::GetDamp() {
return this->damp;
}
float CCombFilter::GetFeedback() {
return this->feedback;
}
void CCombFilter::Mute() {
memset(this->buffer, 0, this->bufferSize * sizeof(float));
}
float CCombFilter::Process(float sample) {
float output = this->buffer[this->bufferIndex];
this->filterStore = output * this->damp2 + this->filterStore * this->damp;
this->buffer[this->bufferIndex] = sample + this->filterStore * this->feedback;
this->bufferIndex++;
if (this->bufferIndex >= this->bufferSize) {
this->bufferIndex = 0;
}
return output;
}
void CCombFilter::SetBuffer(float *buffer, uint32_t size) {
this->buffer = buffer;
this->bufferSize = size;
this->bufferIndex = 0;
}
void CCombFilter::SetDamp(float damp) {
this->damp = damp;
this->damp2 = 1.0f - damp;
}
void CCombFilter::SetFeedback(float feedback) {
this->feedback = feedback;
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
class CCombFilter {
public:
CCombFilter();
float GetDamp();
float GetFeedback();
void Mute();
float Process(float sample);
void SetBuffer(float *buffer, uint32_t size);
void SetDamp(float damp);
void SetFeedback(float feedback);
private:
float feedback;
float filterStore;
float damp;
float damp2;
float *buffer;
uint32_t bufferSize;
uint32_t bufferIndex;
};

View File

@ -0,0 +1,206 @@
#include "CRevModel.h"
CRevModel::CRevModel() {
buffers[0] = new float[1116];
buffers[1] = new float[1139];
buffers[2] = new float[1188];
buffers[3] = new float[1211];
buffers[4] = new float[1277];
buffers[5] = new float[1300];
buffers[6] = new float[1356];
buffers[7] = new float[1379];
buffers[8] = new float[1422];
buffers[9] = new float[1445];
buffers[10] = new float[1491];
buffers[11] = new float[1514];
buffers[12] = new float[1557];
buffers[13] = new float[1580];
buffers[14] = new float[1617];
buffers[15] = new float[1640];
buffers[16] = new float[556];
buffers[17] = new float[579];
buffers[18] = new float[441];
buffers[19] = new float[464];
buffers[20] = new float[341];
buffers[21] = new float[364];
buffers[22] = new float[225];
buffers[23] = new float[248];
combL[0].SetBuffer(buffers[0], 1116);
combR[0].SetBuffer(buffers[1], 1139);
combL[1].SetBuffer(buffers[2], 1188);
combR[1].SetBuffer(buffers[3], 1211);
combL[2].SetBuffer(buffers[4], 1277);
combR[2].SetBuffer(buffers[5], 1300);
combL[3].SetBuffer(buffers[6], 1356);
combR[3].SetBuffer(buffers[7], 1379);
combL[4].SetBuffer(buffers[8], 1422);
combR[4].SetBuffer(buffers[9], 1445);
combL[5].SetBuffer(buffers[10], 1491);
combR[5].SetBuffer(buffers[11], 1514);
combL[6].SetBuffer(buffers[12], 1557);
combR[6].SetBuffer(buffers[13], 1580);
combL[7].SetBuffer(buffers[14], 1617);
combR[7].SetBuffer(buffers[15], 1640);
allpassL[0].SetBuffer(buffers[16], 556);
allpassR[0].SetBuffer(buffers[17], 579);
allpassL[1].SetBuffer(buffers[18], 441);
allpassR[1].SetBuffer(buffers[19], 464);
allpassL[2].SetBuffer(buffers[20], 341);
allpassR[2].SetBuffer(buffers[21], 364);
allpassL[3].SetBuffer(buffers[22], 225);
allpassR[3].SetBuffer(buffers[23], 248);
allpassL[0].SetFeedback(0.5);
allpassR[0].SetFeedback(0.5);
allpassL[1].SetFeedback(0.5);
allpassR[1].SetFeedback(0.5);
allpassL[2].SetFeedback(0.5);
allpassR[2].SetFeedback(0.5);
allpassL[3].SetFeedback(0.5);
allpassR[3].SetFeedback(0.5);
SetWet(0.167);
SetRoomSize(0.5);
SetDry(0.25);
SetDamp(0.5);
SetWidth(1.0);
SetMode(0.0);
Reset();
}
CRevModel::~CRevModel() {
for (auto &buffer : buffers) {
delete[] buffer;
}
}
float CRevModel::GetDamp() {
return damp / 0.4f;
}
float CRevModel::GetDry() {
return dry / 2.0f;
}
float CRevModel::GetMode() {
if (this->mode >= 0.5) {
return 1.0;
}
return this->mode;
}
float CRevModel::GetRoomSize() {
return (this->roomSize - 0.7f) / 0.28f;
}
float CRevModel::GetWet() {
return wet / 3.0f;
}
float CRevModel::GetWidth() {
return width;
}
void CRevModel::Mute() {
if (GetMode() >= 0.5) return;
for (int i = 0; i < 8; i++) {
combL[i].Mute();
combR[i].Mute();
}
for (int i = 0; i < 4; i++) {
allpassL[i].Mute();
allpassR[i].Mute();
}
}
void CRevModel::ProcessReplace(float *bufL, float *bufR, uint32_t size) {
for (uint32_t idx = 0; idx < size; idx++) {
float outL = 0.0;
float outR = 0.0;
float input = (bufL[idx] + bufR[idx]) * gain;
for (uint32_t i = 0; i < 8; i++) {
outL += combL[i].Process(input);
outR += combR[i].Process(input);
}
for (uint32_t i = 0; i < 4; i++) {
outL = allpassL[i].Process(outL);
outR = allpassR[i].Process(outR);
}
bufL[idx] = outL * unknown1 + outR * unknown2 + bufL[idx] * dry;
bufR[idx] = outR * unknown1 + outL * unknown2 + bufR[idx] * dry;
}
}
void CRevModel::Reset() {
if (GetMode() >= 0.5) return;
for (int i = 0; i < 8; i++) {
combL[i].Mute();
combR[i].Mute();
}
for (int i = 0; i < 4; i++) {
allpassL[i].Mute();
allpassR[i].Mute();
}
}
void CRevModel::SetDamp(float damp) {
this->damp = damp * 0.4f;
UpdateCoeffs();
}
void CRevModel::SetDry(float dry) {
this->dry = dry * 2.0f;
}
void CRevModel::SetMode(float mode) {
this->mode = mode;
UpdateCoeffs();
}
void CRevModel::SetRoomSize(float roomSize) {
this->roomSize = (roomSize * 0.28f) + 0.7f;
UpdateCoeffs();
}
void CRevModel::SetWet(float wet) {
this->wet = wet * 3.0f;
UpdateCoeffs();
}
void CRevModel::SetWidth(float width) {
this->width = width;
UpdateCoeffs();
}
void CRevModel::UpdateCoeffs() {
this->unknown1 = this->wet * (this->width / 2.0f + 0.5f);
this->unknown2 = this->wet * (1.0f - this->width) / 2.0f;
if (this->mode >= 0.5) {
this->internalRoomSize = 1.0;
this->internalDamp = 0.0;
this->gain = 0.0;
} else {
this->internalRoomSize = this->roomSize;
this->internalDamp = this->damp;
this->gain = 0.015;
}
for (int i = 0; i < 8; i++) {
this->combL[i].SetFeedback(this->internalRoomSize);
this->combL[i].SetDamp(this->internalDamp);
this->combR[i].SetFeedback(this->internalRoomSize);
this->combR[i].SetDamp(this->internalDamp);
}
}

View File

@ -0,0 +1,51 @@
#pragma once
#include "CCombFilter.h"
#include "CAllpassFilter.h"
class CRevModel {
public:
CRevModel();
~CRevModel();
void Mute();
void ProcessReplace(float *bufL, float *bufR, uint32_t size);
void UpdateCoeffs();
void Reset();
void SetRoomSize(float roomSize);
void SetDamp(float damp);
void SetWet(float wet);
void SetDry(float dry);
void SetWidth(float width);
void SetMode(float mode);
float GetRoomSize();
float GetDamp();
float GetWet();
float GetDry();
float GetWidth();
float GetMode();
private:
float gain;
float roomSize;
float internalRoomSize;
float damp;
float internalDamp;
float wet;
float unknown1;
float unknown2;
float dry;
float width;
float mode;
CCombFilter combL[8];
CCombFilter combR[8];
CAllpassFilter allpassL[4];
CAllpassFilter allpassR[4];
float *buffers[24];
};

View File

@ -0,0 +1,109 @@
#include <cstring>
#include <cmath>
#include "Crossfeed.h"
#include "../constants.h"
// Basically Bauer-to-Stereophonic Binaural filter
// See: http://bs2b.sourceforge.net/
Crossfeed::Crossfeed() {
this->a0_lo = 0.f;
this->b1_lo = 0.f;
this->a0_hi = 0.f;
this->a1_hi = 0.f;
this->b1_hi = 0.f;
this->gain = 0.f;
memset(&this->lfs, 0, 6 * sizeof(float));
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->preset.cutoff = 700;
this->preset.feedback = 45;
}
#define lo_filter(in, out_1) (this->a0_lo * (in) + this->b1_lo * (out_1))
#define hi_filter(in, in_1, out_1) (this->a0_hi * (in) + this->a1_hi * (in_1) + this->b1_hi * (out_1))
void Crossfeed::FilterSample(float *sample) {
this->lfs.lo[0] = lo_filter(sample[0], this->lfs.lo[0]);
this->lfs.lo[1] = lo_filter(sample[1], this->lfs.lo[1]);
this->lfs.hi[0] = hi_filter(sample[0], this->lfs.asis[0], this->lfs.hi[0]);
this->lfs.hi[1] = hi_filter(sample[1], this->lfs.asis[1], this->lfs.hi[1]);
this->lfs.asis[0] = sample[0];
this->lfs.asis[1] = sample[1];
sample[0] = (this->lfs.hi[0] + this->lfs.lo[1]) * this->gain;
sample[1] = (this->lfs.hi[1] + this->lfs.lo[0]) * this->gain;
}
uint16_t Crossfeed::GetCutoff() {
return this->preset.cutoff;
}
float Crossfeed::GetFeedback() {
return (float) this->preset.feedback / 10.0f;
}
float Crossfeed::GetLevelDelay() {
if (this->preset.cutoff <= 1800) { // TODO: Previous version reports <= 2000
return (float) ((18700.0 / (double) this->preset.cutoff) * 10.0);
} else {
return 0.0;
}
}
struct Crossfeed::Preset Crossfeed::GetPreset() {
return this->preset;
}
void Crossfeed::ProcessFrames(float *buffer, uint32_t size) {
for (uint32_t i = 0; i < size; i += 2) {
FilterSample(&buffer[i]);
}
}
void Crossfeed::Reset() {
uint16_t cutoff = this->preset.cutoff;
uint16_t level = this->preset.feedback;
level /= 10.0;
double GB_lo = level * -5.0 / 6.0 - 3.0;
double GB_hi = level / 6.0 - 3.0;
double G_lo = pow(10, GB_lo / 20.0);
double G_hi = 1.0 - pow(10, GB_hi / 20.0);
double Fc_hi = cutoff * pow(2.0, (GB_lo - 20.0 * log10(G_hi)) / 12.0);
double x = exp(-2.0 * M_PI * cutoff / this->samplingRate);
this->b1_lo = (float) x;
this->a0_lo = (float) (G_lo * (1.0 - x));
x = exp(-2.0 * M_PI * Fc_hi / this->samplingRate);
this->b1_hi = (float) x;
this->a0_hi = (float) (1.0 - G_hi * (1.0 - x));
this->a1_hi = (float) -x;
this->gain = (float) (1.0 / (1.0 - G_hi + G_lo));
memset(&this->lfs, 0, 6 * sizeof(float));
}
void Crossfeed::SetCutoff(uint16_t cutoff) {
this->preset.cutoff = cutoff;
Reset();
}
void Crossfeed::SetFeedback(float feedback) {
this->preset.feedback = (uint16_t) (feedback * 10.0f);
Reset();
}
void Crossfeed::SetPreset(struct Crossfeed::Preset preset) {
this->preset = preset;
Reset();
}
void Crossfeed::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
Reset();
}
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <cstdint>
class Crossfeed {
public:
struct Preset {
uint16_t cutoff;
uint16_t feedback;
};
Crossfeed();
void Reset();
void ProcessFrames(float *buffer, uint32_t size);
void FilterSample(float *sample);
uint16_t GetCutoff();
float GetFeedback();
float GetLevelDelay();
struct Preset GetPreset();
void SetCutoff(uint16_t cutoff);
void SetFeedback(float feedback);
void SetPreset(struct Preset preset);
void SetSamplingRate(uint32_t samplingRate);
private:
uint32_t samplingRate;
float a0_lo, b1_lo;
float a0_hi, b1_hi, a1_hi;
float gain;
struct {
float asis[2], lo[2], hi[2];
} lfs;
struct Preset preset;
};

View File

@ -0,0 +1,83 @@
#include "DepthSurround.h"
#include <cmath>
#include "../constants.h"
DepthSurround::DepthSurround() {
this->strength = 0;
this->enabled = false;
this->strengthAtLeast500 = false;
this->gain = 0;
for (auto &prev : this->prev) {
prev = 0.0f;
}
this->SetSamplingRate(VIPER_DEFAULT_SAMPLING_RATE);
this->RefreshStrength(this->strength);
}
void DepthSurround::Process(float *samples, uint32_t size) {
if (this->enabled) {
if (!this->strengthAtLeast500) {
for (uint32_t i = 0; i < size; i++) {
float sampleLeft = samples[2 * i];
float sampleRight = samples[2 * i + 1];
this->prev[0] = this->gain * this->timeConstDelay[0].ProcessSample(sampleLeft + this->prev[1]);
this->prev[1] = this->gain * this->timeConstDelay[1].ProcessSample(sampleRight + this->prev[0]);
float l = this->prev[0] + sampleLeft;
float r = this->prev[1] + sampleRight;
float diff = (l - r) / 2.f;
float avg = (l + r) / 2.f;
float avgOut = (float) this->highpass.ProcessSample(diff);
samples[2 * i] = avg + (diff - avgOut);
samples[2 * i + 1] = avg - (diff - avgOut);
}
} else {
for (uint32_t i = 0; i < size; i++) {
float sampleLeft = samples[2 * i];
float sampleRight = samples[2 * i + 1];
this->prev[0] = this->gain * this->timeConstDelay[0].ProcessSample(sampleLeft + this->prev[1]);
this->prev[1] = -this->gain * this->timeConstDelay[1].ProcessSample(sampleRight + this->prev[0]);
float l = this->prev[0] + sampleLeft;
float r = this->prev[1] + sampleRight;
float diff = (l - r) / 2.f;
float avg = (l + r) / 2.f;
float avgOut = (float) this->highpass.ProcessSample(diff);
samples[2 * i] = avg + (diff - avgOut);
samples[2 * i + 1] = avg - (diff - avgOut);
}
}
}
}
void DepthSurround::RefreshStrength(short strength) {
this->strengthAtLeast500 = strength >= 500;
this->enabled = strength != 0;
if (strength != 0) {
float gain = (float) pow(10.0, ((strength / 1000.0) * 10.0 - 15.0) / 20.0);
if (gain > 1.0) {
gain = 1.0;
}
this->gain = (float) gain;
} else {
this->gain = 0.0;
}
}
void DepthSurround::SetSamplingRate(uint32_t samplingRate) {
this->timeConstDelay[0].SetParameters(samplingRate, 0.02);
this->timeConstDelay[1].SetParameters(samplingRate, 0.014);
this->highpass.SetHighPassParameter(800.0f, samplingRate, -11.0f, 0.72f, 0.0);
for (auto &prev : this->prev) {
prev = 0.0f;
}
}
void DepthSurround::SetStrength(short strength) {
this->strength = strength;
this->RefreshStrength(strength);
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <cstdint>
#include "Biquad.h"
#include "TimeConstDelay.h"
class DepthSurround {
public:
DepthSurround();
void Process(float *samples, uint32_t size);
void RefreshStrength(short strength);
void SetSamplingRate(uint32_t samplingRate);
void SetStrength(short strength);
private:
short strength;
bool enabled;
bool strengthAtLeast500;
float gain;
float prev[2];
TimeConstDelay timeConstDelay[2];
Biquad highpass;
};

View File

@ -0,0 +1,90 @@
#include "DynamicBass.h"
#include "../constants.h"
DynamicBass::DynamicBass() {
this->qPeak = 0;
SetSamplingRate(VIPER_DEFAULT_SAMPLING_RATE);
this->bassGain = 1.f;
this->sideGainX = 1.f;
this->sideGainY = 1.f;
this->lowFreqX = 120;
this->highFreqX = 80;
this->lowFreqY = 40;
this->highFreqY = (uint32_t) ((float) this->samplingRate / 4.0f);
this->filterX.SetPassFilter(this->lowFreqX, this->highFreqX);
this->filterY.SetPassFilter(this->lowFreqY, this->highFreqY);
this->lowPass.SetLowPassParameter(55.f, this->samplingRate, this->qPeak / 666.f + 0.5f);
}
void DynamicBass::FilterSamples(float *samples, uint32_t size) {
if (this->lowFreqX <= 120) {
for (uint32_t i = 0; i < size; i++) {
float left = samples[2 * i];
float right = samples[2 * i + 1];
float avg = (float) this->lowPass.ProcessSample(left + right);
samples[2 * i] = left + avg;
samples[2 * i + 1] = right + avg;
}
} else {
for (uint32_t i = 0; i < size; i++) {
float x1, x2, x3, x4, x5, x6, y1, y2, y3, y4, y5, y6;
this->filterX.DoFilterLeft(samples[2 * i], &x1, &x2, &x3);
this->filterX.DoFilterRight(samples[2 * i + 1], &x4, &x5, &x6);
this->filterY.DoFilterLeft(this->bassGain * x1, &y1, &y2, &y3);
this->filterY.DoFilterRight(this->bassGain * x4, &y4, &y5, &y6);
samples[2 * i] = x2 + y3 + this->sideGainX * y2 + this->sideGainY * y1 + x3;
samples[2 * i + 1] = x5 + y6 + this->sideGainX * y5 + this->sideGainY * y4 + x6;
}
}
}
void DynamicBass::Reset() {
this->filterX.Reset();
this->filterY.Reset();
this->lowPass.SetLowPassParameter(55.0, this->samplingRate, this->qPeak / 666.0f + 0.5f);
}
void DynamicBass::SetBassGain(float gain) {
this->bassGain = gain;
double x = ((gain - 1.0) / 20.0) * 1600.0;
if (x > 1600.0) {
x = 1600.0;
}
this->qPeak = (float) x;
this->lowPass.SetLowPassParameter(55.0, this->samplingRate, this->qPeak / 666.0f + 0.5f);
}
void DynamicBass::SetFilterXPassFrequency(uint32_t low, uint32_t high) {
this->lowFreqX = low;
this->highFreqX = high;
this->filterX.SetPassFilter(low, high);
this->filterX.SetSamplingRate(this->samplingRate);
this->lowPass.SetLowPassParameter(55.0, this->samplingRate, this->qPeak / 666.0f + 0.5f);
}
void DynamicBass::SetFilterYPassFrequency(uint32_t low, uint32_t high) {
this->lowFreqY = low;
this->highFreqY = high;
this->filterY.SetPassFilter(low, high);
this->filterY.SetSamplingRate(this->samplingRate);
this->lowPass.SetLowPassParameter(55.0, this->samplingRate, this->qPeak / 666.0f + 0.5f);
}
void DynamicBass::SetSamplingRate(uint32_t samplingRate) {
this->samplingRate = samplingRate;
this->filterX.SetSamplingRate(samplingRate);
this->filterY.SetSamplingRate(samplingRate);
this->lowPass.SetLowPassParameter(55.0, samplingRate, this->qPeak / 666.0f + 0.5f);
}
void DynamicBass::SetSideGain(float gainX, float gainY) {
this->sideGainX = gainX;
this->sideGainY = gainY;
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <cstdint>
#include "PolesFilter.h"
#include "Biquad.h"
class DynamicBass {
public:
DynamicBass();
void FilterSamples(float *samples, uint32_t size);
void Reset();
void SetBassGain(float gain);
void SetFilterXPassFrequency(uint32_t low, uint32_t high);
void SetFilterYPassFrequency(uint32_t low, uint32_t high);
void SetSamplingRate(uint32_t samplingRate);
void SetSideGain(float gainX, float gainY);
uint32_t lowFreqX, highFreqX;
uint32_t lowFreqY, highFreqY;
uint32_t samplingRate;
float qPeak;
float bassGain;
float sideGainX, sideGainY;
PolesFilter filterX;
PolesFilter filterY;
Biquad lowPass;
};

92
src/viper/utils/FIR.cpp Normal file
View File

@ -0,0 +1,92 @@
#include <cstring>
#include "FIR.h"
FIR::FIR() {
this->offsetBlock = nullptr;
this->coeffs = nullptr;
this->block = nullptr;
this->coeffsSize = 0;
this->blockLength = 0;
this->hasCoefficients = false;
}
FIR::~FIR() {
delete[] this->offsetBlock;
delete[] this->coeffs;
delete[] this->block;
}
void FIR::FilterSamples(float *samples, uint32_t size) {
this->FilterSamplesInterleaved(samples, size, 1);
}
void FIR::FilterSamplesInterleaved(float *samples, uint32_t size, uint32_t channels) {
if (!this->hasCoefficients || size == 0) return;
for (uint32_t i = 0; i < size; i++) {
this->block[i] = samples[i * channels];
}
if (this->blockLength > size) {
memset(this->block + size, 0, (this->blockLength - size) * sizeof(float));
}
memcpy(this->offsetBlock + this->coeffsSize - 1, this->block, this->blockLength * sizeof(float));
for (uint32_t i = 0; i < this->blockLength; i++) {
float sample = 0.0f;
for (uint32_t j = 0; j < this->coeffsSize; j++) {
sample += this->coeffs[j] * this->offsetBlock[this->coeffsSize + i - j - 1];
}
if (i < size) {
samples[i * channels] = sample;
}
}
if (this->coeffsSize > 1) {
// TODO: Replace this with memcpy
float *pfVar1 = this->block;
float *pfVar6 = pfVar1 + blockLength;
float *pfVar2 = this->offsetBlock + this->coeffsSize;
do {
pfVar6 = pfVar6 + -1;
pfVar2[-2] = *pfVar6;
pfVar2 = pfVar2 + -1;
} while (pfVar6 != pfVar1 + blockLength + (1 - this->coeffsSize));
//memcpy(this->offsetBlock + this->coeffsSize - 2 - (this->coeffsSize - 1), this->block + this->blockLength - 1 - (this->coeffsSize - 1), (this->coeffsSize - 1) * sizeof(float));
}
}
uint32_t FIR::GetBlockLength() {
return this->blockLength;
}
int FIR::LoadCoefficients(const float *coeffs, uint32_t coeffsSize, uint32_t blockLength) {
if (coeffs == nullptr || coeffsSize == 0 || blockLength == 0) return 0;
delete[] this->offsetBlock;
delete[] this->coeffs;
delete[] this->block;
this->offsetBlock = new float[coeffsSize + blockLength + 1];
this->coeffs = new float[coeffsSize];
this->block = new float[blockLength];
this->coeffsSize = coeffsSize;
this->blockLength = blockLength;
memcpy(this->coeffs, coeffs, coeffsSize * sizeof(float));
Reset();
this->hasCoefficients = true;
return 1;
}
void FIR::Reset() {
if (this->offsetBlock != nullptr && this->coeffsSize + this->blockLength > 0) {
memset(this->offsetBlock, 0, (this->coeffsSize + this->blockLength + 1) * sizeof(float));
}
}

25
src/viper/utils/FIR.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
class FIR {
public:
FIR();
~FIR();
void FilterSamples(float *samples, uint32_t size);
void FilterSamplesInterleaved(float *samples, uint32_t size, uint32_t channels);
uint32_t GetBlockLength();
int LoadCoefficients(const float *coeffs, uint32_t coeffsSize, uint32_t blockLength);
void Reset();
private:
float *offsetBlock;
float *coeffs;
float *block;
uint32_t coeffsSize;
uint32_t blockLength;
bool hasCoefficients;
};

View File

@ -0,0 +1,108 @@
#include <cstring>
#include <cmath>
#include "Harmonic.h"
static const float HARMONIC_DEFAULT[] = {
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
};
Harmonic::Harmonic() {
UpdateCoeffs(HARMONIC_DEFAULT);
Reset();
}
double Harmonic::Process(double sample) {
double prevLast = this->lastProcessed;
this->lastProcessed =
(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.999) - prevLast;
if (this->sampleCounter < this->biggestCoeff) {
this->sampleCounter++;
return 0.0;
}
return this->prevOut;
}
void Harmonic::Reset() {
this->lastProcessed = 0.0;
this->sampleCounter = 0;
this->prevOut = 0.0;
}
void Harmonic::SetHarmonics(const float *coefficients) {
UpdateCoeffs(coefficients);
Reset();
}
void Harmonic::UpdateCoeffs(const float *coefficients) {
float unkarr1[11];
float unkarr2[11];
memset(unkarr1, 0, 11 * sizeof(float));
float biggestCoeffVal = 0.0;
float absCoeffSum = 0.0;
for (uint32_t i = 0; i < 10; i++) {
float absCoeffVal = abs(coefficients[i]);
absCoeffSum += absCoeffVal;
if (absCoeffVal > biggestCoeffVal) {
biggestCoeffVal = absCoeffVal;
}
}
this->biggestCoeff = (uint32_t) (biggestCoeffVal * 10000.0);
memcpy(unkarr1 + 1, coefficients, 10 * sizeof(float));
float unk1 = 1.0;
if (absCoeffSum > 1.0) {
unk1 = 1.0f / absCoeffSum;
}
for (uint32_t i = 1; i < 11; i++) {
unkarr1[i] *= unk1;
}
memset(this->coeffs, 0, 11 * sizeof(float));
memset(unkarr2, 0, 11 * sizeof(float));
this->coeffs[10] = unkarr1[10];
for (uint32_t i = 2; i < 11; i++) {
for (uint32_t j = 0; j < i; j++) {
float tmp = unkarr2[i - j];
unkarr2[i - j] = this->coeffs[i - j];
this->coeffs[i - j] = this->coeffs[i - j - 1] * 2.0f - tmp;
}
float tmp = unkarr1[10 - i + 1] - unkarr2[0];
unkarr2[0] = this->coeffs[0];
this->coeffs[0] = tmp;
}
for (uint32_t i = 1; i < 11; i++) {
this->coeffs[10 - i + 1] = this->coeffs[10 - i] - unkarr2[10 - i + 1];
}
this->coeffs[0] = unkarr1[0] / 2.0f - unkarr2[0];
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <cstdint>
class Harmonic {
public:
Harmonic();
double Process(double sample);
void Reset();
void SetHarmonics(const float *coeffs);
void UpdateCoeffs(const float *coeffs);
private:
float coeffs[11];
double lastProcessed;
double prevOut;
uint32_t biggestCoeff;
uint32_t sampleCounter;
};

78
src/viper/utils/HiFi.cpp Normal file
View File

@ -0,0 +1,78 @@
#include "HiFi.h"
#include "../constants.h"
HiFi::HiFi() {
this->gain = 1.f;
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
for (int i = 0; i < 2; i++) {
this->buffers[i] = new WaveBuffer(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 (uint32_t 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]->GetBuffer();
float *lpOut = this->buffers[1]->GetBuffer();
for (uint32_t 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 (uint32_t i = 0; i < 2; i++) {
this->filters[i].lowpass->setLPF(120.0, this->samplingRate);
this->filters[i].lowpass->Mute();
this->filters[i].highpass->setHPF(1200.0, this->samplingRate);
this->filters[i].highpass->Mute();
this->filters[i].bandpass->setBPF(120.f, 1200.f, this->samplingRate);
this->filters[i].bandpass->Mute();
}
this->buffers[0]->Reset();
this->buffers[0]->PushZeros(this->samplingRate / 400);
this->buffers[1]->Reset();
this->buffers[1]->PushZeros(this->samplingRate / 200);
}
void HiFi::SetClarity(float value) {
this->gain = value;
}
void HiFi::SetSamplingRate(uint32_t samplingRate) {
this->samplingRate = samplingRate;
Reset();
}

32
src/viper/utils/HiFi.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include "IIR_NOrder_BW_LH.h"
#include "WaveBuffer.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 samplingRate);
WaveBuffer *buffers[2];
struct {
IIR_NOrder_BW_LH *lowpass;
IIR_NOrder_BW_LH *highpass;
IIR_NOrder_BW_BP *bandpass;
} filters[2];
float gain;
uint32_t samplingRate;
};

View File

@ -0,0 +1,46 @@
#include "HighShelf.h"
#include <cmath>
double HighShelf::Process(double sample) {
double out = (((this->x_1 * this->b1 + sample * this->b0 + this->b2 * this->x_2) - this->y_1 * this->a1) - this->a2 * this->y_2) * this->a0;
this->y_2 = this->y_1;
this->y_1 = out;
this->x_2 = this->x_1;
this->x_1 = sample;
return out;
}
void HighShelf::SetFrequency(float freq) {
this->frequency = freq;
}
void HighShelf::SetGain(float gain) {
this->gain = 20.0 * log10((double) gain);
}
void HighShelf::SetSamplingRate(uint32_t samplingRate) {
double x = (2 * M_PI * this->frequency) / (double) samplingRate;
double sinX = sin(x);
double cosX = cos(x);
double y = exp((this->gain * log(10.0)) / 40.0);
this->x_1 = 0.0;
this->x_2 = 0.0;
this->y_1 = 0.0;
this->y_2 = 0.0;
double z = sqrt(y * 2.0) * sinX;
double a = (y - 1.0) * cosX;
double b = (y + 1.0) - a;
double c = z + b;
double d = (y + 1.0) * cosX;
double e = (y + 1.0) + a;
double f = (y - 1.0) - d;
this->a0 = 1.0 / c;
this->a1 = f * 2.0;
this->a2 = b - z;
this->b0 = (e + z) * y;
this->b1 = -y * 2.0 * ((y - 1.0) + d);
this->b2 = (e - z) * y;
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <cstdint>
class HighShelf {
public:
double Process(double sample);
void SetFrequency(float freq);
void SetGain(float gain);
void SetSamplingRate(uint32_t samplingRate);
private:
float frequency;
double gain;
double x_1;
double x_2;
double y_1;
double y_2;
double b0;
double b1;
double b2;
double a0;
double a1;
double a2;
};

149
src/viper/utils/IIR_1st.cpp Normal file
View File

@ -0,0 +1,149 @@
#include <cmath>
#include "IIR_1st.h"
// Seems to be taken from https://github.com/michaelwillis/dragonfly-reverb/blob/master/common/freeverb/efilter.cpp
// Or similar sources
IIR_1st::IIR_1st() {
this->b0 = 0.f;
this->b1 = 0.f;
this->a1 = 0.f;
Mute();
}
void IIR_1st::Mute() {
this->prevSample = 0.f;
}
void IIR_1st::SetCoefficients(float b0, float b1, float a1) {
this->b0 = b0;
this->b1 = b1;
this->a1 = a1;
}
#define angle(freq, samplingRate) (expf(-1*(float)M_PI*(freq)/((float)(samplingRate)/2.f)))
#define omega() (2.f * (float)M_PI * frequency / (float)samplingRate)
#define omega_2() ((float)M_PI * frequency / (float)samplingRate)
void IIR_1st::setHPF_A(float frequency, uint32_t samplingRate) {
this->a1 = angle(frequency, samplingRate);
float norm = (1 + a1) / 2.f;
this->b0 = norm;
this->b1 = -norm;
}
void IIR_1st::setHPF_BW(float frequency, uint32_t samplingRate) {
float omega_2 = omega_2();
float tan_omega_2 = tanf(omega_2);
this->b0 = 1 / (1 + tan_omega_2);
this->b1 = -this->b0;
this->a1 = (1 - tan_omega_2) / (1 + tan_omega_2);
}
void IIR_1st::setHPF_C(float frequency, uint32_t samplingRate) {
this->b0 = (float) samplingRate / ((float) samplingRate + frequency);
this->b1 = -1 * this->b0;
this->a1 = ((float) samplingRate - frequency) / ((float) samplingRate + frequency);
}
void IIR_1st::setHPFwLPS_A(float frequency, uint32_t samplingRate) {
this->a1 = -0.12f;
this->b0 = -1.f;
this->b1 = angle(frequency, samplingRate);
float norm = (1 - this->a1) / fabsf(this->b0 + this->b1);
this->b0 *= norm;
this->b1 *= norm;;
}
void IIR_1st::setHSF_A(float f1, float f2, uint32_t samplingRate) {
this->a1 = angle(f1, samplingRate);
this->b0 = -1.f;
this->b1 = angle(f2, samplingRate);
float norm = (1 - this->a1) / (this->b0 + this->b1);
this->b0 *= norm;
this->b1 *= norm;
}
void IIR_1st::setLPF_A(float frequency, uint32_t samplingRate) {
this->a1 = angle(frequency, samplingRate);
this->b0 = 1.f;
this->b1 = 0.12f;
float norm = (1 + this->a1) / (this->b0 + this->b1);
this->b0 *= norm;
this->b1 *= norm;
}
void IIR_1st::setLPF_BW(float frequency, uint32_t samplingRate) {
float omega_2 = omega_2();
float tan_omega_2 = tanf(omega_2);
this->a1 = (1 - tan_omega_2) / (1 + tan_omega_2);
this->b0 = tan_omega_2 / (1 + tan_omega_2);
this->b1 = this->b0;
}
void IIR_1st::setLPF_C(float frequency, uint32_t samplingRate) {
this->b0 = frequency / ((float) samplingRate + frequency);
this->b1 = this->b0;
this->a1 = ((float) samplingRate - frequency) / ((float) samplingRate + frequency);
}
void IIR_1st::setLSF_A(float f1, float f2, uint32_t samplingRate) {
this->a1 = angle(f1, samplingRate);
this->b0 = -1.f;
this->b1 = angle(f2, samplingRate);
}
void IIR_1st::setPole(float a1) {
this->a1 = a1;
this->b0 = 1.f - fabsf(a1);
this->b1 = 0.f;
}
void IIR_1st::setPoleHPF(float frequency, uint32_t samplingRate) {
float omega = omega();
float cos_omega = cosf(omega);
float tmp = (2.f + cos_omega);
float coeff = tmp - sqrtf(tmp * tmp - 1.f);
this->a1 = -coeff;
this->b0 = 1.f - coeff;
this->b1 = 0;
}
void IIR_1st::setPoleLPF(float frequency, uint32_t samplingRate) {
float omega = omega();
float cos_omega = cosf(omega);
float tmp = (2.f - cos_omega);
float coeff = tmp - sqrtf(tmp * tmp - 1.f);
this->a1 = coeff;
this->b0 = 1.f - coeff;
this->b1 = 0.f;
}
void IIR_1st::setZero(float b1) {
this->a1 = 0;
this->b0 = -1;
this->b1 = b1;
float norm = fabsf(this->b0) + fabsf(this->b1);
this->b0 *= norm;
this->b1 *= norm;
}
void IIR_1st::setZeroHPF(float frequency, uint32_t samplingRate) {
float omega = omega();
float cos_omega = cosf(omega);
float tmp = (1.f - 2.f * cos_omega);
float coeff = tmp - sqrtf(tmp * tmp - 1.f);
this->a1 = 0.f;
this->b0 = 1.f / (1.f + coeff);
this->b1 = -coeff / (1.f + coeff);
}
void IIR_1st::setZeroLPF(float frequency, uint32_t samplingRate) {
float omega = omega();
float cos_omega = cosf(omega);
float tmp = (1.f + 2.f * cos_omega);
float coeff = tmp - sqrtf(tmp * tmp - 1.f);
this->a1 = 0.f;
this->b0 = 1.f / (1.f + coeff);
this->b1 = coeff / (1.f + coeff);
}

36
src/viper/utils/IIR_1st.h Normal file
View File

@ -0,0 +1,36 @@
#pragma once
#include <cstdint>
class IIR_1st {
public:
IIR_1st();
void Mute();
void SetCoefficients(float b0, float b1, float a1);
void setHPF_A(float frequency, uint32_t samplingRate);
void setHPF_BW(float frequency, uint32_t samplingRate);
void setHPF_C(float frequency, uint32_t samplingRate);
void setHPFwLPS_A(float frequency, uint32_t samplingRate);
void setHSF_A(float f1, float f2, uint32_t samplingRate);
void setLPF_A(float frequency, uint32_t samplingRate);
void setLPF_BW(float frequency, uint32_t samplingRate);
void setLPF_C(float frequency, uint32_t samplingRate);
void setLSF_A(float f1, float f2, uint32_t samplingRate);
void setPole(float a1);
void setPoleHPF(float frequency, uint32_t samplingRate);
void setPoleLPF(float frequency, uint32_t samplingRate);
void setZero(float b1);
void setZeroHPF(float frequency, uint32_t samplingRate);
void setZeroLPF(float frequency, uint32_t samplingRate);
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;
}

View File

@ -0,0 +1,31 @@
#include "IIR_NOrder_BW_BP.h"
IIR_NOrder_BW_BP::IIR_NOrder_BW_BP(uint32_t order) {
this->lowpass = new IIR_1st[order];
this->highpass = new IIR_1st[order];
this->order = order;
for (uint32_t x = 0; x < order; x++) {
this->lowpass[x].Mute();
this->highpass[x].Mute();
}
}
IIR_NOrder_BW_BP::~IIR_NOrder_BW_BP() {
delete[] this->lowpass;
delete[] this->highpass;
}
void IIR_NOrder_BW_BP::Mute() {
for (uint32_t x = 0; x < this->order; x++) {
this->lowpass[x].Mute();
this->highpass[x].Mute();
}
}
void IIR_NOrder_BW_BP::setBPF(float highCut, float lowCut, uint32_t samplingRate) {
for (uint32_t x = 0; x < this->order; x++) {
this->lowpass[x].setLPF_BW(lowCut, samplingRate);
this->highpass[x].setHPF_BW(highCut, samplingRate);
}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include "IIR_1st.h"
class IIR_NOrder_BW_BP {
public:
explicit IIR_NOrder_BW_BP(uint32_t order);
~IIR_NOrder_BW_BP();
void Mute();
void setBPF(float highCut, float lowCut, uint32_t samplingRate);
IIR_1st *lowpass;
IIR_1st *highpass;
uint32_t order;
};
inline float do_filter_bplp(IIR_NOrder_BW_BP *filt, float sample) {
for (uint32_t 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 (uint32_t 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));
}

View File

@ -0,0 +1,32 @@
#include "IIR_NOrder_BW_LH.h"
IIR_NOrder_BW_LH::IIR_NOrder_BW_LH(uint32_t order) {
this->filters = new IIR_1st[order];
this->order = order;
for (uint32_t x = 0; x < order; x++) {
this->filters[x].Mute();
}
}
IIR_NOrder_BW_LH::~IIR_NOrder_BW_LH() {
delete[] this->filters;
}
void IIR_NOrder_BW_LH::Mute() {
for (uint32_t x = 0; x < this->order; x++) {
this->filters[x].Mute();
}
}
void IIR_NOrder_BW_LH::setLPF(float frequency, uint32_t samplingRate) {
for (uint32_t x = 0; x < this->order; x++) {
this->filters[x].setLPF_BW(frequency, samplingRate);
}
}
void IIR_NOrder_BW_LH::setHPF(float frequency, uint32_t samplingRate) {
for (uint32_t x = 0; x < this->order; x++) {
this->filters[x].setHPF_BW(frequency, samplingRate);
}
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "IIR_1st.h"
class IIR_NOrder_BW_LH {
public:
explicit IIR_NOrder_BW_LH(uint32_t order);
~IIR_NOrder_BW_LH();
void Mute();
void setLPF(float frequency, uint32_t samplingRate);
void setHPF(float frequency, uint32_t samplingRate);
IIR_1st *filters;
uint32_t order;
};
inline float do_filter_lh(IIR_NOrder_BW_LH *filt, float sample) {
for (uint32_t idx = 0; idx < filt->order; idx++) {
sample = do_filter(&filt->filters[idx], sample);
}
return sample;
}

View File

@ -0,0 +1,218 @@
#include "MinPhaseIIRCoeffs.h"
#include "../constants.h"
#include <cmath>
static const float MIN_PHASE_IIR_COEFFS_FREQ_10BANDS[] = {
31.0,
62.0,
125.0,
250.0,
500.0,
1000.0,
2000.0,
4000.0,
8000.0,
16000.0
};
static const float MIN_PHASE_IIR_COEFFS_FREQ_15BANDS[] = {
25.0,
40.0,
63.0,
100.0,
160.0,
250.0,
400.0,
630.0,
1000.0,
1600.0,
2500.0,
4000.0,
6300.0,
10000.0,
16000.0
};
static const float MIN_PHASE_IIR_COEFFS_FREQ_25BANDS[] = {
20.0,
31.5,
40.0,
50.0,
80.0,
100.0,
125.0,
160.0,
250.0,
315.0,
400.0,
500.0,
800.0,
1000.0,
1250.0,
1600.0,
2500.0,
3150.0,
4000.0,
5000.0,
8000.0,
10000.0,
12500.0,
16000.0,
20000.0
};
static const float MIN_PHASE_IIR_COEFFS_FREQ_31BANDS[] = {
20.0,
25.0,
31.5,
40.0,
50.0,
63.0,
80.0,
100.0,
125.0,
160.0,
200.0,
250.0,
315.0,
400.0,
500.0,
630.0,
800.0,
1000.0,
1250.0,
1600.0,
2000.0,
2500.0,
3150.0,
4000.0,
5000.0,
6300.0,
8000.0,
10000.0,
12500.0,
16000.0,
20000.0
};
MinPhaseIIRCoeffs::MinPhaseIIRCoeffs() {
this->coeffs = nullptr;
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->bands = 0;
}
MinPhaseIIRCoeffs::~MinPhaseIIRCoeffs() {
delete[] this->coeffs;
}
void MinPhaseIIRCoeffs::Find_F1_F2(double param_2, double param_3, double *param_4, double *param_5) {
double x = pow(2.0, param_3 / 2.0);
*param_5 = param_2 / x;
*param_4 = param_2 * x;
}
double *MinPhaseIIRCoeffs::GetCoefficients() {
return this->coeffs;
}
float MinPhaseIIRCoeffs::GetIndexFrequency(uint32_t index) {
switch (this->bands) {
case 10:
return MIN_PHASE_IIR_COEFFS_FREQ_10BANDS[index];
case 15:
return MIN_PHASE_IIR_COEFFS_FREQ_15BANDS[index];
case 25:
return MIN_PHASE_IIR_COEFFS_FREQ_25BANDS[index];
case 31:
return MIN_PHASE_IIR_COEFFS_FREQ_31BANDS[index];
default:
return 0.0;
}
}
int MinPhaseIIRCoeffs::SolveRoot(double param_2, double param_3, double param_4, double *param_5) {
double x = (param_4 - pow(param_3, 2) / (param_2 * 4.0)) / param_2;
double y = param_3 / (param_2 * 2.0);
if (x >= 0.0) {
return -1;
}
double z = sqrt(-x);
double a = -y - z;
double b = z - y;
if (a > b) {
*param_5 = b;
} else {
*param_5 = a;
}
return 0;
}
int MinPhaseIIRCoeffs::UpdateCoeffs(uint32_t bands, uint32_t samplingRate) {
if ((bands != 10 && bands != 15 && bands != 25 && bands != 31) || samplingRate < 44100) {
return 0;
}
this->bands = bands;
this->samplingRate = samplingRate;
delete[] this->coeffs;
this->coeffs = new double[bands * 4](); // TODO: Check this array size, original type: float
const float *coeffsArray;
double tmp;
switch (bands) {
case 10:
coeffsArray = MIN_PHASE_IIR_COEFFS_FREQ_10BANDS;
tmp = 3.0 / 3.0;
break;
case 15:
coeffsArray = MIN_PHASE_IIR_COEFFS_FREQ_15BANDS;
tmp = 2.0 / 3.0;
break;
case 25:
coeffsArray = MIN_PHASE_IIR_COEFFS_FREQ_25BANDS;
tmp = 1.0 / 3.0;
break;
case 31:
coeffsArray = MIN_PHASE_IIR_COEFFS_FREQ_31BANDS;
tmp = 1.0 / 3.0;
break;
}
for (uint32_t i = 0; i < bands; i++) {
double ret1;
double ret2;
Find_F1_F2(coeffsArray[i], tmp, &ret1, &ret2);
double x = (2.0 * M_PI * (double) coeffsArray[i]) / (double) this->samplingRate;
double y = (2.0 * M_PI * ret2) / (double) this->samplingRate;
double cosX = cos(x);
double cosY = cos(y);
double sinY = sin(y);
double a = cosX * cosY;
double b = pow(cosX, 2.0) / 2.0;
double c = pow(sinY, 2.0);
// ((b - a) + 0.5) - c
double d = ((b - a) + 0.5) - c;
// c + (((b + pow(cosY, 2.0)) - a) - 0.5)
double e = c + (((b + pow(cosY, 2.0)) - a) - 0.5);
// ((pow(cosX, 2.0) / 8.0 - cosX * cosY / 4.0) + 0.125) - c / 4.0
double f = ((pow(cosX, 2.0) * 0.125 - cosX * cosY * 0.25) + 0.125) - c * 0.25;
if (SolveRoot(d, e, f, &ret1) == 0) {
this->coeffs[4 * i] = ret1 * 2.0;
this->coeffs[4 * i + 1] = ((0.5 - ret1) * 0.5) * 2.0;
this->coeffs[4 * i + 2] = ((ret1 + 0.5) * cosX) * 2.0;
}
}
return 1;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <cstdint>
class MinPhaseIIRCoeffs {
public:
MinPhaseIIRCoeffs();
~MinPhaseIIRCoeffs();
void Find_F1_F2(double param_2, double param_3, double *param_4, double *param_5);
double *GetCoefficients();
float GetIndexFrequency(uint32_t param_1);
int SolveRoot(double param_2, double param_3, double param_4, double *param_5);
int UpdateCoeffs(uint32_t bands, uint32_t samplingRate);
private:
double *coeffs;
uint32_t samplingRate;
uint32_t bands;
};

View File

@ -0,0 +1,156 @@
#include "MultiBiquad.h"
#include <cmath>
MultiBiquad::MultiBiquad() {
this->a1 = 0.0;
this->a2 = 0.0;
this->b0 = 0.0;
this->b1 = 0.0;
this->b2 = 0.0;
this->x1 = 0.0;
this->x2 = 0.0;
this->y1 = 0.0;
this->y2 = 0.0;
}
double MultiBiquad::ProcessSample(double sample) {
double out =
sample * this->b0 +
this->x1 * this->b1 +
this->x2 * this->b2 +
this->y1 * this->a1 +
this->y2 * this->a2;
this->x2 = this->x1;
this->x1 = sample;
this->y2 = this->y1;
this->y1 = out;
return out;
}
void
MultiBiquad::RefreshFilter(FilterType type, float gainAmp, float frequency, uint32_t samplingRate, float qFactor, bool param_7) {
double gain;
if (type == FilterType::PEAK || type == FilterType::LOW_SHELF || type == HIGH_SHELF) {
gain = pow(10.0, (double) gainAmp / 40.0);
} else {
gain = pow(10.0, (double) gainAmp / 20.0);
}
double omega = (2.0 * M_PI * (double) frequency) / (double) samplingRate;
double sinOmega = sin(omega);
double cosOmega = cos(omega);
double y;
double z;
if (type == FilterType::LOW_SHELF || type == FilterType::HIGH_SHELF) {
y = sinOmega / 2.0 * sqrt((1.0 / gain + gain) * (1.0 / (double) qFactor - 1.0) + 2.0);
z = sqrt(gain) * 2.0 * y;
} else if (!param_7) {
y = sinOmega / ((double) qFactor * 2.0);
z = -1.0; // Unused in this case
} else {
y = sinh(((double) qFactor * log(2.0) * omega / 2.0) / sinOmega) * sinOmega;
z = -1.0; // Unused in this case
}
double a0;
double a1;
double a2;
double b0;
double b1;
double b2;
switch (type) {
case LOW_PASS: {
a0 = 1.0 + y;
a1 = -2.0 * cosOmega;
a2 = 1.0 - y;
b0 = (1.0 - cosOmega) / 2.0;
b1 = 1.0 - cosOmega;
b2 = (1.0 - cosOmega) / 2.0;
break;
}
case HIGH_PASS: {
a0 = 1.0 + y;
a1 = -2.0 * cosOmega;
a2 = 1.0 - y;
b0 = (1.0 + cosOmega) / 2.0;
b1 = -(1.0 + cosOmega);
b2 = (1.0 + cosOmega) / 2.0;
break;
}
case BAND_PASS: {
a0 = 1.0 + y;
a1 = -2.0 * cosOmega;
a2 = 1.0 - y;
b0 = y;
b1 = 0.0;
b2 = -y;
break;
}
case BAND_STOP: {
a0 = 1.0 + y;
a1 = -2.0 * cosOmega;
a2 = 1.0 - y;
b0 = 1.0;
b1 = -2.0 * cosOmega;
b2 = 1.0;
break;
}
case ALL_PASS: {
a0 = 1.0 + y;
a1 = -2.0 * cosOmega;
a2 = 1.0 - y;
b0 = 1.0 - y;
b1 = -2.0 * cosOmega;
b2 = 1.0 + y;
break;
}
case PEAK: {
a0 = 1.0 + y / gain;
a1 = -2.0 * cosOmega;
a2 = 1.0 - y / gain;
b0 = 1.0 + y * gain;
b1 = -2.0 * cosOmega;
b2 = 1.0 - y * gain;
break;
}
case LOW_SHELF: { // TODO: Check me!
double tmp1 = (gain + 1.0) - (gain - 1.0) * cosOmega;
double tmp2 = (gain + 1.0) + (gain - 1.0) * cosOmega;
a1 = ((gain - 1.0) + (gain + 1.0) * cosOmega) * -2.0;
a2 = tmp2 - z;
b1 = (gain * 2.0) * ((gain - 1.0) - (gain + 1.0) * cosOmega);
a0 = tmp2 + z;
b0 = (tmp1 + z) * gain;
b2 = (tmp1 - z) * gain;
break;
}
case HIGH_SHELF: { // TODO: Check me!
double tmp1 = (gain + 1.0) + (gain - 1.0) * cosOmega;
double tmp2 = (gain + 1.0) - (gain - 1.0) * cosOmega;
a2 = tmp2 - z;
a0 = tmp2 + z;
a1 = ((gain - 1.0) - (gain + 1.0) * cosOmega) * 2.0;
b1 = gain * -2.0 * ((gain - 1.0) + (gain + 1.0) * cosOmega);
b0 = (tmp1 + z) * gain;
b2 = (tmp1 - z) * gain;
break;
}
}
this->x2 = 0.0;
this->x1 = 0.0;
this->y2 = 0.0;
this->y1 = 0.0;
this->a1 = -a1 / a0;
this->a2 = -a2 / a0;
this->b0 = b0 / a0;
this->b1 = b1 / a0;
this->b2 = b2 / a0;
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <cstdint>
class MultiBiquad {
public:
enum FilterType {
LOW_PASS,
HIGH_PASS,
BAND_PASS,
BAND_STOP,
ALL_PASS,
PEAK,
LOW_SHELF,
HIGH_SHELF
};
MultiBiquad();
double ProcessSample(double sample);
void RefreshFilter(FilterType type, float gainAmp, float frequency, uint32_t samplingRate, float qFactor, bool param_7);
private:
double x1;
double x2;
double y1;
double y2;
double a1;
double a2;
double b0;
double b1;
double b2;
};

View File

@ -0,0 +1,52 @@
#include "NoiseSharpening.h"
#include "../constants.h"
NoiseSharpening::NoiseSharpening() {
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->gain = 0.0;
Reset();
}
void NoiseSharpening::Process(float *buffer, uint32_t size) {
for (uint32_t i = 0; i < size; i++) {
float sampleLeft = buffer[i * 2];
float sampleRight = buffer[i * 2 + 1];
float prevLeft = this->in[0];
float prevRight = this->in[1];
this->in[0] = sampleLeft;
this->in[1] = sampleRight;
float diffLeft = (sampleLeft - prevLeft) * this->gain;
float diffRight = (sampleRight - prevRight) * this->gain;
float sampleLeftIn = sampleLeft + diffLeft;
float sampleRightIn = sampleRight + diffRight;
float hist = (sampleLeftIn) * this->filters[0].b1;
float left = this->filters[0].prevSample + (sampleLeftIn) * this->filters[0].b0;
this->filters[0].prevSample = (sampleLeftIn) * this->filters[0].a1 + hist;
hist = (sampleRightIn) * this->filters[1].b1;
float right = this->filters[1].prevSample + (sampleRightIn) * this->filters[1].b0;
this->filters[1].prevSample = (sampleRightIn) * this->filters[1].a1 + hist;
buffer[i * 2] = left;
buffer[i * 2 + 1] = right;
}
}
void NoiseSharpening::Reset() {
for (int i = 0; i < 2; i++) {
this->filters[i].setLPF_BW((float) ((double) this->samplingRate / 2.0 - 1000.0), this->samplingRate);
this->filters[i].Mute();
this->in[i] = 0.0;
}
}
void NoiseSharpening::SetGain(float gain) {
this->gain = gain;
}
void NoiseSharpening::SetSamplingRate(uint32_t samplingRate) {
this->samplingRate = samplingRate;
Reset();
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "IIR_1st.h"
class NoiseSharpening {
public:
NoiseSharpening();
void Process(float *buffer, uint32_t size);
void Reset();
void SetGain(float gain);
void SetSamplingRate(uint32_t samplingRate);
IIR_1st filters[2];
float in[2];
int32_t samplingRate;
float gain;
};

View File

@ -0,0 +1,103 @@
#include <cstdlib>
#include <cstring>
#include "PConvSingle_F32.h"
PConvSingle_F32::PConvSingle_F32() {
this->enabled = false;
this->segments = 0;
this->segmentSize = 0;
this->data = nullptr;
}
PConvSingle_F32::~PConvSingle_F32() {
ReleaseResources();
}
void PConvSingle_F32::Reset() {
// TODO
}
int PConvSingle_F32::GetFFTSize() {
return this->segmentSize * 2;
}
int PConvSingle_F32::GetSegmentCount() {
return this->segments;
}
int PConvSingle_F32::GetSegmentSize() {
return this->segmentSize;
}
bool PConvSingle_F32::InstanceUsable() {
return this->enabled;
}
void PConvSingle_F32::Convolve(float *buffer) {
ConvSegment(buffer, false, 0);
}
void PConvSingle_F32::ConvolveInterleaved(float *buffer, int channel) {
ConvSegment(buffer, true, channel);
}
void PConvSingle_F32::ConvSegment(float *buffer, bool interleaved, int channel) {
// TODO
}
int PConvSingle_F32::LoadKernel(float *buf, int param_2, int segmentSize) {
if (buf == nullptr) {
return 0;
}
if (param_2 > 0 && segmentSize > 0 && segmentSize % 2 == 0) {
this->enabled = false;
ReleaseResources();
this->data = new PConvData(); //(PConvData *) malloc(0x140); // TODO: Sizeof
this->segmentSize = segmentSize;
int n = ProcessKernel(buf, param_2, 1);
if (n != 0) {
this->enabled = true;
return n;
}
ReleaseResources();
}
return 0;
}
int PConvSingle_F32::LoadKernel(float *buf, float *param_2, int segmentSize, int param_4, int param_5) {
if (buf == nullptr) {
return 0;
}
if (param_5 > 0 && segmentSize > 0 && segmentSize % 2 == 0) {
this->enabled = false;
ReleaseResources();
this->data = new PConvData(); //(PConvData *) malloc(0x140); // TODO: Sizeof
this->segmentSize = segmentSize;
int n = ProcessKernel(1, param_2, param_4, param_5);
if (n != 0) {
this->enabled = true;
return n;
}
ReleaseResources();
}
return 0;
}
int PConvSingle_F32::ProcessKernel(float *param_1, int param_2, int param_3) {
// TODO
return 0;
}
int PConvSingle_F32::ProcessKernel(int param_2, float *param_3, int param_4, int param_5) {
// TODO
return 0;
}
void PConvSingle_F32::ReleaseResources() {
// TODO
}
void PConvSingle_F32::UnloadKernel() {
this->enabled = false;
ReleaseResources();
}

View File

@ -0,0 +1,61 @@
#pragma once
typedef struct {
int unk_0x00;
int unk_0x04;
int unk_0x08;
float *unk_buffer;
float *fftInputBuffer;
float *fftOutputBuffer;
float *unk_buffer_2;
float *unk_buffer_3;
int size_A;
void *field_A1;
void *field_A2;
int size_B;
void *field_B1;
void *field_B2;
int *unk_0x120;
void *fft_plan_1;
void *fft_plan_2;
} PConvData;
class PConvSingle_F32 {
public:
PConvSingle_F32();
~PConvSingle_F32();
void Reset();
int GetFFTSize();
int GetSegmentCount();
int GetSegmentSize();
bool InstanceUsable();
void Convolve(float *buffer);
void ConvolveInterleaved(float *buffer, int channel);
void ConvSegment(float *buffer, bool interleaved, int channel);
int LoadKernel(float *buf, int param_2, int segmentSize);
int LoadKernel(float *buf, float *param_2, int segmentSize, int param_4, int param_5);
int ProcessKernel(float *param_1, int param_2, int param_3);
int ProcessKernel(int param_2, float *param_3, int param_4, int param_5);
void ReleaseResources();
void UnloadKernel();
bool enabled;
int segments, segmentSize;
PConvData *data; // TODO: Type
};

View File

@ -0,0 +1,59 @@
#include "PassFilter.h"
#include "../constants.h"
PassFilter::PassFilter() {
this->filters[0] = new IIR_NOrder_BW_LH(3);
this->filters[1] = new IIR_NOrder_BW_LH(3);
this->filters[2] = new IIR_NOrder_BW_LH(1);
this->filters[3] = new IIR_NOrder_BW_LH(1);
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
Reset();
}
PassFilter::~PassFilter() {
delete this->filters[0];
delete this->filters[1];
delete this->filters[2];
delete this->filters[3];
}
void PassFilter::ProcessFrames(float *buffer, uint32_t size) {
for (uint32_t x = 0; x < size; x++) {
float left = buffer[2 * x];
float right = buffer[2 * x + 1];
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;
}
}
void PassFilter::Reset() {
float cutoff;
if (this->samplingRate < 44100) {
cutoff = (float) this->samplingRate - 100.0f;
} else {
cutoff = 18000.0;
}
this->filters[0]->setLPF(cutoff, this->samplingRate);
this->filters[1]->setLPF(cutoff, this->samplingRate);
this->filters[2]->setHPF(10.0, this->samplingRate);
this->filters[3]->setHPF(10.0, this->samplingRate);
this->filters[0]->Mute();
this->filters[1]->Mute();
this->filters[2]->Mute();
this->filters[3]->Mute();
}
void PassFilter::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
Reset();
}
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <cstdint>
#include "IIR_NOrder_BW_LH.h"
class PassFilter {
public:
PassFilter();
~PassFilter();
void Reset();
void ProcessFrames(float *buffer, uint32_t size);
void SetSamplingRate(uint32_t samplingRate);
private:
IIR_NOrder_BW_LH *filters[4];
uint32_t samplingRate;
};

View File

@ -0,0 +1,65 @@
#include "PolesFilter.h"
#include "../constants.h"
#include <cstring>
#include <cmath>
PolesFilter::PolesFilter() {
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->lower_freq = 160;
this->upper_freq = 8000;
UpdateCoeff();
}
void PolesFilter::Reset() {
UpdateCoeff();
}
void PolesFilter::UpdateCoeff() {
memset(&this->channels[0], 0, sizeof(channel));
memset(&this->channels[1], 0, sizeof(channel));
this->channels[0].lower_angle = (float) this->lower_freq * (float) M_PI / (float) this->samplingRate;
this->channels[1].lower_angle = (float) this->lower_freq * (float) M_PI / (float) this->samplingRate;
this->channels[0].upper_angle = (float) this->upper_freq * (float) M_PI / (float) this->samplingRate;
this->channels[1].upper_angle = (float) this->upper_freq * (float) M_PI / (float) this->samplingRate;
}
static inline void DoFilterSide(channel *side, float sample, float *out1, float *out2, float *out3) {
float oldestSampleIn = side->in[2];
side->in[2] = side->in[1];
side->in[1] = side->in[0];
side->in[0] = sample;
side->x[0] += side->lower_angle * (sample - side->x[0]);
side->x[1] += side->lower_angle * (side->x[0] - side->x[1]);
side->x[2] += side->lower_angle * (side->x[1] - side->x[2]);
side->x[3] += side->lower_angle * (side->x[2] - side->x[3]);
side->y[0] += side->upper_angle * (sample - side->y[0]);
side->y[1] += side->upper_angle * (side->y[0] - side->y[1]);
side->y[2] += side->upper_angle * (side->y[1] - side->y[2]);
side->y[3] += side->upper_angle * (side->y[2] - side->y[3]);
*out1 = side->x[3];
*out2 = oldestSampleIn - side->y[3];
*out3 = side->y[3] - side->x[3];
}
void PolesFilter::DoFilterLeft(float sample, float *out1, float *out2, float *out3) {
DoFilterSide(&this->channels[0], sample, out1, out2, out3);
}
void PolesFilter::DoFilterRight(float sample, float *out1, float *out2, float *out3) {
DoFilterSide(&this->channels[1], sample, out1, out2, out3);
}
void PolesFilter::SetPassFilter(uint32_t lower_freq, uint32_t upper_freq) {
this->lower_freq = lower_freq;
this->upper_freq = upper_freq;
UpdateCoeff();
}
void PolesFilter::SetSamplingRate(uint32_t samplingRate) {
this->samplingRate = samplingRate;
UpdateCoeff();
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <cstdint>
typedef struct {
float lower_angle;
float upper_angle;
float in[3];
float x[4];
float y[4];
} channel;
class PolesFilter {
public:
PolesFilter();
void Reset();
void UpdateCoeff();
void DoFilterLeft(float sample, float *out1, float *out2, float *out3);
void DoFilterRight(float sample, float *out1, float *out2, float *out3);
void SetPassFilter(uint32_t lower_freq, uint32_t upper_freq);
void SetSamplingRate(uint32_t samplingRate);
channel channels[2];
uint32_t lower_freq;
uint32_t upper_freq;
uint32_t samplingRate;
};

View File

@ -0,0 +1,193 @@
#include "Polyphase.h"
#include "../constants.h"
static const float POLYPHASE_COEFFICIENTS_2[] = {
-0.002339,
-0.002073,
-0.001940,
-0.001675,
-0.001515,
-0.001329,
-0.001223,
-0.001037,
-0.000904,
-0.000851,
-0.000532,
-0.000851,
-0.000106,
-0.001010,
0.000558,
-0.001435,
0.001302,
-0.001967,
0.002259,
-0.002605,
0.003216,
-0.003562,
0.004784,
-0.005475,
0.007655,
-0.008506,
0.017622,
-0.024639,
0.028679,
-0.017303,
-0.032507,
0.623321,
0.184702,
-0.166867,
0.025729,
-0.078490,
-0.015735,
-0.041199,
-0.023151,
-0.031524,
-0.020121,
-0.024985,
-0.017303,
-0.019616,
-0.015018,
-0.015204,
-0.012838,
-0.011881,
-0.010951,
-0.009516,
-0.009090,
-0.007788,
-0.007442,
-0.006353,
-0.006087,
-0.005183,
-0.004970,
-0.004253,
-0.003987,
-0.003482,
-0.003216,
-0.002871,
-0.002578
};
static const float POLYPHASE_COEFFICIENTS_OTHER[] = {
-0.014194,
-0.002339,
-0.006220,
-0.019722,
-0.020626,
-0.014885,
-0.012240,
-0.012386,
-0.011801,
-0.011376,
-0.016293,
-0.018845,
-0.018327,
-0.013902,
-0.014951,
-0.015895,
-0.019044,
-0.017928,
-0.020094,
-0.017715,
-0.018845,
-0.015377,
-0.018354,
-0.016665,
-0.018951,
-0.011416,
-0.019469,
-0.017250,
0.003549,
-0.076045,
0.288350,
0.267751,
-0.041212,
-0.005130,
-0.088418,
-0.089348,
-0.087686,
-0.065625,
-0.041305,
-0.013343,
0.001422,
0.010313,
0.005834,
-0.001170,
-0.014499,
-0.021822,
-0.030792,
-0.029331,
-0.031071,
-0.018407,
-0.027271,
-0.008373,
-0.010791,
-0.040680,
0.229171,
0.080324,
-0.070955,
0.021689,
-0.046607,
-0.025011,
-0.026886,
-0.027271,
-0.032919
};
Polyphase::Polyphase(int param_1) {
this->samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->waveBuffer1 = new WaveBuffer(2, 0x1000);
this->waveBuffer2 = new WaveBuffer(2, 0x1000);
this->buffer = new float[0x7e0];
if (param_1 == 2) {
this->fir1.LoadCoefficients(POLYPHASE_COEFFICIENTS_2, 63, 1008);
this->fir2.LoadCoefficients(POLYPHASE_COEFFICIENTS_2, 63, 1008);
} else { // if (param_1 < 2)
this->fir1.LoadCoefficients(POLYPHASE_COEFFICIENTS_OTHER, 63, 1008);
this->fir2.LoadCoefficients(POLYPHASE_COEFFICIENTS_OTHER, 63, 1008);
}
}
Polyphase::~Polyphase() {
delete this->waveBuffer1;
delete this->waveBuffer2;
delete[] this->buffer;
}
uint32_t Polyphase::GetLatency() {
return 63;
}
uint32_t Polyphase::Process(float *samples, uint32_t size) {
if (this->waveBuffer1->PushSamples(samples, size)) {
while (this->waveBuffer1->GetBufferOffset() >= 1008) {
if (this->waveBuffer1->PopSamples(this->buffer, 1008, false) == 1008) {
this->fir1.FilterSamplesInterleaved(this->buffer, 1008, 2);
this->fir2.FilterSamplesInterleaved(this->buffer + 1, 1008, 2);
this->waveBuffer2->PushSamples(this->buffer, 1008);
}
}
if (this->waveBuffer2->GetBufferOffset() < size) {
return 0;
}
this->waveBuffer2->PopSamples(samples, size, true);
}
return size;
}
void Polyphase::Reset() {
this->fir1.Reset();
this->fir2.Reset();
this->waveBuffer1->Reset();
this->waveBuffer2->Reset();
}
void Polyphase::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
#include "FIR.h"
#include "WaveBuffer.h"
class Polyphase {
public:
Polyphase(int param_1);
~Polyphase();
uint32_t GetLatency();
uint32_t Process(float *samples, uint32_t size);
void Reset();
void SetSamplingRate(uint32_t samplingRate);
private:
FIR fir1;
FIR fir2;
WaveBuffer *waveBuffer1;
WaveBuffer *waveBuffer2;
float *buffer;
uint32_t samplingRate;
};

View File

@ -0,0 +1,66 @@
#include "Stereo3DSurround.h"
Stereo3DSurround::Stereo3DSurround() {
this->middleImage = 1.0;
this->stereoWiden = 0.0;
this->coeffLeft = 0.5;
this->coeffRight = 0.5;
}
void Stereo3DSurround::Process(float *samples, uint32_t size) {
if (size == 0) return;
uint32_t pairs = size / 2;
uint32_t remainder = size % 2;
if (pairs > 0) {
for (uint32_t i = 0; i < pairs; i++) {
float a = this->coeffLeft * (samples[4 * i] + samples[4 * i + 1]);
float b = this->coeffRight * (samples[4 * i + 1] - samples[4 * i]);
float c = this->coeffLeft * (samples[4 * i + 2] + samples[4 * i + 3]);
float d = this->coeffRight * (samples[4 * i + 3] - samples[4 * i + 2]);
samples[4 * i] = a - b;
samples[4 * i + 1] = a + b;
samples[4 * i + 2] = c - d;
samples[4 * i + 3] = c + d;
}
}
if (remainder > 0) {
for (uint32_t i = pairs; i < pairs + remainder; i++) {
float a = samples[2 * i];
float b = samples[2 * i + 1];
float c = this->coeffLeft * (a + b);
float d = this->coeffRight * (b - a);
samples[2 * i] = c - d;
samples[2 * i + 1] = c + d;
}
}
}
inline void Stereo3DSurround::ConfigureVariables() {
float tmp = this->stereoWiden + 1.0f;
float x = tmp + 1.0f;
float y;
if (x < 2.0) {
y = 0.5;
} else {
y = 1.0f / x;
}
this->coeffLeft = this->middleImage * y;
this->coeffRight = tmp * y;
}
void Stereo3DSurround::SetMiddleImage(float middleImage) {
this->middleImage = middleImage;
this->ConfigureVariables();
}
void Stereo3DSurround::SetStereoWiden(float stereoWiden) {
this->stereoWiden = stereoWiden;
this->ConfigureVariables();
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <cstdint>
class Stereo3DSurround {
public:
Stereo3DSurround();
void Process(float *samples, uint32_t size);
void SetMiddleImage(float middleImage);
void SetStereoWiden(float stereoWiden);
private:
void ConfigureVariables();
float stereoWiden;
float middleImage;
float coeffLeft;
float coeffRight;
};

View File

@ -0,0 +1,36 @@
#include "Subwoofer.h"
#include "../constants.h"
#include <cmath>
Subwoofer::Subwoofer() {
uint32_t samplingRate = VIPER_DEFAULT_SAMPLING_RATE;
this->peak[0].RefreshFilter(MultiBiquad::FilterType::PEAK, 0.0, 37.0, samplingRate, 1.0, false);
this->peak[1].RefreshFilter(MultiBiquad::FilterType::PEAK, 0.0, 37.0, samplingRate, 1.0, false);
this->peakLow[0].RefreshFilter(MultiBiquad::FilterType::PEAK, 0.0, 75.0, samplingRate, 1.0, false);
this->peakLow[1].RefreshFilter(MultiBiquad::FilterType::PEAK, 0.0, 75.0, samplingRate, 1.0, false);
this->lowpass[0].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 200.0, samplingRate, 1.0, false);
this->lowpass[1].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 200.0, samplingRate, 1.0, false);
}
void Subwoofer::Process(float *samples, uint32_t size) {
for (uint32_t i = 0; i < size * 2; i++) {
auto sample = (double) samples[i];
int index = i % 2;
double tmp = this->peak[index].ProcessSample(sample);
tmp = this->peakLow[index].ProcessSample(tmp);
tmp = this->lowpass[index].ProcessSample(tmp - sample);
samples[i] = (float) ((sample / 2.0) + (tmp * 0.6));
}
}
void Subwoofer::SetBassGain(uint32_t samplingRate, float gainDb) {
float gain = 20.0f * log10( gainDb);
float gainLower = 20.0f * log10( gainDb / 8.0f);
this->peak[0].RefreshFilter(MultiBiquad::FilterType::PEAK, gain, 44.0, samplingRate, 0.75, true);
this->peak[1].RefreshFilter(MultiBiquad::FilterType::PEAK, gain, 44.0, samplingRate, 0.75, true);
this->peakLow[0].RefreshFilter(MultiBiquad::FilterType::PEAK, gainLower, 80.0, samplingRate, 0.2, true);
this->peakLow[1].RefreshFilter(MultiBiquad::FilterType::PEAK, gainLower, 80.0, samplingRate, 0.2, true);
this->lowpass[0].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 380.0, samplingRate, 0.6, false);
this->lowpass[1].RefreshFilter(MultiBiquad::FilterType::LOW_PASS, 0.0, 380.0, samplingRate, 0.6, false);
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
#include "MultiBiquad.h"
class Subwoofer {
public:
Subwoofer();
void Process(float *samples, uint32_t size);
void SetBassGain(uint32_t samplingRate, float gainDb);
private:
MultiBiquad peak[2];
MultiBiquad peakLow[2];
MultiBiquad lowpass[2];
};

View File

@ -0,0 +1,29 @@
#include "TimeConstDelay.h"
#include <cstdlib>
TimeConstDelay::TimeConstDelay() {
this->samples = nullptr;
this->offset = 0;
this->sampleCount = 0;
}
TimeConstDelay::~TimeConstDelay() {
delete[] this->samples;
}
float TimeConstDelay::ProcessSample(float sample) {
if (this->samples != nullptr) {
float val = this->samples[this->offset];
this->samples[this->offset] = sample;
this->offset = (int) modf((float) this->offset + 1, (float *) &this->sampleCount); // TODO: check if this is correct
return val;
}
return 0.0;
}
void TimeConstDelay::SetParameters(uint32_t samplingRate, float delay) {
this->sampleCount = (uint32_t) ((float) samplingRate * delay);
delete[] this->samples;
this->samples = new float[this->sampleCount]();
this->offset = 0;
}

View File

@ -0,0 +1,17 @@
#pragma once
#include <cstdint>
class TimeConstDelay {
public:
TimeConstDelay();
~TimeConstDelay();
float ProcessSample(float sample);
void SetParameters(uint32_t samplingRate, float delay);
private:
float *samples;
uint32_t offset;
uint32_t sampleCount;
};

View File

@ -0,0 +1,143 @@
#include "WaveBuffer.h"
#include <cstring>
WaveBuffer::WaveBuffer(uint32_t channels, uint32_t length) {
this->channels = channels;
this->size = length * channels;
this->index = 0;
this->buffer = new float[this->size];
}
WaveBuffer::~WaveBuffer() {
delete[] this->buffer;
}
uint32_t WaveBuffer::GetBufferOffset() {
return this->index / this->channels;
}
uint32_t WaveBuffer::GetBufferSize() {
return this->size / this->channels;
}
float *WaveBuffer::GetBuffer() {
return this->buffer;
}
uint32_t WaveBuffer::PopSamples(uint32_t size, bool resetIndex) {
if (this->buffer == nullptr || this->size == 0) {
return 0;
}
if (this->channels * size <= this->index) {
this->index -= this->channels * size;
memmove(this->buffer, this->buffer + this->channels * size, this->index * sizeof(float));
return size;
}
if (resetIndex) {
uint32_t ret = this->index / this->channels;
this->index = 0;
return ret;
}
return 0;
}
uint32_t WaveBuffer::PopSamples(float *dest, uint32_t size, bool resetIndex) {
if (this->buffer == nullptr || this->size == 0 || dest == nullptr) {
return 0;
}
if (this->channels * size <= this->index) {
memcpy(dest, this->buffer, this->channels * size * sizeof(float));
this->index -= this->channels * size;
memmove(this->buffer, this->buffer + this->channels * size, this->index * sizeof(float));
return size;
}
if (resetIndex) {
uint32_t ret = this->index / this->channels;
memcpy(dest, this->buffer, this->index * sizeof(float));
this->index = 0;
return ret;
}
return 0;
}
int WaveBuffer::PushSamples(float *source, uint32_t size) {
if (this->buffer == nullptr) {
return 0;
}
if (size > 0) {
uint32_t requiredSize = this->channels * size + this->index;
if (this->size < requiredSize) {
auto *newBuffer = new float[requiredSize];
memcpy(newBuffer, this->buffer, this->index * sizeof(float));
delete[] this->buffer;
this->buffer = newBuffer;
this->size = requiredSize;
}
memcpy(this->buffer + this->index, source, this->channels * size * sizeof(float));
this->index += this->channels * size;
}
return 1;
}
int WaveBuffer::PushZeros(uint32_t size) {
if (this->buffer == nullptr) {
return 0;
}
if (size > 0) {
uint32_t requiredSize = this->channels * size + this->index;
if (this->size < requiredSize) {
auto *newBuffer = new float[requiredSize];
memcpy(newBuffer, this->buffer, this->index * sizeof(float));
delete[] this->buffer;
this->buffer = newBuffer;
this->size = requiredSize;
}
memset(this->buffer + this->index, 0, this->channels * size * sizeof(float));
this->index += this->channels * size;
}
return 1;
}
float *WaveBuffer::PushZerosGetBuffer(uint32_t size) {
if (this->buffer == nullptr) {
return nullptr;
}
uint32_t oldIndex = this->index;
if (size > 0) {
uint32_t requiredSize = this->channels * size + this->index;
if (this->size < requiredSize) {
auto *newBuffer = new float[requiredSize];
memcpy(newBuffer, this->buffer, this->index * sizeof(float));
delete[] this->buffer;
this->buffer = newBuffer;
this->size = requiredSize;
}
memset(this->buffer + this->index, 0, this->channels * size * sizeof(float));
this->index += this->channels * size;
}
return this->buffer + oldIndex;
}
void WaveBuffer::Reset() {
this->index = 0;
}
void WaveBuffer::SetBufferOffset(uint32_t offset) {
uint32_t maxOffset = this->size / this->channels;
if (offset <= maxOffset) {
this->index = offset * this->channels;
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <cstdint>
class WaveBuffer {
public:
WaveBuffer(uint32_t channels, uint32_t length);
~WaveBuffer();
void Reset();
uint32_t GetBufferOffset();
uint32_t GetBufferSize();
float *GetBuffer();
uint32_t PopSamples(uint32_t size, bool resetIndex);
uint32_t PopSamples(float *dest, uint32_t size, bool resetIndex);
int PushSamples(float *source, uint32_t size);
int PushZeros(uint32_t size);
float *PushZerosGetBuffer(uint32_t size);
void SetBufferOffset(uint32_t offset);
private:
float *buffer;
uint32_t size;
uint32_t index;
uint32_t channels;
};