This commit is contained in:
Iscle 2022-10-11 00:36:38 +02:00
parent 9d54379bd8
commit 39aef22062
21 changed files with 407 additions and 529 deletions

View File

@ -1,7 +1,5 @@
#include <cstring>
#include <cerrno>
#include <ctime>
#include "viper/ViPER.h"
#include "essential.h"
#include "log.h"
@ -10,7 +8,6 @@
#define VIPER_EFFECT_NAME "ViPER4Android"
static effect_descriptor_t viper_descriptor = {
// ee48cf24-9221-4095-2cb9-40faa133111b
.type = EFFECT_UUID_INITIALIZER,
// 41d3c987-e6cf-11e3-a88a-11aba5d5c51b
// Original: {0x41d3c987, 0xe6cf, 0x11e3, 0xa88a, {0x11, 0xab, 0xa5, 0xd5, 0xc5, 0x1b}}
@ -28,18 +25,13 @@ extern "C" {
struct ViperContext {
const struct effect_interface_s *interface; // Should always be the first struct member
effect_config_t config;
bool isConfigValid;
ViPER *viper;
};
static int32_t Viper_IProcess(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
auto pContext = reinterpret_cast<ViperContext *>(self);
static uint32_t tmp = 0;
if (tmp % 50 == 0) {
VIPER_LOGD("Viper_IProcess called!");
}
tmp++;
if (pContext == nullptr ||
inBuffer == nullptr || outBuffer == nullptr ||
inBuffer->raw == nullptr || outBuffer->raw == nullptr ||
@ -55,12 +47,12 @@ static int32_t Viper_IProcess(effect_handle_t self, audio_buffer_t *inBuffer, au
memcpy(outBufferPtr, inBufferPtr, outBuffer->frameCount * 2 * sizeof(float));
}
/*return */pContext->viper->processBuffer(outBufferPtr, outBuffer->frameCount);
return 0; // TODO: Return code from processBuffer()
pContext->viper->processBuffer(outBufferPtr, outBuffer->frameCount);
return 0;
}
static int configure(ViperContext *pContext, effect_config_t *newConfig) {
VIPER_LOGI("Begin audio configure ...");
static int handleSetConfig(ViperContext *pContext, effect_config_t *newConfig) {
VIPER_LOGI("Begin handleSetConfig ...");
VIPER_LOGI("Checking input and output configuration ...");
VIPER_LOGD("Input sampling rate: %d", newConfig->inputCfg.samplingRate);
@ -70,6 +62,8 @@ static int configure(ViperContext *pContext, effect_config_t *newConfig) {
VIPER_LOGD("Output channels: %d", newConfig->outputCfg.channels);
VIPER_LOGD("Output format: %d", newConfig->outputCfg.format);
pContext->isConfigValid = false;
if (newConfig->inputCfg.samplingRate != newConfig->outputCfg.samplingRate) {
VIPER_LOGE("ViPER4Android disabled, reason [in.SR = %d, out.SR = %d]",
newConfig->inputCfg.samplingRate, newConfig->outputCfg.samplingRate);
@ -109,19 +103,127 @@ static int configure(ViperContext *pContext, effect_config_t *newConfig) {
VIPER_LOGI("Input and output configuration checked.");
pContext->config = *newConfig;
pContext->viper->samplingRate = newConfig->inputCfg.samplingRate;
pContext->viper->ResetAllEffects();
pContext->isConfigValid = true;
VIPER_LOGI("Audio configure finished");
VIPER_LOGI("Audio handleSetConfig finished");
return 0;
}
static int32_t handleSetParam(ViperContext *pContext, effect_param_t *pCmdParam, void *pReplyData) {
// The value offset of an effect parameter is computed by rounding up
// the parameter size to the next 32 bit alignment.
uint32_t vOffset = ((pCmdParam->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) * sizeof(int32_t);
*(int *) pReplyData = 0;
int param = *(int *) (pCmdParam->data);
int *intValues = (int *) (pCmdParam->data + vOffset);
if (pCmdParam->vsize == sizeof(int)) {
pContext->viper->DispatchCommand(param, intValues[0], 0, 0, 0, 0, nullptr);
return 0;
} else if (pCmdParam->vsize == sizeof(int) * 2) {
pContext->viper->DispatchCommand(param, intValues[0], intValues[1], 0, 0, 0, nullptr);
return 0;
} else if (pCmdParam->vsize == sizeof(int) * 3) {
pContext->viper->DispatchCommand(param, intValues[0], intValues[1], intValues[2], 0, 0, nullptr);
return 0;
} else if (pCmdParam->vsize == sizeof(int) * 4) {
pContext->viper->DispatchCommand(param, intValues[0], intValues[1], intValues[2], intValues[3], 0, nullptr);
return 0;
} else if (pCmdParam->vsize == 256 || pCmdParam->vsize == 1024) {
uint32_t arrSize = *(uint32_t *) (pCmdParam->data + vOffset);
signed char *arr = (signed char *) (pCmdParam->data + vOffset + sizeof(uint32_t));
pContext->viper->DispatchCommand(param, 0, 0, 0, 0, arrSize, arr);
return 0;
} else if (pCmdParam->vsize == 8192) {
int value1 = *(int *) (pCmdParam->data + vOffset);
uint32_t arrSize = *(uint32_t *) (pCmdParam->data + vOffset + sizeof(int));
signed char *arr = (signed char *) (pCmdParam->data + vOffset + sizeof(int) + sizeof(uint32_t));
pContext->viper->DispatchCommand(param, value1, 0, 0, 0, arrSize, arr);
return 0;
}
return -EINVAL;
}
static int32_t handleGetParam(ViperContext *pContext, effect_param_t *pCmdParam, effect_param_t *pReplyParam, uint32_t *pReplySize) {
// The value offset of an effect parameter is computed by rounding up
// the parameter size to the next 32 bit alignment.
uint32_t vOffset = ((pCmdParam->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) * sizeof(int32_t);
VIPER_LOGD("Viper_ICommand() EFFECT_CMD_GET_PARAM called with data = %d, psize = %d, vsize = %d", *(uint32_t *) pCmdParam->data, pCmdParam->psize, pCmdParam->vsize);
memcpy(pReplyParam, pCmdParam, sizeof(effect_param_t) + pCmdParam->psize);
switch (*(uint32_t *) pCmdParam->data) {
case PARAM_GET_DRIVER_VERSION: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(uint32_t);
*(uint32_t *) (pReplyParam->data + vOffset) = 0x2050005; // As original, change as needed
*pReplySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_ENABLED: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(int32_t);
*(int32_t *) (pReplyParam->data + vOffset) = pContext->viper->enabled;
*pReplySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_CONFIGURE: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(int32_t);
*(int32_t *) (pReplyParam->data + vOffset) = pContext->isConfigValid;
*pReplySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_STREAMING: { // Is processing
struct timeval time{};
gettimeofday(&time, nullptr);
uint64_t currentMs = (time.tv_sec * 1000) + (time.tv_usec / 1000);
uint64_t lastProcessTime = pContext->viper->processTimeMs;
uint64_t diff;
if (currentMs > lastProcessTime) {
diff = currentMs - lastProcessTime;
} else {
diff = lastProcessTime - currentMs;
}
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(int32_t);
*(int32_t *) (pReplyParam->data + vOffset) = diff > 5000 ? 0 : 1;
*pReplySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_SAMPLING_RATE: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(uint32_t);
*(uint32_t *) (pReplyParam->data + vOffset) = pContext->viper->samplingRate;
*pReplySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_CONVOLUTION_KERNEL_ID: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(uint32_t);
*(uint32_t *) (pReplyParam->data + vOffset) = pContext->viper->convolver->GetKernelID();
*pReplySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
}
return 0;
}
static int32_t Viper_ICommand(effect_handle_t self,
uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
uint32_t *replySize, void *pReplyData) {
auto pContext = reinterpret_cast<ViperContext *>(self);
if (pContext == nullptr || pContext->viper == nullptr) {
VIPER_LOGE("Viper_ICommand: pContext or pContext->viper is null!");
return -EINVAL;
}
@ -131,25 +233,16 @@ static int32_t Viper_ICommand(effect_handle_t self,
*((int *) pReplyData) = 0;
return 0;
case EFFECT_CMD_SET_CONFIG: {
auto currentSampleRate = pContext->viper->samplingRate;
*(int *) pReplyData = configure(pContext, (effect_config_t *) pCmdData);
if (*(int *) pReplyData == 0) {
if (currentSampleRate != pContext->viper->samplingRate) {
pContext->viper->ResetAllEffects();
}
}
*(int *) pReplyData = handleSetConfig(pContext, (effect_config_t *) pCmdData);
return 0;
}
case EFFECT_CMD_RESET: {
pContext->viper->ResetAllEffects();
break;
*((int *) pReplyData) = 0;
return 0;
}
case EFFECT_CMD_ENABLE: {
if (!pContext->viper->enabled) {
pContext->viper->ResetAllEffects();
}
pContext->viper->ResetAllEffects();
pContext->viper->enabled = true;
*((int *) pReplyData) = 0;
return 0;
@ -160,108 +253,10 @@ static int32_t Viper_ICommand(effect_handle_t self,
return 0;
}
case EFFECT_CMD_SET_PARAM: {
auto *pCmdParam = reinterpret_cast<effect_param_t *>(pCmdData);
// The value offset of an effect parameter is computed by rounding up
// the parameter size to the next 32 bit alignment.
uint32_t vOffset = ((pCmdParam->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) * sizeof(int32_t);
int param = *(int *) (pCmdParam->data);
*(int *) pReplyData = 0;
int *intValues = (int *) (pCmdParam->data + vOffset);
if (pCmdParam->vsize == sizeof(int)) {
pContext->viper->DispatchCommand(param, intValues[0], 0, 0, 0, 0, nullptr);
return 0;
} else if (pCmdParam->vsize == sizeof(int) * 2) {
pContext->viper->DispatchCommand(param, intValues[0], intValues[1], 0, 0, 0, nullptr);
return 0;
} else if (pCmdParam->vsize == sizeof(int) * 3) {
pContext->viper->DispatchCommand(param, intValues[0], intValues[1], intValues[2], 0, 0, nullptr);
return 0;
} else if (pCmdParam->vsize == sizeof(int) * 4) {
pContext->viper->DispatchCommand(param, intValues[0], intValues[1], intValues[2], intValues[3], 0, nullptr);
return 0;
} else if (pCmdParam->vsize == 256 || pCmdParam->vsize == 1024) {
uint32_t arrSize = *(uint32_t *) (pCmdParam->data + vOffset);
signed char *arr = (signed char *) (pCmdParam->data + vOffset + sizeof(uint32_t));
pContext->viper->DispatchCommand(param, 0, 0, 0, 0, arrSize, arr);
return 0;
} else if (pCmdParam->vsize == 8192) {
int value1 = *(int *) (pCmdParam->data + vOffset);
uint32_t arrSize = *(uint32_t *) (pCmdParam->data + vOffset + sizeof(int));
signed char *arr = (signed char *) (pCmdParam->data + vOffset + sizeof(int) + sizeof(uint32_t));
pContext->viper->DispatchCommand(param, value1, 0, 0, 0, arrSize, arr);
return 0;
}
return handleSetParam(pContext, (effect_param_t *) pCmdData, pReplyData);
}
case EFFECT_CMD_GET_PARAM: {
auto *pCmdParam = reinterpret_cast<effect_param_t *>(pCmdData);
auto *pReplyParam = reinterpret_cast<effect_param_t *>(pReplyData);
// The value offset of an effect parameter is computed by rounding up
// the parameter size to the next 32 bit alignment.
uint32_t vOffset = ((pCmdParam->psize + sizeof(int32_t) - 1) / sizeof(int32_t)) * sizeof(int32_t);
VIPER_LOGD("Viper_ICommand() EFFECT_CMD_GET_PARAM called with data = %d, psize = %d, vsize = %d", *(uint32_t *) pCmdParam->data, pCmdParam->psize, pCmdParam->vsize);
//memcpy(pReplyParam, pCmdParam, sizeof(effect_param_t) + pCmdParam->psize);
switch (*(uint32_t *) pCmdParam->data) {
case PARAM_GET_DRIVER_VERSION: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(uint32_t);
*(uint32_t *) (pReplyParam->data + vOffset) = 0x2050005; // As original, change as needed
*replySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_ENABLED: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(int32_t);
*(int32_t *) (pReplyParam->data + vOffset) = pContext->viper->enabled;
*replySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_CONFIGURE: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(int32_t);
*(int32_t *) (pReplyParam->data + vOffset) = 1; // TODO?
*replySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_STREAMING: { // Is processing
struct timeval time{};
gettimeofday(&time, nullptr);
uint64_t currentMs = (time.tv_sec * 1000) + (time.tv_usec / 1000);
uint64_t lastProcessTime = pContext->viper->process_time_ms;
uint64_t diff;
if (currentMs > lastProcessTime) {
diff = currentMs - lastProcessTime;
} else {
diff = lastProcessTime - currentMs;
}
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(int32_t);
*(int32_t *) (pReplyParam->data + vOffset) = diff > 5000 ? 0 : 1;
*replySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_SAMPLINGRATE: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(uint32_t);
*(uint32_t *) (pReplyParam->data + vOffset) = pContext->viper->samplingRate;
*replySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
case PARAM_GET_CONVKNLID: {
pReplyParam->status = 0;
pReplyParam->vsize = sizeof(uint32_t);
*(uint32_t *) (pReplyParam->data + vOffset) = pContext->viper->convolver->GetKernelID();
*replySize = sizeof(effect_param_t) + pReplyParam->psize + vOffset + pReplyParam->vsize;
return 0;
}
}
return handleGetParam(pContext, (effect_param_t *) pCmdData, (effect_param_t *) pReplyData, replySize);
}
case EFFECT_CMD_GET_CONFIG: {
*(effect_config_t *) pReplyData = pContext->config;
@ -275,10 +270,7 @@ static int32_t Viper_ICommand(effect_handle_t self,
static int32_t Viper_IGetDescriptor(effect_handle_t self, effect_descriptor_t *pDescriptor) {
auto pContext = reinterpret_cast<ViperContext *>(self);
VIPER_LOGD("Viper_IGetDescriptor called");
if (pContext == nullptr || pDescriptor == nullptr) {
VIPER_LOGE("Viper_IGetDescriptor: pContext or pDescriptor is null!");
return -EINVAL;
}
@ -295,40 +287,21 @@ static const effect_interface_s viper_interface = {
static void Viper_Init(ViperContext *pContext) {
pContext->interface = &viper_interface;
memset(&pContext->config, 0, sizeof(effect_config_t));
pContext->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
pContext->config.inputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
pContext->config.inputCfg.samplingRate = DEFAULT_SAMPLERATE;
pContext->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
pContext->config.inputCfg.mask = AUDIO_PORT_CONFIG_ALL;
pContext->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
pContext->config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
pContext->config.outputCfg.samplingRate = DEFAULT_SAMPLERATE;
pContext->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
pContext->config.outputCfg.mask = AUDIO_PORT_CONFIG_ALL;
pContext->viper = new ViPER();
}
static int32_t
Viper_Create(const effect_uuid_t *uuid, int32_t sessionId __unused, int32_t ioId __unused, effect_handle_t *pHandle) {
VIPER_LOGI("Enter Viper_Create()");
if (uuid == nullptr || pHandle == nullptr) {
VIPER_LOGE("Viper_Create: uuid or pHandle is null!");
return -EINVAL;
}
if (memcmp(uuid, &viper_descriptor.uuid, sizeof(effect_uuid_t)) != 0) {
VIPER_LOGE("Viper_Create: uuid is not viper_descriptor.uuid!");
return -EINVAL;
}
VIPER_LOGI("Viper_Create: uuid matches, creating viper...");
VIPER_LOGD("Creating new ViPER instance");
auto *pContext = new ViperContext;
Viper_Init(pContext);
*pHandle = reinterpret_cast<effect_handle_t>(pContext);
@ -339,15 +312,11 @@ Viper_Create(const effect_uuid_t *uuid, int32_t sessionId __unused, int32_t ioId
static int32_t Viper_Release(effect_handle_t handle) {
auto pContext = reinterpret_cast<ViperContext *>(handle);
VIPER_LOGI("Enter Viper_Release()");
if (pContext == nullptr) {
VIPER_LOGE("Viper_Release: pContext is null!");
return -EINVAL;
}
VIPER_LOGI("Viper_Release: deleting viper...");
VIPER_LOGD("Releasing ViPER instance");
delete pContext->viper;
delete pContext;
@ -355,20 +324,14 @@ static int32_t Viper_Release(effect_handle_t handle) {
}
static int32_t Viper_GetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor) {
VIPER_LOGI("Enter Viper_GetDescriptor()");
if (uuid == nullptr || pDescriptor == nullptr) {
VIPER_LOGE("Viper_GetDescriptor: uuid or pDescriptor is null!");
return -EINVAL;
}
if (memcmp(uuid, &viper_descriptor.uuid, sizeof(effect_uuid_t)) != 0) {
VIPER_LOGE("Viper_GetDescriptor: uuid is not viper_descriptor.uuid!");
return -EINVAL;
}
VIPER_LOGI("Viper_GetDescriptor: uuid matches, returning descriptor...");
*pDescriptor = viper_descriptor;
return 0;

View File

@ -4,35 +4,24 @@
// Updated parameters source: https://github.com/vipersaudio/viper4android_fx/blob/master/android_4.x/src/com/vipercn/viper4android_v2/service/ViPER4AndroidService.java
extern "C" {
enum ParamsMode {
COMMAND_CODE_GET = 0x01,
COMMAND_CODE_SET,
};
// Command code
#define COMMAND_CODE_GET 0x01
#define COMMAND_CODE_SET 0x02
enum ParamsGet {
PARAM_GET_DRIVER_VERSION = 0,
PARAM_GET_ENABLED,
PARAM_GET_CONFIGURE,
PARAM_GET_STREAMING,
PARAM_GET_SAMPLINGRATE,
PARAM_GET_CONVKNLID
};
// Param get
#define PARAM_GET_DRIVER_VERSION 0
#define PARAM_GET_ENABLED 1
#define PARAM_GET_CONFIGURE 2
#define PARAM_GET_STREAMING 3
#define PARAM_GET_SAMPLING_RATE 4
#define PARAM_GET_CONVOLUTION_KERNEL_ID 5
// Param set
#define PARAM_SET_UPDATE_STATUS 0x9002
#define PARAM_SET_RESET_STATUS 0x9003
enum ParamsSet {
PARAM_SET_STATUS_BEGIN = 0x9000,
PARAM_SET_UNKNOWN,
PARAM_SET_UPDATE_STATUS,
PARAM_SET_RESET_STATUS,
PARAM_SET_DOPROCESS_STATUS,
PARAM_SET_FORCEENABLE_STATUS,
PARAM_SET_SELFDIAGNOSE_STATUS,
PARAM_SET_STATUS_END
};
enum ParamsConfigure {
PARAM_PROCESSUNIT_FX_BEGIN = 0x10000,
PARAM_FX_TYPE_SWITCH, // 0x10001
PARAM_FX_TYPE_SWITCH = 0x10001, // 0x10001
PARAM_HPFX_CONV_PROCESS_ENABLED, // 0x10002
PARAM_HPFX_CONV_UPDATEKERNEL, // 0x10003
/*****************************************/
@ -87,26 +76,7 @@ enum ParamsConfigure {
PARAM_HPFX_OUTPUT_VOLUME, // 0x10032
PARAM_HPFX_OUTPUT_PAN, // 0x10033
PARAM_HPFX_LIMITER_THRESHOLD, // 0x10034
PARAM_SPKFX_CONV_PROCESS_ENABLED, // 0x10035
PARAM_SPKFX_CONV_UPDATEKERNEL, // 0x10036
PARAM_SPKFX_CONV_PREPAREBUFFER, // 0x10037
PARAM_SPKFX_CONV_SETBUFFER, // 0x10038
PARAM_SPKFX_CONV_COMMITBUFFER, // 0x10039
PARAM_SPKFX_CONV_CROSSCHANNEL, // 0x1003A
PARAM_SPKFX_FIREQ_PROCESS_ENABLED, // 0x1003B
PARAM_SPKFX_FIREQ_BANDLEVEL, // 0x1003C
PARAM_SPKFX_REVB_PROCESS_ENABLED, // 0x1003D
PARAM_SPKFX_REVB_ROOMSIZE, // 0x1003E
PARAM_SPKFX_REVB_WIDTH, // 0x1003F
PARAM_SPKFX_REVB_DAMP, // 0x10040
PARAM_SPKFX_REVB_WET, // 0x10041
PARAM_SPKFX_REVB_DRY, // 0x10042
PARAM_SPKFX_AGC_PROCESS_ENABLED, // 0x10043
PARAM_SPKFX_AGC_RATIO, // 0x10044
PARAM_SPKFX_AGC_VOLUME, // 0x10045
PARAM_SPKFX_AGC_MAXSCALER, // 0x10046
PARAM_SPKFX_OUTPUT_VOLUME, // 0x10047
PARAM_SPKFX_LIMITER_THRESHOLD, // 0x10048
PARAM_HPFX_FETCOMP_PROCESS_ENABLED, // 0x10049
PARAM_HPFX_FETCOMP_THRESHOLD, // 0x1004A
PARAM_HPFX_FETCOMP_RATIO, // 0x1004B
@ -124,25 +94,6 @@ enum ParamsConfigure {
PARAM_HPFX_FETCOMP_META_CREST, // 0x10057
PARAM_HPFX_FETCOMP_META_ADAPT, // 0x10058
PARAM_HPFX_FETCOMP_META_NOCLIP_ENABLED, // 0x10059
PARAM_SPKFX_FETCOMP_PROCESS_ENABLED, // 0x1005A
PARAM_SPKFX_FETCOMP_THRESHOLD, // 0x1005B
PARAM_SPKFX_FETCOMP_RATIO, // 0x1005C
PARAM_SPKFX_FETCOMP_KNEEWIDTH, // 0x1005D
PARAM_SPKFX_FETCOMP_AUTOKNEE_ENABLED, // 0x1005E
PARAM_SPKFX_FETCOMP_GAIN, // 0x1005F
PARAM_SPKFX_FETCOMP_AUTOGAIN_ENABLED, // 0x10060
PARAM_SPKFX_FETCOMP_ATTACK, // 0x10061
PARAM_SPKFX_FETCOMP_AUTOATTACK_ENABLED, // 0x10062
PARAM_SPKFX_FETCOMP_RELEASE, // 0x10063
PARAM_SPKFX_FETCOMP_AUTORELEASE_ENABLED, // 0x10064
PARAM_SPKFX_FETCOMP_META_KNEEMULTI, // 0x10065
PARAM_SPKFX_FETCOMP_META_MAXATTACK, // 0x10066
PARAM_SPKFX_FETCOMP_META_MAXRELEASE, // 0x10067
PARAM_SPKFX_FETCOMP_META_CREST, // 0x10068
PARAM_SPKFX_FETCOMP_META_ADAPT, // 0x10069
PARAM_SPKFX_FETCOMP_META_NOCLIP_ENABLED, // 0x1006A
PARAM_PROCESSUNIT_FX_END
};
}

View File

@ -7,6 +7,8 @@ ViPER::ViPER() {
VIPER_LOGI("Welcome to ViPER FX");
VIPER_LOGI("Current version is %s %s", VERSION_STRING, VERSION_CODENAME);
this->samplingRate = DEFAULT_SAMPLERATE;
this->adaptiveBuffer = new AdaptiveBuffer(2, 4096);
this->waveBuffer = new WaveBuffer(2, 4096);
@ -81,11 +83,11 @@ ViPER::ViPER() {
this->cure->Reset();
this->tubeSimulator = new TubeSimulator();
this->tubeSimulator->enabled = false; //SetEnable(false);
this->tubeSimulator->SetEnable(false);
this->tubeSimulator->Reset();
this->analogX = new AnalogX();
// this->analogX->SetEnable(false);
this->analogX->SetEnable(false);
this->analogX->SetSamplingRate(this->samplingRate);
this->analogX->SetProcessingModel(0);
this->analogX->Reset();
@ -100,12 +102,12 @@ ViPER::ViPER() {
softwareLimiter->ResetLimiter();
}
this->frame_scale = 1.0;
this->left_pan = 1.0;
this->process_time_ms = 0;
this->right_pan = 1.0;
this->frameScale = 1.0;
this->leftPan = 1.0;
this->rightPan = 1.0;
this->updateProcessTime = false;
this->processTimeMs = 0;
this->enabled = false;
this->update_status = false;
}
ViPER::~ViPER() {
@ -144,10 +146,10 @@ void ViPER::processBuffer(float *buffer, uint32_t size) {
return;
}
if (this->update_status) {
if (this->updateProcessTime) {
struct timeval time{};
gettimeofday(&time, nullptr);
this->process_time_ms = time.tv_sec * 1000 + time.tv_usec / 1000;
this->processTimeMs = time.tv_sec * 1000 + time.tv_usec / 1000;
}
uint32_t ret;
@ -155,6 +157,8 @@ void ViPER::processBuffer(float *buffer, uint32_t size) {
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;
@ -178,6 +182,8 @@ void ViPER::processBuffer(float *buffer, uint32_t size) {
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);
@ -189,6 +195,7 @@ void ViPER::processBuffer(float *buffer, uint32_t size) {
}
}
// VIPER_LOGD("Process buffer size: %d", tmpBufSize);
if (tmpBufSize != 0) {
this->viperDdc->Process(tmpBuf, size);
this->spectrumExtend->Process(tmpBuf, size);
@ -206,12 +213,12 @@ void ViPER::processBuffer(float *buffer, uint32_t size) {
this->tubeSimulator->TubeProcess(tmpBuf, size);
this->analogX->Process(tmpBuf, tmpBufSize);
if (this->frame_scale != 1.0) {
this->adaptiveBuffer->ScaleFrames(this->frame_scale);
if (this->frameScale != 1.0) {
this->adaptiveBuffer->ScaleFrames(this->frameScale);
}
if (this->left_pan < 1.0 || this->right_pan < 1.0) {
this->adaptiveBuffer->PanFrames(this->left_pan, this->right_pan);
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) {
@ -235,41 +242,26 @@ void ViPER::processBuffer(float *buffer, uint32_t size) {
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_UNKNOWN: {
break;
}
case PARAM_SET_UPDATE_STATUS: {
this->updateProcessTime = val1 != 0;
break;
}
case PARAM_SET_RESET_STATUS: {
this->ResetAllEffects();
break;
}
case PARAM_SET_DOPROCESS_STATUS: {
break;
}
case PARAM_SET_FORCEENABLE_STATUS: {
break;
}
case PARAM_SET_SELFDIAGNOSE_STATUS: {
break;
}
case PARAM_FX_TYPE_SWITCH: {
// Unused
// TODO: Remove
break;
} // 0x10001
case PARAM_HPFX_CONV_PROCESS_ENABLED: {
// this->convolver->SetEnabled(val1 != 0);
break;
} // 0x10002
case PARAM_HPFX_CONV_UPDATEKERNEL: {
break;
} // 0x10003
case PARAM_HPFX_CONV_PREPAREBUFFER: {
this->convolver->PrepareKernelBuffer(val1, val2, val3);
break;
} // 0x10004
case PARAM_HPFX_CONV_SETBUFFER: {
this->convolver->SetKernelBuffer(val1, (float *) arr, arrSize);
break;
} // 0x10005
case PARAM_HPFX_CONV_COMMITBUFFER: {
@ -277,6 +269,7 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
break;
} // 0x10006
case PARAM_HPFX_CONV_CROSSCHANNEL: {
this->convolver->SetCrossChannel((float) val1 / 100.0f);
break;
} // 0x10007
case PARAM_HPFX_VHE_PROCESS_ENABLED: {
@ -333,6 +326,7 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
break;
} // 0x10014
case PARAM_HPFX_DIFFSURR_PROCESS_ENABLED: {
this->diffSurround->SetEnable(val1 != 0);
break;
} // 0x10015
case PARAM_HPFX_DIFFSURR_DELAYTIME: {
@ -340,9 +334,11 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
break;
} // 0x10016
case PARAM_HPFX_REVB_PROCESS_ENABLED: {
this->reverberation->SetEnable(val1 != 0);
break;
} // 0x10017
case PARAM_HPFX_REVB_ROOMSIZE: {
this->reverberation->SetRoomSize((float) val1 / 100.0f);
break;
} // 0x10018
case PARAM_HPFX_REVB_WIDTH: {
@ -350,12 +346,15 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
break;
} // 0x10019
case PARAM_HPFX_REVB_DAMP: {
this->reverberation->SetDamp((float) val1 / 100.0f);
break;
} // 0x1001A
case PARAM_HPFX_REVB_WET: {
this->reverberation->SetWet((float) val1 / 100.0f);
break;
} // 0x1001B
case PARAM_HPFX_REVB_DRY: {
this->reverberation->SetDry((float) val1 / 100.0f);
break;
} // 0x1001C
case PARAM_HPFX_AGC_PROCESS_ENABLED: {
@ -395,11 +394,11 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
break;
} // 0x10025
case PARAM_HPFX_VIPERBASS_PROCESS_ENABLED: {
// this->viperBass->SetEnable(val1 != 0);
this->viperBass->SetEnable(val1 != 0);
break;
} // 0x10026
case PARAM_HPFX_VIPERBASS_MODE: {
this->viperBass->SetProcessMode(static_cast<ViPERBass::ProcessMode>(val1));
this->viperBass->SetProcessMode((ViPERBass::ProcessMode) val1);
break;
} // 0x10027
case PARAM_HPFX_VIPERBASS_SPEAKER: {
@ -411,11 +410,11 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
break;
} // 0x10029
case PARAM_HPFX_VIPERCLARITY_PROCESS_ENABLED: {
//this->viperClarity->SetEnable(val1 != 0);
this->viperClarity->SetEnable(val1 != 0);
break;
} // 0x1002A
case PARAM_HPFX_VIPERCLARITY_MODE: {
this->viperClarity->SetProcessMode(static_cast<ViPERClarity::ClarityMode>(val1));
this->viperClarity->SetProcessMode((ViPERClarity::ClarityMode) val1);
break;
} // 0x1002B
case PARAM_HPFX_VIPERCLARITY_CLARITY: {
@ -441,11 +440,11 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
break;
} // 0x1002E
case PARAM_HPFX_TUBE_PROCESS_ENABLED: {
// TODO: Enable
this->tubeSimulator->SetEnable(val1 != 0);
break;
} // 0x1002F
case PARAM_HPFX_ANALOGX_PROCESS_ENABLED: {
// TODO: Enable
this->analogX->SetEnable(val1 != 0);
break;
} // 0x10030
case PARAM_HPFX_ANALOGX_MODE: {
@ -453,17 +452,17 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
break;
} // 0x10031
case PARAM_HPFX_OUTPUT_VOLUME: {
this->frameScale = (float) val1 / 100.0f;
break;
} // 0x10032
case PARAM_HPFX_OUTPUT_PAN: {
float tmp = (float) val1 / 100.0f;
if (tmp < 0.0f) {
this->left_pan = 1.0f;
this->right_pan = 1.0f + tmp;
this->leftPan = 1.0f;
this->rightPan = 1.0f + tmp;
} else {
this->left_pan = 1.0f - tmp;
this->right_pan = 1.0f;
this->leftPan = 1.0f - tmp;
this->rightPan = 1.0f;
}
break;
} // 0x10033
@ -472,77 +471,10 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
this->softwareLimiters[1]->SetGate((float) val1 / 100.0f);
break;
} // 0x10034
case PARAM_SPKFX_CONV_PROCESS_ENABLED: {
break;
} // 0x10035
case PARAM_SPKFX_CONV_UPDATEKERNEL: {
break;
} // 0x10036
case PARAM_SPKFX_CONV_PREPAREBUFFER: {
break;
} // 0x10037
case PARAM_SPKFX_CONV_SETBUFFER: {
break;
} // 0x10038
case PARAM_SPKFX_CONV_COMMITBUFFER: {
break;
} // 0x10039
case PARAM_SPKFX_CONV_CROSSCHANNEL: {
this->convolver->SetCrossChannel((float) val1 / 100.0f);
break;
} // 0x1003A
case PARAM_SPKFX_FIREQ_PROCESS_ENABLED: {
break;
} // 0x1003B
case PARAM_SPKFX_FIREQ_BANDLEVEL: {
break;
} // 0x1003C
case PARAM_SPKFX_REVB_PROCESS_ENABLED: {
this->reverberation->SetEnable(val1 != 0);
break;
} // 0x1003D
case PARAM_SPKFX_REVB_ROOMSIZE: {
this->reverberation->SetRoomSize((float) val1 / 100.0f);
break;
} // 0x1003E
case PARAM_SPKFX_REVB_WIDTH: {
break;
} // 0x1003F
case PARAM_SPKFX_REVB_DAMP: {
this->reverberation->SetDamp((float) val1 / 100.0f);
break;
} // 0x10040
case PARAM_SPKFX_REVB_WET: {
this->reverberation->SetWet((float) val1 / 100.0f);
break;
} // 0x10041
case PARAM_SPKFX_REVB_DRY: {
this->reverberation->SetDry((float) val1 / 100.0f);
break;
} // 0x10042
case PARAM_SPKFX_AGC_PROCESS_ENABLED: {
this->speakerCorrection->SetEnable(val1 != 0);
break;
} // 0x10043
case PARAM_SPKFX_AGC_RATIO: {
break;
} // 0x10044
case PARAM_SPKFX_AGC_VOLUME: {
this->playbackGain->SetVolume((float) val1 / 100.0f);
break;
} // 0x10045
case PARAM_SPKFX_AGC_MAXSCALER: {
this->playbackGain->SetMaxGainFactor((float) val1 / 100.0f);
break;
} // 0x10046
case PARAM_SPKFX_OUTPUT_VOLUME: {
this->frame_scale = (float) val1 / 100.0f;
break;
} // 0x10047
case PARAM_SPKFX_LIMITER_THRESHOLD: {
this->frame_scale = (float) val1 / 100.0f;
break;
} // 0x10048
case PARAM_HPFX_FETCOMP_PROCESS_ENABLED: {
break;
} // 0x10049
@ -598,59 +530,6 @@ void ViPER::DispatchCommand(int param, int val1, int val2, int val3, int val4, u
this->fetCompressor->SetParameter(15, (float) val1 / 100.0f);
break;
} // 0x10059
case PARAM_SPKFX_FETCOMP_PROCESS_ENABLED: {
break;
} // 0x1005A
case PARAM_SPKFX_FETCOMP_THRESHOLD: {
break;
} // 0x1005B
case PARAM_SPKFX_FETCOMP_RATIO: {
break;
} // 0x1005C
case PARAM_SPKFX_FETCOMP_KNEEWIDTH: {
this->fetCompressor->SetParameter(2, (float) val1 / 100.0f);
break;
} // 0x1005D
case PARAM_SPKFX_FETCOMP_AUTOKNEE_ENABLED: {
break;
} // 0x1005E
case PARAM_SPKFX_FETCOMP_GAIN: {
break;
} // 0x1005F
case PARAM_SPKFX_FETCOMP_AUTOGAIN_ENABLED: {
break;
} // 0x10060
case PARAM_SPKFX_FETCOMP_ATTACK: {
break;
} // 0x10061
case PARAM_SPKFX_FETCOMP_AUTOATTACK_ENABLED: {
break;
} // 0x10062
case PARAM_SPKFX_FETCOMP_RELEASE: {
break;
} // 0x10063
case PARAM_SPKFX_FETCOMP_AUTORELEASE_ENABLED: {
break;
} // 0x10064
case PARAM_SPKFX_FETCOMP_META_KNEEMULTI: {
break;
} // 0x10065
case PARAM_SPKFX_FETCOMP_META_MAXATTACK: {
break;
} // 0x10066
case PARAM_SPKFX_FETCOMP_META_MAXRELEASE: {
break;
} // 0x10067
case PARAM_SPKFX_FETCOMP_META_CREST: {
break;
} // 0x10068
case PARAM_SPKFX_FETCOMP_META_ADAPT: {
break;
} // 0x10069
case PARAM_SPKFX_FETCOMP_META_NOCLIP_ENABLED: {
break;
} // 0x1006A
}
}

View File

@ -33,8 +33,8 @@ public:
void ResetAllEffects();
//private:
bool update_status;
uint64_t process_time_ms;
bool updateProcessTime;
uint64_t processTimeMs;
bool enabled;
uint32_t samplingRate;
@ -60,7 +60,7 @@ public:
SpeakerCorrection *speakerCorrection;
SoftwareLimiter *softwareLimiters[2];
float frame_scale;
float left_pan;
float right_pan;
float frameScale;
float leftPan;
float rightPan;
};

View File

@ -18,27 +18,29 @@ static float ANALOGX_HARMONICS[10] = {
AnalogX::AnalogX() {
this->samplingRate = DEFAULT_SAMPLERATE;
this->processingModel = 0;
this->enabled = false;
this->enable = false;
Reset();
}
void AnalogX::Process(float *samples, uint32_t size) {
for (int i = 0; i < size * 2; i++) {
float sample = samples[i];
int channel = i % 2;
if (this->enable) {
for (int i = 0; i < size * 2; i++) {
float sample = samples[i];
int channel = i % 2;
float tmp = this->highpass[channel].ProcessSample(sample);
tmp = this->harmonic[channel].Process(tmp);
float tmp = this->highpass[channel].ProcessSample(sample);
tmp = this->harmonic[channel].Process(tmp);
tmp = this->lowpass[channel].ProcessSample(sample + tmp * this->gain);
tmp = this->peak->ProcessSample(tmp * 0.8f);
tmp = this->lowpass[channel].ProcessSample(sample + tmp * this->gain);
tmp = this->peak->ProcessSample(tmp * 0.8f);
samples[i] = tmp;
}
samples[i] = tmp;
}
if (this->freqRange < this->samplingRate / 4) {
this->freqRange += size;
memset(samples, 0, size * 2 * sizeof(float));
if (this->freqRange < this->samplingRate / 4) {
this->freqRange += size;
memset(samples, 0, size * 2 * sizeof(float));
}
}
}
@ -90,6 +92,15 @@ void AnalogX::Reset() {
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;

View File

@ -10,6 +10,7 @@ public:
void Process(float *samples, uint32_t size);
void Reset();
void SetEnable(bool enable);
void SetProcessingModel(int processingModel);
void SetSamplingRate(uint32_t samplingRate);
@ -23,7 +24,7 @@ private:
uint32_t freqRange;
int processingModel;
uint32_t samplingRate;
bool enabled;
bool enable;
};

View File

@ -8,7 +8,7 @@ IIRFilter::IIRFilter(uint32_t bands) {
this->samplingRate = DEFAULT_SAMPLERATE;
if (bands == 10 || bands == 15 || bands == 25 || bands == 31) {
this->bands = bands;
this->minPhaseIirCoeffs.UpdateCoeffs(bands, this->samplingRate);
this->minPhaseIirCoeffs.UpdateCoeffs(this->bands, this->samplingRate);
} else {
this->bands = 0;
}
@ -17,7 +17,7 @@ IIRFilter::IIRFilter(uint32_t bands) {
bandLevelWithQ = 0.636;
}
this->Reset();
Reset();
}
void IIRFilter::Process(float *samples, uint32_t size) {
@ -54,14 +54,16 @@ void IIRFilter::Process(float *samples, uint32_t size) {
}
void IIRFilter::Reset() {
memset(this->buf,0,0x7c0);
memset(this->buf,0,sizeof(buf)); // size should be 0x7c0
this->unknown3 = 1;
this->unknown2 = 2;
this->unknown4 = 0;
}
void IIRFilter::SetBandLevel(uint32_t band, float level) {
this->bandLevelsWithQ[band] = (float) (pow(10.0, level / 20.0) * 0.636);
if (band > 30) return;
double bandLevel = pow(10.0, level / 20.0);
this->bandLevelsWithQ[band] = (float) (bandLevel * 0.636);
}
void IIRFilter::SetEnable(bool enable) {

View File

@ -8,13 +8,15 @@ SpeakerCorrection::SpeakerCorrection() {
}
void SpeakerCorrection::Process(float *samples, uint32_t size) {
for (int i = 0; i < size * 2; i++) {
float sample = samples[i];
int index = i % 2;
sample = this->lowpass[index].ProcessSample(sample);
sample = this->highpass[index].ProcessSample(sample);
float tmp = sample / 2.f;
samples[i] = tmp + this->bandpass[index].ProcessSample(tmp);
if (this->enabled) {
for (int i = 0; i < size * 2; i++) {
float sample = samples[i];
int index = i % 2;
sample = this->lowpass[index].ProcessSample(sample);
sample = this->highpass[index].ProcessSample(sample);
float tmp = sample / 2.f;
samples[i] = tmp + this->bandpass[index].ProcessSample(tmp);
}
}
}

View File

@ -27,13 +27,15 @@ SpectrumExtend::~SpectrumExtend() {
}
void SpectrumExtend::Process(float *samples, uint32_t size) {
for (int 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;
if (this->enabled) {
for (int 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;
}
}
}

View File

@ -3,17 +3,26 @@
TubeSimulator::TubeSimulator() {
this->acc[0] = 0.f;
this->acc[1] = 0.f;
this->enabled = false;
this->enable = false;
}
void TubeSimulator::Reset() {
this->acc[0] = 0.f;
this->acc[1] = 0.f;
this->enabled = false;
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->enabled) {
if (this->enable) {
for (int 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;

View File

@ -8,9 +8,11 @@ public:
~TubeSimulator();
void Reset();
void SetEnable(bool enable);
void TubeProcess(float *buffer, uint32_t size);
private:
float acc[2];
bool enabled;
bool enable;
};

View File

@ -2,9 +2,10 @@
#include "../constants.h"
ViPERBass::ViPERBass() {
this->enable = false;
this->samplingRate = DEFAULT_SAMPLERATE;
this->speaker = 60;
this->invertedSamplingRate = 1.0 / DEFAULT_SAMPLERATE;
this->samplingRatePeriod = 1.0 / DEFAULT_SAMPLERATE;
this->antiPop = 0.0;
this->processMode = ProcessMode::NATURAL_BASS;
this->bassFactor = 0.0;
@ -27,6 +28,10 @@ ViPERBass::~ViPERBass() {
}
void ViPERBass::Process(float *samples, uint32_t size) {
if (!this->enable) {
return;
}
if (size == 0) {
return;
}
@ -36,7 +41,7 @@ void ViPERBass::Process(float *samples, uint32_t size) {
samples[i] *= this->antiPop;
samples[i + 1] *= this->antiPop;
float x = this->antiPop + this->invertedSamplingRate;
float x = this->antiPop + this->samplingRatePeriod;
if (x > 1.0) {
x = 1.0;
}
@ -48,14 +53,14 @@ void ViPERBass::Process(float *samples, uint32_t size) {
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;
auto x = (float) this->biquad->ProcessSample(sample);
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) != 0) {
if (this->waveBuffer->PushSamples(samples, size)) {
float *buffer = this->waveBuffer->GetBuffer();
uint32_t bufferOffset = this->waveBuffer->GetBufferOffset();
@ -90,8 +95,8 @@ void ViPERBass::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;
this->invertedSamplingRate = 1.0f / (float) this->samplingRate;
}
void ViPERBass::SetBassFactor(float bassFactor) {
@ -101,6 +106,15 @@ void ViPERBass::SetBassFactor(float bassFactor) {
}
}
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;
@ -111,10 +125,10 @@ void ViPERBass::SetProcessMode(ProcessMode processMode) {
void ViPERBass::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
this->invertedSamplingRate = 1.0f / (float) samplingRate;
this->polyphase->SetSamplingRate(samplingRate);
this->biquad->SetLowPassParameter((float) this->speaker, samplingRate, 0.53);
this->subwoofer->SetBassGain(samplingRate, this->bassFactor * 2.5f);
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);
}
}

View File

@ -20,6 +20,7 @@ public:
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);
@ -29,9 +30,10 @@ private:
Biquad *biquad;
Subwoofer *subwoofer;
WaveBuffer *waveBuffer;
bool enable;
ProcessMode processMode;
uint32_t samplingRate;
float invertedSamplingRate;
float samplingRatePeriod;
float antiPop;
uint32_t speaker;
float bassFactor;

View File

@ -8,13 +8,18 @@ ViPERClarity::ViPERClarity() {
highShelf.SetSamplingRate(DEFAULT_SAMPLERATE);
}
this->enable = false;
this->processMode = ClarityMode::NATURAL;
this->samplingRate = DEFAULT_SAMPLERATE;
this->clarityGainPercent = 0.0;
this->Reset();
Reset();
}
void ViPERClarity::Process(float *samples, uint32_t size) {
if (!this->enable) {
return;
}
switch (this->processMode) {
case ClarityMode::NATURAL: {
this->noiseSharpening.Process(samples, size);
@ -50,7 +55,7 @@ void ViPERClarity::SetClarity(float gainPercent) {
if (this->processMode != ClarityMode::OZONE) {
this->SetClarityToFilter();
} else {
this->Reset();
Reset();
}
}
@ -61,16 +66,25 @@ void ViPERClarity::SetClarityToFilter() {
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;
this->Reset();
Reset();
}
}
void ViPERClarity::SetSamplingRate(uint32_t samplingRate) {
if (this->samplingRate != samplingRate) {
this->samplingRate = samplingRate;
this->Reset();
Reset();
}
}

View File

@ -19,6 +19,7 @@ public:
void Reset();
void SetClarity(float gainPercent);
void SetClarityToFilter();
void SetEnable(bool enable);
void SetProcessMode(ClarityMode processMode);
void SetSamplingRate(uint32_t samplingRate);
@ -26,6 +27,7 @@ private:
NoiseSharpening noiseSharpening;
HighShelf highShelf[2];
HiFi hifi;
bool enable;
ClarityMode processMode;
uint32_t samplingRate;
float clarityGainPercent;

View File

@ -38,7 +38,7 @@ uint32_t AdaptiveBuffer::GetChannels() const {
void AdaptiveBuffer::PanFrames(float left, float right) {
if (this->buffer != nullptr && this->channels == 2) {
for (int i = 0; i < this->offset * this->channels; i++) {
for (uint32_t i = 0; i < this->offset * this->channels; i++) {
if (i % 2 == 0) {
this->buffer[i] = this->buffer[i] * left;
} else {
@ -57,7 +57,7 @@ int AdaptiveBuffer::PopFrames(float *frames, uint32_t length) {
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));
memmove(this->buffer, this->buffer + (length * this->channels), this->offset * this->channels * sizeof(float));
}
}
@ -78,7 +78,7 @@ int AdaptiveBuffer::PushFrames(const float *frames, uint32_t length) {
this->length = this->offset + length;
}
memcpy(&this->buffer[this->offset * this->channels], frames, length * this->channels * sizeof(float));
memcpy(this->buffer + (this->offset * this->channels), frames, length * this->channels * sizeof(float));
this->offset = this->offset + length;
}
@ -98,7 +98,7 @@ int AdaptiveBuffer::PushZero(uint32_t length) {
this->length = this->offset + length;
}
memset(&this->buffer[this->offset * this->channels], 0, length * this->channels * sizeof(float));
memset(this->buffer + (this->offset * this->channels), 0, length * this->channels * sizeof(float));
this->offset = this->offset + length;
return 1;

View File

@ -1,53 +1,64 @@
#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->x_1 * this->b1 + this->x_2 * this->b2 + this->y_1 * this->a1 +
this->y_2 * this->a2;
this->y_2 = this->y_1;
this->y_1 = out;
this->x_2 = this->x_1;
this->x_1 = 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;
this->a2 = 0;
this->b0 = 0;
this->b1 = 0;
this->b2 = 0;
this->x_1 = 0;
this->x_2 = 0;
this->y_1 = 0;
this->y_2 = 0;
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 x = (2.0 * M_PI * (double) frequency) / (double) samplingRate;
double sinX = sin(x);
double cosX = cos(x);
double y = sinX / ((double) qFactor * 2.0);
double omega = (2.0 * M_PI * (double) frequency) / (double) samplingRate;
double sinOmega = sin(omega);
double cosOmega = cos(omega);
double a0 = 1.0 + y;
double a1 = -cosX * 2.0;
double a2 = 1.0 - y;
double b0 = sinX / 2.0;
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 = -sinX / 2.0;
this->SetCoeffs(a0, a1, a2, b0, b1, b2);
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->x_2 = 0;
this->x_1 = 0;
this->y_2 = 0;
this->y_1 = 0;
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;
@ -55,44 +66,47 @@ void Biquad::SetCoeffs(double a0, double a1, double a2, double b0, double b1, do
this->b2 = b2 / a0;
}
// TODO: Check
void
Biquad::SetHighPassParameter(float frequency, uint32_t samplingRate, double param_4, float qFactor, double param_6) {
double x = (2.0 * M_PI * (double) frequency) / (double) samplingRate;
double sinX = sin(x);
double cosX = cos(x);
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 y = pow(10.0, param_4 / 40.0);
double sqrtY = sqrt(y);
double A = pow(10.0, dbGain / 40.0);
double sqrtY = sqrt(A);
double z = sinX / 2.0 * sqrt((1.0 / y + y) * (1.0 / (double) qFactor - 1.0) + 2.0);
double a = (y - 1.0) * cosX;
double b = (y + 1.0) + a;
double c = (y + 1.0) * cosX;
double d = (y + 1.0) - 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 = (y - 1.0) - c;
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) * y * e;
double b1 = y * -2.0 * ((y - 1.0) + c) * e;
double b2 = (b - (sqrtY * 2.0) * z) * y * e;
this->SetCoeffs(a0, a1, a2, b0, b1, b2);
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 x = (2.0 * M_PI * (double) frequency) / (double) samplingRate;
double sinX = sin(x);
double y = sinX / ((double) qFactor * 2.0);
double cosX = cos(x);
double z = 1.0 - cosX;
double omega = (2.0 * M_PI * (double) frequency) / (double) samplingRate;
double sinOmega = sin(omega);
double cosOmega = cos(omega);
double a0 = y + 1.0;
double a1 = -cosX * 2.0;
double a2 = 1.0 - y;
double b0 = z / 2.0;
double b1 = z;
double b2 = z / 2.0;
this->SetCoeffs(a0, a1, a2, b0, b1, b2);
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);
}

View File

@ -10,14 +10,14 @@ public:
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 param_4, float qFactor, double param_6);
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 x_1;
double x_2;
double y_1;
double y_2;
double x1;
double x2;
double y1;
double y2;
double a1;
double a2;
double b0;

View File

@ -28,10 +28,10 @@ void FIR::FilterSamplesInterleaved(float *samples, uint32_t size, uint32_t chann
}
if (this->blockLength > size) {
memset(&this->block[size], 0, (this->blockLength - size) * sizeof(float));
memset(this->block + size, 0, (this->blockLength - size) * sizeof(float));
}
memcpy(&this->offsetBlock[this->coeffsSize - 1], this->block, this->blockLength * 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;
@ -46,7 +46,7 @@ void FIR::FilterSamplesInterleaved(float *samples, uint32_t size, uint32_t chann
}
if (this->coeffsSize > 1) {
memcpy(&this->offsetBlock[this->coeffsSize - 2], &this->block[this->blockLength - 1], this->blockLength - (this->coeffsSize - 1) * sizeof(float));
memcpy(this->offsetBlock + this->coeffsSize - 2, this->block + this->blockLength - 1, this->blockLength - (this->coeffsSize - 1) * sizeof(float));
}
}

View File

@ -131,7 +131,7 @@ float MinPhaseIIRCoeffs::GetIndexFrequency(uint32_t index) {
}
int MinPhaseIIRCoeffs::SolveRoot(double param_2, double param_3, double param_4, double *param_5) {
double x = (param_4 - pow(param_3, 2.0) / (param_2 * 4.0)) / param_2;
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) {
@ -151,7 +151,7 @@ int MinPhaseIIRCoeffs::SolveRoot(double param_2, double param_3, double param_4,
}
int MinPhaseIIRCoeffs::UpdateCoeffs(uint32_t bands, uint32_t samplingRate) {
if ((bands != 10 && bands != 15 && bands != 25 && bands != 31) || samplingRate != 44100) {
if ((bands != 10 && bands != 15 && bands != 25 && bands != 31) || samplingRate < 44100) {
return 0;
}
@ -159,7 +159,7 @@ int MinPhaseIIRCoeffs::UpdateCoeffs(uint32_t bands, uint32_t samplingRate) {
this->samplingRate = samplingRate;
delete[] this->coeffs;
this->coeffs = new float[bands * 4]();
this->coeffs = new float[bands * 4](); // TODO: Check this array size
const float *coeffsArray;
double tmp;
@ -186,7 +186,8 @@ int MinPhaseIIRCoeffs::UpdateCoeffs(uint32_t bands, uint32_t samplingRate) {
for (uint32_t i = 0; i < bands; i++) {
double ret1;
double ret2;
this->Find_F1_F2(coeffsArray[i], tmp, &ret1, &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;
@ -199,10 +200,17 @@ int MinPhaseIIRCoeffs::UpdateCoeffs(uint32_t bands, uint32_t samplingRate) {
double b = pow(cosX, 2.0) / 2.0;
double c = pow(sinY, 2.0);
if (this->SolveRoot(((b - a) + 0.5) - c, c + (((b + pow(cosY, 2.0)) - a) - 0.5), ((pow(cosX, 2.0) / 8.0 - cosX * cosY / 4.0) + 0.125) - c / 4.0, &ret1) == 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] = (float) (ret1 * 2.0);
this->coeffs[4 * i + 1] = (float) (0.5 - ret1);
this->coeffs[4 * i + 2] = (float) ((ret1 + 0.5) * cosX);
this->coeffs[4 * i + 1] = (float) (((0.5 - ret1) * 0.5) * 2.0);
this->coeffs[4 * i + 2] = (float) (((ret1 + 0.5) * cosX) * 2.0);
}
}

View File

@ -144,7 +144,7 @@ Polyphase::Polyphase(int unknown1) {
if (unknown1 == 2) {
this->fir1->LoadCoefficients(POLYPHASE_COEFFICIENTS_2, sizeof(POLYPHASE_COEFFICIENTS_2) / sizeof(float), 1008);
this->fir2->LoadCoefficients(POLYPHASE_COEFFICIENTS_2, sizeof(POLYPHASE_COEFFICIENTS_2) / sizeof(float), 1008);
} else if (unknown1 > 2) {
} else { // if (unknown1 < 2)
this->fir1->LoadCoefficients(POLYPHASE_COEFFICIENTS_OTHER, sizeof(POLYPHASE_COEFFICIENTS_OTHER) / sizeof(float), 1008);
this->fir2->LoadCoefficients(POLYPHASE_COEFFICIENTS_OTHER, sizeof(POLYPHASE_COEFFICIENTS_OTHER) / sizeof(float), 1008);
}
@ -163,21 +163,23 @@ uint32_t Polyphase::GetLatency() {
}
uint32_t Polyphase::Process(float *samples, uint32_t size) {
if (this->waveBuffer1->PushSamples(samples, size) != 0) {
uint32_t bufferOffset = this->waveBuffer1->GetBufferOffset();
while (bufferOffset >= 1008) {
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);
}
bufferOffset = this->waveBuffer1->GetBufferOffset();
}
if (this->waveBuffer2->GetBufferOffset() >= size) {
this->waveBuffer2->PopSamples(samples, size, true);
if (this->waveBuffer2->GetBufferOffset() < size) {
return 0;
}
this->waveBuffer2->PopSamples(samples, size, true);
}
return 0;
return size;
}
void Polyphase::Reset() {