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