1 /*----------------------------------------------------------------------------
2  *
3  * File:
4  * eas_wtsynth.c
5  *
6  * Contents and purpose:
7  * Implements the synthesizer functions.
8  *
9  * Copyright Sonic Network Inc. 2004
10 
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  *
23  *----------------------------------------------------------------------------
24  * Revision Control:
25  *   $Revision: 795 $
26  *   $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
27  *----------------------------------------------------------------------------
28 */
29 
30 // includes
31 #include "log/log.h"
32 #include <cutils/log.h>
33 
34 #include "eas_data.h"
35 #include "eas_report.h"
36 #include "eas_host.h"
37 #include "eas_math.h"
38 #include "eas_synth_protos.h"
39 #include "eas_wtsynth.h"
40 #include "eas_pan.h"
41 
42 #ifdef DLS_SYNTHESIZER
43 #include "eas_dlssynth.h"
44 #endif
45 
46 #ifdef _METRICS_ENABLED
47 #include "eas_perf.h"
48 #endif
49 
50 /* local prototypes */
51 static EAS_RESULT WT_Initialize(S_VOICE_MGR *pVoiceMgr);
52 static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
53 static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
54 static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum);
55 static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex);
56 static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples);
57 static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
58 static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents);
59 static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain);
60 static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv);
61 static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv);
62 
63 #ifdef EAS_SPLIT_WT_SYNTH
64 extern EAS_BOOL WTE_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer);
65 extern EAS_BOOL WTE_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain);
66 #endif
67 
68 #ifdef _FILTER_ENABLED
69 static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt);
70 #endif
71 
72 #ifdef _STATS
73 extern double statsPhaseIncrement;
74 extern double statsMaxPhaseIncrement;
75 extern long statsPhaseSampleCount;
76 extern double statsSampleSize;
77 extern long statsSampleCount;
78 #endif
79 
80 /*----------------------------------------------------------------------------
81  * Synthesizer interface
82  *----------------------------------------------------------------------------
83 */
84 
85 const S_SYNTH_INTERFACE wtSynth =
86 {
87     WT_Initialize,
88     WT_StartVoice,
89     WT_UpdateVoice,
90     WT_ReleaseVoice,
91     WT_MuteVoice,
92     WT_SustainPedal,
93     WT_UpdateChannel
94 };
95 
96 #ifdef EAS_SPLIT_WT_SYNTH
97 const S_FRAME_INTERFACE wtFrameInterface =
98 {
99     WTE_StartFrame,
100     WTE_EndFrame
101 };
102 #endif
103 
104 /*----------------------------------------------------------------------------
105  * WT_Initialize()
106  *----------------------------------------------------------------------------
107  * Purpose:
108  *
109  * Inputs:
110  * pVoice - pointer to voice to initialize
111  *
112  * Outputs:
113  *
114  *----------------------------------------------------------------------------
115 */
WT_Initialize(S_VOICE_MGR * pVoiceMgr)116 static EAS_RESULT WT_Initialize (S_VOICE_MGR *pVoiceMgr)
117 {
118     EAS_INT i;
119 
120     for (i = 0; i < NUM_WT_VOICES; i++)
121     {
122 
123         pVoiceMgr->wtVoices[i].artIndex = DEFAULT_ARTICULATION_INDEX;
124 
125         pVoiceMgr->wtVoices[i].eg1State = DEFAULT_EG1_STATE;
126         pVoiceMgr->wtVoices[i].eg1Value = DEFAULT_EG1_VALUE;
127         pVoiceMgr->wtVoices[i].eg1Increment = DEFAULT_EG1_INCREMENT;
128 
129         pVoiceMgr->wtVoices[i].eg2State = DEFAULT_EG2_STATE;
130         pVoiceMgr->wtVoices[i].eg2Value = DEFAULT_EG2_VALUE;
131         pVoiceMgr->wtVoices[i].eg2Increment = DEFAULT_EG2_INCREMENT;
132 
133         /* left and right gain values are needed only if stereo output */
134 #if (NUM_OUTPUT_CHANNELS == 2)
135         pVoiceMgr->wtVoices[i].gainLeft = DEFAULT_VOICE_GAIN;
136         pVoiceMgr->wtVoices[i].gainRight = DEFAULT_VOICE_GAIN;
137 #endif
138 
139         pVoiceMgr->wtVoices[i].phaseFrac = DEFAULT_PHASE_FRAC;
140         pVoiceMgr->wtVoices[i].phaseAccum = DEFAULT_PHASE_INT;
141 
142 #ifdef _FILTER_ENABLED
143         pVoiceMgr->wtVoices[i].filter.z1 = DEFAULT_FILTER_ZERO;
144         pVoiceMgr->wtVoices[i].filter.z2 = DEFAULT_FILTER_ZERO;
145 #endif
146     }
147 
148     return EAS_TRUE;
149 }
150 
151 /*----------------------------------------------------------------------------
152  * WT_ReleaseVoice()
153  *----------------------------------------------------------------------------
154  * Purpose:
155  * The selected voice is being released.
156  *
157  * Inputs:
158  * pEASData - pointer to S_EAS_DATA
159  * pVoice - pointer to voice to release
160  *
161  * Outputs:
162  * None
163  *----------------------------------------------------------------------------
164 */
165 /*lint -esym(715, pVoice) used in some implementations */
WT_ReleaseVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum)166 static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
167 {
168     S_WT_VOICE *pWTVoice;
169     const S_ARTICULATION *pArticulation;
170 
171 #ifdef DLS_SYNTHESIZER
172     if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
173     {
174         DLS_ReleaseVoice(pVoiceMgr, pSynth, pVoice, voiceNum);
175         return;
176     }
177 #endif
178 
179     pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
180     pArticulation = &pSynth->pEAS->pArticulations[pWTVoice->artIndex];
181 
182     /* release EG1 */
183     pWTVoice->eg1State = eEnvelopeStateRelease;
184     pWTVoice->eg1Increment = pArticulation->eg1.releaseTime;
185 
186     /*
187     The spec says we should release EG2, but doing so with the current
188     voicing is causing clicks. This fix will need to be coordinated with
189     a new sound library release
190     */
191 
192     /* release EG2 */
193     pWTVoice->eg2State = eEnvelopeStateRelease;
194     pWTVoice->eg2Increment = pArticulation->eg2.releaseTime;
195 }
196 
197 /*----------------------------------------------------------------------------
198  * WT_MuteVoice()
199  *----------------------------------------------------------------------------
200  * Purpose:
201  * The selected voice is being muted.
202  *
203  * Inputs:
204  * pVoice - pointer to voice to release
205  *
206  * Outputs:
207  * None
208  *----------------------------------------------------------------------------
209 */
210 /*lint -esym(715, pSynth) used in some implementations */
WT_MuteVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum)211 static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
212 {
213 
214 #ifdef DLS_SYNTHESIZER
215     if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
216     {
217         DLS_MuteVoice(pVoiceMgr, pSynth, pVoice, voiceNum);
218         return;
219     }
220 #endif
221 
222     /* clear deferred action flags */
223     pVoice->voiceFlags &=
224         ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF |
225         VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF |
226         VOICE_FLAG_DEFER_MUTE);
227 
228     /* set the envelope state */
229     pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateMuted;
230     pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateMuted;
231 }
232 
233 /*----------------------------------------------------------------------------
234  * WT_SustainPedal()
235  *----------------------------------------------------------------------------
236  * Purpose:
237  * The selected voice is held due to sustain pedal
238  *
239  * Inputs:
240  * pVoice - pointer to voice to sustain
241  *
242  * Outputs:
243  * None
244  *----------------------------------------------------------------------------
245 */
246 /*lint -esym(715, pChannel) used in some implementations */
WT_SustainPedal(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,S_SYNTH_CHANNEL * pChannel,EAS_I32 voiceNum)247 static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum)
248 {
249     S_WT_VOICE *pWTVoice;
250 
251 #ifdef DLS_SYNTHESIZER
252     if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
253     {
254         DLS_SustainPedal(pVoiceMgr, pSynth, pVoice, pChannel, voiceNum);
255         return;
256     }
257 #endif
258 
259     /* don't catch the voice if below the sustain level */
260     pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
261     if (pWTVoice->eg1Value < pSynth->pEAS->pArticulations[pWTVoice->artIndex].eg1.sustainLevel)
262         return;
263 
264     /* sustain flag is set, damper pedal is on */
265     /* defer releasing this note until the damper pedal is off */
266     pWTVoice->eg1State = eEnvelopeStateDecay;
267     pVoice->voiceState = eVoiceStatePlay;
268 
269     /*
270     because sustain pedal is on, this voice
271     should defer releasing its note
272     */
273     pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
274 
275 #ifdef _DEBUG_SYNTH
276     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_SustainPedal: defer note off because sustain pedal is on\n"); */ }
277 #endif
278 }
279 
280 /*----------------------------------------------------------------------------
281  * WT_StartVoice()
282  *----------------------------------------------------------------------------
283  * Purpose:
284  * Assign the region for the given instrument using the midi key number
285  * and the RPN2 (coarse tuning) value. By using RPN2 as part of the
286  * region selection process, we reduce the amount a given sample has
287  * to be transposed by selecting the closest recorded root instead.
288  *
289  * This routine is the second half of SynthAssignRegion().
290  * If the region was successfully found by SynthFindRegionIndex(),
291  * then assign the region's parameters to the voice.
292  *
293  * Setup and initialize the following voice parameters:
294  * m_nRegionIndex
295  *
296  * Inputs:
297  * pVoice - ptr to the voice we have assigned for this channel
298  * nRegionIndex - index of the region
299  * pEASData - pointer to overall EAS data structure
300  *
301  * Outputs:
302  * success - could find and assign the region for this voice's note otherwise
303  * failure - could not find nor assign the region for this voice's note
304  *
305  * Side Effects:
306  * psSynthObject->m_sVoice[].m_nRegionIndex is assigned
307  * psSynthObject->m_sVoice[] parameters are assigned
308  *----------------------------------------------------------------------------
309 */
WT_StartVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum,EAS_U16 regionIndex)310 static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex)
311 {
312     S_WT_VOICE *pWTVoice;
313     const S_WT_REGION *pRegion;
314     const S_ARTICULATION *pArt;
315     S_SYNTH_CHANNEL *pChannel;
316 
317 #if (NUM_OUTPUT_CHANNELS == 2)
318     EAS_INT pan;
319 #endif
320 
321 #ifdef EAS_SPLIT_WT_SYNTH
322     S_WT_CONFIG wtConfig;
323 #endif
324 
325     /* no samples have been synthesized for this note yet */
326     pVoice->regionIndex = regionIndex;
327     pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
328 
329     /* get the articulation index for this region */
330     pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
331     pChannel = &pSynth->channels[pVoice->channel & 15];
332 
333     /* update static channel parameters */
334     if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS)
335         WT_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15);
336 
337 #ifdef DLS_SYNTHESIZER
338     if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
339         return DLS_StartVoice(pVoiceMgr, pSynth, pVoice, voiceNum, regionIndex);
340 #endif
341 
342     pRegion = &(pSynth->pEAS->pWTRegions[regionIndex]);
343     pWTVoice->artIndex = pRegion->artIndex;
344 
345 #ifdef _DEBUG_SYNTH
346     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ }
347 #endif
348 
349     pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex];
350 
351     /* MIDI note on puts this voice into attack state */
352     pWTVoice->eg1State = eEnvelopeStateAttack;
353     pWTVoice->eg1Value = 0;
354     pWTVoice->eg1Increment = pArt->eg1.attackTime;
355     pWTVoice->eg2State = eEnvelopeStateAttack;
356     pWTVoice->eg2Value = 0;
357     pWTVoice->eg2Increment = pArt->eg2.attackTime;
358 
359     /* init the LFO */
360     pWTVoice->modLFO.lfoValue = 0;
361     pWTVoice->modLFO.lfoPhase = -pArt->lfoDelay;
362 
363     pVoice->gain = 0;
364 
365 #if (NUM_OUTPUT_CHANNELS == 2)
366     /*
367     Get the Midi CC10 pan value for this voice's channel
368     convert the pan value to an "angle" representation suitable for
369     our sin, cos calculator. This representation is NOT necessarily the same
370     as the transform in the GM manuals because of our sin, cos calculator.
371     "angle" = (CC10 - 64)/128
372     */
373     pan = (EAS_INT) pSynth->channels[pVoice->channel & 15].pan - 64;
374     pan += pArt->pan;
375     EAS_CalcPanControl(pan, &pWTVoice->gainLeft, &pWTVoice->gainRight);
376 #endif
377 
378 #ifdef _FILTER_ENABLED
379     /* clear out the filter states */
380     pWTVoice->filter.z1 = 0;
381     pWTVoice->filter.z2 = 0;
382 #endif
383 
384     /* if this wave is to be generated using noise generator */
385     if (pRegion->region.keyGroupAndFlags & REGION_FLAG_USE_WAVE_GENERATOR)
386     {
387         pWTVoice->phaseAccum = 4574296;
388         pWTVoice->loopStart = WT_NOISE_GENERATOR;
389         pWTVoice->loopEnd = 4574295;
390     }
391 
392     /* normal sample */
393     else
394     {
395 
396 #ifdef EAS_SPLIT_WT_SYNTH
397         if (voiceNum < NUM_PRIMARY_VOICES)
398             pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex];
399         else
400             pWTVoice->phaseAccum = pSynth->pEAS->pSampleOffsets[pRegion->waveIndex];
401 #else
402         pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex];
403 #endif
404 
405         if (pRegion->region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED)
406         {
407             pWTVoice->loopStart = pWTVoice->phaseAccum + pRegion->loopStart;
408             pWTVoice->loopEnd = pWTVoice->phaseAccum + pRegion->loopEnd - 1;
409         }
410         else
411             pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pEAS->pSampleLen[pRegion->waveIndex] - 1;
412     }
413 
414 #ifdef EAS_SPLIT_WT_SYNTH
415     /* configure off-chip voices */
416     if (voiceNum >= NUM_PRIMARY_VOICES)
417     {
418         wtConfig.phaseAccum = pWTVoice->phaseAccum;
419         wtConfig.loopStart = pWTVoice->loopStart;
420         wtConfig.loopEnd = pWTVoice->loopEnd;
421         wtConfig.gain = pVoice->gain;
422 
423 #if (NUM_OUTPUT_CHANNELS == 2)
424         wtConfig.gainLeft = pWTVoice->gainLeft;
425         wtConfig.gainRight = pWTVoice->gainRight;
426 #endif
427 
428         WTE_ConfigVoice(voiceNum - NUM_PRIMARY_VOICES, &wtConfig, pVoiceMgr->pFrameBuffer);
429     }
430 #endif
431 
432     return EAS_SUCCESS;
433 }
434 
435 /*----------------------------------------------------------------------------
436  * WT_CheckSampleEnd
437  *----------------------------------------------------------------------------
438  * Purpose:
439  * Check for end of sample and calculate number of samples to synthesize
440  *
441  * Inputs:
442  *
443  * Outputs:
444  *
445  * Notes:
446  *
447  *----------------------------------------------------------------------------
448 */
WT_CheckSampleEnd(S_WT_VOICE * pWTVoice,S_WT_INT_FRAME * pWTIntFrame,EAS_BOOL update)449 EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update)
450 {
451     EAS_U32 endPhaseAccum;
452     EAS_U32 endPhaseFrac;
453     EAS_I32 numSamples;
454     EAS_BOOL done = EAS_FALSE;
455 
456     /* check to see if we hit the end of the waveform this time */
457     /*lint -e{703} use shift for performance */
458     endPhaseFrac = pWTVoice->phaseFrac + (pWTIntFrame->frame.phaseIncrement << SYNTH_UPDATE_PERIOD_IN_BITS);
459     endPhaseAccum = pWTVoice->phaseAccum + GET_PHASE_INT_PART(endPhaseFrac);
460     if (endPhaseAccum >= pWTVoice->loopEnd)
461     {
462         /* calculate how far current ptr is from end */
463         numSamples = (EAS_I32) (pWTVoice->loopEnd - pWTVoice->phaseAccum);
464 
465         /* now account for the fractional portion */
466         /*lint -e{703} use shift for performance */
467         numSamples = (EAS_I32) ((numSamples << NUM_PHASE_FRAC_BITS) - pWTVoice->phaseFrac);
468         if (pWTIntFrame->frame.phaseIncrement) {
469             pWTIntFrame->numSamples = 1 + (numSamples / pWTIntFrame->frame.phaseIncrement);
470         } else {
471             pWTIntFrame->numSamples = numSamples;
472         }
473         if (pWTIntFrame->numSamples < 0) {
474             ALOGE("b/26366256");
475             android_errorWriteLog(0x534e4554, "26366256");
476             pWTIntFrame->numSamples = 0;
477         }
478 
479         /* sound will be done this frame */
480         done = EAS_TRUE;
481     }
482 
483     /* update data for off-chip synth */
484     if (update)
485     {
486         pWTVoice->phaseFrac = endPhaseFrac;
487         pWTVoice->phaseAccum = endPhaseAccum;
488     }
489 
490     return done;
491 }
492 
493 /*----------------------------------------------------------------------------
494  * WT_UpdateVoice()
495  *----------------------------------------------------------------------------
496  * Purpose:
497  * Synthesize a block of samples for the given voice.
498  * Use linear interpolation.
499  *
500  * Inputs:
501  * pEASData - pointer to overall EAS data structure
502  *
503  * Outputs:
504  * number of samples actually written to buffer
505  *
506  * Side Effects:
507  * - samples are added to the presently free buffer
508  *
509  *----------------------------------------------------------------------------
510 */
WT_UpdateVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum,EAS_I32 * pMixBuffer,EAS_I32 numSamples)511 static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32  numSamples)
512 {
513     S_WT_VOICE *pWTVoice;
514     S_WT_INT_FRAME intFrame;
515     S_SYNTH_CHANNEL *pChannel;
516     const S_WT_REGION *pWTRegion;
517     const S_ARTICULATION *pArt;
518     EAS_I32 temp;
519     EAS_BOOL done;
520 
521 #ifdef DLS_SYNTHESIZER
522     if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
523         return DLS_UpdateVoice(pVoiceMgr, pSynth, pVoice, voiceNum, pMixBuffer, numSamples);
524 #endif
525 
526     /* establish pointers to critical data */
527     pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
528     pWTRegion = &pSynth->pEAS->pWTRegions[pVoice->regionIndex & REGION_INDEX_MASK];
529     pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex];
530     pChannel = &pSynth->channels[pVoice->channel & 15];
531     intFrame.prevGain = pVoice->gain;
532 
533     /* update the envelopes */
534     WT_UpdateEG1(pWTVoice, &pArt->eg1);
535     WT_UpdateEG2(pWTVoice, &pArt->eg2);
536 
537     /* update the LFO */
538     WT_UpdateLFO(&pWTVoice->modLFO, pArt->lfoFreq);
539 
540 #ifdef _FILTER_ENABLED
541     /* calculate filter if library uses filter */
542     if (pSynth->pEAS->libAttr & LIB_FORMAT_FILTER_ENABLED)
543         WT_UpdateFilter(pWTVoice, &intFrame, pArt);
544     else
545         intFrame.frame.k = 0;
546 #endif
547 
548     /* update the gain */
549     intFrame.frame.gainTarget = WT_UpdateGain(pVoice, pWTVoice, pArt, pChannel, pWTRegion->gain);
550 
551     /* calculate base pitch*/
552     temp = pChannel->staticPitch + pWTRegion->tuning;
553 
554     /* include global transpose */
555     if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)
556         temp += pVoice->note * 100;
557     else
558         temp += (pVoice->note + pSynth->globalTranspose) * 100;
559     intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp);
560 
561     /* call into engine to generate samples */
562     intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer;
563     intFrame.pMixBuffer = pMixBuffer;
564     intFrame.numSamples = numSamples;
565 
566     /* check for end of sample */
567     if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd))
568         done = WT_CheckSampleEnd(pWTVoice, &intFrame, (EAS_BOOL) (voiceNum >= NUM_PRIMARY_VOICES));
569     else
570         done = EAS_FALSE;
571 
572     if (intFrame.numSamples < 0) intFrame.numSamples = 0;
573 
574     if (intFrame.numSamples > BUFFER_SIZE_IN_MONO_SAMPLES)
575         intFrame.numSamples = BUFFER_SIZE_IN_MONO_SAMPLES;
576 
577 #ifdef EAS_SPLIT_WT_SYNTH
578     if (voiceNum < NUM_PRIMARY_VOICES)
579     {
580 #ifndef _SPLIT_WT_TEST_HARNESS
581         WT_ProcessVoice(pWTVoice, &intFrame);
582 #endif
583     }
584     else
585         WTE_ProcessVoice(voiceNum - NUM_PRIMARY_VOICES, &intFrame.frame, pVoiceMgr->pFrameBuffer);
586 #else
587     WT_ProcessVoice(pWTVoice, &intFrame);
588 #endif
589 
590     /* clear flag */
591     pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
592 
593     /* if voice has finished, set flag for voice manager */
594     if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted))
595         done = EAS_TRUE;
596 
597     /* if the update interval has elapsed, then force the current gain to the next
598      * gain since we never actually reach the next gain when ramping -- we just get
599      * very close to the target gain.
600      */
601     pVoice->gain = (EAS_I16) intFrame.frame.gainTarget;
602 
603     return done;
604 }
605 
606 /*----------------------------------------------------------------------------
607  * WT_UpdatePhaseInc()
608  *----------------------------------------------------------------------------
609  * Purpose:
610  * Calculate the phase increment
611  *
612  * Inputs:
613  * pVoice - pointer to the voice being updated
614  * psRegion - pointer to the region
615  * psArticulation - pointer to the articulation
616  * nChannelPitchForThisVoice - the portion of the pitch that is fixed for this
617  *                  voice during the duration of this synthesis
618  * pEASData - pointer to overall EAS data structure
619  *
620  * Outputs:
621  *
622  * Side Effects:
623  * set the phase increment for this voice
624  *----------------------------------------------------------------------------
625 */
WT_UpdatePhaseInc(S_WT_VOICE * pWTVoice,const S_ARTICULATION * pArt,S_SYNTH_CHANNEL * pChannel,EAS_I32 pitchCents)626 static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents)
627 {
628     EAS_I32 temp;
629 
630     /*pitchCents due to CC1 = LFO * (CC1 / 128) * DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS */
631     temp = MULT_EG1_EG1(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS,
632         ((pChannel->modWheel) << (NUM_EG1_FRAC_BITS -7)));
633 
634     /* pitchCents due to channel pressure = LFO * (channel pressure / 128) * DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS */
635     temp += MULT_EG1_EG1(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS,
636          ((pChannel->channelPressure) << (NUM_EG1_FRAC_BITS -7)));
637 
638     /* now multiply the (channel pressure + CC1) pitch values by the LFO value */
639     temp = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, temp);
640 
641     /*
642     add in the LFO pitch due to
643     channel pressure and CC1 along with
644     the LFO pitch, the EG2 pitch, and the
645     "static" pitch for this voice on this channel
646     */
647     temp += pitchCents +
648         (MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToPitch)) +
649         (MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToPitch));
650 
651     /* convert from cents to linear phase increment */
652     return EAS_Calculate2toX(temp);
653 }
654 
655 /*----------------------------------------------------------------------------
656  * WT_UpdateChannel()
657  *----------------------------------------------------------------------------
658  * Purpose:
659  * Calculate and assign static channel parameters
660  * These values only need to be updated if one of the controller values
661  * for this channel changes
662  *
663  * Inputs:
664  * nChannel - channel to update
665  * pEASData - pointer to overall EAS data structure
666  *
667  * Outputs:
668  *
669  * Side Effects:
670  * - the given channel's static gain and static pitch are updated
671  *----------------------------------------------------------------------------
672 */
673 /*lint -esym(715, pVoiceMgr) reserved for future use */
WT_UpdateChannel(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel)674 static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
675 {
676     EAS_I32 staticGain;
677     EAS_I32 pitchBend;
678     S_SYNTH_CHANNEL *pChannel;
679 
680     pChannel = &pSynth->channels[channel];
681 
682     /*
683     nChannelGain = (CC7 * CC11)^2  * master volume
684     where CC7 == 100 by default, CC11 == 127, master volume == 32767
685     */
686     staticGain = MULT_EG1_EG1((pChannel->volume) << (NUM_EG1_FRAC_BITS - 7),
687         (pChannel->expression) << (NUM_EG1_FRAC_BITS - 7));
688 
689     /* staticGain has to be squared */
690     staticGain = MULT_EG1_EG1(staticGain, staticGain);
691 
692     pChannel->staticGain = (EAS_I16) MULT_EG1_EG1(staticGain, pSynth->masterVolume);
693 
694     /*
695     calculate pitch bend: RPN0 * ((2*pitch wheel)/16384  -1)
696     However, if we use the EG1 macros, remember that EG1 has a full
697     scale value of 32768 (instead of 16384). So instead of multiplying
698     by 2, multiply by 4 (left shift by 2), and subtract by 32768 instead
699     of 16384. This utilizes the fact that the EG1 macro places a binary
700     point 15 places to the left instead of 14 places.
701     */
702     /*lint -e{703} <avoid multiply for performance>*/
703     pitchBend =
704         (((EAS_I32)(pChannel->pitchBend) << 2)
705         - 32768);
706 
707     pChannel->staticPitch =
708         MULT_EG1_EG1(pitchBend, pChannel->pitchBendSensitivity);
709 
710     /* if this is not a drum channel, then add in the per-channel tuning */
711     if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL))
712         pChannel->staticPitch += pChannel->finePitch + (pChannel->coarsePitch * 100);
713 
714     /* clear update flag */
715     pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
716     return;
717 }
718 
719 /*----------------------------------------------------------------------------
720  * WT_UpdateGain()
721  *----------------------------------------------------------------------------
722  * Purpose:
723  * Calculate and assign static voice parameters as part of WT_UpdateVoice()
724  *
725  * Inputs:
726  * pVoice - ptr to the synth voice that we want to synthesize
727  * pEASData - pointer to overall EAS data structure
728  *
729  * Outputs:
730  *
731  * Side Effects:
732  * - various voice parameters are calculated and assigned
733  *
734  *----------------------------------------------------------------------------
735 */
WT_UpdateGain(S_SYNTH_VOICE * pVoice,S_WT_VOICE * pWTVoice,const S_ARTICULATION * pArt,S_SYNTH_CHANNEL * pChannel,EAS_I32 gain)736 static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain)
737 {
738     EAS_I32 lfoGain;
739     EAS_I32 temp;
740 
741     /*
742     If this voice was stolen, then the velocity is actually
743     for the new note, not the note that we are currently ramping down.
744     So we really shouldn't use this velocity. However, that would require
745     more memory to store the velocity value, and the improvement may
746     not be sufficient to warrant the added memory.
747     */
748     /* velocity is fixed at note start for a given voice and must be squared */
749     temp = (pVoice->velocity) << (NUM_EG1_FRAC_BITS - 7);
750     temp = MULT_EG1_EG1(temp, temp);
751 
752     /* region gain is fixed as part of the articulation */
753     temp = MULT_EG1_EG1(temp, gain);
754 
755     /* include the channel gain */
756     temp = MULT_EG1_EG1(temp, pChannel->staticGain);
757 
758     /* calculate LFO gain using an approximation for 10^x */
759     lfoGain = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToGain);
760     lfoGain = MULT_EG1_EG1(lfoGain, LFO_GAIN_TO_CENTS);
761 
762     /* convert from a dB-like value to linear gain */
763     lfoGain = EAS_Calculate2toX(lfoGain);
764     temp = MULT_EG1_EG1(temp, lfoGain);
765 
766     /* calculate the voice's gain */
767     temp = (EAS_I16)MULT_EG1_EG1(temp, pWTVoice->eg1Value);
768 
769     return temp;
770 }
771 
772 /*----------------------------------------------------------------------------
773  * WT_UpdateEG1()
774  *----------------------------------------------------------------------------
775  * Purpose:
776  * Calculate the EG1 envelope for the given voice (but do not update any
777  * state)
778  *
779  * Inputs:
780  * pVoice - ptr to the voice whose envelope we want to update
781  * nVoice - this voice's number - used only for debug
782  * pEASData - pointer to overall EAS data structure
783  *
784  * Outputs:
785  * nValue - the envelope value
786  *
787  * Side Effects:
788  * - updates EG1 state value for the given voice
789  *----------------------------------------------------------------------------
790 */
WT_UpdateEG1(S_WT_VOICE * pWTVoice,const S_ENVELOPE * pEnv)791 static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv)
792 {
793     EAS_I32 temp;
794 
795     switch (pWTVoice->eg1State)
796     {
797         case eEnvelopeStateAttack:
798             temp = pWTVoice->eg1Value + pWTVoice->eg1Increment;
799 
800             /* check if we have reached peak amplitude */
801             if (temp >= SYNTH_FULL_SCALE_EG1_GAIN)
802             {
803                 /* limit the volume */
804                 temp = SYNTH_FULL_SCALE_EG1_GAIN;
805 
806                 /* prepare to move to decay state */
807                 pWTVoice->eg1State = eEnvelopeStateDecay;
808                 pWTVoice->eg1Increment = pEnv->decayTime;
809             }
810 
811             break;
812 
813         /* exponential decay */
814         case eEnvelopeStateDecay:
815             temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment);
816 
817             /* check if we have reached sustain level */
818             if (temp <= pEnv->sustainLevel)
819             {
820                 /* enforce the sustain level */
821                 temp = pEnv->sustainLevel;
822 
823                 /* if sustain level is zero, skip sustain & release the voice */
824                 if (temp > 0)
825                     pWTVoice->eg1State = eEnvelopeStateSustain;
826 
827                 /* move to sustain state */
828                 else
829                     pWTVoice->eg1State = eEnvelopeStateMuted;
830             }
831 
832             break;
833 
834         case eEnvelopeStateSustain:
835             return;
836 
837         case eEnvelopeStateRelease:
838             temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment);
839 
840             /* if we hit zero, this voice isn't contributing any audio */
841             if (temp <= 0)
842             {
843                 temp = 0;
844                 pWTVoice->eg1State = eEnvelopeStateMuted;
845             }
846             break;
847 
848         /* voice is muted, set target to zero */
849         case eEnvelopeStateMuted:
850             temp = 0;
851             break;
852 
853         case eEnvelopeStateInvalid:
854         default:
855             temp = 0;
856 #ifdef  _DEBUG_SYNTH
857             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG1: error, %d is an unrecognized state\n",
858                 pWTVoice->eg1State); */ }
859 #endif
860             break;
861 
862     }
863 
864     pWTVoice->eg1Value = (EAS_I16) temp;
865 }
866 
867 /*----------------------------------------------------------------------------
868  * WT_UpdateEG2()
869  *----------------------------------------------------------------------------
870  * Purpose:
871  * Update the EG2 envelope for the given voice
872  *
873  * Inputs:
874  * pVoice - ptr to the voice whose envelope we want to update
875  * pEASData - pointer to overall EAS data structure
876  *
877  * Outputs:
878  *
879  * Side Effects:
880  * - updates EG2 values for the given voice
881  *----------------------------------------------------------------------------
882 */
883 
WT_UpdateEG2(S_WT_VOICE * pWTVoice,const S_ENVELOPE * pEnv)884 static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv)
885 {
886     EAS_I32 temp;
887 
888     switch (pWTVoice->eg2State)
889     {
890         case eEnvelopeStateAttack:
891             temp = pWTVoice->eg2Value + pWTVoice->eg2Increment;
892 
893             /* check if we have reached peak amplitude */
894             if (temp >= SYNTH_FULL_SCALE_EG1_GAIN)
895             {
896                 /* limit the volume */
897                 temp = SYNTH_FULL_SCALE_EG1_GAIN;
898 
899                 /* prepare to move to decay state */
900                 pWTVoice->eg2State = eEnvelopeStateDecay;
901 
902                 pWTVoice->eg2Increment = pEnv->decayTime;
903             }
904 
905             break;
906 
907             /* implement linear pitch decay in cents */
908         case eEnvelopeStateDecay:
909             temp = pWTVoice->eg2Value -pWTVoice->eg2Increment;
910 
911             /* check if we have reached sustain level */
912             if (temp <= pEnv->sustainLevel)
913             {
914                 /* enforce the sustain level */
915                 temp = pEnv->sustainLevel;
916 
917                 /* prepare to move to sustain state */
918                 pWTVoice->eg2State = eEnvelopeStateSustain;
919             }
920             break;
921 
922         case eEnvelopeStateSustain:
923             return;
924 
925         case eEnvelopeStateRelease:
926             temp = pWTVoice->eg2Value - pWTVoice->eg2Increment;
927 
928             if (temp <= 0)
929             {
930                 temp = 0;
931                 pWTVoice->eg2State = eEnvelopeStateMuted;
932             }
933 
934             break;
935 
936         /* voice is muted, set target to zero */
937         case eEnvelopeStateMuted:
938             temp = 0;
939             break;
940 
941         case eEnvelopeStateInvalid:
942         default:
943             temp = 0;
944 #ifdef  _DEBUG_SYNTH
945             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG2: error, %d is an unrecognized state\n",
946                 pWTVoice->eg2State); */ }
947 #endif
948             break;
949     }
950 
951     pWTVoice->eg2Value = (EAS_I16) temp;
952 }
953 
954 /*----------------------------------------------------------------------------
955  * WT_UpdateLFO ()
956  *----------------------------------------------------------------------------
957  * Purpose:
958  * Calculate the LFO for the given voice
959  *
960  * Inputs:
961  * pLFO         - ptr to the LFO data
962  * phaseInc     - phase increment
963  *
964  * Outputs:
965  *
966  * Side Effects:
967  * - updates LFO values for the given voice
968  *----------------------------------------------------------------------------
969 */
WT_UpdateLFO(S_LFO_CONTROL * pLFO,EAS_I16 phaseInc)970 void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc)
971 {
972 
973     /* To save memory, if m_nPhaseValue is negative, we are in the
974      * delay phase, and m_nPhaseValue represents the time left
975      * in the delay.
976      */
977      if (pLFO->lfoPhase < 0)
978      {
979         pLFO->lfoPhase++;
980         return;
981      }
982 
983     /* calculate LFO output from phase value */
984     /*lint -e{701} Use shift for performance */
985     pLFO->lfoValue = (EAS_I16) (pLFO->lfoPhase << 2);
986     /*lint -e{502} <shortcut to turn sawtooth into triangle wave> */
987     if ((pLFO->lfoPhase > 0x1fff) && (pLFO->lfoPhase < 0x6000))
988         pLFO->lfoValue = ~pLFO->lfoValue;
989 
990     /* update LFO phase */
991     pLFO->lfoPhase = (pLFO->lfoPhase + phaseInc) & 0x7fff;
992 }
993 
994 #ifdef _FILTER_ENABLED
995 /*----------------------------------------------------------------------------
996  * WT_UpdateFilter()
997  *----------------------------------------------------------------------------
998  * Purpose:
999  * Update the Filter parameters
1000  *
1001  * Inputs:
1002  * pVoice - ptr to the voice whose filter we want to update
1003  * pEASData - pointer to overall EAS data structure
1004  *
1005  * Outputs:
1006  *
1007  * Side Effects:
1008  * - updates Filter values for the given voice
1009  *----------------------------------------------------------------------------
1010 */
WT_UpdateFilter(S_WT_VOICE * pWTVoice,S_WT_INT_FRAME * pIntFrame,const S_ARTICULATION * pArt)1011 static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt)
1012 {
1013     EAS_I32 cutoff;
1014 
1015     /* no need to calculate filter coefficients if it is bypassed */
1016     if (pArt->filterCutoff == DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY)
1017     {
1018         pIntFrame->frame.k = 0;
1019         return;
1020     }
1021 
1022     /* determine the dynamic cutoff frequency */
1023     cutoff = MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToFc);
1024     cutoff += pArt->filterCutoff;
1025 
1026     /* subtract the A5 offset and the sampling frequency */
1027     cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS;
1028 
1029     /* limit the cutoff frequency */
1030     if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS)
1031         cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS;
1032     else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS)
1033         cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS;
1034 
1035     WT_SetFilterCoeffs(pIntFrame, cutoff, pArt->filterQ);
1036 }
1037 #endif
1038 
1039 #if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER)
1040 /*----------------------------------------------------------------------------
1041  * coef
1042  *----------------------------------------------------------------------------
1043  * Table of filter coefficients for low-pass filter
1044  *----------------------------------------------------------------------------
1045  *
1046  * polynomial coefficients are based on 8kHz sampling frequency
1047  * filter coef b2 = k2 = k2g0*k^0 + k2g1*k^1*(2^x) + k2g2*k^2*(2^x)
1048  *
1049  *where k2g0, k2g1, k2g2 are from the truncated power series expansion on theta
1050  *(k*2^x = theta, but we incorporate the k along with the k2g0, k2g1, k2g2)
1051  *note: this is a power series in 2^x, not k*2^x
1052  *where k = (2*pi*440)/8kHz == convert octaves to radians
1053  *
1054  *  so actually, the following coefs listed as k2g0, k2g1, k2g2 are really
1055  *  k2g0*k^0 = k2g0
1056  *  k2g1*k^1
1057  *  k2g2*k^2
1058  *
1059  *
1060  * filter coef n1 = numerator = n1g0*k^0 + n1g1*k^1*(2^x) + n1g2*k^2*(2^x) + n1g3*k^3*(2^x)
1061  *
1062  *where n1g0, n1g1, n1g2, n1g3 are from the truncated power series expansion on theta
1063  *(k*2^x = theta, but we incorporate the k along with the n1g0, n1g1, n1g2, n2g3)
1064  *note: this is a power series in 2^x, not k*2^x
1065  *where k = (2*pi*440)/8kHz == convert octaves to radians
1066  *we also include the optimization factor of 0.81
1067  *
1068  *  so actually, the following coefs listed as n1g0, n1g1, n1g2, n2g3 are really
1069  *  n1g0*k^0 = n1g0
1070  *  n1g1*k^1
1071  *  n1g2*k^2
1072  *  n1g3*k^3
1073  *
1074  *  NOTE that n1g0 == n1g1 == 0, always, so we only need to store n1g2 and n1g3
1075  *----------------------------------------------------------------------------
1076 */
1077 
1078 static const EAS_I16 nk1g0 = -32768;
1079 static const EAS_I16 nk1g2 = 1580;
1080 static const EAS_I16 k2g0 = 32767;
1081 
1082 static const EAS_I16 k2g1[] =
1083 {
1084         -11324, /* k2g1[0] = -0.3455751918948761 */
1085         -10387, /* k2g1[1] = -0.3169878073928751 */
1086         -9528,  /* k2g1[2] = -0.29076528753345476 */
1087         -8740,  /* k2g1[3] = -0.2667120011011279 */
1088         -8017,  /* k2g1[4] = -0.24464850028971705 */
1089         -7353,  /* k2g1[5] = -0.22441018194495696 */
1090         -6745,  /* k2g1[6] = -0.20584605955455101 */
1091         -6187,  /* k2g1[7] = -0.18881763682420102 */
1092         -5675,  /* k2g1[8] = -0.1731978744360067 */
1093         -5206,  /* k2g1[9] = -0.15887024228080968 */
1094         -4775,  /* k2g1[10] = -0.14572785009373057 */
1095         -4380,  /* k2g1[11] = -0.13367265000706827 */
1096         -4018,  /* k2g1[12] = -0.1226147050712642 */
1097         -3685,  /* k2g1[13] = -0.11247151828678581 */
1098         -3381,  /* k2g1[14] = -0.10316741714122014 */
1099         -3101,  /* k2g1[15] = -0.0946329890599603 */
1100         -2844,  /* k2g1[16] = -0.08680456355870586 */
1101         -2609,  /* k2g1[17] = -0.07962373723441349 */
1102         -2393,  /* k2g1[18] = -0.07303693805092666 */
1103         -2195,  /* k2g1[19] = -0.06699502566866912 */
1104         -2014,  /* k2g1[20] = -0.06145292483669077 */
1105         -1847,  /* k2g1[21] = -0.056369289112013346 */
1106         -1694,  /* k2g1[22] = -0.05170619239747895 */
1107         -1554,  /* k2g1[23] = -0.04742884599684141 */
1108         -1426,  /* k2g1[24] = -0.043505339076210514 */
1109         -1308,  /* k2g1[25] = -0.03990640059558053 */
1110         -1199,  /* k2g1[26] = -0.03660518093435039 */
1111         -1100,  /* k2g1[27] = -0.03357705158166837 */
1112         -1009,  /* k2g1[28] = -0.030799421397205727 */
1113         -926,   /* k2g1[29] = -0.028251568071585884 */
1114         -849    /* k2g1[30] = -0.025914483529091967 */
1115 };
1116 
1117 static const EAS_I16 k2g2[] =
1118 {
1119         1957,   /* k2g2[0] = 0.059711106626580836 */
1120         1646,   /* k2g2[1] = 0.05024063501786333 */
1121         1385,   /* k2g2[2] = 0.042272226217199664 */
1122         1165,   /* k2g2[3] = 0.03556764576567844 */
1123         981,    /* k2g2[4] = 0.029926444346999134 */
1124         825,    /* k2g2[5] = 0.025179964880280382 */
1125         694,    /* k2g2[6] = 0.02118630011706455 */
1126         584,    /* k2g2[7] = 0.01782604998793514 */
1127         491,    /* k2g2[8] = 0.014998751854573014 */
1128         414,    /* k2g2[9] = 0.012619876941179595 */
1129         348,    /* k2g2[10] = 0.010618303146468736 */
1130         293,    /* k2g2[11] = 0.008934188679954682 */
1131         246,    /* k2g2[12] = 0.007517182949855368 */
1132         207,    /* k2g2[13] = 0.006324921212866403 */
1133         174,    /* k2g2[14] = 0.005321757979794424 */
1134         147,    /* k2g2[15] = 0.004477701309210577 */
1135         123,    /* k2g2[16] = 0.00376751612730811 */
1136         104,    /* k2g2[17] = 0.0031699697655869644 */
1137         87,     /* k2g2[18] = 0.00266719715992703 */
1138         74,     /* k2g2[19] = 0.0022441667321724647 */
1139         62,     /* k2g2[20] = 0.0018882309854916855 */
1140         52,     /* k2g2[21] = 0.0015887483774966232 */
1141         44,     /* k2g2[22] = 0.0013367651661223448 */
1142         37,     /* k2g2[23] = 0.0011247477162958733 */
1143         31,     /* k2g2[24] = 0.0009463572640678758 */
1144         26,     /* k2g2[25] = 0.0007962604042473498 */
1145         22,     /* k2g2[26] = 0.0006699696356181593 */
1146         18,     /* k2g2[27] = 0.0005637091964589207 */
1147         16,     /* k2g2[28] = 0.00047430217920125243 */
1148         13,     /* k2g2[29] = 0.00039907554925166274 */
1149         11      /* k2g2[30] = 0.00033578022828973666 */
1150 };
1151 
1152 static const EAS_I16 n1g2[] =
1153 {
1154         3170,   /* n1g2[0] = 0.0967319927350769 */
1155         3036,   /* n1g2[1] = 0.0926446051254155 */
1156         2908,   /* n1g2[2] = 0.08872992911818503 */
1157         2785,   /* n1g2[3] = 0.08498066682523227 */
1158         2667,   /* n1g2[4] = 0.08138982872895201 */
1159         2554,   /* n1g2[5] = 0.07795072065216213 */
1160         2446,   /* n1g2[6] = 0.0746569312785634 */
1161         2343,   /* n1g2[7] = 0.07150232020051943 */
1162         2244,   /* n1g2[8] = 0.06848100647187474 */
1163         2149,   /* n1g2[9] = 0.06558735764447099 */
1164         2058,   /* n1g2[10] = 0.06281597926792246 */
1165         1971,   /* n1g2[11] = 0.06016170483307614 */
1166         1888,   /* n1g2[12] = 0.05761958614040857 */
1167         1808,   /* n1g2[13] = 0.05518488407540374 */
1168         1732,   /* n1g2[14] = 0.052853059773715245 */
1169         1659,   /* n1g2[15] = 0.05061976615964251 */
1170         1589,   /* n1g2[16] = 0.04848083984214659 */
1171         1521,   /* n1g2[17] = 0.046432293353298 */
1172         1457,   /* n1g2[18] = 0.04447030771468711 */
1173         1396,   /* n1g2[19] = 0.04259122531793907 */
1174         1337,   /* n1g2[20] = 0.040791543106060944 */
1175         1280,   /* n1g2[21] = 0.03906790604290942 */
1176         1226,   /* n1g2[22] = 0.037417100858604564 */
1177         1174,   /* n1g2[23] = 0.035836050059229754 */
1178         1125,   /* n1g2[24] = 0.03432180618965023 */
1179         1077,   /* n1g2[25] = 0.03287154633875494 */
1180         1032,   /* n1g2[26] = 0.03148256687687814 */
1181         988,    /* n1g2[27] = 0.030152278415589925 */
1182         946,    /* n1g2[28] = 0.028878200980459685 */
1183         906,    /* n1g2[29] = 0.02765795938779331 */
1184         868     /* n1g2[30] = 0.02648927881672521 */
1185 };
1186 
1187 static const EAS_I16 n1g3[] =
1188 {
1189         -548,   /* n1g3[0] = -0.016714088475899017 */
1190         -481,   /* n1g3[1] = -0.014683605122742116 */
1191         -423,   /* n1g3[2] = -0.012899791676436092 */
1192         -371,   /* n1g3[3] = -0.01133268185193299 */
1193         -326,   /* n1g3[4] = -0.00995594976868754 */
1194         -287,   /* n1g3[5] = -0.008746467702146129 */
1195         -252,   /* n1g3[6] = -0.00768391756106361 */
1196         -221,   /* n1g3[7] = -0.006750449563854721 */
1197         -194,   /* n1g3[8] = -0.005930382380083576 */
1198         -171,   /* n1g3[9] = -0.005209939699767622 */
1199         -150,   /* n1g3[10] = -0.004577018805123356 */
1200         -132,   /* n1g3[11] = -0.004020987256990177 */
1201         -116,   /* n1g3[12] = -0.003532504280467257 */
1202         -102,   /* n1g3[13] = -0.00310336384922047 */
1203         -89,    /* n1g3[14] = -0.002726356832432369 */
1204         -78,    /* n1g3[15] = -0.002395149888601605 */
1205         -69,    /* n1g3[16] = -0.0021041790717285314 */
1206         -61,    /* n1g3[17] = -0.0018485563625771063 */
1207         -53,    /* n1g3[18] = -0.001623987554831628 */
1208         -47,    /* n1g3[19] = -0.0014267001167177025 */
1209         -41,    /* n1g3[20] = -0.0012533798162347005 */
1210         -36,    /* n1g3[21] = -0.0011011150453668693 */
1211         -32,    /* n1g3[22] = -0.0009673479079754438 */
1212         -28,    /* n1g3[23] = -0.0008498312496971563 */
1213         -24,    /* n1g3[24] = -0.0007465909079943587 */
1214         -21,    /* n1g3[25] = -0.0006558925481952733 */
1215         -19,    /* n1g3[26] = -0.0005762125284029567 */
1216         -17,    /* n1g3[27] = -0.0005062123038325457 */
1217         -15,    /* n1g3[28] = -0.0004447159405951901 */
1218         -13,    /* n1g3[29] = -0.00039069036118270117 */
1219         -11     /* n1g3[30] = -0.00034322798979677605 */
1220 };
1221 
1222 /*----------------------------------------------------------------------------
1223  * WT_SetFilterCoeffs()
1224  *----------------------------------------------------------------------------
1225  * Purpose:
1226  * Update the Filter parameters
1227  *
1228  * Inputs:
1229  * pVoice - ptr to the voice whose filter we want to update
1230  * pEASData - pointer to overall EAS data structure
1231  *
1232  * Outputs:
1233  *
1234  * Side Effects:
1235  * - updates Filter values for the given voice
1236  *----------------------------------------------------------------------------
1237 */
WT_SetFilterCoeffs(S_WT_INT_FRAME * pIntFrame,EAS_I32 cutoff,EAS_I32 resonance)1238 void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance)
1239 {
1240     EAS_I32 temp;
1241 
1242     /*
1243     Convert the cutoff, which has had A5 subtracted, using the 2^x approx
1244     Note, this cutoff is related to theta cutoff by
1245     theta = k * 2^x
1246     We use 2^x and incorporate k in the power series coefs instead
1247     */
1248     cutoff = EAS_Calculate2toX(cutoff);
1249 
1250     /* calculate b2 coef */
1251     temp = k2g1[resonance] + MULT_AUDIO_COEF(cutoff, k2g2[resonance]);
1252     temp = k2g0 + MULT_AUDIO_COEF(cutoff, temp);
1253     pIntFrame->frame.b2 = temp;
1254 
1255     /* calculate b1 coef */
1256     temp = MULT_AUDIO_COEF(cutoff, nk1g2);
1257     temp = nk1g0 + MULT_AUDIO_COEF(cutoff, temp);
1258     temp += MULT_AUDIO_COEF(temp, pIntFrame->frame.b2);
1259     pIntFrame->frame.b1 = temp >> 1;
1260 
1261     /* calculate K coef */
1262     temp = n1g2[resonance] + MULT_AUDIO_COEF(cutoff, n1g3[resonance]);
1263     temp = MULT_AUDIO_COEF(cutoff, temp);
1264     temp = MULT_AUDIO_COEF(cutoff, temp);
1265     pIntFrame->frame.k = temp;
1266 }
1267 #endif
1268 
1269