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;
VMGetLibHandle(EAS_INT libNum)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 */
GetRegionPtr(S_SYNTH * pSynth,EAS_U16 regionIndex)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 */
GetSynthPtr(EAS_INT voiceNum)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 
GetAdjustedVoiceNum(EAS_INT voiceNum)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 
VSynthToChannel(S_SYNTH * pSynth,EAS_U8 channel)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 */
InitVoice(S_SYNTH_VOICE * pVoice)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 */
IncVoicePoolCount(S_VOICE_MGR * pVoiceMgr,S_SYNTH_VOICE * pVoice)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 */
DecVoicePoolCount(S_VOICE_MGR * pVoiceMgr,S_SYNTH_VOICE * pVoice)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 */
VMInitialize(S_EAS_DATA * pEASData)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 */
VMInitMIDI(S_EAS_DATA * pEASData,S_SYNTH ** ppSynth)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 */
VMIncRefCount(S_SYNTH * pSynth)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 */
VMReset(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_BOOL force)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 */
VMInitializeAllChannels(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth)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 */
VMResetControllers(S_SYNTH * pSynth)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 */
VMInitializeAllVoices(S_VOICE_MGR * pVoiceMgr,EAS_INT vSynthNum)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 */
VMMuteVoice(S_VOICE_MGR * pVoiceMgr,EAS_I32 voiceNum)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 */
VMReleaseVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_I32 voiceNum)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 */
VMInitMIPTable(S_SYNTH * pSynth)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 */
VMSetMIPEntry(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel,EAS_U8 priority,EAS_U8 mip)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 */
VMMIPUpdateChannelMuting(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth)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 */
VMUpdateMIPTable(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth)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 */
VMMuteAllVoices(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth)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 */
VMReleaseAllVoices(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth)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 */
VMAllNotesOff(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel)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 */
VMDeferredStopNote(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth)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 */
VMReleaseAllDeferredNoteOffs(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel)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 */
VMCatchNotesForSustainPedal(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel)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 */
VMUpdateAllNotesAge(S_VOICE_MGR * pVoiceMgr,EAS_U16 age)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 */
VMStolenVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_I32 voiceNum,EAS_U8 channel,EAS_U8 note,EAS_U8 velocity,EAS_U16 regionIndex)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 */
VMFreeVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,S_SYNTH_VOICE * pVoice)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 */
VMRetargetStolenVoice(S_VOICE_MGR * pVoiceMgr,EAS_I32 voiceNum)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 */
VMCheckKeyGroup(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U16 keyGroup,EAS_U8 channel)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 */
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)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 */
VMStartVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel,EAS_U8 note,EAS_U8 velocity,EAS_U16 regionIndex)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 */
VMStartNote(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel,EAS_U8 note,EAS_U8 velocity)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 */
VMStopNote(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel,EAS_U8 note,EAS_U8 velocity)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 */
VMFindAvailableVoice(S_VOICE_MGR * pVoiceMgr,EAS_INT * pVoiceNumber,EAS_I32 lowVoice,EAS_I32 highVoice)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 */
VMStealVoice(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_INT * pVoiceNumber,EAS_U8 channel,EAS_U8 note,EAS_I32 lowVoice,EAS_I32 highVoice)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 */
VMChannelPressure(S_SYNTH * pSynth,EAS_U8 channel,EAS_U8 value)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 */
VMPitchBend(S_SYNTH * pSynth,EAS_U8 channel,EAS_U8 nPitchLSB,EAS_U8 nPitchMSB)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 */
VMControlChange(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel,EAS_U8 controller,EAS_U8 value)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 */
VMUpdateRPNStateMachine(S_SYNTH * pSynth,EAS_U8 channel,EAS_U8 controller,EAS_U8 value)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 */
VMUpdateStaticChannelParameters(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth)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 */
VMFindProgram(const S_EAS * pEAS,EAS_U32 bank,EAS_U8 programNum,EAS_U16 * pRegionIndex)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 */
VMFindDLSProgram(const S_DLS * pDLS,EAS_U32 bank,EAS_U8 programNum,EAS_U16 * pRegionIndex)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 */
VMProgramChange(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_U8 channel,EAS_U8 program)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 */
VMAddSamples(S_VOICE_MGR * pVoiceMgr,EAS_I32 * pMixBuffer,EAS_I32 numSamples)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 */
VMRender(S_VOICE_MGR * pVoiceMgr,EAS_I32 numSamples,EAS_I32 * pMixBuffer,EAS_I32 * pVoicesRendered)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 */
VMInitWorkload(S_VOICE_MGR * pVoiceMgr)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 */
VMSetWorkload(S_VOICE_MGR * pVoiceMgr,EAS_I32 maxWorkLoad)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 */
VMCheckWorkload(S_VOICE_MGR * pVoiceMgr)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 */
VMActiveVoices(S_SYNTH * pSynth)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 */
VMSetSynthPolyphony(S_VOICE_MGR * pVoiceMgr,EAS_I32 synth,EAS_I32 polyphonyCount)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 */
VMGetSynthPolyphony(S_VOICE_MGR * pVoiceMgr,EAS_I32 synth,EAS_I32 * pPolyphonyCount)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 */
VMSetPolyphony(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_I32 polyphonyCount)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 */
VMGetPolyphony(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_I32 * pPolyphonyCount)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 */
VMSetPriority(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_I32 priority)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 */
VMGetPriority(S_VOICE_MGR * pVoiceMgr,S_SYNTH * pSynth,EAS_I32 * pPriority)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 */
VMSetVolume(S_SYNTH * pSynth,EAS_U16 masterVolume)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 */
VMSetPitchBendRange(S_SYNTH * pSynth,EAS_INT channel,EAS_I16 pitchBendRange)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 */
VMValidateEASLib(EAS_SNDLIB_HANDLE pEAS)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 */
VMSetGlobalEASLib(S_VOICE_MGR * pVoiceMgr,EAS_SNDLIB_HANDLE pEAS)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 */
VMSetEASLib(S_SYNTH * pSynth,EAS_SNDLIB_HANDLE pEAS)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 */
VMSetGlobalDLSLib(EAS_DATA_HANDLE pEASData,EAS_DLSLIB_HANDLE pDLS)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 */
VMSetDLSLib(S_SYNTH * pSynth,EAS_DLSLIB_HANDLE pDLS)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 */
VMSetTranposition(S_SYNTH * pSynth,EAS_I32 transposition)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 */
VMGetTranposition(S_SYNTH * pSynth,EAS_I32 * pTransposition)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 */
VMGetNoteCount(S_SYNTH * pSynth)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 */
VMMIDIShutdown(S_EAS_DATA * pEASData,S_SYNTH * pSynth)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 */
VMShutdown(S_EAS_DATA * pEASData)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 */
VMRegExtAudioCallback(S_SYNTH * pSynth,EAS_VOID_PTR pInstData,EAS_EXT_PRG_CHG_FUNC cbProgChgFunc,EAS_EXT_EVENT_FUNC cbEventFunc)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 */
VMGetMIDIControllers(S_SYNTH * pSynth,EAS_U8 channel,S_MIDI_CONTROLLERS * pControl)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 */
VMStartFrame(S_EAS_DATA * pEASData)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 */
VMEndFrame(S_EAS_DATA * pEASData)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 */
VMSanityCheck(EAS_DATA_HANDLE pEASData)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