eas_fmengine.c revision e442bb7cd6a085b33a4dd52c0e20a157ada7feb1
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*----------------------------------------------------------------------------
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * File:
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * eas_fmengine.c
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Contents and purpose:
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Implements the low-level FM synthesizer functions.
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright Sonic Network Inc. 2004, 2005
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Licensed under the Apache License, Version 2.0 (the "License");
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * you may not use this file except in compliance with the License.
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * You may obtain a copy of the License at
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
157ffb1b21abcc7bbed5a0fc711f6dd7b9dbb4f577ctguil@chromium.org *      http://www.apache.org/licenses/LICENSE-2.0
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Unless required by applicable law or agreed to in writing, software
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * distributed under the License is distributed on an "AS IS" BASIS,
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * See the License for the specific language governing permissions and
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * limitations under the License.
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *----------------------------------------------------------------------------
24e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com * Revision Control:
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *   $Revision: 795 $
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *   $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *----------------------------------------------------------------------------
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* includes */
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "eas_types.h"
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "eas_math.h"
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "eas_audioconst.h"
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "eas_fmengine.h"
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if defined(EAS_FM_SYNTH) || defined(EAS_HYBRID_SYNTH) || defined(EAS_SPLIT_HYBRID_SYNTH) || defined(EAS_SPLIT_FM_SYNTH)
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "eas_data.h"
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* externals */
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comextern const EAS_I16 sineTable[];
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comextern const EAS_U8 fmScaleTable[16];
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// saturation constants for 32-bit to 16-bit conversion
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define _EAS_MAX_OUTPUT 32767
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define _EAS_MIN_OUTPUT -32767
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic S_FM_ENG_VOICE voices[NUM_FM_VOICES];
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* local prototypes */
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid FM_SynthMixVoice (S_FM_ENG_VOICE *p,  EAS_U16 gainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer);
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* used in development environment */
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if defined(_SATURATION_MONITOR)
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic EAS_BOOL bSaturated = EAS_FALSE;
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*----------------------------------------------------------------------------
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * FM_CheckSaturation()
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *----------------------------------------------------------------------------
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Purpose:
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Allows the sound development tool to check for saturation at the voice
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * level. Useful for tuning the level controls.
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Inputs:
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Outputs:
67b530ef5869c5c64af8f3b3c62ed7711fe4325c9creed@google.com * Returns true if saturation has occurred since the last time the function
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * was called.
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Side Effects:
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Resets the saturation flag
723467ee06d31798b2673364ef4f7abd83619b21ddreed@google.com *----------------------------------------------------------------------------
733467ee06d31798b2673364ef4f7abd83619b21ddreed@google.com*/
743467ee06d31798b2673364ef4f7abd83619b21ddreed@google.comEAS_BOOL FM_CheckSaturation ()
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	EAS_BOOL bTemp;
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bTemp = bSaturated;
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bSaturated = EAS_FALSE;
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return bTemp;
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*----------------------------------------------------------------------------
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * FM_Saturate()
850da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com *----------------------------------------------------------------------------
860da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com * Purpose:
870da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com * This inline function saturates a 32-bit number to 16-bits
880da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com *
890da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com * Inputs:
900da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com * psEASData - pointer to overall EAS data structure
910da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com *
920da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com * Outputs:
930da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com * Returns a 16-bit integer
940da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com *----------------------------------------------------------------------------
950da41dbf5bdf9614a3d2f1d3ebd959221bbac44breed@android.com*/
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comEAS_INLINE EAS_I16 FM_Saturate (EAS_I32 nValue)
971271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com{
981271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com	if (nValue > _EAS_MAX_OUTPUT)
991271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com	{
1001271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com#if defined(_SATURATION_MONITOR)
101e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com		bSaturated = EAS_TRUE;
1021271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com#endif
1031271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com		return _EAS_MAX_OUTPUT;
104046f1f6ff4b2b3f4571a9562e74f41e82419a4a1commit-bot@chromium.org	}
105046f1f6ff4b2b3f4571a9562e74f41e82419a4a1commit-bot@chromium.org	if (nValue < _EAS_MIN_OUTPUT)
106046f1f6ff4b2b3f4571a9562e74f41e82419a4a1commit-bot@chromium.org	{
107046f1f6ff4b2b3f4571a9562e74f41e82419a4a1commit-bot@chromium.org#if defined(_SATURATION_MONITOR)
108046f1f6ff4b2b3f4571a9562e74f41e82419a4a1commit-bot@chromium.org		bSaturated = EAS_TRUE;
109046f1f6ff4b2b3f4571a9562e74f41e82419a4a1commit-bot@chromium.org#endif
110046f1f6ff4b2b3f4571a9562e74f41e82419a4a1commit-bot@chromium.org		return _EAS_MIN_OUTPUT;
1111271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com	}
1121271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com	return (EAS_I16) nValue;
1131271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com}
1141271d78e8ff4cda0622a24dcec6063b50f6be051reed@google.com
115aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org/*----------------------------------------------------------------------------
116aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org * FM_Noise()
117aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org *----------------------------------------------------------------------------
118aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org * Purpose:
119aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org * A 31-bit low-cost linear congruential PRNG algorithm used to
120aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org * generate noise.
121e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com *
122aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org * Inputs:
123aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org * pnSeed - pointer to 32-bit PRNG seed
124aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org *
125e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com * Outputs:
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Returns a 16-bit integer
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *----------------------------------------------------------------------------
1287fc0e0a75a99ac5ea2e5d03ab3a00cacabacfa09skia.committer@gmail.com*/
129aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.orgEAS_INLINE EAS_I16 FM_Noise (EAS_U32 *pnSeed)
130aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org{
131aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org	*pnSeed = *pnSeed * 214013L + 2531011L;
132aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org	return (EAS_I16) ((*pnSeed >> 15) & 0xffff);
1337af56bee17764a0c118c8856a035bb3d27766969humper@google.com}
1347af56bee17764a0c118c8856a035bb3d27766969humper@google.com
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*----------------------------------------------------------------------------
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * FM_PhaseInc()
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *----------------------------------------------------------------------------
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Purpose:
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Transform pitch cents to linear phase increment
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Inputs:
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * nCents - 	measured in cents
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * psEASData - pointer to overall EAS data structure
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Outputs:
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * nResult - int.frac result (where frac has NUM_DENTS_FRAC_BITS)
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
148fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com * Side Effects:
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *----------------------------------------------------------------------------
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic EAS_I32 FM_PhaseInc (EAS_I32 nCents)
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
154a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	EAS_I32 nDents;
155a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	EAS_I32 nExponentInt, nExponentFrac;
156a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	EAS_I32 nTemp1, nTemp2;
157a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	EAS_I32	nResult;
158a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org
159a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	/* convert cents to dents */
160e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com	nDents = FMUL_15x15(nCents, CENTS_TO_DENTS);
161a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	nExponentInt = GET_DENTS_INT_PART(nDents) + (32 - SINE_TABLE_SIZE_IN_BITS - NUM_EG1_FRAC_BITS);
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	nExponentFrac = GET_DENTS_FRAC_PART(nDents);
163a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org
16493d5ffda58391fe819199bf5afddc622e067af7ecommit-bot@chromium.org	/* implement 2^(fracPart) as a power series */
165a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	nTemp1 = GN2_TO_X2 + MULT_DENTS_COEF(nExponentFrac, GN2_TO_X3);
166a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	nTemp2 = GN2_TO_X1 + MULT_DENTS_COEF(nExponentFrac, nTemp1);
167a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	nTemp1 = GN2_TO_X0 + MULT_DENTS_COEF(nExponentFrac, nTemp2);
168e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/*
170a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	implement 2^(intPart) as
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	a left shift for intPart >= 0 or
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	a left shift for intPart <  0
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	*/
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	if (nExponentInt >= 0)
175a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	{
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		/* left shift for positive exponents */
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		/*lint -e{703} <avoid multiply for performance>*/
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		nResult = nTemp1 << nExponentInt;
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	}
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	else
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	{
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		/* right shift for negative exponents */
183e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com		nExponentInt = -nExponentInt;
184e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com		nResult = nTemp1 >> nExponentInt;
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	}
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	return nResult;
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
189a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if	(NUM_OUTPUT_CHANNELS == 2)
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*----------------------------------------------------------------------------
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * FM_CalculatePan()
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *----------------------------------------------------------------------------
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Purpose:
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Assign the left and right gain values corresponding to the given pan value.
196fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com *
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Inputs:
198fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com * psVoice - ptr to the voice we have assigned for this channel
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * psArticulation - ptr to this voice's articulation
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * psEASData - pointer to overall EAS data structure
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Outputs:
203e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com *
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * Side Effects:
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * the given voice's m_nGainLeft and m_nGainRight are assigned
206e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com *----------------------------------------------------------------------------
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void FM_CalculatePan (EAS_I16 pan, EAS_U16 *pGainLeft, EAS_U16 *pGainRight)
209ffe39bd3b66eb5090684959e7f2409346ab72d93tomhudson@google.com{
210a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	EAS_I32	nTemp;
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	EAS_INT nNetAngle;
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/*
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	Implement the following
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	sin(x) = (2-4*c)*x^2 + c + x
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	cos(x) = (2-4*c)*x^2 + c - x
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	  where  c = 1/sqrt(2)
219e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com	using the a0 + x*(a1 + x*a2) approach
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	*/
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/*
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	Get the Midi CC10 pan value for this voice's channel
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	convert the pan value to an "angle" representation suitable for
225e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com	our sin, cos calculator. This representation is NOT necessarily the same
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	as the transform in the GM manuals because of our sin, cos calculator.
227e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com	"angle" = (CC10 - 64)/128
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	*/
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/*lint -e{703} <avoid multiply for performance reasons>*/
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	nNetAngle = ((EAS_I32) pan) << (NUM_EG1_FRAC_BITS -7);
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/* calculate sin */
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	nTemp = EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle);
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle);
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN)
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		nTemp = SYNTH_FULL_SCALE_EG1_GAIN;
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	else if (nTemp < 0)
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		nTemp = 0;
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	*pGainRight = (EAS_U16) nTemp;
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/* calculate cos */
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	nTemp = -EG1_ONE + FMUL_15x15(COEFF_PAN_G2, nNetAngle);
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	nTemp = COEFF_PAN_G0 + FMUL_15x15(nTemp, nNetAngle);
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	if (nTemp > SYNTH_FULL_SCALE_EG1_GAIN)
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		nTemp = SYNTH_FULL_SCALE_EG1_GAIN;
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	else if (nTemp < 0)
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		nTemp = 0;
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2526fcd28ba1de83b72f4c8343ccec27d26c127de32reed@google.com	*pGainLeft = (EAS_U16) nTemp;
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*----------------------------------------------------------------------------
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com * FM_Operator()
258df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com *----------------------------------------------------------------------------
259af07d065d19ec387b783b6dfdc3deafd7c614b69epoger@google.com * Purpose:
260af07d065d19ec387b783b6dfdc3deafd7c614b69epoger@google.com * Synthesizes a buffer of samples based on passed parameters.
261af07d065d19ec387b783b6dfdc3deafd7c614b69epoger@google.com *
262af07d065d19ec387b783b6dfdc3deafd7c614b69epoger@google.com * Inputs:
263af07d065d19ec387b783b6dfdc3deafd7c614b69epoger@google.com * nNumSamplesToAdd - number of samples to synthesize
264af07d065d19ec387b783b6dfdc3deafd7c614b69epoger@google.com * psEASData - pointer to overall EAS data structure
265af07d065d19ec387b783b6dfdc3deafd7c614b69epoger@google.com *
266df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com * Outputs:
267df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com *
268df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com * Side Effects:
269e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com *
270df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com *----------------------------------------------------------------------------
271df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com*/
272df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.comvoid FM_Operator (
273df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com		S_FM_ENG_OPER *p,
274df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com		EAS_I32 numSamplesToAdd,
275df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com		EAS_PCM *pBuffer,
276df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com		EAS_PCM *pModBuffer,
277df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com		EAS_BOOL mix,
278df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com		EAS_U16 gainTarget,
279df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com		EAS_I16 pitch,
280df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com		EAS_U8 feedback,
281c6081abd2f28d2179ad8e3bef557cb0d00fffe01zachr@google.com		EAS_I16 *pLastOutput)
282df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com{
283df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com	EAS_I32 gain;
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	EAS_I32 gainInc;
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	EAS_U32 phase;
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	EAS_U32 phaseInc;
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	EAS_U32 phaseTemp;
2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	EAS_I32 temp;
2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	EAS_I32 temp2;
2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/* establish local gain variable */
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	gain = (EAS_I32) p->gain << 16;
2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/* calculate gain increment */
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/*lint -e{703} use shift for performance */
296c51db02181982fbcb8888e2a89132363a7d9371cscroggo	gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/* establish local phase variables */
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	phase = p->phase;
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/* calculate the new phase increment */
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	phaseInc = (EAS_U32) FM_PhaseInc(pitch);
3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/* restore final output from previous frame for feedback loop */
3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	if (pLastOutput)
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		temp = *pLastOutput;
3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	else
3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		temp = 0;
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	/* generate a buffer of samples */
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	while (numSamplesToAdd--)
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	{
3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		/* incorporate modulation */
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		if (pModBuffer)
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		{
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com			/*lint -e{701} use shift for performance */
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com			temp = *pModBuffer++ << FM_MODULATOR_INPUT_SHIFT;
3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		}
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3218433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com		/* incorporate feedback */
3228433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com		else
3238433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com		{
3248433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com			/*lint -e{703} use shift for performance */
3258433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com			temp = (temp * (EAS_I32) feedback) << FM_FEEDBACK_SHIFT;
3268433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com		}
3278433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com
3288433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com		/*lint -e{737} <use this behavior to avoid extra mask step> */
3298433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com		phaseTemp = phase + temp;
3308433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com
3318433b5db1a0f94cd92d2606817d5374ab899b87areed@android.com		/* fetch sample from wavetable */
332aa537d4bdb2384cdcd0644a02a2ab7fb0ecdd3b3commit-bot@chromium.org		temp = sineTable[phaseTemp >> (32 - SINE_TABLE_SIZE_IN_BITS)];
33321cbec4870660f776f470e3a5e327599b6433dd2bsalomon@google.com
33421cbec4870660f776f470e3a5e327599b6433dd2bsalomon@google.com		/* increment operator phase */
33521cbec4870660f776f470e3a5e327599b6433dd2bsalomon@google.com		phase += phaseInc;
33621cbec4870660f776f470e3a5e327599b6433dd2bsalomon@google.com
33721cbec4870660f776f470e3a5e327599b6433dd2bsalomon@google.com		/* internal gain for modulation effects */
33821cbec4870660f776f470e3a5e327599b6433dd2bsalomon@google.com		temp = FMUL_15x15(temp, (gain >> 16));
33921cbec4870660f776f470e3a5e327599b6433dd2bsalomon@google.com
34021cbec4870660f776f470e3a5e327599b6433dd2bsalomon@google.com		/* output gain calculation */
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		temp2 = FMUL_15x15(temp, p->outputGain);
3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		/* saturating add to buffer */
3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		if (mix)
3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		{
3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com			temp2 += *pBuffer;
3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com			*pBuffer++ = FM_Saturate(temp2);
3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		}
3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		/* output to buffer */
3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		else
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com			*pBuffer++ = (EAS_I16) temp2;
3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		/* increment gain */
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		gain += gainInc;
3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	}
3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
359e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com	/* save phase and gain */
360e9cd27d4a3c92393cc6c79d4d6f93d266411d95erobertphillips@google.com	p->phase = phase;
3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com	p->gain = gainTarget;
362a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org
363a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	/* save last output for feedback in next frame */
364a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org	if (pLastOutput)
365a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org		*pLastOutput = (EAS_I16) temp;
366a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org}
367a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org
368a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org/*----------------------------------------------------------------------------
36909f0ba7eb3c1933c7be878a043de5c287edd00abcommit-bot@chromium.org * FM_NoiseOperator()
370a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org *----------------------------------------------------------------------------
371a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org * Purpose:
372a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org * Synthesizes a buffer of samples based on passed parameters.
373a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org *
374a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org * Inputs:
375a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org * nNumSamplesToAdd - number of samples to synthesize
376a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org * psEASData - pointer to overall EAS data structure
377a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org *
378a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org * Outputs:
379a87b21cd0041bac0d96b6836ac6e71a2dbcd4e10commit-bot@chromium.org *
380ca21a00c736d05686c84ab874ce6a49008da6a76commit-bot@chromium.org * Side Effects:
381ca21a00c736d05686c84ab874ce6a49008da6a76commit-bot@chromium.org *
382ca21a00c736d05686c84ab874ce6a49008da6a76commit-bot@chromium.org *----------------------------------------------------------------------------
383ca21a00c736d05686c84ab874ce6a49008da6a76commit-bot@chromium.org*/
384ca21a00c736d05686c84ab874ce6a49008da6a76commit-bot@chromium.orgvoid FM_NoiseOperator (
385ca21a00c736d05686c84ab874ce6a49008da6a76commit-bot@chromium.org		S_FM_ENG_OPER *p,
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		EAS_I32 numSamplesToAdd,
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		EAS_PCM *pBuffer,
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		EAS_BOOL mix,
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com		EAS_U16 gainTarget,
390		EAS_U8 feedback,
391		EAS_I16 *pLastOutput)
392{
393	EAS_I32 gain;
394	EAS_I32 gainInc;
395	EAS_U32 phase;
396	EAS_I32 temp;
397	EAS_I32 temp2;
398
399	/* establish local gain variable */
400	gain = (EAS_I32) p->gain << 16;
401
402	/* calculate gain increment */
403	/*lint -e{703} use shift for performance */
404	gainInc = ((EAS_I32) gainTarget - (EAS_I32) p->gain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
405
406	/* establish local phase variables */
407	phase = p->phase;
408
409	/* establish local phase variables */
410	phase = p->phase;
411
412	/* recall last sample for filter Z-1 term */
413	temp = 0;
414	if (pLastOutput)
415		temp = *pLastOutput;
416
417	/* generate a buffer of samples */
418	while (numSamplesToAdd--)
419	{
420
421		/* if using filter */
422		if (pLastOutput)
423		{
424			/* use PRNG for noise */
425			temp2 = FM_Noise(&phase);
426
427			/*lint -e{704} use shift for performance */
428			temp += ((temp2 -temp) * feedback) >> 8;
429		}
430		else
431		{
432			temp = FM_Noise(&phase);
433		}
434
435		/* internal gain for modulation effects */
436		temp2 = FMUL_15x15(temp, (gain >> 16));
437
438		/* output gain calculation */
439		temp2 = FMUL_15x15(temp2, p->outputGain);
440
441		/* saturating add to buffer */
442		if (mix)
443		{
444			temp2 += *pBuffer;
445			*pBuffer++ = FM_Saturate(temp2);
446		}
447
448		/* output to buffer */
449		else
450			*pBuffer++ = (EAS_I16) temp2;
451
452		/* increment gain */
453		gain += gainInc;
454
455	}
456
457	/* save phase and gain */
458	p->phase = phase;
459	p->gain = gainTarget;
460
461	/* save last output for feedback in next frame */
462	if (pLastOutput)
463		*pLastOutput = (EAS_I16) temp;
464}
465
466/*----------------------------------------------------------------------------
467 * FM_ConfigVoice()
468 *----------------------------------------------------------------------------
469 * Purpose:
470 * Receives parameters to start a new voice.
471 *
472 * Inputs:
473 * voiceNum		- voice number to start
474 * vCfg			- configuration data
475 * pMixBuffer	- pointer to host supplied buffer
476 *
477 * Outputs:
478 *
479 * Side Effects:
480 *
481 * Notes:
482 * pFrameBuffer is not used in the test version, but is passed as a
483 * courtesy to split architecture implementations. It can be used as
484 * as pointer to the interprocessor communications buffer when the
485 * synthesis parameters are passed off to a DSP for synthesis.
486 *----------------------------------------------------------------------------
487*/
488/*lint -esym(715, pFrameBuffer) pFrameBuffer not used in test version - see above */
489void FM_ConfigVoice (EAS_I32 voiceNum, S_FM_VOICE_CONFIG *vCfg, EAS_FRAME_BUFFER_HANDLE pFrameBuffer)
490{
491	S_FM_ENG_VOICE *pVoice;
492	EAS_INT i;
493
494	/* establish pointer to voice data */
495	pVoice = &voices[voiceNum];
496
497	/* save data */
498	pVoice->feedback = vCfg->feedback;
499	pVoice->flags = vCfg->flags;
500	pVoice->voiceGain = vCfg->voiceGain;
501
502	/* initialize Z-1 terms */
503	pVoice->op1Out = 0;
504	pVoice->op3Out = 0;
505
506	/* initialize operators */
507	for (i = 0; i < 4; i++)
508	{
509		/* save operator data */
510		pVoice->oper[i].gain = vCfg->gain[i];
511		pVoice->oper[i].outputGain = vCfg->outputGain[i];
512		pVoice->oper[i].outputGain = vCfg->outputGain[i];
513
514		/* initalize operator */
515		pVoice->oper[i].phase = 0;
516	}
517
518	/* calculate pan */
519#if NUM_OUTPUT_CHANNELS == 2
520	FM_CalculatePan(vCfg->pan, &pVoice->gainLeft, &pVoice->gainRight);
521#endif
522}
523
524/*----------------------------------------------------------------------------
525 * FM_ProcessVoice()
526 *----------------------------------------------------------------------------
527 * Purpose:
528 * Synthesizes a buffer of samples based on calculated parameters.
529 *
530 * Inputs:
531 * nNumSamplesToAdd - number of samples to synthesize
532 * psEASData - pointer to overall EAS data structure
533 *
534 * Outputs:
535 *
536 * Side Effects:
537 *
538 * Notes:
539 * pOut is not used in the test version, but is passed as a
540 * courtesy to split architecture implementations. It can be used as
541 * as pointer to the interprocessor communications buffer when the
542 * synthesis parameters are passed off to a DSP for synthesis.
543 *----------------------------------------------------------------------------
544*/
545/*lint -esym(715, pOut) pOut not used in test version - see above */
546void FM_ProcessVoice (
547		EAS_I32 voiceNum,
548		S_FM_VOICE_FRAME *pFrame,
549		EAS_I32 numSamplesToAdd,
550		EAS_PCM *pTempBuffer,
551		EAS_PCM *pBuffer,
552		EAS_I32 *pMixBuffer,
553		EAS_FRAME_BUFFER_HANDLE pFrameBuffer)
554{
555	S_FM_ENG_VOICE *p;
556	EAS_PCM *pOutBuf;
557	EAS_PCM *pMod;
558	EAS_BOOL mix;
559	EAS_U8 feedback1;
560	EAS_U8 feedback3;
561	EAS_U8 mode;
562
563	/* establish pointer to voice data */
564	p = &voices[voiceNum];
565	mode = p->flags & 0x07;
566
567	/* lookup feedback values */
568	feedback1 = fmScaleTable[p->feedback >> 4];
569	feedback3 = fmScaleTable[p->feedback & 0x0f];
570
571	/* operator 3 is on output bus in modes 0, 1, and 3 */
572	if ((mode == 0) || (mode == 1) || (mode == 3))
573		pOutBuf = pBuffer;
574	else
575		pOutBuf = pTempBuffer;
576
577	if (p->flags & FLAG_FM_ENG_VOICE_OP3_NOISE)
578	{
579		FM_NoiseOperator(
580				p->oper + 2,
581				numSamplesToAdd,
582				pOutBuf,
583				EAS_FALSE,
584				pFrame->gain[2],
585				feedback3,
586				&p->op3Out);
587	}
588	else
589	{
590		FM_Operator(
591				p->oper + 2,
592				numSamplesToAdd,
593				pOutBuf,
594				0,
595				EAS_FALSE,
596				pFrame->gain[2],
597				pFrame->pitch[2],
598				feedback3,
599				&p->op3Out);
600	}
601
602	/* operator 4 is on output bus in modes 0, 1, and 2 */
603	if (mode < 3)
604		pOutBuf = pBuffer;
605	else
606		pOutBuf = pTempBuffer;
607
608	/* operator 4 is modulated in modes 2, 4, and 5 */
609	if ((mode == 2) || (mode == 4) || (mode == 5))
610		pMod = pTempBuffer;
611	else
612		pMod = 0;
613
614	/* operator 4 is in mix mode in modes 0 and 1 */
615	mix = (mode < 2);
616
617	if (p->flags & FLAG_FM_ENG_VOICE_OP4_NOISE)
618	{
619		FM_NoiseOperator(
620				p->oper + 3,
621				numSamplesToAdd,
622				pOutBuf,
623				mix,
624				pFrame->gain[3],
625				0,
626				0);
627	}
628	else
629	{
630		FM_Operator(
631				p->oper + 3,
632				numSamplesToAdd,
633				pOutBuf,
634				pMod,
635				mix,
636				pFrame->gain[3],
637				pFrame->pitch[3],
638				0,
639				0);
640	}
641
642	/* operator 1 is on output bus in mode 0 */
643	if (mode == 0)
644		pOutBuf = pBuffer;
645	else
646		pOutBuf = pTempBuffer;
647
648	/* operator 1 is modulated in modes 3 and 4 */
649	if ((mode == 3) || (mode == 4))
650		pMod = pTempBuffer;
651	else
652		pMod = 0;
653
654	/* operator 1 is in mix mode in modes 0 and 5 */
655	mix = ((mode == 0) || (mode == 5));
656
657	if (p->flags & FLAG_FM_ENG_VOICE_OP1_NOISE)
658	{
659		FM_NoiseOperator(
660				p->oper,
661				numSamplesToAdd,
662				pOutBuf,
663				mix,
664				pFrame->gain[0],
665				feedback1,
666				&p->op1Out);
667	}
668	else
669	{
670		FM_Operator(
671				p->oper,
672				numSamplesToAdd,
673				pOutBuf,
674				pMod,
675				mix,
676				pFrame->gain[0],
677				pFrame->pitch[0],
678				feedback1,
679				&p->op1Out);
680	}
681
682	/* operator 2 is modulated in all modes except 0 */
683	if (mode != 0)
684		pMod = pTempBuffer;
685	else
686		pMod = 0;
687
688	/* operator 1 is in mix mode in modes 0 -3 */
689	mix = (mode < 4);
690
691	if (p->flags & FLAG_FM_ENG_VOICE_OP2_NOISE)
692	{
693		FM_NoiseOperator(
694				p->oper + 1,
695				numSamplesToAdd,
696				pBuffer,
697				mix,
698				pFrame->gain[1],
699				0,
700				0);
701	}
702	else
703	{
704		FM_Operator(
705				p->oper + 1,
706				numSamplesToAdd,
707				pBuffer,
708				pMod,
709				mix,
710				pFrame->gain[1],
711				pFrame->pitch[1],
712				0,
713				0);
714	}
715
716	/* mix voice output to synthesizer output buffer */
717	FM_SynthMixVoice(p, pFrame->voiceGain, numSamplesToAdd, pBuffer, pMixBuffer);
718}
719
720/*----------------------------------------------------------------------------
721 * FM_SynthMixVoice()
722 *----------------------------------------------------------------------------
723 * Purpose:
724 * Mixes the voice output buffer into the final mix using an anti-zipper
725 * filter.
726 *
727 * Inputs:
728 * nNumSamplesToAdd - number of samples to synthesize
729 * psEASData - pointer to overall EAS data structure
730 *
731 * Outputs:
732 *
733 * Side Effects:
734 *
735 *----------------------------------------------------------------------------
736*/
737void FM_SynthMixVoice(S_FM_ENG_VOICE *p,  EAS_U16 nGainTarget, EAS_I32 numSamplesToAdd, EAS_PCM *pInputBuffer, EAS_I32 *pBuffer)
738{
739	EAS_I32 nGain;
740	EAS_I32 nGainInc;
741	EAS_I32 nTemp;
742
743	/* restore previous gain */
744	/*lint -e{703} <use shift for performance> */
745	nGain = (EAS_I32) p->voiceGain << 16;
746
747	/* calculate gain increment */
748	/*lint -e{703} <use shift for performance> */
749	nGainInc = ((EAS_I32) nGainTarget - (EAS_I32) p->voiceGain) << (16 - SYNTH_UPDATE_PERIOD_IN_BITS);
750
751	/* mix the output buffer */
752	while (numSamplesToAdd--)
753	{
754		/* output gain calculation */
755		nTemp = *pInputBuffer++;
756
757		/* sum to output buffer */
758#if (NUM_OUTPUT_CHANNELS == 2)
759
760		/*lint -e{704} <use shift for performance> */
761		nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_GAIN_SHIFT;
762
763		/*lint -e{704} <use shift for performance> */
764		{
765			EAS_I32 nTemp2;
766			nTemp = nTemp >> FM_STEREO_PRE_GAIN_SHIFT;
767			nTemp2 = (nTemp * p->gainLeft) >> FM_STEREO_POST_GAIN_SHIFT;
768			*pBuffer++ += nTemp2;
769			nTemp2 = (nTemp * p->gainRight) >> FM_STEREO_POST_GAIN_SHIFT;
770			*pBuffer++ += nTemp2;
771		}
772#else
773		/*lint -e{704} <use shift for performance> */
774		nTemp = ((EAS_I32) nTemp * (nGain >> 16)) >> FM_MONO_GAIN_SHIFT;
775		*pBuffer++ += nTemp;
776#endif
777
778		/* increment gain for anti-zipper filter */
779		nGain += nGainInc;
780	}
781
782	/* save gain */
783	p->voiceGain = nGainTarget;
784}
785
786