156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * File:
456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * eas_fmengine.c
556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Contents and purpose:
756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Implements the low-level FM synthesizer functions.
856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Copyright Sonic Network Inc. 2004, 2005
107df30109963092559d3760c0661a020f9daf1030The Android Open Source Project
117df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
127df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * you may not use this file except in compliance with the License.
137df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * You may obtain a copy of the License at
147df30109963092559d3760c0661a020f9daf1030The Android Open Source Project *
157df30109963092559d3760c0661a020f9daf1030The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
167df30109963092559d3760c0661a020f9daf1030The Android Open Source Project *
177df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
187df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
197df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
207df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * See the License for the specific language governing permissions and
217df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * limitations under the License.
2256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
2356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
2456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Revision Control:
2556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *   $Revision: 795 $
2656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *   $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
2756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
2856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
2956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
3056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* includes */
3156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_types.h"
3256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_math.h"
3356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_audioconst.h"
3456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_fmengine.h"
3556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
3656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if defined(EAS_FM_SYNTH) || defined(EAS_HYBRID_SYNTH) || defined(EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH)
3756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_data.h"
3856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif
3956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
4056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* externals */
4156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksextern const EAS_I16 sineTable[];
4256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksextern const EAS_U8 fmScaleTable[16];
4356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
4456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks// saturation constants for 32-bit to 16-bit conversion
4556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define _EAS_MAX_OUTPUT 32767
4656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define _EAS_MIN_OUTPUT -32767
4756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
4856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic S_FM_ENG_VOICE voices[NUM_FM_VOICES];
4956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
5056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* local prototypes */
5156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksvoid FM_SynthMixVoice (S_FM_ENG_VOICE *p,  EAS_U16 gainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer);
5256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
5356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* used in development environment */
5456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if defined(_SATURATION_MONITOR)
5556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_BOOL bSaturated = EAS_FALSE;
5656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
5756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
5856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_CheckSaturation()
5956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
6056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
6156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Allows the sound development tool to check for saturation at the voice
6256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * level. Useful for tuning the level controls.
6356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
6456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
6556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
6656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
6756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Returns true if saturation has occurred since the last time the function
6856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * was called.
6956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
7056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects:
7156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Resets the saturation flag
7256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
7356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
7456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksEAS_BOOL FM_CheckSaturation ()
7556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
7656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_BOOL bTemp;
7756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    bTemp = bSaturated;
7856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    bSaturated = EAS_FALSE;
7956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    return bTemp;
8056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
8156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif
8256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
8356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
8456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_Saturate()
8556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
8656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
8756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * This inline function saturates a 32-bit number to 16-bits
8856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
8956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
9056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure
9156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
9256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
9356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Returns a 16-bit integer
9456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
9556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
9656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksEAS_INLINE EAS_I16 FM_Saturate (EAS_I32 nValue)
9756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
9856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (nValue > _EAS_MAX_OUTPUT)
9956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
10056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if defined(_SATURATION_MONITOR)
10156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        bSaturated = EAS_TRUE;
10256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif
10356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        return _EAS_MAX_OUTPUT;
10456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
10556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (nValue < _EAS_MIN_OUTPUT)
10656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
10756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if defined(_SATURATION_MONITOR)
10856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        bSaturated = EAS_TRUE;
10956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif
11056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        return _EAS_MIN_OUTPUT;
11156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
11256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    return (EAS_I16) nValue;
11356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
11456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
11556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
11656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_Noise()
11756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
11856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
11956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * A 31-bit low-cost linear congruential PRNG algorithm used to
12056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * generate noise.
12156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
12256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
12356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pnSeed - pointer to 32-bit PRNG seed
12456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
12556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
12656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Returns a 16-bit integer
12756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
12856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
12956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksEAS_INLINE EAS_I16 FM_Noise (EAS_U32 *pnSeed)
13056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
13156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    *pnSeed = *pnSeed * 214013L + 2531011L;
13256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    return (EAS_I16) ((*pnSeed >> 15) & 0xffff);
13356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
13456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
13556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
13656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_PhaseInc()
13756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
13856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
13956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Transform pitch cents to linear phase increment
14056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
14156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
14256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nCents -     measured in cents
14356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure
14456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
14556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
14656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS)
14756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
14856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects:
14956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
15056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
15156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
15256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_I32 FM_PhaseInc (EAS_I32 nCents)
15356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
15456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 nDents;
15556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 nExponentInt, nExponentFrac;
15656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 nTemp1, nTemp2;
15756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 nResult;
15856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
15956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* convert cents to dents */
16056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nDents = FMUL_15x15(nCents, CENTS_TO_DENTS);
16156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nExponentInt = GET_DENTS_INT_PART(nDents) + (32 - SINE_TABLE_SIZE_IN_BITS - NUM_EG1_FRAC_BITS);
16256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nExponentFrac = GET_DENTS_FRAC_PART(nDents);
16356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
16456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* implement 2^(fracPart) as a power series */
16556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3);
16656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1);
16756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2);
16856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
16956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /*
17056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    implement 2^(intPart) as
17156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    a left shift for intPart >= 0 or
17256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    a left shift for intPart <  0
17356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    */
17456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (nExponentInt >= 0)
17556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
17656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* left shift for positive exponents */
17756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /*lint -e{703} <avoid multiply for performance>*/
17856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nResult = nTemp1 << nExponentInt;
17956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
18056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
18156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
18256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* right shift for negative exponents */
18356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nExponentInt = -nExponentInt;
18456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nResult = nTemp1 >> nExponentInt;
18556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
18656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
18756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    return nResult;
18856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
18956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
19056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if (NUM_OUTPUT_CHANNELS == 2)
19156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
19256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_CalculatePan()
19356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
19456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
19556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Assign the left and right gain values corresponding to the given pan value.
19656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
19756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
19856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psVoice - ptr to the voice we have assigned for this channel
19956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psArticulation - ptr to this voice's articulation
20056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure
20156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
20256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
20356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
20456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects:
20556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * the given voice's m_nGainLeft and m_nGainRight are assigned
20656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
20756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
20856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_CalculatePan (EAS_I16 pan, EAS_U16 *pGainLeft, EAS_U16 *pGainRight)
20956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
21056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 nTemp;
21156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_INT nNetAngle;
21256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
21356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /*
21456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    Implement the following
21556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    sin(x) = (2-4*c)*x^2 + c + x
21656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    cos(x) = (2-4*c)*x^2 + c - x
21756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
21856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks      where  c = 1/sqrt(2)
21956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    using the a0 + x*(a1 + x*a2) approach
22056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    */
22156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
22256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /*
22356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    Get the Midi CC10 pan value for this voice's channel
22456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    convert the pan value to an "angle" representation suitable for
22556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    our sin, cos calculator. This representation is NOT necessarily the same
22656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    as the transform in the GM manuals because of our sin, cos calculator.
22756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    "angle" = (CC10 - 64)/128
22856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    */
22956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /*lint -e{703} <avoid multiply for performance reasons>*/
23056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nNetAngle = ((EAS_I32) pan) << (NUM_EG1_FRAC_BITS -7);
23156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
23256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* calculate sin */
23356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nTemp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle);
23456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle);
23556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
23656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN)
23756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nTemp = SYNTH_FULL_SCALE_EG1_GAIN;
23856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else if (nTemp < 0)
23956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nTemp = 0;
24056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
24156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    *pGainRight = (EAS_U16) nTemp;
24256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
24356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* calculate cos */
24456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nTemp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle);
24556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle);
24656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
24756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN)
24856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nTemp = SYNTH_FULL_SCALE_EG1_GAIN;
24956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else if (nTemp < 0)
25056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nTemp = 0;
25156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
25256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    *pGainLeft = (EAS_U16) nTemp;
25356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
25456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */
25556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
25656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
25756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_Operator()
25856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
25956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
26056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Synthesizes a buffer of samples based on passed parameters.
26156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
26256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
26356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nNumSamplesToAdd - number of samples to synthesize
26456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure
26556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
26656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
26756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
26856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects:
26956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
27056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
27156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
27256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksvoid FM_Operator (
27356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        S_FM_ENG_OPER *p,
27456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_I32 numSamplesToAdd,
27556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_PCM *pBuffer,
27656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_PCM *pModBuffer,
27756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_BOOL mix,
27856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_U16 gainTarget,
27956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_I16 pitch,
28056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_U8 feedback,
28156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_I16 *pLastOutput)
28256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
28356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 gain;
28456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 gainInc;
28556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_U32 phase;
28656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_U32 phaseInc;
28756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_U32 phaseTemp;
28856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 temp;
28956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 temp2;
29056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
29156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* establish local gain variable */
29256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    gain = (EAS_I32) p->gain << 16;
29356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
29456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* calculate gain increment */
29556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /*lint -e{703} use shift for performance */
29656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
29756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
29856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* establish local phase variables */
29956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    phase = p->phase;
30056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
30156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* calculate the new phase increment */
30256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    phaseInc = (EAS_U32) FM_PhaseInc(pitch);
30356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
30456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* restore final output from previous frame for feedback loop */
30556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (pLastOutput)
30656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        temp = *pLastOutput;
30756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
30856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        temp = 0;
30956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
31056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* generate a buffer of samples */
31156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    while (numSamplesToAdd--)
31256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
31356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
31456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* incorporate modulation */
31556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        if (pModBuffer)
31656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        {
31756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            /*lint -e{701} use shift for performance */
31856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            temp = *pModBuffer++ << FM_MODULATOR_INPUT_SHIFT;
31956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        }
32056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
32156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* incorporate feedback */
32256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        else
32356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        {
32456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            /*lint -e{703} use shift for performance */
32556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            temp = (temp * (EAS_I32) feedback) << FM_FEEDBACK_SHIFT;
32656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        }
32756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
32856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /*lint -e{737} <use this behavior to avoid extra mask step> */
32956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        phaseTemp = phase + temp;
33056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
33156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* fetch sample from wavetable */
33256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        temp = sineTable[phaseTemp >> (32 - SINE_TABLE_SIZE_IN_BITS)];
33356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
33456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* increment operator phase */
33556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        phase += phaseInc;
33656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
33756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* internal gain for modulation effects */
33856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        temp = FMUL_15x15(temp, (gain >> 16));
33956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
34056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* output gain calculation */
34156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        temp2 = FMUL_15x15(temp, p->outputGain);
34256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
34356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* saturating add to buffer */
34456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        if (mix)
34556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        {
34656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            temp2 += *pBuffer;
34756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            *pBuffer++ = FM_Saturate(temp2);
34856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        }
34956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
35056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* output to buffer */
35156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        else
35256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            *pBuffer++ = (EAS_I16) temp2;
35356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
35456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* increment gain */
35556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        gain += gainInc;
35656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
35756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
35856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
35956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* save phase and gain */
36056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    p->phase = phase;
36156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    p->gain = gainTarget;
36256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
36356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* save last output for feedback in next frame */
36456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (pLastOutput)
36556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        *pLastOutput = (EAS_I16) temp;
36656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
36756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
36856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
36956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_NoiseOperator()
37056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
37156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
37256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Synthesizes a buffer of samples based on passed parameters.
37356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
37456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
37556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nNumSamplesToAdd - number of samples to synthesize
37656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure
37756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
37856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
37956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
38056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects:
38156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
38256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
38356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
38456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksvoid FM_NoiseOperator (
38556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        S_FM_ENG_OPER *p,
38656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_I32 numSamplesToAdd,
38756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_PCM *pBuffer,
38856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_BOOL mix,
38956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_U16 gainTarget,
39056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_U8 feedback,
39156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_I16 *pLastOutput)
39256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
39356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 gain;
39456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 gainInc;
39556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_U32 phase;
39656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 temp;
39756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 temp2;
39856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
39956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* establish local gain variable */
40056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    gain = (EAS_I32) p->gain << 16;
40156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
40256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* calculate gain increment */
40356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /*lint -e{703} use shift for performance */
40456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
40556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
40656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* establish local phase variables */
40756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    phase = p->phase;
40856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
40956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* establish local phase variables */
41056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    phase = p->phase;
41156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
41256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* recall last sample for filter Z-1 term */
41356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    temp = 0;
41456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (pLastOutput)
41556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        temp = *pLastOutput;
41656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
41756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* generate a buffer of samples */
41856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    while (numSamplesToAdd--)
41956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
42056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
42156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* if using filter */
42256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        if (pLastOutput)
42356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        {
42456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            /* use PRNG for noise */
42556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            temp2 = FM_Noise(&phase);
42656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
42756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            /*lint -e{704} use shift for performance */
42856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            temp += ((temp2 -temp) * feedback) >> 8;
42956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        }
43056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        else
43156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        {
43256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            temp = FM_Noise(&phase);
43356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        }
43456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
43556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* internal gain for modulation effects */
43656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        temp2 = FMUL_15x15(temp, (gain >> 16));
43756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
43856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* output gain calculation */
43956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        temp2 = FMUL_15x15(temp2, p->outputGain);
44056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
44156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* saturating add to buffer */
44256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        if (mix)
44356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        {
44456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            temp2 += *pBuffer;
44556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            *pBuffer++ = FM_Saturate(temp2);
44656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        }
44756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
44856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* output to buffer */
44956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        else
45056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            *pBuffer++ = (EAS_I16) temp2;
45156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
45256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* increment gain */
45356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        gain += gainInc;
45456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
45556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
45656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
45756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* save phase and gain */
45856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    p->phase = phase;
45956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    p->gain = gainTarget;
46056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
46156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* save last output for feedback in next frame */
46256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (pLastOutput)
46356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        *pLastOutput = (EAS_I16) temp;
46456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
46556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
46656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
46756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_ConfigVoice()
46856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
46956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
47056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Receives parameters to start a new voice.
47156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
47256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
47356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * voiceNum     - voice number to start
47456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * vCfg         - configuration data
47556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pMixBuffer   - pointer to host supplied buffer
47656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
47756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
47856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
47956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects:
48056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
48156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Notes:
48256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pFrameBuffer is not used in the test version, but is passed as a
48356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * courtesy to split architecture implementations. It can be used as
48456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * as pointer to the interprocessor communications buffer when the
48556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * synthesis parameters are passed off to a DSP for synthesis.
48656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
48756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
48856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*lint -esym(715, pFrameBuffer) pFrameBuffer not used in test version - see above */
48956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksvoid FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer)
49056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
49156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    S_FM_ENG_VOICE *pVoice;
49256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_INT i;
49356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
49456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* establish pointer to voice data */
49556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    pVoice = &voices[voiceNum];
49656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
49756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* save data */
49856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    pVoice->feedback = vCfg->feedback;
49956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    pVoice->flags = vCfg->flags;
50056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    pVoice->voiceGain = vCfg->voiceGain;
50156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
50256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* initialize Z-1 terms */
50356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    pVoice->op1Out = 0;
50456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    pVoice->op3Out = 0;
50556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
50656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* initialize operators */
50756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    for (i = 0; i < 4; i++)
50856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
50956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* save operator data */
51056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pVoice->oper[i].gain = vCfg->gain[i];
51156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pVoice->oper[i].outputGain = vCfg->outputGain[i];
51256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pVoice->oper[i].outputGain = vCfg->outputGain[i];
51356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
51456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* initalize operator */
51556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pVoice->oper[i].phase = 0;
51656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
51756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
51856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* calculate pan */
51956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if NUM_OUTPUT_CHANNELS == 2
52056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    FM_CalculatePan(vCfg->pan, &pVoice->gainLeft, &pVoice->gainRight);
52156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif
52256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
52356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
52456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
52556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_ProcessVoice()
52656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
52756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
52856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Synthesizes a buffer of samples based on calculated parameters.
52956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
53056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
53156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nNumSamplesToAdd - number of samples to synthesize
53256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure
53356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
53456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
53556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
53656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects:
53756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
53856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Notes:
53956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pOut is not used in the test version, but is passed as a
54056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * courtesy to split architecture implementations. It can be used as
54156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * as pointer to the interprocessor communications buffer when the
54256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * synthesis parameters are passed off to a DSP for synthesis.
54356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
54456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
54556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*lint -esym(715, pOut) pOut not used in test version - see above */
54656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksvoid FM_ProcessVoice (
54756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_I32 voiceNum,
54856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        S_FM_VOICE_FRAME *pFrame,
54956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_I32 numSamplesToAdd,
55056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_PCM *pTempBuffer,
55156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_PCM *pBuffer,
55256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_I32 *pMixBuffer,
55356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        EAS_FRAME_BUFFER_HANDLE pFrameBuffer)
55456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
55556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    S_FM_ENG_VOICE *p;
55656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_PCM *pOutBuf;
55756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_PCM *pMod;
55856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_BOOL mix;
55956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_U8 feedback1;
56056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_U8 feedback3;
56156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_U8 mode;
56256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
56356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* establish pointer to voice data */
56456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    p = &voices[voiceNum];
56556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    mode = p->flags & 0x07;
56656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
56756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* lookup feedback values */
56856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    feedback1 = fmScaleTable[p->feedback >> 4];
56956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    feedback3 = fmScaleTable[p->feedback & 0x0f];
57056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
57156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* operator 3 is on output bus in modes 0, 1, and 3 */
57256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if ((mode == 0) || (mode == 1) || (mode == 3))
57356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pOutBuf = pBuffer;
57456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
57556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pOutBuf = pTempBuffer;
57656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
57756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (p->flags & FLAG_FM_ENG_VOICE_OP3_NOISE)
57856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
57956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        FM_NoiseOperator(
58056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                p->oper + 2,
58156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                numSamplesToAdd,
58256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pOutBuf,
58356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                EAS_FALSE,
58456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->gain[2],
58556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                feedback3,
58656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                &p->op3Out);
58756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
58856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
58956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
59056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        FM_Operator(
59156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                p->oper + 2,
59256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                numSamplesToAdd,
59356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pOutBuf,
59456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                0,
59556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                EAS_FALSE,
59656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->gain[2],
59756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->pitch[2],
59856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                feedback3,
59956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                &p->op3Out);
60056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
60156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
60256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* operator 4 is on output bus in modes 0, 1, and 2 */
60356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (mode < 3)
60456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pOutBuf = pBuffer;
60556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
60656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pOutBuf = pTempBuffer;
60756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
60856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* operator 4 is modulated in modes 2, 4, and 5 */
60956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if ((mode == 2) || (mode == 4) || (mode == 5))
61056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pMod = pTempBuffer;
61156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
61256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pMod = 0;
61356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
61456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* operator 4 is in mix mode in modes 0 and 1 */
61556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    mix = (mode < 2);
61656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
61756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (p->flags & FLAG_FM_ENG_VOICE_OP4_NOISE)
61856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
61956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        FM_NoiseOperator(
62056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                p->oper + 3,
62156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                numSamplesToAdd,
62256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pOutBuf,
62356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                mix,
62456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->gain[3],
62556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                0,
62656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                0);
62756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
62856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
62956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
63056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        FM_Operator(
63156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                p->oper + 3,
63256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                numSamplesToAdd,
63356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pOutBuf,
63456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pMod,
63556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                mix,
63656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->gain[3],
63756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->pitch[3],
63856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                0,
63956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                0);
64056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
64156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
64256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* operator 1 is on output bus in mode 0 */
64356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (mode == 0)
64456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pOutBuf = pBuffer;
64556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
64656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pOutBuf = pTempBuffer;
64756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
64856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* operator 1 is modulated in modes 3 and 4 */
64956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if ((mode == 3) || (mode == 4))
65056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pMod = pTempBuffer;
65156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
65256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pMod = 0;
65356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
65456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* operator 1 is in mix mode in modes 0 and 5 */
65556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    mix = ((mode == 0) || (mode == 5));
65656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
65756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (p->flags & FLAG_FM_ENG_VOICE_OP1_NOISE)
65856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
65956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        FM_NoiseOperator(
66056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                p->oper,
66156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                numSamplesToAdd,
66256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pOutBuf,
66356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                mix,
66456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->gain[0],
66556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                feedback1,
66656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                &p->op1Out);
66756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
66856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
66956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
67056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        FM_Operator(
67156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                p->oper,
67256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                numSamplesToAdd,
67356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pOutBuf,
67456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pMod,
67556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                mix,
67656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->gain[0],
67756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->pitch[0],
67856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                feedback1,
67956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                &p->op1Out);
68056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
68156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
68256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* operator 2 is modulated in all modes except 0 */
68356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (mode != 0)
68456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pMod = pTempBuffer;
68556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
68656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        pMod = 0;
68756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
68856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* operator 1 is in mix mode in modes 0 -3 */
68956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    mix = (mode < 4);
69056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
69156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    if (p->flags & FLAG_FM_ENG_VOICE_OP2_NOISE)
69256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
69356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        FM_NoiseOperator(
69456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                p->oper + 1,
69556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                numSamplesToAdd,
69656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pBuffer,
69756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                mix,
69856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->gain[1],
69956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                0,
70056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                0);
70156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
70256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    else
70356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
70456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        FM_Operator(
70556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                p->oper + 1,
70656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                numSamplesToAdd,
70756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pBuffer,
70856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pMod,
70956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                mix,
71056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->gain[1],
71156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                pFrame->pitch[1],
71256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                0,
71356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks                0);
71456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
71556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
71656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* mix voice output to synthesizer output buffer */
71756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    FM_SynthMixVoice(p, pFrame->voiceGain, numSamplesToAdd, pBuffer, pMixBuffer);
71856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
71956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
72056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*----------------------------------------------------------------------------
72156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_SynthMixVoice()
72256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
72356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose:
72456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Mixes the voice output buffer into the final mix using an anti-zipper
72556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * filter.
72656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
72756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs:
72856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nNumSamplesToAdd - number of samples to synthesize
72956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure
73056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
73156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs:
73256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
73356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects:
73456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *
73556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *----------------------------------------------------------------------------
73656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/
73756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksvoid FM_SynthMixVoice(S_FM_ENG_VOICE *p,  EAS_U16 nGainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer)
73856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{
73956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 nGain;
74056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 nGainInc;
74156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    EAS_I32 nTemp;
74256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
74356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* restore previous gain */
74456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /*lint -e{703} <use shift for performance> */
74556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nGain = (EAS_I32) p->voiceGain << 16;
74656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
74756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* calculate gain increment */
74856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /*lint -e{703} <use shift for performance> */
74956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    nGainInc = ((EAS_I32) nGainTarget - (EAS_I32) p->voiceGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
75056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
75156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* mix the output buffer */
75256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    while (numSamplesToAdd--)
75356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    {
75456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* output gain calculation */
75556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nTemp = *pInputBuffer++;
75656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
75756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* sum to output buffer */
75856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if (NUM_OUTPUT_CHANNELS == 2)
75956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
76056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /*lint -e{704} <use shift for performance> */
76156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_GAIN_SHIFT;
76256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
76356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /*lint -e{704} <use shift for performance> */
76456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        {
76556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            EAS_I32 nTemp2;
76656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            nTemp = nTemp >> FM_STEREO_PRE_GAIN_SHIFT;
76756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            nTemp2 = (nTemp * p->gainLeft) >> FM_STEREO_POST_GAIN_SHIFT;
76856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            *pBuffer++ += nTemp2;
76956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            nTemp2 = (nTemp * p->gainRight) >> FM_STEREO_POST_GAIN_SHIFT;
77056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks            *pBuffer++ += nTemp2;
77156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        }
77256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#else
77356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /*lint -e{704} <use shift for performance> */
77456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_MONO_GAIN_SHIFT;
77556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        *pBuffer++ += nTemp;
77656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif
77756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
77856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        /* increment gain for anti-zipper filter */
77956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks        nGain += nGainInc;
78056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    }
78156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
78256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    /* save gain */
78356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks    p->voiceGain = nGainTarget;
78456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}
78556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks
786