From 56c99cd2c2c1e6ab038dac5fced5b92ccf11ff6c Mon Sep 17 00:00:00 2001 From: Dave Sparks Date: Mon, 24 Aug 2009 17:35:45 -0700 Subject: Sonivox whitespace cleanup --- arm-fm-22k/lib_src/eas_chorus.c | 1184 +++++++++++++++++++-------------------- 1 file changed, 592 insertions(+), 592 deletions(-) (limited to 'arm-fm-22k/lib_src/eas_chorus.c') diff --git a/arm-fm-22k/lib_src/eas_chorus.c b/arm-fm-22k/lib_src/eas_chorus.c index bc42237..4a2c8d0 100644 --- a/arm-fm-22k/lib_src/eas_chorus.c +++ b/arm-fm-22k/lib_src/eas_chorus.c @@ -1,13 +1,13 @@ -/*---------------------------------------------------------------------------- - * - * File: - * eas_chorus.c - * - * Contents and purpose: - * Contains the implementation of the Chorus effect. - * - * - * Copyright Sonic Network Inc. 2006 +/*---------------------------------------------------------------------------- + * + * File: + * eas_chorus.c + * + * Contents and purpose: + * Contains the implementation of the Chorus effect. + * + * + * Copyright Sonic Network Inc. 2006 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,585 +20,585 @@ * 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. - * - *---------------------------------------------------------------------------- - * Revision Control: - * $Revision: 499 $ - * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ - *---------------------------------------------------------------------------- -*/ - -#include "eas_data.h" -#include "eas_effects.h" -#include "eas_math.h" -#include "eas_chorusdata.h" -#include "eas_chorus.h" -#include "eas_config.h" -#include "eas_host.h" -#include "eas_report.h" - -/* prototypes for effects interface */ -static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); -static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); -static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); -static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); -static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); - -/* common effects interface for configuration module */ -const S_EFFECTS_INTERFACE EAS_Chorus = -{ - ChorusInit, - ChorusProcess, - ChorusShutdown, - ChorusGetParam, - ChorusSetParam -}; - - - -//LFO shape table used by the chorus, larger table would sound better -//this is a sine wave, where 32767 = 1.0 -static const EAS_I16 EAS_chorusShape[CHORUS_SHAPE_SIZE] = { - 0, 1608, 3212, 4808, 6393, 7962, 9512, 11309, 12539, 14010, 15446, 16846, 18204, 19519, 20787, 22005, 23170, - 24279, 25329, 26319, 27245, 28105, 28898, 29621, 30273, 30852, 31356, 31785, 32137, 32412, 32609, 32728, - 32767, 32728, 32609, 32412, 32137, 31785, 31356, 30852, 30273, 29621, 28898, 28105, 27245, 26319, 25329, - 24279, 23170, 22005, 20787, 19519, 18204, 16846, 15446, 14010, 12539, 11039, 9512, 7962, 6393, 4808, 3212, - 1608, 0, -1608, -3212, -4808, -6393, -7962, -9512, -11309, -12539, -14010, -15446, -16846, -18204, -19519, - -20787, -22005, -23170, -24279, -25329, -26319, -27245, -28105, -28898, -29621, -30273, -30852, -31356, -31785, - -32137, -32412, -32609, -32728, -32767, -32728, -32609, -32412, -32137, -31785, -31356, -30852, -30273, -29621, - -28898, -28105, -27245, -26319, -25329, -24279, -23170, -22005, -20787, -19519, -18204, -16846, -15446, -14010, - -12539, -11039, -9512, -7962, -6393, -4808, -3212, -1608 -}; - -/*---------------------------------------------------------------------------- - * InitializeChorus() - *---------------------------------------------------------------------------- - * Purpose: Initializes chorus parameters - * - * - * Inputs: - * - * Outputs: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) -{ - S_CHORUS_OBJECT *pChorusData; - S_CHORUS_PRESET *pPreset; - EAS_I32 index; - - /* check Configuration Module for data allocation */ - if (pEASData->staticMemoryModel) - pChorusData = EAS_CMEnumFXData(EAS_MODULE_CHORUS); - - /* allocate dynamic memory */ - else - pChorusData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_CHORUS_OBJECT)); - - if (pChorusData == NULL) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Chorus memory\n"); */ } - return EAS_ERROR_MALLOC_FAILED; - } - - /* clear the structure */ - EAS_HWMemSet(pChorusData, 0, sizeof(S_CHORUS_OBJECT)); - - ChorusReadInPresets(pChorusData); - - /* set some default values */ - pChorusData->bypass = EAS_CHORUS_BYPASS_DEFAULT; - pChorusData->preset = EAS_CHORUS_PRESET_DEFAULT; - pChorusData->m_nLevel = EAS_CHORUS_LEVEL_DEFAULT; - pChorusData->m_nRate = EAS_CHORUS_RATE_DEFAULT; - pChorusData->m_nDepth = EAS_CHORUS_DEPTH_DEFAULT; - - //chorus rate and depth need some massaging from preset value (which is sample rate independent) - - //convert rate from steps of .05 Hz to value which can be used as phase increment, - //with current CHORUS_SHAPE_SIZE and rate limits, this fits into 16 bits - //want to compute ((shapeSize * 65536) * (storedRate/20))/sampleRate; - //computing it as below allows rate steps to be evenly spaced - //uses 32 bit divide, but only once when new value is selected - pChorusData->m_nRate = (EAS_I16) - ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); - - //convert depth from steps of .05 ms, to samples, with 16 bit whole part, discard fraction - //want to compute ((depth * sampleRate)/20000) - //use the following approximation since 105/32 is roughly 65536/20000 - /*lint -e{704} use shift for performance */ - pChorusData->m_nDepth = (EAS_I16) - (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); - - pChorusData->m_nLevel = pChorusData->m_nLevel; - - //zero delay memory for chorus - for (index = CHORUS_L_SIZE - 1; index >= 0; index--) - { - pChorusData->chorusDelayL[index] = 0; - } - for (index = CHORUS_R_SIZE - 1; index >= 0; index--) - { - pChorusData->chorusDelayR[index] = 0; - } - - //init delay line index, these are used to implement circular delay buffer - pChorusData->chorusIndexL = 0; - pChorusData->chorusIndexR = 0; - - //init LFO phase - //16 bit whole part, 16 bit fraction - pChorusData->lfoLPhase = 0; - pChorusData->lfoRPhase = (CHORUS_SHAPE_SIZE << 16) >> 2; // 1/4 of total, i.e. 90 degrees out of phase; - - //init chorus delay position - //right now chorus delay is a compile-time value, as is sample rate - pChorusData->chorusTapPosition = (EAS_I16)((CHORUS_DELAY_MS * _OUTPUT_SAMPLE_RATE)/1000); - - //now copy from the new preset into Chorus - pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; - - pChorusData->m_nLevel = pPreset->m_nLevel; - pChorusData->m_nRate = pPreset->m_nRate; - pChorusData->m_nDepth = pPreset->m_nDepth; - - pChorusData->m_nRate = (EAS_I16) - ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); - - /*lint -e{704} use shift for performance */ - pChorusData->m_nDepth = (EAS_I16) - (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); - - *pInstData = pChorusData; - - return EAS_SUCCESS; -} /* end ChorusInit */ - -/*---------------------------------------------------------------------------- - * WeightedTap() - *---------------------------------------------------------------------------- - * Purpose: Does fractional array look-up using linear interpolation - * - * first convert indexDesired to actual desired index by taking into account indexReference - * then do linear interpolation between two actual samples using fractional part - * - * Inputs: - * array: pointer to array of signed 16 bit values, typically either PCM data or control data - * indexReference: the circular buffer relative offset - * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) - * indexLimit: the total size of the array, used to compute buffer wrap - * - * Outputs: - * Value from the input array, linearly interpolated between two actual data values - * - *---------------------------------------------------------------------------- -*/ -static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit) -{ - EAS_I16 index; - EAS_I16 fraction; - EAS_I16 val1; - EAS_I16 val2; - - //separate indexDesired into whole and fractional parts - /*lint -e{704} use shift for performance */ - index = (EAS_I16)(indexDesired >> 16); - /*lint -e{704} use shift for performance */ - fraction = (EAS_I16)((indexDesired>>1) & 0x07FFF); //just use 15 bits of fractional part - - //adjust whole part by indexReference - index = indexReference - index; - //make sure we stay within array bounds, this implements circular buffer - while (index < 0) - { - index += indexLimit; - } - - //get two adjacent values from the array - val1 = array[index]; - - //handle special case when index == 0, else typical case - if (index == 0) - { - val2 = array[indexLimit-1]; //get last value from array - } - else - { - val2 = array[index-1]; //get previous value from array - } - - //compute linear interpolation as (val1 + ((val2-val1)*fraction)) - return(val1 + (EAS_I16)MULT_EG1_EG1(val2-val1,fraction)); -} - -/*---------------------------------------------------------------------------- - * ChorusProcess() - *---------------------------------------------------------------------------- - * Purpose: compute the chorus on the input buffer, and mix into output buffer - * - * - * Inputs: - * src: pointer to input buffer of PCM values to be processed - * dst: pointer to output buffer of PCM values we are to sume the result with - * bufSize: the number of sample frames (i.e. stereo samples) in the buffer - * - * Outputs: - * None - * - *---------------------------------------------------------------------------- -*/ -//compute the chorus, and mix into output buffer -static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) -{ - EAS_I32 ix; - EAS_I32 nChannelNumber; - EAS_I16 lfoValueLeft; - EAS_I16 lfoValueRight; - EAS_I32 positionOffsetL; - EAS_I32 positionOffsetR; - EAS_PCM tapL; - EAS_PCM tapR; - EAS_I32 tempValue; - EAS_PCM nInputSample; - EAS_I32 nOutputSample; - EAS_PCM *pIn; - EAS_PCM *pOut; - - S_CHORUS_OBJECT *pChorusData; - - pChorusData = (S_CHORUS_OBJECT*) pInstData; - - //if the chorus is disabled or turned all the way down - if (pChorusData->bypass == EAS_TRUE || pChorusData->m_nLevel == 0) - { - if (pSrc != pDst) - EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); - return; - } - - if (pChorusData->m_nNextChorus != pChorusData->m_nCurrentChorus) - { - ChorusUpdate(pChorusData); - } - - for (nChannelNumber = 0; nChannelNumber < NUM_OUTPUT_CHANNELS; nChannelNumber++) - { - - pIn = pSrc + nChannelNumber; - pOut = pDst + nChannelNumber; - - if(nChannelNumber==0) - { - for (ix = 0; ix < numSamples; ix++) - { - nInputSample = *pIn; - pIn += NUM_OUTPUT_CHANNELS; - - //feed input into chorus delay line - pChorusData->chorusDelayL[pChorusData->chorusIndexL] = nInputSample; - - //compute chorus lfo value using phase as fractional index into chorus shape table - //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number - lfoValueLeft = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoLPhase, CHORUS_SHAPE_SIZE); - - //scale chorus depth by lfo value to get relative fractional sample index - //index is expressed as 32 bit number with 16 bit fractional part - /*lint -e{703} use shift for performance */ - positionOffsetL = pChorusData->m_nDepth * (((EAS_I32)lfoValueLeft) << 1); - - //add fixed chorus delay to get actual fractional sample index - positionOffsetL += ((EAS_I32)pChorusData->chorusTapPosition) << 16; - - //get tap value from chorus delay using fractional sample index - tapL = WeightedTap(pChorusData->chorusDelayL, pChorusData->chorusIndexL, positionOffsetL, CHORUS_L_SIZE); - - //scale by chorus level, then sum with input buffer contents and saturate - tempValue = MULT_EG1_EG1(tapL, pChorusData->m_nLevel); - nOutputSample = SATURATE(tempValue + nInputSample); - - *pOut = (EAS_I16)SATURATE(nOutputSample); - pOut += NUM_OUTPUT_CHANNELS; - - - //increment chorus delay index and make it wrap as needed - //this implements circular buffer - if ((pChorusData->chorusIndexL+=1) >= CHORUS_L_SIZE) - pChorusData->chorusIndexL = 0; - - //increment fractional lfo phase, and make it wrap as needed - pChorusData->lfoLPhase += pChorusData->m_nRate; - while (pChorusData->lfoLPhase >= (CHORUS_SHAPE_SIZE<<16)) - { - pChorusData->lfoLPhase -= (CHORUS_SHAPE_SIZE<<16); - } - } - } - else - { - for (ix = 0; ix < numSamples; ix++) - { - nInputSample = *pIn; - pIn += NUM_OUTPUT_CHANNELS; - - //feed input into chorus delay line - pChorusData->chorusDelayR[pChorusData->chorusIndexR] = nInputSample; - - //compute chorus lfo value using phase as fractional index into chorus shape table - //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number - lfoValueRight = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoRPhase, CHORUS_SHAPE_SIZE); - - //scale chorus depth by lfo value to get relative fractional sample index - //index is expressed as 32 bit number with 16 bit fractional part - /*lint -e{703} use shift for performance */ - positionOffsetR = pChorusData->m_nDepth * (((EAS_I32)lfoValueRight) << 1); - - //add fixed chorus delay to get actual fractional sample index - positionOffsetR += ((EAS_I32)pChorusData->chorusTapPosition) << 16; - - //get tap value from chorus delay using fractional sample index - tapR = WeightedTap(pChorusData->chorusDelayR, pChorusData->chorusIndexR, positionOffsetR, CHORUS_R_SIZE); - - //scale by chorus level, then sum with output buffer contents and saturate - tempValue = MULT_EG1_EG1(tapR, pChorusData->m_nLevel); - nOutputSample = SATURATE(tempValue + nInputSample); - - *pOut = (EAS_I16)SATURATE(nOutputSample); - pOut += NUM_OUTPUT_CHANNELS; - - //increment chorus delay index and make it wrap as needed - //this implements circular buffer - if ((pChorusData->chorusIndexR+=1) >= CHORUS_R_SIZE) - pChorusData->chorusIndexR = 0; - - //increment fractional lfo phase, and make it wrap as needed - pChorusData->lfoRPhase += pChorusData->m_nRate; - while (pChorusData->lfoRPhase >= (CHORUS_SHAPE_SIZE<<16)) - { - pChorusData->lfoRPhase -= (CHORUS_SHAPE_SIZE<<16); - } - } - } - - } -} /* end ChorusProcess */ - - - -/*---------------------------------------------------------------------------- - * ChorusShutdown() - *---------------------------------------------------------------------------- - * Purpose: - * Initializes the Chorus effect. - * - * Inputs: - * pInstData - handle to instance data - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) -{ - /* check Configuration Module for static memory allocation */ - if (!pEASData->staticMemoryModel) - EAS_HWFree(pEASData->hwInstData, pInstData); - return EAS_SUCCESS; -} /* end ChorusShutdown */ - -/*---------------------------------------------------------------------------- - * ChorusGetParam() - *---------------------------------------------------------------------------- - * Purpose: - * Get a Chorus parameter - * - * Inputs: - * pInstData - handle to instance data - * param - parameter index - * *pValue - pointer to variable to hold retrieved value - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) -{ - S_CHORUS_OBJECT *p; - - p = (S_CHORUS_OBJECT*) pInstData; - - switch (param) - { - case EAS_PARAM_CHORUS_BYPASS: - *pValue = (EAS_I32) p->bypass; - break; - case EAS_PARAM_CHORUS_PRESET: - *pValue = (EAS_I8) p->m_nCurrentChorus; - break; - case EAS_PARAM_CHORUS_RATE: - *pValue = (EAS_I32) p->m_nRate; - break; - case EAS_PARAM_CHORUS_DEPTH: - *pValue = (EAS_I32) p->m_nDepth; - break; - case EAS_PARAM_CHORUS_LEVEL: - *pValue = (EAS_I32) p->m_nLevel; - break; - default: - return EAS_ERROR_INVALID_PARAMETER; - } - return EAS_SUCCESS; -} /* end ChorusGetParam */ - - -/*---------------------------------------------------------------------------- - * ChorusSetParam() - *---------------------------------------------------------------------------- - * Purpose: - * Set a Chorus parameter - * - * Inputs: - * pInstData - handle to instance data - * param - parameter index - * *pValue - new paramter value - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) -{ - S_CHORUS_OBJECT *p; - - p = (S_CHORUS_OBJECT*) pInstData; - - switch (param) - { - case EAS_PARAM_CHORUS_BYPASS: - p->bypass = (EAS_BOOL) value; - break; - case EAS_PARAM_CHORUS_PRESET: - if(value!=EAS_PARAM_CHORUS_PRESET1 && value!=EAS_PARAM_CHORUS_PRESET2 && - value!=EAS_PARAM_CHORUS_PRESET3 && value!=EAS_PARAM_CHORUS_PRESET4) - return EAS_ERROR_INVALID_PARAMETER; - p->m_nNextChorus = (EAS_I8)value; - break; - case EAS_PARAM_CHORUS_RATE: - if(valueEAS_CHORUS_RATE_MAX) - return EAS_ERROR_INVALID_PARAMETER; - p->m_nRate = (EAS_I16) value; - break; - case EAS_PARAM_CHORUS_DEPTH: - if(valueEAS_CHORUS_DEPTH_MAX) - return EAS_ERROR_INVALID_PARAMETER; - p->m_nDepth = (EAS_I16) value; - break; - case EAS_PARAM_CHORUS_LEVEL: - if(valueEAS_CHORUS_LEVEL_MAX) - return EAS_ERROR_INVALID_PARAMETER; - p->m_nLevel = (EAS_I16) value; - break; - - default: - return EAS_ERROR_INVALID_PARAMETER; - } - return EAS_SUCCESS; -} /* end ChorusSetParam */ - - -/*---------------------------------------------------------------------------- - * ChorusReadInPresets() - *---------------------------------------------------------------------------- - * Purpose: sets global Chorus preset bank to defaults - * - * Inputs: - * - * Outputs: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData) -{ - - int preset = 0; - int defaultPreset = 0; - - //now init any remaining presets to defaults - for (defaultPreset = preset; defaultPreset < CHORUS_MAX_TYPE; defaultPreset++) - { - S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[defaultPreset]; - if (defaultPreset == 0 || defaultPreset > CHORUS_MAX_TYPE-1) - { - pPreset->m_nDepth = 39; - pPreset->m_nRate = 30; - pPreset->m_nLevel = 32767; - } - else if (defaultPreset == 1) - { - pPreset->m_nDepth = 21; - pPreset->m_nRate = 45; - pPreset->m_nLevel = 25000; - } - else if (defaultPreset == 2) - { - pPreset->m_nDepth = 53; - pPreset->m_nRate = 25; - pPreset->m_nLevel = 32000; - } - else if (defaultPreset == 3) - { - pPreset->m_nDepth = 32; - pPreset->m_nRate = 37; - pPreset->m_nLevel = 29000; - } - } - - return EAS_SUCCESS; -} - - -/*---------------------------------------------------------------------------- - * ChorusUpdate - *---------------------------------------------------------------------------- - * Purpose: - * Update the Chorus preset parameters as required - * - * Inputs: - * - * Outputs: - * - * - * Side Effects: - * - chorus paramters will be changed - * - m_nCurrentRoom := m_nNextRoom - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT *pChorusData) -{ - S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; - - pChorusData->m_nLevel = pPreset->m_nLevel; - pChorusData->m_nRate = pPreset->m_nRate; - pChorusData->m_nDepth = pPreset->m_nDepth; - - pChorusData->m_nRate = (EAS_I16) - ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); - - /*lint -e{704} use shift for performance */ - pChorusData->m_nDepth = (EAS_I16) - (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); - - pChorusData->m_nCurrentChorus = pChorusData->m_nNextChorus; - - return EAS_SUCCESS; - -} /* end ChorusUpdate */ + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 499 $ + * $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_effects.h" +#include "eas_math.h" +#include "eas_chorusdata.h" +#include "eas_chorus.h" +#include "eas_config.h" +#include "eas_host.h" +#include "eas_report.h" + +/* prototypes for effects interface */ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData); +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples); +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); + +/* common effects interface for configuration module */ +const S_EFFECTS_INTERFACE EAS_Chorus = +{ + ChorusInit, + ChorusProcess, + ChorusShutdown, + ChorusGetParam, + ChorusSetParam +}; + + + +//LFO shape table used by the chorus, larger table would sound better +//this is a sine wave, where 32767 = 1.0 +static const EAS_I16 EAS_chorusShape[CHORUS_SHAPE_SIZE] = { + 0, 1608, 3212, 4808, 6393, 7962, 9512, 11309, 12539, 14010, 15446, 16846, 18204, 19519, 20787, 22005, 23170, + 24279, 25329, 26319, 27245, 28105, 28898, 29621, 30273, 30852, 31356, 31785, 32137, 32412, 32609, 32728, + 32767, 32728, 32609, 32412, 32137, 31785, 31356, 30852, 30273, 29621, 28898, 28105, 27245, 26319, 25329, + 24279, 23170, 22005, 20787, 19519, 18204, 16846, 15446, 14010, 12539, 11039, 9512, 7962, 6393, 4808, 3212, + 1608, 0, -1608, -3212, -4808, -6393, -7962, -9512, -11309, -12539, -14010, -15446, -16846, -18204, -19519, + -20787, -22005, -23170, -24279, -25329, -26319, -27245, -28105, -28898, -29621, -30273, -30852, -31356, -31785, + -32137, -32412, -32609, -32728, -32767, -32728, -32609, -32412, -32137, -31785, -31356, -30852, -30273, -29621, + -28898, -28105, -27245, -26319, -25329, -24279, -23170, -22005, -20787, -19519, -18204, -16846, -15446, -14010, + -12539, -11039, -9512, -7962, -6393, -4808, -3212, -1608 +}; + +/*---------------------------------------------------------------------------- + * InitializeChorus() + *---------------------------------------------------------------------------- + * Purpose: Initializes chorus parameters + * + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData) +{ + S_CHORUS_OBJECT *pChorusData; + S_CHORUS_PRESET *pPreset; + EAS_I32 index; + + /* check Configuration Module for data allocation */ + if (pEASData->staticMemoryModel) + pChorusData = EAS_CMEnumFXData(EAS_MODULE_CHORUS); + + /* allocate dynamic memory */ + else + pChorusData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_CHORUS_OBJECT)); + + if (pChorusData == NULL) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Chorus memory\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + + /* clear the structure */ + EAS_HWMemSet(pChorusData, 0, sizeof(S_CHORUS_OBJECT)); + + ChorusReadInPresets(pChorusData); + + /* set some default values */ + pChorusData->bypass = EAS_CHORUS_BYPASS_DEFAULT; + pChorusData->preset = EAS_CHORUS_PRESET_DEFAULT; + pChorusData->m_nLevel = EAS_CHORUS_LEVEL_DEFAULT; + pChorusData->m_nRate = EAS_CHORUS_RATE_DEFAULT; + pChorusData->m_nDepth = EAS_CHORUS_DEPTH_DEFAULT; + + //chorus rate and depth need some massaging from preset value (which is sample rate independent) + + //convert rate from steps of .05 Hz to value which can be used as phase increment, + //with current CHORUS_SHAPE_SIZE and rate limits, this fits into 16 bits + //want to compute ((shapeSize * 65536) * (storedRate/20))/sampleRate; + //computing it as below allows rate steps to be evenly spaced + //uses 32 bit divide, but only once when new value is selected + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + //convert depth from steps of .05 ms, to samples, with 16 bit whole part, discard fraction + //want to compute ((depth * sampleRate)/20000) + //use the following approximation since 105/32 is roughly 65536/20000 + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nLevel = pChorusData->m_nLevel; + + //zero delay memory for chorus + for (index = CHORUS_L_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayL[index] = 0; + } + for (index = CHORUS_R_SIZE - 1; index >= 0; index--) + { + pChorusData->chorusDelayR[index] = 0; + } + + //init delay line index, these are used to implement circular delay buffer + pChorusData->chorusIndexL = 0; + pChorusData->chorusIndexR = 0; + + //init LFO phase + //16 bit whole part, 16 bit fraction + pChorusData->lfoLPhase = 0; + pChorusData->lfoRPhase = (CHORUS_SHAPE_SIZE << 16) >> 2; // 1/4 of total, i.e. 90 degrees out of phase; + + //init chorus delay position + //right now chorus delay is a compile-time value, as is sample rate + pChorusData->chorusTapPosition = (EAS_I16)((CHORUS_DELAY_MS * _OUTPUT_SAMPLE_RATE)/1000); + + //now copy from the new preset into Chorus + pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + *pInstData = pChorusData; + + return EAS_SUCCESS; +} /* end ChorusInit */ + +/*---------------------------------------------------------------------------- + * WeightedTap() + *---------------------------------------------------------------------------- + * Purpose: Does fractional array look-up using linear interpolation + * + * first convert indexDesired to actual desired index by taking into account indexReference + * then do linear interpolation between two actual samples using fractional part + * + * Inputs: + * array: pointer to array of signed 16 bit values, typically either PCM data or control data + * indexReference: the circular buffer relative offset + * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction) + * indexLimit: the total size of the array, used to compute buffer wrap + * + * Outputs: + * Value from the input array, linearly interpolated between two actual data values + * + *---------------------------------------------------------------------------- +*/ +static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit) +{ + EAS_I16 index; + EAS_I16 fraction; + EAS_I16 val1; + EAS_I16 val2; + + //separate indexDesired into whole and fractional parts + /*lint -e{704} use shift for performance */ + index = (EAS_I16)(indexDesired >> 16); + /*lint -e{704} use shift for performance */ + fraction = (EAS_I16)((indexDesired>>1) & 0x07FFF); //just use 15 bits of fractional part + + //adjust whole part by indexReference + index = indexReference - index; + //make sure we stay within array bounds, this implements circular buffer + while (index < 0) + { + index += indexLimit; + } + + //get two adjacent values from the array + val1 = array[index]; + + //handle special case when index == 0, else typical case + if (index == 0) + { + val2 = array[indexLimit-1]; //get last value from array + } + else + { + val2 = array[index-1]; //get previous value from array + } + + //compute linear interpolation as (val1 + ((val2-val1)*fraction)) + return(val1 + (EAS_I16)MULT_EG1_EG1(val2-val1,fraction)); +} + +/*---------------------------------------------------------------------------- + * ChorusProcess() + *---------------------------------------------------------------------------- + * Purpose: compute the chorus on the input buffer, and mix into output buffer + * + * + * Inputs: + * src: pointer to input buffer of PCM values to be processed + * dst: pointer to output buffer of PCM values we are to sume the result with + * bufSize: the number of sample frames (i.e. stereo samples) in the buffer + * + * Outputs: + * None + * + *---------------------------------------------------------------------------- +*/ +//compute the chorus, and mix into output buffer +static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples) +{ + EAS_I32 ix; + EAS_I32 nChannelNumber; + EAS_I16 lfoValueLeft; + EAS_I16 lfoValueRight; + EAS_I32 positionOffsetL; + EAS_I32 positionOffsetR; + EAS_PCM tapL; + EAS_PCM tapR; + EAS_I32 tempValue; + EAS_PCM nInputSample; + EAS_I32 nOutputSample; + EAS_PCM *pIn; + EAS_PCM *pOut; + + S_CHORUS_OBJECT *pChorusData; + + pChorusData = (S_CHORUS_OBJECT*) pInstData; + + //if the chorus is disabled or turned all the way down + if (pChorusData->bypass == EAS_TRUE || pChorusData->m_nLevel == 0) + { + if (pSrc != pDst) + EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM)); + return; + } + + if (pChorusData->m_nNextChorus != pChorusData->m_nCurrentChorus) + { + ChorusUpdate(pChorusData); + } + + for (nChannelNumber = 0; nChannelNumber < NUM_OUTPUT_CHANNELS; nChannelNumber++) + { + + pIn = pSrc + nChannelNumber; + pOut = pDst + nChannelNumber; + + if(nChannelNumber==0) + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayL[pChorusData->chorusIndexL] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueLeft = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoLPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetL = pChorusData->m_nDepth * (((EAS_I32)lfoValueLeft) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetL += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapL = WeightedTap(pChorusData->chorusDelayL, pChorusData->chorusIndexL, positionOffsetL, CHORUS_L_SIZE); + + //scale by chorus level, then sum with input buffer contents and saturate + tempValue = MULT_EG1_EG1(tapL, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexL+=1) >= CHORUS_L_SIZE) + pChorusData->chorusIndexL = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoLPhase += pChorusData->m_nRate; + while (pChorusData->lfoLPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoLPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + else + { + for (ix = 0; ix < numSamples; ix++) + { + nInputSample = *pIn; + pIn += NUM_OUTPUT_CHANNELS; + + //feed input into chorus delay line + pChorusData->chorusDelayR[pChorusData->chorusIndexR] = nInputSample; + + //compute chorus lfo value using phase as fractional index into chorus shape table + //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number + lfoValueRight = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoRPhase, CHORUS_SHAPE_SIZE); + + //scale chorus depth by lfo value to get relative fractional sample index + //index is expressed as 32 bit number with 16 bit fractional part + /*lint -e{703} use shift for performance */ + positionOffsetR = pChorusData->m_nDepth * (((EAS_I32)lfoValueRight) << 1); + + //add fixed chorus delay to get actual fractional sample index + positionOffsetR += ((EAS_I32)pChorusData->chorusTapPosition) << 16; + + //get tap value from chorus delay using fractional sample index + tapR = WeightedTap(pChorusData->chorusDelayR, pChorusData->chorusIndexR, positionOffsetR, CHORUS_R_SIZE); + + //scale by chorus level, then sum with output buffer contents and saturate + tempValue = MULT_EG1_EG1(tapR, pChorusData->m_nLevel); + nOutputSample = SATURATE(tempValue + nInputSample); + + *pOut = (EAS_I16)SATURATE(nOutputSample); + pOut += NUM_OUTPUT_CHANNELS; + + //increment chorus delay index and make it wrap as needed + //this implements circular buffer + if ((pChorusData->chorusIndexR+=1) >= CHORUS_R_SIZE) + pChorusData->chorusIndexR = 0; + + //increment fractional lfo phase, and make it wrap as needed + pChorusData->lfoRPhase += pChorusData->m_nRate; + while (pChorusData->lfoRPhase >= (CHORUS_SHAPE_SIZE<<16)) + { + pChorusData->lfoRPhase -= (CHORUS_SHAPE_SIZE<<16); + } + } + } + + } +} /* end ChorusProcess */ + + + +/*---------------------------------------------------------------------------- + * ChorusShutdown() + *---------------------------------------------------------------------------- + * Purpose: + * Initializes the Chorus effect. + * + * Inputs: + * pInstData - handle to instance data + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData) +{ + /* check Configuration Module for static memory allocation */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pInstData); + return EAS_SUCCESS; +} /* end ChorusShutdown */ + +/*---------------------------------------------------------------------------- + * ChorusGetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Get a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - pointer to variable to hold retrieved value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + *pValue = (EAS_I32) p->bypass; + break; + case EAS_PARAM_CHORUS_PRESET: + *pValue = (EAS_I8) p->m_nCurrentChorus; + break; + case EAS_PARAM_CHORUS_RATE: + *pValue = (EAS_I32) p->m_nRate; + break; + case EAS_PARAM_CHORUS_DEPTH: + *pValue = (EAS_I32) p->m_nDepth; + break; + case EAS_PARAM_CHORUS_LEVEL: + *pValue = (EAS_I32) p->m_nLevel; + break; + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusGetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusSetParam() + *---------------------------------------------------------------------------- + * Purpose: + * Set a Chorus parameter + * + * Inputs: + * pInstData - handle to instance data + * param - parameter index + * *pValue - new paramter value + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_CHORUS_OBJECT *p; + + p = (S_CHORUS_OBJECT*) pInstData; + + switch (param) + { + case EAS_PARAM_CHORUS_BYPASS: + p->bypass = (EAS_BOOL) value; + break; + case EAS_PARAM_CHORUS_PRESET: + if(value!=EAS_PARAM_CHORUS_PRESET1 && value!=EAS_PARAM_CHORUS_PRESET2 && + value!=EAS_PARAM_CHORUS_PRESET3 && value!=EAS_PARAM_CHORUS_PRESET4) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nNextChorus = (EAS_I8)value; + break; + case EAS_PARAM_CHORUS_RATE: + if(valueEAS_CHORUS_RATE_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nRate = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_DEPTH: + if(valueEAS_CHORUS_DEPTH_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nDepth = (EAS_I16) value; + break; + case EAS_PARAM_CHORUS_LEVEL: + if(valueEAS_CHORUS_LEVEL_MAX) + return EAS_ERROR_INVALID_PARAMETER; + p->m_nLevel = (EAS_I16) value; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} /* end ChorusSetParam */ + + +/*---------------------------------------------------------------------------- + * ChorusReadInPresets() + *---------------------------------------------------------------------------- + * Purpose: sets global Chorus preset bank to defaults + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData) +{ + + int preset = 0; + int defaultPreset = 0; + + //now init any remaining presets to defaults + for (defaultPreset = preset; defaultPreset < CHORUS_MAX_TYPE; defaultPreset++) + { + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[defaultPreset]; + if (defaultPreset == 0 || defaultPreset > CHORUS_MAX_TYPE-1) + { + pPreset->m_nDepth = 39; + pPreset->m_nRate = 30; + pPreset->m_nLevel = 32767; + } + else if (defaultPreset == 1) + { + pPreset->m_nDepth = 21; + pPreset->m_nRate = 45; + pPreset->m_nLevel = 25000; + } + else if (defaultPreset == 2) + { + pPreset->m_nDepth = 53; + pPreset->m_nRate = 25; + pPreset->m_nLevel = 32000; + } + else if (defaultPreset == 3) + { + pPreset->m_nDepth = 32; + pPreset->m_nRate = 37; + pPreset->m_nLevel = 29000; + } + } + + return EAS_SUCCESS; +} + + +/*---------------------------------------------------------------------------- + * ChorusUpdate + *---------------------------------------------------------------------------- + * Purpose: + * Update the Chorus preset parameters as required + * + * Inputs: + * + * Outputs: + * + * + * Side Effects: + * - chorus paramters will be changed + * - m_nCurrentRoom := m_nNextRoom + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT *pChorusData) +{ + S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus]; + + pChorusData->m_nLevel = pPreset->m_nLevel; + pChorusData->m_nRate = pPreset->m_nRate; + pChorusData->m_nDepth = pPreset->m_nDepth; + + pChorusData->m_nRate = (EAS_I16) + ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate); + + /*lint -e{704} use shift for performance */ + pChorusData->m_nDepth = (EAS_I16) + (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16); + + pChorusData->m_nCurrentChorus = pChorusData->m_nNextChorus; + + return EAS_SUCCESS; + +} /* end ChorusUpdate */ -- cgit v1.2.3