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