Home | History | Annotate | Download | only in lib_src
      1 /*----------------------------------------------------------------------------
      2  *
      3  * File:
      4  * eas_dlssynth.c
      5  *
      6  * Contents and purpose:
      7  * Implements the Mobile DLS synthesizer.
      8  *
      9  * Copyright Sonic Network Inc. 2006
     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 #include "eas_mdls.h"
     39 #include "eas_dlssynth.h"
     40 
     41 #ifdef _METRICS_ENABLED
     42 #include "eas_perf.h"
     43 #endif
     44 
     45 static void DLS_UpdateEnvelope (S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel,  const S_DLS_ENVELOPE *pEnvParams, EAS_I16 *pValue, EAS_I16 *pIncrement, EAS_U8 *pState);
     46 
     47 /*----------------------------------------------------------------------------
     48  * DLS_MuteVoice()
     49  *----------------------------------------------------------------------------
     50  * Mute the voice using shutdown time from the DLS articulation data
     51  *----------------------------------------------------------------------------
     52 */
     53 void DLS_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
     54 {
     55     S_WT_VOICE *pWTVoice;
     56     const S_DLS_ARTICULATION *pDLSArt;
     57 
     58     pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
     59     pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
     60 
     61     /* clear deferred action flags */
     62     pVoice->voiceFlags &=
     63         ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF |
     64         VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF |
     65         VOICE_FLAG_DEFER_MUTE);
     66 
     67     /* set the envelope state */
     68     pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateRelease;
     69     pWTVoice->eg1Increment = pDLSArt->eg1ShutdownTime;
     70     pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateRelease;
     71     pWTVoice->eg2Increment = pDLSArt->eg2.releaseTime;
     72 }
     73 
     74 /*----------------------------------------------------------------------------
     75  * DLS_ReleaseVoice()
     76  *----------------------------------------------------------------------------
     77  * Release the selected voice.
     78  *----------------------------------------------------------------------------
     79 */
     80 /*lint -esym(715, pVoice) standard API, pVoice may be used by other synthesizers */
     81 void DLS_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
     82 {
     83     S_WT_VOICE *pWTVoice;
     84     const S_DLS_ARTICULATION *pDLSArt;
     85 
     86     pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
     87     pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
     88 
     89     /* if still in attack phase, convert units to log */
     90     /*lint -e{732} eg1Value is never negative */
     91     /*lint -e{703} use shift for performance */
     92     if (pWTVoice->eg1State == eEnvelopeStateAttack)
     93         pWTVoice->eg1Value = (EAS_I16) ((EAS_flog2(pWTVoice->eg1Value) << 1) + 2048);
     94 
     95     /* release EG1 */
     96     pWTVoice->eg1State = eEnvelopeStateRelease;
     97     pWTVoice->eg1Increment = pDLSArt->eg1.releaseTime;
     98 
     99     /* release EG2 */
    100     pWTVoice->eg2State = eEnvelopeStateRelease;
    101     pWTVoice->eg2Increment = pDLSArt->eg2.releaseTime;
    102 }
    103 
    104 /*----------------------------------------------------------------------------
    105  * DLS_SustainPedal()
    106  *----------------------------------------------------------------------------
    107  * The sustain pedal was just depressed. If the voice is still
    108  * above the sustain level, catch the voice and continue holding.
    109  *----------------------------------------------------------------------------
    110 */
    111 /*lint -esym(715, pChannel) pChannel reserved for future use */
    112 void DLS_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum)
    113 {
    114     S_WT_VOICE *pWTVoice;
    115     const S_DLS_ARTICULATION *pDLSArt;
    116 
    117     pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
    118     pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
    119 
    120     /* don't catch the voice if below the sustain level */
    121     if (pWTVoice->eg1Value < pDLSArt->eg1.sustainLevel)
    122         return;
    123 
    124     /* defer releasing this note until the damper pedal is off */
    125     pWTVoice->eg1State = eEnvelopeStateDecay;
    126     pVoice->voiceState = eVoiceStatePlay;
    127     pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
    128 
    129 #ifdef _DEBUG_SYNTH
    130     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "DLS_SustainPedal: defer note off because sustain pedal is on\n"); */ }
    131 #endif
    132 }
    133 
    134 /*----------------------------------------------------------------------------
    135  * DLS_UpdatePhaseInc()
    136  *----------------------------------------------------------------------------
    137  * Calculate the oscillator phase increment for the next frame
    138  *----------------------------------------------------------------------------
    139 */
    140 static EAS_I32 DLS_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_DLS_ARTICULATION *pDLSArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents)
    141 {
    142     EAS_I32 temp;
    143 
    144     /* start with base mod LFO modulation */
    145     temp = pDLSArt->modLFOToPitch;
    146 
    147     /* add mod wheel effect */
    148     /*lint -e{702} use shift for performance */
    149     temp += ((pDLSArt->modLFOCC1ToPitch * pChannel->modWheel) >> 7);
    150 
    151     /* add channel pressure effect */
    152     /*lint -e{702} use shift for performance */
    153     temp += ((pDLSArt->modLFOChanPressToPitch * pChannel->channelPressure) >> 7);
    154 
    155     /* add total mod LFO effect */
    156     pitchCents += FMUL_15x15(temp, pWTVoice->modLFO.lfoValue);
    157 
    158     /* start with base vib LFO modulation */
    159     temp = pDLSArt->vibLFOToPitch;
    160 
    161     /* add mod wheel effect */
    162     /*lint -e{702} use shift for performance */
    163     temp += ((pDLSArt->vibLFOCC1ToPitch * pChannel->modWheel) >> 7);
    164 
    165     /* add channel pressure effect */
    166     /*lint -e{702} use shift for performance */
    167     temp += ((pDLSArt->vibLFOChanPressToPitch * pChannel->channelPressure) >> 7);
    168 
    169     /* add total vibrato LFO effect */
    170     pitchCents += FMUL_15x15(temp, pWTVoice->vibLFO.lfoValue);
    171 
    172     /* add EG2 effect */
    173     pitchCents += FMUL_15x15(pDLSArt->eg2ToPitch, pWTVoice->eg2Value);
    174 
    175     /* convert from cents to linear phase increment */
    176     return EAS_Calculate2toX(pitchCents);
    177 }
    178 
    179 /*----------------------------------------------------------------------------
    180  * DLS_UpdateGain()
    181  *----------------------------------------------------------------------------
    182  * Calculate the gain for the next frame
    183  *----------------------------------------------------------------------------
    184 */
    185 static EAS_I32 DLS_UpdateGain (S_WT_VOICE *pWTVoice, const S_DLS_ARTICULATION *pDLSArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain, EAS_U8 velocity)
    186 {
    187     EAS_I32 temp;
    188 
    189     /* start with base mod LFO modulation */
    190     temp = pDLSArt->modLFOToGain;
    191 
    192     /* add mod wheel effect */
    193     /*lint -e{702} use shift for performance */
    194     temp += ((pDLSArt->modLFOCC1ToGain * pChannel->modWheel) >> 7);
    195 
    196     /* add channel pressure effect */
    197     /*lint -e{702} use shift for performance */
    198     temp += ((pDLSArt->modLFOChanPressToGain * pChannel->channelPressure) >> 7);
    199 
    200     /* add total mod LFO effect */
    201     gain += FMUL_15x15(temp, pWTVoice->modLFO.lfoValue);
    202     if (gain > 0)
    203         gain = 0;
    204 
    205     /* convert to linear gain including EG1 */
    206     if (pWTVoice->eg1State != eEnvelopeStateAttack)
    207     {
    208         gain = (DLS_GAIN_FACTOR * gain) >> DLS_GAIN_SHIFT;
    209         /*lint -e{702} use shift for performance */
    210 #if 1
    211         gain += (pWTVoice->eg1Value - 32767) >> 1;
    212         gain = EAS_LogToLinear16(gain);
    213 #else
    214         gain = EAS_LogToLinear16(gain);
    215         temp = EAS_LogToLinear16((pWTVoice->eg1Value - 32767) >> 1);
    216         gain = FMUL_15x15(gain, temp);
    217 #endif
    218     }
    219     else
    220     {
    221         gain = (DLS_GAIN_FACTOR * gain) >> DLS_GAIN_SHIFT;
    222         gain = EAS_LogToLinear16(gain);
    223         gain = FMUL_15x15(gain, pWTVoice->eg1Value);
    224     }
    225 
    226     /* include MIDI channel gain */
    227     gain = FMUL_15x15(gain, pChannel->staticGain);
    228 
    229     /* include velocity */
    230     if (pDLSArt->filterQandFlags & FLAG_DLS_VELOCITY_SENSITIVE)
    231     {
    232         temp = velocity << 8;
    233         temp = FMUL_15x15(temp, temp);
    234         gain = FMUL_15x15(gain, temp);
    235     }
    236 
    237     /* return gain */
    238     return gain;
    239 }
    240 
    241 /*----------------------------------------------------------------------------
    242  * DLS_UpdateFilter()
    243  *----------------------------------------------------------------------------
    244  * Update the Filter parameters
    245  *----------------------------------------------------------------------------
    246 */
    247 static void DLS_UpdateFilter (S_SYNTH_VOICE *pVoice, S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pIntFrame, S_SYNTH_CHANNEL *pChannel, const S_DLS_ARTICULATION *pDLSArt)
    248 {
    249     EAS_I32 cutoff;
    250     EAS_I32 temp;
    251 
    252     /* no need to calculate filter coefficients if it is bypassed */
    253     if (pDLSArt->filterCutoff == DEFAULT_DLS_FILTER_CUTOFF_FREQUENCY)
    254     {
    255         pIntFrame->frame.k = 0;
    256         return;
    257     }
    258 
    259     /* start with base cutoff frequency */
    260     cutoff = pDLSArt->filterCutoff;
    261 
    262     /* get base mod LFO modulation */
    263     temp = pDLSArt->modLFOToFc;
    264 
    265     /* add mod wheel effect */
    266     /*lint -e{702} use shift for performance */
    267     temp += ((pDLSArt->modLFOCC1ToFc * pChannel->modWheel) >> 7);
    268 
    269     /* add channel pressure effect */
    270     /*lint -e{702} use shift for performance */
    271     temp += ((pDLSArt->modLFOChanPressToFc* pChannel->channelPressure) >> 7);
    272 
    273     /* add total mod LFO effect */
    274     cutoff += FMUL_15x15(temp, pWTVoice->modLFO.lfoValue);
    275 
    276     /* add EG2 effect */
    277     cutoff += FMUL_15x15(pWTVoice->eg2Value, pDLSArt->eg2ToFc);
    278 
    279     /* add velocity effect */
    280     /*lint -e{702} use shift for performance */
    281     cutoff += (pVoice->velocity * pDLSArt->velToFc) >> 7;
    282 
    283     /* add velocity effect */
    284     /*lint -e{702} use shift for performance */
    285     cutoff += (pVoice->note * pDLSArt->keyNumToFc) >> 7;
    286 
    287     /* subtract the A5 offset and the sampling frequency */
    288     cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS;
    289 
    290     /* limit the cutoff frequency */
    291     if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS)
    292         cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS;
    293     else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS)
    294         cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS;
    295 
    296     WT_SetFilterCoeffs(pIntFrame, cutoff, pDLSArt->filterQandFlags & FILTER_Q_MASK);
    297 }
    298 
    299 /*----------------------------------------------------------------------------
    300  * DLS_StartVoice()
    301  *----------------------------------------------------------------------------
    302  * Start up a DLS voice
    303  *----------------------------------------------------------------------------
    304 */
    305 EAS_RESULT DLS_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex)
    306 {
    307     S_WT_VOICE *pWTVoice;
    308     const S_DLS_REGION *pDLSRegion;
    309     const S_DLS_ARTICULATION *pDLSArt;
    310     S_SYNTH_CHANNEL *pChannel;
    311 
    312 #ifdef _DEBUG_SYNTH
    313     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "DLS_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ }
    314 #endif
    315 
    316     pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
    317     pChannel = &pSynth->channels[pVoice->channel & 15];
    318     pDLSRegion = &pSynth->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK];
    319     pWTVoice->artIndex = pDLSRegion->wtRegion.artIndex;
    320     pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
    321 
    322     /* initialize the envelopes */
    323     pWTVoice->eg1State = eEnvelopeStateInit;
    324     DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg1, &pWTVoice->eg1Value, &pWTVoice->eg1Increment, &pWTVoice->eg1State);
    325     pWTVoice->eg2State = eEnvelopeStateInit;
    326     DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg2, &pWTVoice->eg2Value, &pWTVoice->eg2Increment, &pWTVoice->eg2State);
    327 
    328     /* initialize the LFOs */
    329     pWTVoice->modLFO.lfoValue = 0;
    330     pWTVoice->modLFO.lfoPhase = pDLSArt->modLFO.lfoDelay;
    331     pWTVoice->vibLFO.lfoValue = 0;
    332     pWTVoice->vibLFO.lfoPhase = pDLSArt->vibLFO.lfoDelay;
    333 
    334     /* initalize the envelopes and calculate initial gain */
    335     DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg1, &pWTVoice->eg1Value, &pWTVoice->eg1Increment, &pWTVoice->eg1State);
    336     DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg2, &pWTVoice->eg2Value, &pWTVoice->eg2Increment, &pWTVoice->eg2State);
    337     pVoice->gain = (EAS_I16) DLS_UpdateGain(pWTVoice, pDLSArt, pChannel, pDLSRegion->wtRegion.gain, pVoice->velocity);
    338 
    339 #if (NUM_OUTPUT_CHANNELS == 2)
    340     EAS_CalcPanControl((EAS_INT) pChannel->pan - 64 + (EAS_INT) pDLSArt->pan, &pWTVoice->gainLeft, &pWTVoice->gainRight);
    341 #endif
    342 
    343     /* initialize the filter states */
    344     pWTVoice->filter.z1 = 0;
    345     pWTVoice->filter.z2 = 0;
    346 
    347     /* initialize the oscillator */
    348     pWTVoice->phaseAccum = (EAS_U32) pSynth->pDLS->pDLSSamples + pSynth->pDLS->pDLSSampleOffsets[pDLSRegion->wtRegion.waveIndex];
    349     if (pDLSRegion->wtRegion.region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED)
    350     {
    351         pWTVoice->loopStart = pWTVoice->phaseAccum + pDLSRegion->wtRegion.loopStart;
    352         pWTVoice->loopEnd = pWTVoice->phaseAccum + pDLSRegion->wtRegion.loopEnd - 1;
    353     }
    354     else
    355         pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pDLS->pDLSSampleLen[pDLSRegion->wtRegion.waveIndex] - 1;
    356 
    357     return EAS_SUCCESS;
    358 }
    359 
    360 /*----------------------------------------------------------------------------
    361  * DLS_UpdateVoice()
    362  *----------------------------------------------------------------------------
    363  * Purpose:
    364  * Synthesize a block of samples for the given voice.
    365  * Use linear interpolation.
    366  *
    367  * Inputs:
    368  * pEASData - pointer to overall EAS data structure
    369  *
    370  * Outputs:
    371  * number of samples actually written to buffer
    372  *
    373  * Side Effects:
    374  * - samples are added to the presently free buffer
    375  *
    376  *----------------------------------------------------------------------------
    377 */
    378 EAS_BOOL DLS_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples)
    379 {
    380     S_WT_VOICE *pWTVoice;
    381     S_SYNTH_CHANNEL *pChannel;
    382     const S_DLS_REGION *pDLSRegion;
    383     const S_DLS_ARTICULATION *pDLSArt;
    384     S_WT_INT_FRAME intFrame;
    385     EAS_I32 temp;
    386     EAS_BOOL done = EAS_FALSE;
    387 
    388     /* establish pointers to critical data */
    389     pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
    390     pDLSRegion = &pSynth->pDLS->pDLSRegions[pVoice->regionIndex & REGION_INDEX_MASK];
    391     pChannel = &pSynth->channels[pVoice->channel & 15];
    392     pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
    393 
    394     /* update the envelopes */
    395     DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg1, &pWTVoice->eg1Value, &pWTVoice->eg1Increment, &pWTVoice->eg1State);
    396     DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg2, &pWTVoice->eg2Value, &pWTVoice->eg2Increment, &pWTVoice->eg2State);
    397 
    398     /* update the LFOs using the EAS synth function */
    399     WT_UpdateLFO(&pWTVoice->modLFO, pDLSArt->modLFO.lfoFreq);
    400     WT_UpdateLFO(&pWTVoice->vibLFO, pDLSArt->vibLFO.lfoFreq);
    401 
    402     /* calculate base frequency */
    403     temp = pDLSArt->tuning + pChannel->staticPitch + pDLSRegion->wtRegion.tuning +
    404         (((EAS_I32) pVoice->note * (EAS_I32) pDLSArt->keyNumToPitch) >> 7);
    405 
    406     /* don't transpose rhythm channel */
    407     if ((pChannel ->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) == 0)
    408         temp += pSynth->globalTranspose * 100;
    409 
    410     /* calculate phase increment including modulation effects */
    411     intFrame.frame.phaseIncrement = DLS_UpdatePhaseInc(pWTVoice, pDLSArt, pChannel, temp);
    412 
    413     /* calculate gain including modulation effects */
    414     intFrame.frame.gainTarget = DLS_UpdateGain(pWTVoice, pDLSArt, pChannel, pDLSRegion->wtRegion.gain, pVoice->velocity);
    415     intFrame.prevGain = pVoice->gain;
    416 
    417     DLS_UpdateFilter(pVoice, pWTVoice, &intFrame, pChannel, pDLSArt);
    418 
    419     /* call into engine to generate samples */
    420     intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer;
    421     intFrame.pMixBuffer = pMixBuffer;
    422     intFrame.numSamples = numSamples;
    423     if (numSamples < 0)
    424         return EAS_FALSE;
    425 
    426     /* check for end of sample */
    427     if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd))
    428         done = WT_CheckSampleEnd(pWTVoice, &intFrame, EAS_FALSE);
    429 
    430     WT_ProcessVoice(pWTVoice, &intFrame);
    431 
    432     /* clear flag */
    433     pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
    434 
    435     /* if the update interval has elapsed, then force the current gain to the next
    436      * gain since we never actually reach the next gain when ramping -- we just get
    437      * very close to the target gain.
    438      */
    439     pVoice->gain = (EAS_I16) intFrame.frame.gainTarget;
    440 
    441     /* if voice has finished, set flag for voice manager */
    442     if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted))
    443         done = EAS_TRUE;
    444 
    445     return done;
    446 }
    447 
    448 /*----------------------------------------------------------------------------
    449  * DLS_UpdateEnvelope()
    450  *----------------------------------------------------------------------------
    451  * Purpose:
    452  * Synthesize a block of samples for the given voice.
    453  * Use linear interpolation.
    454  *
    455  * Inputs:
    456  * pEASData - pointer to overall EAS data structure
    457  *
    458  * Outputs:
    459  * number of samples actually written to buffer
    460  *
    461  * Side Effects:
    462  * - samples are added to the presently free buffer
    463  *
    464  *----------------------------------------------------------------------------
    465 */
    466 /*lint -esym(715, pChannel) pChannel not used in this instance */
    467 static void DLS_UpdateEnvelope (S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel,  const S_DLS_ENVELOPE *pEnvParams, EAS_I16 *pValue, EAS_I16 *pIncrement, EAS_U8 *pState)
    468 {
    469     EAS_I32 temp;
    470 
    471     switch (*pState)
    472     {
    473         /* initial state */
    474         case eEnvelopeStateInit:
    475             *pState = eEnvelopeStateDelay;
    476             *pValue = 0;
    477             *pIncrement = pEnvParams->delayTime;
    478             if (*pIncrement != 0)
    479                 return;
    480             /*lint -e{825} falls through to next case */
    481 
    482         case eEnvelopeStateDelay:
    483             if (*pIncrement)
    484             {
    485                 *pIncrement = *pIncrement - 1;
    486                 return;
    487             }
    488 
    489             /* calculate attack rate */
    490             *pState = eEnvelopeStateAttack;
    491             if (pEnvParams->attackTime != ZERO_TIME_IN_CENTS)
    492             {
    493                 /*lint -e{702} use shift for performance */
    494                 temp = pEnvParams->attackTime + ((pEnvParams->velToAttack * pVoice->velocity) >> 7);
    495                 *pIncrement = ConvertRate(temp);
    496                 return;
    497             }
    498 
    499             *pValue = SYNTH_FULL_SCALE_EG1_GAIN;
    500             /*lint -e{825} falls through to next case */
    501 
    502         case eEnvelopeStateAttack:
    503             if (*pValue < SYNTH_FULL_SCALE_EG1_GAIN)
    504             {
    505                 temp = *pValue + *pIncrement;
    506                 *pValue = (EAS_I16) (temp < SYNTH_FULL_SCALE_EG1_GAIN ? temp : SYNTH_FULL_SCALE_EG1_GAIN);
    507                 return;
    508             }
    509 
    510             /* calculate hold time */
    511             *pState = eEnvelopeStateHold;
    512             if (pEnvParams->holdTime != ZERO_TIME_IN_CENTS)
    513             {
    514                 /*lint -e{702} use shift for performance */
    515                 temp = pEnvParams->holdTime + ((pEnvParams->keyNumToHold * pVoice->note) >> 7);
    516                 *pIncrement = ConvertDelay(temp);
    517                 return;
    518             }
    519             else
    520                 *pIncrement = 0;
    521             /*lint -e{825} falls through to next case */
    522 
    523         case eEnvelopeStateHold:
    524             if (*pIncrement)
    525             {
    526                 *pIncrement = *pIncrement - 1;
    527                 return;
    528             }
    529 
    530             /* calculate decay rate */
    531             *pState = eEnvelopeStateDecay;
    532             if (pEnvParams->decayTime != ZERO_TIME_IN_CENTS)
    533             {
    534                 /*lint -e{702} use shift for performance */
    535                 temp = pEnvParams->decayTime + ((pEnvParams->keyNumToDecay * pVoice->note) >> 7);
    536                 *pIncrement = ConvertRate(temp);
    537                 return;
    538             }
    539 
    540 //          *pValue = pEnvParams->sustainLevel;
    541             /*lint -e{825} falls through to next case */
    542 
    543         case eEnvelopeStateDecay:
    544             if (*pValue > pEnvParams->sustainLevel)
    545             {
    546                 temp = *pValue - *pIncrement;
    547                 *pValue = (EAS_I16) (temp > pEnvParams->sustainLevel ? temp : pEnvParams->sustainLevel);
    548                 return;
    549             }
    550 
    551             *pState = eEnvelopeStateSustain;
    552             *pValue = pEnvParams->sustainLevel;
    553             /*lint -e{825} falls through to next case */
    554 
    555         case eEnvelopeStateSustain:
    556             return;
    557 
    558         case eEnvelopeStateRelease:
    559             temp = *pValue - *pIncrement;
    560             if (temp <= 0)
    561             {
    562                 *pState = eEnvelopeStateMuted;
    563                 *pValue = 0;
    564             }
    565             else
    566                 *pValue = (EAS_I16) temp;
    567             break;
    568 
    569         case eEnvelopeStateMuted:
    570             *pValue = 0;
    571             return;
    572 
    573         default:
    574             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Envelope in invalid state %d\n", *pState); */ }
    575             break;
    576     }
    577 }
    578 
    579