eas_chorus.c revision a8c89077d78769bf4840fa91609edc51fe2fa02d
1/*----------------------------------------------------------------------------
2 *
3 * File:
4 * eas_chorus.c
5 *
6 * Contents and purpose:
7 * Contains the implementation of the Chorus effect.
8 *
9 *
10 * Copyright Sonic Network Inc. 2006
11
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 *      http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 *----------------------------------------------------------------------------
25 * Revision Control:
26 *   $Revision: 499 $
27 *   $Date: 2006-12-11 16:07:20 -0800 (Mon, 11 Dec 2006) $
28 *----------------------------------------------------------------------------
29*/
30
31#include "eas_data.h"
32#include "eas_effects.h"
33#include "eas_math.h"
34#include "eas_chorusdata.h"
35#include "eas_chorus.h"
36#include "eas_config.h"
37#include "eas_host.h"
38#include "eas_report.h"
39
40/* prototypes for effects interface */
41static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData);
42static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples);
43static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData);
44static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
45static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
46
47/* common effects interface for configuration module */
48const S_EFFECTS_INTERFACE EAS_Chorus =
49{
50    ChorusInit,
51    ChorusProcess,
52    ChorusShutdown,
53    ChorusGetParam,
54    ChorusSetParam
55};
56
57
58
59//LFO shape table used by the chorus, larger table would sound better
60//this is a sine wave, where 32767 = 1.0
61static const EAS_I16 EAS_chorusShape[CHORUS_SHAPE_SIZE] = {
62    0, 1608, 3212, 4808, 6393, 7962, 9512, 11309, 12539, 14010, 15446, 16846, 18204, 19519, 20787, 22005, 23170,
63    24279, 25329, 26319, 27245, 28105, 28898, 29621, 30273, 30852, 31356, 31785, 32137, 32412, 32609, 32728,
64    32767, 32728, 32609, 32412, 32137, 31785, 31356, 30852, 30273, 29621, 28898, 28105, 27245, 26319, 25329,
65    24279, 23170, 22005, 20787, 19519, 18204, 16846, 15446, 14010, 12539, 11039, 9512, 7962, 6393, 4808, 3212,
66    1608, 0, -1608, -3212, -4808, -6393, -7962, -9512, -11309, -12539, -14010, -15446, -16846, -18204, -19519,
67    -20787, -22005, -23170, -24279, -25329, -26319, -27245, -28105, -28898, -29621, -30273, -30852, -31356, -31785,
68    -32137, -32412, -32609, -32728, -32767, -32728, -32609, -32412, -32137, -31785, -31356, -30852, -30273, -29621,
69    -28898, -28105, -27245, -26319, -25329, -24279, -23170, -22005, -20787, -19519, -18204, -16846, -15446, -14010,
70    -12539, -11039, -9512, -7962, -6393, -4808, -3212, -1608
71};
72
73/*----------------------------------------------------------------------------
74 * InitializeChorus()
75 *----------------------------------------------------------------------------
76 * Purpose: Initializes chorus parameters
77 *
78 *
79 * Inputs:
80 *
81 * Outputs:
82 *
83 *----------------------------------------------------------------------------
84*/
85static EAS_RESULT ChorusInit (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR *pInstData)
86{
87    S_CHORUS_OBJECT *pChorusData;
88    S_CHORUS_PRESET *pPreset;
89    EAS_I32 index;
90
91    /* check Configuration Module for data allocation */
92    if (pEASData->staticMemoryModel)
93        pChorusData = EAS_CMEnumFXData(EAS_MODULE_CHORUS);
94
95    /* allocate dynamic memory */
96    else
97        pChorusData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_CHORUS_OBJECT));
98
99    if (pChorusData == NULL)
100    {
101        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate Chorus memory\n"); */ }
102        return EAS_ERROR_MALLOC_FAILED;
103    }
104
105    /* clear the structure */
106    EAS_HWMemSet(pChorusData, 0, sizeof(S_CHORUS_OBJECT));
107
108    ChorusReadInPresets(pChorusData);
109
110    /* set some default values */
111    pChorusData->bypass =       EAS_CHORUS_BYPASS_DEFAULT;
112    pChorusData->preset =       EAS_CHORUS_PRESET_DEFAULT;
113    pChorusData->m_nLevel =     EAS_CHORUS_LEVEL_DEFAULT;
114    pChorusData->m_nRate =      EAS_CHORUS_RATE_DEFAULT;
115    pChorusData->m_nDepth =     EAS_CHORUS_DEPTH_DEFAULT;
116
117    //chorus rate and depth need some massaging from preset value (which is sample rate independent)
118
119    //convert rate from steps of .05 Hz to value which can be used as phase increment,
120    //with current CHORUS_SHAPE_SIZE and rate limits, this fits into 16 bits
121    //want to compute ((shapeSize * 65536) * (storedRate/20))/sampleRate;
122    //computing it as below allows rate steps to be evenly spaced
123    //uses 32 bit divide, but only once when new value is selected
124    pChorusData->m_nRate = (EAS_I16)
125        ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate);
126
127    //convert depth from steps of .05 ms, to samples, with 16 bit whole part, discard fraction
128    //want to compute ((depth * sampleRate)/20000)
129    //use the following approximation since 105/32 is roughly 65536/20000
130    /*lint -e{704} use shift for performance */
131    pChorusData->m_nDepth = (EAS_I16)
132        (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16);
133
134    pChorusData->m_nLevel = pChorusData->m_nLevel;
135
136    //zero delay memory for chorus
137    for (index = CHORUS_L_SIZE - 1; index >= 0; index--)
138    {
139        pChorusData->chorusDelayL[index] = 0;
140    }
141    for (index = CHORUS_R_SIZE - 1; index >= 0; index--)
142    {
143        pChorusData->chorusDelayR[index] = 0;
144    }
145
146    //init delay line index, these are used to implement circular delay buffer
147    pChorusData->chorusIndexL = 0;
148    pChorusData->chorusIndexR = 0;
149
150    //init LFO phase
151    //16 bit whole part, 16 bit fraction
152    pChorusData->lfoLPhase = 0;
153    pChorusData->lfoRPhase = (CHORUS_SHAPE_SIZE << 16) >> 2; // 1/4 of total, i.e. 90 degrees out of phase;
154
155    //init chorus delay position
156    //right now chorus delay is a compile-time value, as is sample rate
157    pChorusData->chorusTapPosition = (EAS_I16)((CHORUS_DELAY_MS * _OUTPUT_SAMPLE_RATE)/1000);
158
159    //now copy from the new preset into Chorus
160    pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus];
161
162    pChorusData->m_nLevel = pPreset->m_nLevel;
163    pChorusData->m_nRate =  pPreset->m_nRate;
164    pChorusData->m_nDepth = pPreset->m_nDepth;
165
166    pChorusData->m_nRate = (EAS_I16)
167        ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate);
168
169    /*lint -e{704} use shift for performance */
170    pChorusData->m_nDepth = (EAS_I16)
171        (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16);
172
173    *pInstData = pChorusData;
174
175    return EAS_SUCCESS;
176} /* end ChorusInit */
177
178/*----------------------------------------------------------------------------
179 * WeightedTap()
180 *----------------------------------------------------------------------------
181 * Purpose: Does fractional array look-up using linear interpolation
182 *
183 * first convert indexDesired to actual desired index by taking into account indexReference
184 * then do linear interpolation between two actual samples using fractional part
185 *
186 * Inputs:
187 * array: pointer to array of signed 16 bit values, typically either PCM data or control data
188 * indexReference: the circular buffer relative offset
189 * indexDesired: the fractional index we are looking up (16 bits index + 16 bits fraction)
190 * indexLimit: the total size of the array, used to compute buffer wrap
191 *
192 * Outputs:
193 * Value from the input array, linearly interpolated between two actual data values
194 *
195 *----------------------------------------------------------------------------
196*/
197static EAS_I16 WeightedTap(const EAS_I16 *array, EAS_I16 indexReference, EAS_I32 indexDesired, EAS_I16 indexLimit)
198{
199    EAS_I16 index;
200    EAS_I16 fraction;
201    EAS_I16 val1;
202    EAS_I16 val2;
203
204    //separate indexDesired into whole and fractional parts
205    /*lint -e{704} use shift for performance */
206    index = (EAS_I16)(indexDesired >> 16);
207    /*lint -e{704} use shift for performance */
208    fraction = (EAS_I16)((indexDesired>>1) & 0x07FFF); //just use 15 bits of fractional part
209
210    //adjust whole part by indexReference
211    index = indexReference - index;
212    //make sure we stay within array bounds, this implements circular buffer
213    while (index < 0)
214    {
215        index += indexLimit;
216    }
217
218    //get two adjacent values from the array
219    val1 = array[index];
220
221    //handle special case when index == 0, else typical case
222    if (index == 0)
223    {
224        val2 = array[indexLimit-1]; //get last value from array
225    }
226    else
227    {
228        val2 = array[index-1]; //get previous value from array
229    }
230
231    //compute linear interpolation as (val1 + ((val2-val1)*fraction))
232    return(val1 + (EAS_I16)MULT_EG1_EG1(val2-val1,fraction));
233}
234
235/*----------------------------------------------------------------------------
236 * ChorusProcess()
237 *----------------------------------------------------------------------------
238 * Purpose: compute the chorus on the input buffer, and mix into output buffer
239 *
240 *
241 * Inputs:
242 * src: pointer to input buffer of PCM values to be processed
243 * dst: pointer to output buffer of PCM values we are to sume the result with
244 * bufSize: the number of sample frames (i.e. stereo samples) in the buffer
245 *
246 * Outputs:
247 * None
248 *
249 *----------------------------------------------------------------------------
250*/
251//compute the chorus, and mix into output buffer
252static void ChorusProcess (EAS_VOID_PTR pInstData, EAS_PCM *pSrc, EAS_PCM *pDst, EAS_I32 numSamples)
253{
254    EAS_I32 ix;
255    EAS_I32 nChannelNumber;
256    EAS_I16 lfoValueLeft;
257    EAS_I16 lfoValueRight;
258    EAS_I32 positionOffsetL;
259    EAS_I32 positionOffsetR;
260    EAS_PCM tapL;
261    EAS_PCM tapR;
262    EAS_I32 tempValue;
263    EAS_PCM nInputSample;
264    EAS_I32 nOutputSample;
265    EAS_PCM *pIn;
266    EAS_PCM *pOut;
267
268    S_CHORUS_OBJECT *pChorusData;
269
270    pChorusData = (S_CHORUS_OBJECT*) pInstData;
271
272    //if the chorus is disabled or turned all the way down
273    if (pChorusData->bypass == EAS_TRUE || pChorusData->m_nLevel == 0)
274    {
275        if (pSrc != pDst)
276            EAS_HWMemCpy(pSrc, pDst, numSamples * NUM_OUTPUT_CHANNELS * (EAS_I32) sizeof(EAS_PCM));
277        return;
278    }
279
280    if (pChorusData->m_nNextChorus != pChorusData->m_nCurrentChorus)
281    {
282        ChorusUpdate(pChorusData);
283    }
284
285    for (nChannelNumber = 0; nChannelNumber < NUM_OUTPUT_CHANNELS; nChannelNumber++)
286    {
287
288        pIn = pSrc + nChannelNumber;
289        pOut = pDst + nChannelNumber;
290
291        if(nChannelNumber==0)
292        {
293            for (ix = 0; ix < numSamples; ix++)
294            {
295                nInputSample = *pIn;
296                pIn += NUM_OUTPUT_CHANNELS;
297
298                //feed input into chorus delay line
299                pChorusData->chorusDelayL[pChorusData->chorusIndexL] = nInputSample;
300
301                //compute chorus lfo value using phase as fractional index into chorus shape table
302                //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number
303                lfoValueLeft = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoLPhase, CHORUS_SHAPE_SIZE);
304
305                //scale chorus depth by lfo value to get relative fractional sample index
306                //index is expressed as 32 bit number with 16 bit fractional part
307                /*lint -e{703} use shift for performance */
308                positionOffsetL = pChorusData->m_nDepth * (((EAS_I32)lfoValueLeft) << 1);
309
310                //add fixed chorus delay to get actual fractional sample index
311                positionOffsetL += ((EAS_I32)pChorusData->chorusTapPosition) << 16;
312
313                //get tap value from chorus delay using fractional sample index
314                tapL = WeightedTap(pChorusData->chorusDelayL, pChorusData->chorusIndexL, positionOffsetL, CHORUS_L_SIZE);
315
316                //scale by chorus level, then sum with input buffer contents and saturate
317                tempValue = MULT_EG1_EG1(tapL, pChorusData->m_nLevel);
318                nOutputSample = SATURATE(tempValue + nInputSample);
319
320                *pOut = (EAS_I16)SATURATE(nOutputSample);
321                pOut += NUM_OUTPUT_CHANNELS;
322
323
324                //increment chorus delay index and make it wrap as needed
325                //this implements circular buffer
326                if ((pChorusData->chorusIndexL+=1) >= CHORUS_L_SIZE)
327                    pChorusData->chorusIndexL = 0;
328
329                //increment fractional lfo phase, and make it wrap as needed
330                pChorusData->lfoLPhase += pChorusData->m_nRate;
331                while (pChorusData->lfoLPhase >= (CHORUS_SHAPE_SIZE<<16))
332                {
333                    pChorusData->lfoLPhase -= (CHORUS_SHAPE_SIZE<<16);
334                }
335            }
336        }
337        else
338        {
339            for (ix = 0; ix < numSamples; ix++)
340            {
341                nInputSample = *pIn;
342                pIn += NUM_OUTPUT_CHANNELS;
343
344                //feed input into chorus delay line
345                pChorusData->chorusDelayR[pChorusData->chorusIndexR] = nInputSample;
346
347                //compute chorus lfo value using phase as fractional index into chorus shape table
348                //resulting value is between -1.0 and 1.0, expressed as signed 16 bit number
349                lfoValueRight = WeightedTap(EAS_chorusShape, 0, pChorusData->lfoRPhase, CHORUS_SHAPE_SIZE);
350
351                //scale chorus depth by lfo value to get relative fractional sample index
352                //index is expressed as 32 bit number with 16 bit fractional part
353                /*lint -e{703} use shift for performance */
354                positionOffsetR = pChorusData->m_nDepth * (((EAS_I32)lfoValueRight) << 1);
355
356                //add fixed chorus delay to get actual fractional sample index
357                positionOffsetR += ((EAS_I32)pChorusData->chorusTapPosition) << 16;
358
359                //get tap value from chorus delay using fractional sample index
360                tapR = WeightedTap(pChorusData->chorusDelayR, pChorusData->chorusIndexR, positionOffsetR, CHORUS_R_SIZE);
361
362                //scale by chorus level, then sum with output buffer contents and saturate
363                tempValue = MULT_EG1_EG1(tapR, pChorusData->m_nLevel);
364                nOutputSample = SATURATE(tempValue + nInputSample);
365
366                *pOut = (EAS_I16)SATURATE(nOutputSample);
367                pOut += NUM_OUTPUT_CHANNELS;
368
369                //increment chorus delay index and make it wrap as needed
370                //this implements circular buffer
371                if ((pChorusData->chorusIndexR+=1) >= CHORUS_R_SIZE)
372                    pChorusData->chorusIndexR = 0;
373
374                //increment fractional lfo phase, and make it wrap as needed
375                pChorusData->lfoRPhase += pChorusData->m_nRate;
376                while (pChorusData->lfoRPhase >= (CHORUS_SHAPE_SIZE<<16))
377                {
378                    pChorusData->lfoRPhase -= (CHORUS_SHAPE_SIZE<<16);
379                }
380            }
381        }
382
383    }
384}  /* end ChorusProcess */
385
386
387
388/*----------------------------------------------------------------------------
389 * ChorusShutdown()
390 *----------------------------------------------------------------------------
391 * Purpose:
392 * Initializes the Chorus effect.
393 *
394 * Inputs:
395 * pInstData        - handle to instance data
396 *
397 * Outputs:
398 *
399 *
400 * Side Effects:
401 *
402 *----------------------------------------------------------------------------
403*/
404static EAS_RESULT ChorusShutdown (EAS_DATA_HANDLE pEASData, EAS_VOID_PTR pInstData)
405{
406    /* check Configuration Module for static memory allocation */
407    if (!pEASData->staticMemoryModel)
408        EAS_HWFree(pEASData->hwInstData, pInstData);
409    return EAS_SUCCESS;
410} /* end ChorusShutdown */
411
412/*----------------------------------------------------------------------------
413 * ChorusGetParam()
414 *----------------------------------------------------------------------------
415 * Purpose:
416 * Get a Chorus parameter
417 *
418 * Inputs:
419 * pInstData        - handle to instance data
420 * param            - parameter index
421 * *pValue          - pointer to variable to hold retrieved value
422 *
423 * Outputs:
424 *
425 *
426 * Side Effects:
427 *
428 *----------------------------------------------------------------------------
429*/
430static EAS_RESULT ChorusGetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
431{
432    S_CHORUS_OBJECT *p;
433
434    p = (S_CHORUS_OBJECT*) pInstData;
435
436    switch (param)
437    {
438        case EAS_PARAM_CHORUS_BYPASS:
439            *pValue = (EAS_I32) p->bypass;
440            break;
441        case EAS_PARAM_CHORUS_PRESET:
442            *pValue = (EAS_I8) p->m_nCurrentChorus;
443            break;
444        case EAS_PARAM_CHORUS_RATE:
445            *pValue = (EAS_I32) p->m_nRate;
446            break;
447        case EAS_PARAM_CHORUS_DEPTH:
448            *pValue = (EAS_I32) p->m_nDepth;
449            break;
450        case EAS_PARAM_CHORUS_LEVEL:
451            *pValue = (EAS_I32) p->m_nLevel;
452            break;
453        default:
454            return EAS_ERROR_INVALID_PARAMETER;
455    }
456    return EAS_SUCCESS;
457} /* end ChorusGetParam */
458
459
460/*----------------------------------------------------------------------------
461 * ChorusSetParam()
462 *----------------------------------------------------------------------------
463 * Purpose:
464 * Set a Chorus parameter
465 *
466 * Inputs:
467 * pInstData        - handle to instance data
468 * param            - parameter index
469 * *pValue          - new paramter value
470 *
471 * Outputs:
472 *
473 *
474 * Side Effects:
475 *
476 *----------------------------------------------------------------------------
477*/
478static EAS_RESULT ChorusSetParam (EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
479{
480    S_CHORUS_OBJECT *p;
481
482    p = (S_CHORUS_OBJECT*) pInstData;
483
484    switch (param)
485    {
486        case EAS_PARAM_CHORUS_BYPASS:
487            p->bypass = (EAS_BOOL) value;
488            break;
489        case EAS_PARAM_CHORUS_PRESET:
490            if(value!=EAS_PARAM_CHORUS_PRESET1 && value!=EAS_PARAM_CHORUS_PRESET2 &&
491                value!=EAS_PARAM_CHORUS_PRESET3 && value!=EAS_PARAM_CHORUS_PRESET4)
492                return EAS_ERROR_INVALID_PARAMETER;
493            p->m_nNextChorus = (EAS_I8)value;
494            break;
495        case EAS_PARAM_CHORUS_RATE:
496            if(value<EAS_CHORUS_RATE_MIN || value>EAS_CHORUS_RATE_MAX)
497                return EAS_ERROR_INVALID_PARAMETER;
498            p->m_nRate = (EAS_I16) value;
499            break;
500        case EAS_PARAM_CHORUS_DEPTH:
501            if(value<EAS_CHORUS_DEPTH_MIN || value>EAS_CHORUS_DEPTH_MAX)
502                return EAS_ERROR_INVALID_PARAMETER;
503            p->m_nDepth = (EAS_I16) value;
504            break;
505        case EAS_PARAM_CHORUS_LEVEL:
506            if(value<EAS_CHORUS_LEVEL_MIN || value>EAS_CHORUS_LEVEL_MAX)
507                return EAS_ERROR_INVALID_PARAMETER;
508            p->m_nLevel = (EAS_I16) value;
509            break;
510
511        default:
512            return EAS_ERROR_INVALID_PARAMETER;
513    }
514    return EAS_SUCCESS;
515} /* end ChorusSetParam */
516
517
518/*----------------------------------------------------------------------------
519 * ChorusReadInPresets()
520 *----------------------------------------------------------------------------
521 * Purpose: sets global Chorus preset bank to defaults
522 *
523 * Inputs:
524 *
525 * Outputs:
526 *
527 *----------------------------------------------------------------------------
528*/
529static EAS_RESULT ChorusReadInPresets(S_CHORUS_OBJECT *pChorusData)
530{
531
532    int preset = 0;
533    int defaultPreset = 0;
534
535    //now init any remaining presets to defaults
536    for (defaultPreset = preset; defaultPreset < CHORUS_MAX_TYPE; defaultPreset++)
537    {
538        S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[defaultPreset];
539        if (defaultPreset == 0 || defaultPreset > CHORUS_MAX_TYPE-1)
540        {
541            pPreset->m_nDepth = 39;
542            pPreset->m_nRate = 30;
543            pPreset->m_nLevel = 32767;
544        }
545        else if (defaultPreset == 1)
546        {
547            pPreset->m_nDepth = 21;
548            pPreset->m_nRate = 45;
549            pPreset->m_nLevel = 25000;
550        }
551        else if (defaultPreset == 2)
552        {
553            pPreset->m_nDepth = 53;
554            pPreset->m_nRate = 25;
555            pPreset->m_nLevel = 32000;
556        }
557        else if (defaultPreset == 3)
558        {
559            pPreset->m_nDepth = 32;
560            pPreset->m_nRate = 37;
561            pPreset->m_nLevel = 29000;
562        }
563    }
564
565    return EAS_SUCCESS;
566}
567
568
569/*----------------------------------------------------------------------------
570 * ChorusUpdate
571 *----------------------------------------------------------------------------
572 * Purpose:
573 * Update the Chorus preset parameters as required
574 *
575 * Inputs:
576 *
577 * Outputs:
578 *
579 *
580 * Side Effects:
581 * - chorus paramters will be changed
582 * - m_nCurrentRoom := m_nNextRoom
583 *----------------------------------------------------------------------------
584*/
585static EAS_RESULT ChorusUpdate(S_CHORUS_OBJECT *pChorusData)
586{
587    S_CHORUS_PRESET *pPreset = &pChorusData->m_sPreset.m_sPreset[pChorusData->m_nNextChorus];
588
589    pChorusData->m_nLevel = pPreset->m_nLevel;
590    pChorusData->m_nRate =  pPreset->m_nRate;
591    pChorusData->m_nDepth = pPreset->m_nDepth;
592
593    pChorusData->m_nRate = (EAS_I16)
594        ((((EAS_I32)CHORUS_SHAPE_SIZE<<16)/(20*(EAS_I32)_OUTPUT_SAMPLE_RATE)) * pChorusData->m_nRate);
595
596    /*lint -e{704} use shift for performance */
597    pChorusData->m_nDepth = (EAS_I16)
598        (((((EAS_I32)pChorusData->m_nDepth * _OUTPUT_SAMPLE_RATE)>>5) * 105) >> 16);
599
600    pChorusData->m_nCurrentChorus = pChorusData->m_nNextChorus;
601
602    return EAS_SUCCESS;
603
604}   /* end ChorusUpdate */
605