midi.cpp
1 //------------------------------------------------------------------------- 2 /* 3 Copyright (C) 2010-2019 EDuke32 developers and contributors 4 Copyright (C) 2019 Nuke.YKT 5 6 This file is part of NBlood. 7 8 NBlood is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License version 2 10 as published by the Free Software Foundation. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 16 See the GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 */ 22 //------------------------------------------------------------------------- 23 24 /********************************************************************** 25 module: MIDI.C 26 27 author: James R. Dose 28 date: May 25, 1994 29 30 Midi song file playback routines. 31 32 (c) Copyright 1994 James R. Dose. All Rights Reserved. 33 **********************************************************************/ 34 35 #include "midi.h" 36 37 #include "_midi.h" 38 #include "compat.h" 39 #include "drivers.h" 40 #include "music.h" 41 #include "pragmas.h" 42 #include "sndcards.h" 43 44 extern int MV_MixRate; 45 extern int ASS_MIDISoundDriver; 46 47 int MIDI_GetDevice() 48 { 49 return ASS_MIDISoundDriver; 50 } 51 52 static const int _MIDI_CommandLengths[NUM_MIDI_CHANNELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 }; 53 54 static track * _MIDI_TrackPtr; 55 static int _MIDI_TrackMemSize; 56 static int _MIDI_NumTracks; 57 58 static int _MIDI_SongActive; 59 static int _MIDI_SongLoaded; 60 static int _MIDI_Loop; 61 62 static int _MIDI_Division; 63 static int _MIDI_Tick; 64 static int _MIDI_Beat = 1; 65 static int _MIDI_Measure = 1; 66 static uint32_t _MIDI_Time; 67 static int _MIDI_BeatsPerMeasure; 68 static int _MIDI_TicksPerBeat; 69 static int _MIDI_TimeBase; 70 static int _MIDI_FPSecondsPerTick; 71 static uint32_t _MIDI_TotalTime; 72 static int _MIDI_TotalTicks; 73 static int _MIDI_TotalBeats; 74 static int _MIDI_TotalMeasures; 75 76 uint32_t _MIDI_PositionInTicks; 77 uint32_t _MIDI_GlobalPositionInTicks; 78 79 static int _MIDI_Context; 80 81 static int _MIDI_ActiveTracks; 82 static int _MIDI_TotalVolume = MIDI_MaxVolume; 83 84 static int _MIDI_ChannelVolume[NUM_MIDI_CHANNELS]; 85 86 static midifuncs *_MIDI_Funcs; 87 88 static int _MIDI_Reset; 89 90 int MV_MIDIRenderTempo = -1; 91 int MV_MIDIRenderTimer; 92 93 static char *_MIDI_SongPtr; 94 95 static void _MIDI_SetChannelVolume(int channel, int volume); 96 97 void MIDI_Restart(void) 98 { 99 if (_MIDI_SongLoaded) 100 { 101 songposition pos; 102 MIDI_GetSongPosition(&pos); 103 MIDI_PlaySong(_MIDI_SongPtr, _MIDI_Loop); 104 MIDI_SetSongPosition(pos.measure, pos.beat, pos.tick); 105 } 106 } 107 108 static int _MIDI_ReadNumber(void *from, size_t size) 109 { 110 if (size > 4) 111 size = 4; 112 113 char *FromPtr = (char *)from; 114 int value = 0; 115 116 while (size--) 117 { 118 value <<= 8; 119 value += *FromPtr++; 120 } 121 122 return value; 123 } 124 125 static int _MIDI_ReadDelta(track *ptr) 126 { 127 int value; 128 129 GET_NEXT_EVENT(ptr, value); 130 131 if (value & 0x80) 132 { 133 value &= 0x7f; 134 char c; 135 136 do 137 { 138 GET_NEXT_EVENT(ptr, c); 139 value = (value << 7) + (c & 0x7f); 140 } 141 while (c & 0x80); 142 } 143 144 return value; 145 } 146 147 static void _MIDI_ResetTracks(void) 148 { 149 _MIDI_Tick = 0; 150 _MIDI_Beat = 1; 151 _MIDI_Measure = 1; 152 _MIDI_Time = 0; 153 _MIDI_BeatsPerMeasure = 4; 154 _MIDI_TicksPerBeat = _MIDI_Division; 155 _MIDI_TimeBase = 4; 156 _MIDI_PositionInTicks = 0; 157 _MIDI_ActiveTracks = 0; 158 _MIDI_Context = 0; 159 160 track *ptr = _MIDI_TrackPtr; 161 for (bssize_t i = 0; i < _MIDI_NumTracks; ++i) 162 { 163 ptr->pos = ptr->start; 164 ptr->delay = _MIDI_ReadDelta(ptr); 165 ptr->active = ptr->EMIDI_IncludeTrack; 166 ptr->RunningStatus = 0; 167 ptr->currentcontext = 0; 168 ptr->context[0].loopstart = ptr->start; 169 ptr->context[0].loopcount = 0; 170 171 if (ptr->active) 172 _MIDI_ActiveTracks++; 173 174 ptr++; 175 } 176 } 177 178 static void _MIDI_AdvanceTick(void) 179 { 180 _MIDI_PositionInTicks++; 181 _MIDI_Time += _MIDI_FPSecondsPerTick; 182 183 _MIDI_Tick++; 184 while (_MIDI_Tick > _MIDI_TicksPerBeat) 185 { 186 _MIDI_Tick -= _MIDI_TicksPerBeat; 187 _MIDI_Beat++; 188 } 189 while (_MIDI_Beat > _MIDI_BeatsPerMeasure) 190 { 191 _MIDI_Beat -= _MIDI_BeatsPerMeasure; 192 _MIDI_Measure++; 193 } 194 } 195 196 static void _MIDI_SysEx(track *Track) 197 { 198 int length = _MIDI_ReadDelta(Track); 199 Track->pos += length; 200 } 201 202 203 static void _MIDI_MetaEvent(track *Track) 204 { 205 int command; 206 int length; 207 208 GET_NEXT_EVENT(Track, command); 209 GET_NEXT_EVENT(Track, length); 210 211 switch (command) 212 { 213 case MIDI_END_OF_TRACK: 214 Track->active = FALSE; 215 216 _MIDI_ActiveTracks--; 217 break; 218 219 case MIDI_TEMPO_CHANGE: 220 { 221 int tempo = tabledivide32_noinline(60000000L, _MIDI_ReadNumber(Track->pos, 3)); 222 MIDI_SetTempo(tempo); 223 break; 224 } 225 226 case MIDI_TIME_SIGNATURE: 227 { 228 if ((_MIDI_Tick > 0) || (_MIDI_Beat > 1)) 229 _MIDI_Measure++; 230 231 _MIDI_Tick = 0; 232 _MIDI_Beat = 1; 233 _MIDI_TimeBase = 1; 234 _MIDI_BeatsPerMeasure = (int)*Track->pos; 235 int denominator = (int) * (Track->pos + 1); 236 237 while (denominator > 0) 238 { 239 _MIDI_TimeBase += _MIDI_TimeBase; 240 denominator--; 241 } 242 243 _MIDI_TicksPerBeat = tabledivide32_noinline(_MIDI_Division * 4, _MIDI_TimeBase); 244 break; 245 } 246 } 247 248 Track->pos += length; 249 } 250 251 static int _MIDI_InterpretControllerInfo(track *Track, int TimeSet, int channel, int c1, int c2) 252 { 253 track *trackptr; 254 int tracknum; 255 int loopcount; 256 257 switch (c1) 258 { 259 case MIDI_MONO_MODE_ON : 260 Track->pos++; 261 break; 262 263 case MIDI_VOLUME : 264 if (!Track->EMIDI_VolumeChange) 265 _MIDI_SetChannelVolume(channel, c2); 266 break; 267 268 case EMIDI_INCLUDE_TRACK : 269 case EMIDI_EXCLUDE_TRACK : 270 break; 271 272 case EMIDI_PROGRAM_CHANGE : 273 if (Track->EMIDI_ProgramChange) 274 _MIDI_Funcs->ProgramChange(channel, c2 & 0x7f); 275 break; 276 277 case EMIDI_VOLUME_CHANGE : 278 if (Track->EMIDI_VolumeChange) 279 _MIDI_SetChannelVolume(channel, c2); 280 break; 281 282 case EMIDI_CONTEXT_START : 283 break; 284 285 case EMIDI_CONTEXT_END : 286 if ((Track->currentcontext == _MIDI_Context) || (_MIDI_Context < 0) || 287 (Track->context[_MIDI_Context].pos == nullptr)) 288 break; 289 290 Track->currentcontext = _MIDI_Context; 291 Track->context[0].loopstart = Track->context[_MIDI_Context].loopstart; 292 Track->context[0].loopcount = Track->context[_MIDI_Context].loopcount; 293 Track->pos = Track->context[_MIDI_Context].pos; 294 Track->RunningStatus = Track->context[_MIDI_Context].RunningStatus; 295 296 if (TimeSet) 297 { 298 break; 299 } 300 301 _MIDI_Time = Track->context[_MIDI_Context].time; 302 _MIDI_FPSecondsPerTick = Track->context[_MIDI_Context].FPSecondsPerTick; 303 _MIDI_Tick = Track->context[_MIDI_Context].tick; 304 _MIDI_Beat = Track->context[_MIDI_Context].beat; 305 _MIDI_Measure = Track->context[_MIDI_Context].measure; 306 _MIDI_BeatsPerMeasure = Track->context[_MIDI_Context].BeatsPerMeasure; 307 _MIDI_TicksPerBeat = Track->context[_MIDI_Context].TicksPerBeat; 308 _MIDI_TimeBase = Track->context[_MIDI_Context].TimeBase; 309 TimeSet = TRUE; 310 break; 311 312 case EMIDI_LOOP_START : 313 case EMIDI_SONG_LOOP_START : 314 loopcount = (c2 == 0) ? EMIDI_INFINITE : c2; 315 316 if (c1 == EMIDI_SONG_LOOP_START) 317 { 318 trackptr = _MIDI_TrackPtr; 319 tracknum = _MIDI_NumTracks; 320 } 321 else 322 { 323 trackptr = Track; 324 tracknum = 1; 325 } 326 327 while (tracknum > 0) 328 { 329 trackptr->context[0].loopcount = loopcount; 330 trackptr->context[0].pos = trackptr->pos; 331 trackptr->context[0].loopstart = trackptr->pos; 332 trackptr->context[0].RunningStatus = trackptr->RunningStatus; 333 trackptr->context[0].active = trackptr->active; 334 trackptr->context[0].delay = trackptr->delay; 335 trackptr->context[0].time = _MIDI_Time; 336 trackptr->context[0].FPSecondsPerTick = _MIDI_FPSecondsPerTick; 337 trackptr->context[0].tick = _MIDI_Tick; 338 trackptr->context[0].beat = _MIDI_Beat; 339 trackptr->context[0].measure = _MIDI_Measure; 340 trackptr->context[0].BeatsPerMeasure = _MIDI_BeatsPerMeasure; 341 trackptr->context[0].TicksPerBeat = _MIDI_TicksPerBeat; 342 trackptr->context[0].TimeBase = _MIDI_TimeBase; 343 trackptr++; 344 tracknum--; 345 } 346 break; 347 348 case EMIDI_LOOP_END : 349 case EMIDI_SONG_LOOP_END : 350 if ((c2 != EMIDI_END_LOOP_VALUE) || (Track->context[0].loopstart == nullptr) || (Track->context[0].loopcount == 0)) 351 break; 352 353 if (c1 == EMIDI_SONG_LOOP_END) 354 { 355 trackptr = _MIDI_TrackPtr; 356 tracknum = _MIDI_NumTracks; 357 _MIDI_ActiveTracks = 0; 358 } 359 else 360 { 361 trackptr = Track; 362 tracknum = 1; 363 _MIDI_ActiveTracks--; 364 } 365 366 while (tracknum > 0) 367 { 368 if (trackptr->context[0].loopcount != EMIDI_INFINITE) 369 { 370 trackptr->context[0].loopcount--; 371 } 372 373 trackptr->pos = trackptr->context[0].loopstart; 374 trackptr->RunningStatus = trackptr->context[0].RunningStatus; 375 trackptr->delay = trackptr->context[0].delay; 376 trackptr->active = trackptr->context[0].active; 377 if (trackptr->active) 378 { 379 _MIDI_ActiveTracks++; 380 } 381 382 if (!TimeSet) 383 { 384 _MIDI_Time = trackptr->context[0].time; 385 _MIDI_FPSecondsPerTick = trackptr->context[0].FPSecondsPerTick; 386 _MIDI_Tick = trackptr->context[0].tick; 387 _MIDI_Beat = trackptr->context[0].beat; 388 _MIDI_Measure = trackptr->context[0].measure; 389 _MIDI_BeatsPerMeasure = trackptr->context[0].BeatsPerMeasure; 390 _MIDI_TicksPerBeat = trackptr->context[0].TicksPerBeat; 391 _MIDI_TimeBase = trackptr->context[0].TimeBase; 392 TimeSet = TRUE; 393 } 394 395 trackptr++; 396 tracknum--; 397 } 398 break; 399 400 default : 401 if (_MIDI_Funcs->ControlChange) 402 _MIDI_Funcs->ControlChange(channel, c1, c2); 403 } 404 405 return TimeSet; 406 } 407 408 void MIDI_ServiceRoutine(void) 409 { 410 if (!_MIDI_SongActive) 411 return; 412 413 track *Track = _MIDI_TrackPtr; 414 int tracknum = 0; 415 int TimeSet = FALSE; 416 int c1 = 0; 417 int c2 = 0; 418 419 while (tracknum < _MIDI_NumTracks) 420 { 421 while ((Track->active) && (Track->delay == 0)) 422 { 423 int event; 424 GET_NEXT_EVENT(Track, event); 425 426 if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL) 427 { 428 switch (event) 429 { 430 case MIDI_SYSEX: 431 case MIDI_SYSEX_CONTINUE: _MIDI_SysEx(Track); break; 432 case MIDI_META_EVENT: _MIDI_MetaEvent(Track); break; 433 } 434 435 if (Track->active) 436 Track->delay = _MIDI_ReadDelta(Track); 437 continue; 438 } 439 440 if (event & MIDI_RUNNING_STATUS) 441 Track->RunningStatus = event; 442 else 443 { 444 event = Track->RunningStatus; 445 Track->pos--; 446 } 447 448 int const channel = GET_MIDI_CHANNEL(event); 449 int const command = GET_MIDI_COMMAND(event); 450 451 if (_MIDI_CommandLengths[command] > 0) 452 { 453 GET_NEXT_EVENT(Track, c1); 454 if (_MIDI_CommandLengths[command] > 1) 455 GET_NEXT_EVENT(Track, c2); 456 } 457 458 switch (command) 459 { 460 case MIDI_NOTE_OFF: 461 if (_MIDI_Funcs->NoteOff) 462 _MIDI_Funcs->NoteOff(channel, c1, c2); 463 break; 464 465 case MIDI_NOTE_ON: 466 if (_MIDI_Funcs->NoteOn) 467 _MIDI_Funcs->NoteOn(channel, c1, c2); 468 break; 469 470 case MIDI_POLY_AFTER_TCH: 471 if (_MIDI_Funcs->PolyAftertouch) 472 _MIDI_Funcs->PolyAftertouch(channel, c1, c2); 473 break; 474 475 case MIDI_CONTROL_CHANGE: 476 TimeSet = _MIDI_InterpretControllerInfo(Track, TimeSet, channel, c1, c2); 477 break; 478 479 case MIDI_PROGRAM_CHANGE: 480 if ((_MIDI_Funcs->ProgramChange) && (!Track->EMIDI_ProgramChange)) 481 _MIDI_Funcs->ProgramChange(channel, c1 & 0x7f); 482 break; 483 484 case MIDI_AFTER_TOUCH: 485 if (_MIDI_Funcs->ChannelAftertouch) 486 _MIDI_Funcs->ChannelAftertouch(channel, c1); 487 break; 488 489 case MIDI_PITCH_BEND: 490 if (_MIDI_Funcs->PitchBend) 491 _MIDI_Funcs->PitchBend(channel, c1, c2); 492 break; 493 494 default: break; 495 } 496 497 Track->delay = _MIDI_ReadDelta(Track); 498 } 499 500 Track->delay--; 501 Track++; 502 tracknum++; 503 504 if (_MIDI_ActiveTracks == 0) 505 { 506 _MIDI_ResetTracks(); 507 if (_MIDI_Loop) 508 { 509 tracknum = 0; 510 Track = _MIDI_TrackPtr; 511 } 512 else 513 { 514 _MIDI_SongActive = FALSE; 515 break; 516 } 517 } 518 } 519 520 _MIDI_AdvanceTick(); 521 _MIDI_GlobalPositionInTicks++; 522 } 523 524 static int _MIDI_SendControlChange(int channel, int c1, int c2) 525 { 526 if (_MIDI_Funcs == nullptr || _MIDI_Funcs->ControlChange == nullptr) 527 return MIDI_Error; 528 529 _MIDI_Funcs->ControlChange(channel, c1, c2); 530 531 return MIDI_Ok; 532 } 533 534 static int _MIDI_SendProgramChange(int channel, int c1) 535 { 536 if (_MIDI_Funcs == nullptr || _MIDI_Funcs->ProgramChange == nullptr) 537 return MIDI_Error; 538 539 _MIDI_Funcs->ProgramChange(channel, c1); 540 541 return MIDI_Ok; 542 } 543 544 int MIDI_AllNotesOff(void) 545 { 546 SoundDriver_MIDI_Lock(); 547 548 for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++) 549 { 550 _MIDI_SendControlChange(channel, MIDI_HOLD1, 0); 551 _MIDI_SendControlChange(channel, MIDI_SOSTENUTO, 0); 552 _MIDI_SendControlChange(channel, MIDI_ALL_NOTES_OFF, 0); 553 _MIDI_SendControlChange(channel, MIDI_ALL_SOUNDS_OFF, 0); 554 } 555 556 SoundDriver_MIDI_Unlock(); 557 558 return MIDI_Ok; 559 } 560 561 static void _MIDI_SetChannelVolume(int channel, int volume) 562 { 563 _MIDI_ChannelVolume[channel] = volume; 564 565 if (_MIDI_Funcs == nullptr || _MIDI_Funcs->ControlChange == nullptr) 566 return; 567 568 if (_MIDI_Funcs->SetVolume == nullptr) 569 { 570 volume *= _MIDI_TotalVolume; 571 volume = tabledivide32_noinline(volume, MIDI_MaxVolume); 572 } 573 574 _MIDI_Funcs->ControlChange(channel, MIDI_VOLUME, volume); 575 } 576 577 static void _MIDI_SendChannelVolumes(void) 578 { 579 for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++) 580 _MIDI_SetChannelVolume(channel, _MIDI_ChannelVolume[channel]); 581 } 582 583 int MIDI_Reset(void) 584 { 585 MIDI_AllNotesOff(); 586 587 SoundDriver_MIDI_Lock(); 588 589 for (bssize_t channel = 0; channel < NUM_MIDI_CHANNELS; channel++) 590 { 591 _MIDI_SendControlChange(channel, MIDI_RESET_ALL_CONTROLLERS, 0); 592 _MIDI_SendControlChange(channel, MIDI_RPN_MSB, MIDI_PITCHBEND_MSB); 593 _MIDI_SendControlChange(channel, MIDI_RPN_LSB, MIDI_PITCHBEND_LSB); 594 _MIDI_SendControlChange(channel, MIDI_DATAENTRY_MSB, 2); /* Pitch Bend Sensitivity MSB */ 595 _MIDI_SendControlChange(channel, MIDI_DATAENTRY_LSB, 0); /* Pitch Bend Sensitivity LSB */ 596 _MIDI_ChannelVolume[channel] = GENMIDI_DefaultVolume; 597 _MIDI_SendControlChange(channel, MIDI_PAN, 64); // begin TURRICAN's recommendation 598 _MIDI_SendControlChange(channel, MIDI_REVERB, 40); 599 _MIDI_SendControlChange(channel, MIDI_CHORUS, 0); 600 _MIDI_SendControlChange(channel, MIDI_BANK_SELECT_MSB, 0); 601 _MIDI_SendControlChange(channel, MIDI_BANK_SELECT_LSB, 0); 602 _MIDI_SendProgramChange(channel, 0); // end TURRICAN's recommendation 603 } 604 605 _MIDI_SendChannelVolumes(); 606 607 SoundDriver_MIDI_Unlock(); 608 609 _MIDI_Reset = TRUE; 610 611 return MIDI_Ok; 612 } 613 614 615 int MIDI_SetVolume(int volume) 616 { 617 if (_MIDI_Funcs == nullptr) 618 return MIDI_NullMidiModule; 619 620 volume = min(MIDI_MaxVolume, volume); 621 volume = max(0, volume); 622 623 _MIDI_TotalVolume = volume; 624 625 SoundDriver_MIDI_Lock(); 626 627 if (_MIDI_Funcs->SetVolume) 628 _MIDI_Funcs->SetVolume(volume); 629 else 630 _MIDI_SendChannelVolumes(); 631 632 SoundDriver_MIDI_Unlock(); 633 634 return MIDI_Ok; 635 } 636 637 638 int MIDI_GetVolume(void) 639 { 640 if (_MIDI_Funcs == nullptr) 641 return MIDI_NullMidiModule; 642 643 SoundDriver_MIDI_Lock(); 644 int volume = (_MIDI_Funcs->GetVolume) ? _MIDI_Funcs->GetVolume() : _MIDI_TotalVolume; 645 SoundDriver_MIDI_Unlock(); 646 647 return volume; 648 } 649 650 void MIDI_SetLoopFlag(int loopflag) { _MIDI_Loop = loopflag; } 651 652 void MIDI_ContinueSong(void) 653 { 654 if (!_MIDI_SongLoaded) 655 return; 656 657 _MIDI_SongActive = TRUE; 658 } 659 660 void MIDI_PauseSong(void) 661 { 662 if (!_MIDI_SongLoaded) 663 return; 664 665 _MIDI_SongActive = FALSE; 666 MIDI_AllNotesOff(); 667 } 668 669 void MIDI_SetMidiFuncs(midifuncs *funcs) { _MIDI_Funcs = funcs; } 670 671 void MIDI_StopSong(void) 672 { 673 if (!_MIDI_SongLoaded) 674 return; 675 676 SoundDriver_MIDI_HaltPlayback(); 677 678 _MIDI_SongActive = FALSE; 679 _MIDI_SongLoaded = FALSE; 680 681 MIDI_Reset(); 682 _MIDI_ResetTracks(); 683 684 DO_FREE_AND_NULL(_MIDI_TrackPtr); 685 686 _MIDI_NumTracks = 0; 687 _MIDI_TrackMemSize = 0; 688 689 _MIDI_TotalTime = 0; 690 _MIDI_TotalTicks = 0; 691 _MIDI_TotalBeats = 0; 692 _MIDI_TotalMeasures = 0; 693 } 694 695 static void _MIDI_InitEMIDI(void); 696 697 int MIDI_PlaySong(char *song, int loopflag) 698 { 699 if (_MIDI_Funcs == nullptr) 700 return MIDI_NullMidiModule; 701 702 if (B_UNBUF32(song) != MIDI_HEADER_SIGNATURE) 703 return MIDI_InvalidMidiFile; 704 705 _MIDI_SongPtr = song; 706 707 song += 4; 708 int const headersize = _MIDI_ReadNumber(song, 4); 709 song += 4; 710 int const format = _MIDI_ReadNumber(song, 2); 711 712 int My_MIDI_NumTracks = _MIDI_ReadNumber(song + 2, 2); 713 int My_MIDI_Division = _MIDI_ReadNumber(song + 4, 2); 714 715 if (My_MIDI_Division < 0) 716 { 717 // If a SMPTE time division is given, just set to 96 so no errors occur 718 My_MIDI_Division = 96; 719 } 720 721 if (format > MAX_FORMAT) 722 return MIDI_UnknownMidiFormat; 723 724 char *ptr = song + headersize; 725 726 if (My_MIDI_NumTracks == 0) 727 return MIDI_NoTracks; 728 729 int My_MIDI_TrackMemSize = My_MIDI_NumTracks * sizeof(track); 730 track * My_MIDI_TrackPtr = (track *)Xmalloc(My_MIDI_TrackMemSize); 731 732 auto CurrentTrack = My_MIDI_TrackPtr; 733 int numtracks = My_MIDI_NumTracks; 734 735 while (numtracks--) 736 { 737 if (B_UNBUF32(ptr) != MIDI_TRACK_SIGNATURE) 738 { 739 DO_FREE_AND_NULL(My_MIDI_TrackPtr); 740 741 My_MIDI_TrackMemSize = 0; 742 743 return MIDI_InvalidTrack; 744 } 745 746 int tracklength = _MIDI_ReadNumber(ptr + 4, 4); 747 ptr += 8; 748 CurrentTrack->start = ptr; 749 CurrentTrack->EMIDI_IncludeTrack = FALSE; 750 ptr += tracklength; 751 CurrentTrack++; 752 } 753 754 // at this point we know song load is successful 755 756 if (_MIDI_SongLoaded) 757 MIDI_StopSong(); 758 759 _MIDI_Loop = loopflag; 760 _MIDI_NumTracks = My_MIDI_NumTracks; 761 _MIDI_Division = My_MIDI_Division; 762 _MIDI_TrackMemSize = My_MIDI_TrackMemSize; 763 _MIDI_TrackPtr = My_MIDI_TrackPtr; 764 765 _MIDI_InitEMIDI(); 766 _MIDI_ResetTracks(); 767 768 if (!_MIDI_Reset) 769 MIDI_Reset(); 770 771 _MIDI_Reset = FALSE; 772 773 // this can either stay like this, or I can add another field to the MIDI driver spec that holds the service callback 774 if (SoundDriver_MIDI_StartPlayback() != MIDI_Ok) 775 return MIDI_DriverError; 776 777 MIDI_SetTempo(120); 778 779 _MIDI_SongLoaded = TRUE; 780 _MIDI_SongActive = TRUE; 781 782 return MIDI_Ok; 783 } 784 785 void MIDI_SetTempo(int tempo) 786 { 787 SoundDriver_MIDI_SetTempo(tempo, _MIDI_Division); 788 int const tickspersecond = tempo * _MIDI_Division / 60; 789 _MIDI_FPSecondsPerTick = tabledivide32_noinline(1 << TIME_PRECISION, tickspersecond); 790 } 791 792 static int _MIDI_ProcessNextTick(void) 793 { 794 if (_MIDI_TrackPtr == nullptr) 795 return 0; 796 797 int TimeSet = FALSE; 798 int tracknum = 0; 799 800 track *Track = _MIDI_TrackPtr; 801 802 while (tracknum < _MIDI_NumTracks) 803 { 804 while ((Track->active) && (Track->delay == 0)) 805 { 806 int event; 807 808 GET_NEXT_EVENT(Track, event); 809 810 if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL) 811 { 812 switch (event) 813 { 814 case MIDI_SYSEX: 815 case MIDI_SYSEX_CONTINUE: 816 _MIDI_SysEx(Track); 817 break; 818 819 case MIDI_META_EVENT: 820 _MIDI_MetaEvent(Track); 821 break; 822 } 823 824 if (Track->active) 825 Track->delay = _MIDI_ReadDelta(Track); 826 827 continue; 828 } 829 830 if (event & MIDI_RUNNING_STATUS) 831 Track->RunningStatus = event; 832 else 833 { 834 event = Track->RunningStatus; 835 Track->pos--; 836 } 837 838 int channel = GET_MIDI_CHANNEL(event); 839 int command = GET_MIDI_COMMAND(event); 840 841 int c1 = 0; 842 int c2 = 0; 843 844 if (_MIDI_CommandLengths[command] > 0) 845 { 846 GET_NEXT_EVENT(Track, c1); 847 if (_MIDI_CommandLengths[command] > 1) 848 GET_NEXT_EVENT(Track, c2); 849 } 850 851 switch (command) 852 { 853 case MIDI_NOTE_OFF: 854 break; 855 856 case MIDI_NOTE_ON: 857 break; 858 859 case MIDI_POLY_AFTER_TCH: 860 if (_MIDI_Funcs->PolyAftertouch) 861 _MIDI_Funcs->PolyAftertouch(channel, c1, c2); 862 break; 863 864 case MIDI_CONTROL_CHANGE: 865 TimeSet = _MIDI_InterpretControllerInfo(Track, TimeSet, channel, c1, c2); 866 break; 867 868 case MIDI_PROGRAM_CHANGE: 869 if ((_MIDI_Funcs->ProgramChange) && (!Track->EMIDI_ProgramChange)) 870 _MIDI_Funcs->ProgramChange(channel, c1); 871 break; 872 873 case MIDI_AFTER_TOUCH: 874 if (_MIDI_Funcs->ChannelAftertouch) 875 _MIDI_Funcs->ChannelAftertouch(channel, c1); 876 break; 877 878 case MIDI_PITCH_BEND: 879 if (_MIDI_Funcs->PitchBend) 880 _MIDI_Funcs->PitchBend(channel, c1, c2); 881 break; 882 883 default: 884 break; 885 } 886 887 Track->delay = _MIDI_ReadDelta(Track); 888 } 889 890 Track->delay--; 891 Track++; 892 tracknum++; 893 894 if (_MIDI_ActiveTracks == 0) 895 break; 896 } 897 898 _MIDI_AdvanceTick(); 899 900 return TimeSet; 901 } 902 903 void MIDI_SetSongPosition(int measure, int beat, int tick) 904 { 905 if (!_MIDI_SongLoaded) 906 return; 907 908 MIDI_PauseSong(); 909 910 int32_t pos = RELATIVE_BEAT(measure, beat, tick); 911 912 if (pos < RELATIVE_BEAT(_MIDI_Measure, _MIDI_Beat, _MIDI_Tick)) 913 { 914 SoundDriver_MIDI_Lock(); 915 _MIDI_ResetTracks(); 916 SoundDriver_MIDI_Unlock(); 917 918 MIDI_Reset(); 919 } 920 921 SoundDriver_MIDI_Lock(); 922 while (RELATIVE_BEAT(_MIDI_Measure, _MIDI_Beat, _MIDI_Tick) < pos) 923 { 924 if (_MIDI_ProcessNextTick()) 925 break; 926 927 if (_MIDI_ActiveTracks == 0) 928 { 929 _MIDI_ResetTracks(); 930 if (!_MIDI_Loop) 931 { 932 SoundDriver_MIDI_Unlock(); 933 return; 934 } 935 break; 936 } 937 } 938 SoundDriver_MIDI_Unlock(); 939 940 MIDI_SetVolume(_MIDI_TotalVolume); 941 MIDI_ContinueSong(); 942 } 943 944 void MIDI_GetSongPosition(songposition *pos) 945 { 946 uint32_t mil = (_MIDI_Time & ((1 << TIME_PRECISION) - 1)) * 1000; 947 uint32_t sec = _MIDI_Time >> TIME_PRECISION; 948 pos->milliseconds = (mil >> TIME_PRECISION) + (sec * 1000); 949 pos->tickposition = _MIDI_PositionInTicks; 950 pos->measure = _MIDI_Measure; 951 pos->beat = _MIDI_Beat; 952 pos->tick = _MIDI_Tick; 953 } 954 955 static void _MIDI_InitEMIDI(void) 956 { 957 int const type = (ASS_EMIDICard != -1) ? ASS_EMIDICard : SoundDriver_MIDI_GetCardType(); 958 959 _MIDI_ResetTracks(); 960 961 _MIDI_TotalTime = 0; 962 _MIDI_TotalTicks = 0; 963 _MIDI_TotalBeats = 0; 964 _MIDI_TotalMeasures = 0; 965 966 track *Track = _MIDI_TrackPtr; 967 int tracknum = 0; 968 969 while ((tracknum < _MIDI_NumTracks) && (Track != nullptr)) 970 { 971 _MIDI_Tick = 0; 972 _MIDI_Beat = 1; 973 _MIDI_Measure = 1; 974 _MIDI_Time = 0; 975 _MIDI_BeatsPerMeasure = 4; 976 _MIDI_TicksPerBeat = _MIDI_Division; 977 _MIDI_TimeBase = 4; 978 979 _MIDI_PositionInTicks = 0; 980 _MIDI_ActiveTracks = 0; 981 _MIDI_Context = -1; 982 983 Track->RunningStatus = 0; 984 Track->active = TRUE; 985 986 Track->EMIDI_ProgramChange = FALSE; 987 Track->EMIDI_VolumeChange = FALSE; 988 Track->EMIDI_IncludeTrack = TRUE; 989 990 memset(Track->context, 0, sizeof(Track->context)); 991 992 while (Track->delay > 0) 993 { 994 _MIDI_AdvanceTick(); 995 Track->delay--; 996 } 997 998 int IncludeFound = FALSE; 999 1000 while (Track->active) 1001 { 1002 int event; 1003 1004 GET_NEXT_EVENT(Track, event); 1005 1006 if (GET_MIDI_COMMAND(event) == MIDI_SPECIAL) 1007 { 1008 switch (event) 1009 { 1010 case MIDI_SYSEX: 1011 case MIDI_SYSEX_CONTINUE: _MIDI_SysEx(Track); break; 1012 case MIDI_META_EVENT: _MIDI_MetaEvent(Track); break; 1013 } 1014 1015 if (Track->active) 1016 { 1017 Track->delay = _MIDI_ReadDelta(Track); 1018 while (Track->delay > 0) 1019 { 1020 _MIDI_AdvanceTick(); 1021 Track->delay--; 1022 } 1023 } 1024 1025 continue; 1026 } 1027 1028 if (event & MIDI_RUNNING_STATUS) 1029 Track->RunningStatus = event; 1030 else 1031 { 1032 event = Track->RunningStatus; 1033 Track->pos--; 1034 } 1035 1036 // channel = GET_MIDI_CHANNEL(event); 1037 int const command = GET_MIDI_COMMAND(event); 1038 int length = _MIDI_CommandLengths[command]; 1039 1040 if (command == MIDI_CONTROL_CHANGE) 1041 { 1042 if (*Track->pos == MIDI_MONO_MODE_ON) 1043 length++; 1044 1045 int c1, c2; 1046 GET_NEXT_EVENT(Track, c1); 1047 GET_NEXT_EVENT(Track, c2); 1048 length -= 2; 1049 1050 switch (c1) 1051 { 1052 case EMIDI_LOOP_START : 1053 case EMIDI_SONG_LOOP_START : 1054 Track->context[0].loopcount = (c2 == 0) ? EMIDI_INFINITE : c2; 1055 Track->context[0].pos = Track->pos; 1056 Track->context[0].loopstart = Track->pos; 1057 Track->context[0].RunningStatus = Track->RunningStatus; 1058 Track->context[0].time = _MIDI_Time; 1059 Track->context[0].FPSecondsPerTick = _MIDI_FPSecondsPerTick; 1060 Track->context[0].tick = _MIDI_Tick; 1061 Track->context[0].beat = _MIDI_Beat; 1062 Track->context[0].measure = _MIDI_Measure; 1063 Track->context[0].BeatsPerMeasure = _MIDI_BeatsPerMeasure; 1064 Track->context[0].TicksPerBeat = _MIDI_TicksPerBeat; 1065 Track->context[0].TimeBase = _MIDI_TimeBase; 1066 break; 1067 1068 case EMIDI_LOOP_END : 1069 case EMIDI_SONG_LOOP_END : 1070 if (c2 == EMIDI_END_LOOP_VALUE) 1071 { 1072 Track->context[0].loopstart = nullptr; 1073 Track->context[0].loopcount = 0; 1074 } 1075 break; 1076 1077 case EMIDI_INCLUDE_TRACK : 1078 if (EMIDI_AffectsCurrentCard(c2, type)) 1079 { 1080 //printf( "Include track %d on card %d\n", tracknum, c2 ); 1081 IncludeFound = TRUE; 1082 Track->EMIDI_IncludeTrack = TRUE; 1083 } 1084 else if (!IncludeFound) 1085 { 1086 //printf( "Track excluded %d on card %d\n", tracknum, c2 ); 1087 IncludeFound = TRUE; 1088 Track->EMIDI_IncludeTrack = FALSE; 1089 } 1090 break; 1091 1092 case EMIDI_EXCLUDE_TRACK : 1093 if (EMIDI_AffectsCurrentCard(c2, type)) 1094 { 1095 //printf( "Exclude track %d on card %d\n", tracknum, c2 ); 1096 Track->EMIDI_IncludeTrack = FALSE; 1097 } 1098 break; 1099 1100 case EMIDI_PROGRAM_CHANGE : 1101 if (!Track->EMIDI_ProgramChange) 1102 //printf( "Program change on track %d\n", tracknum ); 1103 Track->EMIDI_ProgramChange = TRUE; 1104 break; 1105 1106 case EMIDI_VOLUME_CHANGE : 1107 if (!Track->EMIDI_VolumeChange) 1108 //printf( "Volume change on track %d\n", tracknum ); 1109 Track->EMIDI_VolumeChange = TRUE; 1110 break; 1111 1112 case EMIDI_CONTEXT_START : 1113 if ((c2 > 0) && (c2 < EMIDI_NUM_CONTEXTS)) 1114 { 1115 Track->context[c2].pos = Track->pos; 1116 Track->context[c2].loopstart = Track->context[0].loopstart; 1117 Track->context[c2].loopcount = Track->context[0].loopcount; 1118 Track->context[c2].RunningStatus = Track->RunningStatus; 1119 Track->context[c2].time = _MIDI_Time; 1120 Track->context[c2].FPSecondsPerTick = _MIDI_FPSecondsPerTick; 1121 Track->context[c2].tick = _MIDI_Tick; 1122 Track->context[c2].beat = _MIDI_Beat; 1123 Track->context[c2].measure = _MIDI_Measure; 1124 Track->context[c2].BeatsPerMeasure = _MIDI_BeatsPerMeasure; 1125 Track->context[c2].TicksPerBeat = _MIDI_TicksPerBeat; 1126 Track->context[c2].TimeBase = _MIDI_TimeBase; 1127 } 1128 break; 1129 1130 case EMIDI_CONTEXT_END : 1131 break; 1132 } 1133 } 1134 1135 Track->pos += length; 1136 Track->delay = _MIDI_ReadDelta(Track); 1137 1138 while (Track->delay > 0) 1139 { 1140 _MIDI_AdvanceTick(); 1141 Track->delay--; 1142 } 1143 } 1144 1145 _MIDI_TotalTime = max(_MIDI_TotalTime, _MIDI_Time); 1146 if (RELATIVE_BEAT(_MIDI_Measure, _MIDI_Beat, _MIDI_Tick) > 1147 RELATIVE_BEAT(_MIDI_TotalMeasures, _MIDI_TotalBeats, _MIDI_TotalTicks)) 1148 { 1149 _MIDI_TotalTicks = _MIDI_Tick; 1150 _MIDI_TotalBeats = _MIDI_Beat; 1151 _MIDI_TotalMeasures = _MIDI_Measure; 1152 } 1153 1154 Track++; 1155 tracknum++; 1156 } 1157 1158 _MIDI_ResetTracks(); 1159 }