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, ®ionIndex) != 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, ®ionIndex) != 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, ®ionIndex) != EAS_SUCCESS)
2749
2750 /* switch to program 0 in the default bank */
2751 {
2752 if (VMFindProgram(pSynth->pEAS, bank, 0, ®ionIndex) != 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