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