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