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