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