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