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