Effect API: - Use different definitions for audio device, channels, formats... in AudioSystem and EffectApi: Removed media/AudioCommon.h file created for initial version of EffectApi - Indicate audio session and output ID to effect library when calling EffectCreate(). Session ID can be useful to optimize the implementation of effect chains in the same audio session. Output ID can be used for effects implemented in audio hardware. - Renamed EffectQueryNext() function to EffectQueryEffect() and changed operating mode: now an index is passed for the queried effect instead of implicitly querying the next one. - Added CPU load and memory usage indication in effects descriptor - Added flags and commands to indicate changes in audio mode (ring tone, in call...) to effect engine - Added flag to indicate hardware accelerated effect implementation. - Renamed EffectFactoryApi.h to EffectsFactoryApi.h for consistency with EffectsFactory.c/h Effect libraries: - Reflected changes in Effect API - Several fixes in reverb implementation - Added build option TEST_EFFECT_LIBRARIES in makefile to prepare integration of actual effect library. - Replaced pointer by integer identifier for library handle returned by effects factory Audio effect framework: - Added support for audio session -1 in preparation of output stage effects configuration. - Reflected changes in Effect API - Removed volume ramp up/down when effect is inserted/removed: this has to be taken care of by effect engines. - Added some overflow verification on indexes used for deferred parameter updates via shared memory - Added hardcoded CPU and memory limit check when creating a new effect instance Change-Id: I43fee5182ee201384ea3479af6d0acb95092901d
2087 lines
74 KiB
C
2087 lines
74 KiB
C
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "EffectReverb"
|
|
//
|
|
#define LOG_NDEBUG 0
|
|
#include <cutils/log.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include "EffectReverb.h"
|
|
#include "EffectsMath.h"
|
|
|
|
// effect_interface_t interface implementation for reverb effect
|
|
const struct effect_interface_s gReverbInterface = {
|
|
Reverb_Process,
|
|
Reverb_Command
|
|
};
|
|
|
|
// Google auxiliary environmental reverb UUID: 1f0ae2e0-4ef7-11df-bc09-0002a5d5c51b
|
|
static const effect_descriptor_t gAuxEnvReverbDescriptor = {
|
|
{0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
|
|
{0x1f0ae2e0, 0x4ef7, 0x11df, 0xbc09, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
|
|
EFFECT_API_VERSION,
|
|
// flags other than EFFECT_FLAG_TYPE_AUXILIARY set for test purpose
|
|
EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_AUDIO_MODE_IND,
|
|
0, // TODO
|
|
33,
|
|
"Aux Environmental Reverb",
|
|
"Google Inc."
|
|
};
|
|
|
|
// Google insert environmental reverb UUID: aa476040-6342-11df-91a4-0002a5d5c51b
|
|
static const effect_descriptor_t gInsertEnvReverbDescriptor = {
|
|
{0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
|
|
{0xaa476040, 0x6342, 0x11df, 0x91a4, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
|
|
EFFECT_API_VERSION,
|
|
EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
|
|
0, // TODO
|
|
33,
|
|
"Insert Environmental reverb",
|
|
"Google Inc."
|
|
};
|
|
|
|
// Google auxiliary preset reverb UUID: 63909320-53a6-11df-bdbd-0002a5d5c51b
|
|
static const effect_descriptor_t gAuxPresetReverbDescriptor = {
|
|
{0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
|
|
{0x63909320, 0x53a6, 0x11df, 0xbdbd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
|
|
EFFECT_API_VERSION,
|
|
EFFECT_FLAG_TYPE_AUXILIARY,
|
|
0, // TODO
|
|
33,
|
|
"Aux Preset Reverb",
|
|
"Google Inc."
|
|
};
|
|
|
|
// Google insert preset reverb UUID: d93dc6a0-6342-11df-b128-0002a5d5c51b
|
|
static const effect_descriptor_t gInsertPresetReverbDescriptor = {
|
|
{0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
|
|
{0xd93dc6a0, 0x6342, 0x11df, 0xb128, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
|
|
EFFECT_API_VERSION,
|
|
EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
|
|
0, // TODO
|
|
33,
|
|
"Insert Preset Reverb",
|
|
"Google Inc."
|
|
};
|
|
|
|
// gDescriptors contains pointers to all defined effect descriptor in this library
|
|
static const effect_descriptor_t * const gDescriptors[] = {
|
|
&gAuxEnvReverbDescriptor,
|
|
&gInsertEnvReverbDescriptor,
|
|
&gAuxPresetReverbDescriptor,
|
|
&gInsertPresetReverbDescriptor
|
|
};
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Effect API implementation
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
/*--- Effect Library Interface Implementation ---*/
|
|
|
|
int EffectQueryNumberEffects(uint32_t *pNumEffects) {
|
|
*pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
|
|
return 0;
|
|
}
|
|
|
|
int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor) {
|
|
if (pDescriptor == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
if (index >= sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)) {
|
|
return -EINVAL;
|
|
}
|
|
memcpy(pDescriptor, gDescriptors[index],
|
|
sizeof(effect_descriptor_t));
|
|
return 0;
|
|
}
|
|
|
|
int EffectCreate(effect_uuid_t *uuid,
|
|
int32_t sessionId,
|
|
int32_t ioId,
|
|
effect_interface_t *pInterface) {
|
|
int ret;
|
|
int i;
|
|
reverb_module_t *module;
|
|
const effect_descriptor_t *desc;
|
|
int aux = 0;
|
|
int preset = 0;
|
|
|
|
LOGV("EffectLibCreateEffect start");
|
|
|
|
if (pInterface == NULL || uuid == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; gDescriptors[i] != NULL; i++) {
|
|
desc = gDescriptors[i];
|
|
if (memcmp(uuid, &desc->uuid, sizeof(effect_uuid_t))
|
|
== 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (gDescriptors[i] == NULL) {
|
|
return -ENOENT;
|
|
}
|
|
|
|
module = malloc(sizeof(reverb_module_t));
|
|
|
|
module->itfe = &gReverbInterface;
|
|
|
|
if (memcmp(&desc->type, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) {
|
|
preset = 1;
|
|
}
|
|
if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
|
aux = 1;
|
|
}
|
|
ret = Reverb_Init(module, aux, preset);
|
|
if (ret < 0) {
|
|
LOGW("EffectLibCreateEffect() init failed");
|
|
free(module);
|
|
return ret;
|
|
}
|
|
|
|
*pInterface = (effect_interface_t) module;
|
|
|
|
LOGV("EffectLibCreateEffect %p ,size %d", module, sizeof(reverb_module_t));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int EffectRelease(effect_interface_t interface) {
|
|
reverb_module_t *pRvbModule = (reverb_module_t *)interface;
|
|
|
|
LOGV("EffectLibReleaseEffect %p", interface);
|
|
if (interface == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
free(pRvbModule);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*--- Effect Control Interface Implementation ---*/
|
|
|
|
static int Reverb_Process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
|
|
reverb_object_t *pReverb;
|
|
int16_t *pSrc, *pDst;
|
|
reverb_module_t *pRvbModule = (reverb_module_t *)self;
|
|
|
|
if (pRvbModule == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (inBuffer == NULL || inBuffer->raw == NULL ||
|
|
outBuffer == NULL || outBuffer->raw == NULL ||
|
|
inBuffer->frameCount != outBuffer->frameCount) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
pReverb = (reverb_object_t*) &pRvbModule->context;
|
|
|
|
//if bypassed or the preset forces the signal to be completely dry
|
|
if (pReverb->m_bBypass) {
|
|
if (inBuffer->raw != outBuffer->raw) {
|
|
int16_t smp;
|
|
pSrc = inBuffer->s16;
|
|
pDst = outBuffer->s16;
|
|
size_t count = inBuffer->frameCount;
|
|
if (pRvbModule->config.inputCfg.channels == pRvbModule->config.outputCfg.channels) {
|
|
count *= 2;
|
|
while (count--) {
|
|
*pDst++ = *pSrc++;
|
|
}
|
|
} else {
|
|
while (count--) {
|
|
smp = *pSrc++;
|
|
*pDst++ = smp;
|
|
*pDst++ = smp;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (pReverb->m_nNextRoom != pReverb->m_nCurrentRoom) {
|
|
ReverbUpdateRoom(pReverb, true);
|
|
}
|
|
|
|
pSrc = inBuffer->s16;
|
|
pDst = outBuffer->s16;
|
|
size_t numSamples = outBuffer->frameCount;
|
|
while (numSamples) {
|
|
uint32_t processedSamples;
|
|
if (numSamples > (uint32_t) pReverb->m_nUpdatePeriodInSamples) {
|
|
processedSamples = (uint32_t) pReverb->m_nUpdatePeriodInSamples;
|
|
} else {
|
|
processedSamples = numSamples;
|
|
}
|
|
|
|
/* increment update counter */
|
|
pReverb->m_nUpdateCounter += (int16_t) processedSamples;
|
|
/* check if update counter needs to be reset */
|
|
if (pReverb->m_nUpdateCounter >= pReverb->m_nUpdatePeriodInSamples) {
|
|
/* update interval has elapsed, so reset counter */
|
|
pReverb->m_nUpdateCounter -= pReverb->m_nUpdatePeriodInSamples;
|
|
ReverbUpdateXfade(pReverb, pReverb->m_nUpdatePeriodInSamples);
|
|
|
|
} /* end if m_nUpdateCounter >= update interval */
|
|
|
|
Reverb(pReverb, processedSamples, pDst, pSrc);
|
|
|
|
numSamples -= processedSamples;
|
|
if (pReverb->m_Aux) {
|
|
pSrc += processedSamples;
|
|
} else {
|
|
pSrc += processedSamples * NUM_OUTPUT_CHANNELS;
|
|
}
|
|
pDst += processedSamples * NUM_OUTPUT_CHANNELS;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int Reverb_Command(effect_interface_t self, int cmdCode, int cmdSize,
|
|
void *pCmdData, int *replySize, void *pReplyData) {
|
|
reverb_module_t *pRvbModule = (reverb_module_t *) self;
|
|
reverb_object_t *pReverb;
|
|
int retsize;
|
|
|
|
if (pRvbModule == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
pReverb = (reverb_object_t*) &pRvbModule->context;
|
|
|
|
LOGV("Reverb_Command command %d cmdSize %d",cmdCode, cmdSize);
|
|
|
|
switch (cmdCode) {
|
|
case EFFECT_CMD_INIT:
|
|
if (pReplyData == NULL || *replySize != sizeof(int)) {
|
|
return -EINVAL;
|
|
}
|
|
*(int *) pReplyData = Reverb_Init(pRvbModule, pReverb->m_Aux, pReverb->m_Preset);
|
|
break;
|
|
case EFFECT_CMD_CONFIGURE:
|
|
if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
|
|
|| pReplyData == NULL || *replySize != sizeof(int)) {
|
|
return -EINVAL;
|
|
}
|
|
*(int *) pReplyData = Reverb_Configure(pRvbModule,
|
|
(effect_config_t *)pCmdData, false);
|
|
break;
|
|
case EFFECT_CMD_RESET:
|
|
Reverb_Reset(pReverb, false);
|
|
break;
|
|
case EFFECT_CMD_GET_PARAM:
|
|
LOGV("Reverb_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %d, pReplyData: %p",pCmdData, *replySize, pReplyData);
|
|
|
|
if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
|
|
pReplyData == NULL || *replySize < (int) sizeof(effect_param_t)) {
|
|
return -EINVAL;
|
|
}
|
|
effect_param_t *rep = (effect_param_t *) pReplyData;
|
|
memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(int32_t));
|
|
LOGV("Reverb_Command EFFECT_CMD_GET_PARAM param %d, replySize %d",*(int32_t *)rep->data, rep->vsize);
|
|
rep->status = Reverb_getParameter(pReverb, *(int32_t *)rep->data, &rep->vsize,
|
|
rep->data + sizeof(int32_t));
|
|
*replySize = sizeof(effect_param_t) + sizeof(int32_t) + rep->vsize;
|
|
break;
|
|
case EFFECT_CMD_SET_PARAM:
|
|
LOGV("Reverb_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
|
|
cmdSize, pCmdData, *replySize, pReplyData);
|
|
if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)))
|
|
|| pReplyData == NULL || *replySize != (int)sizeof(int32_t)) {
|
|
return -EINVAL;
|
|
}
|
|
effect_param_t *cmd = (effect_param_t *) pCmdData;
|
|
*(int *)pReplyData = Reverb_setParameter(pReverb, *(int32_t *)cmd->data,
|
|
cmd->vsize, cmd->data + sizeof(int32_t));
|
|
break;
|
|
case EFFECT_CMD_ENABLE:
|
|
case EFFECT_CMD_DISABLE:
|
|
if (pReplyData == NULL || *replySize != sizeof(int)) {
|
|
return -EINVAL;
|
|
}
|
|
*(int *)pReplyData = 0;
|
|
break;
|
|
case EFFECT_CMD_SET_DEVICE:
|
|
if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
|
|
return -EINVAL;
|
|
}
|
|
LOGV("Reverb_Command EFFECT_CMD_SET_DEVICE: 0x%08x", *(uint32_t *)pCmdData);
|
|
break;
|
|
case EFFECT_CMD_SET_VOLUME: {
|
|
// audio output is always stereo => 2 channel volumes
|
|
if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t) * 2) {
|
|
return -EINVAL;
|
|
}
|
|
float left = (float)(*(uint32_t *)pCmdData) / (1 << 24);
|
|
float right = (float)(*((uint32_t *)pCmdData + 1)) / (1 << 24);
|
|
LOGV("Reverb_Command EFFECT_CMD_SET_VOLUME: left %f, right %f ", left, right);
|
|
break;
|
|
}
|
|
case EFFECT_CMD_SET_AUDIO_MODE:
|
|
if (pCmdData == NULL || cmdSize != (int)sizeof(uint32_t)) {
|
|
return -EINVAL;
|
|
}
|
|
LOGV("Reverb_Command EFFECT_CMD_SET_AUDIO_MODE: %d", *(uint32_t *)pCmdData);
|
|
break;
|
|
default:
|
|
LOGW("Reverb_Command invalid command %d",cmdCode);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Reverb internal functions
|
|
*--------------------------------------------------------------------------*/
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Reverb_Init()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* Initialize reverb context and apply default parameters
|
|
*
|
|
* Inputs:
|
|
* pRvbModule - pointer to reverb effect module
|
|
* aux - indicates if the reverb is used as auxiliary (1) or insert (0)
|
|
* preset - indicates if the reverb is used in preset (1) or environmental (0) mode
|
|
*
|
|
* Outputs:
|
|
*
|
|
* Side Effects:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int Reverb_Init(reverb_module_t *pRvbModule, int aux, int preset) {
|
|
int ret;
|
|
|
|
LOGV("Reverb_Init module %p, aux: %d, preset: %d", pRvbModule,aux, preset);
|
|
|
|
memset(&pRvbModule->context, 0, sizeof(reverb_object_t));
|
|
|
|
pRvbModule->context.m_Aux = (uint16_t)aux;
|
|
pRvbModule->context.m_Preset = (uint16_t)preset;
|
|
|
|
pRvbModule->config.inputCfg.samplingRate = 44100;
|
|
if (aux) {
|
|
pRvbModule->config.inputCfg.channels = CHANNEL_MONO;
|
|
} else {
|
|
pRvbModule->config.inputCfg.channels = CHANNEL_STEREO;
|
|
}
|
|
pRvbModule->config.inputCfg.format = SAMPLE_FORMAT_PCM_S15;
|
|
pRvbModule->config.inputCfg.bufferProvider.getBuffer = NULL;
|
|
pRvbModule->config.inputCfg.bufferProvider.releaseBuffer = NULL;
|
|
pRvbModule->config.inputCfg.bufferProvider.cookie = NULL;
|
|
pRvbModule->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
|
|
pRvbModule->config.inputCfg.mask = EFFECT_CONFIG_ALL;
|
|
pRvbModule->config.outputCfg.samplingRate = 44100;
|
|
pRvbModule->config.outputCfg.channels = CHANNEL_STEREO;
|
|
pRvbModule->config.outputCfg.format = SAMPLE_FORMAT_PCM_S15;
|
|
pRvbModule->config.outputCfg.bufferProvider.getBuffer = NULL;
|
|
pRvbModule->config.outputCfg.bufferProvider.releaseBuffer = NULL;
|
|
pRvbModule->config.outputCfg.bufferProvider.cookie = NULL;
|
|
pRvbModule->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
|
|
pRvbModule->config.outputCfg.mask = EFFECT_CONFIG_ALL;
|
|
|
|
ret = Reverb_Configure(pRvbModule, &pRvbModule->config, true);
|
|
if (ret < 0) {
|
|
LOGV("Reverb_Init error %d on module %p", ret, pRvbModule);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Reverb_Init()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* Set input and output audio configuration.
|
|
*
|
|
* Inputs:
|
|
* pRvbModule - pointer to reverb effect module
|
|
* pConfig - pointer to effect_config_t structure containing input
|
|
* and output audio parameters configuration
|
|
* init - true if called from init function
|
|
* Outputs:
|
|
*
|
|
* Side Effects:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig,
|
|
bool init) {
|
|
reverb_object_t *pReverb = &pRvbModule->context;
|
|
int bufferSizeInSamples;
|
|
int updatePeriodInSamples;
|
|
int xfadePeriodInSamples;
|
|
|
|
// Check configuration compatibility with build options
|
|
if (pConfig->inputCfg.samplingRate
|
|
!= pConfig->outputCfg.samplingRate
|
|
|| pConfig->outputCfg.channels != OUTPUT_CHANNELS
|
|
|| pConfig->inputCfg.format != SAMPLE_FORMAT_PCM_S15
|
|
|| pConfig->outputCfg.format != SAMPLE_FORMAT_PCM_S15) {
|
|
LOGV("Reverb_Configure invalid config");
|
|
return -EINVAL;
|
|
}
|
|
if ((pReverb->m_Aux && (pConfig->inputCfg.channels != CHANNEL_MONO)) ||
|
|
(!pReverb->m_Aux && (pConfig->inputCfg.channels != CHANNEL_STEREO))) {
|
|
LOGV("Reverb_Configure invalid config");
|
|
return -EINVAL;
|
|
}
|
|
|
|
memcpy(&pRvbModule->config, pConfig, sizeof(effect_config_t));
|
|
|
|
pReverb->m_nSamplingRate = pRvbModule->config.outputCfg.samplingRate;
|
|
|
|
switch (pReverb->m_nSamplingRate) {
|
|
case 8000:
|
|
pReverb->m_nUpdatePeriodInBits = 5;
|
|
bufferSizeInSamples = 4096;
|
|
pReverb->m_nCosWT_5KHz = -23170;
|
|
break;
|
|
case 16000:
|
|
pReverb->m_nUpdatePeriodInBits = 6;
|
|
bufferSizeInSamples = 8192;
|
|
pReverb->m_nCosWT_5KHz = -12540;
|
|
break;
|
|
case 22050:
|
|
pReverb->m_nUpdatePeriodInBits = 7;
|
|
bufferSizeInSamples = 8192;
|
|
pReverb->m_nCosWT_5KHz = 4768;
|
|
break;
|
|
case 32000:
|
|
pReverb->m_nUpdatePeriodInBits = 7;
|
|
bufferSizeInSamples = 16384;
|
|
pReverb->m_nCosWT_5KHz = 18205;
|
|
break;
|
|
case 44100:
|
|
pReverb->m_nUpdatePeriodInBits = 8;
|
|
bufferSizeInSamples = 16384;
|
|
pReverb->m_nCosWT_5KHz = 24799;
|
|
break;
|
|
case 48000:
|
|
pReverb->m_nUpdatePeriodInBits = 8;
|
|
bufferSizeInSamples = 16384;
|
|
pReverb->m_nCosWT_5KHz = 25997;
|
|
break;
|
|
default:
|
|
LOGV("Reverb_Configure invalid sampling rate %d", pReverb->m_nSamplingRate);
|
|
return -EINVAL;
|
|
}
|
|
|
|
// Define a mask for circular addressing, so that array index
|
|
// can wraparound and stay in array boundary of 0, 1, ..., (buffer size -1)
|
|
// The buffer size MUST be a power of two
|
|
pReverb->m_nBufferMask = (int32_t) (bufferSizeInSamples - 1);
|
|
/* reverb parameters are updated every 2^(pReverb->m_nUpdatePeriodInBits) samples */
|
|
updatePeriodInSamples = (int32_t) (0x1L << pReverb->m_nUpdatePeriodInBits);
|
|
/*
|
|
calculate the update counter by bitwise ANDING with this value to
|
|
generate a 2^n modulo value
|
|
*/
|
|
pReverb->m_nUpdatePeriodInSamples = (int32_t) updatePeriodInSamples;
|
|
|
|
xfadePeriodInSamples = (int32_t) (REVERB_XFADE_PERIOD_IN_SECONDS
|
|
* (double) pReverb->m_nSamplingRate);
|
|
|
|
// set xfade parameters
|
|
pReverb->m_nPhaseIncrement
|
|
= (int16_t) (65536 / ((int16_t) xfadePeriodInSamples
|
|
/ (int16_t) updatePeriodInSamples));
|
|
|
|
if (init) {
|
|
ReverbReadInPresets(pReverb);
|
|
|
|
// for debugging purposes, allow noise generator
|
|
pReverb->m_bUseNoise = true;
|
|
|
|
// for debugging purposes, allow bypass
|
|
pReverb->m_bBypass = false;
|
|
|
|
pReverb->m_nNextRoom = 1;
|
|
|
|
pReverb->m_nNoise = (int16_t) 0xABCD;
|
|
}
|
|
|
|
Reverb_Reset(pReverb, init);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Reverb_Reset()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* Reset internal states and clear delay lines.
|
|
*
|
|
* Inputs:
|
|
* pReverb - pointer to reverb context
|
|
* init - true if called from init function
|
|
*
|
|
* Outputs:
|
|
*
|
|
* Side Effects:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void Reverb_Reset(reverb_object_t *pReverb, bool init) {
|
|
int bufferSizeInSamples = (int32_t) (pReverb->m_nBufferMask + 1);
|
|
int maxApSamples;
|
|
int maxDelaySamples;
|
|
int maxEarlySamples;
|
|
int ap1In;
|
|
int delay0In;
|
|
int delay1In;
|
|
int32_t i;
|
|
uint16_t nOffset;
|
|
|
|
maxApSamples = ((int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16);
|
|
maxDelaySamples = ((int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
|
|
>> 16);
|
|
maxEarlySamples = ((int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
|
|
>> 16);
|
|
|
|
ap1In = (AP0_IN + maxApSamples + GUARD);
|
|
delay0In = (ap1In + maxApSamples + GUARD);
|
|
delay1In = (delay0In + maxDelaySamples + GUARD);
|
|
// Define the max offsets for the end points of each section
|
|
// i.e., we don't expect a given section's taps to go beyond
|
|
// the following limits
|
|
|
|
pReverb->m_nEarly0in = (delay1In + maxDelaySamples + GUARD);
|
|
pReverb->m_nEarly1in = (pReverb->m_nEarly0in + maxEarlySamples + GUARD);
|
|
|
|
pReverb->m_sAp0.m_zApIn = AP0_IN;
|
|
|
|
pReverb->m_zD0In = delay0In;
|
|
|
|
pReverb->m_sAp1.m_zApIn = ap1In;
|
|
|
|
pReverb->m_zD1In = delay1In;
|
|
|
|
pReverb->m_zOutLpfL = 0;
|
|
pReverb->m_zOutLpfR = 0;
|
|
|
|
pReverb->m_nRevFbkR = 0;
|
|
pReverb->m_nRevFbkL = 0;
|
|
|
|
// set base index into circular buffer
|
|
pReverb->m_nBaseIndex = 0;
|
|
|
|
// clear the reverb delay line
|
|
for (i = 0; i < bufferSizeInSamples; i++) {
|
|
pReverb->m_nDelayLine[i] = 0;
|
|
}
|
|
|
|
ReverbUpdateRoom(pReverb, init);
|
|
|
|
pReverb->m_nUpdateCounter = 0;
|
|
|
|
pReverb->m_nPhase = -32768;
|
|
|
|
pReverb->m_nSin = 0;
|
|
pReverb->m_nCos = 0;
|
|
pReverb->m_nSinIncrement = 0;
|
|
pReverb->m_nCosIncrement = 0;
|
|
|
|
// set delay tap lengths
|
|
nOffset = ReverbCalculateNoise(pReverb);
|
|
|
|
pReverb->m_zD1Cross = pReverb->m_nDelay1Out - pReverb->m_nMaxExcursion
|
|
+ nOffset;
|
|
|
|
nOffset = ReverbCalculateNoise(pReverb);
|
|
|
|
pReverb->m_zD0Cross = pReverb->m_nDelay0Out - pReverb->m_nMaxExcursion
|
|
- nOffset;
|
|
|
|
nOffset = ReverbCalculateNoise(pReverb);
|
|
|
|
pReverb->m_zD0Self = pReverb->m_nDelay0Out - pReverb->m_nMaxExcursion
|
|
- nOffset;
|
|
|
|
nOffset = ReverbCalculateNoise(pReverb);
|
|
|
|
pReverb->m_zD1Self = pReverb->m_nDelay1Out - pReverb->m_nMaxExcursion
|
|
+ nOffset;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Reverb_getParameter()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* Get a Reverb parameter
|
|
*
|
|
* Inputs:
|
|
* pReverb - handle to instance data
|
|
* param - parameter
|
|
* pValue - pointer to variable to hold retrieved value
|
|
* pSize - pointer to value size: maximum size as input
|
|
*
|
|
* Outputs:
|
|
* *pValue updated with parameter value
|
|
* *pSize updated with actual value size
|
|
*
|
|
*
|
|
* Side Effects:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize,
|
|
void *pValue) {
|
|
int32_t *pValue32;
|
|
int16_t *pValue16;
|
|
t_reverb_properties *pProperties;
|
|
int32_t i;
|
|
int32_t temp;
|
|
int32_t temp2;
|
|
size_t size;
|
|
|
|
if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
|
|
return -EINVAL;
|
|
}
|
|
if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (param) {
|
|
case REVERB_PARAM_ROOM_LEVEL:
|
|
case REVERB_PARAM_ROOM_HF_LEVEL:
|
|
case REVERB_PARAM_DECAY_HF_RATIO:
|
|
case REVERB_PARAM_REFLECTIONS_LEVEL:
|
|
case REVERB_PARAM_REVERB_LEVEL:
|
|
case REVERB_PARAM_DIFFUSION:
|
|
case REVERB_PARAM_DENSITY:
|
|
size = sizeof(int16_t);
|
|
break;
|
|
|
|
case REVERB_PARAM_BYPASS:
|
|
case REVERB_PARAM_PRESET:
|
|
case REVERB_PARAM_DECAY_TIME:
|
|
case REVERB_PARAM_REFLECTIONS_DELAY:
|
|
case REVERB_PARAM_REVERB_DELAY:
|
|
size = sizeof(int32_t);
|
|
break;
|
|
|
|
case REVERB_PARAM_PROPERTIES:
|
|
size = sizeof(t_reverb_properties);
|
|
break;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (*pSize < size) {
|
|
return -EINVAL;
|
|
}
|
|
*pSize = size;
|
|
pValue32 = (int32_t *) pValue;
|
|
pValue16 = (int16_t *) pValue;
|
|
pProperties = (t_reverb_properties *) pValue;
|
|
|
|
switch (param) {
|
|
case REVERB_PARAM_BYPASS:
|
|
*(int32_t *) pValue = (int32_t) pReverb->m_bBypass;
|
|
break;
|
|
case REVERB_PARAM_PRESET:
|
|
*(int32_t *) pValue = (int8_t) pReverb->m_nCurrentRoom;
|
|
break;
|
|
|
|
case REVERB_PARAM_PROPERTIES:
|
|
pValue16 = &pProperties->roomLevel;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_ROOM_LEVEL:
|
|
// Convert m_nRoomLpfFwd to millibels
|
|
temp = (pReverb->m_nRoomLpfFwd << 15)
|
|
/ (32767 - pReverb->m_nRoomLpfFbk);
|
|
*pValue16 = Effects_Linear16ToMillibels(temp);
|
|
|
|
LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
|
|
|
|
if (param == REVERB_PARAM_ROOM_LEVEL) {
|
|
break;
|
|
}
|
|
pValue16 = &pProperties->roomHFLevel;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_ROOM_HF_LEVEL:
|
|
// The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
|
|
// (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
|
|
// - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
|
|
// - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
|
|
|
|
temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
|
|
LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
|
|
temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
|
|
<< 1;
|
|
LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
|
|
temp = 32767 + temp - temp2;
|
|
LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
|
|
temp = Effects_Sqrt(temp) * 181;
|
|
LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
|
|
temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
|
|
|
|
LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
|
|
|
|
*pValue16 = Effects_Linear16ToMillibels(temp);
|
|
|
|
if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
|
|
break;
|
|
}
|
|
pValue32 = &pProperties->decayTime;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_DECAY_TIME:
|
|
// Calculate reverb feedback path gain
|
|
temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
|
|
temp = Effects_Linear16ToMillibels(temp);
|
|
|
|
// Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
|
|
temp = (-6000 * pReverb->m_nLateDelay) / temp;
|
|
|
|
// Convert samples to ms
|
|
*pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
|
|
|
|
LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
|
|
|
|
if (param == REVERB_PARAM_DECAY_TIME) {
|
|
break;
|
|
}
|
|
pValue16 = &pProperties->decayHFRatio;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_DECAY_HF_RATIO:
|
|
// If r is the decay HF ratio (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
|
|
// DT_5000Hz = DT_0Hz * r
|
|
// and G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
|
|
// r = G_0Hz/G_5000Hz in millibels
|
|
// The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
|
|
// - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
|
|
// - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
|
|
// - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
|
|
if (pReverb->m_nRvbLpfFbk == 0) {
|
|
*pValue16 = 1000;
|
|
LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
|
|
} else {
|
|
temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
|
|
temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
|
|
<< 1;
|
|
temp = 32767 + temp - temp2;
|
|
temp = Effects_Sqrt(temp) * 181;
|
|
temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
|
|
// The linear gain at 0Hz is b0 / (a1 + 1)
|
|
temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
|
|
- pReverb->m_nRvbLpfFbk);
|
|
|
|
temp = Effects_Linear16ToMillibels(temp);
|
|
temp2 = Effects_Linear16ToMillibels(temp2);
|
|
LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
|
|
|
|
if (temp == 0)
|
|
temp = 1;
|
|
temp = (int16_t) ((1000 * temp2) / temp);
|
|
if (temp > 1000)
|
|
temp = 1000;
|
|
|
|
*pValue16 = temp;
|
|
LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
|
|
}
|
|
|
|
if (param == REVERB_PARAM_DECAY_HF_RATIO) {
|
|
break;
|
|
}
|
|
pValue16 = &pProperties->reflectionsLevel;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_REFLECTIONS_LEVEL:
|
|
*pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
|
|
|
|
LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
|
|
if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
|
|
break;
|
|
}
|
|
pValue32 = &pProperties->reflectionsDelay;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_REFLECTIONS_DELAY:
|
|
// convert samples to ms
|
|
*pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
|
|
|
|
LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
|
|
|
|
if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
|
|
break;
|
|
}
|
|
pValue16 = &pProperties->reverbLevel;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_REVERB_LEVEL:
|
|
// Convert linear gain to millibels
|
|
*pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
|
|
|
|
LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
|
|
|
|
if (param == REVERB_PARAM_REVERB_LEVEL) {
|
|
break;
|
|
}
|
|
pValue32 = &pProperties->reverbDelay;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_REVERB_DELAY:
|
|
// convert samples to ms
|
|
*pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
|
|
|
|
LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
|
|
|
|
if (param == REVERB_PARAM_REVERB_DELAY) {
|
|
break;
|
|
}
|
|
pValue16 = &pProperties->diffusion;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_DIFFUSION:
|
|
temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
|
|
/ AP0_GAIN_RANGE);
|
|
|
|
if (temp < 0)
|
|
temp = 0;
|
|
if (temp > 1000)
|
|
temp = 1000;
|
|
|
|
*pValue16 = temp;
|
|
LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
|
|
|
|
if (param == REVERB_PARAM_DIFFUSION) {
|
|
break;
|
|
}
|
|
pValue16 = &pProperties->density;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_DENSITY:
|
|
// Calculate AP delay in time units
|
|
temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
|
|
/ pReverb->m_nSamplingRate;
|
|
|
|
temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
|
|
|
|
if (temp < 0)
|
|
temp = 0;
|
|
if (temp > 1000)
|
|
temp = 1000;
|
|
|
|
*pValue16 = temp;
|
|
|
|
LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
LOGV("Reverb_getParameter, context %p, param %d, value %d",
|
|
pReverb, param, *(int *)pValue);
|
|
|
|
return 0;
|
|
} /* end Reverb_getParameter */
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Reverb_setParameter()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* Set a Reverb parameter
|
|
*
|
|
* Inputs:
|
|
* pReverb - handle to instance data
|
|
* param - parameter
|
|
* pValue - pointer to parameter value
|
|
* size - value size
|
|
*
|
|
* Outputs:
|
|
*
|
|
*
|
|
* Side Effects:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
int Reverb_setParameter(reverb_object_t *pReverb, int32_t param, size_t size,
|
|
void *pValue) {
|
|
int32_t value32;
|
|
int16_t value16;
|
|
t_reverb_properties *pProperties;
|
|
int32_t i;
|
|
int32_t temp;
|
|
int32_t temp2;
|
|
reverb_preset_t *pPreset;
|
|
int maxSamples;
|
|
int32_t averageDelay;
|
|
size_t paramSize;
|
|
|
|
LOGV("Reverb_setParameter, context %p, param %d, value16 %d, value32 %d",
|
|
pReverb, param, *(int16_t *)pValue, *(int32_t *)pValue);
|
|
|
|
if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
|
|
return -EINVAL;
|
|
}
|
|
if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (param) {
|
|
case REVERB_PARAM_ROOM_LEVEL:
|
|
case REVERB_PARAM_ROOM_HF_LEVEL:
|
|
case REVERB_PARAM_DECAY_HF_RATIO:
|
|
case REVERB_PARAM_REFLECTIONS_LEVEL:
|
|
case REVERB_PARAM_REVERB_LEVEL:
|
|
case REVERB_PARAM_DIFFUSION:
|
|
case REVERB_PARAM_DENSITY:
|
|
paramSize = sizeof(int16_t);
|
|
break;
|
|
|
|
case REVERB_PARAM_BYPASS:
|
|
case REVERB_PARAM_PRESET:
|
|
case REVERB_PARAM_DECAY_TIME:
|
|
case REVERB_PARAM_REFLECTIONS_DELAY:
|
|
case REVERB_PARAM_REVERB_DELAY:
|
|
paramSize = sizeof(int32_t);
|
|
break;
|
|
|
|
case REVERB_PARAM_PROPERTIES:
|
|
paramSize = sizeof(t_reverb_properties);
|
|
break;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (size != paramSize) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (paramSize == sizeof(int16_t)) {
|
|
value16 = *(int16_t *) pValue;
|
|
} else if (paramSize == sizeof(int32_t)) {
|
|
value32 = *(int32_t *) pValue;
|
|
} else {
|
|
pProperties = (t_reverb_properties *) pValue;
|
|
}
|
|
|
|
pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nCurrentRoom];
|
|
|
|
switch (param) {
|
|
case REVERB_PARAM_BYPASS:
|
|
pReverb->m_bBypass = (uint16_t)value32;
|
|
break;
|
|
case REVERB_PARAM_PRESET:
|
|
if (value32 != REVERB_PRESET_LARGE_HALL && value32
|
|
!= REVERB_PRESET_HALL && value32 != REVERB_PRESET_CHAMBER
|
|
&& value32 != REVERB_PRESET_ROOM)
|
|
return -EINVAL;
|
|
pReverb->m_nNextRoom = (int16_t) value32;
|
|
break;
|
|
|
|
case REVERB_PARAM_PROPERTIES:
|
|
value16 = pProperties->roomLevel;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_ROOM_LEVEL:
|
|
// Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
|
|
if (value16 > 0)
|
|
return -EINVAL;
|
|
|
|
temp = Effects_MillibelsToLinear16(value16);
|
|
|
|
pReverb->m_nRoomLpfFwd
|
|
= MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
|
|
|
|
LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
|
|
if (param == REVERB_PARAM_ROOM_LEVEL)
|
|
break;
|
|
value16 = pProperties->roomHFLevel;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_ROOM_HF_LEVEL:
|
|
|
|
// Limit to 0 , -40dB range because of low pass implementation
|
|
if (value16 > 0 || value16 < -4000)
|
|
return -EINVAL;
|
|
// Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
|
|
// m_nRoomLpfFbk is -a1 where a1 is the solution of:
|
|
// a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
|
|
// - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
|
|
// - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
|
|
|
|
// Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
|
|
// while changing HF level
|
|
temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
|
|
- pReverb->m_nRoomLpfFbk);
|
|
if (value16 == 0) {
|
|
pReverb->m_nRoomLpfFbk = 0;
|
|
} else {
|
|
int32_t dG2, b, delta;
|
|
|
|
// dG^2
|
|
temp = Effects_MillibelsToLinear16(value16);
|
|
LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
|
|
temp = (1 << 30) / temp;
|
|
LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
|
|
dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
|
|
LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
|
|
// b = 2*(C-dG^2)/(1-dG^2)
|
|
b = (int32_t) ((((int64_t) 1 << (15 + 1))
|
|
* ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
|
|
/ ((int64_t) 32767 - (int64_t) dG2));
|
|
|
|
// delta = b^2 - 4
|
|
delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
|
|
+ 2)));
|
|
|
|
LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
|
|
|
|
LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
|
|
// m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
|
|
pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
|
|
}
|
|
LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
|
|
temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
|
|
|
|
pReverb->m_nRoomLpfFwd
|
|
= MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
|
|
LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
|
|
|
|
if (param == REVERB_PARAM_ROOM_HF_LEVEL)
|
|
break;
|
|
value32 = pProperties->decayTime;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_DECAY_TIME:
|
|
|
|
// Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
|
|
// convert ms to samples
|
|
value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
|
|
|
|
// calculate valid decay time range as a function of current reverb delay and
|
|
// max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
|
|
// Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
|
|
// g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
|
|
averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
|
|
averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
|
|
+ (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
|
|
|
|
temp = (-6000 * averageDelay) / value32;
|
|
LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
|
|
if (temp < -4000 || temp > -100)
|
|
return -EINVAL;
|
|
|
|
// calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
|
|
// xfade and sum gain (max +9dB)
|
|
temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
|
|
temp = Effects_MillibelsToLinear16(temp);
|
|
|
|
// DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
|
|
pReverb->m_nRvbLpfFwd
|
|
= MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
|
|
|
|
LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
|
|
|
|
if (param == REVERB_PARAM_DECAY_TIME)
|
|
break;
|
|
value16 = pProperties->decayHFRatio;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_DECAY_HF_RATIO:
|
|
|
|
// We limit max value to 1000 because reverb filter is lowpass only
|
|
if (value16 < 100 || value16 > 1000)
|
|
return -EINVAL;
|
|
// Convert per mille to => m_nLpfFwd, m_nLpfFbk
|
|
|
|
// Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
|
|
// while changing HF level
|
|
temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
|
|
|
|
if (value16 == 1000) {
|
|
pReverb->m_nRvbLpfFbk = 0;
|
|
} else {
|
|
int32_t dG2, b, delta;
|
|
|
|
temp = Effects_Linear16ToMillibels(temp2);
|
|
// G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
|
|
|
|
value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
|
|
LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
|
|
|
|
temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
|
|
|
|
if (temp < -4000) {
|
|
LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
|
|
temp = -4000;
|
|
}
|
|
|
|
temp = Effects_MillibelsToLinear16(temp);
|
|
LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
|
|
// dG^2
|
|
temp = (temp2 << 15) / temp;
|
|
dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
|
|
|
|
// b = 2*(C-dG^2)/(1-dG^2)
|
|
b = (int32_t) ((((int64_t) 1 << (15 + 1))
|
|
* ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
|
|
/ ((int64_t) 32767 - (int64_t) dG2));
|
|
|
|
// delta = b^2 - 4
|
|
delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
|
|
+ 2)));
|
|
|
|
// m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
|
|
pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
|
|
|
|
LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
|
|
|
|
}
|
|
|
|
LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
|
|
|
|
pReverb->m_nRvbLpfFwd
|
|
= MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
|
|
|
|
if (param == REVERB_PARAM_DECAY_HF_RATIO)
|
|
break;
|
|
value16 = pProperties->reflectionsLevel;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_REFLECTIONS_LEVEL:
|
|
// We limit max value to 0 because gain is limited to 0dB
|
|
if (value16 > 0 || value16 < -6000)
|
|
return -EINVAL;
|
|
|
|
// Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
|
|
value16 = Effects_MillibelsToLinear16(value16);
|
|
for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
|
|
pReverb->m_sEarlyL.m_nGain[i]
|
|
= MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
|
|
pReverb->m_sEarlyR.m_nGain[i]
|
|
= MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
|
|
}
|
|
pReverb->m_nEarlyGain = value16;
|
|
LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
|
|
|
|
if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
|
|
break;
|
|
value32 = pProperties->reflectionsDelay;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_REFLECTIONS_DELAY:
|
|
// We limit max value MAX_EARLY_TIME
|
|
// convert ms to time units
|
|
temp = (value32 * 65536) / 1000;
|
|
if (temp < 0 || temp > MAX_EARLY_TIME)
|
|
return -EINVAL;
|
|
|
|
maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
|
|
>> 16;
|
|
temp = (temp * pReverb->m_nSamplingRate) >> 16;
|
|
for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
|
|
temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
|
|
* pReverb->m_nSamplingRate) >> 16);
|
|
if (temp2 > maxSamples)
|
|
temp2 = maxSamples;
|
|
pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
|
|
temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
|
|
* pReverb->m_nSamplingRate) >> 16);
|
|
if (temp2 > maxSamples)
|
|
temp2 = maxSamples;
|
|
pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
|
|
}
|
|
pReverb->m_nEarlyDelay = temp;
|
|
|
|
LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
|
|
|
|
// Convert milliseconds to sample count => m_nEarlyDelay
|
|
if (param == REVERB_PARAM_REFLECTIONS_DELAY)
|
|
break;
|
|
value16 = pProperties->reverbLevel;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_REVERB_LEVEL:
|
|
// We limit max value to 0 because gain is limited to 0dB
|
|
if (value16 > 0 || value16 < -6000)
|
|
return -EINVAL;
|
|
// Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
|
|
pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
|
|
|
|
LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
|
|
|
|
if (param == REVERB_PARAM_REVERB_LEVEL)
|
|
break;
|
|
value32 = pProperties->reverbDelay;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_REVERB_DELAY:
|
|
// We limit max value to MAX_DELAY_TIME
|
|
// convert ms to time units
|
|
temp = (value32 * 65536) / 1000;
|
|
if (temp < 0 || temp > MAX_DELAY_TIME)
|
|
return -EINVAL;
|
|
|
|
maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
|
|
>> 16;
|
|
temp = (temp * pReverb->m_nSamplingRate) >> 16;
|
|
if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
|
|
temp = maxSamples - pReverb->m_nMaxExcursion;
|
|
}
|
|
if (temp < pReverb->m_nMaxExcursion) {
|
|
temp = pReverb->m_nMaxExcursion;
|
|
}
|
|
|
|
temp -= pReverb->m_nLateDelay;
|
|
pReverb->m_nDelay0Out += temp;
|
|
pReverb->m_nDelay1Out += temp;
|
|
pReverb->m_nLateDelay += temp;
|
|
|
|
LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
|
|
|
|
// Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
|
|
if (param == REVERB_PARAM_REVERB_DELAY)
|
|
break;
|
|
|
|
value16 = pProperties->diffusion;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_DIFFUSION:
|
|
if (value16 < 0 || value16 > 1000)
|
|
return -EINVAL;
|
|
|
|
// Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
|
|
pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
|
|
* AP0_GAIN_RANGE) / 1000;
|
|
pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
|
|
* AP1_GAIN_RANGE) / 1000;
|
|
|
|
LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
|
|
|
|
if (param == REVERB_PARAM_DIFFUSION)
|
|
break;
|
|
|
|
value16 = pProperties->density;
|
|
/* FALL THROUGH */
|
|
|
|
case REVERB_PARAM_DENSITY:
|
|
if (value16 < 0 || value16 > 1000)
|
|
return -EINVAL;
|
|
|
|
// Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
|
|
maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
|
|
|
|
temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
|
|
/*lint -e{702} shift for performance */
|
|
temp = (temp * pReverb->m_nSamplingRate) >> 16;
|
|
if (temp > maxSamples)
|
|
temp = maxSamples;
|
|
pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
|
|
|
|
LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
|
|
|
|
temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
|
|
/*lint -e{702} shift for performance */
|
|
temp = (temp * pReverb->m_nSamplingRate) >> 16;
|
|
if (temp > maxSamples)
|
|
temp = maxSamples;
|
|
pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
|
|
|
|
LOGV("Ap1 delay smps %d", temp);
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
} /* end Reverb_setParameter */
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* ReverbUpdateXfade
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* Update the xfade parameters as required
|
|
*
|
|
* Inputs:
|
|
* nNumSamplesToAdd - number of samples to write to buffer
|
|
*
|
|
* Outputs:
|
|
*
|
|
*
|
|
* Side Effects:
|
|
* - xfade parameters will be changed
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
static int ReverbUpdateXfade(reverb_object_t *pReverb, int nNumSamplesToAdd) {
|
|
uint16_t nOffset;
|
|
int16_t tempCos;
|
|
int16_t tempSin;
|
|
|
|
if (pReverb->m_nXfadeCounter >= pReverb->m_nXfadeInterval) {
|
|
/* update interval has elapsed, so reset counter */
|
|
pReverb->m_nXfadeCounter = 0;
|
|
|
|
// Pin the sin,cos values to min / max values to ensure that the
|
|
// modulated taps' coefs are zero (thus no clicks)
|
|
if (pReverb->m_nPhaseIncrement > 0) {
|
|
// if phase increment > 0, then sin -> 1, cos -> 0
|
|
pReverb->m_nSin = 32767;
|
|
pReverb->m_nCos = 0;
|
|
|
|
// reset the phase to match the sin, cos values
|
|
pReverb->m_nPhase = 32767;
|
|
|
|
// modulate the cross taps because their tap coefs are zero
|
|
nOffset = ReverbCalculateNoise(pReverb);
|
|
|
|
pReverb->m_zD1Cross = pReverb->m_nDelay1Out
|
|
- pReverb->m_nMaxExcursion + nOffset;
|
|
|
|
nOffset = ReverbCalculateNoise(pReverb);
|
|
|
|
pReverb->m_zD0Cross = pReverb->m_nDelay0Out
|
|
- pReverb->m_nMaxExcursion - nOffset;
|
|
} else {
|
|
// if phase increment < 0, then sin -> 0, cos -> 1
|
|
pReverb->m_nSin = 0;
|
|
pReverb->m_nCos = 32767;
|
|
|
|
// reset the phase to match the sin, cos values
|
|
pReverb->m_nPhase = -32768;
|
|
|
|
// modulate the self taps because their tap coefs are zero
|
|
nOffset = ReverbCalculateNoise(pReverb);
|
|
|
|
pReverb->m_zD0Self = pReverb->m_nDelay0Out
|
|
- pReverb->m_nMaxExcursion - nOffset;
|
|
|
|
nOffset = ReverbCalculateNoise(pReverb);
|
|
|
|
pReverb->m_zD1Self = pReverb->m_nDelay1Out
|
|
- pReverb->m_nMaxExcursion + nOffset;
|
|
|
|
} // end if-else (pReverb->m_nPhaseIncrement > 0)
|
|
|
|
// Reverse the direction of the sin,cos so that the
|
|
// tap whose coef was previously increasing now decreases
|
|
// and vice versa
|
|
pReverb->m_nPhaseIncrement = -pReverb->m_nPhaseIncrement;
|
|
|
|
} // end if counter >= update interval
|
|
|
|
//compute what phase will be next time
|
|
pReverb->m_nPhase += pReverb->m_nPhaseIncrement;
|
|
|
|
//calculate what the new sin and cos need to reach by the next update
|
|
ReverbCalculateSinCos(pReverb->m_nPhase, &tempSin, &tempCos);
|
|
|
|
//calculate the per-sample increment required to get there by the next update
|
|
/*lint -e{702} shift for performance */
|
|
pReverb->m_nSinIncrement = (tempSin - pReverb->m_nSin)
|
|
>> pReverb->m_nUpdatePeriodInBits;
|
|
|
|
/*lint -e{702} shift for performance */
|
|
pReverb->m_nCosIncrement = (tempCos - pReverb->m_nCos)
|
|
>> pReverb->m_nUpdatePeriodInBits;
|
|
|
|
/* increment update counter */
|
|
pReverb->m_nXfadeCounter += (uint16_t) nNumSamplesToAdd;
|
|
|
|
return 0;
|
|
|
|
} /* end ReverbUpdateXfade */
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* ReverbCalculateNoise
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* Calculate a noise sample and limit its value
|
|
*
|
|
* Inputs:
|
|
* nMaxExcursion - noise value is limited to this value
|
|
* pnNoise - return new noise sample in this (not limited)
|
|
*
|
|
* Outputs:
|
|
* new limited noise value
|
|
*
|
|
* Side Effects:
|
|
* - *pnNoise noise value is updated
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
static uint16_t ReverbCalculateNoise(reverb_object_t *pReverb) {
|
|
int16_t nNoise = pReverb->m_nNoise;
|
|
|
|
// calculate new noise value
|
|
if (pReverb->m_bUseNoise) {
|
|
nNoise = (int16_t) (nNoise * 5 + 1);
|
|
} else {
|
|
nNoise = 0;
|
|
}
|
|
|
|
pReverb->m_nNoise = nNoise;
|
|
// return the limited noise value
|
|
return (pReverb->m_nMaxExcursion & nNoise);
|
|
|
|
} /* end ReverbCalculateNoise */
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* ReverbCalculateSinCos
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* Calculate a new sin and cosine value based on the given phase
|
|
*
|
|
* Inputs:
|
|
* nPhase - phase angle
|
|
* pnSin - input old value, output new value
|
|
* pnCos - input old value, output new value
|
|
*
|
|
* Outputs:
|
|
*
|
|
* Side Effects:
|
|
* - *pnSin, *pnCos are updated
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
static int ReverbCalculateSinCos(int16_t nPhase, int16_t *pnSin, int16_t *pnCos) {
|
|
int32_t nTemp;
|
|
int32_t nNetAngle;
|
|
|
|
// -1 <= nPhase < 1
|
|
// However, for the calculation, we need a value
|
|
// that ranges from -1/2 to +1/2, so divide the phase by 2
|
|
/*lint -e{702} shift for performance */
|
|
nNetAngle = nPhase >> 1;
|
|
|
|
/*
|
|
Implement the following
|
|
sin(x) = (2-4*c)*x^2 + c + x
|
|
cos(x) = (2-4*c)*x^2 + c - x
|
|
|
|
where c = 1/sqrt(2)
|
|
using the a0 + x*(a1 + x*a2) approach
|
|
*/
|
|
|
|
/* limit the input "angle" to be between -0.5 and +0.5 */
|
|
if (nNetAngle > EG1_HALF) {
|
|
nNetAngle = EG1_HALF;
|
|
} else if (nNetAngle < EG1_MINUS_HALF) {
|
|
nNetAngle = EG1_MINUS_HALF;
|
|
}
|
|
|
|
/* calculate sin */
|
|
nTemp = EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle);
|
|
nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle);
|
|
*pnSin = (int16_t) SATURATE_EG1(nTemp);
|
|
|
|
/* calculate cos */
|
|
nTemp = -EG1_ONE + MULT_EG1_EG1(REVERB_PAN_G2, nNetAngle);
|
|
nTemp = REVERB_PAN_G0 + MULT_EG1_EG1(nTemp, nNetAngle);
|
|
*pnCos = (int16_t) SATURATE_EG1(nTemp);
|
|
|
|
return 0;
|
|
} /* end ReverbCalculateSinCos */
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* Reverb
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* apply reverb to the given signal
|
|
*
|
|
* Inputs:
|
|
* nNu
|
|
* pnSin - input old value, output new value
|
|
* pnCos - input old value, output new value
|
|
*
|
|
* Outputs:
|
|
* number of samples actually reverberated
|
|
*
|
|
* Side Effects:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
static int Reverb(reverb_object_t *pReverb, int nNumSamplesToAdd,
|
|
short *pOutputBuffer, short *pInputBuffer) {
|
|
int32_t i;
|
|
int32_t nDelayOut0;
|
|
int32_t nDelayOut1;
|
|
uint16_t nBase;
|
|
|
|
uint32_t nAddr;
|
|
int32_t nTemp1;
|
|
int32_t nTemp2;
|
|
int32_t nApIn;
|
|
int32_t nApOut;
|
|
|
|
int32_t j;
|
|
int32_t nEarlyOut;
|
|
|
|
int32_t tempValue;
|
|
|
|
// get the base address
|
|
nBase = pReverb->m_nBaseIndex;
|
|
|
|
for (i = 0; i < nNumSamplesToAdd; i++) {
|
|
// ********** Left Allpass - start
|
|
nApIn = *pInputBuffer;
|
|
if (!pReverb->m_Aux) {
|
|
pInputBuffer++;
|
|
}
|
|
// store to early delay line
|
|
nAddr = CIRCULAR(nBase, pReverb->m_nEarly0in, pReverb->m_nBufferMask);
|
|
pReverb->m_nDelayLine[nAddr] = (short) nApIn;
|
|
|
|
// left input = (left dry * m_nLateGain) + right feedback from previous period
|
|
|
|
nApIn = SATURATE(nApIn + pReverb->m_nRevFbkR);
|
|
nApIn = MULT_EG1_EG1(nApIn, pReverb->m_nLateGain);
|
|
|
|
// fetch allpass delay line out
|
|
//nAddr = CIRCULAR(nBase, psAp0->m_zApOut, pReverb->m_nBufferMask);
|
|
nAddr
|
|
= CIRCULAR(nBase, pReverb->m_sAp0.m_zApOut, pReverb->m_nBufferMask);
|
|
nDelayOut0 = pReverb->m_nDelayLine[nAddr];
|
|
|
|
// calculate allpass feedforward; subtract the feedforward result
|
|
nTemp1 = MULT_EG1_EG1(nApIn, pReverb->m_sAp0.m_nApGain);
|
|
nApOut = SATURATE(nDelayOut0 - nTemp1); // allpass output
|
|
|
|
// calculate allpass feedback; add the feedback result
|
|
nTemp1 = MULT_EG1_EG1(nApOut, pReverb->m_sAp0.m_nApGain);
|
|
nTemp1 = SATURATE(nApIn + nTemp1);
|
|
|
|
// inject into allpass delay
|
|
nAddr
|
|
= CIRCULAR(nBase, pReverb->m_sAp0.m_zApIn, pReverb->m_nBufferMask);
|
|
pReverb->m_nDelayLine[nAddr] = (short) nTemp1;
|
|
|
|
// inject allpass output into delay line
|
|
nAddr = CIRCULAR(nBase, pReverb->m_zD0In, pReverb->m_nBufferMask);
|
|
pReverb->m_nDelayLine[nAddr] = (short) nApOut;
|
|
|
|
// ********** Left Allpass - end
|
|
|
|
// ********** Right Allpass - start
|
|
nApIn = (*pInputBuffer++);
|
|
// store to early delay line
|
|
nAddr = CIRCULAR(nBase, pReverb->m_nEarly1in, pReverb->m_nBufferMask);
|
|
pReverb->m_nDelayLine[nAddr] = (short) nApIn;
|
|
|
|
// right input = (right dry * m_nLateGain) + left feedback from previous period
|
|
/*lint -e{702} use shift for performance */
|
|
nApIn = SATURATE(nApIn + pReverb->m_nRevFbkL);
|
|
nApIn = MULT_EG1_EG1(nApIn, pReverb->m_nLateGain);
|
|
|
|
// fetch allpass delay line out
|
|
nAddr
|
|
= CIRCULAR(nBase, pReverb->m_sAp1.m_zApOut, pReverb->m_nBufferMask);
|
|
nDelayOut1 = pReverb->m_nDelayLine[nAddr];
|
|
|
|
// calculate allpass feedforward; subtract the feedforward result
|
|
nTemp1 = MULT_EG1_EG1(nApIn, pReverb->m_sAp1.m_nApGain);
|
|
nApOut = SATURATE(nDelayOut1 - nTemp1); // allpass output
|
|
|
|
// calculate allpass feedback; add the feedback result
|
|
nTemp1 = MULT_EG1_EG1(nApOut, pReverb->m_sAp1.m_nApGain);
|
|
nTemp1 = SATURATE(nApIn + nTemp1);
|
|
|
|
// inject into allpass delay
|
|
nAddr
|
|
= CIRCULAR(nBase, pReverb->m_sAp1.m_zApIn, pReverb->m_nBufferMask);
|
|
pReverb->m_nDelayLine[nAddr] = (short) nTemp1;
|
|
|
|
// inject allpass output into delay line
|
|
nAddr = CIRCULAR(nBase, pReverb->m_zD1In, pReverb->m_nBufferMask);
|
|
pReverb->m_nDelayLine[nAddr] = (short) nApOut;
|
|
|
|
// ********** Right Allpass - end
|
|
|
|
// ********** D0 output - start
|
|
// fetch delay line self out
|
|
nAddr = CIRCULAR(nBase, pReverb->m_zD0Self, pReverb->m_nBufferMask);
|
|
nDelayOut0 = pReverb->m_nDelayLine[nAddr];
|
|
|
|
// calculate delay line self out
|
|
nTemp1 = MULT_EG1_EG1(nDelayOut0, pReverb->m_nSin);
|
|
|
|
// fetch delay line cross out
|
|
nAddr = CIRCULAR(nBase, pReverb->m_zD1Cross, pReverb->m_nBufferMask);
|
|
nDelayOut0 = pReverb->m_nDelayLine[nAddr];
|
|
|
|
// calculate delay line self out
|
|
nTemp2 = MULT_EG1_EG1(nDelayOut0, pReverb->m_nCos);
|
|
|
|
// calculate unfiltered delay out
|
|
nDelayOut0 = SATURATE(nTemp1 + nTemp2);
|
|
|
|
// ********** D0 output - end
|
|
|
|
// ********** D1 output - start
|
|
// fetch delay line self out
|
|
nAddr = CIRCULAR(nBase, pReverb->m_zD1Self, pReverb->m_nBufferMask);
|
|
nDelayOut1 = pReverb->m_nDelayLine[nAddr];
|
|
|
|
// calculate delay line self out
|
|
nTemp1 = MULT_EG1_EG1(nDelayOut1, pReverb->m_nSin);
|
|
|
|
// fetch delay line cross out
|
|
nAddr = CIRCULAR(nBase, pReverb->m_zD0Cross, pReverb->m_nBufferMask);
|
|
nDelayOut1 = pReverb->m_nDelayLine[nAddr];
|
|
|
|
// calculate delay line self out
|
|
nTemp2 = MULT_EG1_EG1(nDelayOut1, pReverb->m_nCos);
|
|
|
|
// calculate unfiltered delay out
|
|
nDelayOut1 = SATURATE(nTemp1 + nTemp2);
|
|
|
|
// ********** D1 output - end
|
|
|
|
// ********** mixer and feedback - start
|
|
// sum is fedback to right input (R + L)
|
|
nDelayOut0 = (short) SATURATE(nDelayOut0 + nDelayOut1);
|
|
|
|
// difference is feedback to left input (R - L)
|
|
/*lint -e{685} lint complains that it can't saturate negative */
|
|
nDelayOut1 = (short) SATURATE(nDelayOut1 - nDelayOut0);
|
|
|
|
// ********** mixer and feedback - end
|
|
|
|
// calculate lowpass filter (mixer scale factor included in LPF feedforward)
|
|
nTemp1 = MULT_EG1_EG1(nDelayOut0, pReverb->m_nRvbLpfFwd);
|
|
|
|
nTemp2 = MULT_EG1_EG1(pReverb->m_nRevFbkL, pReverb->m_nRvbLpfFbk);
|
|
|
|
// calculate filtered delay out and simultaneously update LPF state variable
|
|
// filtered delay output is stored in m_nRevFbkL
|
|
pReverb->m_nRevFbkL = (short) SATURATE(nTemp1 + nTemp2);
|
|
|
|
// calculate lowpass filter (mixer scale factor included in LPF feedforward)
|
|
nTemp1 = MULT_EG1_EG1(nDelayOut1, pReverb->m_nRvbLpfFwd);
|
|
|
|
nTemp2 = MULT_EG1_EG1(pReverb->m_nRevFbkR, pReverb->m_nRvbLpfFbk);
|
|
|
|
// calculate filtered delay out and simultaneously update LPF state variable
|
|
// filtered delay output is stored in m_nRevFbkR
|
|
pReverb->m_nRevFbkR = (short) SATURATE(nTemp1 + nTemp2);
|
|
|
|
// ********** start early reflection generator, left
|
|
//psEarly = &(pReverb->m_sEarlyL);
|
|
|
|
|
|
for (j = 0; j < REVERB_MAX_NUM_REFLECTIONS; j++) {
|
|
// fetch delay line out
|
|
//nAddr = CIRCULAR(nBase, psEarly->m_zDelay[j], pReverb->m_nBufferMask);
|
|
nAddr
|
|
= CIRCULAR(nBase, pReverb->m_sEarlyL.m_zDelay[j], pReverb->m_nBufferMask);
|
|
|
|
nTemp1 = pReverb->m_nDelayLine[nAddr];
|
|
|
|
// calculate reflection
|
|
//nTemp1 = MULT_EG1_EG1(nDelayOut0, psEarly->m_nGain[j]);
|
|
nTemp1 = MULT_EG1_EG1(nTemp1, pReverb->m_sEarlyL.m_nGain[j]);
|
|
|
|
nDelayOut0 = SATURATE(nDelayOut0 + nTemp1);
|
|
|
|
} // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++)
|
|
|
|
// apply lowpass to early reflections and reverb output
|
|
//nTemp1 = MULT_EG1_EG1(nEarlyOut, psEarly->m_nRvbLpfFwd);
|
|
nTemp1 = MULT_EG1_EG1(nDelayOut0, pReverb->m_nRoomLpfFwd);
|
|
|
|
//nTemp2 = MULT_EG1_EG1(psEarly->m_zLpf, psEarly->m_nLpfFbk);
|
|
nTemp2 = MULT_EG1_EG1(pReverb->m_zOutLpfL, pReverb->m_nRoomLpfFbk);
|
|
|
|
// calculate filtered out and simultaneously update LPF state variable
|
|
// filtered output is stored in m_zOutLpfL
|
|
pReverb->m_zOutLpfL = (short) SATURATE(nTemp1 + nTemp2);
|
|
|
|
//sum with output buffer
|
|
tempValue = *pOutputBuffer;
|
|
*pOutputBuffer++ = (short) SATURATE(tempValue+pReverb->m_zOutLpfL);
|
|
|
|
// ********** end early reflection generator, left
|
|
|
|
// ********** start early reflection generator, right
|
|
//psEarly = &(pReverb->m_sEarlyR);
|
|
|
|
for (j = 0; j < REVERB_MAX_NUM_REFLECTIONS; j++) {
|
|
// fetch delay line out
|
|
nAddr
|
|
= CIRCULAR(nBase, pReverb->m_sEarlyR.m_zDelay[j], pReverb->m_nBufferMask);
|
|
nTemp1 = pReverb->m_nDelayLine[nAddr];
|
|
|
|
// calculate reflection
|
|
nTemp1 = MULT_EG1_EG1(nTemp1, pReverb->m_sEarlyR.m_nGain[j]);
|
|
|
|
nDelayOut1 = SATURATE(nDelayOut1 + nTemp1);
|
|
|
|
} // end for (j=0; j < REVERB_MAX_NUM_REFLECTIONS; j++)
|
|
|
|
// apply lowpass to early reflections
|
|
nTemp1 = MULT_EG1_EG1(nDelayOut1, pReverb->m_nRoomLpfFwd);
|
|
|
|
nTemp2 = MULT_EG1_EG1(pReverb->m_zOutLpfR, pReverb->m_nRoomLpfFbk);
|
|
|
|
// calculate filtered out and simultaneously update LPF state variable
|
|
// filtered output is stored in m_zOutLpfR
|
|
pReverb->m_zOutLpfR = (short) SATURATE(nTemp1 + nTemp2);
|
|
|
|
//sum with output buffer
|
|
tempValue = *pOutputBuffer;
|
|
*pOutputBuffer++ = (short) SATURATE(tempValue + pReverb->m_zOutLpfR);
|
|
|
|
// ********** end early reflection generator, right
|
|
|
|
// decrement base addr for next sample period
|
|
nBase--;
|
|
|
|
pReverb->m_nSin += pReverb->m_nSinIncrement;
|
|
pReverb->m_nCos += pReverb->m_nCosIncrement;
|
|
|
|
} // end for (i=0; i < nNumSamplesToAdd; i++)
|
|
|
|
// store the most up to date version
|
|
pReverb->m_nBaseIndex = nBase;
|
|
|
|
return 0;
|
|
} /* end Reverb */
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* ReverbUpdateRoom
|
|
*----------------------------------------------------------------------------
|
|
* Purpose:
|
|
* Update the room's preset parameters as required
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Outputs:
|
|
*
|
|
*
|
|
* Side Effects:
|
|
* - reverb paramters (fbk, fwd, etc) will be changed
|
|
* - m_nCurrentRoom := m_nNextRoom
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
static int ReverbUpdateRoom(reverb_object_t *pReverb, bool fullUpdate) {
|
|
int temp;
|
|
int i;
|
|
int maxSamples;
|
|
int earlyDelay;
|
|
int earlyGain;
|
|
|
|
reverb_preset_t *pPreset =
|
|
&pReverb->m_sPreset.m_sPreset[pReverb->m_nNextRoom];
|
|
|
|
if (fullUpdate) {
|
|
pReverb->m_nRvbLpfFwd = pPreset->m_nRvbLpfFwd;
|
|
pReverb->m_nRvbLpfFbk = pPreset->m_nRvbLpfFbk;
|
|
|
|
pReverb->m_nEarlyGain = pPreset->m_nEarlyGain;
|
|
//stored as time based, convert to sample based
|
|
pReverb->m_nLateGain = pPreset->m_nLateGain;
|
|
pReverb->m_nRoomLpfFbk = pPreset->m_nRoomLpfFbk;
|
|
pReverb->m_nRoomLpfFwd = pPreset->m_nRoomLpfFwd;
|
|
|
|
// set the early reflections gains
|
|
earlyGain = pPreset->m_nEarlyGain;
|
|
for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
|
|
pReverb->m_sEarlyL.m_nGain[i]
|
|
= MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],earlyGain);
|
|
pReverb->m_sEarlyR.m_nGain[i]
|
|
= MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],earlyGain);
|
|
}
|
|
|
|
pReverb->m_nMaxExcursion = pPreset->m_nMaxExcursion;
|
|
|
|
pReverb->m_sAp0.m_nApGain = pPreset->m_nAp0_ApGain;
|
|
pReverb->m_sAp1.m_nApGain = pPreset->m_nAp1_ApGain;
|
|
|
|
// set the early reflections delay
|
|
earlyDelay = ((int) pPreset->m_nEarlyDelay * pReverb->m_nSamplingRate)
|
|
>> 16;
|
|
pReverb->m_nEarlyDelay = earlyDelay;
|
|
maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
|
|
>> 16;
|
|
for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
|
|
//stored as time based, convert to sample based
|
|
temp = earlyDelay + (((int) pPreset->m_sEarlyL.m_zDelay[i]
|
|
* pReverb->m_nSamplingRate) >> 16);
|
|
if (temp > maxSamples)
|
|
temp = maxSamples;
|
|
pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp;
|
|
//stored as time based, convert to sample based
|
|
temp = earlyDelay + (((int) pPreset->m_sEarlyR.m_zDelay[i]
|
|
* pReverb->m_nSamplingRate) >> 16);
|
|
if (temp > maxSamples)
|
|
temp = maxSamples;
|
|
pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp;
|
|
}
|
|
|
|
maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
|
|
>> 16;
|
|
//stored as time based, convert to sample based
|
|
/*lint -e{702} shift for performance */
|
|
temp = (pPreset->m_nLateDelay * pReverb->m_nSamplingRate) >> 16;
|
|
if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
|
|
temp = maxSamples - pReverb->m_nMaxExcursion;
|
|
}
|
|
temp -= pReverb->m_nLateDelay;
|
|
pReverb->m_nDelay0Out += temp;
|
|
pReverb->m_nDelay1Out += temp;
|
|
pReverb->m_nLateDelay += temp;
|
|
|
|
maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
|
|
//stored as time based, convert to absolute sample value
|
|
temp = pPreset->m_nAp0_ApOut;
|
|
/*lint -e{702} shift for performance */
|
|
temp = (temp * pReverb->m_nSamplingRate) >> 16;
|
|
if (temp > maxSamples)
|
|
temp = maxSamples;
|
|
pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
|
|
|
|
//stored as time based, convert to absolute sample value
|
|
temp = pPreset->m_nAp1_ApOut;
|
|
/*lint -e{702} shift for performance */
|
|
temp = (temp * pReverb->m_nSamplingRate) >> 16;
|
|
if (temp > maxSamples)
|
|
temp = maxSamples;
|
|
pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
|
|
//gpsReverbObject->m_sAp1.m_zApOut = pPreset->m_nAp1_ApOut;
|
|
}
|
|
|
|
//stored as time based, convert to sample based
|
|
temp = pPreset->m_nXfadeInterval;
|
|
/*lint -e{702} shift for performance */
|
|
temp = (temp * pReverb->m_nSamplingRate) >> 16;
|
|
pReverb->m_nXfadeInterval = (uint16_t) temp;
|
|
//gsReverbObject.m_nXfadeInterval = pPreset->m_nXfadeInterval;
|
|
pReverb->m_nXfadeCounter = pReverb->m_nXfadeInterval + 1; // force update on first iteration
|
|
|
|
pReverb->m_nCurrentRoom = pReverb->m_nNextRoom;
|
|
|
|
return 0;
|
|
|
|
} /* end ReverbUpdateRoom */
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* ReverbReadInPresets()
|
|
*----------------------------------------------------------------------------
|
|
* Purpose: sets global reverb preset bank to defaults
|
|
*
|
|
* Inputs:
|
|
*
|
|
* Outputs:
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
static int ReverbReadInPresets(reverb_object_t *pReverb) {
|
|
|
|
int preset = 0;
|
|
int defaultPreset = 0;
|
|
|
|
//now init any remaining presets to defaults
|
|
for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++) {
|
|
reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[defaultPreset];
|
|
if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE - 1) {
|
|
pPreset->m_nRvbLpfFbk = 8307;
|
|
pPreset->m_nRvbLpfFwd = 14768;
|
|
pPreset->m_nEarlyGain = 27690;
|
|
pPreset->m_nEarlyDelay = 1311;
|
|
pPreset->m_nLateGain = 8191;
|
|
pPreset->m_nLateDelay = 3932;
|
|
pPreset->m_nRoomLpfFbk = 3692;
|
|
pPreset->m_nRoomLpfFwd = 24569;
|
|
pPreset->m_sEarlyL.m_zDelay[0] = 1376;
|
|
pPreset->m_sEarlyL.m_nGain[0] = 22152;
|
|
pPreset->m_sEarlyL.m_zDelay[1] = 2163;
|
|
pPreset->m_sEarlyL.m_nGain[1] = 17537;
|
|
pPreset->m_sEarlyL.m_zDelay[2] = 0;
|
|
pPreset->m_sEarlyL.m_nGain[2] = 14768;
|
|
pPreset->m_sEarlyL.m_zDelay[3] = 1835;
|
|
pPreset->m_sEarlyL.m_nGain[3] = 14307;
|
|
pPreset->m_sEarlyL.m_zDelay[4] = 0;
|
|
pPreset->m_sEarlyL.m_nGain[4] = 13384;
|
|
pPreset->m_sEarlyR.m_zDelay[0] = 721;
|
|
pPreset->m_sEarlyR.m_nGain[0] = 20306;
|
|
pPreset->m_sEarlyR.m_zDelay[1] = 2621;
|
|
pPreset->m_sEarlyR.m_nGain[1] = 17537;
|
|
pPreset->m_sEarlyR.m_zDelay[2] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[2] = 14768;
|
|
pPreset->m_sEarlyR.m_zDelay[3] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[3] = 16153;
|
|
pPreset->m_sEarlyR.m_zDelay[4] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[4] = 13384;
|
|
pPreset->m_nMaxExcursion = 127;
|
|
pPreset->m_nXfadeInterval = 6388;
|
|
pPreset->m_nAp0_ApGain = 15691;
|
|
pPreset->m_nAp0_ApOut = 711;
|
|
pPreset->m_nAp1_ApGain = 16317;
|
|
pPreset->m_nAp1_ApOut = 1029;
|
|
pPreset->m_rfu4 = 0;
|
|
pPreset->m_rfu5 = 0;
|
|
pPreset->m_rfu6 = 0;
|
|
pPreset->m_rfu7 = 0;
|
|
pPreset->m_rfu8 = 0;
|
|
pPreset->m_rfu9 = 0;
|
|
pPreset->m_rfu10 = 0;
|
|
} else if (defaultPreset == 1) {
|
|
pPreset->m_nRvbLpfFbk = 6461;
|
|
pPreset->m_nRvbLpfFwd = 14307;
|
|
pPreset->m_nEarlyGain = 27690;
|
|
pPreset->m_nEarlyDelay = 1311;
|
|
pPreset->m_nLateGain = 8191;
|
|
pPreset->m_nLateDelay = 3932;
|
|
pPreset->m_nRoomLpfFbk = 3692;
|
|
pPreset->m_nRoomLpfFwd = 24569;
|
|
pPreset->m_sEarlyL.m_zDelay[0] = 1376;
|
|
pPreset->m_sEarlyL.m_nGain[0] = 22152;
|
|
pPreset->m_sEarlyL.m_zDelay[1] = 1462;
|
|
pPreset->m_sEarlyL.m_nGain[1] = 17537;
|
|
pPreset->m_sEarlyL.m_zDelay[2] = 0;
|
|
pPreset->m_sEarlyL.m_nGain[2] = 14768;
|
|
pPreset->m_sEarlyL.m_zDelay[3] = 1835;
|
|
pPreset->m_sEarlyL.m_nGain[3] = 14307;
|
|
pPreset->m_sEarlyL.m_zDelay[4] = 0;
|
|
pPreset->m_sEarlyL.m_nGain[4] = 13384;
|
|
pPreset->m_sEarlyR.m_zDelay[0] = 721;
|
|
pPreset->m_sEarlyR.m_nGain[0] = 20306;
|
|
pPreset->m_sEarlyR.m_zDelay[1] = 2621;
|
|
pPreset->m_sEarlyR.m_nGain[1] = 17537;
|
|
pPreset->m_sEarlyR.m_zDelay[2] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[2] = 14768;
|
|
pPreset->m_sEarlyR.m_zDelay[3] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[3] = 16153;
|
|
pPreset->m_sEarlyR.m_zDelay[4] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[4] = 13384;
|
|
pPreset->m_nMaxExcursion = 127;
|
|
pPreset->m_nXfadeInterval = 6391;
|
|
pPreset->m_nAp0_ApGain = 15230;
|
|
pPreset->m_nAp0_ApOut = 708;
|
|
pPreset->m_nAp1_ApGain = 15547;
|
|
pPreset->m_nAp1_ApOut = 1023;
|
|
pPreset->m_rfu4 = 0;
|
|
pPreset->m_rfu5 = 0;
|
|
pPreset->m_rfu6 = 0;
|
|
pPreset->m_rfu7 = 0;
|
|
pPreset->m_rfu8 = 0;
|
|
pPreset->m_rfu9 = 0;
|
|
pPreset->m_rfu10 = 0;
|
|
} else if (defaultPreset == 2) {
|
|
pPreset->m_nRvbLpfFbk = 5077;
|
|
pPreset->m_nRvbLpfFwd = 12922;
|
|
pPreset->m_nEarlyGain = 27690;
|
|
pPreset->m_nEarlyDelay = 1311;
|
|
pPreset->m_nLateGain = 8191;
|
|
pPreset->m_nLateDelay = 3932;
|
|
pPreset->m_nRoomLpfFbk = 3692;
|
|
pPreset->m_nRoomLpfFwd = 21703;
|
|
pPreset->m_sEarlyL.m_zDelay[0] = 1376;
|
|
pPreset->m_sEarlyL.m_nGain[0] = 22152;
|
|
pPreset->m_sEarlyL.m_zDelay[1] = 1462;
|
|
pPreset->m_sEarlyL.m_nGain[1] = 17537;
|
|
pPreset->m_sEarlyL.m_zDelay[2] = 0;
|
|
pPreset->m_sEarlyL.m_nGain[2] = 14768;
|
|
pPreset->m_sEarlyL.m_zDelay[3] = 1835;
|
|
pPreset->m_sEarlyL.m_nGain[3] = 14307;
|
|
pPreset->m_sEarlyL.m_zDelay[4] = 0;
|
|
pPreset->m_sEarlyL.m_nGain[4] = 13384;
|
|
pPreset->m_sEarlyR.m_zDelay[0] = 721;
|
|
pPreset->m_sEarlyR.m_nGain[0] = 20306;
|
|
pPreset->m_sEarlyR.m_zDelay[1] = 2621;
|
|
pPreset->m_sEarlyR.m_nGain[1] = 17537;
|
|
pPreset->m_sEarlyR.m_zDelay[2] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[2] = 14768;
|
|
pPreset->m_sEarlyR.m_zDelay[3] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[3] = 16153;
|
|
pPreset->m_sEarlyR.m_zDelay[4] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[4] = 13384;
|
|
pPreset->m_nMaxExcursion = 127;
|
|
pPreset->m_nXfadeInterval = 6449;
|
|
pPreset->m_nAp0_ApGain = 15691;
|
|
pPreset->m_nAp0_ApOut = 774;
|
|
pPreset->m_nAp1_ApGain = 16317;
|
|
pPreset->m_nAp1_ApOut = 1155;
|
|
pPreset->m_rfu4 = 0;
|
|
pPreset->m_rfu5 = 0;
|
|
pPreset->m_rfu6 = 0;
|
|
pPreset->m_rfu7 = 0;
|
|
pPreset->m_rfu8 = 0;
|
|
pPreset->m_rfu9 = 0;
|
|
pPreset->m_rfu10 = 0;
|
|
} else if (defaultPreset == 3) {
|
|
pPreset->m_nRvbLpfFbk = 5077;
|
|
pPreset->m_nRvbLpfFwd = 11076;
|
|
pPreset->m_nEarlyGain = 27690;
|
|
pPreset->m_nEarlyDelay = 1311;
|
|
pPreset->m_nLateGain = 8191;
|
|
pPreset->m_nLateDelay = 3932;
|
|
pPreset->m_nRoomLpfFbk = 3692;
|
|
pPreset->m_nRoomLpfFwd = 20474;
|
|
pPreset->m_sEarlyL.m_zDelay[0] = 1376;
|
|
pPreset->m_sEarlyL.m_nGain[0] = 22152;
|
|
pPreset->m_sEarlyL.m_zDelay[1] = 1462;
|
|
pPreset->m_sEarlyL.m_nGain[1] = 17537;
|
|
pPreset->m_sEarlyL.m_zDelay[2] = 0;
|
|
pPreset->m_sEarlyL.m_nGain[2] = 14768;
|
|
pPreset->m_sEarlyL.m_zDelay[3] = 1835;
|
|
pPreset->m_sEarlyL.m_nGain[3] = 14307;
|
|
pPreset->m_sEarlyL.m_zDelay[4] = 0;
|
|
pPreset->m_sEarlyL.m_nGain[4] = 13384;
|
|
pPreset->m_sEarlyR.m_zDelay[0] = 721;
|
|
pPreset->m_sEarlyR.m_nGain[0] = 20306;
|
|
pPreset->m_sEarlyR.m_zDelay[1] = 2621;
|
|
pPreset->m_sEarlyR.m_nGain[1] = 17537;
|
|
pPreset->m_sEarlyR.m_zDelay[2] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[2] = 14768;
|
|
pPreset->m_sEarlyR.m_zDelay[3] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[3] = 16153;
|
|
pPreset->m_sEarlyR.m_zDelay[4] = 0;
|
|
pPreset->m_sEarlyR.m_nGain[4] = 13384;
|
|
pPreset->m_nMaxExcursion = 127;
|
|
pPreset->m_nXfadeInterval = 6470; //6483;
|
|
pPreset->m_nAp0_ApGain = 14768;
|
|
pPreset->m_nAp0_ApOut = 792;
|
|
pPreset->m_nAp1_ApGain = 14777;
|
|
pPreset->m_nAp1_ApOut = 1191;
|
|
pPreset->m_rfu4 = 0;
|
|
pPreset->m_rfu5 = 0;
|
|
pPreset->m_rfu6 = 0;
|
|
pPreset->m_rfu7 = 0;
|
|
pPreset->m_rfu8 = 0;
|
|
pPreset->m_rfu9 = 0;
|
|
pPreset->m_rfu10 = 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|