| /*---------------------------------------------------------------------------- |
| * |
| * 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. |
| * 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. |
| * |
| *---------------------------------------------------------------------------- |
| * 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(value<EAS_CHORUS_RATE_MIN || value>EAS_CHORUS_RATE_MAX) |
| return EAS_ERROR_INVALID_PARAMETER; |
| p->m_nRate = (EAS_I16) value; |
| break; |
| case EAS_PARAM_CHORUS_DEPTH: |
| if(value<EAS_CHORUS_DEPTH_MIN || value>EAS_CHORUS_DEPTH_MAX) |
| return EAS_ERROR_INVALID_PARAMETER; |
| p->m_nDepth = (EAS_I16) value; |
| break; |
| case EAS_PARAM_CHORUS_LEVEL: |
| if(value<EAS_CHORUS_LEVEL_MIN || value>EAS_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 */ |