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 "log/log.h"
32 #include <cutils/log.h>
33
34 #include "eas_data.h"
35 #include "eas_report.h"
36 #include "eas_host.h"
37 #include "eas_math.h"
38 #include "eas_synth_protos.h"
39 #include "eas_wtsynth.h"
40 #include "eas_pan.h"
41
42 #ifdef DLS_SYNTHESIZER
43 #include "eas_dlssynth.h"
44 #endif
45
46 #ifdef _METRICS_ENABLED
47 #include "eas_perf.h"
48 #endif
49
50 /* local prototypes */
51 static EAS_RESULT WT_Initialize(S_VOICE_MGR *pVoiceMgr);
52 static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
53 static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
54 static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum);
55 static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex);
56 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);
57 static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
58 static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents);
59 static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain);
60 static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv);
61 static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv);
62
63 #ifdef EAS_SPLIT_WT_SYNTH
64 extern EAS_BOOL WTE_StartFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer);
65 extern EAS_BOOL WTE_EndFrame (EAS_FRAME_BUFFER_HANDLE pFrameBuffer, EAS_I32 *pMixBuffer, EAS_I16 masterGain);
66 #endif
67
68 #ifdef _FILTER_ENABLED
69 static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt);
70 #endif
71
72 #ifdef _STATS
73 extern double statsPhaseIncrement;
74 extern double statsMaxPhaseIncrement;
75 extern long statsPhaseSampleCount;
76 extern double statsSampleSize;
77 extern long statsSampleCount;
78 #endif
79
80 /*----------------------------------------------------------------------------
81 * Synthesizer interface
82 *----------------------------------------------------------------------------
83 */
84
85 const S_SYNTH_INTERFACE wtSynth =
86 {
87 WT_Initialize,
88 WT_StartVoice,
89 WT_UpdateVoice,
90 WT_ReleaseVoice,
91 WT_MuteVoice,
92 WT_SustainPedal,
93 WT_UpdateChannel
94 };
95
96 #ifdef EAS_SPLIT_WT_SYNTH
97 const S_FRAME_INTERFACE wtFrameInterface =
98 {
99 WTE_StartFrame,
100 WTE_EndFrame
101 };
102 #endif
103
104 /*----------------------------------------------------------------------------
105 * WT_Initialize()
106 *----------------------------------------------------------------------------
107 * Purpose:
108 *
109 * Inputs:
110 * pVoice - pointer to voice to initialize
111 *
112 * Outputs:
113 *
114 *----------------------------------------------------------------------------
115 */
WT_Initialize(S_VOICE_MGR * pVoiceMgr)116 static EAS_RESULT WT_Initialize (S_VOICE_MGR *pVoiceMgr)
117 {
118 EAS_INT i;
119
120 for (i = 0; i < NUM_WT_VOICES; i++)
121 {
122
123 pVoiceMgr->wtVoices[i].artIndex = DEFAULT_ARTICULATION_INDEX;
124
125 pVoiceMgr->wtVoices[i].eg1State = DEFAULT_EG1_STATE;
126 pVoiceMgr->wtVoices[i].eg1Value = DEFAULT_EG1_VALUE;
127 pVoiceMgr->wtVoices[i].eg1Increment = DEFAULT_EG1_INCREMENT;
128
129 pVoiceMgr->wtVoices[i].eg2State = DEFAULT_EG2_STATE;
130 pVoiceMgr->wtVoices[i].eg2Value = DEFAULT_EG2_VALUE;
131 pVoiceMgr->wtVoices[i].eg2Increment = DEFAULT_EG2_INCREMENT;
132
133 /* left and right gain values are needed only if stereo output */
134 #if (NUM_OUTPUT_CHANNELS == 2)
135 pVoiceMgr->wtVoices[i].gainLeft = DEFAULT_VOICE_GAIN;
136 pVoiceMgr->wtVoices[i].gainRight = DEFAULT_VOICE_GAIN;
137 #endif
138
139 pVoiceMgr->wtVoices[i].phaseFrac = DEFAULT_PHASE_FRAC;
140 pVoiceMgr->wtVoices[i].phaseAccum = DEFAULT_PHASE_INT;
141
142 #ifdef _FILTER_ENABLED
143 pVoiceMgr->wtVoices[i].filter.z1 = DEFAULT_FILTER_ZERO;
144 pVoiceMgr->wtVoices[i].filter.z2 = DEFAULT_FILTER_ZERO;
145 #endif
146 }
147
148 return EAS_TRUE;
149 }
150
151 /*----------------------------------------------------------------------------
152 * WT_ReleaseVoice()
153 *----------------------------------------------------------------------------
154 * Purpose:
155 * The selected voice is being released.
156 *
157 * Inputs:
158 * pEASData - pointer to S_EAS_DATA
159 * pVoice - pointer to voice to release
160 *
161 * Outputs:
162 * None
163 *----------------------------------------------------------------------------
164 */
165 /*lint -esym(715, pVoice) used in some implementations */
WT_ReleaseVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum)166 static void WT_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
167 {
168 S_WT_VOICE *pWTVoice;
169 const S_ARTICULATION *pArticulation;
170
171 #ifdef DLS_SYNTHESIZER
172 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
173 {
174 DLS_ReleaseVoice(pVoiceMgr, pSynth, pVoice, voiceNum);
175 return;
176 }
177 #endif
178
179 pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
180 pArticulation = &pSynth->pEAS->pArticulations[pWTVoice->artIndex];
181
182 /* release EG1 */
183 pWTVoice->eg1State = eEnvelopeStateRelease;
184 pWTVoice->eg1Increment = pArticulation->eg1.releaseTime;
185
186 /*
187 The spec says we should release EG2, but doing so with the current
188 voicing is causing clicks. This fix will need to be coordinated with
189 a new sound library release
190 */
191
192 /* release EG2 */
193 pWTVoice->eg2State = eEnvelopeStateRelease;
194 pWTVoice->eg2Increment = pArticulation->eg2.releaseTime;
195 }
196
197 /*----------------------------------------------------------------------------
198 * WT_MuteVoice()
199 *----------------------------------------------------------------------------
200 * Purpose:
201 * The selected voice is being muted.
202 *
203 * Inputs:
204 * pVoice - pointer to voice to release
205 *
206 * Outputs:
207 * None
208 *----------------------------------------------------------------------------
209 */
210 /*lint -esym(715, pSynth) used in some implementations */
WT_MuteVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum)211 static void WT_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
212 {
213
214 #ifdef DLS_SYNTHESIZER
215 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
216 {
217 DLS_MuteVoice(pVoiceMgr, pSynth, pVoice, voiceNum);
218 return;
219 }
220 #endif
221
222 /* clear deferred action flags */
223 pVoice->voiceFlags &=
224 ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF |
225 VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF |
226 VOICE_FLAG_DEFER_MUTE);
227
228 /* set the envelope state */
229 pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateMuted;
230 pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateMuted;
231 }
232
233 /*----------------------------------------------------------------------------
234 * WT_SustainPedal()
235 *----------------------------------------------------------------------------
236 * Purpose:
237 * The selected voice is held due to sustain pedal
238 *
239 * Inputs:
240 * pVoice - pointer to voice to sustain
241 *
242 * Outputs:
243 * None
244 *----------------------------------------------------------------------------
245 */
246 /*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)247 static void WT_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum)
248 {
249 S_WT_VOICE *pWTVoice;
250
251 #ifdef DLS_SYNTHESIZER
252 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
253 {
254 DLS_SustainPedal(pVoiceMgr, pSynth, pVoice, pChannel, voiceNum);
255 return;
256 }
257 #endif
258
259 /* don't catch the voice if below the sustain level */
260 pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
261 if (pWTVoice->eg1Value < pSynth->pEAS->pArticulations[pWTVoice->artIndex].eg1.sustainLevel)
262 return;
263
264 /* sustain flag is set, damper pedal is on */
265 /* defer releasing this note until the damper pedal is off */
266 pWTVoice->eg1State = eEnvelopeStateDecay;
267 pVoice->voiceState = eVoiceStatePlay;
268
269 /*
270 because sustain pedal is on, this voice
271 should defer releasing its note
272 */
273 pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
274
275 #ifdef _DEBUG_SYNTH
276 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_SustainPedal: defer note off because sustain pedal is on\n"); */ }
277 #endif
278 }
279
280 /*----------------------------------------------------------------------------
281 * WT_StartVoice()
282 *----------------------------------------------------------------------------
283 * Purpose:
284 * Assign the region for the given instrument using the midi key number
285 * and the RPN2 (coarse tuning) value. By using RPN2 as part of the
286 * region selection process, we reduce the amount a given sample has
287 * to be transposed by selecting the closest recorded root instead.
288 *
289 * This routine is the second half of SynthAssignRegion().
290 * If the region was successfully found by SynthFindRegionIndex(),
291 * then assign the region's parameters to the voice.
292 *
293 * Setup and initialize the following voice parameters:
294 * m_nRegionIndex
295 *
296 * Inputs:
297 * pVoice - ptr to the voice we have assigned for this channel
298 * nRegionIndex - index of the region
299 * pEASData - pointer to overall EAS data structure
300 *
301 * Outputs:
302 * success - could find and assign the region for this voice's note otherwise
303 * failure - could not find nor assign the region for this voice's note
304 *
305 * Side Effects:
306 * psSynthObject->m_sVoice[].m_nRegionIndex is assigned
307 * psSynthObject->m_sVoice[] parameters are assigned
308 *----------------------------------------------------------------------------
309 */
WT_StartVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum,EAS_U16 regionIndex)310 static EAS_RESULT WT_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex)
311 {
312 S_WT_VOICE *pWTVoice;
313 const S_WT_REGION *pRegion;
314 const S_ARTICULATION *pArt;
315 S_SYNTH_CHANNEL *pChannel;
316
317 #if (NUM_OUTPUT_CHANNELS == 2)
318 EAS_INT pan;
319 #endif
320
321 #ifdef EAS_SPLIT_WT_SYNTH
322 S_WT_CONFIG wtConfig;
323 #endif
324
325 /* no samples have been synthesized for this note yet */
326 pVoice->regionIndex = regionIndex;
327 pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
328
329 /* get the articulation index for this region */
330 pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
331 pChannel = &pSynth->channels[pVoice->channel & 15];
332
333 /* update static channel parameters */
334 if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS)
335 WT_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15);
336
337 #ifdef DLS_SYNTHESIZER
338 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
339 return DLS_StartVoice(pVoiceMgr, pSynth, pVoice, voiceNum, regionIndex);
340 #endif
341
342 pRegion = &(pSynth->pEAS->pWTRegions[regionIndex]);
343 pWTVoice->artIndex = pRegion->artIndex;
344
345 #ifdef _DEBUG_SYNTH
346 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ }
347 #endif
348
349 pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex];
350
351 /* MIDI note on puts this voice into attack state */
352 pWTVoice->eg1State = eEnvelopeStateAttack;
353 pWTVoice->eg1Value = 0;
354 pWTVoice->eg1Increment = pArt->eg1.attackTime;
355 pWTVoice->eg2State = eEnvelopeStateAttack;
356 pWTVoice->eg2Value = 0;
357 pWTVoice->eg2Increment = pArt->eg2.attackTime;
358
359 /* init the LFO */
360 pWTVoice->modLFO.lfoValue = 0;
361 pWTVoice->modLFO.lfoPhase = -pArt->lfoDelay;
362
363 pVoice->gain = 0;
364
365 #if (NUM_OUTPUT_CHANNELS == 2)
366 /*
367 Get the Midi CC10 pan value for this voice's channel
368 convert the pan value to an "angle" representation suitable for
369 our sin, cos calculator. This representation is NOT necessarily the same
370 as the transform in the GM manuals because of our sin, cos calculator.
371 "angle" = (CC10 - 64)/128
372 */
373 pan = (EAS_INT) pSynth->channels[pVoice->channel & 15].pan - 64;
374 pan += pArt->pan;
375 EAS_CalcPanControl(pan, &pWTVoice->gainLeft, &pWTVoice->gainRight);
376 #endif
377
378 #ifdef _FILTER_ENABLED
379 /* clear out the filter states */
380 pWTVoice->filter.z1 = 0;
381 pWTVoice->filter.z2 = 0;
382 #endif
383
384 /* if this wave is to be generated using noise generator */
385 if (pRegion->region.keyGroupAndFlags & REGION_FLAG_USE_WAVE_GENERATOR)
386 {
387 pWTVoice->phaseAccum = 4574296;
388 pWTVoice->loopStart = WT_NOISE_GENERATOR;
389 pWTVoice->loopEnd = 4574295;
390 }
391
392 /* normal sample */
393 else
394 {
395
396 #ifdef EAS_SPLIT_WT_SYNTH
397 if (voiceNum < NUM_PRIMARY_VOICES)
398 pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex];
399 else
400 pWTVoice->phaseAccum = pSynth->pEAS->pSampleOffsets[pRegion->waveIndex];
401 #else
402 pWTVoice->phaseAccum = (EAS_U32) pSynth->pEAS->pSamples + pSynth->pEAS->pSampleOffsets[pRegion->waveIndex];
403 #endif
404
405 if (pRegion->region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED)
406 {
407 pWTVoice->loopStart = pWTVoice->phaseAccum + pRegion->loopStart;
408 pWTVoice->loopEnd = pWTVoice->phaseAccum + pRegion->loopEnd - 1;
409 }
410 else
411 pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pEAS->pSampleLen[pRegion->waveIndex] - 1;
412 }
413
414 #ifdef EAS_SPLIT_WT_SYNTH
415 /* configure off-chip voices */
416 if (voiceNum >= NUM_PRIMARY_VOICES)
417 {
418 wtConfig.phaseAccum = pWTVoice->phaseAccum;
419 wtConfig.loopStart = pWTVoice->loopStart;
420 wtConfig.loopEnd = pWTVoice->loopEnd;
421 wtConfig.gain = pVoice->gain;
422
423 #if (NUM_OUTPUT_CHANNELS == 2)
424 wtConfig.gainLeft = pWTVoice->gainLeft;
425 wtConfig.gainRight = pWTVoice->gainRight;
426 #endif
427
428 WTE_ConfigVoice(voiceNum - NUM_PRIMARY_VOICES, &wtConfig, pVoiceMgr->pFrameBuffer);
429 }
430 #endif
431
432 return EAS_SUCCESS;
433 }
434
435 /*----------------------------------------------------------------------------
436 * WT_CheckSampleEnd
437 *----------------------------------------------------------------------------
438 * Purpose:
439 * Check for end of sample and calculate number of samples to synthesize
440 *
441 * Inputs:
442 *
443 * Outputs:
444 *
445 * Notes:
446 *
447 *----------------------------------------------------------------------------
448 */
WT_CheckSampleEnd(S_WT_VOICE * pWTVoice,S_WT_INT_FRAME * pWTIntFrame,EAS_BOOL update)449 EAS_BOOL WT_CheckSampleEnd (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame, EAS_BOOL update)
450 {
451 EAS_U32 endPhaseAccum;
452 EAS_U32 endPhaseFrac;
453 EAS_I32 numSamples;
454 EAS_BOOL done = EAS_FALSE;
455
456 /* check to see if we hit the end of the waveform this time */
457 /*lint -e{703} use shift for performance */
458 endPhaseFrac = pWTVoice->phaseFrac + (pWTIntFrame->frame.phaseIncrement << SYNTH_UPDATE_PERIOD_IN_BITS);
459 endPhaseAccum = pWTVoice->phaseAccum + GET_PHASE_INT_PART(endPhaseFrac);
460 if (endPhaseAccum >= pWTVoice->loopEnd)
461 {
462 /* calculate how far current ptr is from end */
463 numSamples = (EAS_I32) (pWTVoice->loopEnd - pWTVoice->phaseAccum);
464
465 /* now account for the fractional portion */
466 /*lint -e{703} use shift for performance */
467 numSamples = (EAS_I32) ((numSamples << NUM_PHASE_FRAC_BITS) - pWTVoice->phaseFrac);
468 if (pWTIntFrame->frame.phaseIncrement) {
469 pWTIntFrame->numSamples = 1 + (numSamples / pWTIntFrame->frame.phaseIncrement);
470 } else {
471 pWTIntFrame->numSamples = numSamples;
472 }
473 if (pWTIntFrame->numSamples < 0) {
474 ALOGE("b/26366256");
475 android_errorWriteLog(0x534e4554, "26366256");
476 pWTIntFrame->numSamples = 0;
477 }
478
479 /* sound will be done this frame */
480 done = EAS_TRUE;
481 }
482
483 /* update data for off-chip synth */
484 if (update)
485 {
486 pWTVoice->phaseFrac = endPhaseFrac;
487 pWTVoice->phaseAccum = endPhaseAccum;
488 }
489
490 return done;
491 }
492
493 /*----------------------------------------------------------------------------
494 * WT_UpdateVoice()
495 *----------------------------------------------------------------------------
496 * Purpose:
497 * Synthesize a block of samples for the given voice.
498 * Use linear interpolation.
499 *
500 * Inputs:
501 * pEASData - pointer to overall EAS data structure
502 *
503 * Outputs:
504 * number of samples actually written to buffer
505 *
506 * Side Effects:
507 * - samples are added to the presently free buffer
508 *
509 *----------------------------------------------------------------------------
510 */
WT_UpdateVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice,EAS_I32 voiceNum,EAS_I32 * pMixBuffer,EAS_I32 numSamples)511 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)
512 {
513 S_WT_VOICE *pWTVoice;
514 S_WT_INT_FRAME intFrame;
515 S_SYNTH_CHANNEL *pChannel;
516 const S_WT_REGION *pWTRegion;
517 const S_ARTICULATION *pArt;
518 EAS_I32 temp;
519 EAS_BOOL done;
520
521 #ifdef DLS_SYNTHESIZER
522 if (pVoice->regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
523 return DLS_UpdateVoice(pVoiceMgr, pSynth, pVoice, voiceNum, pMixBuffer, numSamples);
524 #endif
525
526 /* establish pointers to critical data */
527 pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
528 pWTRegion = &pSynth->pEAS->pWTRegions[pVoice->regionIndex & REGION_INDEX_MASK];
529 pArt = &pSynth->pEAS->pArticulations[pWTVoice->artIndex];
530 pChannel = &pSynth->channels[pVoice->channel & 15];
531 intFrame.prevGain = pVoice->gain;
532
533 /* update the envelopes */
534 WT_UpdateEG1(pWTVoice, &pArt->eg1);
535 WT_UpdateEG2(pWTVoice, &pArt->eg2);
536
537 /* update the LFO */
538 WT_UpdateLFO(&pWTVoice->modLFO, pArt->lfoFreq);
539
540 #ifdef _FILTER_ENABLED
541 /* calculate filter if library uses filter */
542 if (pSynth->pEAS->libAttr & LIB_FORMAT_FILTER_ENABLED)
543 WT_UpdateFilter(pWTVoice, &intFrame, pArt);
544 else
545 intFrame.frame.k = 0;
546 #endif
547
548 /* update the gain */
549 intFrame.frame.gainTarget = WT_UpdateGain(pVoice, pWTVoice, pArt, pChannel, pWTRegion->gain);
550
551 /* calculate base pitch*/
552 temp = pChannel->staticPitch + pWTRegion->tuning;
553
554 /* include global transpose */
555 if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)
556 temp += pVoice->note * 100;
557 else
558 temp += (pVoice->note + pSynth->globalTranspose) * 100;
559 intFrame.frame.phaseIncrement = WT_UpdatePhaseInc(pWTVoice, pArt, pChannel, temp);
560
561 /* call into engine to generate samples */
562 intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer;
563 intFrame.pMixBuffer = pMixBuffer;
564 intFrame.numSamples = numSamples;
565
566 /* check for end of sample */
567 if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd))
568 done = WT_CheckSampleEnd(pWTVoice, &intFrame, (EAS_BOOL) (voiceNum >= NUM_PRIMARY_VOICES));
569 else
570 done = EAS_FALSE;
571
572 if (intFrame.numSamples < 0) intFrame.numSamples = 0;
573
574 if (intFrame.numSamples > BUFFER_SIZE_IN_MONO_SAMPLES)
575 intFrame.numSamples = BUFFER_SIZE_IN_MONO_SAMPLES;
576
577 #ifdef EAS_SPLIT_WT_SYNTH
578 if (voiceNum < NUM_PRIMARY_VOICES)
579 {
580 #ifndef _SPLIT_WT_TEST_HARNESS
581 WT_ProcessVoice(pWTVoice, &intFrame);
582 #endif
583 }
584 else
585 WTE_ProcessVoice(voiceNum - NUM_PRIMARY_VOICES, &intFrame.frame, pVoiceMgr->pFrameBuffer);
586 #else
587 WT_ProcessVoice(pWTVoice, &intFrame);
588 #endif
589
590 /* clear flag */
591 pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
592
593 /* if voice has finished, set flag for voice manager */
594 if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted))
595 done = EAS_TRUE;
596
597 /* if the update interval has elapsed, then force the current gain to the next
598 * gain since we never actually reach the next gain when ramping -- we just get
599 * very close to the target gain.
600 */
601 pVoice->gain = (EAS_I16) intFrame.frame.gainTarget;
602
603 return done;
604 }
605
606 /*----------------------------------------------------------------------------
607 * WT_UpdatePhaseInc()
608 *----------------------------------------------------------------------------
609 * Purpose:
610 * Calculate the phase increment
611 *
612 * Inputs:
613 * pVoice - pointer to the voice being updated
614 * psRegion - pointer to the region
615 * psArticulation - pointer to the articulation
616 * nChannelPitchForThisVoice - the portion of the pitch that is fixed for this
617 * voice during the duration of this synthesis
618 * pEASData - pointer to overall EAS data structure
619 *
620 * Outputs:
621 *
622 * Side Effects:
623 * set the phase increment for this voice
624 *----------------------------------------------------------------------------
625 */
WT_UpdatePhaseInc(S_WT_VOICE * pWTVoice,const S_ARTICULATION * pArt,S_SYNTH_CHANNEL * pChannel,EAS_I32 pitchCents)626 static EAS_I32 WT_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents)
627 {
628 EAS_I32 temp;
629
630 /*pitchCents due to CC1 = LFO * (CC1 / 128) * DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS */
631 temp = MULT_EG1_EG1(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS,
632 ((pChannel->modWheel) << (NUM_EG1_FRAC_BITS -7)));
633
634 /* pitchCents due to channel pressure = LFO * (channel pressure / 128) * DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS */
635 temp += MULT_EG1_EG1(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS,
636 ((pChannel->channelPressure) << (NUM_EG1_FRAC_BITS -7)));
637
638 /* now multiply the (channel pressure + CC1) pitch values by the LFO value */
639 temp = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, temp);
640
641 /*
642 add in the LFO pitch due to
643 channel pressure and CC1 along with
644 the LFO pitch, the EG2 pitch, and the
645 "static" pitch for this voice on this channel
646 */
647 temp += pitchCents +
648 (MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToPitch)) +
649 (MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToPitch));
650
651 /* convert from cents to linear phase increment */
652 return EAS_Calculate2toX(temp);
653 }
654
655 /*----------------------------------------------------------------------------
656 * WT_UpdateChannel()
657 *----------------------------------------------------------------------------
658 * Purpose:
659 * Calculate and assign static channel parameters
660 * These values only need to be updated if one of the controller values
661 * for this channel changes
662 *
663 * Inputs:
664 * nChannel - channel to update
665 * pEASData - pointer to overall EAS data structure
666 *
667 * Outputs:
668 *
669 * Side Effects:
670 * - the given channel's static gain and static pitch are updated
671 *----------------------------------------------------------------------------
672 */
673 /*lint -esym(715, pVoiceMgr) reserved for future use */
WT_UpdateChannel(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel)674 static void WT_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
675 {
676 EAS_I32 staticGain;
677 EAS_I32 pitchBend;
678 S_SYNTH_CHANNEL *pChannel;
679
680 pChannel = &pSynth->channels[channel];
681
682 /*
683 nChannelGain = (CC7 * CC11)^2 * master volume
684 where CC7 == 100 by default, CC11 == 127, master volume == 32767
685 */
686 staticGain = MULT_EG1_EG1((pChannel->volume) << (NUM_EG1_FRAC_BITS - 7),
687 (pChannel->expression) << (NUM_EG1_FRAC_BITS - 7));
688
689 /* staticGain has to be squared */
690 staticGain = MULT_EG1_EG1(staticGain, staticGain);
691
692 pChannel->staticGain = (EAS_I16) MULT_EG1_EG1(staticGain, pSynth->masterVolume);
693
694 /*
695 calculate pitch bend: RPN0 * ((2*pitch wheel)/16384 -1)
696 However, if we use the EG1 macros, remember that EG1 has a full
697 scale value of 32768 (instead of 16384). So instead of multiplying
698 by 2, multiply by 4 (left shift by 2), and subtract by 32768 instead
699 of 16384. This utilizes the fact that the EG1 macro places a binary
700 point 15 places to the left instead of 14 places.
701 */
702 /*lint -e{703} <avoid multiply for performance>*/
703 pitchBend =
704 (((EAS_I32)(pChannel->pitchBend) << 2)
705 - 32768);
706
707 pChannel->staticPitch =
708 MULT_EG1_EG1(pitchBend, pChannel->pitchBendSensitivity);
709
710 /* if this is not a drum channel, then add in the per-channel tuning */
711 if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL))
712 pChannel->staticPitch += pChannel->finePitch + (pChannel->coarsePitch * 100);
713
714 /* clear update flag */
715 pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
716 return;
717 }
718
719 /*----------------------------------------------------------------------------
720 * WT_UpdateGain()
721 *----------------------------------------------------------------------------
722 * Purpose:
723 * Calculate and assign static voice parameters as part of WT_UpdateVoice()
724 *
725 * Inputs:
726 * pVoice - ptr to the synth voice that we want to synthesize
727 * pEASData - pointer to overall EAS data structure
728 *
729 * Outputs:
730 *
731 * Side Effects:
732 * - various voice parameters are calculated and assigned
733 *
734 *----------------------------------------------------------------------------
735 */
WT_UpdateGain(S_SYNTH_VOICE * pVoice,S_WT_VOICE * pWTVoice,const S_ARTICULATION * pArt,S_SYNTH_CHANNEL * pChannel,EAS_I32 gain)736 static EAS_I32 WT_UpdateGain (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, const S_ARTICULATION *pArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain)
737 {
738 EAS_I32 lfoGain;
739 EAS_I32 temp;
740
741 /*
742 If this voice was stolen, then the velocity is actually
743 for the new note, not the note that we are currently ramping down.
744 So we really shouldn't use this velocity. However, that would require
745 more memory to store the velocity value, and the improvement may
746 not be sufficient to warrant the added memory.
747 */
748 /* velocity is fixed at note start for a given voice and must be squared */
749 temp = (pVoice->velocity) << (NUM_EG1_FRAC_BITS - 7);
750 temp = MULT_EG1_EG1(temp, temp);
751
752 /* region gain is fixed as part of the articulation */
753 temp = MULT_EG1_EG1(temp, gain);
754
755 /* include the channel gain */
756 temp = MULT_EG1_EG1(temp, pChannel->staticGain);
757
758 /* calculate LFO gain using an approximation for 10^x */
759 lfoGain = MULT_EG1_EG1(pWTVoice->modLFO.lfoValue, pArt->lfoToGain);
760 lfoGain = MULT_EG1_EG1(lfoGain, LFO_GAIN_TO_CENTS);
761
762 /* convert from a dB-like value to linear gain */
763 lfoGain = EAS_Calculate2toX(lfoGain);
764 temp = MULT_EG1_EG1(temp, lfoGain);
765
766 /* calculate the voice's gain */
767 temp = (EAS_I16)MULT_EG1_EG1(temp, pWTVoice->eg1Value);
768
769 return temp;
770 }
771
772 /*----------------------------------------------------------------------------
773 * WT_UpdateEG1()
774 *----------------------------------------------------------------------------
775 * Purpose:
776 * Calculate the EG1 envelope for the given voice (but do not update any
777 * state)
778 *
779 * Inputs:
780 * pVoice - ptr to the voice whose envelope we want to update
781 * nVoice - this voice's number - used only for debug
782 * pEASData - pointer to overall EAS data structure
783 *
784 * Outputs:
785 * nValue - the envelope value
786 *
787 * Side Effects:
788 * - updates EG1 state value for the given voice
789 *----------------------------------------------------------------------------
790 */
WT_UpdateEG1(S_WT_VOICE * pWTVoice,const S_ENVELOPE * pEnv)791 static void WT_UpdateEG1 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv)
792 {
793 EAS_I32 temp;
794
795 switch (pWTVoice->eg1State)
796 {
797 case eEnvelopeStateAttack:
798 temp = pWTVoice->eg1Value + pWTVoice->eg1Increment;
799
800 /* check if we have reached peak amplitude */
801 if (temp >= SYNTH_FULL_SCALE_EG1_GAIN)
802 {
803 /* limit the volume */
804 temp = SYNTH_FULL_SCALE_EG1_GAIN;
805
806 /* prepare to move to decay state */
807 pWTVoice->eg1State = eEnvelopeStateDecay;
808 pWTVoice->eg1Increment = pEnv->decayTime;
809 }
810
811 break;
812
813 /* exponential decay */
814 case eEnvelopeStateDecay:
815 temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment);
816
817 /* check if we have reached sustain level */
818 if (temp <= pEnv->sustainLevel)
819 {
820 /* enforce the sustain level */
821 temp = pEnv->sustainLevel;
822
823 /* if sustain level is zero, skip sustain & release the voice */
824 if (temp > 0)
825 pWTVoice->eg1State = eEnvelopeStateSustain;
826
827 /* move to sustain state */
828 else
829 pWTVoice->eg1State = eEnvelopeStateMuted;
830 }
831
832 break;
833
834 case eEnvelopeStateSustain:
835 return;
836
837 case eEnvelopeStateRelease:
838 temp = MULT_EG1_EG1(pWTVoice->eg1Value, pWTVoice->eg1Increment);
839
840 /* if we hit zero, this voice isn't contributing any audio */
841 if (temp <= 0)
842 {
843 temp = 0;
844 pWTVoice->eg1State = eEnvelopeStateMuted;
845 }
846 break;
847
848 /* voice is muted, set target to zero */
849 case eEnvelopeStateMuted:
850 temp = 0;
851 break;
852
853 case eEnvelopeStateInvalid:
854 default:
855 temp = 0;
856 #ifdef _DEBUG_SYNTH
857 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG1: error, %d is an unrecognized state\n",
858 pWTVoice->eg1State); */ }
859 #endif
860 break;
861
862 }
863
864 pWTVoice->eg1Value = (EAS_I16) temp;
865 }
866
867 /*----------------------------------------------------------------------------
868 * WT_UpdateEG2()
869 *----------------------------------------------------------------------------
870 * Purpose:
871 * Update the EG2 envelope for the given voice
872 *
873 * Inputs:
874 * pVoice - ptr to the voice whose envelope we want to update
875 * pEASData - pointer to overall EAS data structure
876 *
877 * Outputs:
878 *
879 * Side Effects:
880 * - updates EG2 values for the given voice
881 *----------------------------------------------------------------------------
882 */
883
WT_UpdateEG2(S_WT_VOICE * pWTVoice,const S_ENVELOPE * pEnv)884 static void WT_UpdateEG2 (S_WT_VOICE *pWTVoice, const S_ENVELOPE *pEnv)
885 {
886 EAS_I32 temp;
887
888 switch (pWTVoice->eg2State)
889 {
890 case eEnvelopeStateAttack:
891 temp = pWTVoice->eg2Value + pWTVoice->eg2Increment;
892
893 /* check if we have reached peak amplitude */
894 if (temp >= SYNTH_FULL_SCALE_EG1_GAIN)
895 {
896 /* limit the volume */
897 temp = SYNTH_FULL_SCALE_EG1_GAIN;
898
899 /* prepare to move to decay state */
900 pWTVoice->eg2State = eEnvelopeStateDecay;
901
902 pWTVoice->eg2Increment = pEnv->decayTime;
903 }
904
905 break;
906
907 /* implement linear pitch decay in cents */
908 case eEnvelopeStateDecay:
909 temp = pWTVoice->eg2Value -pWTVoice->eg2Increment;
910
911 /* check if we have reached sustain level */
912 if (temp <= pEnv->sustainLevel)
913 {
914 /* enforce the sustain level */
915 temp = pEnv->sustainLevel;
916
917 /* prepare to move to sustain state */
918 pWTVoice->eg2State = eEnvelopeStateSustain;
919 }
920 break;
921
922 case eEnvelopeStateSustain:
923 return;
924
925 case eEnvelopeStateRelease:
926 temp = pWTVoice->eg2Value - pWTVoice->eg2Increment;
927
928 if (temp <= 0)
929 {
930 temp = 0;
931 pWTVoice->eg2State = eEnvelopeStateMuted;
932 }
933
934 break;
935
936 /* voice is muted, set target to zero */
937 case eEnvelopeStateMuted:
938 temp = 0;
939 break;
940
941 case eEnvelopeStateInvalid:
942 default:
943 temp = 0;
944 #ifdef _DEBUG_SYNTH
945 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WT_UpdateEG2: error, %d is an unrecognized state\n",
946 pWTVoice->eg2State); */ }
947 #endif
948 break;
949 }
950
951 pWTVoice->eg2Value = (EAS_I16) temp;
952 }
953
954 /*----------------------------------------------------------------------------
955 * WT_UpdateLFO ()
956 *----------------------------------------------------------------------------
957 * Purpose:
958 * Calculate the LFO for the given voice
959 *
960 * Inputs:
961 * pLFO - ptr to the LFO data
962 * phaseInc - phase increment
963 *
964 * Outputs:
965 *
966 * Side Effects:
967 * - updates LFO values for the given voice
968 *----------------------------------------------------------------------------
969 */
WT_UpdateLFO(S_LFO_CONTROL * pLFO,EAS_I16 phaseInc)970 void WT_UpdateLFO (S_LFO_CONTROL *pLFO, EAS_I16 phaseInc)
971 {
972
973 /* To save memory, if m_nPhaseValue is negative, we are in the
974 * delay phase, and m_nPhaseValue represents the time left
975 * in the delay.
976 */
977 if (pLFO->lfoPhase < 0)
978 {
979 pLFO->lfoPhase++;
980 return;
981 }
982
983 /* calculate LFO output from phase value */
984 /*lint -e{701} Use shift for performance */
985 pLFO->lfoValue = (EAS_I16) (pLFO->lfoPhase << 2);
986 /*lint -e{502} <shortcut to turn sawtooth into triangle wave> */
987 if ((pLFO->lfoPhase > 0x1fff) && (pLFO->lfoPhase < 0x6000))
988 pLFO->lfoValue = ~pLFO->lfoValue;
989
990 /* update LFO phase */
991 pLFO->lfoPhase = (pLFO->lfoPhase + phaseInc) & 0x7fff;
992 }
993
994 #ifdef _FILTER_ENABLED
995 /*----------------------------------------------------------------------------
996 * WT_UpdateFilter()
997 *----------------------------------------------------------------------------
998 * Purpose:
999 * Update the Filter parameters
1000 *
1001 * Inputs:
1002 * pVoice - ptr to the voice whose filter we want to update
1003 * pEASData - pointer to overall EAS data structure
1004 *
1005 * Outputs:
1006 *
1007 * Side Effects:
1008 * - updates Filter values for the given voice
1009 *----------------------------------------------------------------------------
1010 */
WT_UpdateFilter(S_WT_VOICE * pWTVoice,S_WT_INT_FRAME * pIntFrame,const S_ARTICULATION * pArt)1011 static void WT_UpdateFilter (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, const S_ARTICULATION *pArt)
1012 {
1013 EAS_I32 cutoff;
1014
1015 /* no need to calculate filter coefficients if it is bypassed */
1016 if (pArt->filterCutoff == DEFAULT_EAS_FILTER_CUTOFF_FREQUENCY)
1017 {
1018 pIntFrame->frame.k = 0;
1019 return;
1020 }
1021
1022 /* determine the dynamic cutoff frequency */
1023 cutoff = MULT_EG1_EG1(pWTVoice->eg2Value, pArt->eg2ToFc);
1024 cutoff += pArt->filterCutoff;
1025
1026 /* subtract the A5 offset and the sampling frequency */
1027 cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS;
1028
1029 /* limit the cutoff frequency */
1030 if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS)
1031 cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS;
1032 else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS)
1033 cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS;
1034
1035 WT_SetFilterCoeffs(pIntFrame, cutoff, pArt->filterQ);
1036 }
1037 #endif
1038
1039 #if defined(_FILTER_ENABLED) || defined(DLS_SYNTHESIZER)
1040 /*----------------------------------------------------------------------------
1041 * coef
1042 *----------------------------------------------------------------------------
1043 * Table of filter coefficients for low-pass filter
1044 *----------------------------------------------------------------------------
1045 *
1046 * polynomial coefficients are based on 8kHz sampling frequency
1047 * filter coef b2 = k2 = k2g0*k^0 + k2g1*k^1*(2^x) + k2g2*k^2*(2^x)
1048 *
1049 *where k2g0, k2g1, k2g2 are from the truncated power series expansion on theta
1050 *(k*2^x = theta, but we incorporate the k along with the k2g0, k2g1, k2g2)
1051 *note: this is a power series in 2^x, not k*2^x
1052 *where k = (2*pi*440)/8kHz == convert octaves to radians
1053 *
1054 * so actually, the following coefs listed as k2g0, k2g1, k2g2 are really
1055 * k2g0*k^0 = k2g0
1056 * k2g1*k^1
1057 * k2g2*k^2
1058 *
1059 *
1060 * filter coef n1 = numerator = n1g0*k^0 + n1g1*k^1*(2^x) + n1g2*k^2*(2^x) + n1g3*k^3*(2^x)
1061 *
1062 *where n1g0, n1g1, n1g2, n1g3 are from the truncated power series expansion on theta
1063 *(k*2^x = theta, but we incorporate the k along with the n1g0, n1g1, n1g2, n2g3)
1064 *note: this is a power series in 2^x, not k*2^x
1065 *where k = (2*pi*440)/8kHz == convert octaves to radians
1066 *we also include the optimization factor of 0.81
1067 *
1068 * so actually, the following coefs listed as n1g0, n1g1, n1g2, n2g3 are really
1069 * n1g0*k^0 = n1g0
1070 * n1g1*k^1
1071 * n1g2*k^2
1072 * n1g3*k^3
1073 *
1074 * NOTE that n1g0 == n1g1 == 0, always, so we only need to store n1g2 and n1g3
1075 *----------------------------------------------------------------------------
1076 */
1077
1078 static const EAS_I16 nk1g0 = -32768;
1079 static const EAS_I16 nk1g2 = 1580;
1080 static const EAS_I16 k2g0 = 32767;
1081
1082 static const EAS_I16 k2g1[] =
1083 {
1084 -11324, /* k2g1[0] = -0.3455751918948761 */
1085 -10387, /* k2g1[1] = -0.3169878073928751 */
1086 -9528, /* k2g1[2] = -0.29076528753345476 */
1087 -8740, /* k2g1[3] = -0.2667120011011279 */
1088 -8017, /* k2g1[4] = -0.24464850028971705 */
1089 -7353, /* k2g1[5] = -0.22441018194495696 */
1090 -6745, /* k2g1[6] = -0.20584605955455101 */
1091 -6187, /* k2g1[7] = -0.18881763682420102 */
1092 -5675, /* k2g1[8] = -0.1731978744360067 */
1093 -5206, /* k2g1[9] = -0.15887024228080968 */
1094 -4775, /* k2g1[10] = -0.14572785009373057 */
1095 -4380, /* k2g1[11] = -0.13367265000706827 */
1096 -4018, /* k2g1[12] = -0.1226147050712642 */
1097 -3685, /* k2g1[13] = -0.11247151828678581 */
1098 -3381, /* k2g1[14] = -0.10316741714122014 */
1099 -3101, /* k2g1[15] = -0.0946329890599603 */
1100 -2844, /* k2g1[16] = -0.08680456355870586 */
1101 -2609, /* k2g1[17] = -0.07962373723441349 */
1102 -2393, /* k2g1[18] = -0.07303693805092666 */
1103 -2195, /* k2g1[19] = -0.06699502566866912 */
1104 -2014, /* k2g1[20] = -0.06145292483669077 */
1105 -1847, /* k2g1[21] = -0.056369289112013346 */
1106 -1694, /* k2g1[22] = -0.05170619239747895 */
1107 -1554, /* k2g1[23] = -0.04742884599684141 */
1108 -1426, /* k2g1[24] = -0.043505339076210514 */
1109 -1308, /* k2g1[25] = -0.03990640059558053 */
1110 -1199, /* k2g1[26] = -0.03660518093435039 */
1111 -1100, /* k2g1[27] = -0.03357705158166837 */
1112 -1009, /* k2g1[28] = -0.030799421397205727 */
1113 -926, /* k2g1[29] = -0.028251568071585884 */
1114 -849 /* k2g1[30] = -0.025914483529091967 */
1115 };
1116
1117 static const EAS_I16 k2g2[] =
1118 {
1119 1957, /* k2g2[0] = 0.059711106626580836 */
1120 1646, /* k2g2[1] = 0.05024063501786333 */
1121 1385, /* k2g2[2] = 0.042272226217199664 */
1122 1165, /* k2g2[3] = 0.03556764576567844 */
1123 981, /* k2g2[4] = 0.029926444346999134 */
1124 825, /* k2g2[5] = 0.025179964880280382 */
1125 694, /* k2g2[6] = 0.02118630011706455 */
1126 584, /* k2g2[7] = 0.01782604998793514 */
1127 491, /* k2g2[8] = 0.014998751854573014 */
1128 414, /* k2g2[9] = 0.012619876941179595 */
1129 348, /* k2g2[10] = 0.010618303146468736 */
1130 293, /* k2g2[11] = 0.008934188679954682 */
1131 246, /* k2g2[12] = 0.007517182949855368 */
1132 207, /* k2g2[13] = 0.006324921212866403 */
1133 174, /* k2g2[14] = 0.005321757979794424 */
1134 147, /* k2g2[15] = 0.004477701309210577 */
1135 123, /* k2g2[16] = 0.00376751612730811 */
1136 104, /* k2g2[17] = 0.0031699697655869644 */
1137 87, /* k2g2[18] = 0.00266719715992703 */
1138 74, /* k2g2[19] = 0.0022441667321724647 */
1139 62, /* k2g2[20] = 0.0018882309854916855 */
1140 52, /* k2g2[21] = 0.0015887483774966232 */
1141 44, /* k2g2[22] = 0.0013367651661223448 */
1142 37, /* k2g2[23] = 0.0011247477162958733 */
1143 31, /* k2g2[24] = 0.0009463572640678758 */
1144 26, /* k2g2[25] = 0.0007962604042473498 */
1145 22, /* k2g2[26] = 0.0006699696356181593 */
1146 18, /* k2g2[27] = 0.0005637091964589207 */
1147 16, /* k2g2[28] = 0.00047430217920125243 */
1148 13, /* k2g2[29] = 0.00039907554925166274 */
1149 11 /* k2g2[30] = 0.00033578022828973666 */
1150 };
1151
1152 static const EAS_I16 n1g2[] =
1153 {
1154 3170, /* n1g2[0] = 0.0967319927350769 */
1155 3036, /* n1g2[1] = 0.0926446051254155 */
1156 2908, /* n1g2[2] = 0.08872992911818503 */
1157 2785, /* n1g2[3] = 0.08498066682523227 */
1158 2667, /* n1g2[4] = 0.08138982872895201 */
1159 2554, /* n1g2[5] = 0.07795072065216213 */
1160 2446, /* n1g2[6] = 0.0746569312785634 */
1161 2343, /* n1g2[7] = 0.07150232020051943 */
1162 2244, /* n1g2[8] = 0.06848100647187474 */
1163 2149, /* n1g2[9] = 0.06558735764447099 */
1164 2058, /* n1g2[10] = 0.06281597926792246 */
1165 1971, /* n1g2[11] = 0.06016170483307614 */
1166 1888, /* n1g2[12] = 0.05761958614040857 */
1167 1808, /* n1g2[13] = 0.05518488407540374 */
1168 1732, /* n1g2[14] = 0.052853059773715245 */
1169 1659, /* n1g2[15] = 0.05061976615964251 */
1170 1589, /* n1g2[16] = 0.04848083984214659 */
1171 1521, /* n1g2[17] = 0.046432293353298 */
1172 1457, /* n1g2[18] = 0.04447030771468711 */
1173 1396, /* n1g2[19] = 0.04259122531793907 */
1174 1337, /* n1g2[20] = 0.040791543106060944 */
1175 1280, /* n1g2[21] = 0.03906790604290942 */
1176 1226, /* n1g2[22] = 0.037417100858604564 */
1177 1174, /* n1g2[23] = 0.035836050059229754 */
1178 1125, /* n1g2[24] = 0.03432180618965023 */
1179 1077, /* n1g2[25] = 0.03287154633875494 */
1180 1032, /* n1g2[26] = 0.03148256687687814 */
1181 988, /* n1g2[27] = 0.030152278415589925 */
1182 946, /* n1g2[28] = 0.028878200980459685 */
1183 906, /* n1g2[29] = 0.02765795938779331 */
1184 868 /* n1g2[30] = 0.02648927881672521 */
1185 };
1186
1187 static const EAS_I16 n1g3[] =
1188 {
1189 -548, /* n1g3[0] = -0.016714088475899017 */
1190 -481, /* n1g3[1] = -0.014683605122742116 */
1191 -423, /* n1g3[2] = -0.012899791676436092 */
1192 -371, /* n1g3[3] = -0.01133268185193299 */
1193 -326, /* n1g3[4] = -0.00995594976868754 */
1194 -287, /* n1g3[5] = -0.008746467702146129 */
1195 -252, /* n1g3[6] = -0.00768391756106361 */
1196 -221, /* n1g3[7] = -0.006750449563854721 */
1197 -194, /* n1g3[8] = -0.005930382380083576 */
1198 -171, /* n1g3[9] = -0.005209939699767622 */
1199 -150, /* n1g3[10] = -0.004577018805123356 */
1200 -132, /* n1g3[11] = -0.004020987256990177 */
1201 -116, /* n1g3[12] = -0.003532504280467257 */
1202 -102, /* n1g3[13] = -0.00310336384922047 */
1203 -89, /* n1g3[14] = -0.002726356832432369 */
1204 -78, /* n1g3[15] = -0.002395149888601605 */
1205 -69, /* n1g3[16] = -0.0021041790717285314 */
1206 -61, /* n1g3[17] = -0.0018485563625771063 */
1207 -53, /* n1g3[18] = -0.001623987554831628 */
1208 -47, /* n1g3[19] = -0.0014267001167177025 */
1209 -41, /* n1g3[20] = -0.0012533798162347005 */
1210 -36, /* n1g3[21] = -0.0011011150453668693 */
1211 -32, /* n1g3[22] = -0.0009673479079754438 */
1212 -28, /* n1g3[23] = -0.0008498312496971563 */
1213 -24, /* n1g3[24] = -0.0007465909079943587 */
1214 -21, /* n1g3[25] = -0.0006558925481952733 */
1215 -19, /* n1g3[26] = -0.0005762125284029567 */
1216 -17, /* n1g3[27] = -0.0005062123038325457 */
1217 -15, /* n1g3[28] = -0.0004447159405951901 */
1218 -13, /* n1g3[29] = -0.00039069036118270117 */
1219 -11 /* n1g3[30] = -0.00034322798979677605 */
1220 };
1221
1222 /*----------------------------------------------------------------------------
1223 * WT_SetFilterCoeffs()
1224 *----------------------------------------------------------------------------
1225 * Purpose:
1226 * Update the Filter parameters
1227 *
1228 * Inputs:
1229 * pVoice - ptr to the voice whose filter we want to update
1230 * pEASData - pointer to overall EAS data structure
1231 *
1232 * Outputs:
1233 *
1234 * Side Effects:
1235 * - updates Filter values for the given voice
1236 *----------------------------------------------------------------------------
1237 */
WT_SetFilterCoeffs(S_WT_INT_FRAME * pIntFrame,EAS_I32 cutoff,EAS_I32 resonance)1238 void WT_SetFilterCoeffs (S_WT_INT_FRAME *pIntFrame, EAS_I32 cutoff, EAS_I32 resonance)
1239 {
1240 EAS_I32 temp;
1241
1242 /*
1243 Convert the cutoff, which has had A5 subtracted, using the 2^x approx
1244 Note, this cutoff is related to theta cutoff by
1245 theta = k * 2^x
1246 We use 2^x and incorporate k in the power series coefs instead
1247 */
1248 cutoff = EAS_Calculate2toX(cutoff);
1249
1250 /* calculate b2 coef */
1251 temp = k2g1[resonance] + MULT_AUDIO_COEF(cutoff, k2g2[resonance]);
1252 temp = k2g0 + MULT_AUDIO_COEF(cutoff, temp);
1253 pIntFrame->frame.b2 = temp;
1254
1255 /* calculate b1 coef */
1256 temp = MULT_AUDIO_COEF(cutoff, nk1g2);
1257 temp = nk1g0 + MULT_AUDIO_COEF(cutoff, temp);
1258 temp += MULT_AUDIO_COEF(temp, pIntFrame->frame.b2);
1259 pIntFrame->frame.b1 = temp >> 1;
1260
1261 /* calculate K coef */
1262 temp = n1g2[resonance] + MULT_AUDIO_COEF(cutoff, n1g3[resonance]);
1263 temp = MULT_AUDIO_COEF(cutoff, temp);
1264 temp = MULT_AUDIO_COEF(cutoff, temp);
1265 pIntFrame->frame.k = temp;
1266 }
1267 #endif
1268
1269