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