summaryrefslogtreecommitdiffstats
path: root/arm-wt-22k/lib_src/eas_dlssynth.c
diff options
context:
space:
mode:
Diffstat (limited to 'arm-wt-22k/lib_src/eas_dlssynth.c')
-rw-r--r--arm-wt-22k/lib_src/eas_dlssynth.c578
1 files changed, 578 insertions, 0 deletions
diff --git a/arm-wt-22k/lib_src/eas_dlssynth.c b/arm-wt-22k/lib_src/eas_dlssynth.c
new file mode 100644
index 0000000..c1fa1ef
--- /dev/null
+++ b/arm-wt-22k/lib_src/eas_dlssynth.c
@@ -0,0 +1,578 @@
+/*----------------------------------------------------------------------------
+ *
+ * File:
+ * eas_dlssynth.c
+ *
+ * Contents and purpose:
+ * Implements the Mobile DLS synthesizer.
+ *
+ * Copyright Sonic Network Inc. 2006
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *----------------------------------------------------------------------------
+ * Revision Control:
+ * $Revision: 795 $
+ * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
+ *----------------------------------------------------------------------------
+*/
+
+// includes
+#include "eas_data.h"
+#include "eas_report.h"
+#include "eas_host.h"
+#include "eas_math.h"
+#include "eas_synth_protos.h"
+#include "eas_wtsynth.h"
+#include "eas_pan.h"
+#include "eas_mdls.h"
+#include "eas_dlssynth.h"
+
+#ifdef _METRICS_ENABLED
+#include "eas_perf.h"
+#endif
+
+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);
+
+/*----------------------------------------------------------------------------
+ * DLS_MuteVoice()
+ *----------------------------------------------------------------------------
+ * Mute the voice using shutdown time from the DLS articulation data
+ *----------------------------------------------------------------------------
+*/
+void DLS_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
+{
+ S_WT_VOICE *pWTVoice;
+ const S_DLS_ARTICULATION *pDLSArt;
+
+ pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
+ pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
+
+ /* clear deferred action flags */
+ pVoice->voiceFlags &=
+ ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF |
+ VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF |
+ VOICE_FLAG_DEFER_MUTE);
+
+ /* set the envelope state */
+ pVoiceMgr->wtVoices[voiceNum].eg1State = eEnvelopeStateRelease;
+ pWTVoice->eg1Increment = pDLSArt->eg1ShutdownTime;
+ pVoiceMgr->wtVoices[voiceNum].eg2State = eEnvelopeStateRelease;
+ pWTVoice->eg2Increment = pDLSArt->eg2.releaseTime;
+}
+
+/*----------------------------------------------------------------------------
+ * DLS_ReleaseVoice()
+ *----------------------------------------------------------------------------
+ * Release the selected voice.
+ *----------------------------------------------------------------------------
+*/
+/*lint -esym(715, pVoice) standard API, pVoice may be used by other synthesizers */
+void DLS_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
+{
+ S_WT_VOICE *pWTVoice;
+ const S_DLS_ARTICULATION *pDLSArt;
+
+ pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
+ pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
+
+ /* if still in attack phase, convert units to log */
+ /*lint -e{732} eg1Value is never negative */
+ /*lint -e{703} use shift for performance */
+ if (pWTVoice->eg1State == eEnvelopeStateAttack)
+ pWTVoice->eg1Value = (EAS_I16) ((EAS_flog2(pWTVoice->eg1Value) << 1) + 2048);
+
+ /* release EG1 */
+ pWTVoice->eg1State = eEnvelopeStateRelease;
+ pWTVoice->eg1Increment = pDLSArt->eg1.releaseTime;
+
+ /* release EG2 */
+ pWTVoice->eg2State = eEnvelopeStateRelease;
+ pWTVoice->eg2Increment = pDLSArt->eg2.releaseTime;
+}
+
+/*----------------------------------------------------------------------------
+ * DLS_SustainPedal()
+ *----------------------------------------------------------------------------
+ * The sustain pedal was just depressed. If the voice is still
+ * above the sustain level, catch the voice and continue holding.
+ *----------------------------------------------------------------------------
+*/
+/*lint -esym(715, pChannel) pChannel reserved for future use */
+void DLS_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum)
+{
+ S_WT_VOICE *pWTVoice;
+ const S_DLS_ARTICULATION *pDLSArt;
+
+ pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
+ pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
+
+ /* don't catch the voice if below the sustain level */
+ if (pWTVoice->eg1Value < pDLSArt->eg1.sustainLevel)
+ return;
+
+ /* defer releasing this note until the damper pedal is off */
+ pWTVoice->eg1State = eEnvelopeStateDecay;
+ pVoice->voiceState = eVoiceStatePlay;
+ pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
+
+#ifdef _DEBUG_SYNTH
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "DLS_SustainPedal: defer note off because sustain pedal is on\n"); */ }
+#endif
+}
+
+/*----------------------------------------------------------------------------
+ * DLS_UpdatePhaseInc()
+ *----------------------------------------------------------------------------
+ * Calculate the oscillator phase increment for the next frame
+ *----------------------------------------------------------------------------
+*/
+static EAS_I32 DLS_UpdatePhaseInc (S_WT_VOICE *pWTVoice, const S_DLS_ARTICULATION *pDLSArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 pitchCents)
+{
+ EAS_I32 temp;
+
+ /* start with base mod LFO modulation */
+ temp = pDLSArt->modLFOToPitch;
+
+ /* add mod wheel effect */
+ /*lint -e{702} use shift for performance */
+ temp += ((pDLSArt->modLFOCC1ToPitch * pChannel->modWheel) >> 7);
+
+ /* add channel pressure effect */
+ /*lint -e{702} use shift for performance */
+ temp += ((pDLSArt->modLFOChanPressToPitch * pChannel->channelPressure) >> 7);
+
+ /* add total mod LFO effect */
+ pitchCents += FMUL_15x15(temp, pWTVoice->modLFO.lfoValue);
+
+ /* start with base vib LFO modulation */
+ temp = pDLSArt->vibLFOToPitch;
+
+ /* add mod wheel effect */
+ /*lint -e{702} use shift for performance */
+ temp += ((pDLSArt->vibLFOCC1ToPitch * pChannel->modWheel) >> 7);
+
+ /* add channel pressure effect */
+ /*lint -e{702} use shift for performance */
+ temp += ((pDLSArt->vibLFOChanPressToPitch * pChannel->channelPressure) >> 7);
+
+ /* add total vibrato LFO effect */
+ pitchCents += FMUL_15x15(temp, pWTVoice->vibLFO.lfoValue);
+
+ /* add EG2 effect */
+ pitchCents += FMUL_15x15(pDLSArt->eg2ToPitch, pWTVoice->eg2Value);
+
+ /* convert from cents to linear phase increment */
+ return EAS_Calculate2toX(pitchCents);
+}
+
+/*----------------------------------------------------------------------------
+ * DLS_UpdateGain()
+ *----------------------------------------------------------------------------
+ * Calculate the gain for the next frame
+ *----------------------------------------------------------------------------
+*/
+static EAS_I32 DLS_UpdateGain (S_WT_VOICE *pWTVoice, const S_DLS_ARTICULATION *pDLSArt, S_SYNTH_CHANNEL *pChannel, EAS_I32 gain, EAS_U8 velocity)
+{
+ EAS_I32 temp;
+
+ /* start with base mod LFO modulation */
+ temp = pDLSArt->modLFOToGain;
+
+ /* add mod wheel effect */
+ /*lint -e{702} use shift for performance */
+ temp += ((pDLSArt->modLFOCC1ToGain * pChannel->modWheel) >> 7);
+
+ /* add channel pressure effect */
+ /*lint -e{702} use shift for performance */
+ temp += ((pDLSArt->modLFOChanPressToGain * pChannel->channelPressure) >> 7);
+
+ /* add total mod LFO effect */
+ gain += FMUL_15x15(temp, pWTVoice->modLFO.lfoValue);
+ if (gain > 0)
+ gain = 0;
+
+ /* convert to linear gain including EG1 */
+ if (pWTVoice->eg1State != eEnvelopeStateAttack)
+ {
+ gain = (DLS_GAIN_FACTOR * gain) >> DLS_GAIN_SHIFT;
+ /*lint -e{702} use shift for performance */
+#if 1
+ gain += (pWTVoice->eg1Value - 32767) >> 1;
+ gain = EAS_LogToLinear16(gain);
+#else
+ gain = EAS_LogToLinear16(gain);
+ temp = EAS_LogToLinear16((pWTVoice->eg1Value - 32767) >> 1);
+ gain = FMUL_15x15(gain, temp);
+#endif
+ }
+ else
+ {
+ gain = (DLS_GAIN_FACTOR * gain) >> DLS_GAIN_SHIFT;
+ gain = EAS_LogToLinear16(gain);
+ gain = FMUL_15x15(gain, pWTVoice->eg1Value);
+ }
+
+ /* include MIDI channel gain */
+ gain = FMUL_15x15(gain, pChannel->staticGain);
+
+ /* include velocity */
+ if (pDLSArt->filterQandFlags & FLAG_DLS_VELOCITY_SENSITIVE)
+ {
+ temp = velocity << 8;
+ temp = FMUL_15x15(temp, temp);
+ gain = FMUL_15x15(gain, temp);
+ }
+
+ /* return gain */
+ return gain;
+}
+
+/*----------------------------------------------------------------------------
+ * DLS_UpdateFilter()
+ *----------------------------------------------------------------------------
+ * Update the Filter parameters
+ *----------------------------------------------------------------------------
+*/
+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)
+{
+ EAS_I32 cutoff;
+ EAS_I32 temp;
+
+ /* no need to calculate filter coefficients if it is bypassed */
+ if (pDLSArt->filterCutoff == DEFAULT_DLS_FILTER_CUTOFF_FREQUENCY)
+ {
+ pIntFrame->frame.k = 0;
+ return;
+ }
+
+ /* start with base cutoff frequency */
+ cutoff = pDLSArt->filterCutoff;
+
+ /* get base mod LFO modulation */
+ temp = pDLSArt->modLFOToFc;
+
+ /* add mod wheel effect */
+ /*lint -e{702} use shift for performance */
+ temp += ((pDLSArt->modLFOCC1ToFc * pChannel->modWheel) >> 7);
+
+ /* add channel pressure effect */
+ /*lint -e{702} use shift for performance */
+ temp += ((pDLSArt->modLFOChanPressToFc* pChannel->channelPressure) >> 7);
+
+ /* add total mod LFO effect */
+ cutoff += FMUL_15x15(temp, pWTVoice->modLFO.lfoValue);
+
+ /* add EG2 effect */
+ cutoff += FMUL_15x15(pWTVoice->eg2Value, pDLSArt->eg2ToFc);
+
+ /* add velocity effect */
+ /*lint -e{702} use shift for performance */
+ cutoff += (pVoice->velocity * pDLSArt->velToFc) >> 7;
+
+ /* add velocity effect */
+ /*lint -e{702} use shift for performance */
+ cutoff += (pVoice->note * pDLSArt->keyNumToFc) >> 7;
+
+ /* subtract the A5 offset and the sampling frequency */
+ cutoff -= FILTER_CUTOFF_FREQ_ADJUST + A5_PITCH_OFFSET_IN_CENTS;
+
+ /* limit the cutoff frequency */
+ if (cutoff > FILTER_CUTOFF_MAX_PITCH_CENTS)
+ cutoff = FILTER_CUTOFF_MAX_PITCH_CENTS;
+ else if (cutoff < FILTER_CUTOFF_MIN_PITCH_CENTS)
+ cutoff = FILTER_CUTOFF_MIN_PITCH_CENTS;
+
+ WT_SetFilterCoeffs(pIntFrame, cutoff, pDLSArt->filterQandFlags & FILTER_Q_MASK);
+}
+
+/*----------------------------------------------------------------------------
+ * DLS_StartVoice()
+ *----------------------------------------------------------------------------
+ * Start up a DLS voice
+ *----------------------------------------------------------------------------
+*/
+EAS_RESULT DLS_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex)
+{
+ S_WT_VOICE *pWTVoice;
+ const S_DLS_REGION *pDLSRegion;
+ const S_DLS_ARTICULATION *pDLSArt;
+ S_SYNTH_CHANNEL *pChannel;
+
+#ifdef _DEBUG_SYNTH
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "DLS_StartVoice: Voice %ld; Region %d\n", (EAS_I32) (pVoice - pVoiceMgr->voices), regionIndex); */ }
+#endif
+
+ pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
+ pChannel = &pSynth->channels[pVoice->channel & 15];
+ pDLSRegion = &pSynth->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK];
+ pWTVoice->artIndex = pDLSRegion->wtRegion.artIndex;
+ pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
+
+ /* initialize the envelopes */
+ pWTVoice->eg1State = eEnvelopeStateInit;
+ DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg1, &pWTVoice->eg1Value, &pWTVoice->eg1Increment, &pWTVoice->eg1State);
+ pWTVoice->eg2State = eEnvelopeStateInit;
+ DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg2, &pWTVoice->eg2Value, &pWTVoice->eg2Increment, &pWTVoice->eg2State);
+
+ /* initialize the LFOs */
+ pWTVoice->modLFO.lfoValue = 0;
+ pWTVoice->modLFO.lfoPhase = pDLSArt->modLFO.lfoDelay;
+ pWTVoice->vibLFO.lfoValue = 0;
+ pWTVoice->vibLFO.lfoPhase = pDLSArt->vibLFO.lfoDelay;
+
+ /* initalize the envelopes and calculate initial gain */
+ DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg1, &pWTVoice->eg1Value, &pWTVoice->eg1Increment, &pWTVoice->eg1State);
+ DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg2, &pWTVoice->eg2Value, &pWTVoice->eg2Increment, &pWTVoice->eg2State);
+ pVoice->gain = (EAS_I16) DLS_UpdateGain(pWTVoice, pDLSArt, pChannel, pDLSRegion->wtRegion.gain, pVoice->velocity);
+
+#if (NUM_OUTPUT_CHANNELS == 2)
+ EAS_CalcPanControl((EAS_INT) pChannel->pan - 64 + (EAS_INT) pDLSArt->pan, &pWTVoice->gainLeft, &pWTVoice->gainRight);
+#endif
+
+ /* initialize the filter states */
+ pWTVoice->filter.z1 = 0;
+ pWTVoice->filter.z2 = 0;
+
+ /* initialize the oscillator */
+ pWTVoice->phaseAccum = (EAS_U32) pSynth->pDLS->pDLSSamples + pSynth->pDLS->pDLSSampleOffsets[pDLSRegion->wtRegion.waveIndex];
+ if (pDLSRegion->wtRegion.region.keyGroupAndFlags & REGION_FLAG_IS_LOOPED)
+ {
+ pWTVoice->loopStart = pWTVoice->phaseAccum + pDLSRegion->wtRegion.loopStart;
+ pWTVoice->loopEnd = pWTVoice->phaseAccum + pDLSRegion->wtRegion.loopEnd - 1;
+ }
+ else
+ pWTVoice->loopStart = pWTVoice->loopEnd = pWTVoice->phaseAccum + pSynth->pDLS->pDLSSampleLen[pDLSRegion->wtRegion.waveIndex] - 1;
+
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * DLS_UpdateVoice()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Synthesize a block of samples for the given voice.
+ * Use linear interpolation.
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ *
+ * Outputs:
+ * number of samples actually written to buffer
+ *
+ * Side Effects:
+ * - samples are added to the presently free buffer
+ *
+ *----------------------------------------------------------------------------
+*/
+EAS_BOOL DLS_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples)
+{
+ S_WT_VOICE *pWTVoice;
+ S_SYNTH_CHANNEL *pChannel;
+ const S_DLS_REGION *pDLSRegion;
+ const S_DLS_ARTICULATION *pDLSArt;
+ S_WT_INT_FRAME intFrame;
+ EAS_I32 temp;
+ EAS_BOOL done = EAS_FALSE;
+
+ /* establish pointers to critical data */
+ pWTVoice = &pVoiceMgr->wtVoices[voiceNum];
+ pDLSRegion = &pSynth->pDLS->pDLSRegions[pVoice->regionIndex & REGION_INDEX_MASK];
+ pChannel = &pSynth->channels[pVoice->channel & 15];
+ pDLSArt = &pSynth->pDLS->pDLSArticulations[pWTVoice->artIndex];
+
+ /* update the envelopes */
+ DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg1, &pWTVoice->eg1Value, &pWTVoice->eg1Increment, &pWTVoice->eg1State);
+ DLS_UpdateEnvelope(pVoice, pChannel, &pDLSArt->eg2, &pWTVoice->eg2Value, &pWTVoice->eg2Increment, &pWTVoice->eg2State);
+
+ /* update the LFOs using the EAS synth function */
+ WT_UpdateLFO(&pWTVoice->modLFO, pDLSArt->modLFO.lfoFreq);
+ WT_UpdateLFO(&pWTVoice->vibLFO, pDLSArt->vibLFO.lfoFreq);
+
+ /* calculate base frequency */
+ temp = pDLSArt->tuning + pChannel->staticPitch + pDLSRegion->wtRegion.tuning +
+ (((EAS_I32) pVoice->note * (EAS_I32) pDLSArt->keyNumToPitch) >> 7);
+
+ /* don't transpose rhythm channel */
+ if ((pChannel ->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL) == 0)
+ temp += pSynth->globalTranspose * 100;
+
+ /* calculate phase increment including modulation effects */
+ intFrame.frame.phaseIncrement = DLS_UpdatePhaseInc(pWTVoice, pDLSArt, pChannel, temp);
+
+ /* calculate gain including modulation effects */
+ intFrame.frame.gainTarget = DLS_UpdateGain(pWTVoice, pDLSArt, pChannel, pDLSRegion->wtRegion.gain, pVoice->velocity);
+ intFrame.prevGain = pVoice->gain;
+
+ DLS_UpdateFilter(pVoice, pWTVoice, &intFrame, pChannel, pDLSArt);
+
+ /* call into engine to generate samples */
+ intFrame.pAudioBuffer = pVoiceMgr->voiceBuffer;
+ intFrame.pMixBuffer = pMixBuffer;
+ intFrame.numSamples = numSamples;
+ if (numSamples < 0)
+ return EAS_FALSE;
+
+ /* check for end of sample */
+ if ((pWTVoice->loopStart != WT_NOISE_GENERATOR) && (pWTVoice->loopStart == pWTVoice->loopEnd))
+ done = WT_CheckSampleEnd(pWTVoice, &intFrame, EAS_FALSE);
+
+ WT_ProcessVoice(pWTVoice, &intFrame);
+
+ /* clear flag */
+ pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
+
+ /* if the update interval has elapsed, then force the current gain to the next
+ * gain since we never actually reach the next gain when ramping -- we just get
+ * very close to the target gain.
+ */
+ pVoice->gain = (EAS_I16) intFrame.frame.gainTarget;
+
+ /* if voice has finished, set flag for voice manager */
+ if ((pVoice->voiceState != eVoiceStateStolen) && (pWTVoice->eg1State == eEnvelopeStateMuted))
+ done = EAS_TRUE;
+
+ return done;
+}
+
+/*----------------------------------------------------------------------------
+ * DLS_UpdateEnvelope()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Synthesize a block of samples for the given voice.
+ * Use linear interpolation.
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ *
+ * Outputs:
+ * number of samples actually written to buffer
+ *
+ * Side Effects:
+ * - samples are added to the presently free buffer
+ *
+ *----------------------------------------------------------------------------
+*/
+/*lint -esym(715, pChannel) pChannel not used in this instance */
+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)
+{
+ EAS_I32 temp;
+
+ switch (*pState)
+ {
+ /* initial state */
+ case eEnvelopeStateInit:
+ *pState = eEnvelopeStateDelay;
+ *pValue = 0;
+ *pIncrement = pEnvParams->delayTime;
+ if (*pIncrement != 0)
+ return;
+ /*lint -e{825} falls through to next case */
+
+ case eEnvelopeStateDelay:
+ if (*pIncrement)
+ {
+ *pIncrement = *pIncrement - 1;
+ return;
+ }
+
+ /* calculate attack rate */
+ *pState = eEnvelopeStateAttack;
+ if (pEnvParams->attackTime != ZERO_TIME_IN_CENTS)
+ {
+ /*lint -e{702} use shift for performance */
+ temp = pEnvParams->attackTime + ((pEnvParams->velToAttack * pVoice->velocity) >> 7);
+ *pIncrement = ConvertRate(temp);
+ return;
+ }
+
+ *pValue = SYNTH_FULL_SCALE_EG1_GAIN;
+ /*lint -e{825} falls through to next case */
+
+ case eEnvelopeStateAttack:
+ if (*pValue < SYNTH_FULL_SCALE_EG1_GAIN)
+ {
+ temp = *pValue + *pIncrement;
+ *pValue = (EAS_I16) (temp < SYNTH_FULL_SCALE_EG1_GAIN ? temp : SYNTH_FULL_SCALE_EG1_GAIN);
+ return;
+ }
+
+ /* calculate hold time */
+ *pState = eEnvelopeStateHold;
+ if (pEnvParams->holdTime != ZERO_TIME_IN_CENTS)
+ {
+ /*lint -e{702} use shift for performance */
+ temp = pEnvParams->holdTime + ((pEnvParams->keyNumToHold * pVoice->note) >> 7);
+ *pIncrement = ConvertDelay(temp);
+ return;
+ }
+ else
+ *pIncrement = 0;
+ /*lint -e{825} falls through to next case */
+
+ case eEnvelopeStateHold:
+ if (*pIncrement)
+ {
+ *pIncrement = *pIncrement - 1;
+ return;
+ }
+
+ /* calculate decay rate */
+ *pState = eEnvelopeStateDecay;
+ if (pEnvParams->decayTime != ZERO_TIME_IN_CENTS)
+ {
+ /*lint -e{702} use shift for performance */
+ temp = pEnvParams->decayTime + ((pEnvParams->keyNumToDecay * pVoice->note) >> 7);
+ *pIncrement = ConvertRate(temp);
+ return;
+ }
+
+// *pValue = pEnvParams->sustainLevel;
+ /*lint -e{825} falls through to next case */
+
+ case eEnvelopeStateDecay:
+ if (*pValue > pEnvParams->sustainLevel)
+ {
+ temp = *pValue - *pIncrement;
+ *pValue = (EAS_I16) (temp > pEnvParams->sustainLevel ? temp : pEnvParams->sustainLevel);
+ return;
+ }
+
+ *pState = eEnvelopeStateSustain;
+ *pValue = pEnvParams->sustainLevel;
+ /*lint -e{825} falls through to next case */
+
+ case eEnvelopeStateSustain:
+ return;
+
+ case eEnvelopeStateRelease:
+ temp = *pValue - *pIncrement;
+ if (temp <= 0)
+ {
+ *pState = eEnvelopeStateMuted;
+ *pValue = 0;
+ }
+ else
+ *pValue = (EAS_I16) temp;
+ break;
+
+ case eEnvelopeStateMuted:
+ *pValue = 0;
+ return;
+
+ default:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Envelope in invalid state %d\n", *pState); */ }
+ break;
+ }
+}
+