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