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