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