eas_fmsynth.c revision e442bb7cd6a085b33a4dd52c0e20a157ada7feb1
10e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*----------------------------------------------------------------------------
20e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
30e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * File:
40e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * fmsynth.c
50e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
60e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Contents and purpose:
70e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Implements the high-level FM synthesizer functions.
80e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
90e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Copyright Sonic Network Inc. 2004
100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Licensed under the Apache License, Version 2.0 (the "License");
120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * you may not use this file except in compliance with the License.
130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * You may obtain a copy of the License at
140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *      http://www.apache.org/licenses/LICENSE-2.0
160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Unless required by applicable law or agreed to in writing, software
180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * distributed under the License is distributed on an "AS IS" BASIS,
190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * See the License for the specific language governing permissions and
210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * limitations under the License.
220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Revision Control:
250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *   $Revision: 795 $
260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *   $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $
270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org*/
290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// includes
310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "eas_host.h"
320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "eas_report.h"
330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "eas_data.h"
35cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "eas_synth_protos.h"
362a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "eas_audioconst.h"
372a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "eas_fmengine.h"
380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "eas_math.h"
390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/* option sanity check */
410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef _REVERB
420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#error "No reverb for FM synthesizer"
430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef _CHORUS
450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#error "No chorus for FM synthesizer"
460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*
490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WARNING: These macros can cause unwanted side effects. Use them
500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * with care. For example, min(x++,y++) will cause either x or y to be
510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * incremented twice.
520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org */
530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define min(a,b) ((a) < (b) ? (a) : (b))
540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define max(a,b) ((a) > (b) ? (a) : (b))
550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/* pivot point for keyboard scalars */
570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define EG_SCALE_PIVOT_POINT 64
580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define KEY_SCALE_PIVOT_POINT 36
590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/* This number is the negative of the frequency of the note (in cents) of
610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * the sine wave played at unity. The number can be calculated as follows:
620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * MAGIC_NUMBER = 1200 * log(base2) (SINE_TABLE_SIZE * 8.175798916 / SAMPLE_RATE)
640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * 8.17578 is a reference to the frequency of MIDI note 0
660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org */
670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#if	defined (_SAMPLE_RATE_8000)
680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define MAGIC_NUMBER 1279
690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#elif	defined (_SAMPLE_RATE_16000)
700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define MAGIC_NUMBER 79
710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#elif	defined (_SAMPLE_RATE_20000)
720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define MAGIC_NUMBER -308
730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#elif	defined (_SAMPLE_RATE_22050)
740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define MAGIC_NUMBER -477
750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#elif	defined (_SAMPLE_RATE_24000)
760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define MAGIC_NUMBER -623
770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#elif defined (_SAMPLE_RATE_32000)
780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define MAGIC_NUMBER -1121
790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#elif defined (_SAMPLE_RATE_44100)
800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define MAGIC_NUMBER -1677
810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#elif defined (_SAMPLE_RATE_48000)
820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#define MAGIC_NUMBER -1823
830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/* externs */
860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgextern const EAS_I16 fmControlTable[128];
870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgextern const EAS_U16 fmRateTable[256];
880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgextern const EAS_U16 fmAttackTable[16];
890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgextern const EAS_U8 fmDecayTable[16];
900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgextern const EAS_U8 fmReleaseTable[16];
910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgextern const EAS_U8 fmScaleTable[16];
920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/* local prototypes */
940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*lint -esym(715, pVoiceMgr) standard synthesizer interface - pVoiceMgr not used */
950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic EAS_RESULT FM_Initialize (S_VOICE_MGR *pVoiceMgr) { return EAS_SUCCESS; }
960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex);
970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples);
980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum);
1000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum);
1010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel);
1020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*----------------------------------------------------------------------------
1050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Synthesizer interface
1060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
1070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org*/
1080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst S_SYNTH_INTERFACE fmSynth =
1090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
1100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	FM_Initialize,
1110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	FM_StartVoice,
1120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	FM_UpdateVoice,
1130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	FM_ReleaseVoice,
1140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	FM_MuteVoice,
1150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	FM_SustainPedal,
1160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	FM_UpdateChannel
1170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
1180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef FM_OFFBOARD
1200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst S_FRAME_INTERFACE fmFrameInterface =
1210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
1220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	FM_StartFrame,
1230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	FM_EndFrame
1240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
1250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
1260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*----------------------------------------------------------------------------
1280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * inline functions
1290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
1300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org */
1310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgEAS_INLINE S_FM_VOICE *GetFMVoicePtr (S_VOICE_MGR *pVoiceMgr, EAS_INT voiceNum)
1320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
1330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	return &pVoiceMgr->fmVoices[voiceNum];
1340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgEAS_INLINE S_SYNTH_CHANNEL *GetChannelPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice)
1360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
1370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	return &pSynth->channels[pVoice->channel & 15];
1380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgEAS_INLINE const S_FM_REGION *GetFMRegionPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice)
1400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
1410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef _SECONDARY_SYNTH
1420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	return &pSynth->pEAS->pFMRegions[pVoice->regionIndex & REGION_INDEX_MASK];
1430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#else
1440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	return &pSynth->pEAS->pFMRegions[pVoice->regionIndex];
1450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
1460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*----------------------------------------------------------------------------
1490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * FM_SynthIsOutputOperator
1500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
1510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Purpose:
1520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Returns true if the operator is a direct output and not muted
1530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
1540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Inputs:
1550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
1560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Outputs:
1570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Returns boolean
1580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
1590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org*/
1600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic EAS_BOOL FM_SynthIsOutputOperator (const S_FM_REGION *pRegion, EAS_INT operIndex)
1610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
1620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	/* see if voice is muted */
1640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	if ((pRegion->oper[operIndex].gain & 0xfc) == 0)
1650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		return 0;
1660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	/* check based on mode */
1680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	switch (pRegion->region.keyGroupAndFlags & 7)
1690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	{
1700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    /* mode 0 - all operators are external */
1720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    case 0:
1730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        return EAS_TRUE;
1740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    /* mode 1 - operators 1-3 are external */
1760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    case 1:
1770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    	if (operIndex != 0)
1780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        	return EAS_TRUE;
1790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		break;
1800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    /* mode 2 - operators 1 & 3 are external */
1820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    case 2:
1830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        if ((operIndex == 1) || (operIndex == 3))
1840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        	return EAS_TRUE;
1850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        break;
1860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    /* mode 2 - operators 1 & 2 are external */
1880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    case 3:
1890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        if ((operIndex == 1) || (operIndex == 2))
1900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        	return EAS_TRUE;
1910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        break;
1920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    /* modes 4 & 5 - operator 1 is external */
1940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    case 4:
1950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	    case 5:
1960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        if (operIndex == 1)
1970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        	return EAS_TRUE;
1980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	        break;
1990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		default:
2010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid voice mode: %d",
2020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org				pRegion->region.keyGroupAndFlags & 7); */ }
2030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	}
2040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	return EAS_FALSE;
2060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*----------------------------------------------------------------------------
2090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * FM_CalcEGRate()
2100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
2110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Purpose:
2120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
2130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Inputs:
2140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * nKeyNumber - MIDI note
2150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * nLogRate - logarithmic scale rate from patch data
2160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * nKeyScale - key scaling factor for this EG
2170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
2180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Outputs:
2190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * 16-bit linear multiplier
2200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
2210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org*/
2220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic EAS_U16 FM_CalcEGRate (EAS_U8 nKeyNumber, EAS_U8 nLogRate, EAS_U8 nEGScale)
2240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
2250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	EAS_I32 temp;
2260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    /* incorporate key scaling on release rate */
2280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    temp = (EAS_I32) nLogRate << 7;
2290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    temp += ((EAS_I32) nKeyNumber - EG_SCALE_PIVOT_POINT) * (EAS_I32) nEGScale;
2300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    /* saturate */
2320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    temp = max(temp, 0);
2330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    temp = min(temp, 32767);
2340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    /* look up in rate table */
2360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	/*lint -e{704} use shift for performance */
2370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return fmRateTable[temp >> 8];
2380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*----------------------------------------------------------------------------
2410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * FM_ReleaseVoice()
2420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
2430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Purpose:
2440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * The selected voice is being released.
2450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
2460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Inputs:
2470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * psEASData - pointer to S_EAS_DATA
2480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * pVoice - pointer to voice to release
2490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
2500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Outputs:
2510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * None
2520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
2530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org*/
2540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
2550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
2560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	EAS_INT operIndex;
2570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	const S_FM_REGION *pRegion;
2580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	S_FM_VOICE *pFMVoice;
2590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	/* check to see if voice responds to NOTE-OFF's */
2610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pRegion = GetFMRegionPtr(pSynth, pVoice);
2620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	if (pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT)
2630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		return;
2640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	/* set all envelopes to release state */
2660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
2670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	for (operIndex = 0; operIndex < 4; operIndex++)
2680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	{
2690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		pFMVoice->oper[operIndex].envState = eFMEnvelopeStateRelease;
2700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		/* incorporate key scaling on release rate */
2720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		pFMVoice->oper[operIndex].envRate = FM_CalcEGRate(
2730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org				pVoice->note,
2740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org				fmReleaseTable[pRegion->oper[operIndex].velocityRelease & 0x0f],
2750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org				fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]);
2760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	} /* end for (operIndex = 0; operIndex < 4; operIndex++) */
2770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*----------------------------------------------------------------------------
2800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * FM_MuteVoice()
2810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
2820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Purpose:
2830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * The selected voice is being muted.
2840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
2850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Inputs:
2860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * pVoice - pointer to voice to release
2870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
2880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Outputs:
2890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * None
2900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
2910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org*/
2920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*lint -esym(715, pSynth) standard interface, pVoiceMgr not used */
2930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum)
2940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
2950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	S_FM_VOICE *pFMVoice;
2960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	/* clear deferred action flags */
2980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pVoice->voiceFlags &=
2990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF |
3000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF |
3010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		VOICE_FLAG_DEFER_MUTE);
3020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	/* set all envelopes to muted state */
3040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
3050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pFMVoice->oper[0].envState = eFMEnvelopeStateMuted;
3060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pFMVoice->oper[1].envState = eFMEnvelopeStateMuted;
3070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pFMVoice->oper[2].envState = eFMEnvelopeStateMuted;
3080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pFMVoice->oper[3].envState = eFMEnvelopeStateMuted;
3090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*----------------------------------------------------------------------------
3120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * FM_SustainPedal()
3130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
3140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Purpose:
3150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * The selected voice is held due to sustain pedal
3160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
3170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Inputs:
3180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * pVoice - pointer to voice to sustain
3190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
3200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Outputs:
3210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * None
3220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
3230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org*/
3240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*lint -esym(715, pChannel) standard interface, pVoiceMgr not used */
3251a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.orgstatic void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum)
3260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org{
3270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	const S_FM_REGION *pRegion;
3280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	S_FM_VOICE *pFMVoice;
3290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	EAS_INT operIndex;
3300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pRegion = GetFMRegionPtr(pSynth, pVoice);
3320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
3330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	/* check to see if any envelopes are above the sustain level */
3350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	for (operIndex = 0; operIndex < 4; operIndex++)
3360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	{
3370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		/* if level control or envelope gain is zero, skip this envelope */
3390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		if (((pRegion->oper[operIndex].gain & 0xfc) == 0) ||
3400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			(pFMVoice->oper[operIndex].envGain == 0))
3411a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org		{
3420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			continue;
3430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		}
3440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		/* if the envelope gain is above the sustain level, we need to catch this voice */
3460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		if (pFMVoice->oper[operIndex].envGain >= ((EAS_U16) (pRegion->oper[operIndex].sustain & 0xfc) << 7))
3470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		{
3480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			/* reset envelope to decay state */
3500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay;
3510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			pFMVoice->oper[operIndex].envRate = FM_CalcEGRate(
3530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org					pVoice->note,
3540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org					fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f],
3550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org					fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]);
3560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			/* set voice to decay state */
3580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			pVoice->voiceState = eVoiceStatePlay;
3590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			/* set sustain flag */
3610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org			pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
3620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org		}
3630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org	} /* end for (operIndex = 0; operIndex < 4; operIndex++) */
3640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*----------------------------------------------------------------------------
3670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * FM_StartVoice()
3680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
3690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Purpose:
3700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Assign the region for the given instrument using the midi key number
3710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * and the RPN2 (coarse tuning) value. By using RPN2 as part of the
3720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * region selection process, we reduce the amount a given sample has
3730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * to be transposed by selecting the closest recorded root instead.
3740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
3750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * This routine is the second half of SynthAssignRegion().
3760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * If the region was successfully found by SynthFindRegionIndex(),
3770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * then assign the region's parameters to the voice.
3780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
3790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Setup and initialize the following voice parameters:
3800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * m_nRegionIndex
3810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
3820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Inputs:
3830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * pVoice - ptr to the voice we have assigned for this channel
3840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * nRegionIndex - index of the region
3850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * psEASData - pointer to overall EAS data structure
3860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
3870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Outputs:
3880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * success - could find and assign the region for this voice's note otherwise
3890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * failure - could not find nor assign the region for this voice's note
3900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
3910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Side Effects:
3920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * psSynthObject->m_sVoice[].m_nRegionIndex is assigned
3930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * psSynthObject->m_sVoice[] parameters are assigned
3940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *----------------------------------------------------------------------------
3950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org*/
3960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex)
397{
398	S_FM_VOICE *pFMVoice;
399	S_SYNTH_CHANNEL *pChannel;
400	const S_FM_REGION *pRegion;
401	EAS_I32 temp;
402	EAS_INT operIndex;
403
404	/* establish pointers to data */
405	pVoice->regionIndex = regionIndex;
406	pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
407	pChannel = GetChannelPtr(pSynth, pVoice);
408	pRegion = GetFMRegionPtr(pSynth, pVoice);
409
410	/* update static channel parameters */
411	if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS)
412		FM_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15);
413
414	/* init the LFO */
415	pFMVoice->lfoValue = 0;
416	pFMVoice->lfoPhase = 0;
417	pFMVoice->lfoDelay = (EAS_U16) (fmScaleTable[pRegion->lfoFreqDelay & 0x0f] >> 1);
418
419#if	(NUM_OUTPUT_CHANNELS == 2)
420	/* calculate pan gain values only if stereo output */
421	/* set up panning only at note start */
422	temp = (EAS_I32) pChannel->pan - 64;
423	temp += (EAS_I32) pRegion->pan;
424	if (temp < -64)
425		temp = -64;
426	if (temp > 64)
427		temp = 64;
428	pFMVoice->pan = (EAS_I8) temp;
429#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */
430
431	/* no samples have been synthesized for this note yet */
432	pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
433
434	/* initialize gain value for anti-zipper filter */
435	pFMVoice->voiceGain = (EAS_I16) EAS_LogToLinear16(pChannel->staticGain);
436	pFMVoice->voiceGain = (EAS_I16) FMUL_15x15(pFMVoice->voiceGain, pSynth->masterVolume);
437
438	/* initialize the operators */
439	for (operIndex = 0; operIndex < 4; operIndex++)
440	{
441
442		/* establish operator output gain level */
443		/*lint -e{701} <use shift for performance> */
444		pFMVoice->oper[operIndex].outputGain = EAS_LogToLinear16(((EAS_I16) (pRegion->oper[operIndex].gain & 0xfc) - 0xfc) << 7);
445
446		/* check for linear velocity flag */
447		/*lint -e{703} <use shift for performance> */
448		if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_LINEAR_VELOCITY)
449			temp = (EAS_I32) (pVoice->velocity - 127) << 5;
450		else
451			temp = (EAS_I32) fmControlTable[pVoice->velocity];
452
453		/* scale velocity */
454		/*lint -e{704} use shift for performance */
455		temp = (temp * (EAS_I32)(pRegion->oper[operIndex].velocityRelease & 0xf0)) >> 7;
456
457		/* include key scalar */
458		temp -= ((EAS_I32) pVoice->note - KEY_SCALE_PIVOT_POINT) * (EAS_I32) fmScaleTable[pRegion->oper[operIndex].egKeyScale & 0x0f];
459
460		/* saturate */
461		temp = min(temp, 0);
462		temp = max(temp, -32768);
463
464		/* save static gain parameters */
465		pFMVoice->oper[operIndex].baseGain = (EAS_I16) EAS_LogToLinear16(temp);
466
467		/* incorporate key scaling on decay rate */
468		pFMVoice->oper[operIndex].envRate = FM_CalcEGRate(
469			pVoice->note,
470			fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f],
471			fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]);
472
473		/* if zero attack time, max out envelope and jump to decay state */
474		if ((pRegion->oper[operIndex].attackDecay & 0xf0) == 0xf0)
475		{
476
477			/* start out envelope at max */
478			pFMVoice->oper[operIndex].envGain = 0x7fff;
479
480			/* set envelope to decay state */
481			pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay;
482		}
483
484		/* start envelope at zero and start in attack state */
485		else
486		{
487			pFMVoice->oper[operIndex].envGain = 0;
488			pFMVoice->oper[operIndex].envState = eFMEnvelopeStateAttack;
489		}
490	}
491
492	return EAS_SUCCESS;
493}
494
495/*----------------------------------------------------------------------------
496 * FM_UpdateChannel()
497 *----------------------------------------------------------------------------
498 * Purpose:
499 * Calculate and assign static channel parameters
500 * These values only need to be updated if one of the controller values
501 * for this channel changes.
502 * Called when CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS flag is set.
503 *
504 * Inputs:
505 * nChannel - channel to update
506 * psEASData - pointer to overall EAS data structure
507 *
508 * Outputs:
509 *
510 * Side Effects:
511 * - the given channel's static gain and static pitch are updated
512 *----------------------------------------------------------------------------
513*/
514/*lint -esym(715, pVoiceMgr) standard interface, pVoiceMgr not used */
515static void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
516{
517	S_SYNTH_CHANNEL *pChannel;
518	EAS_I32 temp;
519
520	pChannel = &pSynth->channels[channel];
521
522	/* convert CC7 volume controller to log scale */
523	temp = fmControlTable[pChannel->volume];
524
525	/* incorporate CC11 expression controller */
526	temp += fmControlTable[pChannel->expression];
527
528	/* saturate */
529	pChannel->staticGain = (EAS_I16) max(temp,-32768);
530
531	/* calculate pitch bend */
532	/*lint -e{703} <avoid multiply for performance>*/
533	temp = (((EAS_I32)(pChannel->pitchBend) << 2) - 32768);
534
535	temp = FMUL_15x15(temp, pChannel->pitchBendSensitivity);
536
537	/* include "magic number" compensation for sample rate and lookup table size */
538	temp += MAGIC_NUMBER;
539
540	/* if this is not a drum channel, then add in the per-channel tuning */
541	if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL))
542		temp += (pChannel->finePitch + (pChannel->coarsePitch * 100));
543
544	/* save static pitch */
545	pChannel->staticPitch = temp;
546
547	/* Calculate LFO modulation depth */
548	/* mod wheel to LFO depth */
549	temp = FMUL_15x15(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS,
550	pChannel->modWheel << (NUM_EG1_FRAC_BITS -7));
551
552	/* channel pressure to LFO depth */
553	pChannel->lfoAmt = (EAS_I16) (temp +
554	FMUL_15x15(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS,
555	pChannel->channelPressure << (NUM_EG1_FRAC_BITS -7)));
556
557	/* clear update flag */
558	pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
559	return;
560}
561
562/*----------------------------------------------------------------------------
563 * FM_UpdateLFO()
564 *----------------------------------------------------------------------------
565 * Purpose:
566 * Calculate the LFO for the given voice
567 *
568 * Inputs:
569 * pVoice - ptr to the voice whose LFO we want to update
570 * psEASData - pointer to overall EAS data structure - used for debug only
571 *
572 * Outputs:
573 *
574 * Side Effects:
575 * - updates LFO values for the given voice
576 *----------------------------------------------------------------------------
577*/
578static void FM_UpdateLFO (S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion)
579{
580
581	/* increment the LFO phase if the delay time has elapsed */
582	if (!pFMVoice->lfoDelay)
583	{
584		/*lint -e{701} <use shift for performance> */
585		pFMVoice->lfoPhase = pFMVoice->lfoPhase + (EAS_U16) (-fmControlTable[((15 - (pRegion->lfoFreqDelay >> 4)) << 3) + 4]);
586
587		/* square wave LFO? */
588		if (pRegion->region.keyGroupAndFlags & REGION_FLAG_SQUARE_WAVE)
589			pFMVoice->lfoValue = (EAS_I16)(pFMVoice->lfoPhase & 0x8000 ? -32767 : 32767);
590
591		/* trick to get a triangle wave out of a sawtooth */
592		else
593		{
594			pFMVoice->lfoValue = (EAS_I16) (pFMVoice->lfoPhase << 1);
595			/*lint -e{502} <shortcut to turn sawtooth into sine wave> */
596			if ((pFMVoice->lfoPhase > 0x3fff) && (pFMVoice->lfoPhase < 0xC000))
597				pFMVoice->lfoValue = ~pFMVoice->lfoValue;
598		}
599	}
600
601	/* still in delay */
602	else
603		pFMVoice->lfoDelay--;
604
605	return;
606}
607
608/*----------------------------------------------------------------------------
609 * FM_UpdateEG()
610 *----------------------------------------------------------------------------
611 * Purpose:
612 * Calculate the synthesis parameters for an operator to be used during
613 * the next buffer
614 *
615 * Inputs:
616 * pVoice - pointer to the voice being updated
617 * psEASData - pointer to overall EAS data structure
618 *
619 * Outputs:
620 *
621 * Side Effects:
622 *
623 *----------------------------------------------------------------------------
624*/
625static EAS_BOOL FM_UpdateEG (S_SYNTH_VOICE *pVoice, S_OPERATOR *pOper, const S_FM_OPER *pOperData, EAS_BOOL oneShot)
626{
627	EAS_U32 temp;
628	EAS_BOOL done;
629
630	/* set flag assuming the envelope is not done */
631	done = EAS_FALSE;
632
633	/* take appropriate action based on state */
634	switch (pOper->envState)
635	{
636
637		case eFMEnvelopeStateAttack:
638
639			/* the envelope is linear during the attack, so add the value */
640			temp = pOper->envGain + fmAttackTable[pOperData->attackDecay >> 4];
641
642			/* check for end of attack */
643			if (temp >= 0x7fff)
644			{
645				pOper->envGain = 0x7fff;
646				pOper->envState = eFMEnvelopeStateDecay;
647			}
648			else
649				pOper->envGain = (EAS_U16) temp;
650			break;
651
652		case eFMEnvelopeStateDecay:
653
654			/* decay is exponential, multiply by decay rate */
655			pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate);
656
657			/* check for sustain level reached */
658			temp = (EAS_U32) (pOperData->sustain & 0xfc) << 7;
659			if (pOper->envGain <= (EAS_U16) temp)
660			{
661				/* if this is a one-shot patch, go directly to release phase */
662				if (oneShot)
663				{
664					pOper->envRate = FM_CalcEGRate(
665					pVoice->note,
666					fmReleaseTable[pOperData->velocityRelease & 0x0f],
667					fmScaleTable[pOperData->egKeyScale >> 4]);
668					pOper->envState = eFMEnvelopeStateRelease;
669				}
670
671				/* normal sustaining type */
672				else
673				{
674					pOper->envGain = (EAS_U16) temp;
675					pOper->envState = eFMEnvelopeStateSustain;
676				}
677			}
678			break;
679
680		case eFMEnvelopeStateSustain:
681			pOper->envGain = (EAS_U16)((EAS_U16)(pOperData->sustain & 0xfc) << 7);
682			break;
683
684		case eFMEnvelopeStateRelease:
685
686			/* release is exponential, multiply by release rate */
687			pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate);
688
689			/* fully released */
690			if (pOper->envGain == 0)
691			{
692				pOper->envGain = 0;
693				pOper->envState = eFMEnvelopeStateMuted;
694				done = EAS_TRUE;
695			}
696			break;
697
698		case eFMEnvelopeStateMuted:
699			pOper->envGain = 0;
700			done = EAS_TRUE;
701			break;
702		default:
703			{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid operator state: %d", pOper->envState); */ }
704	} /* end switch (pOper->m_eState) */
705
706	return done;
707}
708
709/*----------------------------------------------------------------------------
710 * FM_UpdateDynamic()
711 *----------------------------------------------------------------------------
712 * Purpose:
713 * Calculate the synthesis parameters for this voice that will be used to
714 * synthesize the next buffer
715 *
716 * Inputs:
717 * pVoice - pointer to the voice being updated
718 * psEASData - pointer to overall EAS data structure
719 *
720 * Outputs:
721 * Returns EAS_TRUE if voice will be fully ramped to zero at the end of
722 * the next synthesized buffer.
723 *
724 * Side Effects:
725 *
726 *----------------------------------------------------------------------------
727*/
728static EAS_BOOL FM_UpdateDynamic (S_SYNTH_VOICE *pVoice, S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion, S_SYNTH_CHANNEL *pChannel)
729{
730	EAS_I32 temp;
731	EAS_I32 pitch;
732	EAS_I32 lfoPitch;
733	EAS_INT operIndex;
734	EAS_BOOL done;
735
736	/* increment LFO phase */
737	FM_UpdateLFO(pFMVoice, pRegion);
738
739	/* base pitch in cents */
740	pitch = pVoice->note * 100;
741
742	/* LFO amount includes LFO depth from programming + channel dynamics */
743	temp = (fmScaleTable[pRegion->vibTrem >> 4] >> 1) + pChannel->lfoAmt;
744
745	/* multiply by LFO output to get final pitch modulation */
746	lfoPitch = FMUL_15x15(pFMVoice->lfoValue, temp);
747
748	/* flag to indicate this voice is done */
749	done = EAS_TRUE;
750
751	/* iterate through operators to establish parameters */
752	for (operIndex = 0; operIndex < 4; operIndex++)
753	{
754		EAS_BOOL bTemp;
755
756		/* set base phase increment for each operator */
757		temp = pRegion->oper[operIndex].tuning +
758		pChannel->staticPitch;
759
760		/* add vibrato effect unless it is disabled for this operator */
761		if ((pRegion->oper[operIndex].flags & FM_OPER_FLAG_NO_VIBRATO) == 0)
762			temp += lfoPitch;
763
764		/* if note is monotonic, bias to MIDI note 60 */
765		if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_MONOTONE)
766			temp += 6000;
767		else
768			temp += pitch;
769		pFMVoice->oper[operIndex].pitch = (EAS_I16) temp;
770
771		/* calculate envelope, returns true if done */
772		bTemp = FM_UpdateEG(pVoice, &pFMVoice->oper[operIndex], &pRegion->oper[operIndex], pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT);
773
774		/* check if all output envelopes have completed */
775		if (FM_SynthIsOutputOperator(pRegion, operIndex))
776			done = done && bTemp;
777	}
778
779	return done;
780}
781
782/*----------------------------------------------------------------------------
783 * FM_UpdateVoice()
784 *----------------------------------------------------------------------------
785 * Purpose:
786 * Synthesize a block of samples for the given voice.
787 *
788 * Inputs:
789 * psEASData - pointer to overall EAS data structure
790 *
791 * Outputs:
792 * number of samples actually written to buffer
793 *
794 * Side Effects:
795 * - samples are added to the presently free buffer
796 *
797 *----------------------------------------------------------------------------
798*/
799static EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples)
800{
801	S_SYNTH_CHANNEL *pChannel;
802	const S_FM_REGION *pRegion;
803	S_FM_VOICE *pFMVoice;
804	S_FM_VOICE_CONFIG vCfg;
805	S_FM_VOICE_FRAME vFrame;
806	EAS_I32 temp;
807	EAS_INT oper;
808	EAS_U16 voiceGainTarget;
809	EAS_BOOL done;
810
811	/* setup some pointers */
812	pChannel = GetChannelPtr(pSynth, pVoice);
813	pRegion = GetFMRegionPtr(pSynth, pVoice);
814	pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum);
815
816	/* if the voice is just starting, get the voice configuration data */
817	if (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)
818	{
819
820		/* split architecture may limit the number of voice starts */
821#ifdef MAX_VOICE_STARTS
822		if (pVoiceMgr->numVoiceStarts == MAX_VOICE_STARTS)
823			return EAS_FALSE;
824		pVoiceMgr->numVoiceStarts++;
825#endif
826
827		/* get initial parameters */
828		vCfg.feedback = pRegion->feedback;
829		vCfg.voiceGain = (EAS_U16) pFMVoice->voiceGain;
830
831#if	(NUM_OUTPUT_CHANNELS == 2)
832		vCfg.pan = pFMVoice->pan;
833#endif
834
835		/* get voice mode */
836		vCfg.flags = pRegion->region.keyGroupAndFlags & 7;
837
838		/* get operator parameters */
839		for (oper = 0; oper < 4; oper++)
840		{
841			/* calculate initial gain */
842			vCfg.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain);
843			vCfg.outputGain[oper] = pFMVoice->oper[oper].outputGain;
844
845			/* copy noise waveform flag */
846			if (pRegion->oper[oper].flags & FM_OPER_FLAG_NOISE)
847				vCfg.flags |= (EAS_U8) (FLAG_FM_ENG_VOICE_OP1_NOISE << oper);
848		}
849
850#ifdef FM_OFFBOARD
851		FM_ConfigVoice(voiceNum, &vCfg, pVoiceMgr->pFrameBuffer);
852#else
853		FM_ConfigVoice(voiceNum, &vCfg, NULL);
854#endif
855
856		/* clear startup flag */
857		pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET;
858	}
859
860	/* calculate new synthesis parameters */
861	done = FM_UpdateDynamic(pVoice, pFMVoice, pRegion, pChannel);
862
863	/* calculate LFO gain modulation */
864	/*lint -e{702} <use shift for performance> */
865	temp = ((fmScaleTable[pRegion->vibTrem & 0x0f] >> 1) * pFMVoice->lfoValue) >> FM_LFO_GAIN_SHIFT;
866
867	/* include channel gain */
868	temp += pChannel->staticGain;
869
870	/* -32768 or lower is infinite attenuation */
871	if (temp < -32767)
872		voiceGainTarget = 0;
873
874	/* translate to linear gain multiplier */
875	else
876		voiceGainTarget = EAS_LogToLinear16(temp);
877
878	/* include synth master volume */
879	voiceGainTarget = (EAS_U16) FMUL_15x15(voiceGainTarget, pSynth->masterVolume);
880
881	/* save target values for this frame */
882	vFrame.voiceGain = voiceGainTarget;
883
884	/* assume voice output is zero */
885	pVoice->gain = 0;
886
887	/* save operator targets for this frame */
888	for (oper = 0; oper < 4; oper++)
889	{
890		vFrame.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain);
891		vFrame.pitch[oper] = pFMVoice->oper[oper].pitch;
892
893		/* use the highest output envelope level as the gain for the voice stealing algorithm */
894		if (FM_SynthIsOutputOperator(pRegion, oper))
895			pVoice->gain = max(pVoice->gain, (EAS_I16) vFrame.gain[oper]);
896	}
897
898	/* consider voice gain multiplier in calculating gain for stealing algorithm */
899	pVoice->gain = (EAS_I16) FMUL_15x15(voiceGainTarget, pVoice->gain);
900
901	/* synthesize samples */
902#ifdef FM_OFFBOARD
903	FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, pVoiceMgr->pFrameBuffer);
904#else
905	FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, NULL);
906#endif
907
908	return done;
909}
910
911