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