eas_wtsynth.c revision 56c99cd2c2c1e6ab038dac5fced5b92ccf11ff6c
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        pWTIntFrame->numSamples = 1 + (numSamples / pWTIntFrame->frame.phaseIncrement);
466
467        /* sound will be done this frame */
468        done = EAS_TRUE;
469    }
470
471    /* update data for off-chip synth */
472    if (update)
473    {
474        pWTVoice->phaseFrac = endPhaseFrac;
475        pWTVoice->phaseAccum = endPhaseAccum;
476    }
477
478    return done;
479}
480
481/*----------------------------------------------------------------------------
482 * WT_UpdateVoice()
483 *----------------------------------------------------------------------------
484 * Purpose:
485 * Synthesize a block of samples for the given voice.
486 * Use linear interpolation.
487 *
488 * Inputs:
489 * pEASData - pointer to overall EAS data structure
490 *
491 * Outputs:
492 * number of samples actually written to buffer
493 *
494 * Side Effects:
495 * - samples are added to the presently free buffer
496 *
497 *----------------------------------------------------------------------------
498*/
499static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32  numSamples)
500{
501    S_WT_VOICE *pWTVoice;
502    S_WT_INT_FRAME intFrame;
503    S_SYNTH_CHANNEL *pChannel;
504    const S_WT_REGION *pWTRegion;
505    const S_ARTICULATION *pArt;
506    EAS_I32 temp;
507    EAS_BOOL done;
508
509#ifdef DLS_SYNTHESIZER
510    if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
511        return DLS_UpdateVoice(pVoiceMgr, pSynth, pVoice, voiceNum, pMixBuffer, numSamples);
512#endif
513
514    /* establish pointers to critical data */
515    pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
516    pWTRegion = &pSynth->pEAS->pWTRegions[pVoice->regionIndex & REGION_INDEX_MASK];
517    pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex];
518    pChannel = &pSynth->channels[pVoice->channel & 15];
519    intFrame.prevGain = pVoice->gain;
520
521    /* update the envelopes */
522    WT_UpdateEG1(pWTVoice, &pArt->eg1);
523    WT_UpdateEG2(pWTVoice, &pArt->eg2);
524
525    /* update the LFO */
526    WT_UpdateLFO(&pWTVoice->modLFO, pArt->lfoFreq);
527
528#ifdef _FILTER_ENABLED
529    /* calculate filter if library uses filter */
530    if (pSynth->pEAS->libAttr & LIB_FORMAT_FILTER_ENABLED)
531        WT_UpdateFilter(pWTVoice, &intFrame, pArt);
532    else
533        intFrame.frame.k = 0;
534#endif
535
536    /* update the gain */
537    intFrame.frame.gainTarget = WT_UpdateGain(pVoice, pWTVoice, pArt, pChannel, pWTRegion->gain);
538
539    /* calculate base pitch*/
540    temp = pChannel->staticPitch + pWTRegion->tuning;
541
542    /* include global transpose */
543    if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)
544        temp += pVoice->note * 100;
545    else
546        temp += (pVoice->note + pSynth->globalTranspose) * 100;
547    intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp);
548
549    /* call into engine to generate samples */
550    intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer;
551    intFrame.pMixBuffer = pMixBuffer;
552    intFrame.numSamples = numSamples;
553
554    /* check for end of sample */
555    if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd))
556        done = WT_CheckSampleEnd(pWTVoice, &intFrame, (EAS_BOOL) (voiceNum >= NUM_PRIMARY_VOICES));
557    else
558        done = EAS_FALSE;
559
560#ifdef EAS_SPLIT_WT_SYNTH
561    if (voiceNum < NUM_PRIMARY_VOICES)
562    {
563#ifndef _SPLIT_WT_TEST_HARNESS
564        WT_ProcessVoice(pWTVoice, &intFrame);
565#endif
566    }
567    else
568        WTE_ProcessVoice(voiceNum - NUM_PRIMARY_VOICES, &intFrame.frame, pVoiceMgr->pFrameBuffer);
569#else
570    WT_ProcessVoice(pWTVoice, &intFrame);
571#endif
572
573    /* clear flag */
574    pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
575
576    /* if voice has finished, set flag for voice manager */
577    if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted))
578        done = EAS_TRUE;
579
580    /* if the update interval has elapsed, then force the current gain to the next
581     * gain since we never actually reach the next gain when ramping -- we just get
582     * very close to the target gain.
583     */
584    pVoice->gain = (EAS_I16) intFrame.frame.gainTarget;
585
586    return done;
587}
588
589/*----------------------------------------------------------------------------
590 * WT_UpdatePhaseInc()
591 *----------------------------------------------------------------------------
592 * Purpose:
593 * Calculate the phase increment
594 *
595 * Inputs:
596 * pVoice - pointer to the voice being updated
597 * psRegion - pointer to the region
598 * psArticulation - pointer to the articulation
599 * nChannelPitchForThisVoice - the portion of the pitch that is fixed for this
600 *                  voice during the duration of this synthesis
601 * pEASData - pointer to overall EAS data structure
602 *
603 * Outputs:
604 *
605 * Side Effects:
606 * set the phase increment for this voice
607 *----------------------------------------------------------------------------
608*/
609static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents)
610{
611    EAS_I32 temp;
612
613    /*pitchCents due to CC1 = LFO * (CC1 / 128) * DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS */
614    temp = MULT_EG1_EG1(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS,
615        ((pChannel->modWheel) << (NUM_EG1_FRAC_BITS -7)));
616
617    /* pitchCents due to channel pressure = LFO * (channel pressure / 128) * DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS */
618    temp += MULT_EG1_EG1(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS,
619         ((pChannel->channelPressure) << (NUM_EG1_FRAC_BITS -7)));
620
621    /* now multiply the (channel pressure + CC1) pitch values by the LFO value */
622    temp = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, temp);
623
624    /*
625    add in the LFO pitch due to
626    channel pressure and CC1 along with
627    the LFO pitch, the EG2 pitch, and the
628    "static" pitch for this voice on this channel
629    */
630    temp += pitchCents +
631        (MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToPitch)) +
632        (MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToPitch));
633
634    /* convert from cents to linear phase increment */
635    return EAS_Calculate2toX(temp);
636}
637
638/*----------------------------------------------------------------------------
639 * WT_UpdateChannel()
640 *----------------------------------------------------------------------------
641 * Purpose:
642 * Calculate and assign static channel parameters
643 * These values only need to be updated if one of the controller values
644 * for this channel changes
645 *
646 * Inputs:
647 * nChannel - channel to update
648 * pEASData - pointer to overall EAS data structure
649 *
650 * Outputs:
651 *
652 * Side Effects:
653 * - the given channel's static gain and static pitch are updated
654 *----------------------------------------------------------------------------
655*/
656/*lint -esym(715, pVoiceMgr) reserved for future use */
657static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
658{
659    EAS_I32 staticGain;
660    EAS_I32 pitchBend;
661    S_SYNTH_CHANNEL *pChannel;
662
663    pChannel = &pSynth->channels[channel];
664
665    /*
666    nChannelGain = (CC7 * CC11)^2  * master volume
667    where CC7 == 100 by default, CC11 == 127, master volume == 32767
668    */
669    staticGain = MULT_EG1_EG1((pChannel->volume) << (NUM_EG1_FRAC_BITS - 7),
670        (pChannel->expression) << (NUM_EG1_FRAC_BITS - 7));
671
672    /* staticGain has to be squared */
673    staticGain = MULT_EG1_EG1(staticGain, staticGain);
674
675    pChannel->staticGain = (EAS_I16) MULT_EG1_EG1(staticGain, pSynth->masterVolume);
676
677    /*
678    calculate pitch bend: RPN0 * ((2*pitch wheel)/16384  -1)
679    However, if we use the EG1 macros, remember that EG1 has a full
680    scale value of 32768 (instead of 16384). So instead of multiplying
681    by 2, multiply by 4 (left shift by 2), and subtract by 32768 instead
682    of 16384. This utilizes the fact that the EG1 macro places a binary
683    point 15 places to the left instead of 14 places.
684    */
685    /*lint -e{703} <avoid multiply for performance>*/
686    pitchBend =
687        (((EAS_I32)(pChannel->pitchBend) << 2)
688        - 32768);
689
690    pChannel->staticPitch =
691        MULT_EG1_EG1(pitchBend, pChannel->pitchBendSensitivity);
692
693    /* if this is not a drum channel, then add in the per-channel tuning */
694    if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL))
695        pChannel->staticPitch += pChannel->finePitch + (pChannel->coarsePitch * 100);
696
697    /* clear update flag */
698    pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
699    return;
700}
701
702/*----------------------------------------------------------------------------
703 * WT_UpdateGain()
704 *----------------------------------------------------------------------------
705 * Purpose:
706 * Calculate and assign static voice parameters as part of WT_UpdateVoice()
707 *
708 * Inputs:
709 * pVoice - ptr to the synth voice that we want to synthesize
710 * pEASData - pointer to overall EAS data structure
711 *
712 * Outputs:
713 *
714 * Side Effects:
715 * - various voice parameters are calculated and assigned
716 *
717 *----------------------------------------------------------------------------
718*/
719static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain)
720{
721    EAS_I32 lfoGain;
722    EAS_I32 temp;
723
724    /*
725    If this voice was stolen, then the velocity is actually
726    for the new note, not the note that we are currently ramping down.
727    So we really shouldn't use this velocity. However, that would require
728    more memory to store the velocity value, and the improvement may
729    not be sufficient to warrant the added memory.
730    */
731    /* velocity is fixed at note start for a given voice and must be squared */
732    temp = (pVoice->velocity) << (NUM_EG1_FRAC_BITS - 7);
733    temp = MULT_EG1_EG1(temp, temp);
734
735    /* region gain is fixed as part of the articulation */
736    temp = MULT_EG1_EG1(temp, gain);
737
738    /* include the channel gain */
739    temp = MULT_EG1_EG1(temp, pChannel->staticGain);
740
741    /* calculate LFO gain using an approximation for 10^x */
742    lfoGain = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToGain);
743    lfoGain = MULT_EG1_EG1(lfoGain, LFO_GAIN_TO_CENTS);
744
745    /* convert from a dB-like value to linear gain */
746    lfoGain = EAS_Calculate2toX(lfoGain);
747    temp = MULT_EG1_EG1(temp, lfoGain);
748
749    /* calculate the voice's gain */
750    temp = (EAS_I16)MULT_EG1_EG1(temp, pWTVoice->eg1Value);
751
752    return temp;
753}
754
755/*----------------------------------------------------------------------------
756 * WT_UpdateEG1()
757 *----------------------------------------------------------------------------
758 * Purpose:
759 * Calculate the EG1 envelope for the given voice (but do not update any
760 * state)
761 *
762 * Inputs:
763 * pVoice - ptr to the voice whose envelope we want to update
764 * nVoice - this voice's number - used only for debug
765 * pEASData - pointer to overall EAS data structure
766 *
767 * Outputs:
768 * nValue - the envelope value
769 *
770 * Side Effects:
771 * - updates EG1 state value for the given voice
772 *----------------------------------------------------------------------------
773*/
774static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv)
775{
776    EAS_I32 temp;
777
778    switch (pWTVoice->eg1State)
779    {
780        case eEnvelopeStateAttack:
781            temp = pWTVoice->eg1Value + pWTVoice->eg1Increment;
782
783            /* check if we have reached peak amplitude */
784            if (temp >= SYNTH_FULL_SCALE_EG1_GAIN)
785            {
786                /* limit the volume */
787                temp = SYNTH_FULL_SCALE_EG1_GAIN;
788
789                /* prepare to move to decay state */
790                pWTVoice->eg1State = eEnvelopeStateDecay;
791                pWTVoice->eg1Increment = pEnv->decayTime;
792            }
793
794            break;
795
796        /* exponential decay */
797        case eEnvelopeStateDecay:
798            temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment);
799
800            /* check if we have reached sustain level */
801            if (temp <= pEnv->sustainLevel)
802            {
803                /* enforce the sustain level */
804                temp = pEnv->sustainLevel;
805
806                /* if sustain level is zero, skip sustain & release the voice */
807                if (temp > 0)
808                    pWTVoice->eg1State = eEnvelopeStateSustain;
809
810                /* move to sustain state */
811                else
812                    pWTVoice->eg1State = eEnvelopeStateMuted;
813            }
814
815            break;
816
817        case eEnvelopeStateSustain:
818            return;
819
820        case eEnvelopeStateRelease:
821            temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment);
822
823            /* if we hit zero, this voice isn't contributing any audio */
824            if (temp <= 0)
825            {
826                temp = 0;
827                pWTVoice->eg1State = eEnvelopeStateMuted;
828            }
829            break;
830
831        /* voice is muted, set target to zero */
832        case eEnvelopeStateMuted:
833            temp = 0;
834            break;
835
836        case eEnvelopeStateInvalid:
837        default:
838            temp = 0;
839#ifdef  _DEBUG_SYNTH
840            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG1: error, %d is an unrecognized state\n",
841                pWTVoice->eg1State); */ }
842#endif
843            break;
844
845    }
846
847    pWTVoice->eg1Value = (EAS_I16) temp;
848}
849
850/*----------------------------------------------------------------------------
851 * WT_UpdateEG2()
852 *----------------------------------------------------------------------------
853 * Purpose:
854 * Update the EG2 envelope for the given voice
855 *
856 * Inputs:
857 * pVoice - ptr to the voice whose envelope we want to update
858 * pEASData - pointer to overall EAS data structure
859 *
860 * Outputs:
861 *
862 * Side Effects:
863 * - updates EG2 values for the given voice
864 *----------------------------------------------------------------------------
865*/
866
867static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv)
868{
869    EAS_I32 temp;
870
871    switch (pWTVoice->eg2State)
872    {
873        case eEnvelopeStateAttack:
874            temp = pWTVoice->eg2Value + pWTVoice->eg2Increment;
875
876            /* check if we have reached peak amplitude */
877            if (temp >= SYNTH_FULL_SCALE_EG1_GAIN)
878            {
879                /* limit the volume */
880                temp = SYNTH_FULL_SCALE_EG1_GAIN;
881
882                /* prepare to move to decay state */
883                pWTVoice->eg2State = eEnvelopeStateDecay;
884
885                pWTVoice->eg2Increment = pEnv->decayTime;
886            }
887
888            break;
889
890            /* implement linear pitch decay in cents */
891        case eEnvelopeStateDecay:
892            temp = pWTVoice->eg2Value -pWTVoice->eg2Increment;
893
894            /* check if we have reached sustain level */
895            if (temp <= pEnv->sustainLevel)
896            {
897                /* enforce the sustain level */
898                temp = pEnv->sustainLevel;
899
900                /* prepare to move to sustain state */
901                pWTVoice->eg2State = eEnvelopeStateSustain;
902            }
903            break;
904
905        case eEnvelopeStateSustain:
906            return;
907
908        case eEnvelopeStateRelease:
909            temp = pWTVoice->eg2Value - pWTVoice->eg2Increment;
910
911            if (temp <= 0)
912            {
913                temp = 0;
914                pWTVoice->eg2State = eEnvelopeStateMuted;
915            }
916
917            break;
918
919        /* voice is muted, set target to zero */
920        case eEnvelopeStateMuted:
921            temp = 0;
922            break;
923
924        case eEnvelopeStateInvalid:
925        default:
926            temp = 0;
927#ifdef  _DEBUG_SYNTH
928            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG2: error, %d is an unrecognized state\n",
929                pWTVoice->eg2State); */ }
930#endif
931            break;
932    }
933
934    pWTVoice->eg2Value = (EAS_I16) temp;
935}
936
937/*----------------------------------------------------------------------------
938 * WT_UpdateLFO ()
939 *----------------------------------------------------------------------------
940 * Purpose:
941 * Calculate the LFO for the given voice
942 *
943 * Inputs:
944 * pLFO         - ptr to the LFO data
945 * phaseInc     - phase increment
946 *
947 * Outputs:
948 *
949 * Side Effects:
950 * - updates LFO values for the given voice
951 *----------------------------------------------------------------------------
952*/
953void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc)
954{
955
956    /* To save memory, if m_nPhaseValue is negative, we are in the
957     * delay phase, and m_nPhaseValue represents the time left
958     * in the delay.
959     */
960     if (pLFO->lfoPhase < 0)
961     {
962        pLFO->lfoPhase++;
963        return;
964     }
965
966    /* calculate LFO output from phase value */
967    /*lint -e{701} Use shift for performance */
968    pLFO->lfoValue = (EAS_I16) (pLFO->lfoPhase << 2);
969    /*lint -e{502} <shortcut to turn sawtooth into triangle wave> */
970    if ((pLFO->lfoPhase > 0x1fff) && (pLFO->lfoPhase < 0x6000))
971        pLFO->lfoValue = ~pLFO->lfoValue;
972
973    /* update LFO phase */
974    pLFO->lfoPhase = (pLFO->lfoPhase + phaseInc) & 0x7fff;
975}
976
977#ifdef _FILTER_ENABLED
978/*----------------------------------------------------------------------------
979 * WT_UpdateFilter()
980 *----------------------------------------------------------------------------
981 * Purpose:
982 * Update the Filter parameters
983 *
984 * Inputs:
985 * pVoice - ptr to the voice whose filter we want to update
986 * pEASData - pointer to overall EAS data structure
987 *
988 * Outputs:
989 *
990 * Side Effects:
991 * - updates Filter values for the given voice
992 *----------------------------------------------------------------------------
993*/
994static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt)
995{
996    EAS_I32 cutoff;
997
998    /* no need to calculate filter coefficients if it is bypassed */
999    if (pArt->filterCutoff == DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY)
1000    {
1001        pIntFrame->frame.k = 0;
1002        return;
1003    }
1004
1005    /* determine the dynamic cutoff frequency */
1006    cutoff = MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToFc);
1007    cutoff += pArt->filterCutoff;
1008
1009    /* subtract the A5 offset and the sampling frequency */
1010    cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS;
1011
1012    /* limit the cutoff frequency */
1013    if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS)
1014        cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS;
1015    else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS)
1016        cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS;
1017
1018    WT_SetFilterCoeffs(pIntFrame, cutoff, pArt->filterQ);
1019}
1020#endif
1021
1022#if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER)
1023/*----------------------------------------------------------------------------
1024 * coef
1025 *----------------------------------------------------------------------------
1026 * Table of filter coefficients for low-pass filter
1027 *----------------------------------------------------------------------------
1028 *
1029 * polynomial coefficients are based on 8kHz sampling frequency
1030 * filter coef b2 = k2 = k2g0*k^0 + k2g1*k^1*(2^x) + k2g2*k^2*(2^x)
1031 *
1032 *where k2g0, k2g1, k2g2 are from the truncated power series expansion on theta
1033 *(k*2^x = theta, but we incorporate the k along with the k2g0, k2g1, k2g2)
1034 *note: this is a power series in 2^x, not k*2^x
1035 *where k = (2*pi*440)/8kHz == convert octaves to radians
1036 *
1037 *  so actually, the following coefs listed as k2g0, k2g1, k2g2 are really
1038 *  k2g0*k^0 = k2g0
1039 *  k2g1*k^1
1040 *  k2g2*k^2
1041 *
1042 *
1043 * filter coef n1 = numerator = n1g0*k^0 + n1g1*k^1*(2^x) + n1g2*k^2*(2^x) + n1g3*k^3*(2^x)
1044 *
1045 *where n1g0, n1g1, n1g2, n1g3 are from the truncated power series expansion on theta
1046 *(k*2^x = theta, but we incorporate the k along with the n1g0, n1g1, n1g2, n2g3)
1047 *note: this is a power series in 2^x, not k*2^x
1048 *where k = (2*pi*440)/8kHz == convert octaves to radians
1049 *we also include the optimization factor of 0.81
1050 *
1051 *  so actually, the following coefs listed as n1g0, n1g1, n1g2, n2g3 are really
1052 *  n1g0*k^0 = n1g0
1053 *  n1g1*k^1
1054 *  n1g2*k^2
1055 *  n1g3*k^3
1056 *
1057 *  NOTE that n1g0 == n1g1 == 0, always, so we only need to store n1g2 and n1g3
1058 *----------------------------------------------------------------------------
1059*/
1060
1061static const EAS_I16 nk1g0 = -32768;
1062static const EAS_I16 nk1g2 = 1580;
1063static const EAS_I16 k2g0 = 32767;
1064
1065static const EAS_I16 k2g1[] =
1066{
1067        -11324, /* k2g1[0] = -0.3455751918948761 */
1068        -10387, /* k2g1[1] = -0.3169878073928751 */
1069        -9528,  /* k2g1[2] = -0.29076528753345476 */
1070        -8740,  /* k2g1[3] = -0.2667120011011279 */
1071        -8017,  /* k2g1[4] = -0.24464850028971705 */
1072        -7353,  /* k2g1[5] = -0.22441018194495696 */
1073        -6745,  /* k2g1[6] = -0.20584605955455101 */
1074        -6187,  /* k2g1[7] = -0.18881763682420102 */
1075        -5675,  /* k2g1[8] = -0.1731978744360067 */
1076        -5206,  /* k2g1[9] = -0.15887024228080968 */
1077        -4775,  /* k2g1[10] = -0.14572785009373057 */
1078        -4380,  /* k2g1[11] = -0.13367265000706827 */
1079        -4018,  /* k2g1[12] = -0.1226147050712642 */
1080        -3685,  /* k2g1[13] = -0.11247151828678581 */
1081        -3381,  /* k2g1[14] = -0.10316741714122014 */
1082        -3101,  /* k2g1[15] = -0.0946329890599603 */
1083        -2844,  /* k2g1[16] = -0.08680456355870586 */
1084        -2609,  /* k2g1[17] = -0.07962373723441349 */
1085        -2393,  /* k2g1[18] = -0.07303693805092666 */
1086        -2195,  /* k2g1[19] = -0.06699502566866912 */
1087        -2014,  /* k2g1[20] = -0.06145292483669077 */
1088        -1847,  /* k2g1[21] = -0.056369289112013346 */
1089        -1694,  /* k2g1[22] = -0.05170619239747895 */
1090        -1554,  /* k2g1[23] = -0.04742884599684141 */
1091        -1426,  /* k2g1[24] = -0.043505339076210514 */
1092        -1308,  /* k2g1[25] = -0.03990640059558053 */
1093        -1199,  /* k2g1[26] = -0.03660518093435039 */
1094        -1100,  /* k2g1[27] = -0.03357705158166837 */
1095        -1009,  /* k2g1[28] = -0.030799421397205727 */
1096        -926,   /* k2g1[29] = -0.028251568071585884 */
1097        -849    /* k2g1[30] = -0.025914483529091967 */
1098};
1099
1100static const EAS_I16 k2g2[] =
1101{
1102        1957,   /* k2g2[0] = 0.059711106626580836 */
1103        1646,   /* k2g2[1] = 0.05024063501786333 */
1104        1385,   /* k2g2[2] = 0.042272226217199664 */
1105        1165,   /* k2g2[3] = 0.03556764576567844 */
1106        981,    /* k2g2[4] = 0.029926444346999134 */
1107        825,    /* k2g2[5] = 0.025179964880280382 */
1108        694,    /* k2g2[6] = 0.02118630011706455 */
1109        584,    /* k2g2[7] = 0.01782604998793514 */
1110        491,    /* k2g2[8] = 0.014998751854573014 */
1111        414,    /* k2g2[9] = 0.012619876941179595 */
1112        348,    /* k2g2[10] = 0.010618303146468736 */
1113        293,    /* k2g2[11] = 0.008934188679954682 */
1114        246,    /* k2g2[12] = 0.007517182949855368 */
1115        207,    /* k2g2[13] = 0.006324921212866403 */
1116        174,    /* k2g2[14] = 0.005321757979794424 */
1117        147,    /* k2g2[15] = 0.004477701309210577 */
1118        123,    /* k2g2[16] = 0.00376751612730811 */
1119        104,    /* k2g2[17] = 0.0031699697655869644 */
1120        87,     /* k2g2[18] = 0.00266719715992703 */
1121        74,     /* k2g2[19] = 0.0022441667321724647 */
1122        62,     /* k2g2[20] = 0.0018882309854916855 */
1123        52,     /* k2g2[21] = 0.0015887483774966232 */
1124        44,     /* k2g2[22] = 0.0013367651661223448 */
1125        37,     /* k2g2[23] = 0.0011247477162958733 */
1126        31,     /* k2g2[24] = 0.0009463572640678758 */
1127        26,     /* k2g2[25] = 0.0007962604042473498 */
1128        22,     /* k2g2[26] = 0.0006699696356181593 */
1129        18,     /* k2g2[27] = 0.0005637091964589207 */
1130        16,     /* k2g2[28] = 0.00047430217920125243 */
1131        13,     /* k2g2[29] = 0.00039907554925166274 */
1132        11      /* k2g2[30] = 0.00033578022828973666 */
1133};
1134
1135static const EAS_I16 n1g2[] =
1136{
1137        3170,   /* n1g2[0] = 0.0967319927350769 */
1138        3036,   /* n1g2[1] = 0.0926446051254155 */
1139        2908,   /* n1g2[2] = 0.08872992911818503 */
1140        2785,   /* n1g2[3] = 0.08498066682523227 */
1141        2667,   /* n1g2[4] = 0.08138982872895201 */
1142        2554,   /* n1g2[5] = 0.07795072065216213 */
1143        2446,   /* n1g2[6] = 0.0746569312785634 */
1144        2343,   /* n1g2[7] = 0.07150232020051943 */
1145        2244,   /* n1g2[8] = 0.06848100647187474 */
1146        2149,   /* n1g2[9] = 0.06558735764447099 */
1147        2058,   /* n1g2[10] = 0.06281597926792246 */
1148        1971,   /* n1g2[11] = 0.06016170483307614 */
1149        1888,   /* n1g2[12] = 0.05761958614040857 */
1150        1808,   /* n1g2[13] = 0.05518488407540374 */
1151        1732,   /* n1g2[14] = 0.052853059773715245 */
1152        1659,   /* n1g2[15] = 0.05061976615964251 */
1153        1589,   /* n1g2[16] = 0.04848083984214659 */
1154        1521,   /* n1g2[17] = 0.046432293353298 */
1155        1457,   /* n1g2[18] = 0.04447030771468711 */
1156        1396,   /* n1g2[19] = 0.04259122531793907 */
1157        1337,   /* n1g2[20] = 0.040791543106060944 */
1158        1280,   /* n1g2[21] = 0.03906790604290942 */
1159        1226,   /* n1g2[22] = 0.037417100858604564 */
1160        1174,   /* n1g2[23] = 0.035836050059229754 */
1161        1125,   /* n1g2[24] = 0.03432180618965023 */
1162        1077,   /* n1g2[25] = 0.03287154633875494 */
1163        1032,   /* n1g2[26] = 0.03148256687687814 */
1164        988,    /* n1g2[27] = 0.030152278415589925 */
1165        946,    /* n1g2[28] = 0.028878200980459685 */
1166        906,    /* n1g2[29] = 0.02765795938779331 */
1167        868     /* n1g2[30] = 0.02648927881672521 */
1168};
1169
1170static const EAS_I16 n1g3[] =
1171{
1172        -548,   /* n1g3[0] = -0.016714088475899017 */
1173        -481,   /* n1g3[1] = -0.014683605122742116 */
1174        -423,   /* n1g3[2] = -0.012899791676436092 */
1175        -371,   /* n1g3[3] = -0.01133268185193299 */
1176        -326,   /* n1g3[4] = -0.00995594976868754 */
1177        -287,   /* n1g3[5] = -0.008746467702146129 */
1178        -252,   /* n1g3[6] = -0.00768391756106361 */
1179        -221,   /* n1g3[7] = -0.006750449563854721 */
1180        -194,   /* n1g3[8] = -0.005930382380083576 */
1181        -171,   /* n1g3[9] = -0.005209939699767622 */
1182        -150,   /* n1g3[10] = -0.004577018805123356 */
1183        -132,   /* n1g3[11] = -0.004020987256990177 */
1184        -116,   /* n1g3[12] = -0.003532504280467257 */
1185        -102,   /* n1g3[13] = -0.00310336384922047 */
1186        -89,    /* n1g3[14] = -0.002726356832432369 */
1187        -78,    /* n1g3[15] = -0.002395149888601605 */
1188        -69,    /* n1g3[16] = -0.0021041790717285314 */
1189        -61,    /* n1g3[17] = -0.0018485563625771063 */
1190        -53,    /* n1g3[18] = -0.001623987554831628 */
1191        -47,    /* n1g3[19] = -0.0014267001167177025 */
1192        -41,    /* n1g3[20] = -0.0012533798162347005 */
1193        -36,    /* n1g3[21] = -0.0011011150453668693 */
1194        -32,    /* n1g3[22] = -0.0009673479079754438 */
1195        -28,    /* n1g3[23] = -0.0008498312496971563 */
1196        -24,    /* n1g3[24] = -0.0007465909079943587 */
1197        -21,    /* n1g3[25] = -0.0006558925481952733 */
1198        -19,    /* n1g3[26] = -0.0005762125284029567 */
1199        -17,    /* n1g3[27] = -0.0005062123038325457 */
1200        -15,    /* n1g3[28] = -0.0004447159405951901 */
1201        -13,    /* n1g3[29] = -0.00039069036118270117 */
1202        -11     /* n1g3[30] = -0.00034322798979677605 */
1203};
1204
1205/*----------------------------------------------------------------------------
1206 * WT_SetFilterCoeffs()
1207 *----------------------------------------------------------------------------
1208 * Purpose:
1209 * Update the Filter parameters
1210 *
1211 * Inputs:
1212 * pVoice - ptr to the voice whose filter we want to update
1213 * pEASData - pointer to overall EAS data structure
1214 *
1215 * Outputs:
1216 *
1217 * Side Effects:
1218 * - updates Filter values for the given voice
1219 *----------------------------------------------------------------------------
1220*/
1221void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance)
1222{
1223    EAS_I32 temp;
1224
1225    /*
1226    Convert the cutoff, which has had A5 subtracted, using the 2^x approx
1227    Note, this cutoff is related to theta cutoff by
1228    theta = k * 2^x
1229    We use 2^x and incorporate k in the power series coefs instead
1230    */
1231    cutoff = EAS_Calculate2toX(cutoff);
1232
1233    /* calculate b2 coef */
1234    temp = k2g1[resonance] + MULT_AUDIO_COEF(cutoff, k2g2[resonance]);
1235    temp = k2g0 + MULT_AUDIO_COEF(cutoff, temp);
1236    pIntFrame->frame.b2 = temp;
1237
1238    /* calculate b1 coef */
1239    temp = MULT_AUDIO_COEF(cutoff, nk1g2);
1240    temp = nk1g0 + MULT_AUDIO_COEF(cutoff, temp);
1241    temp += MULT_AUDIO_COEF(temp, pIntFrame->frame.b2);
1242    pIntFrame->frame.b1 = temp >> 1;
1243
1244    /* calculate K coef */
1245    temp = n1g2[resonance] + MULT_AUDIO_COEF(cutoff, n1g3[resonance]);
1246    temp = MULT_AUDIO_COEF(cutoff, temp);
1247    temp = MULT_AUDIO_COEF(cutoff, temp);
1248    pIntFrame->frame.k = temp;
1249}
1250#endif
1251
1252