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