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