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