eas_wtsynth.c revision 7df30109963092559d3760c0661a020f9daf1030
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