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