Home | History | Annotate | Download | only in lib_src
      1 /*----------------------------------------------------------------------------
      2  *
      3  * File:
      4  * eas_voicemgt.c
      5  *
      6  * Contents and purpose:
      7  * Implements the synthesizer functions.
      8  *
      9  * Copyright Sonic Network Inc. 2004
     10 
     11  * Licensed under the Apache License, Version 2.0 (the "License");
     12  * you may not use this file except in compliance with the License.
     13  * You may obtain a copy of the License at
     14  *
     15  *      http://www.apache.org/licenses/LICENSE-2.0
     16  *
     17  * Unless required by applicable law or agreed to in writing, software
     18  * distributed under the License is distributed on an "AS IS" BASIS,
     19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     20  * See the License for the specific language governing permissions and
     21  * limitations under the License.
     22  *
     23  *----------------------------------------------------------------------------
     24  * Revision Control:
     25  *   $Revision: 794 $
     26  *   $Date: 2007-08-01 00:08:48 -0700 (Wed, 01 Aug 2007) $
     27  *----------------------------------------------------------------------------
     28 */
     29 
     30 /* includes */
     31 #include "eas.h"
     32 #include "eas_data.h"
     33 #include "eas_config.h"
     34 #include "eas_report.h"
     35 #include "eas_midictrl.h"
     36 #include "eas_host.h"
     37 #include "eas_synth_protos.h"
     38 #include "eas_vm_protos.h"
     39 
     40 #ifdef DLS_SYNTHESIZER
     41 #include "eas_mdls.h"
     42 #endif
     43 
     44 // #define _DEBUG_VM
     45 
     46 /* some defines for workload */
     47 #define WORKLOAD_AMOUNT_SMALL_INCREMENT     5
     48 #define WORKLOAD_AMOUNT_START_NOTE          10
     49 #define WORKLOAD_AMOUNT_STOP_NOTE           10
     50 #define WORKLOAD_AMOUNT_KEY_GROUP           10
     51 #define WORKLOAD_AMOUNT_POLY_LIMIT          10
     52 
     53 /* pointer to base sound library */
     54 extern S_EAS easSoundLib;
     55 
     56 #ifdef TEST_HARNESS
     57 extern S_EAS easTestLib;
     58 EAS_SNDLIB_HANDLE VMGetLibHandle(EAS_INT libNum)
     59 {
     60     switch (libNum)
     61     {
     62         case 0:
     63             return &easSoundLib;
     64 #ifdef _WT_SYNTH
     65         case 1:
     66             return &easTestLib;
     67 #endif
     68         default:
     69             return NULL;
     70     }
     71 }
     72 #endif
     73 
     74 /* pointer to synthesizer interface(s) */
     75 #ifdef _WT_SYNTH
     76 extern const S_SYNTH_INTERFACE wtSynth;
     77 #endif
     78 
     79 #ifdef _FM_SYNTH
     80 extern const S_SYNTH_INTERFACE fmSynth;
     81 #endif
     82 
     83 typedef S_SYNTH_INTERFACE *S_SYNTH_INTERFACE_HANDLE;
     84 
     85 /* wavetable on MCU */
     86 #if defined(EAS_WT_SYNTH)
     87 const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth;
     88 
     89 /* FM on MCU */
     90 #elif defined(EAS_FM_SYNTH)
     91 const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth;
     92 
     93 /* wavetable drums on MCU, FM melodic on DSP */
     94 #elif defined(EAS_HYBRID_SYNTH)
     95 const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth;
     96 const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth;
     97 
     98 /* wavetable drums on MCU, wavetable melodic on DSP */
     99 #elif defined(EAS_SPLIT_WT_SYNTH)
    100 const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth;
    101 extern const S_FRAME_INTERFACE wtFrameInterface;
    102 const S_FRAME_INTERFACE *const pFrameInterface = &wtFrameInterface;
    103 
    104 /* wavetable drums on MCU, FM melodic on DSP */
    105 #elif defined(EAS_SPLIT_HYBRID_SYNTH)
    106 const S_SYNTH_INTERFACE *const pPrimarySynth = &wtSynth;
    107 const S_SYNTH_INTERFACE *const pSecondarySynth = &fmSynth;
    108 extern const S_FRAME_INTERFACE fmFrameInterface;
    109 const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface;
    110 
    111 /* FM on DSP */
    112 #elif defined(EAS_SPLIT_FM_SYNTH)
    113 const S_SYNTH_INTERFACE *const pPrimarySynth = &fmSynth;
    114 extern const S_FRAME_INTERFACE fmFrameInterface;
    115 const S_FRAME_INTERFACE *const pFrameInterface = &fmFrameInterface;
    116 
    117 #else
    118 #error "Undefined architecture option"
    119 #endif
    120 
    121 /*----------------------------------------------------------------------------
    122  * inline functions
    123  *----------------------------------------------------------------------------
    124 */
    125 EAS_INLINE const S_REGION* GetRegionPtr (S_SYNTH *pSynth, EAS_U16 regionIndex)
    126 {
    127 #if defined(DLS_SYNTHESIZER)
    128     if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
    129         return &pSynth->pDLS->pDLSRegions[regionIndex & REGION_INDEX_MASK].wtRegion.region;
    130 #endif
    131 #if defined(_HYBRID_SYNTH)
    132     if (regionIndex & FLAG_RGN_IDX_FM_SYNTH)
    133         return &pSynth->pEAS->pFMRegions[regionIndex & REGION_INDEX_MASK].region;
    134     else
    135         return &pSynth->pEAS->pWTRegions[regionIndex].region;
    136 #elif defined(_WT_SYNTH)
    137     return &pSynth->pEAS->pWTRegions[regionIndex].region;
    138 #elif defined(_FM_SYNTH)
    139     return &pSynth->pEAS->pFMRegions[regionIndex].region;
    140 #endif
    141 }
    142 
    143 /*lint -esym(715, voiceNum) used in some implementation */
    144 EAS_INLINE const S_SYNTH_INTERFACE* GetSynthPtr (EAS_INT voiceNum)
    145 {
    146 #if defined(_HYBRID_SYNTH)
    147     if (voiceNum < NUM_PRIMARY_VOICES)
    148         return pPrimarySynth;
    149     else
    150         return pSecondarySynth;
    151 #else
    152     return pPrimarySynth;
    153 #endif
    154 }
    155 
    156 EAS_INLINE EAS_INT GetAdjustedVoiceNum (EAS_INT voiceNum)
    157 {
    158 #if defined(_HYBRID_SYNTH)
    159     if (voiceNum >= NUM_PRIMARY_VOICES)
    160         return voiceNum - NUM_PRIMARY_VOICES;
    161 #endif
    162     return voiceNum;
    163 }
    164 
    165 EAS_INLINE EAS_U8 VSynthToChannel (S_SYNTH *pSynth, EAS_U8 channel)
    166 {
    167     /*lint -e{734} synthNum is always 0-15 */
    168     return channel | (pSynth->vSynthNum << 4);
    169 }
    170 
    171 /*----------------------------------------------------------------------------
    172  * InitVoice()
    173  *----------------------------------------------------------------------------
    174  * Initialize a synthesizer voice
    175  *----------------------------------------------------------------------------
    176 */
    177 void InitVoice (S_SYNTH_VOICE *pVoice)
    178 {
    179     pVoice->channel = UNASSIGNED_SYNTH_CHANNEL;
    180     pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL;
    181     pVoice->note = pVoice->nextNote = DEFAULT_KEY_NUMBER;
    182     pVoice->velocity = pVoice->nextVelocity = DEFAULT_VELOCITY;
    183     pVoice->regionIndex = DEFAULT_REGION_INDEX;
    184     pVoice->age = DEFAULT_AGE;
    185     pVoice->voiceFlags = DEFAULT_VOICE_FLAGS;
    186     pVoice->voiceState = DEFAULT_VOICE_STATE;
    187 }
    188 
    189 /*----------------------------------------------------------------------------
    190  * IncVoicePoolCount()
    191  *----------------------------------------------------------------------------
    192  * Updates the voice pool count when a voice changes state
    193  *----------------------------------------------------------------------------
    194 */
    195 static void IncVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice)
    196 {
    197     S_SYNTH *pSynth;
    198     EAS_INT pool;
    199 
    200     /* ignore muting voices */
    201     if (pVoice->voiceState == eVoiceStateMuting)
    202         return;
    203 
    204     if (pVoice->voiceState == eVoiceStateStolen)
    205     {
    206         pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)];
    207         pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool;
    208     }
    209     else
    210     {
    211         pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
    212         pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool;
    213     }
    214 
    215     pSynth->poolCount[pool]++;
    216 
    217 #ifdef _DEBUG_VM
    218     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IncVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ }
    219 #endif
    220 }
    221 
    222 /*----------------------------------------------------------------------------
    223  * DecVoicePoolCount()
    224  *----------------------------------------------------------------------------
    225  * Updates the voice pool count when a voice changes state
    226  *----------------------------------------------------------------------------
    227 */
    228 static void DecVoicePoolCount (S_VOICE_MGR *pVoiceMgr, S_SYNTH_VOICE *pVoice)
    229 {
    230     S_SYNTH *pSynth;
    231     EAS_INT pool;
    232 
    233     /* ignore muting voices */
    234     if (pVoice->voiceState == eVoiceStateMuting)
    235         return;
    236 
    237     if (pVoice->voiceState == eVoiceStateStolen)
    238     {
    239         pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)];
    240         pool = pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool;
    241     }
    242     else
    243     {
    244         pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
    245         pool = pSynth->channels[GET_CHANNEL(pVoice->channel)].pool;
    246     }
    247 
    248     pSynth->poolCount[pool]--;
    249 
    250 #ifdef _DEBUG_VM
    251     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "DecVoicePoolCount: Synth=%d pool=%d\n", pSynth->vSynthNum, pool); */ }
    252 #endif
    253 }
    254 
    255 /*----------------------------------------------------------------------------
    256  * VMInitialize()
    257  *----------------------------------------------------------------------------
    258  * Purpose:
    259  *
    260  * Inputs:
    261  * psEASData - pointer to overall EAS data structure
    262  *
    263  * Outputs:
    264  *
    265  *----------------------------------------------------------------------------
    266 */
    267 EAS_RESULT VMInitialize (S_EAS_DATA *pEASData)
    268 {
    269     S_VOICE_MGR *pVoiceMgr;
    270     EAS_INT i;
    271 
    272     /* check Configuration Module for data allocation */
    273     if (pEASData->staticMemoryModel)
    274         pVoiceMgr = EAS_CMEnumData(EAS_CM_SYNTH_DATA);
    275     else
    276         pVoiceMgr = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_VOICE_MGR));
    277     if (!pVoiceMgr)
    278     {
    279         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitialize: Failed to allocate synthesizer memory\n"); */ }
    280         return EAS_ERROR_MALLOC_FAILED;
    281     }
    282     EAS_HWMemSet(pVoiceMgr, 0, sizeof(S_VOICE_MGR));
    283 
    284     /* initialize non-zero variables */
    285     pVoiceMgr->pGlobalEAS = (S_EAS*) &easSoundLib;
    286     pVoiceMgr->maxPolyphony = (EAS_U16) MAX_SYNTH_VOICES;
    287 
    288 #if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH)
    289     pVoiceMgr->maxPolyphonyPrimary = NUM_PRIMARY_VOICES;
    290     pVoiceMgr->maxPolyphonySecondary = NUM_SECONDARY_VOICES;
    291 #endif
    292 
    293     /* set max workload to zero */
    294     pVoiceMgr->maxWorkLoad = 0;
    295 
    296     /* initialize the voice manager parameters */
    297     for (i = 0; i < MAX_SYNTH_VOICES; i++)
    298         InitVoice(&pVoiceMgr->voices[i]);
    299 
    300     /* initialize the synth */
    301     /*lint -e{522} return unused at this time */
    302     pPrimarySynth->pfInitialize(pVoiceMgr);
    303 
    304     /* initialize the off-chip synth */
    305 #ifdef _HYBRID_SYNTH
    306     /*lint -e{522} return unused at this time */
    307     pSecondarySynth->pfInitialize(pVoiceMgr);
    308 #endif
    309 
    310     pEASData->pVoiceMgr = pVoiceMgr;
    311     return EAS_SUCCESS;
    312 }
    313 
    314 /*----------------------------------------------------------------------------
    315  * VMInitMIDI()
    316  *----------------------------------------------------------------------------
    317  * Purpose:
    318  *
    319  * Inputs:
    320  * psEASData - pointer to overall EAS data structure
    321  *
    322  * Outputs:
    323  *
    324  *----------------------------------------------------------------------------
    325 */
    326 EAS_RESULT VMInitMIDI (S_EAS_DATA *pEASData, S_SYNTH **ppSynth)
    327 {
    328     EAS_RESULT result;
    329     S_SYNTH *pSynth;
    330     EAS_INT virtualSynthNum;
    331 
    332     *ppSynth = NULL;
    333 
    334     /* static memory model only allows one synth */
    335     if (pEASData->staticMemoryModel)
    336     {
    337         if (pEASData->pVoiceMgr->pSynth[0] != NULL)
    338         {
    339             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: No virtual synthesizer support for static memory model\n"); */ }
    340             return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER;
    341         }
    342 
    343         /* check Configuration Module for data allocation */
    344         pSynth = EAS_CMEnumData(EAS_CM_MIDI_DATA);
    345         virtualSynthNum = 0;
    346     }
    347 
    348     /* dynamic memory model */
    349     else
    350     {
    351         for (virtualSynthNum = 0; virtualSynthNum < MAX_VIRTUAL_SYNTHESIZERS; virtualSynthNum++)
    352             if (pEASData->pVoiceMgr->pSynth[virtualSynthNum] == NULL)
    353                 break;
    354         if (virtualSynthNum == MAX_VIRTUAL_SYNTHESIZERS)
    355         {
    356             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Exceeded number of active virtual synthesizers"); */ }
    357             return EAS_ERROR_NO_VIRTUAL_SYNTHESIZER;
    358         }
    359         pSynth = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SYNTH));
    360     }
    361 
    362     /* make sure we have a valid memory pointer */
    363     if (pSynth == NULL)
    364     {
    365         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI: Failed to allocate synthesizer memory\n"); */ }
    366         return EAS_ERROR_MALLOC_FAILED;
    367     }
    368     EAS_HWMemSet(pSynth, 0, sizeof(S_SYNTH));
    369 
    370     /* set the sound library pointer */
    371     if ((result = VMSetEASLib(pSynth, pEASData->pVoiceMgr->pGlobalEAS)) != EAS_SUCCESS)
    372     {
    373         VMMIDIShutdown(pEASData, pSynth);
    374         return result;
    375     }
    376 
    377     /* link in DLS bank if downloaded */
    378 #ifdef DLS_SYNTHESIZER
    379     if (pEASData->pVoiceMgr->pGlobalDLS)
    380     {
    381         pSynth->pDLS = pEASData->pVoiceMgr->pGlobalDLS;
    382         DLSAddRef(pSynth->pDLS);
    383     }
    384 #endif
    385 
    386     /* initialize MIDI state variables */
    387     pSynth->synthFlags = DEFAULT_SYNTH_FLAGS;
    388     pSynth->masterVolume = DEFAULT_SYNTH_MASTER_VOLUME;
    389     pSynth->refCount = 1;
    390     pSynth->priority = DEFAULT_SYNTH_PRIORITY;
    391     pSynth->poolAlloc[0] = (EAS_U8) pEASData->pVoiceMgr->maxPolyphony;
    392 
    393     VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth);
    394 
    395     pSynth->vSynthNum = (EAS_U8) virtualSynthNum;
    396     pEASData->pVoiceMgr->pSynth[virtualSynthNum] = pSynth;
    397 
    398     *ppSynth = pSynth;
    399     return EAS_SUCCESS;
    400 }
    401 
    402 /*----------------------------------------------------------------------------
    403  * VMIncRefCount()
    404  *----------------------------------------------------------------------------
    405  * Increment reference count for virtual synth
    406  *----------------------------------------------------------------------------
    407 */
    408 void VMIncRefCount (S_SYNTH *pSynth)
    409 {
    410     pSynth->refCount++;
    411 }
    412 
    413 /*----------------------------------------------------------------------------
    414  * VMReset()
    415  *----------------------------------------------------------------------------
    416  * Purpose:
    417  * We call this routine to start the process of reseting the synth.
    418  * This routine sets a flag for the entire synth indicating that we want
    419  * to reset.
    420  * We also force all voices to mute quickly.
    421  * However, we do not actually perform any synthesis in this routine. That
    422  * is, we do not ramp the voices down from this routine, but instead, we
    423  * let the "regular" synth processing steps take care of adding the ramp
    424  * down samples to the output buffer. After we are sure that all voices
    425  * have completed ramping down, we continue the process of resetting the
    426  * synth (from another routine).
    427  *
    428  * Inputs:
    429  * psEASData - pointer to overall EAS data structure
    430  * force - force reset even if voices are active
    431  *
    432  * Outputs:
    433  *
    434  * Side Effects:
    435  * - set a flag (in psSynthObject->m_nFlags) indicating synth reset requested.
    436  * - force all voices to update their envelope states to mute
    437  *
    438  *----------------------------------------------------------------------------
    439 */
    440 void VMReset (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_BOOL force)
    441 {
    442 
    443 #ifdef _DEBUG_VM
    444     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: request to reset synth. Force = %d\n", force); */ }
    445 #endif
    446 
    447     /* force voices to off state - may cause audio artifacts */
    448     if (force)
    449     {
    450         pVoiceMgr->activeVoices -= pSynth->numActiveVoices;
    451         pSynth->numActiveVoices = 0;
    452         VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum);
    453     }
    454     else
    455         VMMuteAllVoices(pVoiceMgr, pSynth);
    456 
    457     /* don't reset if voices are still playing */
    458     if (pSynth->numActiveVoices == 0)
    459     {
    460         EAS_INT i;
    461 
    462 #ifdef _DEBUG_VM
    463         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReset: complete the reset process\n"); */ }
    464 #endif
    465 
    466         VMInitializeAllChannels(pVoiceMgr, pSynth);
    467         for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
    468             pSynth->poolCount[i] = 0;
    469 
    470         /* set polyphony */
    471         if (pSynth->maxPolyphony < pVoiceMgr->maxPolyphony)
    472             pSynth->poolAlloc[0] = (EAS_U8) pVoiceMgr->maxPolyphony;
    473         else
    474             pSynth->poolAlloc[0] = (EAS_U8) pSynth->maxPolyphony;
    475 
    476         /* clear reset flag */
    477         pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED;
    478     }
    479 
    480     /* handle reset after voices are muted */
    481     else
    482         pSynth->synthFlags |= SYNTH_FLAG_RESET_IS_REQUESTED;
    483 }
    484 
    485 /*----------------------------------------------------------------------------
    486  * VMInitializeAllChannels()
    487  *----------------------------------------------------------------------------
    488  * Purpose:
    489  *
    490  * Inputs:
    491  * psEASData - pointer to overall EAS data structure
    492  *
    493  * Outputs:
    494  *
    495  *----------------------------------------------------------------------------
    496 */
    497 void VMInitializeAllChannels (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
    498 {
    499     S_SYNTH_CHANNEL *pChannel;
    500     EAS_INT i;
    501 
    502     VMResetControllers(pSynth);
    503 
    504     /* init each channel */
    505     pChannel = pSynth->channels;
    506 
    507     for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++)
    508     {
    509         pChannel->channelFlags = DEFAULT_CHANNEL_FLAGS;
    510         pChannel->staticGain = DEFAULT_CHANNEL_STATIC_GAIN;
    511         pChannel->staticPitch = DEFAULT_CHANNEL_STATIC_PITCH;
    512         pChannel->pool = 0;
    513 
    514         /* the drum channel needs a different init */
    515         if (i == DEFAULT_DRUM_CHANNEL)
    516         {
    517             pChannel->bankNum = DEFAULT_RHYTHM_BANK_NUMBER;
    518             pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL;
    519         }
    520         else
    521             pChannel->bankNum = DEFAULT_MELODY_BANK_NUMBER;
    522 
    523         VMProgramChange(pVoiceMgr, pSynth, (EAS_U8) i, DEFAULT_SYNTH_PROGRAM_NUMBER);
    524     }
    525 
    526 }
    527 
    528 /*----------------------------------------------------------------------------
    529  * VMResetControllers()
    530  *----------------------------------------------------------------------------
    531  * Purpose:
    532  *
    533  * Inputs:
    534  * psEASData - pointer to overall EAS data structure
    535  *
    536  * Outputs:
    537  *
    538  *----------------------------------------------------------------------------
    539 */
    540 void VMResetControllers (S_SYNTH *pSynth)
    541 {
    542     S_SYNTH_CHANNEL *pChannel;
    543     EAS_INT i;
    544 
    545     pChannel = pSynth->channels;
    546 
    547     for (i = 0; i < NUM_SYNTH_CHANNELS; i++, pChannel++)
    548     {
    549         pChannel->pitchBend = DEFAULT_PITCH_BEND;
    550         pChannel->modWheel = DEFAULT_MOD_WHEEL;
    551         pChannel->volume = DEFAULT_CHANNEL_VOLUME;
    552         pChannel->pan = DEFAULT_PAN;
    553         pChannel->expression = DEFAULT_EXPRESSION;
    554 
    555 #ifdef  _REVERB
    556         pSynth->channels[i].reverbSend = DEFAULT_REVERB_SEND;
    557 #endif
    558 
    559 #ifdef  _CHORUS
    560         pSynth->channels[i].chorusSend = DEFAULT_CHORUS_SEND;
    561 #endif
    562 
    563         pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE;
    564         pChannel->registeredParam = DEFAULT_REGISTERED_PARAM;
    565         pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY;
    566         pChannel->finePitch = DEFAULT_FINE_PITCH;
    567         pChannel->coarsePitch = DEFAULT_COARSE_PITCH;
    568 
    569         /* update all voices on this channel */
    570         pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
    571     }
    572 }
    573 
    574 /*----------------------------------------------------------------------------
    575  * VMInitializeAllVoices()
    576  *----------------------------------------------------------------------------
    577  * Purpose:
    578  *
    579  * Inputs:
    580  * psEASData - pointer to overall EAS data structure
    581  *
    582  * Outputs:
    583  *
    584  *----------------------------------------------------------------------------
    585 */
    586 void VMInitializeAllVoices (S_VOICE_MGR *pVoiceMgr, EAS_INT vSynthNum)
    587 {
    588     EAS_INT i;
    589 
    590     /* initialize the voice manager parameters */
    591     for (i = 0; i < MAX_SYNTH_VOICES; i++)
    592     {
    593         if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen)
    594         {
    595             if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == vSynthNum)
    596                 InitVoice(&pVoiceMgr->voices[i]);
    597         }
    598         else
    599         {
    600             if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == vSynthNum)
    601                 InitVoice(&pVoiceMgr->voices[i]);
    602         }
    603     }
    604 }
    605 
    606 /*----------------------------------------------------------------------------
    607  * VMMuteVoice()
    608  *----------------------------------------------------------------------------
    609  * Mute the selected voice
    610  *----------------------------------------------------------------------------
    611 */
    612 void VMMuteVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum)
    613 {
    614     S_SYNTH *pSynth;
    615     S_SYNTH_VOICE *pVoice;
    616 
    617     /* take no action if voice is already muted */
    618     pVoice = &pVoiceMgr->voices[voiceNum];
    619     if ((pVoice->voiceState == eVoiceStateMuting) || (pVoice->voiceState == eVoiceStateFree))
    620         return;
    621 
    622     /* one less voice in pool */
    623     DecVoicePoolCount(pVoiceMgr, pVoice);
    624 
    625     pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
    626     GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum));
    627     pVoice->voiceState = eVoiceStateMuting;
    628 
    629 }
    630 
    631 /*----------------------------------------------------------------------------
    632  * VMReleaseVoice()
    633  *----------------------------------------------------------------------------
    634  * Release the selected voice
    635  *----------------------------------------------------------------------------
    636 */
    637 void VMReleaseVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum)
    638 {
    639     S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum];
    640 
    641     /* take no action if voice is already free, muting, or releasing */
    642     if (( pVoice->voiceState == eVoiceStateMuting) ||
    643         (pVoice->voiceState == eVoiceStateFree) ||
    644         (pVoice->voiceState == eVoiceStateRelease))
    645             return;
    646 
    647     /* stolen voices should just be muted */
    648     if (pVoice->voiceState == eVoiceStateStolen)
    649         VMMuteVoice(pVoiceMgr, voiceNum);
    650 
    651     /* release this voice */
    652     GetSynthPtr(voiceNum)->pfReleaseVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum));
    653     pVoice->voiceState = eVoiceStateRelease;
    654 }
    655 
    656 /*----------------------------------------------------------------------------
    657  * VMInitMIPTable()
    658  *----------------------------------------------------------------------------
    659  * Initialize the SP-MIDI MIP table in preparation for receiving MIP message
    660  *----------------------------------------------------------------------------
    661 */
    662 void VMInitMIPTable (S_SYNTH *pSynth)
    663 {
    664     EAS_INT i;
    665 
    666 #ifdef _DEBUG_VM
    667     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMInitMIPTable\n"); */ }
    668 #endif
    669 
    670     /* clear SP-MIDI flag */
    671     pSynth->synthFlags &= ~SYNTH_FLAG_SP_MIDI_ON;
    672     for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
    673     {
    674         pSynth->channels[i].pool = 0;
    675         pSynth->channels[i].mip = 0;
    676     }
    677 }
    678 
    679 /*----------------------------------------------------------------------------
    680  * VMSetMIPEntry()
    681  *----------------------------------------------------------------------------
    682  * Sets the priority and MIP level for a MIDI channel
    683  *----------------------------------------------------------------------------
    684 */
    685 /*lint -esym(715, pVoiceMgr) reserved for future use */
    686 void VMSetMIPEntry (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 priority, EAS_U8 mip)
    687 {
    688 
    689 #ifdef _DEBUG_VM
    690     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMSetMIPEntry: channel=%d, priority=%d, MIP=%d\n", channel, priority, mip); */ }
    691 #endif
    692 
    693     /* save data for use by MIP message processing */
    694     if (priority < NUM_SYNTH_CHANNELS)
    695     {
    696         pSynth->channels[channel].pool = priority;
    697         pSynth->channels[channel].mip = mip;
    698     }
    699 }
    700 
    701 /*----------------------------------------------------------------------------
    702  * VMMIPUpdateChannelMuting()
    703  *----------------------------------------------------------------------------
    704  * This routine is called after an SP-MIDI message is received and
    705  * any time the allocated polyphony changes. It mutes or unmutes
    706  * channels based on polyphony.
    707  *----------------------------------------------------------------------------
    708 */
    709 void VMMIPUpdateChannelMuting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
    710 {
    711     EAS_INT i;
    712     EAS_INT maxPolyphony;
    713     EAS_INT channel;
    714     EAS_INT vSynthNum;
    715     EAS_INT pool;
    716 
    717 #ifdef _DEBUG_VM
    718     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ }
    719 #endif
    720 
    721     /* determine max polyphony */
    722     if (pSynth->maxPolyphony)
    723         maxPolyphony = pSynth->maxPolyphony;
    724     else
    725         maxPolyphony = pVoiceMgr->maxPolyphony;
    726 
    727     /* process channels */
    728     for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
    729     {
    730 
    731         /* channel must be in MIP message and must meet allocation target */
    732         if ((pSynth->channels[i].mip != 0) && (pSynth->channels[i].mip <= maxPolyphony))
    733             pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_MUTE;
    734         else
    735             pSynth->channels[i].channelFlags |= CHANNEL_FLAG_MUTE;
    736 
    737         /* reset voice pool count */
    738         pSynth->poolCount[i] = 0;
    739     }
    740 
    741     /* mute any voices on muted channels, and count unmuted voices */
    742     for (i = 0; i < MAX_SYNTH_VOICES; i++)
    743     {
    744 
    745         /* ignore free voices */
    746         if (pVoiceMgr->voices[i].voiceState == eVoiceStateFree)
    747             continue;
    748 
    749         /* get channel and virtual synth */
    750         if (pVoiceMgr->voices[i].voiceState != eVoiceStateStolen)
    751         {
    752             vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].channel);
    753             channel = GET_CHANNEL(pVoiceMgr->voices[i].channel);
    754         }
    755         else
    756         {
    757             vSynthNum = GET_VSYNTH(pVoiceMgr->voices[i].nextChannel);
    758             channel = GET_CHANNEL(pVoiceMgr->voices[i].nextChannel);
    759         }
    760 
    761         /* ignore voices on other synths */
    762         if (vSynthNum != pSynth->vSynthNum)
    763             continue;
    764 
    765         /* count voices */
    766         pool = pSynth->channels[channel].pool;
    767 
    768         /* deal with muted channels */
    769         if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_MUTE)
    770         {
    771             /* mute stolen voices scheduled to play on this channel */
    772             if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen)
    773                 pVoiceMgr->voices[i].voiceState = eVoiceStateMuting;
    774 
    775             /* release voices that aren't already muting */
    776             else if (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting)
    777             {
    778                 VMReleaseVoice(pVoiceMgr, pSynth, i);
    779                 pSynth->poolCount[pool]++;
    780             }
    781         }
    782 
    783         /* not muted, count this voice */
    784         else
    785             pSynth->poolCount[pool]++;
    786     }
    787 }
    788 
    789 /*----------------------------------------------------------------------------
    790  * VMUpdateMIPTable()
    791  *----------------------------------------------------------------------------
    792  * This routine is called at the end of the SysEx message to allow
    793  * the Voice Manager to complete the initialization of the MIP
    794  * table. It assigns channels to the appropriate voice pool based
    795  * on the MIP setting and calculates the voices allocated for each
    796  * pool.
    797  *----------------------------------------------------------------------------
    798 */
    799 /*lint -esym(715, pVoiceMgr) reserved for future use */
    800 void VMUpdateMIPTable (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
    801 {
    802     S_SYNTH_CHANNEL *pChannel;
    803     EAS_INT i;
    804     EAS_INT currentMIP;
    805     EAS_INT currentPool;
    806     EAS_INT priority[NUM_SYNTH_CHANNELS];
    807 
    808 #ifdef _DEBUG_VM
    809     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateMIPTable\n"); */ }
    810 #endif
    811 
    812     /* set SP-MIDI flag */
    813     pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON;
    814 
    815     /* sort channels into priority order */
    816     for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
    817         priority[i] = -1;
    818     for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
    819     {
    820         if (pSynth->channels[i].pool != DEFAULT_SP_MIDI_PRIORITY)
    821             priority[pSynth->channels[i].pool] = i;
    822     }
    823 
    824     /* process channels in priority order */
    825     currentMIP = 0;
    826     currentPool = -1;
    827     for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
    828     {
    829         /* stop when we run out of channels */
    830         if (priority[i] == -1)
    831             break;
    832 
    833         pChannel = &pSynth->channels[priority[i]];
    834 
    835         /* when 2 or more channels have the same MIP setting, they
    836          * share a common voice pool
    837          */
    838         if (pChannel->mip == currentMIP && currentPool != -1)
    839             pChannel->pool = (EAS_U8) currentPool;
    840 
    841         /* new voice pool */
    842         else
    843         {
    844             currentPool++;
    845             pSynth->poolAlloc[currentPool] = (EAS_U8) (pChannel->mip - currentMIP);
    846             currentMIP = pChannel->mip;
    847         }
    848     }
    849 
    850     /* set SP-MIDI flag */
    851     pSynth->synthFlags |= SYNTH_FLAG_SP_MIDI_ON;
    852 
    853     /* update channel muting */
    854     VMMIPUpdateChannelMuting (pVoiceMgr, pSynth);
    855 }
    856 
    857 /*----------------------------------------------------------------------------
    858  * VMMuteAllVoices()
    859  *----------------------------------------------------------------------------
    860  * Purpose:
    861  * We call this in an emergency reset situation.
    862  * This forces all voices to mute quickly.
    863  *
    864  * Inputs:
    865  * psEASData - pointer to overall EAS data structure
    866  *
    867  * Outputs:
    868  *
    869  * Side Effects:
    870  * - forces all voices to update their envelope states to mute
    871  *
    872  *----------------------------------------------------------------------------
    873 */
    874 void VMMuteAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
    875 {
    876     EAS_INT i;
    877 
    878 #ifdef _DEBUG_VM
    879     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMMuteAllVoices: about to mute all voices!!\n"); */ }
    880 #endif
    881 
    882     for (i = 0; i < MAX_SYNTH_VOICES; i++)
    883     {
    884         /* for stolen voices, check new channel */
    885         if (pVoiceMgr->voices[i].voiceState == eVoiceStateStolen)
    886         {
    887             if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum)
    888                 VMMuteVoice(pVoiceMgr, i);
    889         }
    890 
    891         else if (pSynth->vSynthNum == GET_VSYNTH(pVoiceMgr->voices[i].channel))
    892             VMMuteVoice(pVoiceMgr, i);
    893     }
    894 }
    895 
    896 /*----------------------------------------------------------------------------
    897  * VMReleaseAllVoices()
    898  *----------------------------------------------------------------------------
    899  * Purpose:
    900  * We call this after we've encountered the end of the Midi file.
    901  * This ensures all voices are either in release (because we received their
    902  * note off already) or forces them to mute quickly.
    903  * We use this as a safety to prevent bad midi files from playing forever.
    904  *
    905  * Inputs:
    906  * psEASData - pointer to overall EAS data structure
    907  *
    908  * Outputs:
    909  *
    910  * Side Effects:
    911  * - forces all voices to update their envelope states to release or mute
    912  *
    913  *----------------------------------------------------------------------------
    914 */
    915 void VMReleaseAllVoices (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
    916 {
    917     EAS_INT i;
    918 
    919     /* release sustain pedal on all channels */
    920     for (i = 0; i < NUM_SYNTH_CHANNELS; i++)
    921     {
    922         if (pSynth->channels[ i ].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
    923         {
    924             VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, (EAS_U8) i);
    925             pSynth->channels[i].channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL;
    926         }
    927     }
    928 
    929     /* release all voices */
    930     for (i = 0; i < MAX_SYNTH_VOICES; i++)
    931     {
    932 
    933         switch (pVoiceMgr->voices[i].voiceState)
    934         {
    935             case eVoiceStateStart:
    936             case eVoiceStatePlay:
    937                 /* only release voices on this synth */
    938                 if (GET_VSYNTH(pVoiceMgr->voices[i].channel) == pSynth->vSynthNum)
    939                     VMReleaseVoice(pVoiceMgr, pSynth, i);
    940                 break;
    941 
    942             case eVoiceStateStolen:
    943                 if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) == pSynth->vSynthNum)
    944                     VMMuteVoice(pVoiceMgr, i);
    945                 break;
    946 
    947             case eVoiceStateFree:
    948             case eVoiceStateRelease:
    949             case eVoiceStateMuting:
    950                 break;
    951 
    952             case eVoiceStateInvalid:
    953             default:
    954 #ifdef _DEBUG_VM
    955                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllVoices: error, %d is an unrecognized state\n",
    956                     pVoiceMgr->voices[i].voiceState); */ }
    957 #endif
    958                 break;
    959         }
    960     }
    961 }
    962 
    963 /*----------------------------------------------------------------------------
    964  * VMAllNotesOff()
    965  *----------------------------------------------------------------------------
    966  * Purpose:
    967  * Quickly mute all notes on the given channel.
    968  *
    969  * Inputs:
    970  * nChannel - quickly turn off all notes on this channel
    971  * psEASData - pointer to overall EAS data structure
    972  *
    973  * Outputs:
    974  *
    975  * Side Effects:
    976  * - forces all voices on this channel to update their envelope states to mute
    977  *
    978  *----------------------------------------------------------------------------
    979 */
    980 void VMAllNotesOff (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
    981 {
    982     EAS_INT voiceNum;
    983     S_SYNTH_VOICE *pVoice;
    984 
    985 #ifdef _DEBUG_VM
    986     if (channel >= NUM_SYNTH_CHANNELS)
    987     {
    988         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAllNotesOff: error, %d invalid channel number\n",
    989             channel); */ }
    990         return;
    991     }
    992 #endif
    993 
    994     /* increment workload */
    995     pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT;
    996 
    997     /* check each voice */
    998     channel = VSynthToChannel(pSynth, channel);
    999     for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
   1000     {
   1001         pVoice = &pVoiceMgr->voices[voiceNum];
   1002         if (pVoice->voiceState != eVoiceStateFree)
   1003         {
   1004             if (((pVoice->voiceState != eVoiceStateStolen) && (channel == pVoice->channel)) ||
   1005                 ((pVoice->voiceState == eVoiceStateStolen) && (channel == pVoice->nextChannel)))
   1006             {
   1007                 /* this voice is assigned to the requested channel */
   1008                 GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pSynth, pVoice, GetAdjustedVoiceNum(voiceNum));
   1009                 pVoice->voiceState = eVoiceStateMuting;
   1010             }
   1011         }
   1012     }
   1013 }
   1014 
   1015 /*----------------------------------------------------------------------------
   1016  * VMDeferredStopNote()
   1017  *----------------------------------------------------------------------------
   1018  * Purpose:
   1019  * Stop the notes that had deferred note-off requests.
   1020  *
   1021  * Inputs:
   1022  * psEASData - pointer to overall EAS data structure
   1023  *
   1024  * Outputs:
   1025  * None.
   1026  *
   1027  * Side Effects:
   1028  * voices that have had deferred note-off requests are now put into release
   1029  * psSynthObject->m_sVoice[i].m_nFlags has the VOICE_FLAG_DEFER_MIDI_NOTE_OFF
   1030  *  cleared
   1031  *----------------------------------------------------------------------------
   1032 */
   1033 void VMDeferredStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
   1034 {
   1035     EAS_INT voiceNum;
   1036     EAS_INT channel;
   1037     EAS_BOOL deferredNoteOff;
   1038 
   1039     deferredNoteOff = EAS_FALSE;
   1040 
   1041     /* check each voice to see if it requires a deferred note off */
   1042     for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
   1043     {
   1044         if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF)
   1045         {
   1046             /* check if this voice was stolen */
   1047             if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen)
   1048             {
   1049                 /*
   1050                 This voice was stolen, AND it also has a deferred note-off.
   1051                 The stolen note must be completely ramped down at this point.
   1052                 The note that caused the stealing to occur, however, must
   1053                 have received a note-off request before the note that caused
   1054                 stealing ever had a chance to even start. We want to give
   1055                 the note that caused the stealing a chance to play, so we
   1056                 start it on the next update interval, and we defer sending
   1057                 the note-off request until the subsequent update interval.
   1058                 So do not send the note-off request for this voice because
   1059                 this voice was stolen and should have completed ramping down,
   1060                 Also, do not clear the global flag nor this voice's flag
   1061                 because we must indicate that the subsequent update interval,
   1062                 after the note that caused stealing has started, should
   1063                 then send the deferred note-off request.
   1064                 */
   1065                 deferredNoteOff = EAS_TRUE;
   1066 
   1067 #ifdef _DEBUG_VM
   1068                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: defer request to stop voice %d (channel=%d note=%d) - voice not started\n",
   1069                     voiceNum,
   1070                     pVoiceMgr->voices[voiceNum].nextChannel,
   1071                     pVoiceMgr->voices[voiceNum].note); */ }
   1072 
   1073                 /* sanity check: this stolen voice better be ramped to zero */
   1074                 if (0 != pVoiceMgr->voices[voiceNum].gain)
   1075                 {
   1076                     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: warning, this voice did not complete its ramp to zero\n"); */ }
   1077                 }
   1078 #endif  // #ifdef _DEBUG_VM
   1079 
   1080             }
   1081             else
   1082             {
   1083                 /* clear the flag using exor */
   1084                 pVoiceMgr->voices[voiceNum].voiceFlags ^=
   1085                     VOICE_FLAG_DEFER_MIDI_NOTE_OFF;
   1086 
   1087 #ifdef _DEBUG_VM
   1088                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMDeferredStopNote: Stop voice %d (channel=%d note=%d)\n",
   1089                     voiceNum,
   1090                     pVoiceMgr->voices[voiceNum].nextChannel,
   1091                     pVoiceMgr->voices[voiceNum].note); */ }
   1092 #endif
   1093 
   1094                 channel = pVoiceMgr->voices[voiceNum].channel & 15;
   1095 
   1096                 /* check if sustain pedal is on */
   1097                 if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
   1098                 {
   1099                     GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum));
   1100                 }
   1101 
   1102                 /* release this voice */
   1103                 else
   1104                     VMReleaseVoice(pVoiceMgr, pSynth, voiceNum);
   1105 
   1106             }
   1107 
   1108         }
   1109 
   1110     }
   1111 
   1112     /* clear the deferred note-off flag, unless there's another one pending */
   1113     if (deferredNoteOff == EAS_FALSE)
   1114         pSynth->synthFlags ^= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING;
   1115 }
   1116 
   1117 /*----------------------------------------------------------------------------
   1118  * VMReleaseAllDeferredNoteOffs()
   1119  *----------------------------------------------------------------------------
   1120  * Purpose:
   1121  * Call this functin when the sustain flag is presently set but
   1122  * we are now transitioning from damper pedal on to
   1123  * damper pedal off. This means all notes in this channel
   1124  * that received a note off while the damper pedal was on, and
   1125  * had their note-off requests deferred, should now proceed to
   1126  * the release state.
   1127  *
   1128  * Inputs:
   1129  * nChannel - this channel has its sustain pedal transitioning from on to off
   1130  * psEASData - pointer to overall EAS data structure
   1131  *
   1132  * Outputs:
   1133  * Side Effects:
   1134  * any voice with deferred note offs on this channel are updated such that
   1135  * pVoice->m_sEG1.m_eState = eEnvelopeStateRelease
   1136  * pVoice->m_sEG1.m_nIncrement = release increment
   1137  * pVoice->m_nFlags = clear the deferred note off flag
   1138  *----------------------------------------------------------------------------
   1139 */
   1140 void VMReleaseAllDeferredNoteOffs (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
   1141 {
   1142     S_SYNTH_VOICE *pVoice;
   1143     EAS_INT voiceNum;
   1144 
   1145 #ifdef _DEBUG_VM
   1146     if (channel >= NUM_SYNTH_CHANNELS)
   1147     {
   1148         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMReleaseAllDeferredNoteOffs: error, %d invalid channel number\n",
   1149             channel); */ }
   1150         return;
   1151     }
   1152 #endif  /* #ifdef _DEBUG_VM */
   1153 
   1154     /* increment workload */
   1155     pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT;
   1156 
   1157     /* find all the voices assigned to this channel */
   1158     channel = VSynthToChannel(pSynth, channel);
   1159     for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
   1160     {
   1161 
   1162         pVoice = &pVoiceMgr->voices[voiceNum];
   1163         if (channel == pVoice->channel)
   1164         {
   1165 
   1166             /* does this voice have a deferred note off? */
   1167             if (pVoice->voiceFlags & VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF)
   1168             {
   1169                 /* release voice */
   1170                 VMReleaseVoice(pVoiceMgr, pSynth, voiceNum);
   1171 
   1172                 /* use exor to flip bit, clear the flag */
   1173                 pVoice->voiceFlags &= ~VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
   1174 
   1175             }
   1176 
   1177         }
   1178     }
   1179 
   1180     return;
   1181 }
   1182 
   1183 /*----------------------------------------------------------------------------
   1184  * VMCatchNotesForSustainPedal()
   1185  *----------------------------------------------------------------------------
   1186  * Purpose:
   1187  * Call this function when the sustain flag is presently clear and
   1188  * the damper pedal is off and we are transitioning from damper pedal OFF to
   1189  * damper pedal ON. Currently sounding notes should be left
   1190  * unchanged. However, we should try to "catch" notes if possible.
   1191  * If any notes are in release and have levels >= sustain level, catch them,
   1192  * otherwise, let them continue to release.
   1193  *
   1194  * Inputs:
   1195  * nChannel - this channel has its sustain pedal transitioning from on to off
   1196  * psEASData - pointer to overall EAS data structure
   1197  *
   1198  * Outputs:
   1199  *----------------------------------------------------------------------------
   1200 */
   1201 void VMCatchNotesForSustainPedal (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel)
   1202 {
   1203     EAS_INT voiceNum;
   1204 
   1205 #ifdef _DEBUG_VM
   1206     if (channel >= NUM_SYNTH_CHANNELS)
   1207     {
   1208         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCatchNotesForSustainPedal: error, %d invalid channel number\n",
   1209             channel); */ }
   1210         return;
   1211     }
   1212 #endif
   1213 
   1214     pVoiceMgr->workload += WORKLOAD_AMOUNT_SMALL_INCREMENT;
   1215     channel = VSynthToChannel(pSynth, channel);
   1216 
   1217     /* find all the voices assigned to this channel */
   1218     for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
   1219     {
   1220         if (channel == pVoiceMgr->voices[voiceNum].channel)
   1221         {
   1222             if (eVoiceStateRelease == pVoiceMgr->voices[voiceNum].voiceState)
   1223                 GetSynthPtr(voiceNum)->pfSustainPedal(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], &pSynth->channels[channel], GetAdjustedVoiceNum(voiceNum));
   1224         }
   1225     }
   1226 }
   1227 
   1228 /*----------------------------------------------------------------------------
   1229  * VMUpdateAllNotesAge()
   1230  *----------------------------------------------------------------------------
   1231  * Purpose:
   1232  * Increment the note age for all of the active voices.
   1233  *
   1234  * Inputs:
   1235  * psEASData - pointer to overall EAS data structure
   1236  *
   1237  * Outputs:
   1238  *
   1239  * Side Effects:
   1240  * m_nAge for all voices is incremented
   1241  *----------------------------------------------------------------------------
   1242 */
   1243 void VMUpdateAllNotesAge (S_VOICE_MGR *pVoiceMgr, EAS_U16 age)
   1244 {
   1245     EAS_INT i;
   1246 
   1247     for (i = 0; i < MAX_SYNTH_VOICES; i++)
   1248     {
   1249         if (age - pVoiceMgr->voices[i].age > 0)
   1250             pVoiceMgr->voices[i].age++;
   1251      }
   1252 }
   1253 
   1254 /*----------------------------------------------------------------------------
   1255  * VMStolenVoice()
   1256  *----------------------------------------------------------------------------
   1257  * Purpose:
   1258  * The selected voice is being stolen. Sets the parameters so that the
   1259  * voice will begin playing the new sound on the next buffer.
   1260  *
   1261  * Inputs:
   1262  * pVoice - pointer to voice to steal
   1263  * nChannel - the channel to start a note on
   1264  * nKeyNumber - the key number to start a note for
   1265  * nNoteVelocity - the key velocity from this note
   1266  *
   1267  * Outputs:
   1268  * None
   1269  *----------------------------------------------------------------------------
   1270 */
   1271 static void VMStolenVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 voiceNum, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex)
   1272 {
   1273     S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum];
   1274 
   1275     /* one less voice in old pool */
   1276     DecVoicePoolCount(pVoiceMgr, pVoice);
   1277 
   1278     /* mute the sound that is currently playing */
   1279     GetSynthPtr(voiceNum)->pfMuteVoice(pVoiceMgr, pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)], &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum));
   1280     pVoice->voiceState = eVoiceStateStolen;
   1281 
   1282     /* set new note data */
   1283     pVoice->nextChannel = VSynthToChannel(pSynth, channel);
   1284     pVoice->nextNote = note;
   1285     pVoice->nextVelocity = velocity;
   1286     pVoice->nextRegionIndex = regionIndex;
   1287 
   1288     /* one more voice in new pool */
   1289     IncVoicePoolCount(pVoiceMgr, pVoice);
   1290 
   1291     /* clear the deferred flags */
   1292     pVoice->voiceFlags &=
   1293         ~(VOICE_FLAG_DEFER_MIDI_NOTE_OFF |
   1294         VOICE_FLAG_DEFER_MUTE |
   1295         VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF);
   1296 
   1297     /* all notes older than this one get "younger" */
   1298     VMUpdateAllNotesAge(pVoiceMgr, pVoice->age);
   1299 
   1300     /* assign current age to this note and increment for the next note */
   1301     pVoice->age = pVoiceMgr->age++;
   1302 }
   1303 
   1304 /*----------------------------------------------------------------------------
   1305  * VMFreeVoice()
   1306  *----------------------------------------------------------------------------
   1307  * Purpose:
   1308  * The selected voice is done playing and being returned to the
   1309  * pool of free voices
   1310  *
   1311  * Inputs:
   1312  * pVoice - pointer to voice to free
   1313  *
   1314  * Outputs:
   1315  * None
   1316  *----------------------------------------------------------------------------
   1317 */
   1318 static void VMFreeVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, S_SYNTH_VOICE *pVoice)
   1319 {
   1320 
   1321     /* do nothing if voice is already free */
   1322     if (pVoice->voiceState == eVoiceStateFree)
   1323     {
   1324         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMFreeVoice: Attempt to free voice that is already free\n"); */ }
   1325         return;
   1326     }
   1327 
   1328     /* if we jump directly to free without passing muting stage,
   1329      * we need to adjust the voice count */
   1330     DecVoicePoolCount(pVoiceMgr, pVoice);
   1331 
   1332 
   1333 #ifdef _DEBUG_VM
   1334     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMFreeVoice: Synth=%d\n", pSynth->vSynthNum); */ }
   1335 #endif
   1336 
   1337     /* return to free voice pool */
   1338     pVoiceMgr->activeVoices--;
   1339     pSynth->numActiveVoices--;
   1340     InitVoice(pVoice);
   1341 
   1342 #ifdef _DEBUG_VM
   1343     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFreeVoice: free voice %d\n", pVoice - pVoiceMgr->voices); */ }
   1344 #endif
   1345 
   1346     /* all notes older than this one get "younger" */
   1347     VMUpdateAllNotesAge(pVoiceMgr, pVoice->age);
   1348  }
   1349 
   1350 /*----------------------------------------------------------------------------
   1351  * VMRetargetStolenVoice()
   1352  *----------------------------------------------------------------------------
   1353  * Purpose:
   1354  * The selected voice has been stolen and needs to be initalized with
   1355  * the paramters of its new note.
   1356  *
   1357  * Inputs:
   1358  * pVoice - pointer to voice to retarget
   1359  *
   1360  * Outputs:
   1361  * None
   1362  *----------------------------------------------------------------------------
   1363 */
   1364 static EAS_BOOL VMRetargetStolenVoice (S_VOICE_MGR *pVoiceMgr, EAS_I32 voiceNum)
   1365 {
   1366     EAS_U8 flags;
   1367     S_SYNTH_CHANNEL *pMIDIChannel;
   1368     S_SYNTH_VOICE *pVoice;
   1369     S_SYNTH *pSynth;
   1370     S_SYNTH *pNextSynth;
   1371 
   1372     /* establish some pointers */
   1373     pVoice = &pVoiceMgr->voices[voiceNum];
   1374     pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
   1375     pMIDIChannel = &pSynth->channels[pVoice->channel & 15];
   1376     pNextSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->nextChannel)];
   1377 
   1378 #ifdef _DEBUG_VM
   1379 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: retargeting stolen voice %d on channel %d\n",
   1380         voiceNum, pVoice->channel); */ }
   1381 
   1382     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\to channel %d note: %d velocity: %d\n",
   1383         pVoice->nextChannel, pVoice->nextNote, pVoice->nextVelocity); */ }
   1384 #endif
   1385 
   1386     /* make sure new channel hasn't been muted by SP-MIDI since the voice was stolen */
   1387     if ((pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON) &&
   1388         (pMIDIChannel->channelFlags & CHANNEL_FLAG_MUTE))
   1389     {
   1390         VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]);
   1391         return EAS_FALSE;
   1392     }
   1393 
   1394     /* if assigned to a new synth, correct the active voice count */
   1395     if (pVoice->channel != pVoice->nextChannel)
   1396     {
   1397 #ifdef _DEBUG_VM
   1398         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetStolenVoice: Note assigned to different virtual synth, adjusting numActiveVoices\n"); */ }
   1399 #endif
   1400         pSynth->numActiveVoices--;
   1401         pNextSynth->numActiveVoices++;
   1402     }
   1403 
   1404     /* assign new channel number, and increase channel voice count */
   1405     pVoice->channel = pVoice->nextChannel;
   1406     pMIDIChannel = &pNextSynth->channels[pVoice->channel & 15];
   1407 
   1408     /* assign other data */
   1409     pVoice->note = pVoice->nextNote;
   1410     pVoice->velocity = pVoice->nextVelocity;
   1411     pVoice->nextChannel = UNASSIGNED_SYNTH_CHANNEL;
   1412     pVoice->regionIndex = pVoice->nextRegionIndex;
   1413 
   1414     /* save the flags, pfStartVoice() will clear them */
   1415     flags = pVoice->voiceFlags;
   1416 
   1417     /* keep track of the note-start related workload */
   1418     pVoiceMgr->workload += WORKLOAD_AMOUNT_START_NOTE;
   1419 
   1420     /* setup the voice parameters */
   1421     pVoice->voiceState = eVoiceStateStart;
   1422 
   1423     /*lint -e{522} return not used at this time */
   1424     GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pNextSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pVoice->regionIndex);
   1425 
   1426     /* did the new note already receive a MIDI note-off request? */
   1427     if (flags & VOICE_FLAG_DEFER_MIDI_NOTE_OFF)
   1428     {
   1429 #ifdef _DEBUG_VM
   1430         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMRetargetVoice: stolen note note-off request deferred\n"); */ }
   1431 #endif
   1432         pVoice->voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF;
   1433         pNextSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING;
   1434     }
   1435 
   1436     return EAS_TRUE;
   1437 }
   1438 
   1439 /*----------------------------------------------------------------------------
   1440  * VMCheckKeyGroup()
   1441  *----------------------------------------------------------------------------
   1442  * If the note that we've been asked to start is in the same key group as
   1443  * any currently playing notes, then we must shut down the currently playing
   1444  * note in the same key group
   1445  *----------------------------------------------------------------------------
   1446 */
   1447 void VMCheckKeyGroup (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U16 keyGroup, EAS_U8 channel)
   1448 {
   1449     const S_REGION *pRegion;
   1450     EAS_INT voiceNum;
   1451 
   1452     /* increment frame workload */
   1453     pVoiceMgr->workload += WORKLOAD_AMOUNT_KEY_GROUP;
   1454 
   1455     /* need to check all voices in case this is a layered sound */
   1456     channel = VSynthToChannel(pSynth, channel);
   1457     for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
   1458     {
   1459         if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen)
   1460         {
   1461             /* voice must be on the same channel */
   1462             if (channel == pVoiceMgr->voices[voiceNum].channel)
   1463             {
   1464                 /* check key group */
   1465                 pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].regionIndex);
   1466                 if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00))
   1467                 {
   1468 #ifdef _DEBUG_VM
   1469                     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ }
   1470 #endif
   1471 
   1472                     /* if this voice was just started, set it to mute on the next buffer */
   1473                     if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)
   1474                         pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE;
   1475 
   1476                     /* mute immediately */
   1477                     else
   1478                         VMMuteVoice(pVoiceMgr, voiceNum);
   1479                 }
   1480             }
   1481         }
   1482 
   1483         /* for stolen voice, check new values */
   1484         else
   1485         {
   1486             /* voice must be on the same channel */
   1487             if (channel == pVoiceMgr->voices[voiceNum].nextChannel)
   1488             {
   1489                 /* check key group */
   1490                 pRegion = GetRegionPtr(pSynth, pVoiceMgr->voices[voiceNum].nextRegionIndex);
   1491                 if (keyGroup == (pRegion->keyGroupAndFlags & 0x0f00))
   1492                 {
   1493 #ifdef _DEBUG_VM
   1494                     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckKeyGroup: voice %d matches key group %d\n", voiceNum, keyGroup >> 8); */ }
   1495 #endif
   1496 
   1497                     /* if this voice was just started, set it to mute on the next buffer */
   1498                     if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)
   1499                         pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MUTE;
   1500 
   1501                     /* mute immediately */
   1502                     else
   1503                         VMMuteVoice(pVoiceMgr, voiceNum);
   1504                 }
   1505             }
   1506 
   1507         }
   1508     }
   1509 }
   1510 
   1511 /*----------------------------------------------------------------------------
   1512  * VMCheckPolyphonyLimiting()
   1513  *----------------------------------------------------------------------------
   1514  * Purpose:
   1515  * We only play at most 2 of the same note on a MIDI channel.
   1516  * E.g., if we are asked to start note 36, and there are already two voices
   1517  * that are playing note 36, then we must steal the voice playing
   1518  * the oldest note 36 and use that stolen voice to play the new note 36.
   1519  *
   1520  * Inputs:
   1521  * nChannel - synth channel that wants to start a new note
   1522  * nKeyNumber - new note's midi note number
   1523  * nNoteVelocity - new note's velocity
   1524  * psEASData - pointer to overall EAS data structure
   1525  *
   1526  * Outputs:
   1527  * pbVoiceStealingRequired - flag: this routine sets true if we needed to
   1528  *                                 steal a voice
   1529  * *
   1530  * Side Effects:
   1531  * psSynthObject->m_sVoice[free voice num].m_nKeyNumber may be assigned
   1532  * psSynthObject->m_sVoice[free voice num].m_nVelocity may be assigned
   1533  *----------------------------------------------------------------------------
   1534 */
   1535 EAS_BOOL VMCheckPolyphonyLimiting (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex, EAS_I32 lowVoice, EAS_I32 highVoice)
   1536 {
   1537     EAS_INT voiceNum;
   1538     EAS_INT oldestVoiceNum;
   1539     EAS_INT numVoicesPlayingNote;
   1540     EAS_U16 age;
   1541     EAS_U16 oldestNoteAge;
   1542 
   1543     pVoiceMgr->workload += WORKLOAD_AMOUNT_POLY_LIMIT;
   1544 
   1545     numVoicesPlayingNote = 0;
   1546     oldestVoiceNum = MAX_SYNTH_VOICES;
   1547     oldestNoteAge = 0;
   1548     channel = VSynthToChannel(pSynth, channel);
   1549 
   1550     /* examine each voice on this channel playing this note */
   1551     for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++)
   1552     {
   1553         /* check stolen notes separately */
   1554         if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateStolen)
   1555         {
   1556 
   1557             /* same channel and note ? */
   1558             if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note))
   1559             {
   1560                 numVoicesPlayingNote++;
   1561                 age = pVoiceMgr->age - pVoiceMgr->voices[voiceNum].age;
   1562 
   1563                 /* is this the oldest voice for this note? */
   1564                 if (age >= oldestNoteAge)
   1565                 {
   1566                     oldestNoteAge = age;
   1567                     oldestVoiceNum = voiceNum;
   1568                 }
   1569             }
   1570         }
   1571 
   1572         /* handle stolen voices */
   1573         else
   1574         {
   1575             /* same channel and note ? */
   1576             if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote))
   1577             {
   1578                 numVoicesPlayingNote++;
   1579             }
   1580         }
   1581     }
   1582 
   1583     /* check to see if we exceeded poly limit */
   1584     if (numVoicesPlayingNote < DEFAULT_CHANNEL_POLYPHONY_LIMIT)
   1585         return EAS_FALSE;
   1586 
   1587     /* make sure we have a voice to steal */
   1588     if (oldestVoiceNum != MAX_SYNTH_VOICES)
   1589     {
   1590 #ifdef _DEBUG_VM
   1591         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMCheckPolyphonyLimiting: voice %d has the oldest note\n", oldestVoiceNum); */ }
   1592         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMCheckPolyphonyLimiting: polyphony limiting requires shutting down note %d \n", pVoiceMgr->voices[oldestVoiceNum].note); */ }
   1593 #endif
   1594         VMStolenVoice(pVoiceMgr, pSynth, oldestVoiceNum, channel, note, velocity, regionIndex);
   1595         return EAS_TRUE;
   1596     }
   1597 
   1598 #ifdef _DEBUG_VM
   1599         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMCheckPolyphonyLimiting: No oldest voice to steal\n"); */ }
   1600 #endif
   1601     return EAS_FALSE;
   1602 }
   1603 
   1604 /*----------------------------------------------------------------------------
   1605  * VMStartVoice()
   1606  *----------------------------------------------------------------------------
   1607  * Starts a voice given a region index
   1608  *----------------------------------------------------------------------------
   1609 */
   1610 void VMStartVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity, EAS_U16 regionIndex)
   1611 {
   1612     const S_REGION *pRegion;
   1613     S_SYNTH_CHANNEL *pChannel;
   1614     EAS_INT voiceNum;
   1615     EAS_INT maxSynthPoly;
   1616     EAS_I32 lowVoice, highVoice;
   1617     EAS_U16 keyGroup;
   1618 
   1619     pChannel = &pSynth->channels[channel];
   1620     pRegion = GetRegionPtr(pSynth, regionIndex);
   1621 
   1622     /* select correct synth */
   1623 #if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH)
   1624     {
   1625 #ifdef EAS_SPLIT_WT_SYNTH
   1626         if ((pRegion->keyGroupAndFlags & REGION_FLAG_OFF_CHIP) == 0)
   1627 #else
   1628         if ((regionIndex & FLAG_RGN_IDX_FM_SYNTH) == 0)
   1629 #endif
   1630         {
   1631             lowVoice = 0;
   1632             highVoice = NUM_PRIMARY_VOICES - 1;
   1633         }
   1634         else
   1635         {
   1636             lowVoice = NUM_PRIMARY_VOICES;
   1637             highVoice = MAX_SYNTH_VOICES - 1;
   1638         }
   1639     }
   1640 #else
   1641     lowVoice = 0;
   1642     highVoice = MAX_SYNTH_VOICES - 1;
   1643 #endif
   1644 
   1645     /* keep track of the note-start related workload */
   1646     pVoiceMgr->workload+= WORKLOAD_AMOUNT_START_NOTE;
   1647 
   1648     /* other voices in pool, check for key group and poly limiting */
   1649     if (pSynth->poolCount[pChannel->pool] != 0)
   1650     {
   1651 
   1652         /* check for key group exclusivity */
   1653         keyGroup = pRegion->keyGroupAndFlags & 0x0f00;
   1654         if (keyGroup!= 0)
   1655             VMCheckKeyGroup(pVoiceMgr, pSynth, keyGroup, channel);
   1656 
   1657         /* check polyphony limit and steal a voice if necessary */
   1658         if ((pRegion->keyGroupAndFlags & REGION_FLAG_NON_SELF_EXCLUSIVE) == 0)
   1659         {
   1660             if (VMCheckPolyphonyLimiting(pVoiceMgr, pSynth, channel, note, velocity, regionIndex, lowVoice, highVoice) == EAS_TRUE)
   1661                 return;
   1662         }
   1663     }
   1664 
   1665     /* check max poly allocation */
   1666     if ((pSynth->maxPolyphony == 0) || (pVoiceMgr->maxPolyphony < pSynth->maxPolyphony))
   1667         maxSynthPoly = pVoiceMgr->maxPolyphony;
   1668     else
   1669         maxSynthPoly = pSynth->maxPolyphony;
   1670 
   1671     /* any free voices? */
   1672     if ((pVoiceMgr->activeVoices < pVoiceMgr->maxPolyphony) &&
   1673         (pSynth->numActiveVoices < maxSynthPoly) &&
   1674         (EAS_SUCCESS == VMFindAvailableVoice(pVoiceMgr, &voiceNum, lowVoice, highVoice)))
   1675     {
   1676         S_SYNTH_VOICE *pVoice = &pVoiceMgr->voices[voiceNum];
   1677 
   1678 #ifdef _DEBUG_VM
   1679     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMStartVoice: Synth=%d\n", pSynth->vSynthNum); */ }
   1680 #endif
   1681 
   1682         /* bump voice counts */
   1683         pVoiceMgr->activeVoices++;
   1684         pSynth->numActiveVoices++;
   1685 
   1686 #ifdef _DEBUG_VM
   1687         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: voice %d assigned to channel %d note %d velocity %d\n",
   1688             voiceNum, channel, note, velocity); */ }
   1689 #endif
   1690 
   1691         /* save parameters */
   1692         pVoiceMgr->voices[voiceNum].channel = VSynthToChannel(pSynth, channel);
   1693         pVoiceMgr->voices[voiceNum].note = note;
   1694         pVoiceMgr->voices[voiceNum].velocity = velocity;
   1695 
   1696         /* establish note age for voice stealing */
   1697         pVoiceMgr->voices[voiceNum].age = pVoiceMgr->age++;
   1698 
   1699         /* setup the synthesis parameters */
   1700         pVoiceMgr->voices[voiceNum].voiceState = eVoiceStateStart;
   1701 
   1702         /* increment voice pool count */
   1703         IncVoicePoolCount(pVoiceMgr, pVoice);
   1704 
   1705         /* start voice on correct synth */
   1706         /*lint -e{522} return not used at this time */
   1707         GetSynthPtr(voiceNum)->pfStartVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), regionIndex);
   1708         return;
   1709     }
   1710 
   1711     /* no free voices, we have to steal one using appropriate algorithm */
   1712     if (VMStealVoice(pVoiceMgr, pSynth, &voiceNum, channel, note, lowVoice, highVoice) == EAS_SUCCESS)
   1713         VMStolenVoice(pVoiceMgr, pSynth, voiceNum, channel, note, velocity, regionIndex);
   1714 
   1715 #ifdef _DEBUG_VM
   1716     else
   1717     {
   1718         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStartVoice: Could not steal a voice for channel %d note %d velocity %d\n",
   1719             channel, note, velocity); */ }
   1720     }
   1721 #endif
   1722 
   1723     return;
   1724 }
   1725 
   1726 /*----------------------------------------------------------------------------
   1727  * VMStartNote()
   1728  *----------------------------------------------------------------------------
   1729  * Purpose:
   1730  * Update the synth's state to play the requested note on the requested
   1731  * channel if possible.
   1732  *
   1733  * Inputs:
   1734  * nChannel - the channel to start a note on
   1735  * nKeyNumber - the key number to start a note for
   1736  * nNoteVelocity - the key velocity from this note
   1737  * psEASData - pointer to overall EAS data structure
   1738  *
   1739  * Outputs:
   1740  * Side Effects:
   1741  * psSynthObject->m_nNumActiveVoices may be incremented
   1742  * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned
   1743  * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned
   1744  * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned
   1745  *----------------------------------------------------------------------------
   1746 */
   1747 void VMStartNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity)
   1748 {
   1749     S_SYNTH_CHANNEL *pChannel;
   1750     EAS_U16 regionIndex;
   1751     EAS_I16 adjustedNote;
   1752 
   1753     /* bump note count */
   1754     pSynth->totalNoteCount++;
   1755 
   1756     pChannel = &pSynth->channels[channel];
   1757 
   1758     /* check channel mute */
   1759     if (pChannel->channelFlags & CHANNEL_FLAG_MUTE)
   1760         return;
   1761 
   1762 #ifdef EXTERNAL_AUDIO
   1763     /* pass event to external audio when requested */
   1764     if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL))
   1765     {
   1766         S_EXT_AUDIO_EVENT event;
   1767         event.channel = channel;
   1768         event.note = note;
   1769         event.velocity = velocity;
   1770         event.noteOn = EAS_TRUE;
   1771         if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event))
   1772             return;
   1773     }
   1774 #endif
   1775 
   1776     /* start search at first region */
   1777     regionIndex = pChannel->regionIndex;
   1778 
   1779     /* handle transposition */
   1780     adjustedNote = note;
   1781     if (pChannel->channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)
   1782         adjustedNote += pChannel->coarsePitch;
   1783     else
   1784         adjustedNote += pChannel->coarsePitch + pSynth->globalTranspose;
   1785 
   1786     /* limit adjusted key number so it does not wraparound, over/underflow */
   1787     if (adjustedNote < 0)
   1788     {
   1789         adjustedNote = 0;
   1790     }
   1791     else if (adjustedNote > 127)
   1792     {
   1793         adjustedNote = 127;
   1794     }
   1795 
   1796 #if defined(DLS_SYNTHESIZER)
   1797     if (regionIndex & FLAG_RGN_IDX_DLS_SYNTH)
   1798     {
   1799         /* DLS voice */
   1800         for (;;)
   1801         {
   1802             /*lint -e{740,826} cast OK, we know this is actually a DLS region */
   1803             const S_DLS_REGION *pDLSRegion = (S_DLS_REGION*) GetRegionPtr(pSynth, regionIndex);
   1804 
   1805             /* check key against this region's key and velocity range */
   1806             if (((adjustedNote >= pDLSRegion->wtRegion.region.rangeLow) && (adjustedNote <= pDLSRegion->wtRegion.region.rangeHigh)) &&
   1807                 ((velocity >= pDLSRegion->velLow) && (velocity <= pDLSRegion->velHigh)))
   1808             {
   1809                 VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex);
   1810             }
   1811 
   1812             /* last region in program? */
   1813             if (pDLSRegion->wtRegion.region.keyGroupAndFlags & REGION_FLAG_LAST_REGION)
   1814                 break;
   1815 
   1816             /* advance to next region */
   1817             regionIndex++;
   1818         }
   1819     }
   1820     else
   1821 #endif
   1822 
   1823     /* braces here for #if clause */
   1824     {
   1825         /* EAS voice */
   1826         for (;;)
   1827         {
   1828             const S_REGION *pRegion = GetRegionPtr(pSynth, regionIndex);
   1829 
   1830             /* check key against this region's keyrange */
   1831             if ((adjustedNote >= pRegion->rangeLow) && (adjustedNote <= pRegion->rangeHigh))
   1832             {
   1833                 VMStartVoice(pVoiceMgr, pSynth, channel, note, velocity, regionIndex);
   1834                 break;
   1835             }
   1836 
   1837             /* last region in program? */
   1838             if (pRegion->keyGroupAndFlags & REGION_FLAG_LAST_REGION)
   1839                 break;
   1840 
   1841             /* advance to next region */
   1842             regionIndex++;
   1843         }
   1844     }
   1845 }
   1846 
   1847 /*----------------------------------------------------------------------------
   1848  * VMStopNote()
   1849  *----------------------------------------------------------------------------
   1850  * Purpose:
   1851  * Update the synth's state to end the requested note on the requested
   1852  * channel.
   1853  *
   1854  * Inputs:
   1855  * nChannel - the channel to stop a note on
   1856  * nKeyNumber - the key number for this note off
   1857  * nNoteVelocity - the note-off velocity
   1858  * psEASData - pointer to overall EAS data structure
   1859  *
   1860  * Outputs:
   1861  * Side Effects:
   1862  * psSynthObject->m_sVoice[free voice num].m_nSynthChannel may be assigned
   1863  * psSynthObject->m_sVoice[free voice num].m_nKeyNumber is assigned
   1864  * psSynthObject->m_sVoice[free voice num].m_nVelocity is assigned
   1865  *----------------------------------------------------------------------------
   1866 */
   1867 /*lint -esym(715, velocity) reserved for future use */
   1868 void VMStopNote (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 note, EAS_U8 velocity)
   1869 {
   1870     S_SYNTH_CHANNEL *pChannel;
   1871     EAS_INT voiceNum;
   1872 
   1873     pChannel = &(pSynth->channels[channel]);
   1874 
   1875 #ifdef EXTERNAL_AUDIO
   1876     if ((pChannel->channelFlags & CHANNEL_FLAG_EXTERNAL_AUDIO) && (pSynth->cbEventFunc != NULL))
   1877     {
   1878         S_EXT_AUDIO_EVENT event;
   1879         event.channel = channel;
   1880         event.note = note;
   1881         event.velocity = velocity;
   1882         event.noteOn = EAS_FALSE;
   1883         if (pSynth->cbEventFunc(pSynth->pExtAudioInstData, &event))
   1884             return;
   1885     }
   1886 #endif
   1887 
   1888     /* keep track of the note-start workload */
   1889     pVoiceMgr->workload += WORKLOAD_AMOUNT_STOP_NOTE;
   1890 
   1891     channel = VSynthToChannel(pSynth, channel);
   1892 
   1893     for (voiceNum=0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
   1894     {
   1895 
   1896         /* stolen notes are handled separately */
   1897         if (eVoiceStateStolen != pVoiceMgr->voices[voiceNum].voiceState)
   1898         {
   1899 
   1900             /* channel and key number must match */
   1901             if ((channel == pVoiceMgr->voices[voiceNum].channel) && (note == pVoiceMgr->voices[voiceNum].note))
   1902             {
   1903 #ifdef _DEBUG_VM
   1904                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n",
   1905                     voiceNum, channel, note); */ }
   1906 #endif
   1907 
   1908                 /* if sustain pedal is down, set deferred note-off flag */
   1909                 if (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
   1910                 {
   1911                     pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_SUSTAIN_PEDAL_DEFER_NOTE_OFF;
   1912                     continue;
   1913                 }
   1914 
   1915                 /* if this note just started, wait before we stop it */
   1916                 if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET)
   1917                 {
   1918 #ifdef _DEBUG_VM
   1919                     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "\tDeferred: Not started yet\n"); */ }
   1920 #endif
   1921                     pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF;
   1922                     pSynth->synthFlags |= SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING;
   1923                 }
   1924 
   1925                 /* release voice */
   1926                 else
   1927                     VMReleaseVoice(pVoiceMgr, pSynth, voiceNum);
   1928 
   1929             }
   1930         }
   1931 
   1932         /* process stolen notes, new channel and key number must match */
   1933         else if ((channel == pVoiceMgr->voices[voiceNum].nextChannel) && (note == pVoiceMgr->voices[voiceNum].nextNote))
   1934         {
   1935 
   1936 #ifdef _DEBUG_VM
   1937             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStopNote: voice %d channel %d note %d\n\tDeferred: Stolen voice\n",
   1938                 voiceNum, channel, note); */ }
   1939 #endif
   1940             pVoiceMgr->voices[voiceNum].voiceFlags |= VOICE_FLAG_DEFER_MIDI_NOTE_OFF;
   1941         }
   1942     }
   1943 }
   1944 
   1945 /*----------------------------------------------------------------------------
   1946  * VMFindAvailableVoice()
   1947  *----------------------------------------------------------------------------
   1948  * Purpose:
   1949  * Find an available voice and return the voice number if available.
   1950  *
   1951  * Inputs:
   1952  * pnVoiceNumber - really an output, returns the voice number found
   1953  * psEASData - pointer to overall EAS data structure
   1954  *
   1955  * Outputs:
   1956  * success - if there is an available voice
   1957  * failure - otherwise
   1958  *----------------------------------------------------------------------------
   1959 */
   1960 EAS_RESULT VMFindAvailableVoice (S_VOICE_MGR *pVoiceMgr, EAS_INT *pVoiceNumber, EAS_I32 lowVoice, EAS_I32 highVoice)
   1961 {
   1962     EAS_INT voiceNum;
   1963 
   1964     /* Check each voice to see if it has been assigned to a synth channel */
   1965     for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++)
   1966     {
   1967         /* check if this voice has been assigned to a synth channel */
   1968         if ( pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateFree)
   1969         {
   1970             *pVoiceNumber = voiceNum;       /* this voice is available */
   1971             return EAS_SUCCESS;
   1972         }
   1973     }
   1974 
   1975     /* if we reach here, we have not found a free voice */
   1976     *pVoiceNumber = UNASSIGNED_SYNTH_VOICE;
   1977 
   1978 #ifdef _DEBUG_VM
   1979     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMFindAvailableVoice: error, could not find an available voice\n"); */ }
   1980 #endif
   1981     return EAS_FAILURE;
   1982 }
   1983 
   1984 /*----------------------------------------------------------------------------
   1985  * VMStealVoice()
   1986  *----------------------------------------------------------------------------
   1987  * Purpose:
   1988  * Steal a voice and return the voice number
   1989  *
   1990  * Stealing algorithm: steal the best choice with minimal work, taking into
   1991  * account SP-Midi channel priorities and polyphony allocation.
   1992  *
   1993  * In one pass through all the voices, figure out which voice to steal
   1994  * taking into account a number of different factors:
   1995  * Priority of the voice's MIDI channel
   1996  * Number of voices over the polyphony allocation for voice's MIDI channel
   1997  * Amplitude of the voice
   1998  * Note age
   1999  * Key velocity (for voices that haven't been started yet)
   2000  * If any matching notes are found
   2001  *
   2002  * Inputs:
   2003  * pnVoiceNumber - really an output, see below
   2004  * nChannel - the channel that this voice wants to be started on
   2005  * nKeyNumber - the key number for this new voice
   2006  * psEASData - pointer to overall EAS data structure
   2007  *
   2008  * Outputs:
   2009  * pnVoiceNumber - voice number of the voice that was stolen
   2010  * EAS_RESULT EAS_SUCCESS - always successful
   2011  *----------------------------------------------------------------------------
   2012 */
   2013 EAS_RESULT VMStealVoice (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_INT *pVoiceNumber, EAS_U8 channel, EAS_U8 note, EAS_I32 lowVoice, EAS_I32 highVoice)
   2014 {
   2015     S_SYNTH_VOICE *pCurrVoice;
   2016     S_SYNTH *pCurrSynth;
   2017     EAS_INT voiceNum;
   2018     EAS_INT bestCandidate;
   2019     EAS_U8 currChannel;
   2020     EAS_U8 currNote;
   2021     EAS_I32 bestPriority;
   2022     EAS_I32 currentPriority;
   2023 
   2024     /* determine which voice to steal */
   2025     bestPriority = 0;
   2026     bestCandidate = MAX_SYNTH_VOICES;
   2027 
   2028     for (voiceNum = lowVoice; voiceNum <= highVoice; voiceNum++)
   2029     {
   2030         pCurrVoice = &pVoiceMgr->voices[voiceNum];
   2031 
   2032         /* ignore free voices */
   2033         if (pCurrVoice->voiceState == eVoiceStateFree)
   2034             continue;
   2035 
   2036         /* for stolen voices, use the new parameters, not the old */
   2037         if (pCurrVoice->voiceState == eVoiceStateStolen)
   2038         {
   2039             pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->nextChannel)];
   2040             currChannel = pCurrVoice->nextChannel;
   2041             currNote = pCurrVoice->nextNote;
   2042         }
   2043         else
   2044         {
   2045             pCurrSynth = pVoiceMgr->pSynth[GET_VSYNTH(pCurrVoice->channel)];
   2046             currChannel = pCurrVoice->channel;
   2047             currNote = pCurrVoice->note;
   2048         }
   2049 
   2050         /* ignore voices that are higher priority */
   2051         if (pSynth->priority > pCurrSynth->priority)
   2052             continue;
   2053 #ifdef _DEBUG_VM
   2054 //      { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: New priority = %d exceeds old priority = %d\n", pSynth->priority, pCurrSynth->priority); */ }
   2055 #endif
   2056 
   2057         /* if voice is stolen or just started, reduce the likelihood it will be stolen */
   2058         if (( pCurrVoice->voiceState == eVoiceStateStolen) || (pCurrVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET))
   2059         {
   2060             currentPriority = 128 - pCurrVoice->nextVelocity;
   2061         }
   2062         else
   2063         {
   2064             /* compute the priority of this voice, higher means better for stealing */
   2065             /* use not age */
   2066             currentPriority = (EAS_I32) pCurrVoice->age << NOTE_AGE_STEAL_WEIGHT;
   2067 
   2068             /* include note gain -higher gain is lower steal value */
   2069             /*lint -e{704} use shift for performance */
   2070             currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) -
   2071                 ((EAS_I32) pCurrVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT));
   2072         }
   2073 
   2074         /* in SP-MIDI mode, include over poly allocation and channel priority */
   2075         if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON)
   2076         {
   2077             S_SYNTH_CHANNEL *pChannel = &pCurrSynth->channels[GET_CHANNEL(currChannel)];
   2078             /*lint -e{701} use shift for performance */
   2079             if (pSynth->poolCount[pChannel->pool] >= pSynth->poolAlloc[pChannel->pool])
   2080                 currentPriority += (pSynth->poolCount[pChannel->pool] -pSynth->poolAlloc[pChannel->pool] + 1) << CHANNEL_POLY_STEAL_WEIGHT;
   2081 
   2082             /* include channel priority */
   2083             currentPriority += (EAS_I32)(pChannel->pool << CHANNEL_PRIORITY_STEAL_WEIGHT);
   2084         }
   2085 
   2086         /* if a note is already playing that matches this note, consider stealing it more readily */
   2087         if ((note == currNote) && (channel == currChannel))
   2088             currentPriority += NOTE_MATCH_PENALTY;
   2089 
   2090         /* is this the best choice so far? */
   2091         if (currentPriority >= bestPriority)
   2092         {
   2093             bestPriority = currentPriority;
   2094             bestCandidate = voiceNum;
   2095         }
   2096     }
   2097 
   2098     /* may happen if all voices are allocated to a higher priority virtual synth */
   2099     if (bestCandidate == MAX_SYNTH_VOICES)
   2100     {
   2101         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Unable to allocate a voice\n"); */ }
   2102         return EAS_ERROR_NO_VOICE_ALLOCATED;
   2103     }
   2104 
   2105 #ifdef _DEBUG_VM
   2106     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMStealVoice: Voice %d stolen\n", bestCandidate); */ }
   2107 
   2108     /* are we stealing a stolen voice? */
   2109     if (pVoiceMgr->voices[bestCandidate].voiceState == eVoiceStateStolen)
   2110     {
   2111         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMStealVoice: Voice %d is already marked as stolen and was scheduled to play ch: %d note: %d vel: %d\n",
   2112             bestCandidate,
   2113             pVoiceMgr->voices[bestCandidate].nextChannel,
   2114             pVoiceMgr->voices[bestCandidate].nextNote,
   2115             pVoiceMgr->voices[bestCandidate].nextVelocity); */ }
   2116     }
   2117 #endif
   2118 
   2119     *pVoiceNumber = (EAS_U16) bestCandidate;
   2120     return EAS_SUCCESS;
   2121 }
   2122 
   2123 /*----------------------------------------------------------------------------
   2124  * VMChannelPressure()
   2125  *----------------------------------------------------------------------------
   2126  * Purpose:
   2127  * Change the channel pressure for the given channel
   2128  *
   2129  * Inputs:
   2130  * nChannel - the MIDI channel
   2131  * nVelocity - the channel pressure value
   2132  * psEASData - pointer to overall EAS data structure
   2133  *
   2134  * Outputs:
   2135  * Side Effects:
   2136  * psSynthObject->m_sChannel[nChannel].m_nChannelPressure is updated
   2137  *----------------------------------------------------------------------------
   2138 */
   2139 void VMChannelPressure (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 value)
   2140 {
   2141     S_SYNTH_CHANNEL *pChannel;
   2142 
   2143     pChannel = &(pSynth->channels[channel]);
   2144     pChannel->channelPressure = value;
   2145 
   2146     /*
   2147     set a channel flag to request parameter updates
   2148     for all the voices associated with this channel
   2149     */
   2150     pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
   2151 }
   2152 
   2153 /*----------------------------------------------------------------------------
   2154  * VMPitchBend()
   2155  *----------------------------------------------------------------------------
   2156  * Purpose:
   2157  * Change the pitch wheel value for the given channel.
   2158  * This routine constructs the proper 14-bit argument when the calling routine
   2159  * passes the pitch LSB and MSB.
   2160  *
   2161  * Note: some midi disassemblers display a bipolar pitch bend value.
   2162  * We can display the bipolar value using
   2163  * if m_nPitchBend >= 0x2000
   2164  *      bipolar pitch bend = postive (m_nPitchBend - 0x2000)
   2165  * else
   2166  *      bipolar pitch bend = negative (0x2000 - m_nPitchBend)
   2167  *
   2168  * Inputs:
   2169  * nChannel - the MIDI channel
   2170  * nPitchLSB - the LSB byte of the pitch bend message
   2171  * nPitchMSB - the MSB byte of the pitch bend message
   2172  * psEASData - pointer to overall EAS data structure
   2173  *
   2174  * Outputs:
   2175  *
   2176  * Side Effects:
   2177  * psSynthObject->m_sChannel[nChannel].m_nPitchBend is changed
   2178  *
   2179  *----------------------------------------------------------------------------
   2180 */
   2181 void VMPitchBend (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 nPitchLSB, EAS_U8 nPitchMSB)
   2182 {
   2183     S_SYNTH_CHANNEL *pChannel;
   2184 
   2185     pChannel = &(pSynth->channels[channel]);
   2186     pChannel->pitchBend = (EAS_I16) ((nPitchMSB << 7) | nPitchLSB);
   2187 
   2188     /*
   2189     set a channel flag to request parameter updates
   2190     for all the voices associated with this channel
   2191     */
   2192     pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
   2193 }
   2194 
   2195 /*----------------------------------------------------------------------------
   2196  * VMControlChange()
   2197  *----------------------------------------------------------------------------
   2198  * Purpose:
   2199  * Change the controller (or mode) for the given channel.
   2200  *
   2201  * Inputs:
   2202  * nChannel - the MIDI channel
   2203  * nControllerNumber - the MIDI controller number
   2204  * nControlValue - the value for this controller message
   2205  * psEASData - pointer to overall EAS data structure
   2206  *
   2207  * Outputs:
   2208  * Side Effects:
   2209  * psSynthObject->m_sChannel[nChannel] controller is changed
   2210  *
   2211  *----------------------------------------------------------------------------
   2212 */
   2213 void VMControlChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value)
   2214 {
   2215     S_SYNTH_CHANNEL *pChannel;
   2216 
   2217     pChannel = &(pSynth->channels[channel]);
   2218 
   2219     /*
   2220     set a channel flag to request parameter updates
   2221     for all the voices associated with this channel
   2222     */
   2223     pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
   2224 
   2225     switch ( controller )
   2226     {
   2227     case MIDI_CONTROLLER_BANK_SELECT_MSB:
   2228 #ifdef _DEBUG_VM
   2229         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select MSB: msb 0x%X\n", value); */ }
   2230 #endif
   2231         /* use this MSB with a zero LSB, until we get an LSB message */
   2232         pChannel->bankNum = value << 8;
   2233         break;
   2234 
   2235     case MIDI_CONTROLLER_MOD_WHEEL:
   2236         /* we treat mod wheel as a 7-bit controller and only use the MSB */
   2237         pChannel->modWheel = value;
   2238         break;
   2239 
   2240     case MIDI_CONTROLLER_VOLUME:
   2241         /* we treat volume as a 7-bit controller and only use the MSB */
   2242         pChannel->volume = value;
   2243         break;
   2244 
   2245     case MIDI_CONTROLLER_PAN:
   2246         /* we treat pan as a 7-bit controller and only use the MSB */
   2247         pChannel->pan = value;
   2248         break;
   2249 
   2250     case MIDI_CONTROLLER_EXPRESSION:
   2251         /* we treat expression as a 7-bit controller and only use the MSB */
   2252         pChannel->expression = value;
   2253         break;
   2254 
   2255     case MIDI_CONTROLLER_BANK_SELECT_LSB:
   2256 #ifdef _DEBUG_VM
   2257         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: Bank Select LSB: lsb 0x%X\n", value); */ }
   2258 #endif
   2259         /*
   2260         construct bank number as 7-bits (stored as 8) of existing MSB
   2261         and 7-bits of new LSB (also stored as 8(
   2262         */
   2263         pChannel->bankNum =
   2264             (pChannel->bankNum & 0xFF00) | value;
   2265 
   2266         break;
   2267 
   2268     case MIDI_CONTROLLER_SUSTAIN_PEDAL:
   2269         /* we treat sustain pedal as a boolean on/off bit flag */
   2270         if (value < 64)
   2271         {
   2272             /*
   2273             we are requested to turn the pedal off, but first check
   2274             if the pedal is already on
   2275             */
   2276             if (0 !=
   2277                 (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
   2278                )
   2279             {
   2280                 /*
   2281                 The sustain flag is presently set and the damper pedal is on.
   2282                 We are therefore transitioning from damper pedal ON to
   2283                 damper pedal OFF. This means all notes in this channel
   2284                 that received a note off while the damper pedal was on, and
   2285                 had their note-off requests deferred, should now proceed to
   2286                 the release state.
   2287                 */
   2288                 VMReleaseAllDeferredNoteOffs(pVoiceMgr, pSynth, channel);
   2289             }   /* end if sustain pedal is already on */
   2290 
   2291             /* turn the sustain pedal off */
   2292             pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL;
   2293         }
   2294         else
   2295         {
   2296             /*
   2297             we are requested to turn the pedal on, but first check
   2298             if the pedal is already off
   2299             */
   2300             if (0 ==
   2301                 (pChannel->channelFlags & CHANNEL_FLAG_SUSTAIN_PEDAL)
   2302                )
   2303             {
   2304                 /*
   2305                 The sustain flag is presently clear and the damper pedal is off.
   2306                 We are therefore transitioning from damper pedal OFF to
   2307                 damper pedal ON. Currently sounding notes should be left
   2308                 unchanged. However, we should try to "catch" notes if possible.
   2309                 If any notes have levels >= sustain level, catch them,
   2310                 otherwise, let them continue to release.
   2311                 */
   2312                 VMCatchNotesForSustainPedal(pVoiceMgr, pSynth, channel);
   2313             }
   2314 
   2315             /* turn the sustain pedal on */
   2316             pChannel->channelFlags |= CHANNEL_FLAG_SUSTAIN_PEDAL;
   2317         }
   2318 
   2319         break;
   2320 #ifdef _REVERB
   2321     case MIDI_CONTROLLER_REVERB_SEND:
   2322         /* we treat send as a 7-bit controller and only use the MSB */
   2323         pSynth->channels[channel].reverbSend = value;
   2324         break;
   2325 #endif
   2326 #ifdef _CHORUS
   2327     case MIDI_CONTROLLER_CHORUS_SEND:
   2328         /* we treat send as a 7-bit controller and only use the MSB */
   2329         pSynth->channels[channel].chorusSend = value;
   2330         break;
   2331 #endif
   2332     case MIDI_CONTROLLER_RESET_CONTROLLERS:
   2333         /* despite the Midi message name, not ALL controllers are reset */
   2334         pChannel->modWheel = DEFAULT_MOD_WHEEL;
   2335         pChannel->expression = DEFAULT_EXPRESSION;
   2336 
   2337         /* turn the sustain pedal off as default/reset */
   2338         pChannel->channelFlags &= ~CHANNEL_FLAG_SUSTAIN_PEDAL;
   2339         pChannel->pitchBend = DEFAULT_PITCH_BEND;
   2340 
   2341         /* reset channel pressure */
   2342         pChannel->channelPressure = DEFAULT_CHANNEL_PRESSURE;
   2343 
   2344         /* reset RPN values */
   2345         pChannel->registeredParam = DEFAULT_REGISTERED_PARAM;
   2346         pChannel->pitchBendSensitivity = DEFAULT_PITCH_BEND_SENSITIVITY;
   2347         pChannel->finePitch = DEFAULT_FINE_PITCH;
   2348         pChannel->coarsePitch = DEFAULT_COARSE_PITCH;
   2349 
   2350         /*
   2351         program change, bank select, channel volume CC7, pan CC10
   2352         are NOT reset
   2353         */
   2354         break;
   2355 
   2356     /*
   2357     For logical reasons, the RPN data entry are grouped together.
   2358     However, keep in mind that these cases are not necessarily in
   2359     ascending order.
   2360     e.g., MIDI_CONTROLLER_DATA_ENTRY_MSB == 6,
   2361     whereas MIDI_CONTROLLER_SUSTAIN_PEDAL == 64.
   2362     So arrange these case statements in whatever manner is more efficient for
   2363     the processor / compiler.
   2364     */
   2365     case MIDI_CONTROLLER_ENTER_DATA_MSB:
   2366     case MIDI_CONTROLLER_ENTER_DATA_LSB:
   2367     case MIDI_CONTROLLER_SELECT_RPN_LSB:
   2368     case MIDI_CONTROLLER_SELECT_RPN_MSB:
   2369     case MIDI_CONTROLLER_SELECT_NRPN_MSB:
   2370     case MIDI_CONTROLLER_SELECT_NRPN_LSB:
   2371         VMUpdateRPNStateMachine(pSynth, channel, controller, value);
   2372         break;
   2373 
   2374     case MIDI_CONTROLLER_ALL_SOUND_OFF:
   2375     case MIDI_CONTROLLER_ALL_NOTES_OFF:
   2376     case MIDI_CONTROLLER_OMNI_OFF:
   2377     case MIDI_CONTROLLER_OMNI_ON:
   2378     case MIDI_CONTROLLER_MONO_ON_POLY_OFF:
   2379     case MIDI_CONTROLLER_POLY_ON_MONO_OFF:
   2380         /* NOTE: we treat all sounds off the same as all notes off */
   2381         VMAllNotesOff(pVoiceMgr, pSynth, channel);
   2382         break;
   2383 
   2384     default:
   2385 #ifdef _DEBUG_VM
   2386         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMControlChange: controller %d not yet implemented\n", controller); */ }
   2387 #endif
   2388         break;
   2389 
   2390     }
   2391 
   2392     return;
   2393 }
   2394 
   2395 /*----------------------------------------------------------------------------
   2396  * VMUpdateRPNStateMachine()
   2397  *----------------------------------------------------------------------------
   2398  * Purpose:
   2399  * Call this function when we want to parse RPN related controller messages.
   2400  * We only support RPN0 (pitch bend sensitivity), RPN1 (fine tuning) and
   2401  * RPN2 (coarse tuning). Any other RPNs or NRPNs are ignored for now.
   2402  *.
   2403  * Supports any order, so not a state machine anymore. This function was
   2404  * rewritten to work correctly regardless of order.
   2405  *
   2406  * Inputs:
   2407  * nChannel - the channel this controller message is coming from
   2408  * nControllerNumber - which RPN related controller
   2409  * nControlValue - the value of the RPN related controller
   2410  * psEASData - pointer to overall EAS data structure
   2411  *
   2412  * Outputs:
   2413  * returns EAS_RESULT, which is typically EAS_SUCCESS, since there are
   2414  * few possible errors
   2415  *
   2416  * Side Effects:
   2417  * gsSynthObject.m_sChannel[nChannel].m_nPitchBendSensitivity
   2418  * (or m_nFinePitch or m_nCoarsePitch)
   2419  * will be updated if the proper RPN message is received.
   2420  *----------------------------------------------------------------------------
   2421 */
   2422 EAS_RESULT VMUpdateRPNStateMachine (S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 controller, EAS_U8 value)
   2423 {
   2424     S_SYNTH_CHANNEL *pChannel;
   2425 
   2426 #ifdef _DEBUG_VM
   2427     if (channel >= NUM_SYNTH_CHANNELS)
   2428     {
   2429         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMUpdateRPNStateMachines: error, %d invalid channel number\n",
   2430             channel); */ }
   2431         return EAS_FAILURE;
   2432     }
   2433 #endif
   2434 
   2435     pChannel = &(pSynth->channels[channel]);
   2436 
   2437     switch (controller)
   2438     {
   2439     case MIDI_CONTROLLER_SELECT_NRPN_MSB:
   2440     case MIDI_CONTROLLER_SELECT_NRPN_LSB:
   2441         pChannel->registeredParam = DEFAULT_REGISTERED_PARAM;
   2442         break;
   2443     case MIDI_CONTROLLER_SELECT_RPN_MSB:
   2444         pChannel->registeredParam =
   2445             (pChannel->registeredParam & 0x7F) | (value<<7);
   2446         break;
   2447     case MIDI_CONTROLLER_SELECT_RPN_LSB:
   2448         pChannel->registeredParam =
   2449             (pChannel->registeredParam & 0x7F00) | value;
   2450         break;
   2451     case MIDI_CONTROLLER_ENTER_DATA_MSB:
   2452         switch (pChannel->registeredParam)
   2453         {
   2454         case 0:
   2455             pChannel->pitchBendSensitivity = value * 100;
   2456             break;
   2457         case 1:
   2458             /*lint -e{702} <avoid division for performance reasons>*/
   2459             pChannel->finePitch = (EAS_I8)((((value << 7) - 8192) * 100) >> 13);
   2460             break;
   2461         case 2:
   2462             pChannel->coarsePitch = (EAS_I8)(value - 64);
   2463             break;
   2464         default:
   2465             break;
   2466         }
   2467         break;
   2468     case MIDI_CONTROLLER_ENTER_DATA_LSB:
   2469         switch (pChannel->registeredParam)
   2470         {
   2471         case 0:
   2472             //ignore lsb
   2473             break;
   2474         case 1:
   2475             //ignore lsb
   2476             break;
   2477         case 2:
   2478             //ignore lsb
   2479             break;
   2480         default:
   2481             break;
   2482         }
   2483         break;
   2484     default:
   2485         return EAS_FAILURE; //not a RPN related controller
   2486     }
   2487 
   2488     return EAS_SUCCESS;
   2489 }
   2490 
   2491 /*----------------------------------------------------------------------------
   2492  * VMUpdateStaticChannelParameters()
   2493  *----------------------------------------------------------------------------
   2494  * Purpose:
   2495  * Update all of the static channel parameters for channels that have had
   2496  * a controller change values
   2497  * Or if the synth has signalled that all channels must forcibly
   2498  * be updated
   2499  *
   2500  * Inputs:
   2501  * psEASData - pointer to overall EAS data structure
   2502  *
   2503  * Outputs:
   2504  * none
   2505  *
   2506  * Side Effects:
   2507  * - psSynthObject->m_sChannel[].m_nStaticGain and m_nStaticPitch
   2508  * are updated for channels whose controller values have changed
   2509  * or if the synth has signalled that all channels must forcibly
   2510  * be updated
   2511  *----------------------------------------------------------------------------
   2512 */
   2513 void VMUpdateStaticChannelParameters (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth)
   2514 {
   2515     EAS_INT channel;
   2516 
   2517     if (pSynth->synthFlags & SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS)
   2518     {
   2519         /*
   2520         the synth wants us to forcibly update all channel
   2521         parameters. This event occurs when we are about to
   2522         finish resetting the synth
   2523         */
   2524         for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++)
   2525         {
   2526 #ifdef _HYBRID_SYNTH
   2527             if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH)
   2528                 pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
   2529             else
   2530                 pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
   2531 #else
   2532             pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
   2533 #endif
   2534         }
   2535 
   2536         /*
   2537         clear the flag to indicates we have now forcibly
   2538         updated all channel parameters
   2539         */
   2540         pSynth->synthFlags &= ~SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS;
   2541     }
   2542     else
   2543     {
   2544 
   2545         /* only update channel params if signalled by a channel flag */
   2546         for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++)
   2547         {
   2548             if ( 0 != (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS))
   2549             {
   2550 #ifdef _HYBRID_SYNTH
   2551                 if (pSynth->channels[channel].regionIndex & FLAG_RGN_IDX_FM_SYNTH)
   2552                     pSecondarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
   2553                 else
   2554                     pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
   2555 #else
   2556                 pPrimarySynth->pfUpdateChannel(pVoiceMgr, pSynth, (EAS_U8) channel);
   2557 #endif
   2558             }
   2559         }
   2560 
   2561     }
   2562 
   2563     return;
   2564 }
   2565 
   2566 /*----------------------------------------------------------------------------
   2567  * VMFindProgram()
   2568  *----------------------------------------------------------------------------
   2569  * Purpose:
   2570  * Look up an individual program in sound library. This function
   2571  * searches the bank list for a program, then the individual program
   2572  * list.
   2573  *
   2574  * Inputs:
   2575  *
   2576  * Outputs:
   2577  *----------------------------------------------------------------------------
   2578 */
   2579 static EAS_RESULT VMFindProgram (const S_EAS *pEAS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex)
   2580 {
   2581     EAS_U32 locale;
   2582     const S_PROGRAM *p;
   2583     EAS_U16 i;
   2584     EAS_U16 regionIndex;
   2585 
   2586     /* make sure we have a valid sound library */
   2587     if (pEAS == NULL)
   2588         return EAS_FAILURE;
   2589 
   2590     /* search the banks */
   2591     for (i = 0; i <  pEAS->numBanks; i++)
   2592     {
   2593         if (bank == (EAS_U32) pEAS->pBanks[i].locale)
   2594         {
   2595             regionIndex = pEAS->pBanks[i].regionIndex[programNum];
   2596             if (regionIndex != INVALID_REGION_INDEX)
   2597             {
   2598                 *pRegionIndex = regionIndex;
   2599                 return EAS_SUCCESS;
   2600             }
   2601             break;
   2602         }
   2603     }
   2604 
   2605     /* establish locale */
   2606     locale = ( bank << 8) | programNum;
   2607 
   2608     /* search for program */
   2609     for (i = 0, p = pEAS->pPrograms; i < pEAS->numPrograms; i++, p++)
   2610     {
   2611         if (p->locale == locale)
   2612         {
   2613             *pRegionIndex = p->regionIndex;
   2614             return EAS_SUCCESS;
   2615         }
   2616     }
   2617 
   2618     return EAS_FAILURE;
   2619 }
   2620 
   2621 #ifdef DLS_SYNTHESIZER
   2622 /*----------------------------------------------------------------------------
   2623  * VMFindDLSProgram()
   2624  *----------------------------------------------------------------------------
   2625  * Purpose:
   2626  * Look up an individual program in sound library. This function
   2627  * searches the bank list for a program, then the individual program
   2628  * list.
   2629  *
   2630  * Inputs:
   2631  *
   2632  * Outputs:
   2633  *----------------------------------------------------------------------------
   2634 */
   2635 static EAS_RESULT VMFindDLSProgram (const S_DLS *pDLS, EAS_U32 bank, EAS_U8 programNum, EAS_U16 *pRegionIndex)
   2636 {
   2637     EAS_U32 locale;
   2638     const S_PROGRAM *p;
   2639     EAS_U16 i;
   2640 
   2641     /* make sure we have a valid sound library */
   2642     if (pDLS == NULL)
   2643         return EAS_FAILURE;
   2644 
   2645     /* establish locale */
   2646     locale = (bank << 8) | programNum;
   2647 
   2648     /* search for program */
   2649     for (i = 0, p = pDLS->pDLSPrograms; i < pDLS->numDLSPrograms; i++, p++)
   2650     {
   2651         if (p->locale == locale)
   2652         {
   2653             *pRegionIndex = p->regionIndex;
   2654             return EAS_SUCCESS;
   2655         }
   2656     }
   2657 
   2658     return EAS_FAILURE;
   2659 }
   2660 #endif
   2661 
   2662 /*----------------------------------------------------------------------------
   2663  * VMProgramChange()
   2664  *----------------------------------------------------------------------------
   2665  * Purpose:
   2666  * Change the instrument (program) for the given channel.
   2667  *
   2668  * Depending on the program number, and the bank selected for this channel, the
   2669  * program may be in ROM, RAM (from SMAF or CMX related RAM wavetable), or
   2670  * Alternate wavetable (from mobile DLS or other DLS file)
   2671  *
   2672  * This function figures out what wavetable should be used, and sets it up as the
   2673  * wavetable to use for this channel. Also the channel may switch from a melodic
   2674  * channel to a rhythm channel, or vice versa.
   2675  *
   2676  * Inputs:
   2677  *
   2678  * Outputs:
   2679  * Side Effects:
   2680  * gsSynthObject.m_sChannel[nChannel].m_nProgramNumber is likely changed
   2681  * gsSynthObject.m_sChannel[nChannel].m_psEAS may be changed
   2682  * gsSynthObject.m_sChannel[nChannel].m_bRhythmChannel may be changed
   2683  *
   2684  *----------------------------------------------------------------------------
   2685 */
   2686 /*lint -esym(715, pVoiceMgr) reserved for future use */
   2687 void VMProgramChange (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_U8 channel, EAS_U8 program)
   2688 {
   2689     S_SYNTH_CHANNEL *pChannel;
   2690     EAS_U32 bank;
   2691     EAS_U16 regionIndex;
   2692 
   2693 #ifdef _DEBUG_VM
   2694     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "VMProgramChange: vSynthNum=%d, channel=%d, program=%d\n", pSynth->vSynthNum, channel, program); */ }
   2695 #endif
   2696 
   2697     /* setup pointer to MIDI channel data */
   2698     pChannel = &pSynth->channels[channel];
   2699     bank = pChannel->bankNum;
   2700 
   2701     /* allow channels to switch between being melodic or rhythm channels, using GM2 CC values */
   2702     if ((bank & 0xFF00) == DEFAULT_RHYTHM_BANK_NUMBER)
   2703     {
   2704         /* make it a rhythm channel */
   2705         pChannel->channelFlags |= CHANNEL_FLAG_RHYTHM_CHANNEL;
   2706     }
   2707     else if ((bank & 0xFF00) == DEFAULT_MELODY_BANK_NUMBER)
   2708     {
   2709         /* make it a melody channel */
   2710         pChannel->channelFlags &= ~CHANNEL_FLAG_RHYTHM_CHANNEL;
   2711     }
   2712 
   2713     regionIndex = DEFAULT_REGION_INDEX;
   2714 
   2715 #ifdef EXTERNAL_AUDIO
   2716     /* give the external audio interface a chance to handle it */
   2717     if (pSynth->cbProgChgFunc != NULL)
   2718     {
   2719         S_EXT_AUDIO_PRG_CHG prgChg;
   2720         prgChg.channel = channel;
   2721         prgChg.bank = (EAS_U16) bank;
   2722         prgChg.program = program;
   2723         if (pSynth->cbProgChgFunc(pSynth->pExtAudioInstData, &prgChg))
   2724             pChannel->channelFlags |= CHANNEL_FLAG_EXTERNAL_AUDIO;
   2725     }
   2726 
   2727 #endif
   2728 
   2729 
   2730 #ifdef DLS_SYNTHESIZER
   2731     /* first check for DLS program that may overlay the internal instrument */
   2732     if (VMFindDLSProgram(pSynth->pDLS, bank, program, &regionIndex) != EAS_SUCCESS)
   2733 #endif
   2734 
   2735     /* braces to support 'if' clause above */
   2736     {
   2737 
   2738         /* look in the internal banks */
   2739         if (VMFindProgram(pSynth->pEAS, bank, program, &regionIndex) != EAS_SUCCESS)
   2740 
   2741         /* fall back to default bank */
   2742         {
   2743             if (pSynth->channels[channel].channelFlags & CHANNEL_FLAG_RHYTHM_CHANNEL)
   2744                 bank = DEFAULT_RHYTHM_BANK_NUMBER;
   2745             else
   2746                 bank = DEFAULT_MELODY_BANK_NUMBER;
   2747 
   2748             if (VMFindProgram(pSynth->pEAS, bank, program, &regionIndex) != EAS_SUCCESS)
   2749 
   2750             /* switch to program 0 in the default bank */
   2751             {
   2752                 if (VMFindProgram(pSynth->pEAS, bank, 0, &regionIndex) != EAS_SUCCESS)
   2753                     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMProgramChange: No program @ %03d:%03d:%03d\n",
   2754                         (bank >> 8) & 0x7f, bank & 0x7f, program); */ }
   2755             }
   2756         }
   2757     }
   2758 
   2759     /* we have our new program change for this channel */
   2760     pChannel->programNum = program;
   2761     pChannel->regionIndex = regionIndex;
   2762 
   2763     /*
   2764     set a channel flag to request parameter updates
   2765     for all the voices associated with this channel
   2766     */
   2767     pChannel->channelFlags |= CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
   2768 
   2769     return;
   2770 }
   2771 
   2772 /*----------------------------------------------------------------------------
   2773  * VMAddSamples()
   2774  *----------------------------------------------------------------------------
   2775  * Purpose:
   2776  * Synthesize the requested number of samples (block based processing)
   2777  *
   2778  * Inputs:
   2779  * nNumSamplesToAdd - number of samples to write to buffer
   2780  * psEASData - pointer to overall EAS data structure
   2781  *
   2782  * Outputs:
   2783  * number of voices rendered
   2784  *
   2785  * Side Effects:
   2786  * - samples are added to the presently free buffer
   2787  *
   2788  *----------------------------------------------------------------------------
   2789 */
   2790 EAS_I32 VMAddSamples (S_VOICE_MGR *pVoiceMgr, EAS_I32 *pMixBuffer, EAS_I32 numSamples)
   2791 {
   2792     S_SYNTH *pSynth;
   2793     EAS_INT voicesRendered;
   2794     EAS_INT voiceNum;
   2795     EAS_BOOL done;
   2796 
   2797 #ifdef  _REVERB
   2798     EAS_PCM *pReverbSendBuffer;
   2799 #endif  // ifdef    _REVERB
   2800 
   2801 #ifdef  _CHORUS
   2802     EAS_PCM *pChorusSendBuffer;
   2803 #endif  // ifdef    _CHORUS
   2804 
   2805     voicesRendered = 0;
   2806     for (voiceNum = 0; voiceNum < MAX_SYNTH_VOICES; voiceNum++)
   2807     {
   2808 
   2809         /* retarget stolen voices */
   2810         if ((pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen) && (pVoiceMgr->voices[voiceNum].gain <= 0))
   2811             VMRetargetStolenVoice(pVoiceMgr, voiceNum);
   2812 
   2813         /* get pointer to virtual synth */
   2814         pSynth = pVoiceMgr->pSynth[pVoiceMgr->voices[voiceNum].channel >> 4];
   2815 
   2816         /* synthesize active voices */
   2817         if (pVoiceMgr->voices[voiceNum].voiceState != eVoiceStateFree)
   2818         {
   2819             done = GetSynthPtr(voiceNum)->pfUpdateVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum], GetAdjustedVoiceNum(voiceNum), pMixBuffer, numSamples);
   2820             voicesRendered++;
   2821 
   2822             /* voice is finished */
   2823             if (done == EAS_TRUE)
   2824             {
   2825                 /* set gain of stolen voice to zero so it will be restarted */
   2826                 if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStolen)
   2827                     pVoiceMgr->voices[voiceNum].gain = 0;
   2828 
   2829                 /* or return it to the free voice pool */
   2830                 else
   2831                     VMFreeVoice(pVoiceMgr, pSynth, &pVoiceMgr->voices[voiceNum]);
   2832             }
   2833 
   2834             /* if this voice is scheduled to be muted, set the mute flag */
   2835             if (pVoiceMgr->voices[voiceNum].voiceFlags & VOICE_FLAG_DEFER_MUTE)
   2836             {
   2837                 pVoiceMgr->voices[voiceNum].voiceFlags &= ~(VOICE_FLAG_DEFER_MUTE | VOICE_FLAG_DEFER_MIDI_NOTE_OFF);
   2838                 VMMuteVoice(pVoiceMgr, voiceNum);
   2839             }
   2840 
   2841             /* if voice just started, advance state to play */
   2842             if (pVoiceMgr->voices[voiceNum].voiceState == eVoiceStateStart)
   2843                 pVoiceMgr->voices[voiceNum].voiceState = eVoiceStatePlay;
   2844         }
   2845     }
   2846 
   2847     return voicesRendered;
   2848 }
   2849 
   2850 /*----------------------------------------------------------------------------
   2851  * VMRender()
   2852  *----------------------------------------------------------------------------
   2853  * Purpose:
   2854  * This routine renders a frame of audio
   2855  *
   2856  * Inputs:
   2857  * psEASData        - pointer to overall EAS data structure
   2858  *
   2859  * Outputs:
   2860  * pVoicesRendered  - number of voices rendered this frame
   2861  *
   2862  * Side Effects:
   2863  *
   2864  *----------------------------------------------------------------------------
   2865 */
   2866 EAS_RESULT VMRender (S_VOICE_MGR *pVoiceMgr, EAS_I32 numSamples, EAS_I32 *pMixBuffer, EAS_I32 *pVoicesRendered)
   2867 {
   2868     S_SYNTH *pSynth;
   2869     EAS_INT i;
   2870     EAS_INT channel;
   2871 
   2872 #ifdef _CHECKED_BUILD
   2873     SanityCheck(pVoiceMgr);
   2874 #endif
   2875 
   2876     /* update MIDI channel parameters */
   2877     *pVoicesRendered = 0;
   2878     for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++)
   2879     {
   2880         if (pVoiceMgr->pSynth[i] != NULL)
   2881             VMUpdateStaticChannelParameters(pVoiceMgr, pVoiceMgr->pSynth[i]);
   2882     }
   2883 
   2884     /* synthesize a buffer of audio */
   2885     *pVoicesRendered = VMAddSamples(pVoiceMgr, pMixBuffer, numSamples);
   2886 
   2887     /*
   2888      * check for deferred note-off messages
   2889      * If flag is set, that means one or more voices are expecting deferred
   2890      * midi note-off messages because the midi note-on and corresponding midi
   2891      * note-off requests occurred during the same update interval. The goal
   2892      * is the defer the note-off request so that the note can at least start.
   2893     */
   2894     for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++)
   2895     {
   2896         pSynth = pVoiceMgr->pSynth[i];
   2897 
   2898         if (pSynth== NULL)
   2899             continue;
   2900 
   2901         if (pSynth->synthFlags & SYNTH_FLAG_DEFERRED_MIDI_NOTE_OFF_PENDING)
   2902             VMDeferredStopNote(pVoiceMgr, pSynth);
   2903 
   2904         /* check if we need to reset the synth */
   2905         if ((pSynth->synthFlags & SYNTH_FLAG_RESET_IS_REQUESTED) &&
   2906             (pSynth->numActiveVoices == 0))
   2907         {
   2908             /*
   2909             complete the process of resetting the synth now that
   2910             all voices have muted
   2911             */
   2912 #ifdef _DEBUG_VM
   2913             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "VMAddSamples: complete the reset process\n"); */ }
   2914 #endif
   2915 
   2916             VMInitializeAllChannels(pVoiceMgr, pSynth);
   2917             VMInitializeAllVoices(pVoiceMgr, pSynth->vSynthNum);
   2918 
   2919             /* clear the reset flag */
   2920             pSynth->synthFlags &= ~SYNTH_FLAG_RESET_IS_REQUESTED;
   2921         }
   2922 
   2923         /* clear channel update flags */
   2924         for (channel = 0; channel < NUM_SYNTH_CHANNELS; channel++)
   2925             pSynth->channels[channel].channelFlags &= ~CHANNEL_FLAG_UPDATE_CHANNEL_PARAMETERS;
   2926 
   2927         }
   2928 
   2929 #ifdef _CHECKED_BUILD
   2930     SanityCheck(pVoiceMgr);
   2931 #endif
   2932 
   2933     return EAS_SUCCESS;
   2934 }
   2935 
   2936 /*----------------------------------------------------------------------------
   2937  * VMInitWorkload()
   2938  *----------------------------------------------------------------------------
   2939  * Purpose:
   2940  * Clears the workload counter
   2941  *
   2942  * Inputs:
   2943  * pVoiceMgr            - pointer to instance data
   2944  *
   2945  * Outputs:
   2946  *
   2947  * Side Effects:
   2948  *
   2949  *----------------------------------------------------------------------------
   2950 */
   2951 void VMInitWorkload (S_VOICE_MGR *pVoiceMgr)
   2952 {
   2953     pVoiceMgr->workload = 0;
   2954 }
   2955 
   2956 /*----------------------------------------------------------------------------
   2957  * VMSetWorkload()
   2958  *----------------------------------------------------------------------------
   2959  * Purpose:
   2960  * Sets the max workload for a single frame.
   2961  *
   2962  * Inputs:
   2963  * pVoiceMgr            - pointer to instance data
   2964  *
   2965  * Outputs:
   2966  *
   2967  * Side Effects:
   2968  *
   2969  *----------------------------------------------------------------------------
   2970 */
   2971 void VMSetWorkload (S_VOICE_MGR *pVoiceMgr, EAS_I32 maxWorkLoad)
   2972 {
   2973     pVoiceMgr->maxWorkLoad = maxWorkLoad;
   2974 }
   2975 
   2976 /*----------------------------------------------------------------------------
   2977  * VMCheckWorkload()
   2978  *----------------------------------------------------------------------------
   2979  * Purpose:
   2980  * Checks to see if work load has been exceeded on this frame.
   2981  *
   2982  * Inputs:
   2983  * pVoiceMgr            - pointer to instance data
   2984  *
   2985  * Outputs:
   2986  *
   2987  * Side Effects:
   2988  *
   2989  *----------------------------------------------------------------------------
   2990 */
   2991 EAS_BOOL VMCheckWorkload (S_VOICE_MGR *pVoiceMgr)
   2992 {
   2993     if (pVoiceMgr->maxWorkLoad > 0)
   2994         return (EAS_BOOL) (pVoiceMgr->workload >= pVoiceMgr->maxWorkLoad);
   2995     return EAS_FALSE;
   2996 }
   2997 
   2998 /*----------------------------------------------------------------------------
   2999  * VMActiveVoices()
   3000  *----------------------------------------------------------------------------
   3001  * Purpose:
   3002  * Returns the number of active voices in the synthesizer.
   3003  *
   3004  * Inputs:
   3005  * pEASData         - pointer to instance data
   3006  *
   3007  * Outputs:
   3008  * Returns the number of active voices
   3009  *
   3010  * Side Effects:
   3011  *
   3012  *----------------------------------------------------------------------------
   3013 */
   3014 EAS_I32 VMActiveVoices (S_SYNTH *pSynth)
   3015 {
   3016     return pSynth->numActiveVoices;
   3017 }
   3018 
   3019 /*----------------------------------------------------------------------------
   3020  * VMSetSynthPolyphony()
   3021  *----------------------------------------------------------------------------
   3022  * Purpose:
   3023  * Set the synth to a new polyphony value. Value must be >= 1 and
   3024  * <= MAX_SYNTH_VOICES. This function will pin the polyphony at those limits
   3025  *
   3026  * Inputs:
   3027  * pVoiceMgr        pointer to synthesizer data
   3028  * polyphonyCount   desired polyphony count
   3029  * synth            synthesizer number (0 = onboard, 1 = DSP)
   3030  *
   3031  * Outputs:
   3032  * Returns error code
   3033  *
   3034  * Side Effects:
   3035  *
   3036  *----------------------------------------------------------------------------
   3037 */
   3038 EAS_RESULT VMSetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 polyphonyCount)
   3039 {
   3040     EAS_INT i;
   3041     EAS_INT activeVoices;
   3042 
   3043     /* lower limit */
   3044     if (polyphonyCount < 1)
   3045         polyphonyCount = 1;
   3046 
   3047     /* split architecture */
   3048 #if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH)
   3049     if (synth == EAS_MCU_SYNTH)
   3050     {
   3051         if (polyphonyCount > NUM_PRIMARY_VOICES)
   3052             polyphonyCount = NUM_PRIMARY_VOICES;
   3053         if (pVoiceMgr->maxPolyphonyPrimary == polyphonyCount)
   3054             return EAS_SUCCESS;
   3055         pVoiceMgr->maxPolyphonyPrimary = (EAS_U16) polyphonyCount;
   3056     }
   3057     else if (synth == EAS_DSP_SYNTH)
   3058     {
   3059         if (polyphonyCount > NUM_SECONDARY_VOICES)
   3060             polyphonyCount = NUM_SECONDARY_VOICES;
   3061         if (pVoiceMgr->maxPolyphonySecondary == polyphonyCount)
   3062             return EAS_SUCCESS;
   3063         pVoiceMgr->maxPolyphonySecondary = (EAS_U16) polyphonyCount;
   3064     }
   3065     else
   3066         return EAS_ERROR_PARAMETER_RANGE;
   3067 
   3068     /* setting for SP-MIDI */
   3069     pVoiceMgr->maxPolyphony = pVoiceMgr->maxPolyphonyPrimary + pVoiceMgr->maxPolyphonySecondary;
   3070 
   3071     /* standard architecture */
   3072 #else
   3073     if (synth != EAS_MCU_SYNTH)
   3074         return EAS_ERROR_PARAMETER_RANGE;
   3075 
   3076     /* pin desired value to possible limits */
   3077     if (polyphonyCount > MAX_SYNTH_VOICES)
   3078         polyphonyCount = MAX_SYNTH_VOICES;
   3079 
   3080     /* set polyphony, if value is different than current value */
   3081     if (pVoiceMgr->maxPolyphony == polyphonyCount)
   3082         return EAS_SUCCESS;
   3083 
   3084     pVoiceMgr->maxPolyphony = (EAS_U16) polyphonyCount;
   3085 #endif
   3086 
   3087     /* if SPMIDI enabled, update channel masking based on new polyphony */
   3088     for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++)
   3089     {
   3090         if (pVoiceMgr->pSynth[i])
   3091         {
   3092             if (pVoiceMgr->pSynth[i]->synthFlags & SYNTH_FLAG_SP_MIDI_ON)
   3093                 VMMIPUpdateChannelMuting(pVoiceMgr, pVoiceMgr->pSynth[i]);
   3094             else
   3095                 pVoiceMgr->pSynth[i]->poolAlloc[0] = (EAS_U8) polyphonyCount;
   3096         }
   3097     }
   3098 
   3099     /* are we under polyphony limit? */
   3100     if (pVoiceMgr->activeVoices <= polyphonyCount)
   3101         return EAS_SUCCESS;
   3102 
   3103     /* count the number of active voices */
   3104     activeVoices = 0;
   3105     for (i = 0; i < MAX_SYNTH_VOICES; i++)
   3106     {
   3107 
   3108         /* is voice active? */
   3109         if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting))
   3110             activeVoices++;
   3111     }
   3112 
   3113     /* we may have to mute voices to reach new target */
   3114     while (activeVoices > polyphonyCount)
   3115     {
   3116         S_SYNTH *pSynth;
   3117         S_SYNTH_VOICE *pVoice;
   3118         EAS_I32 currentPriority, bestPriority;
   3119         EAS_INT bestCandidate;
   3120 
   3121         /* find the lowest priority voice */
   3122         bestPriority = bestCandidate = -1;
   3123         for (i = 0; i < MAX_SYNTH_VOICES; i++)
   3124         {
   3125 
   3126             pVoice = &pVoiceMgr->voices[i];
   3127 
   3128             /* ignore free and muting voices */
   3129             if ((pVoice->voiceState == eVoiceStateFree) || (pVoice->voiceState == eVoiceStateMuting))
   3130                 continue;
   3131 
   3132             pSynth = pVoiceMgr->pSynth[GET_VSYNTH(pVoice->channel)];
   3133 
   3134             /* if voice is stolen or just started, reduce the likelihood it will be stolen */
   3135             if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET))
   3136             {
   3137                 /* include velocity */
   3138                 currentPriority = 128 - pVoice->nextVelocity;
   3139 
   3140                 /* include channel priority */
   3141                 currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT;
   3142             }
   3143             else
   3144             {
   3145                 /* include age */
   3146                 currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT;
   3147 
   3148                 /* include note gain -higher gain is lower steal value */
   3149                 /*lint -e{704} use shift for performance */
   3150                 currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) -
   3151                     ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT));
   3152 
   3153                 /* include channel priority */
   3154                 currentPriority += pSynth->channels[GET_CHANNEL(pVoice->channel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT;
   3155             }
   3156 
   3157             /* include synth priority */
   3158             currentPriority += pSynth->priority << SYNTH_PRIORITY_WEIGHT;
   3159 
   3160             /* is this the best choice so far? */
   3161             if (currentPriority > bestPriority)
   3162             {
   3163                 bestPriority = currentPriority;
   3164                 bestCandidate = i;
   3165             }
   3166         }
   3167 
   3168         /* shutdown best candidate */
   3169         if (bestCandidate < 0)
   3170         {
   3171             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ }
   3172             break;
   3173         }
   3174 
   3175         /* shut down this voice */
   3176         /*lint -e{771} pSynth is initialized if bestCandidate >= 0 */
   3177         VMMuteVoice(pVoiceMgr, bestCandidate);
   3178         activeVoices--;
   3179     }
   3180 
   3181     return EAS_SUCCESS;
   3182 }
   3183 
   3184 /*----------------------------------------------------------------------------
   3185  * VMGetSynthPolyphony()
   3186  *----------------------------------------------------------------------------
   3187  * Purpose:
   3188  * Returns the current polyphony setting
   3189  *
   3190  * Inputs:
   3191  * pVoiceMgr        pointer to synthesizer data
   3192  * synth            synthesizer number (0 = onboard, 1 = DSP)
   3193  *
   3194  * Outputs:
   3195  * Returns actual polyphony value set, as pinned by limits
   3196  *
   3197  * Side Effects:
   3198  *
   3199  *----------------------------------------------------------------------------
   3200 */
   3201 EAS_RESULT VMGetSynthPolyphony (S_VOICE_MGR *pVoiceMgr, EAS_I32 synth, EAS_I32 *pPolyphonyCount)
   3202 {
   3203 
   3204 #if defined(_SECONDARY_SYNTH) || defined(EAS_SPLIT_WT_SYNTH)
   3205     if (synth == EAS_MCU_SYNTH)
   3206         *pPolyphonyCount = pVoiceMgr->maxPolyphonyPrimary;
   3207     else if (synth == EAS_DSP_SYNTH)
   3208         *pPolyphonyCount = pVoiceMgr->maxPolyphonySecondary;
   3209     else
   3210         return EAS_ERROR_PARAMETER_RANGE;
   3211 #else
   3212     if (synth != EAS_MCU_SYNTH)
   3213         return EAS_ERROR_PARAMETER_RANGE;
   3214     *pPolyphonyCount = pVoiceMgr->maxPolyphony;
   3215 #endif
   3216     return EAS_SUCCESS;
   3217 }
   3218 
   3219 /*----------------------------------------------------------------------------
   3220  * VMSetPolyphony()
   3221  *----------------------------------------------------------------------------
   3222  * Purpose:
   3223  * Set the virtual synth polyphony. 0 = no limit (i.e. can use
   3224  * all available voices).
   3225  *
   3226  * Inputs:
   3227  * pVoiceMgr        pointer to synthesizer data
   3228  * polyphonyCount   desired polyphony count
   3229  * pSynth           pointer to virtual synth
   3230  *
   3231  * Outputs:
   3232  * Returns error code
   3233  *
   3234  * Side Effects:
   3235  *
   3236  *----------------------------------------------------------------------------
   3237 */
   3238 EAS_RESULT VMSetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 polyphonyCount)
   3239 {
   3240     EAS_INT i;
   3241     EAS_INT activeVoices;
   3242 
   3243     /* check limits */
   3244     if (polyphonyCount < 0)
   3245         return EAS_ERROR_PARAMETER_RANGE;
   3246 
   3247     /* zero is max polyphony */
   3248     if ((polyphonyCount == 0) || (polyphonyCount > MAX_SYNTH_VOICES))
   3249     {
   3250         pSynth->maxPolyphony = 0;
   3251         return EAS_SUCCESS;
   3252     }
   3253 
   3254     /* set new polyphony */
   3255     pSynth->maxPolyphony = (EAS_U16) polyphonyCount;
   3256 
   3257     /* max polyphony is minimum of virtual synth and actual synth */
   3258     if (polyphonyCount > pVoiceMgr->maxPolyphony)
   3259         polyphonyCount = pVoiceMgr->maxPolyphony;
   3260 
   3261     /* if SP-MIDI mode, update the channel muting */
   3262     if (pSynth->synthFlags & SYNTH_FLAG_SP_MIDI_ON)
   3263         VMMIPUpdateChannelMuting(pVoiceMgr, pSynth);
   3264     else
   3265         pSynth->poolAlloc[0] = (EAS_U8) polyphonyCount;
   3266 
   3267     /* are we under polyphony limit? */
   3268     if (pSynth->numActiveVoices <= polyphonyCount)
   3269         return EAS_SUCCESS;
   3270 
   3271     /* count the number of active voices */
   3272     activeVoices = 0;
   3273     for (i = 0; i < MAX_SYNTH_VOICES; i++)
   3274     {
   3275         /* this synth? */
   3276         if (GET_VSYNTH(pVoiceMgr->voices[i].nextChannel) != pSynth->vSynthNum)
   3277             continue;
   3278 
   3279         /* is voice active? */
   3280         if ((pVoiceMgr->voices[i].voiceState != eVoiceStateFree) && (pVoiceMgr->voices[i].voiceState != eVoiceStateMuting))
   3281             activeVoices++;
   3282     }
   3283 
   3284     /* we may have to mute voices to reach new target */
   3285     while (activeVoices > polyphonyCount)
   3286     {
   3287         S_SYNTH_VOICE *pVoice;
   3288         EAS_I32 currentPriority, bestPriority;
   3289         EAS_INT bestCandidate;
   3290 
   3291         /* find the lowest priority voice */
   3292         bestPriority = bestCandidate = -1;
   3293         for (i = 0; i < MAX_SYNTH_VOICES; i++)
   3294         {
   3295             pVoice = &pVoiceMgr->voices[i];
   3296 
   3297             /* this synth? */
   3298             if (GET_VSYNTH(pVoice->nextChannel) != pSynth->vSynthNum)
   3299                 continue;
   3300 
   3301             /* if voice is stolen or just started, reduce the likelihood it will be stolen */
   3302             if (( pVoice->voiceState == eVoiceStateStolen) || (pVoice->voiceFlags & VOICE_FLAG_NO_SAMPLES_SYNTHESIZED_YET))
   3303             {
   3304                 /* include velocity */
   3305                 currentPriority = 128 - pVoice->nextVelocity;
   3306 
   3307                 /* include channel priority */
   3308                 currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT;
   3309             }
   3310             else
   3311             {
   3312                 /* include age */
   3313                 currentPriority = (EAS_I32) pVoice->age << NOTE_AGE_STEAL_WEIGHT;
   3314 
   3315                 /* include note gain -higher gain is lower steal value */
   3316                 /*lint -e{704} use shift for performance */
   3317                 currentPriority += ((32768 >> (12 - NOTE_GAIN_STEAL_WEIGHT)) + 256) -
   3318                     ((EAS_I32) pVoice->gain >> (12 - NOTE_GAIN_STEAL_WEIGHT));
   3319 
   3320                 /* include channel priority */
   3321                 currentPriority += pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool << CHANNEL_PRIORITY_STEAL_WEIGHT;
   3322             }
   3323 
   3324             /* is this the best choice so far? */
   3325             if (currentPriority > bestPriority)
   3326             {
   3327                 bestPriority = currentPriority;
   3328                 bestCandidate = i;
   3329             }
   3330         }
   3331 
   3332         /* shutdown best candidate */
   3333         if (bestCandidate < 0)
   3334         {
   3335             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "VMSetPolyphony: Unable to reduce polyphony\n"); */ }
   3336             break;
   3337         }
   3338 
   3339         /* shut down this voice */
   3340         VMMuteVoice(pVoiceMgr, bestCandidate);
   3341         activeVoices--;
   3342     }
   3343 
   3344     return EAS_SUCCESS;
   3345 }
   3346 
   3347 /*----------------------------------------------------------------------------
   3348  * VMGetPolyphony()
   3349  *----------------------------------------------------------------------------
   3350  * Purpose:
   3351  * Get the virtual synth polyphony
   3352  *
   3353  * Inputs:
   3354  * pVoiceMgr        pointer to synthesizer data
   3355  * pPolyphonyCount  pointer to variable to hold polyphony count
   3356  * pSynth           pointer to virtual synth
   3357  *
   3358  * Outputs:
   3359  * Returns error code
   3360  *
   3361  * Side Effects:
   3362  *
   3363  *----------------------------------------------------------------------------
   3364 */
   3365 /*lint -esym(715, pVoiceMgr) reserved for future use */
   3366 EAS_RESULT VMGetPolyphony (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPolyphonyCount)
   3367 {
   3368     *pPolyphonyCount = (EAS_U16) pSynth->maxPolyphony;
   3369     return EAS_SUCCESS;
   3370 }
   3371 
   3372 /*----------------------------------------------------------------------------
   3373  * VMSetPriority()
   3374  *----------------------------------------------------------------------------
   3375  * Purpose:
   3376  * Set the virtual synth priority
   3377  *
   3378  * Inputs:
   3379  * pVoiceMgr        pointer to synthesizer data
   3380  * priority         new priority
   3381  * pSynth           pointer to virtual synth
   3382  *
   3383  * Outputs:
   3384  * Returns error code
   3385  *
   3386  * Side Effects:
   3387  *
   3388  *----------------------------------------------------------------------------
   3389 */
   3390 /*lint -esym(715, pVoiceMgr) reserved for future use */
   3391 EAS_RESULT VMSetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 priority)
   3392 {
   3393     pSynth->priority = (EAS_U8) priority ;
   3394     return EAS_SUCCESS;
   3395 }
   3396 
   3397 /*----------------------------------------------------------------------------
   3398  * VMGetPriority()
   3399  *----------------------------------------------------------------------------
   3400  * Purpose:
   3401  * Get the virtual synth priority
   3402  *
   3403  * Inputs:
   3404  * pVoiceMgr        pointer to synthesizer data
   3405  * pPriority        pointer to variable to hold priority
   3406  * pSynth           pointer to virtual synth
   3407  *
   3408  * Outputs:
   3409  * Returns error code
   3410  *
   3411  * Side Effects:
   3412  *
   3413  *----------------------------------------------------------------------------
   3414 */
   3415 /*lint -esym(715, pVoiceMgr) reserved for future use */
   3416 EAS_RESULT VMGetPriority (S_VOICE_MGR *pVoiceMgr, S_SYNTH *pSynth, EAS_I32 *pPriority)
   3417 {
   3418     *pPriority = pSynth->priority;
   3419     return EAS_SUCCESS;
   3420 }
   3421 
   3422 /*----------------------------------------------------------------------------
   3423  * VMSetVolume()
   3424  *----------------------------------------------------------------------------
   3425  * Purpose:
   3426  * Set the master volume for this synthesizer for this sequence.
   3427  *
   3428  * Inputs:
   3429  * nSynthVolume - the desired master volume
   3430  * psEASData - pointer to overall EAS data structure
   3431  *
   3432  * Outputs:
   3433  *
   3434  *
   3435  * Side Effects:
   3436  * overrides any previously set master volume from sysex
   3437  *
   3438  *----------------------------------------------------------------------------
   3439 */
   3440 void VMSetVolume (S_SYNTH *pSynth, EAS_U16 masterVolume)
   3441 {
   3442     pSynth->masterVolume = masterVolume;
   3443     pSynth->synthFlags |= SYNTH_FLAG_UPDATE_ALL_CHANNEL_PARAMETERS;
   3444 }
   3445 
   3446 /*----------------------------------------------------------------------------
   3447  * VMSetPitchBendRange()
   3448  *----------------------------------------------------------------------------
   3449  * Set the pitch bend range for the given channel.
   3450  *----------------------------------------------------------------------------
   3451 */
   3452 void VMSetPitchBendRange (S_SYNTH *pSynth, EAS_INT channel, EAS_I16 pitchBendRange)
   3453 {
   3454     pSynth->channels[channel].pitchBendSensitivity = pitchBendRange;
   3455 }
   3456 
   3457 /*----------------------------------------------------------------------------
   3458  * VMValidateEASLib()
   3459  *----------------------------------------------------------------------------
   3460  * Validates an EAS library
   3461  *----------------------------------------------------------------------------
   3462 */
   3463 EAS_RESULT VMValidateEASLib (EAS_SNDLIB_HANDLE pEAS)
   3464 {
   3465     /* validate the sound library */
   3466     if (pEAS)
   3467     {
   3468         if (pEAS->identifier != _EAS_LIBRARY_VERSION)
   3469         {
   3470             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sound library mismatch in sound library: Read 0x%08x, expected 0x%08x\n",
   3471                 pEAS->identifier, _EAS_LIBRARY_VERSION); */ }
   3472             return EAS_ERROR_SOUND_LIBRARY;
   3473         }
   3474 
   3475         /* check sample rate */
   3476         if ((pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK) != _OUTPUT_SAMPLE_RATE)
   3477         {
   3478             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Sample rate mismatch in sound library: Read %lu, expected %lu\n",
   3479                 pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ }
   3480             return EAS_ERROR_SOUND_LIBRARY;
   3481         }
   3482 
   3483 #ifdef _WT_SYNTH
   3484         /* check sample bit depth */
   3485 #ifdef _8_BIT_SAMPLES
   3486         if (pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES)
   3487         {
   3488             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 8-bit samples and found 16-bit\n",
   3489                 pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ }
   3490             return EAS_ERROR_SOUND_LIBRARY;
   3491         }
   3492 #endif
   3493 #ifdef _16_BIT_SAMPLES
   3494         if ((pEAS->libAttr & LIB_FORMAT_16_BIT_SAMPLES) == 0)
   3495         {
   3496             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMValidateEASLib: Expected 16-bit samples and found 8-bit\n",
   3497                 pEAS->libAttr & LIBFORMAT_SAMPLE_RATE_MASK, _OUTPUT_SAMPLE_RATE); */ }
   3498             return EAS_ERROR_SOUND_LIBRARY;
   3499         }
   3500 #endif
   3501 #endif
   3502     }
   3503 
   3504     return EAS_SUCCESS;
   3505 }
   3506 
   3507 /*----------------------------------------------------------------------------
   3508  * VMSetGlobalEASLib()
   3509  *----------------------------------------------------------------------------
   3510  * Purpose:
   3511  * Sets the EAS library to be used by the synthesizer
   3512  *
   3513  * Inputs:
   3514  * psEASData - pointer to overall EAS data structure
   3515  *
   3516  * Outputs:
   3517  *
   3518  *
   3519  * Side Effects:
   3520  *
   3521  *----------------------------------------------------------------------------
   3522 */
   3523 EAS_RESULT VMSetGlobalEASLib (S_VOICE_MGR *pVoiceMgr, EAS_SNDLIB_HANDLE pEAS)
   3524 {
   3525     EAS_RESULT result;
   3526 
   3527     result = VMValidateEASLib(pEAS);
   3528     if (result != EAS_SUCCESS)
   3529         return result;
   3530 
   3531     pVoiceMgr->pGlobalEAS = pEAS;
   3532     return EAS_SUCCESS;
   3533 }
   3534 
   3535 /*----------------------------------------------------------------------------
   3536  * VMSetEASLib()
   3537  *----------------------------------------------------------------------------
   3538  * Purpose:
   3539  * Sets the EAS library to be used by the synthesizer
   3540  *
   3541  * Inputs:
   3542  * psEASData - pointer to overall EAS data structure
   3543  *
   3544  * Outputs:
   3545  *
   3546  *
   3547  * Side Effects:
   3548  *
   3549  *----------------------------------------------------------------------------
   3550 */
   3551 EAS_RESULT VMSetEASLib (S_SYNTH *pSynth, EAS_SNDLIB_HANDLE pEAS)
   3552 {
   3553     EAS_RESULT result;
   3554 
   3555     result = VMValidateEASLib(pEAS);
   3556     if (result != EAS_SUCCESS)
   3557         return result;
   3558 
   3559     pSynth->pEAS = pEAS;
   3560     return EAS_SUCCESS;
   3561 }
   3562 
   3563 #ifdef DLS_SYNTHESIZER
   3564 /*----------------------------------------------------------------------------
   3565  * VMSetGlobalDLSLib()
   3566  *----------------------------------------------------------------------------
   3567  * Purpose:
   3568  * Sets the DLS library to be used by the synthesizer
   3569  *
   3570  * Inputs:
   3571  * psEASData - pointer to overall EAS data structure
   3572  *
   3573  * Outputs:
   3574  *
   3575  *
   3576  * Side Effects:
   3577  *
   3578  *----------------------------------------------------------------------------
   3579 */
   3580 EAS_RESULT VMSetGlobalDLSLib (EAS_DATA_HANDLE pEASData, EAS_DLSLIB_HANDLE pDLS)
   3581 {
   3582 
   3583     if (pEASData->pVoiceMgr->pGlobalDLS)
   3584         DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS);
   3585 
   3586     pEASData->pVoiceMgr->pGlobalDLS = pDLS;
   3587     return EAS_SUCCESS;
   3588 }
   3589 
   3590 /*----------------------------------------------------------------------------
   3591  * VMSetDLSLib()
   3592  *----------------------------------------------------------------------------
   3593  * Purpose:
   3594  * Sets the DLS library to be used by the synthesizer
   3595  *
   3596  * Inputs:
   3597  * psEASData - pointer to overall EAS data structure
   3598  *
   3599  * Outputs:
   3600  *
   3601  *
   3602  * Side Effects:
   3603  *
   3604  *----------------------------------------------------------------------------
   3605 */
   3606 EAS_RESULT VMSetDLSLib (S_SYNTH *pSynth, EAS_DLSLIB_HANDLE pDLS)
   3607 {
   3608     pSynth->pDLS = pDLS;
   3609     return EAS_SUCCESS;
   3610 }
   3611 #endif
   3612 
   3613 /*----------------------------------------------------------------------------
   3614  * VMSetTranposition()
   3615  *----------------------------------------------------------------------------
   3616  * Purpose:
   3617  * Sets the global key transposition used by the synthesizer.
   3618  * Transposes all melodic instruments up or down by the specified
   3619  * amount. Range is limited to +/-12 semitones.
   3620  *
   3621  * Inputs:
   3622  * psEASData - pointer to overall EAS data structure
   3623  *
   3624  * Outputs:
   3625  *
   3626  *
   3627  * Side Effects:
   3628  *
   3629  *----------------------------------------------------------------------------
   3630 */
   3631 void VMSetTranposition (S_SYNTH *pSynth, EAS_I32 transposition)
   3632 {
   3633     pSynth->globalTranspose = (EAS_I8) transposition;
   3634 }
   3635 
   3636 /*----------------------------------------------------------------------------
   3637  * VMGetTranposition()
   3638  *----------------------------------------------------------------------------
   3639  * Purpose:
   3640  * Gets the global key transposition used by the synthesizer.
   3641  * Transposes all melodic instruments up or down by the specified
   3642  * amount. Range is limited to +/-12 semitones.
   3643  *
   3644  * Inputs:
   3645  * psEASData - pointer to overall EAS data structure
   3646  *
   3647  * Outputs:
   3648  *
   3649  *
   3650  * Side Effects:
   3651  *
   3652  *----------------------------------------------------------------------------
   3653 */
   3654 void VMGetTranposition (S_SYNTH *pSynth, EAS_I32 *pTransposition)
   3655 {
   3656     *pTransposition = pSynth->globalTranspose;
   3657 }
   3658 
   3659 /*----------------------------------------------------------------------------
   3660  * VMGetNoteCount()
   3661  *----------------------------------------------------------------------------
   3662 * Returns the total note count
   3663 *----------------------------------------------------------------------------
   3664 */
   3665 EAS_I32 VMGetNoteCount (S_SYNTH *pSynth)
   3666 {
   3667     return pSynth->totalNoteCount;
   3668 }
   3669 
   3670 /*----------------------------------------------------------------------------
   3671  * VMMIDIShutdown()
   3672  *----------------------------------------------------------------------------
   3673  * Purpose:
   3674  * Clean up any Synth related system issues.
   3675  *
   3676  * Inputs:
   3677  * psEASData - pointer to overall EAS data structure
   3678  *
   3679  * Outputs:
   3680  * None
   3681  *
   3682  * Side Effects:
   3683  *
   3684  *----------------------------------------------------------------------------
   3685 */
   3686 void VMMIDIShutdown (S_EAS_DATA *pEASData, S_SYNTH *pSynth)
   3687 {
   3688     EAS_INT vSynthNum;
   3689 
   3690     /* decrement reference count, free if all references are gone */
   3691     if (--pSynth->refCount > 0)
   3692         return;
   3693 
   3694     vSynthNum = pSynth->vSynthNum;
   3695 
   3696     /* cleanup DLS load */
   3697 #ifdef DLS_SYNTHESIZER
   3698     /*lint -e{550} result used only in debugging code */
   3699     if (pSynth->pDLS != NULL)
   3700     {
   3701         EAS_RESULT result;
   3702         if ((result = DLSCleanup(pEASData->hwInstData, pSynth->pDLS)) != EAS_SUCCESS)
   3703             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMMIDIShutdown: Error %ld cleaning up DLS collection\n", result); */ }
   3704         pSynth->pDLS = NULL;
   3705     }
   3706 #endif
   3707 
   3708     VMReset(pEASData->pVoiceMgr, pSynth, EAS_TRUE);
   3709 
   3710     /* check Configuration Module for static memory allocation */
   3711     if (!pEASData->staticMemoryModel)
   3712         EAS_HWFree(pEASData->hwInstData, pSynth);
   3713 
   3714     /* clear pointer to MIDI state */
   3715     pEASData->pVoiceMgr->pSynth[vSynthNum] = NULL;
   3716 }
   3717 
   3718 /*----------------------------------------------------------------------------
   3719  * VMShutdown()
   3720  *----------------------------------------------------------------------------
   3721  * Purpose:
   3722  * Clean up any Synth related system issues.
   3723  *
   3724  * Inputs:
   3725  * psEASData - pointer to overall EAS data structure
   3726  *
   3727  * Outputs:
   3728  * None
   3729  *
   3730  * Side Effects:
   3731  *
   3732  *----------------------------------------------------------------------------
   3733 */
   3734 void VMShutdown (S_EAS_DATA *pEASData)
   3735 {
   3736 
   3737     /* don't free a NULL pointer */
   3738     if (pEASData->pVoiceMgr == NULL)
   3739         return;
   3740 
   3741 #ifdef DLS_SYNTHESIZER
   3742     /* if we have a global DLS collection, clean it up */
   3743     if (pEASData->pVoiceMgr->pGlobalDLS)
   3744     {
   3745         DLSCleanup(pEASData->hwInstData, pEASData->pVoiceMgr->pGlobalDLS);
   3746         pEASData->pVoiceMgr->pGlobalDLS = NULL;
   3747     }
   3748 #endif
   3749 
   3750     /* check Configuration Module for static memory allocation */
   3751     if (!pEASData->staticMemoryModel)
   3752         EAS_HWFree(pEASData->hwInstData, pEASData->pVoiceMgr);
   3753     pEASData->pVoiceMgr = NULL;
   3754 }
   3755 
   3756 #ifdef EXTERNAL_AUDIO
   3757 /*----------------------------------------------------------------------------
   3758  * EAS_RegExtAudioCallback()
   3759  *----------------------------------------------------------------------------
   3760  * Register a callback for external audio processing
   3761  *----------------------------------------------------------------------------
   3762 */
   3763 void VMRegExtAudioCallback (S_SYNTH *pSynth, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc)
   3764 {
   3765     pSynth->pExtAudioInstData = pInstData;
   3766     pSynth->cbProgChgFunc = cbProgChgFunc;
   3767     pSynth->cbEventFunc = cbEventFunc;
   3768 }
   3769 
   3770 /*----------------------------------------------------------------------------
   3771  * VMGetMIDIControllers()
   3772  *----------------------------------------------------------------------------
   3773  * Returns the MIDI controller values on the specified channel
   3774  *----------------------------------------------------------------------------
   3775 */
   3776 void VMGetMIDIControllers (S_SYNTH *pSynth, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl)
   3777 {
   3778     pControl->modWheel = pSynth->channels[channel].modWheel;
   3779     pControl->volume = pSynth->channels[channel].volume;
   3780     pControl->pan = pSynth->channels[channel].pan;
   3781     pControl->expression = pSynth->channels[channel].expression;
   3782     pControl->channelPressure = pSynth->channels[channel].channelPressure;
   3783 
   3784 #ifdef _REVERB
   3785     pControl->reverbSend = pSynth->channels[channel].reverbSend;
   3786 #endif
   3787 
   3788 #ifdef _CHORUSE
   3789     pControl->chorusSend = pSynth->channels[channel].chorusSend;
   3790 #endif
   3791 }
   3792 #endif
   3793 
   3794 #ifdef _SPLIT_ARCHITECTURE
   3795 /*----------------------------------------------------------------------------
   3796  * VMStartFrame()
   3797  *----------------------------------------------------------------------------
   3798  * Purpose:
   3799  * Starts an audio frame
   3800  *
   3801  * Inputs:
   3802  *
   3803  * Outputs:
   3804  * Returns true if EAS_MixEnginePrep should be called (onboard mixing)
   3805  *
   3806  * Side Effects:
   3807  *
   3808  *----------------------------------------------------------------------------
   3809 */
   3810 EAS_BOOL VMStartFrame (S_EAS_DATA *pEASData)
   3811 {
   3812 
   3813     /* init counter for voices starts in split architecture */
   3814 #ifdef MAX_VOICE_STARTS
   3815     pVoiceMgr->numVoiceStarts = 0;
   3816 #endif
   3817 
   3818     return pFrameInterface->pfStartFrame(pEASData->pVoiceMgr->pFrameBuffer);
   3819 }
   3820 
   3821 /*----------------------------------------------------------------------------
   3822  * VMEndFrame()
   3823  *----------------------------------------------------------------------------
   3824  * Purpose:
   3825  * Stops an audio frame
   3826  *
   3827  * Inputs:
   3828  *
   3829  * Outputs:
   3830  * Returns true if EAS_MixEnginePost should be called (onboard mixing)
   3831  *
   3832  * Side Effects:
   3833  *
   3834  *----------------------------------------------------------------------------
   3835 */
   3836 EAS_BOOL VMEndFrame (S_EAS_DATA *pEASData)
   3837 {
   3838 
   3839     return pFrameInterface->pfEndFrame(pEASData->pVoiceMgr->pFrameBuffer, pEASData->pMixBuffer, pEASData->masterGain);
   3840 }
   3841 #endif
   3842 
   3843 #ifdef TEST_HARNESS
   3844 /*----------------------------------------------------------------------------
   3845  * SanityCheck()
   3846  *----------------------------------------------------------------------------
   3847 */
   3848 EAS_RESULT VMSanityCheck (EAS_DATA_HANDLE pEASData)
   3849 {
   3850     S_SYNTH_VOICE *pVoice;
   3851     S_SYNTH *pSynth;
   3852     EAS_INT i;
   3853     EAS_INT j;
   3854     EAS_INT freeVoices;
   3855     EAS_INT activeVoices;
   3856     EAS_INT playingVoices;
   3857     EAS_INT stolenVoices;
   3858     EAS_INT releasingVoices;
   3859     EAS_INT mutingVoices;
   3860     EAS_INT poolCount[MAX_VIRTUAL_SYNTHESIZERS][NUM_SYNTH_CHANNELS];
   3861     EAS_INT vSynthNum;
   3862     EAS_RESULT result = EAS_SUCCESS;
   3863 
   3864     /* initialize counts */
   3865     EAS_HWMemSet(poolCount, 0, sizeof(poolCount));
   3866     freeVoices = activeVoices = playingVoices = stolenVoices = releasingVoices = mutingVoices = 0;
   3867 
   3868     /* iterate through all voices */
   3869     for (i = 0; i < MAX_SYNTH_VOICES; i++)
   3870     {
   3871         pVoice = &pEASData->pVoiceMgr->voices[i];
   3872         if (pVoice->voiceState != eVoiceStateFree)
   3873         {
   3874             vSynthNum = GET_VSYNTH(pVoice->channel);
   3875             if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS)
   3876             {
   3877                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ }
   3878                 result = EAS_FAILURE;
   3879                 continue;
   3880             }
   3881             pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum];
   3882 
   3883             switch (pVoice->voiceState)
   3884             {
   3885                 case eVoiceStateMuting:
   3886                     activeVoices++;
   3887                     mutingVoices++;
   3888                     break;
   3889 
   3890                 case eVoiceStateStolen:
   3891                     vSynthNum = GET_VSYNTH(pVoice->nextChannel);
   3892                     if (vSynthNum >= MAX_VIRTUAL_SYNTHESIZERS)
   3893                     {
   3894                         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Voice %d has invalid virtual synth number %d\n", i, vSynthNum); */ }
   3895                         result = EAS_FAILURE;
   3896                         continue;
   3897                     }
   3898                     pSynth = pEASData->pVoiceMgr->pSynth[vSynthNum];
   3899                     activeVoices++;
   3900                     stolenVoices++;
   3901                     poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->nextChannel)].pool]++;
   3902                     break;
   3903 
   3904                 case eVoiceStateStart:
   3905                 case eVoiceStatePlay:
   3906                     activeVoices++;
   3907                     playingVoices++;
   3908                     poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++;
   3909                     break;
   3910 
   3911                 case eVoiceStateRelease:
   3912                     activeVoices++;
   3913                     releasingVoices++;
   3914                     poolCount[vSynthNum][pSynth->channels[GET_CHANNEL(pVoice->channel)].pool]++;
   3915                     break;
   3916 
   3917                 default:
   3918                     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck : voice %d in invalid state\n", i); */ }
   3919                     result = EAS_FAILURE;
   3920                     break;
   3921             }
   3922         }
   3923 
   3924         /* count free voices */
   3925         else
   3926             freeVoices++;
   3927     }
   3928 
   3929     /* dump state info */
   3930     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d free\n", freeVoices); */ }
   3931     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d active\n", activeVoices); */ }
   3932     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d playing\n", playingVoices); */ }
   3933     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d releasing\n", releasingVoices); */ }
   3934     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d muting\n", mutingVoices); */ }
   3935     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "%d stolen\n", stolenVoices); */ }
   3936 
   3937     if (pEASData->pVoiceMgr->activeVoices != activeVoices)
   3938     {
   3939         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Active voice mismatch was %d should be %d\n",
   3940             pEASData->pVoiceMgr->activeVoices, activeVoices); */ }
   3941         result = EAS_FAILURE;
   3942     }
   3943 
   3944     /* check virtual synth status */
   3945     for (i = 0; i < MAX_VIRTUAL_SYNTHESIZERS; i++)
   3946     {
   3947         if (pEASData->pVoiceMgr->pSynth[i] == NULL)
   3948             continue;
   3949 
   3950         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Synth %d numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ }
   3951         if (pEASData->pVoiceMgr->pSynth[i]->numActiveVoices > MAX_SYNTH_VOICES)
   3952         {
   3953             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMSanityCheck: Synth %d illegal count for numActiveVoices: %d\n", i, pEASData->pVoiceMgr->pSynth[i]->numActiveVoices); */ }
   3954             result = EAS_FAILURE;
   3955         }
   3956         for (j = 0; j < NUM_SYNTH_CHANNELS; j++)
   3957         {
   3958             if (poolCount[i][j] != pEASData->pVoiceMgr->pSynth[i]->poolCount[j])
   3959             {
   3960                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Pool count mismatch synth %d pool %d, was %d, should be %d\n",
   3961                     i, j, pEASData->pVoiceMgr->pSynth[i]->poolCount[j], poolCount[i][j]); */ }
   3962                 result = EAS_FAILURE;
   3963             }
   3964         }
   3965     }
   3966 
   3967     return result;
   3968 }
   3969 #endif
   3970 
   3971 
   3972