mirror of
https://github.com/AndroidAudioMods/ViPERFX_RE.git
synced 2025-06-22 16:22:24 +08:00
Update
This commit is contained in:
610
src/viper/ViPER.cpp
Normal file
610
src/viper/ViPER.cpp
Normal 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
66
src/viper/ViPER.h
Normal 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
16
src/viper/constants.h
Normal 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"
|
117
src/viper/effects/AnalogX.cpp
Normal file
117
src/viper/effects/AnalogX.cpp
Normal 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();
|
||||
}
|
||||
}
|
30
src/viper/effects/AnalogX.h
Normal file
30
src/viper/effects/AnalogX.h
Normal 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;
|
||||
};
|
||||
|
||||
|
49
src/viper/effects/ColorfulMusic.cpp
Normal file
49
src/viper/effects/ColorfulMusic.cpp
Normal 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);
|
||||
}
|
27
src/viper/effects/ColorfulMusic.h
Normal file
27
src/viper/effects/ColorfulMusic.h
Normal 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;
|
||||
|
||||
};
|
||||
|
||||
|
63
src/viper/effects/Convolver.cpp
Normal file
63
src/viper/effects/Convolver.cpp
Normal 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) {
|
||||
|
||||
}
|
||||
|
||||
|
25
src/viper/effects/Convolver.h
Normal file
25
src/viper/effects/Convolver.h
Normal 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);
|
||||
};
|
||||
|
||||
|
60
src/viper/effects/Cure.cpp
Normal file
60
src/viper/effects/Cure.cpp
Normal 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
27
src/viper/effects/Cure.h
Normal 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;
|
||||
};
|
73
src/viper/effects/DiffSurround.cpp
Normal file
73
src/viper/effects/DiffSurround.cpp
Normal 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();
|
||||
}
|
||||
}
|
23
src/viper/effects/DiffSurround.h
Normal file
23
src/viper/effects/DiffSurround.h
Normal 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];
|
||||
};
|
||||
|
||||
|
52
src/viper/effects/DynamicSystem.cpp
Normal file
52
src/viper/effects/DynamicSystem.cpp
Normal 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);
|
||||
}
|
25
src/viper/effects/DynamicSystem.h
Normal file
25
src/viper/effects/DynamicSystem.h
Normal 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;
|
||||
};
|
||||
|
||||
|
267
src/viper/effects/FETCompressor.cpp
Normal file
267
src/viper/effects/FETCompressor.cpp
Normal 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();
|
||||
}
|
72
src/viper/effects/FETCompressor.h
Normal file
72
src/viper/effects/FETCompressor.h
Normal 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;
|
||||
};
|
||||
|
||||
|
2
src/viper/effects/FIREqualizer.cpp
Normal file
2
src/viper/effects/FIREqualizer.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "FIREqualizer.h"
|
||||
#include <cstring>
|
12
src/viper/effects/FIREqualizer.h
Normal file
12
src/viper/effects/FIREqualizer.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class FIREqualizer {
|
||||
public:
|
||||
FIREqualizer();
|
||||
~FIREqualizer();
|
||||
|
||||
};
|
||||
|
||||
|
91
src/viper/effects/IIRFilter.cpp
Normal file
91
src/viper/effects/IIRFilter.cpp
Normal 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();
|
||||
}
|
||||
}
|
28
src/viper/effects/IIRFilter.h
Normal file
28
src/viper/effects/IIRFilter.h
Normal 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];
|
||||
};
|
||||
|
||||
|
62
src/viper/effects/PlaybackGain.cpp
Normal file
62
src/viper/effects/PlaybackGain.cpp
Normal 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;
|
||||
}
|
35
src/viper/effects/PlaybackGain.h
Normal file
35
src/viper/effects/PlaybackGain.h
Normal 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;
|
||||
};
|
||||
|
||||
|
52
src/viper/effects/Reverberation.cpp
Normal file
52
src/viper/effects/Reverberation.cpp
Normal 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);
|
||||
}
|
25
src/viper/effects/Reverberation.h
Normal file
25
src/viper/effects/Reverberation.h
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
|
29
src/viper/effects/SoftwareLimiter.cpp
Normal file
29
src/viper/effects/SoftwareLimiter.cpp
Normal 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;
|
||||
}
|
24
src/viper/effects/SoftwareLimiter.h
Normal file
24
src/viper/effects/SoftwareLimiter.h
Normal 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;
|
||||
};
|
||||
|
||||
|
58
src/viper/effects/SpeakerCorrection.cpp
Normal file
58
src/viper/effects/SpeakerCorrection.cpp
Normal 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();
|
||||
}
|
||||
}
|
22
src/viper/effects/SpeakerCorrection.h
Normal file
22
src/viper/effects/SpeakerCorrection.h
Normal 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];
|
||||
};
|
82
src/viper/effects/SpectrumExtend.cpp
Normal file
82
src/viper/effects/SpectrumExtend.cpp
Normal 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();
|
||||
}
|
28
src/viper/effects/SpectrumExtend.h
Normal file
28
src/viper/effects/SpectrumExtend.h
Normal 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;
|
||||
};
|
||||
|
||||
|
37
src/viper/effects/TubeSimulator.cpp
Normal file
37
src/viper/effects/TubeSimulator.cpp
Normal 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() {
|
||||
|
||||
}
|
18
src/viper/effects/TubeSimulator.h
Normal file
18
src/viper/effects/TubeSimulator.h
Normal 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
61
src/viper/effects/VHE.cpp
Normal 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
27
src/viper/effects/VHE.h
Normal 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;
|
||||
};
|
||||
|
||||
|
140
src/viper/effects/ViPERBass.cpp
Normal file
140
src/viper/effects/ViPERBass.cpp
Normal 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);
|
||||
}
|
||||
}
|
42
src/viper/effects/ViPERBass.h
Normal file
42
src/viper/effects/ViPERBass.h
Normal 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;
|
||||
};
|
||||
|
||||
|
90
src/viper/effects/ViPERClarity.cpp
Normal file
90
src/viper/effects/ViPERClarity.cpp
Normal 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();
|
||||
}
|
||||
}
|
36
src/viper/effects/ViPERClarity.h
Normal file
36
src/viper/effects/ViPERClarity.h
Normal 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;
|
||||
};
|
||||
|
||||
|
33
src/viper/effects/ViPERDDC.cpp
Normal file
33
src/viper/effects/ViPERDDC.cpp
Normal 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) {
|
||||
|
||||
}
|
18
src/viper/effects/ViPERDDC.h
Normal file
18
src/viper/effects/ViPERDDC.h
Normal 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);
|
||||
};
|
||||
|
||||
|
117
src/viper/utils/AdaptiveBuffer.cpp
Normal file
117
src/viper/utils/AdaptiveBuffer.cpp
Normal 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;
|
||||
}
|
30
src/viper/utils/AdaptiveBuffer.h
Normal file
30
src/viper/utils/AdaptiveBuffer.h
Normal 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
112
src/viper/utils/Biquad.cpp
Normal 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
26
src/viper/utils/Biquad.h
Normal 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;
|
||||
};
|
37
src/viper/utils/CAllpassFilter.cpp
Normal file
37
src/viper/utils/CAllpassFilter.cpp
Normal 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;
|
||||
}
|
20
src/viper/utils/CAllpassFilter.h
Normal file
20
src/viper/utils/CAllpassFilter.h
Normal 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;
|
||||
};
|
50
src/viper/utils/CCombFilter.cpp
Normal file
50
src/viper/utils/CCombFilter.cpp
Normal 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;
|
||||
}
|
28
src/viper/utils/CCombFilter.h
Normal file
28
src/viper/utils/CCombFilter.h
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
|
206
src/viper/utils/CRevModel.cpp
Normal file
206
src/viper/utils/CRevModel.cpp
Normal 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);
|
||||
}
|
||||
}
|
51
src/viper/utils/CRevModel.h
Normal file
51
src/viper/utils/CRevModel.h
Normal 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];
|
||||
};
|
||||
|
||||
|
||||
|
109
src/viper/utils/Crossfeed.cpp
Normal file
109
src/viper/utils/Crossfeed.cpp
Normal 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();
|
||||
}
|
||||
}
|
35
src/viper/utils/Crossfeed.h
Normal file
35
src/viper/utils/Crossfeed.h
Normal 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;
|
||||
};
|
83
src/viper/utils/DepthSurround.cpp
Normal file
83
src/viper/utils/DepthSurround.cpp
Normal 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);
|
||||
}
|
24
src/viper/utils/DepthSurround.h
Normal file
24
src/viper/utils/DepthSurround.h
Normal 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;
|
||||
};
|
90
src/viper/utils/DynamicBass.cpp
Normal file
90
src/viper/utils/DynamicBass.cpp
Normal 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;
|
||||
}
|
35
src/viper/utils/DynamicBass.h
Normal file
35
src/viper/utils/DynamicBass.h
Normal 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
92
src/viper/utils/FIR.cpp
Normal 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
25
src/viper/utils/FIR.h
Normal 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;
|
||||
};
|
||||
|
||||
|
108
src/viper/utils/Harmonic.cpp
Normal file
108
src/viper/utils/Harmonic.cpp
Normal 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];
|
||||
}
|
22
src/viper/utils/Harmonic.h
Normal file
22
src/viper/utils/Harmonic.h
Normal 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
78
src/viper/utils/HiFi.cpp
Normal 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
32
src/viper/utils/HiFi.h
Normal 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;
|
||||
};
|
||||
|
||||
|
46
src/viper/utils/HighShelf.cpp
Normal file
46
src/viper/utils/HighShelf.cpp
Normal 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;
|
||||
}
|
28
src/viper/utils/HighShelf.h
Normal file
28
src/viper/utils/HighShelf.h
Normal 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
149
src/viper/utils/IIR_1st.cpp
Normal 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
36
src/viper/utils/IIR_1st.h
Normal 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;
|
||||
}
|
31
src/viper/utils/IIR_NOrder_BW_BP.cpp
Normal file
31
src/viper/utils/IIR_NOrder_BW_BP.cpp
Normal 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);
|
||||
}
|
||||
}
|
36
src/viper/utils/IIR_NOrder_BW_BP.h
Normal file
36
src/viper/utils/IIR_NOrder_BW_BP.h
Normal 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));
|
||||
}
|
32
src/viper/utils/IIR_NOrder_BW_LH.cpp
Normal file
32
src/viper/utils/IIR_NOrder_BW_LH.cpp
Normal 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);
|
||||
}
|
||||
}
|
25
src/viper/utils/IIR_NOrder_BW_LH.h
Normal file
25
src/viper/utils/IIR_NOrder_BW_LH.h
Normal 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;
|
||||
}
|
218
src/viper/utils/MinPhaseIIRCoeffs.cpp
Normal file
218
src/viper/utils/MinPhaseIIRCoeffs.cpp
Normal 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;
|
||||
}
|
20
src/viper/utils/MinPhaseIIRCoeffs.h
Normal file
20
src/viper/utils/MinPhaseIIRCoeffs.h
Normal 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;
|
||||
};
|
156
src/viper/utils/MultiBiquad.cpp
Normal file
156
src/viper/utils/MultiBiquad.cpp
Normal 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;
|
||||
}
|
36
src/viper/utils/MultiBiquad.h
Normal file
36
src/viper/utils/MultiBiquad.h
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
|
52
src/viper/utils/NoiseSharpening.cpp
Normal file
52
src/viper/utils/NoiseSharpening.cpp
Normal 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();
|
||||
}
|
25
src/viper/utils/NoiseSharpening.h
Normal file
25
src/viper/utils/NoiseSharpening.h
Normal 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;
|
||||
};
|
||||
|
||||
|
||||
|
103
src/viper/utils/PConvSingle_F32.cpp
Normal file
103
src/viper/utils/PConvSingle_F32.cpp
Normal 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();
|
||||
}
|
61
src/viper/utils/PConvSingle_F32.h
Normal file
61
src/viper/utils/PConvSingle_F32.h
Normal 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
|
||||
};
|
59
src/viper/utils/PassFilter.cpp
Normal file
59
src/viper/utils/PassFilter.cpp
Normal 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();
|
||||
}
|
||||
}
|
18
src/viper/utils/PassFilter.h
Normal file
18
src/viper/utils/PassFilter.h
Normal 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;
|
||||
};
|
65
src/viper/utils/PolesFilter.cpp
Normal file
65
src/viper/utils/PolesFilter.cpp
Normal 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();
|
||||
}
|
37
src/viper/utils/PolesFilter.h
Normal file
37
src/viper/utils/PolesFilter.h
Normal 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;
|
||||
};
|
||||
|
||||
|
193
src/viper/utils/Polyphase.cpp
Normal file
193
src/viper/utils/Polyphase.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
26
src/viper/utils/Polyphase.h
Normal file
26
src/viper/utils/Polyphase.h
Normal 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;
|
||||
};
|
||||
|
||||
|
66
src/viper/utils/Stereo3DSurround.cpp
Normal file
66
src/viper/utils/Stereo3DSurround.cpp
Normal 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();
|
||||
}
|
22
src/viper/utils/Stereo3DSurround.h
Normal file
22
src/viper/utils/Stereo3DSurround.h
Normal 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;
|
||||
};
|
||||
|
||||
|
36
src/viper/utils/Subwoofer.cpp
Normal file
36
src/viper/utils/Subwoofer.cpp
Normal 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);
|
||||
}
|
19
src/viper/utils/Subwoofer.h
Normal file
19
src/viper/utils/Subwoofer.h
Normal 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];
|
||||
};
|
||||
|
||||
|
29
src/viper/utils/TimeConstDelay.cpp
Normal file
29
src/viper/utils/TimeConstDelay.cpp
Normal 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;
|
||||
}
|
17
src/viper/utils/TimeConstDelay.h
Normal file
17
src/viper/utils/TimeConstDelay.h
Normal 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;
|
||||
};
|
143
src/viper/utils/WaveBuffer.cpp
Normal file
143
src/viper/utils/WaveBuffer.cpp
Normal 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;
|
||||
}
|
||||
}
|
30
src/viper/utils/WaveBuffer.h
Normal file
30
src/viper/utils/WaveBuffer.h
Normal 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;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user