• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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