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