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