• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
48 static EAS_RESULT WT_Initialize(S_VOICE_MGR *pVoiceMgr);
49 static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
50 static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
51 static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum);
52 static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex);
53 static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples);
54 static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
55 static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents);
56 static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain);
57 static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv);
58 static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv);
59 
60 #ifdef EAS_SPLIT_WT_SYNTH
61 extern EAS_BOOL WTE_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer);
62 extern EAS_BOOL WTE_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain);
63 #endif
64 
65 #ifdef _FILTER_ENABLED
66 static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt);
67 #endif
68 
69 #ifdef _STATS
70 extern double statsPhaseIncrement;
71 extern double statsMaxPhaseIncrement;
72 extern long statsPhaseSampleCount;
73 extern double statsSampleSize;
74 extern long statsSampleCount;
75 #endif
76 
77 /*----------------------------------------------------------------------------
78  * Synthesizer interface
79  *----------------------------------------------------------------------------
80 */
81 
82 const 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
94 const 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 */
WT_Initialize(S_VOICE_MGR * pVoiceMgr)113 static 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 */
WT_ReleaseVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum)163 static 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 */
WT_MuteVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum)208 static 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 */
WT_SustainPedal(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,S_SYNTH_CHANNEL * pChannel,EAS_I32 voiceNum)244 static 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 */
WT_StartVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum,EAS_U16 regionIndex)307 static 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 */
WT_CheckSampleEnd(S_WT_VOICE * pWTVoice,S_WT_INT_FRAME * pWTIntFrame,EAS_BOOL update)446 EAS_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 */
WT_UpdateVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum,EAS_I32 * pMixBuffer,EAS_I32 numSamples)503 static EAS_BOOL WT_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32  numSamples)
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 */
WT_UpdatePhaseInc(S_WT_VOICE * pWTVoice,const S_ARTICULATION * pArt,S_SYNTH_CHANNEL * pChannel,EAS_I32 pitchCents)615 static 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 */
WT_UpdateChannel(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel)663 static 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 */
WT_UpdateGain(S_SYNTH_VOICE * pVoice,S_WT_VOICE * pWTVoice,const S_ARTICULATION * pArt,S_SYNTH_CHANNEL * pChannel,EAS_I32 gain)725 static 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 */
WT_UpdateEG1(S_WT_VOICE * pWTVoice,const S_ENVELOPE * pEnv)780 static 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 
WT_UpdateEG2(S_WT_VOICE * pWTVoice,const S_ENVELOPE * pEnv)873 static 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 */
WT_UpdateLFO(S_LFO_CONTROL * pLFO,EAS_I16 phaseInc)959 void 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 */
WT_UpdateFilter(S_WT_VOICE * pWTVoice,S_WT_INT_FRAME * pIntFrame,const S_ARTICULATION * pArt)1000 static 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 
1067 static const EAS_I16 nk1g0 = -32768;
1068 static const EAS_I16 nk1g2 = 1580;
1069 static const EAS_I16 k2g0 = 32767;
1070 
1071 static 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 
1106 static 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 
1141 static 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 
1176 static 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 */
WT_SetFilterCoeffs(S_WT_INT_FRAME * pIntFrame,EAS_I32 cutoff,EAS_I32 resonance)1227 void 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