diff options
Diffstat (limited to 'arm-hybrid-22k/lib_src/eas_wtengine.c')
-rw-r--r-- | arm-hybrid-22k/lib_src/eas_wtengine.c | 1298 |
1 files changed, 649 insertions, 649 deletions
diff --git a/arm-hybrid-22k/lib_src/eas_wtengine.c b/arm-hybrid-22k/lib_src/eas_wtengine.c index 4215924..8407634 100644 --- a/arm-hybrid-22k/lib_src/eas_wtengine.c +++ b/arm-hybrid-22k/lib_src/eas_wtengine.c @@ -1,13 +1,13 @@ -/*----------------------------------------------------------------------------
- *
- * File:
- * eas_wtengine.c
- *
- * Contents and purpose:
- * This file contains the critical synthesizer components that need to
- * be optimized for best performance.
- *
- * Copyright Sonic Network Inc. 2004-2005
+/*---------------------------------------------------------------------------- + * + * File: + * eas_wtengine.c + * + * Contents and purpose: + * This file contains the critical synthesizer components that need to + * be optimized for best performance. + * + * Copyright Sonic Network Inc. 2004-2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,642 +20,642 @@ * 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: 844 $
- * $Date: 2007-08-23 14:33:32 -0700 (Thu, 23 Aug 2007) $
- *----------------------------------------------------------------------------
-*/
-
-/*------------------------------------
- * includes
- *------------------------------------
-*/
-#include "eas_types.h"
-#include "eas_math.h"
-#include "eas_audioconst.h"
-#include "eas_sndlib.h"
-#include "eas_wtengine.h"
-#include "eas_mixer.h"
-
-/*----------------------------------------------------------------------------
- * prototypes
- *----------------------------------------------------------------------------
-*/
-extern void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame);
-extern void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame);
-
-#if defined(_OPTIMIZED_MONO)
-extern void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame);
-#else
-extern void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame);
-extern void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame);
-#endif
-
-#if defined(_FILTER_ENABLED)
-extern void WT_VoiceFilter (S_FILTER_CONTROL*pFilter, S_WT_INT_FRAME *pWTIntFrame);
-#endif
-
-#if defined(_OPTIMIZED_MONO) || !defined(NATIVE_EAS_KERNEL)
-/*----------------------------------------------------------------------------
- * WT_VoiceGain
- *----------------------------------------------------------------------------
- * Purpose:
- * Output gain for individual voice
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pWTVoice) reserved for future use */
-void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame)
-{
- EAS_I32 *pMixBuffer;
- EAS_PCM *pInputBuffer;
- EAS_I32 gain;
- EAS_I32 gainIncrement;
- EAS_I32 tmp0;
- EAS_I32 tmp1;
- EAS_I32 tmp2;
- EAS_I32 numSamples;
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- EAS_I32 gainLeft, gainRight;
-#endif
-
- /* initialize some local variables */
- numSamples = pWTIntFrame->numSamples;
- pMixBuffer = pWTIntFrame->pMixBuffer;
- pInputBuffer = pWTIntFrame->pAudioBuffer;
-
- /*lint -e{703} <avoid multiply for performance>*/
- gainIncrement = (pWTIntFrame->frame.gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
- if (gainIncrement < 0)
- gainIncrement++;
- /*lint -e{703} <avoid multiply for performance>*/
- gain = pWTIntFrame->prevGain << 16;
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- gainLeft = pWTVoice->gainLeft;
- gainRight = pWTVoice->gainRight;
-#endif
-
- while (numSamples--) {
-
- /* incremental gain step to prevent zipper noise */
- tmp0 = *pInputBuffer++;
- gain += gainIncrement;
- /*lint -e{704} <avoid divide>*/
- tmp2 = gain >> 16;
-
- /* scale sample by gain */
- tmp2 *= tmp0;
-
-
- /* stereo output */
-#if (NUM_OUTPUT_CHANNELS == 2)
- /*lint -e{704} <avoid divide>*/
- tmp2 = tmp2 >> 14;
-
- /* get the current sample in the final mix buffer */
- tmp1 = *pMixBuffer;
-
- /* left channel */
- tmp0 = tmp2 * gainLeft;
- /*lint -e{704} <avoid divide>*/
- tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS;
- tmp1 += tmp0;
- *pMixBuffer++ = tmp1;
-
- /* get the current sample in the final mix buffer */
- tmp1 = *pMixBuffer;
-
- /* right channel */
- tmp0 = tmp2 * gainRight;
- /*lint -e{704} <avoid divide>*/
- tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS;
- tmp1 += tmp0;
- *pMixBuffer++ = tmp1;
-
- /* mono output */
-#else
-
- /* get the current sample in the final mix buffer */
- tmp1 = *pMixBuffer;
- /*lint -e{704} <avoid divide>*/
- tmp2 = tmp2 >> (NUM_MIXER_GUARD_BITS - 1);
- tmp1 += tmp2;
- *pMixBuffer++ = tmp1;
-#endif
-
- }
-}
-#endif
-
-#ifndef NATIVE_EAS_KERNEL
-/*----------------------------------------------------------------------------
- * WT_Interpolate
- *----------------------------------------------------------------------------
- * Purpose:
- * Interpolation engine for wavetable synth
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame)
-{
- EAS_PCM *pOutputBuffer;
- EAS_I32 phaseInc;
- EAS_I32 phaseFrac;
- EAS_I32 acc0;
- const EAS_SAMPLE *pSamples;
- const EAS_SAMPLE *loopEnd;
- EAS_I32 samp1;
- EAS_I32 samp2;
- EAS_I32 numSamples;
-
- /* initialize some local variables */
- numSamples = pWTIntFrame->numSamples;
- pOutputBuffer = pWTIntFrame->pAudioBuffer;
-
- loopEnd = (const EAS_SAMPLE*) pWTVoice->loopEnd + 1;
- pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum;
- /*lint -e{713} truncation is OK */
- phaseFrac = pWTVoice->phaseFrac;
- phaseInc = pWTIntFrame->frame.phaseIncrement;
-
- /* fetch adjacent samples */
-#if defined(_8_BIT_SAMPLES)
- /*lint -e{701} <avoid multiply for performance>*/
- samp1 = pSamples[0] << 8;
- /*lint -e{701} <avoid multiply for performance>*/
- samp2 = pSamples[1] << 8;
-#else
- samp1 = pSamples[0];
- samp2 = pSamples[1];
-#endif
-
- while (numSamples--) {
-
- /* linear interpolation */
- acc0 = samp2 - samp1;
- acc0 = acc0 * phaseFrac;
- /*lint -e{704} <avoid divide>*/
- acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS);
-
- /* save new output sample in buffer */
- /*lint -e{704} <avoid divide>*/
- *pOutputBuffer++ = (EAS_I16)(acc0 >> 2);
-
- /* increment phase */
- phaseFrac += phaseInc;
- /*lint -e{704} <avoid divide>*/
- acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS;
-
- /* next sample */
- if (acc0 > 0) {
-
- /* advance sample pointer */
- pSamples += acc0;
- phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK);
-
- /* check for loop end */
- acc0 = (EAS_I32) (pSamples - loopEnd);
- if (acc0 >= 0)
- pSamples = (const EAS_SAMPLE*) pWTVoice->loopStart + acc0;
-
- /* fetch new samples */
-#if defined(_8_BIT_SAMPLES)
- /*lint -e{701} <avoid multiply for performance>*/
- samp1 = pSamples[0] << 8;
- /*lint -e{701} <avoid multiply for performance>*/
- samp2 = pSamples[1] << 8;
-#else
- samp1 = pSamples[0];
- samp2 = pSamples[1];
-#endif
- }
- }
-
- /* save pointer and phase */
- pWTVoice->phaseAccum = (EAS_U32) pSamples;
- pWTVoice->phaseFrac = (EAS_U32) phaseFrac;
-}
-#endif
-
-#ifndef NATIVE_EAS_KERNEL
-/*----------------------------------------------------------------------------
- * WT_InterpolateNoLoop
- *----------------------------------------------------------------------------
- * Purpose:
- * Interpolation engine for wavetable synth
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame)
-{
- EAS_PCM *pOutputBuffer;
- EAS_I32 phaseInc;
- EAS_I32 phaseFrac;
- EAS_I32 acc0;
- const EAS_SAMPLE *pSamples;
- EAS_I32 samp1;
- EAS_I32 samp2;
- EAS_I32 numSamples;
-
- /* initialize some local variables */
- numSamples = pWTIntFrame->numSamples;
- pOutputBuffer = pWTIntFrame->pAudioBuffer;
-
- phaseInc = pWTIntFrame->frame.phaseIncrement;
- pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum;
- phaseFrac = (EAS_I32)pWTVoice->phaseFrac;
-
- /* fetch adjacent samples */
-#if defined(_8_BIT_SAMPLES)
- /*lint -e{701} <avoid multiply for performance>*/
- samp1 = pSamples[0] << 8;
- /*lint -e{701} <avoid multiply for performance>*/
- samp2 = pSamples[1] << 8;
-#else
- samp1 = pSamples[0];
- samp2 = pSamples[1];
-#endif
-
- while (numSamples--) {
-
-
- /* linear interpolation */
- acc0 = samp2 - samp1;
- acc0 = acc0 * phaseFrac;
- /*lint -e{704} <avoid divide>*/
- acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS);
-
- /* save new output sample in buffer */
- /*lint -e{704} <avoid divide>*/
- *pOutputBuffer++ = (EAS_I16)(acc0 >> 2);
-
- /* increment phase */
- phaseFrac += phaseInc;
- /*lint -e{704} <avoid divide>*/
- acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS;
-
- /* next sample */
- if (acc0 > 0) {
-
- /* advance sample pointer */
- pSamples += acc0;
- phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK);
-
- /* fetch new samples */
-#if defined(_8_BIT_SAMPLES)
- /*lint -e{701} <avoid multiply for performance>*/
- samp1 = pSamples[0] << 8;
- /*lint -e{701} <avoid multiply for performance>*/
- samp2 = pSamples[1] << 8;
-#else
- samp1 = pSamples[0];
- samp2 = pSamples[1];
-#endif
- }
- }
-
- /* save pointer and phase */
- pWTVoice->phaseAccum = (EAS_U32) pSamples;
- pWTVoice->phaseFrac = (EAS_U32) phaseFrac;
-}
-#endif
-
-#if defined(_FILTER_ENABLED) && !defined(NATIVE_EAS_KERNEL)
-/*----------------------------------------------------------------------------
- * WT_VoiceFilter
- *----------------------------------------------------------------------------
- * Purpose:
- * Implements a 2-pole filter
- *
- * Inputs:
- *
- * Outputs:
- *
- *----------------------------------------------------------------------------
-*/
-void WT_VoiceFilter (S_FILTER_CONTROL *pFilter, S_WT_INT_FRAME *pWTIntFrame)
-{
- EAS_PCM *pAudioBuffer;
- EAS_I32 k;
- EAS_I32 b1;
- EAS_I32 b2;
- EAS_I32 z1;
- EAS_I32 z2;
- EAS_I32 acc0;
- EAS_I32 acc1;
- EAS_I32 numSamples;
-
- /* initialize some local variables */
- numSamples = pWTIntFrame->numSamples;
- pAudioBuffer = pWTIntFrame->pAudioBuffer;
-
- z1 = pFilter->z1;
- z2 = pFilter->z2;
- b1 = -pWTIntFrame->frame.b1;
-
- /*lint -e{702} <avoid divide> */
- b2 = -pWTIntFrame->frame.b2 >> 1;
-
- /*lint -e{702} <avoid divide> */
- k = pWTIntFrame->frame.k >> 1;
-
- while (numSamples--)
- {
-
- /* do filter calculations */
- acc0 = *pAudioBuffer;
- acc1 = z1 * b1;
- acc1 += z2 * b2;
- acc0 = acc1 + k * acc0;
- z2 = z1;
-
- /*lint -e{702} <avoid divide> */
- z1 = acc0 >> 14;
- *pAudioBuffer++ = (EAS_I16) z1;
- }
-
- /* save delay values */
- pFilter->z1 = (EAS_I16) z1;
- pFilter->z2 = (EAS_I16) z2;
-}
-#endif
-
-/*----------------------------------------------------------------------------
- * WT_NoiseGenerator
- *----------------------------------------------------------------------------
- * Purpose:
- * Generate pseudo-white noise using PRNG and interpolation engine
- *
- * Inputs:
- *
- * Outputs:
- *
- * Notes:
- * This output is scaled -12dB to prevent saturation in the filter. For a
- * high quality synthesizer, the output can be set to full scale, however
- * if the filter is used, it can overflow with certain coefficients. In this
- * case, either a saturation operation should take in the filter before
- * scaling back to 16 bits or the signal path should be increased to 18 bits
- * or more.
- *----------------------------------------------------------------------------
-*/
- void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame)
- {
- EAS_PCM *pOutputBuffer;
- EAS_I32 phaseInc;
- EAS_I32 tmp0;
- EAS_I32 tmp1;
- EAS_I32 nInterpolatedSample;
- EAS_I32 numSamples;
-
- /* initialize some local variables */
- numSamples = pWTIntFrame->numSamples;
- pOutputBuffer = pWTIntFrame->pAudioBuffer;
- phaseInc = pWTIntFrame->frame.phaseIncrement;
-
- /* get last two samples generated */
- /*lint -e{704} <avoid divide for performance>*/
- tmp0 = (EAS_I32) (pWTVoice->phaseAccum) >> 18;
- /*lint -e{704} <avoid divide for performance>*/
- tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18;
-
- /* generate a buffer of noise */
- while (numSamples--) {
- nInterpolatedSample = MULT_AUDIO_COEF( tmp0, (PHASE_ONE - pWTVoice->phaseFrac));
- nInterpolatedSample += MULT_AUDIO_COEF( tmp1, pWTVoice->phaseFrac);
- *pOutputBuffer++ = (EAS_PCM) nInterpolatedSample;
-
- /* update PRNG */
- pWTVoice->phaseFrac += (EAS_U32) phaseInc;
- if (GET_PHASE_INT_PART(pWTVoice->phaseFrac)) {
- tmp0 = tmp1;
- pWTVoice->phaseAccum = pWTVoice->loopEnd;
- pWTVoice->loopEnd = (5 * pWTVoice->loopEnd + 1);
- tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18;
- pWTVoice->phaseFrac = GET_PHASE_FRAC_PART(pWTVoice->phaseFrac);
- }
-
- }
-}
-
-#ifndef _OPTIMIZED_MONO
-/*----------------------------------------------------------------------------
- * WT_ProcessVoice
- *----------------------------------------------------------------------------
- * Purpose:
- * This routine does the block processing for one voice. It is isolated
- * from the main synth code to allow for various implementation-specific
- * optimizations. It calls the interpolator, filter, and gain routines
- * appropriate for a particular configuration.
- *
- * Inputs:
- *
- * Outputs:
- *
- * Notes:
- *----------------------------------------------------------------------------
-*/
-void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame)
-{
-
- /* use noise generator */
- if (pWTVoice->loopStart == WT_NOISE_GENERATOR)
- WT_NoiseGenerator(pWTVoice, pWTIntFrame);
-
- /* generate interpolated samples for looped waves */
- else if (pWTVoice->loopStart != pWTVoice->loopEnd)
- WT_Interpolate(pWTVoice, pWTIntFrame);
-
- /* generate interpolated samples for unlooped waves */
- else
- {
- WT_InterpolateNoLoop(pWTVoice, pWTIntFrame);
- }
-
-#ifdef _FILTER_ENABLED
- if (pWTIntFrame->frame.k != 0)
- WT_VoiceFilter(&pWTVoice->filter, pWTIntFrame);
-#endif
-
-//2 TEST NEW MIXER FUNCTION
-#ifdef UNIFIED_MIXER
- {
- EAS_I32 gainLeft, gainIncLeft;
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- EAS_I32 gainRight, gainIncRight;
-#endif
-
- gainLeft = (pWTIntFrame->prevGain * pWTVoice->gainLeft) << 1;
- gainIncLeft = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainLeft) << 1) - gainLeft) >> SYNTH_UPDATE_PERIOD_IN_BITS;
-
-#if (NUM_OUTPUT_CHANNELS == 2)
- gainRight = (pWTIntFrame->prevGain * pWTVoice->gainRight) << 1;
- gainIncRight = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainRight) << 1) - gainRight) >> SYNTH_UPDATE_PERIOD_IN_BITS;
- EAS_MixStream(
- pWTIntFrame->pAudioBuffer,
- pWTIntFrame->pMixBuffer,
- pWTIntFrame->numSamples,
- gainLeft,
- gainRight,
- gainIncLeft,
- gainIncRight,
- MIX_FLAGS_STEREO_OUTPUT);
-
-#else
- EAS_MixStream(
- pWTIntFrame->pAudioBuffer,
- pWTIntFrame->pMixBuffer,
- pWTIntFrame->numSamples,
- gainLeft,
- 0,
- gainIncLeft,
- 0,
- 0);
-#endif
- }
-
-#else
- /* apply gain, and left and right gain */
- WT_VoiceGain(pWTVoice, pWTIntFrame);
-#endif
-}
-#endif
-
-#if defined(_OPTIMIZED_MONO) && !defined(NATIVE_EAS_KERNEL)
-/*----------------------------------------------------------------------------
- * WT_InterpolateMono
- *----------------------------------------------------------------------------
- * Purpose:
- * A C version of the sample interpolation + gain routine, optimized for mono.
- * It's not pretty, but it matches the assembly code exactly.
- *
- * Inputs:
- *
- * Outputs:
- *
- * Notes:
- *----------------------------------------------------------------------------
-*/
-void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame)
-{
- EAS_I32 *pMixBuffer;
- const EAS_I8 *pLoopEnd;
- const EAS_I8 *pCurrentPhaseInt;
- EAS_I32 numSamples;
- EAS_I32 gain;
- EAS_I32 gainIncrement;
- EAS_I32 currentPhaseFrac;
- EAS_I32 phaseInc;
- EAS_I32 tmp0;
- EAS_I32 tmp1;
- EAS_I32 tmp2;
- EAS_I8 *pLoopStart;
-
- numSamples = pWTIntFrame->numSamples;
- pMixBuffer = pWTIntFrame->pMixBuffer;
-
- /* calculate gain increment */
- gainIncrement = (pWTIntFrame->gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
- if (gainIncrement < 0)
- gainIncrement++;
- gain = pWTIntFrame->prevGain << 16;
-
- pCurrentPhaseInt = pWTVoice->pPhaseAccum;
- currentPhaseFrac = pWTVoice->phaseFrac;
- phaseInc = pWTIntFrame->phaseIncrement;
-
- pLoopStart = pWTVoice->pLoopStart;
- pLoopEnd = pWTVoice->pLoopEnd + 1;
-
-InterpolationLoop:
- tmp0 = (EAS_I32)(pCurrentPhaseInt - pLoopEnd);
- if (tmp0 >= 0)
- pCurrentPhaseInt = pLoopStart + tmp0;
-
- tmp0 = *pCurrentPhaseInt;
- tmp1 = *(pCurrentPhaseInt + 1);
-
- tmp2 = phaseInc + currentPhaseFrac;
-
- tmp1 = tmp1 - tmp0;
- tmp1 = tmp1 * currentPhaseFrac;
-
- tmp1 = tmp0 + (tmp1 >> NUM_EG1_FRAC_BITS);
-
- pCurrentPhaseInt += (tmp2 >> NUM_PHASE_FRAC_BITS);
- currentPhaseFrac = tmp2 & PHASE_FRAC_MASK;
-
- gain += gainIncrement;
- tmp2 = (gain >> SYNTH_UPDATE_PERIOD_IN_BITS);
-
- tmp0 = *pMixBuffer;
- tmp2 = tmp1 * tmp2;
- tmp2 = (tmp2 >> 9);
- tmp0 = tmp2 + tmp0;
- *pMixBuffer++ = tmp0;
-
- numSamples--;
- if (numSamples)
- goto InterpolationLoop;
-
- pWTVoice->pPhaseAccum = pCurrentPhaseInt;
- pWTVoice->phaseFrac = currentPhaseFrac;
- /*lint -e{702} <avoid divide>*/
- pWTVoice->gain = (EAS_I16)(gain >> SYNTH_UPDATE_PERIOD_IN_BITS);
-}
-#endif
-
-#ifdef _OPTIMIZED_MONO
-/*----------------------------------------------------------------------------
- * WT_ProcessVoice
- *----------------------------------------------------------------------------
- * Purpose:
- * This routine does the block processing for one voice. It is isolated
- * from the main synth code to allow for various implementation-specific
- * optimizations. It calls the interpolator, filter, and gain routines
- * appropriate for a particular configuration.
- *
- * Inputs:
- *
- * Outputs:
- *
- * Notes:
- * This special version works handles an optimized mono-only signal
- * without filters
- *----------------------------------------------------------------------------
-*/
-void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame)
-{
-
- /* use noise generator */
- if (pWTVoice->loopStart== WT_NOISE_GENERATOR)
- {
- WT_NoiseGenerator(pWTVoice, pWTIntFrame);
- WT_VoiceGain(pWTVoice, pWTIntFrame);
- }
-
- /* or generate interpolated samples */
- else
- {
- WT_InterpolateMono(pWTVoice, pWTIntFrame);
- }
-}
-#endif
-
+ * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 844 $ + * $Date: 2007-08-23 14:33:32 -0700 (Thu, 23 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +/*------------------------------------ + * includes + *------------------------------------ +*/ +#include "eas_types.h" +#include "eas_math.h" +#include "eas_audioconst.h" +#include "eas_sndlib.h" +#include "eas_wtengine.h" +#include "eas_mixer.h" + +/*---------------------------------------------------------------------------- + * prototypes + *---------------------------------------------------------------------------- +*/ +extern void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +extern void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); + +#if defined(_OPTIMIZED_MONO) +extern void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +#else +extern void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +extern void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame); +#endif + +#if defined(_FILTER_ENABLED) +extern void WT_VoiceFilter (S_FILTER_CONTROL*pFilter, S_WT_INT_FRAME *pWTIntFrame); +#endif + +#if defined(_OPTIMIZED_MONO) || !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_VoiceGain + *---------------------------------------------------------------------------- + * Purpose: + * Output gain for individual voice + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pWTVoice) reserved for future use */ +void WT_VoiceGain (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_I32 *pMixBuffer; + EAS_PCM *pInputBuffer; + EAS_I32 gain; + EAS_I32 gainIncrement; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 tmp2; + EAS_I32 numSamples; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainLeft, gainRight; +#endif + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pMixBuffer = pWTIntFrame->pMixBuffer; + pInputBuffer = pWTIntFrame->pAudioBuffer; + + /*lint -e{703} <avoid multiply for performance>*/ + gainIncrement = (pWTIntFrame->frame.gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + if (gainIncrement < 0) + gainIncrement++; + /*lint -e{703} <avoid multiply for performance>*/ + gain = pWTIntFrame->prevGain << 16; + +#if (NUM_OUTPUT_CHANNELS == 2) + gainLeft = pWTVoice->gainLeft; + gainRight = pWTVoice->gainRight; +#endif + + while (numSamples--) { + + /* incremental gain step to prevent zipper noise */ + tmp0 = *pInputBuffer++; + gain += gainIncrement; + /*lint -e{704} <avoid divide>*/ + tmp2 = gain >> 16; + + /* scale sample by gain */ + tmp2 *= tmp0; + + + /* stereo output */ +#if (NUM_OUTPUT_CHANNELS == 2) + /*lint -e{704} <avoid divide>*/ + tmp2 = tmp2 >> 14; + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + + /* left channel */ + tmp0 = tmp2 * gainLeft; + /*lint -e{704} <avoid divide>*/ + tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; + tmp1 += tmp0; + *pMixBuffer++ = tmp1; + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + + /* right channel */ + tmp0 = tmp2 * gainRight; + /*lint -e{704} <avoid divide>*/ + tmp0 = tmp0 >> NUM_MIXER_GUARD_BITS; + tmp1 += tmp0; + *pMixBuffer++ = tmp1; + + /* mono output */ +#else + + /* get the current sample in the final mix buffer */ + tmp1 = *pMixBuffer; + /*lint -e{704} <avoid divide>*/ + tmp2 = tmp2 >> (NUM_MIXER_GUARD_BITS - 1); + tmp1 += tmp2; + *pMixBuffer++ = tmp1; +#endif + + } +} +#endif + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * WT_Interpolate + *---------------------------------------------------------------------------- + * Purpose: + * Interpolation engine for wavetable synth + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_Interpolate (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 phaseFrac; + EAS_I32 acc0; + const EAS_SAMPLE *pSamples; + const EAS_SAMPLE *loopEnd; + EAS_I32 samp1; + EAS_I32 samp2; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + + loopEnd = (const EAS_SAMPLE*) pWTVoice->loopEnd + 1; + pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; + /*lint -e{713} truncation is OK */ + phaseFrac = pWTVoice->phaseFrac; + phaseInc = pWTIntFrame->frame.phaseIncrement; + + /* fetch adjacent samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} <avoid multiply for performance>*/ + samp1 = pSamples[0] << 8; + /*lint -e{701} <avoid multiply for performance>*/ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + + while (numSamples--) { + + /* linear interpolation */ + acc0 = samp2 - samp1; + acc0 = acc0 * phaseFrac; + /*lint -e{704} <avoid divide>*/ + acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); + + /* save new output sample in buffer */ + /*lint -e{704} <avoid divide>*/ + *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); + + /* increment phase */ + phaseFrac += phaseInc; + /*lint -e{704} <avoid divide>*/ + acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; + + /* next sample */ + if (acc0 > 0) { + + /* advance sample pointer */ + pSamples += acc0; + phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); + + /* check for loop end */ + acc0 = (EAS_I32) (pSamples - loopEnd); + if (acc0 >= 0) + pSamples = (const EAS_SAMPLE*) pWTVoice->loopStart + acc0; + + /* fetch new samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} <avoid multiply for performance>*/ + samp1 = pSamples[0] << 8; + /*lint -e{701} <avoid multiply for performance>*/ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + } + } + + /* save pointer and phase */ + pWTVoice->phaseAccum = (EAS_U32) pSamples; + pWTVoice->phaseFrac = (EAS_U32) phaseFrac; +} +#endif + +#ifndef NATIVE_EAS_KERNEL +/*---------------------------------------------------------------------------- + * WT_InterpolateNoLoop + *---------------------------------------------------------------------------- + * Purpose: + * Interpolation engine for wavetable synth + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_InterpolateNoLoop (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 phaseFrac; + EAS_I32 acc0; + const EAS_SAMPLE *pSamples; + EAS_I32 samp1; + EAS_I32 samp2; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + + phaseInc = pWTIntFrame->frame.phaseIncrement; + pSamples = (const EAS_SAMPLE*) pWTVoice->phaseAccum; + phaseFrac = (EAS_I32)pWTVoice->phaseFrac; + + /* fetch adjacent samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} <avoid multiply for performance>*/ + samp1 = pSamples[0] << 8; + /*lint -e{701} <avoid multiply for performance>*/ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + + while (numSamples--) { + + + /* linear interpolation */ + acc0 = samp2 - samp1; + acc0 = acc0 * phaseFrac; + /*lint -e{704} <avoid divide>*/ + acc0 = samp1 + (acc0 >> NUM_PHASE_FRAC_BITS); + + /* save new output sample in buffer */ + /*lint -e{704} <avoid divide>*/ + *pOutputBuffer++ = (EAS_I16)(acc0 >> 2); + + /* increment phase */ + phaseFrac += phaseInc; + /*lint -e{704} <avoid divide>*/ + acc0 = phaseFrac >> NUM_PHASE_FRAC_BITS; + + /* next sample */ + if (acc0 > 0) { + + /* advance sample pointer */ + pSamples += acc0; + phaseFrac = (EAS_I32)((EAS_U32)phaseFrac & PHASE_FRAC_MASK); + + /* fetch new samples */ +#if defined(_8_BIT_SAMPLES) + /*lint -e{701} <avoid multiply for performance>*/ + samp1 = pSamples[0] << 8; + /*lint -e{701} <avoid multiply for performance>*/ + samp2 = pSamples[1] << 8; +#else + samp1 = pSamples[0]; + samp2 = pSamples[1]; +#endif + } + } + + /* save pointer and phase */ + pWTVoice->phaseAccum = (EAS_U32) pSamples; + pWTVoice->phaseFrac = (EAS_U32) phaseFrac; +} +#endif + +#if defined(_FILTER_ENABLED) && !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_VoiceFilter + *---------------------------------------------------------------------------- + * Purpose: + * Implements a 2-pole filter + * + * Inputs: + * + * Outputs: + * + *---------------------------------------------------------------------------- +*/ +void WT_VoiceFilter (S_FILTER_CONTROL *pFilter, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_PCM *pAudioBuffer; + EAS_I32 k; + EAS_I32 b1; + EAS_I32 b2; + EAS_I32 z1; + EAS_I32 z2; + EAS_I32 acc0; + EAS_I32 acc1; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pAudioBuffer = pWTIntFrame->pAudioBuffer; + + z1 = pFilter->z1; + z2 = pFilter->z2; + b1 = -pWTIntFrame->frame.b1; + + /*lint -e{702} <avoid divide> */ + b2 = -pWTIntFrame->frame.b2 >> 1; + + /*lint -e{702} <avoid divide> */ + k = pWTIntFrame->frame.k >> 1; + + while (numSamples--) + { + + /* do filter calculations */ + acc0 = *pAudioBuffer; + acc1 = z1 * b1; + acc1 += z2 * b2; + acc0 = acc1 + k * acc0; + z2 = z1; + + /*lint -e{702} <avoid divide> */ + z1 = acc0 >> 14; + *pAudioBuffer++ = (EAS_I16) z1; + } + + /* save delay values */ + pFilter->z1 = (EAS_I16) z1; + pFilter->z2 = (EAS_I16) z2; +} +#endif + +/*---------------------------------------------------------------------------- + * WT_NoiseGenerator + *---------------------------------------------------------------------------- + * Purpose: + * Generate pseudo-white noise using PRNG and interpolation engine + * + * Inputs: + * + * Outputs: + * + * Notes: + * This output is scaled -12dB to prevent saturation in the filter. For a + * high quality synthesizer, the output can be set to full scale, however + * if the filter is used, it can overflow with certain coefficients. In this + * case, either a saturation operation should take in the filter before + * scaling back to 16 bits or the signal path should be increased to 18 bits + * or more. + *---------------------------------------------------------------------------- +*/ + void WT_NoiseGenerator (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) + { + EAS_PCM *pOutputBuffer; + EAS_I32 phaseInc; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 nInterpolatedSample; + EAS_I32 numSamples; + + /* initialize some local variables */ + numSamples = pWTIntFrame->numSamples; + pOutputBuffer = pWTIntFrame->pAudioBuffer; + phaseInc = pWTIntFrame->frame.phaseIncrement; + + /* get last two samples generated */ + /*lint -e{704} <avoid divide for performance>*/ + tmp0 = (EAS_I32) (pWTVoice->phaseAccum) >> 18; + /*lint -e{704} <avoid divide for performance>*/ + tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; + + /* generate a buffer of noise */ + while (numSamples--) { + nInterpolatedSample = MULT_AUDIO_COEF( tmp0, (PHASE_ONE - pWTVoice->phaseFrac)); + nInterpolatedSample += MULT_AUDIO_COEF( tmp1, pWTVoice->phaseFrac); + *pOutputBuffer++ = (EAS_PCM) nInterpolatedSample; + + /* update PRNG */ + pWTVoice->phaseFrac += (EAS_U32) phaseInc; + if (GET_PHASE_INT_PART(pWTVoice->phaseFrac)) { + tmp0 = tmp1; + pWTVoice->phaseAccum = pWTVoice->loopEnd; + pWTVoice->loopEnd = (5 * pWTVoice->loopEnd + 1); + tmp1 = (EAS_I32) (pWTVoice->loopEnd) >> 18; + pWTVoice->phaseFrac = GET_PHASE_FRAC_PART(pWTVoice->phaseFrac); + } + + } +} + +#ifndef _OPTIMIZED_MONO +/*---------------------------------------------------------------------------- + * WT_ProcessVoice + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the block processing for one voice. It is isolated + * from the main synth code to allow for various implementation-specific + * optimizations. It calls the interpolator, filter, and gain routines + * appropriate for a particular configuration. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + + /* use noise generator */ + if (pWTVoice->loopStart == WT_NOISE_GENERATOR) + WT_NoiseGenerator(pWTVoice, pWTIntFrame); + + /* generate interpolated samples for looped waves */ + else if (pWTVoice->loopStart != pWTVoice->loopEnd) + WT_Interpolate(pWTVoice, pWTIntFrame); + + /* generate interpolated samples for unlooped waves */ + else + { + WT_InterpolateNoLoop(pWTVoice, pWTIntFrame); + } + +#ifdef _FILTER_ENABLED + if (pWTIntFrame->frame.k != 0) + WT_VoiceFilter(&pWTVoice->filter, pWTIntFrame); +#endif + +//2 TEST NEW MIXER FUNCTION +#ifdef UNIFIED_MIXER + { + EAS_I32 gainLeft, gainIncLeft; + +#if (NUM_OUTPUT_CHANNELS == 2) + EAS_I32 gainRight, gainIncRight; +#endif + + gainLeft = (pWTIntFrame->prevGain * pWTVoice->gainLeft) << 1; + gainIncLeft = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainLeft) << 1) - gainLeft) >> SYNTH_UPDATE_PERIOD_IN_BITS; + +#if (NUM_OUTPUT_CHANNELS == 2) + gainRight = (pWTIntFrame->prevGain * pWTVoice->gainRight) << 1; + gainIncRight = (((pWTIntFrame->frame.gainTarget * pWTVoice->gainRight) << 1) - gainRight) >> SYNTH_UPDATE_PERIOD_IN_BITS; + EAS_MixStream( + pWTIntFrame->pAudioBuffer, + pWTIntFrame->pMixBuffer, + pWTIntFrame->numSamples, + gainLeft, + gainRight, + gainIncLeft, + gainIncRight, + MIX_FLAGS_STEREO_OUTPUT); + +#else + EAS_MixStream( + pWTIntFrame->pAudioBuffer, + pWTIntFrame->pMixBuffer, + pWTIntFrame->numSamples, + gainLeft, + 0, + gainIncLeft, + 0, + 0); +#endif + } + +#else + /* apply gain, and left and right gain */ + WT_VoiceGain(pWTVoice, pWTIntFrame); +#endif +} +#endif + +#if defined(_OPTIMIZED_MONO) && !defined(NATIVE_EAS_KERNEL) +/*---------------------------------------------------------------------------- + * WT_InterpolateMono + *---------------------------------------------------------------------------- + * Purpose: + * A C version of the sample interpolation + gain routine, optimized for mono. + * It's not pretty, but it matches the assembly code exactly. + * + * Inputs: + * + * Outputs: + * + * Notes: + *---------------------------------------------------------------------------- +*/ +void WT_InterpolateMono (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + EAS_I32 *pMixBuffer; + const EAS_I8 *pLoopEnd; + const EAS_I8 *pCurrentPhaseInt; + EAS_I32 numSamples; + EAS_I32 gain; + EAS_I32 gainIncrement; + EAS_I32 currentPhaseFrac; + EAS_I32 phaseInc; + EAS_I32 tmp0; + EAS_I32 tmp1; + EAS_I32 tmp2; + EAS_I8 *pLoopStart; + + numSamples = pWTIntFrame->numSamples; + pMixBuffer = pWTIntFrame->pMixBuffer; + + /* calculate gain increment */ + gainIncrement = (pWTIntFrame->gainTarget - pWTIntFrame->prevGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS); + if (gainIncrement < 0) + gainIncrement++; + gain = pWTIntFrame->prevGain << 16; + + pCurrentPhaseInt = pWTVoice->pPhaseAccum; + currentPhaseFrac = pWTVoice->phaseFrac; + phaseInc = pWTIntFrame->phaseIncrement; + + pLoopStart = pWTVoice->pLoopStart; + pLoopEnd = pWTVoice->pLoopEnd + 1; + +InterpolationLoop: + tmp0 = (EAS_I32)(pCurrentPhaseInt - pLoopEnd); + if (tmp0 >= 0) + pCurrentPhaseInt = pLoopStart + tmp0; + + tmp0 = *pCurrentPhaseInt; + tmp1 = *(pCurrentPhaseInt + 1); + + tmp2 = phaseInc + currentPhaseFrac; + + tmp1 = tmp1 - tmp0; + tmp1 = tmp1 * currentPhaseFrac; + + tmp1 = tmp0 + (tmp1 >> NUM_EG1_FRAC_BITS); + + pCurrentPhaseInt += (tmp2 >> NUM_PHASE_FRAC_BITS); + currentPhaseFrac = tmp2 & PHASE_FRAC_MASK; + + gain += gainIncrement; + tmp2 = (gain >> SYNTH_UPDATE_PERIOD_IN_BITS); + + tmp0 = *pMixBuffer; + tmp2 = tmp1 * tmp2; + tmp2 = (tmp2 >> 9); + tmp0 = tmp2 + tmp0; + *pMixBuffer++ = tmp0; + + numSamples--; + if (numSamples) + goto InterpolationLoop; + + pWTVoice->pPhaseAccum = pCurrentPhaseInt; + pWTVoice->phaseFrac = currentPhaseFrac; + /*lint -e{702} <avoid divide>*/ + pWTVoice->gain = (EAS_I16)(gain >> SYNTH_UPDATE_PERIOD_IN_BITS); +} +#endif + +#ifdef _OPTIMIZED_MONO +/*---------------------------------------------------------------------------- + * WT_ProcessVoice + *---------------------------------------------------------------------------- + * Purpose: + * This routine does the block processing for one voice. It is isolated + * from the main synth code to allow for various implementation-specific + * optimizations. It calls the interpolator, filter, and gain routines + * appropriate for a particular configuration. + * + * Inputs: + * + * Outputs: + * + * Notes: + * This special version works handles an optimized mono-only signal + * without filters + *---------------------------------------------------------------------------- +*/ +void WT_ProcessVoice (S_WT_VOICE *pWTVoice, S_WT_INT_FRAME *pWTIntFrame) +{ + + /* use noise generator */ + if (pWTVoice->loopStart== WT_NOISE_GENERATOR) + { + WT_NoiseGenerator(pWTVoice, pWTIntFrame); + WT_VoiceGain(pWTVoice, pWTIntFrame); + } + + /* or generate interpolated samples */ + else + { + WT_InterpolateMono(pWTVoice, pWTIntFrame); + } +} +#endif + |