156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * File: 456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * fmsynth.c 556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Contents and purpose: 756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Implements the high-level FM synthesizer functions. 856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Copyright Sonic Network Inc. 2004 107df30109963092559d3760c0661a020f9daf1030The Android Open Source Project 117df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 127df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * you may not use this file except in compliance with the License. 137df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * You may obtain a copy of the License at 147df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * 157df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 167df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * 177df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 187df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 197df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 207df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * See the License for the specific language governing permissions and 217df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * limitations under the License. 2256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 2356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 2456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Revision Control: 2556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * $Revision: 795 $ 2656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ 2756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 2856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 2956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 3056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks// includes 3156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_host.h" 3256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_report.h" 3356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 3456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_data.h" 3556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_synth_protos.h" 3656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_audioconst.h" 3756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_fmengine.h" 3856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_math.h" 3956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 4056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* option sanity check */ 4156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _REVERB 4256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#error "No reverb for FM synthesizer" 4356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 4456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _CHORUS 4556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#error "No chorus for FM synthesizer" 4656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 4756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 4856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* 4956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * WARNING: These macros can cause unwanted side effects. Use them 5056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * with care. For example, min(x++,y++) will cause either x or y to be 5156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * incremented twice. 5256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks */ 5356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define min(a,b) ((a) < (b) ? (a) : (b)) 5456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define max(a,b) ((a) > (b) ? (a) : (b)) 5556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 5656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* pivot point for keyboard scalars */ 5756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define EG_SCALE_PIVOT_POINT 64 5856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define KEY_SCALE_PIVOT_POINT 36 5956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 6056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* This number is the negative of the frequency of the note (in cents) of 6156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * the sine wave played at unity. The number can be calculated as follows: 6256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 6356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * MAGIC_NUMBER = 1200 * log(base2) (SINE_TABLE_SIZE * 8.175798916 / SAMPLE_RATE) 6456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 6556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 8.17578 is a reference to the frequency of MIDI note 0 6656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks */ 6756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if defined (_SAMPLE_RATE_8000) 6856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define MAGIC_NUMBER 1279 6956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#elif defined (_SAMPLE_RATE_16000) 7056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define MAGIC_NUMBER 79 7156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#elif defined (_SAMPLE_RATE_20000) 7256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define MAGIC_NUMBER -308 7356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#elif defined (_SAMPLE_RATE_22050) 7456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define MAGIC_NUMBER -477 7556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#elif defined (_SAMPLE_RATE_24000) 7656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define MAGIC_NUMBER -623 7756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#elif defined (_SAMPLE_RATE_32000) 7856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define MAGIC_NUMBER -1121 7956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#elif defined (_SAMPLE_RATE_44100) 8056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define MAGIC_NUMBER -1677 8156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#elif defined (_SAMPLE_RATE_48000) 8256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#define MAGIC_NUMBER -1823 8356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 8456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 8556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* externs */ 8656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksextern const EAS_I16 fmControlTable[128]; 8756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksextern const EAS_U16 fmRateTable[256]; 8856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksextern const EAS_U16 fmAttackTable[16]; 8956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksextern const EAS_U8 fmDecayTable[16]; 9056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksextern const EAS_U8 fmReleaseTable[16]; 9156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksextern const EAS_U8 fmScaleTable[16]; 9256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 9356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* local prototypes */ 9456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*lint -esym(715, pVoiceMgr) standard synthesizer interface - pVoiceMgr not used */ 9556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_RESULT FM_Initialize (S_VOICE_MGR *pVoiceMgr) { return EAS_SUCCESS; } 9656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex); 9756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples); 9856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); 9956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum); 10056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum); 10156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel); 10256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 10356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 10456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 10556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Synthesizer interface 10656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 10756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 10856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksconst S_SYNTH_INTERFACE fmSynth = 10956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 11056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_Initialize, 11156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_StartVoice, 11256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_UpdateVoice, 11356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_ReleaseVoice, 11456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_MuteVoice, 11556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_SustainPedal, 11656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_UpdateChannel 11756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}; 11856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 11956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef FM_OFFBOARD 12056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksconst S_FRAME_INTERFACE fmFrameInterface = 12156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 12256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_StartFrame, 12356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_EndFrame 12456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks}; 12556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 12656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 12756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 12856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * inline functions 12956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 13056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks */ 13156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksEAS_INLINE S_FM_VOICE *GetFMVoicePtr (S_VOICE_MGR *pVoiceMgr, EAS_INT voiceNum) 13256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 13356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return &pVoiceMgr->fmVoices[voiceNum]; 13456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 13556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksEAS_INLINE S_SYNTH_CHANNEL *GetChannelPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) 13656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 13756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return &pSynth->channels[pVoice->channel & 15]; 13856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 13956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksEAS_INLINE const S_FM_REGION *GetFMRegionPtr (S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice) 14056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 14156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _SECONDARY_SYNTH 14256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return &pSynth->pEAS->pFMRegions[pVoice->regionIndex & REGION_INDEX_MASK]; 14356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#else 14456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return &pSynth->pEAS->pFMRegions[pVoice->regionIndex]; 14556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 14656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 14756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 14856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 14956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_SynthIsOutputOperator 15056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 15156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 15256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Returns true if the operator is a direct output and not muted 15356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 15456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 15556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 15656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 15756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Returns boolean 15856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 15956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 16056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_BOOL FM_SynthIsOutputOperator (const S_FM_REGION *pRegion, EAS_INT operIndex) 16156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 16256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 16356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* see if voice is muted */ 16456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if ((pRegion->oper[operIndex].gain & 0xfc) == 0) 16556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return 0; 16656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 16756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* check based on mode */ 16856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks switch (pRegion->region.keyGroupAndFlags & 7) 16956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 17056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 17156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* mode 0 - all operators are external */ 17256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 0: 17356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return EAS_TRUE; 17456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 17556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* mode 1 - operators 1-3 are external */ 17656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 1: 17756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (operIndex != 0) 17856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return EAS_TRUE; 17956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 18056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 18156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* mode 2 - operators 1 & 3 are external */ 18256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 2: 18356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if ((operIndex == 1) || (operIndex == 3)) 18456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return EAS_TRUE; 18556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 18656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 18756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* mode 2 - operators 1 & 2 are external */ 18856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 3: 18956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if ((operIndex == 1) || (operIndex == 2)) 19056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return EAS_TRUE; 19156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 19256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 19356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* modes 4 & 5 - operator 1 is external */ 19456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 4: 19556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 5: 19656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (operIndex == 1) 19756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return EAS_TRUE; 19856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 19956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 20056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks default: 20156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid voice mode: %d", 20256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pRegion->region.keyGroupAndFlags & 7); */ } 20356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 20456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 20556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return EAS_FALSE; 20656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 20756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 20856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 20956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_CalcEGRate() 21056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 21156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 21256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 21356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 21456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nKeyNumber - MIDI note 21556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nLogRate - logarithmic scale rate from patch data 21656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nKeyScale - key scaling factor for this EG 21756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 21856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 21956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 16-bit linear multiplier 22056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 22156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 22256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 22356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_U16 FM_CalcEGRate (EAS_U8 nKeyNumber, EAS_U8 nLogRate, EAS_U8 nEGScale) 22456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 22556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 temp; 22656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 22756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* incorporate key scaling on release rate */ 22856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (EAS_I32) nLogRate << 7; 22956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp += ((EAS_I32) nKeyNumber - EG_SCALE_PIVOT_POINT) * (EAS_I32) nEGScale; 23056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 23156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* saturate */ 23256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = max(temp, 0); 23356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = min(temp, 32767); 23456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 23556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* look up in rate table */ 23656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /*lint -e{704} use shift for performance */ 23756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return fmRateTable[temp >> 8]; 23856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 23956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 24056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 24156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_ReleaseVoice() 24256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 24356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 24456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * The selected voice is being released. 24556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 24656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 24756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to S_EAS_DATA 24856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pVoice - pointer to voice to release 24956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 25056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 25156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * None 25256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 25356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 25456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_ReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) 25556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 25656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_INT operIndex; 25756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks const S_FM_REGION *pRegion; 25856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_FM_VOICE *pFMVoice; 25956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 26056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* check to see if voice responds to NOTE-OFF's */ 26156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pRegion = GetFMRegionPtr(pSynth, pVoice); 26256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT) 26356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return; 26456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 26556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* set all envelopes to release state */ 26656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); 26756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks for (operIndex = 0; operIndex < 4; operIndex++) 26856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 26956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].envState = eFMEnvelopeStateRelease; 27056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 27156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* incorporate key scaling on release rate */ 27256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( 27356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->note, 27456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fmReleaseTable[pRegion->oper[operIndex].velocityRelease & 0x0f], 27556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); 27656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } /* end for (operIndex = 0; operIndex < 4; operIndex++) */ 27756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 27856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 27956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 28056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_MuteVoice() 28156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 28256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 28356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * The selected voice is being muted. 28456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 28556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 28656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pVoice - pointer to voice to release 28756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 28856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 28956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * None 29056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 29156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 29256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*lint -esym(715, pSynth) standard interface, pVoiceMgr not used */ 29356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_MuteVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum) 29456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 29556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_FM_VOICE *pFMVoice; 29656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 29756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* clear deferred action flags */ 29856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->voiceFlags &= 29956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF | 30056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF | 30156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks VOICE_FLAG_DEFER_MUTE); 30256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 30356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* set all envelopes to muted state */ 30456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); 30556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[0].envState = eFMEnvelopeStateMuted; 30656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[1].envState = eFMEnvelopeStateMuted; 30756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[2].envState = eFMEnvelopeStateMuted; 30856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[3].envState = eFMEnvelopeStateMuted; 30956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 31056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 31156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 31256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_SustainPedal() 31356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 31456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 31556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * The selected voice is held due to sustain pedal 31656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 31756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 31856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pVoice - pointer to voice to sustain 31956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 32056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 32156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * None 32256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 32356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 32456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*lint -esym(715, pChannel) standard interface, pVoiceMgr not used */ 32556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_SustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, S_SYNTH_CHANNEL *pChannel, EAS_I32 voiceNum) 32656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 32756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks const S_FM_REGION *pRegion; 32856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_FM_VOICE *pFMVoice; 32956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_INT operIndex; 33056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 33156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pRegion = GetFMRegionPtr(pSynth, pVoice); 33256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); 33356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 33456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* check to see if any envelopes are above the sustain level */ 33556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks for (operIndex = 0; operIndex < 4; operIndex++) 33656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 33756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 33856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* if level control or envelope gain is zero, skip this envelope */ 33956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (((pRegion->oper[operIndex].gain & 0xfc) == 0) || 34056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks (pFMVoice->oper[operIndex].envGain == 0)) 34156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 34256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks continue; 34356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 34456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 34556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* if the envelope gain is above the sustain level, we need to catch this voice */ 34656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pFMVoice->oper[operIndex].envGain >= ((EAS_U16) (pRegion->oper[operIndex].sustain & 0xfc) << 7)) 34756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 34856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 34956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* reset envelope to decay state */ 35056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay; 35156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 35256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( 35356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->note, 35456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f], 35556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); 35656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 35756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* set voice to decay state */ 35856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->voiceState = eVoiceStatePlay; 35956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 36056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* set sustain flag */ 36156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF; 36256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 36356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } /* end for (operIndex = 0; operIndex < 4; operIndex++) */ 36456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 36556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 36656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 36756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_StartVoice() 36856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 36956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 37056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Assign the region for the given instrument using the midi key number 37156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * and the RPN2 (coarse tuning) value. By using RPN2 as part of the 37256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * region selection process, we reduce the amount a given sample has 37356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * to be transposed by selecting the closest recorded root instead. 37456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 37556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * This routine is the second half of SynthAssignRegion(). 37656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * If the region was successfully found by SynthFindRegionIndex(), 37756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * then assign the region's parameters to the voice. 37856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 37956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Setup and initialize the following voice parameters: 38056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * m_nRegionIndex 38156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 38256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 38356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pVoice - ptr to the voice we have assigned for this channel 38456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nRegionIndex - index of the region 38556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure 38656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 38756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 38856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * success - could find and assign the region for this voice's note otherwise 38956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * failure - could not find nor assign the region for this voice's note 39056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 39156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects: 39256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psSynthObject->m_sVoice[].m_nRegionIndex is assigned 39356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psSynthObject->m_sVoice[] parameters are assigned 39456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 39556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 39656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_RESULT FM_StartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_U16 regionIndex) 39756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 39856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_FM_VOICE *pFMVoice; 39956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_SYNTH_CHANNEL *pChannel; 40056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks const S_FM_REGION *pRegion; 40156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 temp; 40256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_INT operIndex; 40356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 40456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* establish pointers to data */ 40556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->regionIndex = regionIndex; 40656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); 40756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel = GetChannelPtr(pSynth, pVoice); 40856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pRegion = GetFMRegionPtr(pSynth, pVoice); 40956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 41056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* update static channel parameters */ 41156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pChannel->channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS) 41256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_UpdateChannel(pVoiceMgr, pSynth, pVoice->channel & 15); 41356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 41456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* init the LFO */ 41556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->lfoValue = 0; 41656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->lfoPhase = 0; 41756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->lfoDelay = (EAS_U16) (fmScaleTable[pRegion->lfoFreqDelay & 0x0f] >> 1); 41856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 41956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if (NUM_OUTPUT_CHANNELS == 2) 42056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* calculate pan gain values only if stereo output */ 42156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* set up panning only at note start */ 42256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (EAS_I32) pChannel->pan - 64; 42356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp += (EAS_I32) pRegion->pan; 42456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (temp < -64) 42556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = -64; 42656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (temp > 64) 42756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = 64; 42856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->pan = (EAS_I8) temp; 42956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif /* #if (NUM_OUTPUT_CHANNELS == 2) */ 43056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 43156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* no samples have been synthesized for this note yet */ 43256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->voiceFlags = VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; 43356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 43456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* initialize gain value for anti-zipper filter */ 43556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->voiceGain = (EAS_I16) EAS_LogToLinear16(pChannel->staticGain); 43656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->voiceGain = (EAS_I16) FMUL_15x15(pFMVoice->voiceGain, pSynth->masterVolume); 43756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 43856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* initialize the operators */ 43956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks for (operIndex = 0; operIndex < 4; operIndex++) 44056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 44156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 44256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* establish operator output gain level */ 44356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /*lint -e{701} <use shift for performance> */ 44456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].outputGain = EAS_LogToLinear16(((EAS_I16) (pRegion->oper[operIndex].gain & 0xfc) - 0xfc) << 7); 44556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 44656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* check for linear velocity flag */ 44756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /*lint -e{703} <use shift for performance> */ 44856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_LINEAR_VELOCITY) 44956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (EAS_I32) (pVoice->velocity - 127) << 5; 45056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 45156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (EAS_I32) fmControlTable[pVoice->velocity]; 45256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 45356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* scale velocity */ 45456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /*lint -e{704} use shift for performance */ 45556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (temp * (EAS_I32)(pRegion->oper[operIndex].velocityRelease & 0xf0)) >> 7; 45656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 45756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* include key scalar */ 45856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp -= ((EAS_I32) pVoice->note - KEY_SCALE_PIVOT_POINT) * (EAS_I32) fmScaleTable[pRegion->oper[operIndex].egKeyScale & 0x0f]; 45956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 46056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* saturate */ 46156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = min(temp, 0); 46256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = max(temp, -32768); 46356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 46456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* save static gain parameters */ 46556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].baseGain = (EAS_I16) EAS_LogToLinear16(temp); 46656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 46756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* incorporate key scaling on decay rate */ 46856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].envRate = FM_CalcEGRate( 46956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->note, 47056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fmDecayTable[pRegion->oper[operIndex].attackDecay & 0x0f], 47156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fmScaleTable[pRegion->oper[operIndex].egKeyScale >> 4]); 47256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 47356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* if zero attack time, max out envelope and jump to decay state */ 47456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if ((pRegion->oper[operIndex].attackDecay & 0xf0) == 0xf0) 47556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 47656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 47756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* start out envelope at max */ 47856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].envGain = 0x7fff; 47956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 48056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* set envelope to decay state */ 48156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].envState = eFMEnvelopeStateDecay; 48256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 48356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 48456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* start envelope at zero and start in attack state */ 48556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 48656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 48756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].envGain = 0; 48856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].envState = eFMEnvelopeStateAttack; 48956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 49056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 49156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 49256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return EAS_SUCCESS; 49356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 49456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 49556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 49656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_UpdateChannel() 49756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 49856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 49956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Calculate and assign static channel parameters 50056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * These values only need to be updated if one of the controller values 50156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * for this channel changes. 50256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Called when CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS flag is set. 50356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 50456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 50556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * nChannel - channel to update 50656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure 50756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 50856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 50956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 51056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects: 51156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * - the given channel's static gain and static pitch are updated 51256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 51356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 51456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*lint -esym(715, pVoiceMgr) standard interface, pVoiceMgr not used */ 51556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_UpdateChannel (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel) 51656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 51756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_SYNTH_CHANNEL *pChannel; 51856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 temp; 51956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 52056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel = &pSynth->channels[channel]; 52156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 52256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* convert CC7 volume controller to log scale */ 52356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = fmControlTable[pChannel->volume]; 52456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 52556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* incorporate CC11 expression controller */ 52656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp += fmControlTable[pChannel->expression]; 52756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 52856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* saturate */ 52956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel->staticGain = (EAS_I16) max(temp,-32768); 53056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 53156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* calculate pitch bend */ 53256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /*lint -e{703} <avoid multiply for performance>*/ 53356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (((EAS_I32)(pChannel->pitchBend) << 2) - 32768); 53456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 53556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = FMUL_15x15(temp, pChannel->pitchBendSensitivity); 53656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 53756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* include "magic number" compensation for sample rate and lookup table size */ 53856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp += MAGIC_NUMBER; 53956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 54056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* if this is not a drum channel, then add in the per-channel tuning */ 54156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (!(pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)) 54256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp += (pChannel->finePitch + (pChannel->coarsePitch * 100)); 54356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 54456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* save static pitch */ 54556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel->staticPitch = temp; 54656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 54756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* Calculate LFO modulation depth */ 54856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* mod wheel to LFO depth */ 54956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = FMUL_15x15(DEFAULT_LFO_MOD_WHEEL_TO_PITCH_CENTS, 55056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel->modWheel << (NUM_EG1_FRAC_BITS -7)); 55156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 55256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* channel pressure to LFO depth */ 55356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel->lfoAmt = (EAS_I16) (temp + 55456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FMUL_15x15(DEFAULT_LFO_CHANNEL_PRESSURE_TO_PITCH_CENTS, 55556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel->channelPressure << (NUM_EG1_FRAC_BITS -7))); 55656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 55756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* clear update flag */ 55856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel->channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS; 55956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return; 56056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 56156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 56256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 56356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_UpdateLFO() 56456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 56556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 56656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Calculate the LFO for the given voice 56756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 56856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 56956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pVoice - ptr to the voice whose LFO we want to update 57056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure - used for debug only 57156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 57256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 57356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 57456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects: 57556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * - updates LFO values for the given voice 57656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 57756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 57856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FM_UpdateLFO (S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion) 57956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 58056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 58156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* increment the LFO phase if the delay time has elapsed */ 58256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (!pFMVoice->lfoDelay) 58356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 58456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /*lint -e{701} <use shift for performance> */ 58556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->lfoPhase = pFMVoice->lfoPhase + (EAS_U16) (-fmControlTable[((15 - (pRegion->lfoFreqDelay >> 4)) << 3) + 4]); 58656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 58756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* square wave LFO? */ 58856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pRegion->region.keyGroupAndFlags & REGION_FLAG_SQUARE_WAVE) 58956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->lfoValue = (EAS_I16)(pFMVoice->lfoPhase & 0x8000 ? -32767 : 32767); 59056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 59156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* trick to get a triangle wave out of a sawtooth */ 59256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 59356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 59456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->lfoValue = (EAS_I16) (pFMVoice->lfoPhase << 1); 59556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /*lint -e{502} <shortcut to turn sawtooth into sine wave> */ 59656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if ((pFMVoice->lfoPhase > 0x3fff) && (pFMVoice->lfoPhase < 0xC000)) 59756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->lfoValue = ~pFMVoice->lfoValue; 59856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 59956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 60056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 60156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* still in delay */ 60256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 60356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->lfoDelay--; 60456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 60556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return; 60656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 60756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 60856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 60956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_UpdateEG() 61056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 61156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 61256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Calculate the synthesis parameters for an operator to be used during 61356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * the next buffer 61456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 61556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 61656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pVoice - pointer to the voice being updated 61756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure 61856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 61956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 62056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 62156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects: 62256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 62356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 62456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 62556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_BOOL FM_UpdateEG (S_SYNTH_VOICE *pVoice, S_OPERATOR *pOper, const S_FM_OPER *pOperData, EAS_BOOL oneShot) 62656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 62756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U32 temp; 62856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_BOOL done; 62956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 63056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* set flag assuming the envelope is not done */ 63156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_FALSE; 63256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 63356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* take appropriate action based on state */ 63456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks switch (pOper->envState) 63556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 63656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 63756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case eFMEnvelopeStateAttack: 63856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 63956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* the envelope is linear during the attack, so add the value */ 64056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = pOper->envGain + fmAttackTable[pOperData->attackDecay >> 4]; 64156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 64256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* check for end of attack */ 64356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (temp >= 0x7fff) 64456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 64556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envGain = 0x7fff; 64656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envState = eFMEnvelopeStateDecay; 64756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 64856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 64956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envGain = (EAS_U16) temp; 65056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 65156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 65256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case eFMEnvelopeStateDecay: 65356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 65456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* decay is exponential, multiply by decay rate */ 65556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate); 65656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 65756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* check for sustain level reached */ 65856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (EAS_U32) (pOperData->sustain & 0xfc) << 7; 65956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pOper->envGain <= (EAS_U16) temp) 66056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 66156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* if this is a one-shot patch, go directly to release phase */ 66256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (oneShot) 66356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 66456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envRate = FM_CalcEGRate( 66556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->note, 66656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fmReleaseTable[pOperData->velocityRelease & 0x0f], 66756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fmScaleTable[pOperData->egKeyScale >> 4]); 66856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envState = eFMEnvelopeStateRelease; 66956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 67056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 67156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* normal sustaining type */ 67256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 67356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 67456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envGain = (EAS_U16) temp; 67556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envState = eFMEnvelopeStateSustain; 67656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 67756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 67856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 67956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 68056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case eFMEnvelopeStateSustain: 68156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envGain = (EAS_U16)((EAS_U16)(pOperData->sustain & 0xfc) << 7); 68256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 68356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 68456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case eFMEnvelopeStateRelease: 68556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 68656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* release is exponential, multiply by release rate */ 68756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envGain = (EAS_U16) FMUL_15x15(pOper->envGain, pOper->envRate); 68856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 68956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* fully released */ 69056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pOper->envGain == 0) 69156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 69256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envGain = 0; 69356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envState = eFMEnvelopeStateMuted; 69456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 69556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 69656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 69756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 69856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case eFMEnvelopeStateMuted: 69956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pOper->envGain = 0; 70056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 70156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 70256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks default: 70356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL,"Invalid operator state: %d", pOper->envState); */ } 70456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } /* end switch (pOper->m_eState) */ 70556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 70656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return done; 70756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 70856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 70956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 71056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_UpdateDynamic() 71156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 71256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 71356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Calculate the synthesis parameters for this voice that will be used to 71456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * synthesize the next buffer 71556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 71656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 71756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * pVoice - pointer to the voice being updated 71856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure 71956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 72056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 72156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Returns EAS_TRUE if voice will be fully ramped to zero at the end of 72256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * the next synthesized buffer. 72356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 72456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects: 72556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 72656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 72756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 72856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_BOOL FM_UpdateDynamic (S_SYNTH_VOICE *pVoice, S_FM_VOICE *pFMVoice, const S_FM_REGION *pRegion, S_SYNTH_CHANNEL *pChannel) 72956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 73056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 temp; 73156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 pitch; 73256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 lfoPitch; 73356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_INT operIndex; 73456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_BOOL done; 73556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 73656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* increment LFO phase */ 73756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_UpdateLFO(pFMVoice, pRegion); 73856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 73956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* base pitch in cents */ 74056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pitch = pVoice->note * 100; 74156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 74256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* LFO amount includes LFO depth from programming + channel dynamics */ 74356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (fmScaleTable[pRegion->vibTrem >> 4] >> 1) + pChannel->lfoAmt; 74456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 74556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* multiply by LFO output to get final pitch modulation */ 74656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks lfoPitch = FMUL_15x15(pFMVoice->lfoValue, temp); 74756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 74856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* flag to indicate this voice is done */ 74956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 75056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 75156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* iterate through operators to establish parameters */ 75256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks for (operIndex = 0; operIndex < 4; operIndex++) 75356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 75456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_BOOL bTemp; 75556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 75656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* set base phase increment for each operator */ 75756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = pRegion->oper[operIndex].tuning + 75856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel->staticPitch; 75956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 76056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* add vibrato effect unless it is disabled for this operator */ 76156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if ((pRegion->oper[operIndex].flags & FM_OPER_FLAG_NO_VIBRATO) == 0) 76256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp += lfoPitch; 76356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 76456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* if note is monotonic, bias to MIDI note 60 */ 76556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pRegion->oper[operIndex].flags & FM_OPER_FLAG_MONOTONE) 76656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp += 6000; 76756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 76856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp += pitch; 76956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice->oper[operIndex].pitch = (EAS_I16) temp; 77056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 77156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* calculate envelope, returns true if done */ 77256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks bTemp = FM_UpdateEG(pVoice, &pFMVoice->oper[operIndex], &pRegion->oper[operIndex], pRegion->region.keyGroupAndFlags & REGION_FLAG_ONE_SHOT); 77356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 77456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* check if all output envelopes have completed */ 77556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (FM_SynthIsOutputOperator(pRegion, operIndex)) 77656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = done && bTemp; 77756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 77856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 77956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return done; 78056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 78156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 78256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 78356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FM_UpdateVoice() 78456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 78556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: 78656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Synthesize a block of samples for the given voice. 78756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 78856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 78956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * psEASData - pointer to overall EAS data structure 79056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 79156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 79256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * number of samples actually written to buffer 79356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 79456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Side Effects: 79556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * - samples are added to the presently free buffer 79656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 79756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 79856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 79956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic EAS_BOOL FM_UpdateVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice, EAS_I32 voiceNum, EAS_I32 *pMixBuffer, EAS_I32 numSamples) 80056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 80156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_SYNTH_CHANNEL *pChannel; 80256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks const S_FM_REGION *pRegion; 80356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_FM_VOICE *pFMVoice; 80456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_FM_VOICE_CONFIG vCfg; 80556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks S_FM_VOICE_FRAME vFrame; 80656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 temp; 80756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_INT oper; 80856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U16 voiceGainTarget; 80956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_BOOL done; 81056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 81156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* setup some pointers */ 81256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pChannel = GetChannelPtr(pSynth, pVoice); 81356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pRegion = GetFMRegionPtr(pSynth, pVoice); 81456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pFMVoice = GetFMVoicePtr(pVoiceMgr, voiceNum); 81556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 81656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* if the voice is just starting, get the voice configuration data */ 81756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET) 81856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 81956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 82056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* split architecture may limit the number of voice starts */ 82156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef MAX_VOICE_STARTS 82256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pVoiceMgr->numVoiceStarts == MAX_VOICE_STARTS) 82356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return EAS_FALSE; 82456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoiceMgr->numVoiceStarts++; 82556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 82656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 82756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* get initial parameters */ 82856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vCfg.feedback = pRegion->feedback; 82956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vCfg.voiceGain = (EAS_U16) pFMVoice->voiceGain; 83056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 83156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#if (NUM_OUTPUT_CHANNELS == 2) 83256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vCfg.pan = pFMVoice->pan; 83356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 83456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 83556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* get voice mode */ 83656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vCfg.flags = pRegion->region.keyGroupAndFlags & 7; 83756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 83856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* get operator parameters */ 83956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks for (oper = 0; oper < 4; oper++) 84056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 84156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* calculate initial gain */ 84256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vCfg.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain); 84356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vCfg.outputGain[oper] = pFMVoice->oper[oper].outputGain; 84456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 84556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* copy noise waveform flag */ 84656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (pRegion->oper[oper].flags & FM_OPER_FLAG_NOISE) 84756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vCfg.flags |= (EAS_U8) (FLAG_FM_ENG_VOICE_OP1_NOISE << oper); 84856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 84956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 85056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef FM_OFFBOARD 85156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_ConfigVoice(voiceNum, &vCfg, pVoiceMgr->pFrameBuffer); 85256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#else 85356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_ConfigVoice(voiceNum, &vCfg, NULL); 85456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 85556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 85656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* clear startup flag */ 85756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->voiceFlags &= ~VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET; 85856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 85956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 86056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* calculate new synthesis parameters */ 86156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = FM_UpdateDynamic(pVoice, pFMVoice, pRegion, pChannel); 86256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 86356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* calculate LFO gain modulation */ 86456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /*lint -e{702} <use shift for performance> */ 86556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = ((fmScaleTable[pRegion->vibTrem & 0x0f] >> 1) * pFMVoice->lfoValue) >> FM_LFO_GAIN_SHIFT; 86656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 86756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* include channel gain */ 86856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp += pChannel->staticGain; 86956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 87056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* -32768 or lower is infinite attenuation */ 87156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (temp < -32767) 87256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks voiceGainTarget = 0; 87356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 87456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* translate to linear gain multiplier */ 87556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 87656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks voiceGainTarget = EAS_LogToLinear16(temp); 87756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 87856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* include synth master volume */ 87956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks voiceGainTarget = (EAS_U16) FMUL_15x15(voiceGainTarget, pSynth->masterVolume); 88056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 88156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* save target values for this frame */ 88256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vFrame.voiceGain = voiceGainTarget; 88356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 88456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* assume voice output is zero */ 88556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->gain = 0; 88656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 88756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* save operator targets for this frame */ 88856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks for (oper = 0; oper < 4; oper++) 88956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 89056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vFrame.gain[oper] = (EAS_U16) FMUL_15x15(pFMVoice->oper[oper].baseGain, pFMVoice->oper[oper].envGain); 89156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks vFrame.pitch[oper] = pFMVoice->oper[oper].pitch; 89256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 89356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* use the highest output envelope level as the gain for the voice stealing algorithm */ 89456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (FM_SynthIsOutputOperator(pRegion, oper)) 89556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->gain = max(pVoice->gain, (EAS_I16) vFrame.gain[oper]); 89656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 89756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 89856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* consider voice gain multiplier in calculating gain for stealing algorithm */ 89956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks pVoice->gain = (EAS_I16) FMUL_15x15(voiceGainTarget, pVoice->gain); 90056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 90156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* synthesize samples */ 90256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef FM_OFFBOARD 90356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, pVoiceMgr->pFrameBuffer); 90456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#else 90556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FM_ProcessVoice(voiceNum, &vFrame, numSamples, pVoiceMgr->operMixBuffer, pVoiceMgr->voiceBuffer, pMixBuffer, NULL); 90656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 90756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 90856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return done; 90956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 91056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 911