1 /* 2 * Copyright (c) 2002-2004 Matthijs Hollemans 3 * Copyright (c) 2002 Jerome Leveque 4 * Copyright (c) 2002 Paul Stadler 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <File.h> 26 #include <List.h> 27 #include <stdlib.h> 28 #include <string.h> 29 30 #include "MidiDefs.h" 31 #include "MidiStore.h" 32 #include "debug.h" 33 34 //------------------------------------------------------------------------------ 35 36 struct BMidiEvent 37 { 38 BMidiEvent() 39 { 40 byte1 = 0; 41 byte2 = 0; 42 byte3 = 0; 43 data = NULL; 44 length = 0; 45 } 46 47 ~BMidiEvent() 48 { 49 free(data); 50 } 51 52 uint32 time; // either ticks or milliseconds 53 bool ticks; // event is from MIDI file 54 uchar byte1; 55 uchar byte2; 56 uchar byte3; 57 void* data; // sysex data 58 size_t length; // sysex data size 59 int32 tempo; // beats per minute 60 }; 61 62 //------------------------------------------------------------------------------ 63 64 static int compare_events(const void* event1, const void* event2) 65 { 66 BMidiEvent* e1 = *((BMidiEvent**) event1); 67 BMidiEvent* e2 = *((BMidiEvent**) event2); 68 69 return (e1->time - e2->time); 70 } 71 72 //------------------------------------------------------------------------------ 73 74 BMidiStore::BMidiStore() 75 { 76 events = new BList; 77 currentEvent = 0; 78 startTime = 0; 79 needsSorting = false; 80 beatsPerMinute = 60; 81 ticksPerBeat = 240; 82 file = NULL; 83 hookFunc = NULL; 84 looping = false; 85 paused = false; 86 finished = false; 87 instruments = new bool[128]; 88 } 89 90 //------------------------------------------------------------------------------ 91 92 BMidiStore::~BMidiStore() 93 { 94 for (int32 t = 0; t < events->CountItems(); ++t) 95 { 96 delete EventAt(t); 97 } 98 delete events; 99 delete[] instruments; 100 } 101 102 //------------------------------------------------------------------------------ 103 104 void BMidiStore::NoteOff( 105 uchar channel, uchar note, uchar velocity, uint32 time) 106 { 107 BMidiEvent* event = new BMidiEvent; 108 event->time = time; 109 event->ticks = false; 110 event->byte1 = B_NOTE_OFF | (channel - 1); 111 event->byte2 = note; 112 event->byte3 = velocity; 113 AddEvent(event); 114 } 115 116 //------------------------------------------------------------------------------ 117 118 void BMidiStore::NoteOn( 119 uchar channel, uchar note, uchar velocity, uint32 time) 120 { 121 BMidiEvent* event = new BMidiEvent; 122 event->time = time; 123 event->ticks = false; 124 event->byte1 = B_NOTE_ON | (channel - 1); 125 event->byte2 = note; 126 event->byte3 = velocity; 127 AddEvent(event); 128 } 129 130 //------------------------------------------------------------------------------ 131 132 void BMidiStore::KeyPressure( 133 uchar channel, uchar note, uchar pressure, uint32 time) 134 { 135 BMidiEvent* event = new BMidiEvent; 136 event->time = time; 137 event->ticks = false; 138 event->byte1 = B_KEY_PRESSURE | (channel - 1); 139 event->byte2 = note; 140 event->byte3 = pressure; 141 AddEvent(event); 142 } 143 144 //------------------------------------------------------------------------------ 145 146 void BMidiStore::ControlChange( 147 uchar channel, uchar controlNumber, uchar controlValue, uint32 time) 148 { 149 BMidiEvent* event = new BMidiEvent; 150 event->time = time; 151 event->ticks = false; 152 event->byte1 = B_CONTROL_CHANGE | (channel - 1); 153 event->byte2 = controlNumber; 154 event->byte3 = controlValue; 155 AddEvent(event); 156 } 157 158 //------------------------------------------------------------------------------ 159 160 void BMidiStore::ProgramChange( 161 uchar channel, uchar programNumber, uint32 time) 162 { 163 BMidiEvent* event = new BMidiEvent; 164 event->time = time; 165 event->ticks = false; 166 event->byte1 = B_PROGRAM_CHANGE | (channel - 1); 167 event->byte2 = programNumber; 168 AddEvent(event); 169 } 170 171 //------------------------------------------------------------------------------ 172 173 void BMidiStore::ChannelPressure(uchar channel, uchar pressure, uint32 time) 174 { 175 BMidiEvent* event = new BMidiEvent; 176 event->time = time; 177 event->ticks = false; 178 event->byte1 = B_CHANNEL_PRESSURE | (channel - 1); 179 event->byte2 = pressure; 180 AddEvent(event); 181 } 182 183 //------------------------------------------------------------------------------ 184 185 void BMidiStore::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time) 186 { 187 BMidiEvent* event = new BMidiEvent; 188 event->time = time; 189 event->ticks = false; 190 event->byte1 = B_PITCH_BEND | (channel - 1); 191 event->byte2 = lsb; 192 event->byte3 = msb; 193 AddEvent(event); 194 } 195 196 //------------------------------------------------------------------------------ 197 198 void BMidiStore::SystemExclusive(void* data, size_t length, uint32 time) 199 { 200 BMidiEvent* event = new BMidiEvent; 201 event->time = time; 202 event->ticks = false; 203 event->byte1 = B_SYS_EX_START; 204 event->data = malloc(length); 205 event->length = length; 206 memcpy(event->data, data, length); 207 AddEvent(event); 208 } 209 210 //------------------------------------------------------------------------------ 211 212 void BMidiStore::SystemCommon( 213 uchar status, uchar data1, uchar data2, uint32 time) 214 { 215 BMidiEvent* event = new BMidiEvent; 216 event->time = time; 217 event->ticks = false; 218 event->byte1 = status; 219 event->byte2 = data1; 220 event->byte3 = data2; 221 AddEvent(event); 222 } 223 224 //------------------------------------------------------------------------------ 225 226 void BMidiStore::SystemRealTime(uchar status, uint32 time) 227 { 228 BMidiEvent* event = new BMidiEvent; 229 event->time = time; 230 event->ticks = false; 231 event->byte1 = status; 232 AddEvent(event); 233 } 234 235 //------------------------------------------------------------------------------ 236 237 void BMidiStore::TempoChange(int32 beatsPerMinute, uint32 time) 238 { 239 BMidiEvent* event = new BMidiEvent; 240 event->time = time; 241 event->ticks = false; 242 event->byte1 = 0xFF; 243 event->byte2 = 0x51; 244 event->byte3 = 0x03; 245 event->tempo = beatsPerMinute; 246 AddEvent(event); 247 } 248 249 //------------------------------------------------------------------------------ 250 251 status_t BMidiStore::Import(const entry_ref* ref) 252 { 253 memset(instruments, 0, 128 * sizeof(bool)); 254 255 try 256 { 257 file = new BFile(ref, B_READ_ONLY); 258 if (file->InitCheck() != B_OK) 259 { 260 throw file->InitCheck(); 261 } 262 263 char fourcc[4]; 264 ReadFourCC(fourcc); 265 if (strncmp(fourcc, "MThd", 4) != 0) 266 { 267 throw (status_t) B_BAD_MIDI_DATA; 268 } 269 270 if (Read32Bit() != 6) 271 { 272 throw (status_t) B_BAD_MIDI_DATA; 273 } 274 275 format = Read16Bit(); 276 numTracks = Read16Bit(); 277 ticksPerBeat = Read16Bit(); 278 279 if (ticksPerBeat & 0x8000) // we don't support SMPTE 280 { // time codes, only ticks 281 ticksPerBeat = 240; // per quarter note 282 } 283 284 currTrack = 0; 285 while (currTrack < numTracks) 286 { 287 ReadChunk(); 288 } 289 } 290 catch (status_t e) 291 { 292 delete file; 293 file = NULL; 294 return e; 295 } 296 297 SortEvents(true); 298 299 delete file; 300 file = NULL; 301 return B_OK; 302 } 303 304 //------------------------------------------------------------------------------ 305 306 status_t BMidiStore::Export(const entry_ref* ref, int32 format) 307 { 308 try 309 { 310 file = new BFile(ref, B_READ_WRITE); 311 if (file->InitCheck() != B_OK) 312 { 313 throw file->InitCheck(); 314 } 315 316 SortEvents(true); 317 318 WriteFourCC('M', 'T', 'h', 'd'); 319 Write32Bit(6); 320 Write16Bit(0); // we do only format 0 321 Write16Bit(1); 322 Write16Bit(ticksPerBeat); 323 324 WriteTrack(); 325 } 326 catch (status_t e) 327 { 328 delete file; 329 file = NULL; 330 return e; 331 } 332 333 delete file; 334 file = NULL; 335 return B_OK; 336 } 337 338 //------------------------------------------------------------------------------ 339 340 void BMidiStore::SortEvents(bool force) 341 { 342 if (force || needsSorting) 343 { 344 events->SortItems(compare_events); 345 needsSorting = false; 346 } 347 } 348 349 //------------------------------------------------------------------------------ 350 351 uint32 BMidiStore::CountEvents() const 352 { 353 return events->CountItems(); 354 } 355 356 //------------------------------------------------------------------------------ 357 358 uint32 BMidiStore::CurrentEvent() const 359 { 360 return currentEvent; 361 } 362 363 //------------------------------------------------------------------------------ 364 365 void BMidiStore::SetCurrentEvent(uint32 eventNumber) 366 { 367 currentEvent = eventNumber; 368 } 369 370 //------------------------------------------------------------------------------ 371 372 uint32 BMidiStore::DeltaOfEvent(uint32 eventNumber) const 373 { 374 // Even though the BeBook says that the delta is the time span between 375 // an event and the first event in the list, this doesn't appear to be 376 // true for events that were captured from other BMidi objects such as 377 // BMidiPort. For those events, we return the absolute timestamp. The 378 // BeBook is correct for events from MIDI files, though. 379 380 BMidiEvent* event = EventAt(eventNumber); 381 if (event != NULL) 382 { 383 return GetEventTime(event); 384 } 385 386 return 0; 387 } 388 389 //------------------------------------------------------------------------------ 390 391 uint32 BMidiStore::EventAtDelta(uint32 time) const 392 { 393 for (int32 t = 0; t < events->CountItems(); ++t) 394 { 395 if (GetEventTime(EventAt(t)) >= time) { return t; } 396 } 397 398 return 0; 399 } 400 401 //------------------------------------------------------------------------------ 402 403 uint32 BMidiStore::BeginTime() const 404 { 405 return startTime; 406 } 407 408 //------------------------------------------------------------------------------ 409 410 void BMidiStore::SetTempo(int32 beatsPerMinute_) 411 { 412 beatsPerMinute = beatsPerMinute_; 413 } 414 415 //------------------------------------------------------------------------------ 416 417 int32 BMidiStore::Tempo() const 418 { 419 return beatsPerMinute; 420 } 421 422 //------------------------------------------------------------------------------ 423 424 void BMidiStore::_ReservedMidiStore1() { } 425 void BMidiStore::_ReservedMidiStore2() { } 426 void BMidiStore::_ReservedMidiStore3() { } 427 428 //------------------------------------------------------------------------------ 429 430 void BMidiStore::Run() 431 { 432 // This rather compilicated Run() loop is not only used by BMidiStore 433 // but also by BMidiSynthFile. The "paused", "finished", and "looping" 434 // flags, and the "stop hook" are especially provided for the latter. 435 436 paused = false; 437 finished = false; 438 439 int32 timeAdjust; 440 uint32 baseTime; 441 bool firstEvent = true; 442 bool resetTime = false; 443 444 while (KeepRunning()) 445 { 446 if (paused) 447 { 448 resetTime = true; 449 snooze(100000); 450 continue; 451 } 452 453 BMidiEvent* event = EventAt(currentEvent); 454 455 if (event == NULL) // no more events 456 { 457 if (looping) 458 { 459 resetTime = true; 460 currentEvent = 0; 461 } 462 else 463 { 464 break; 465 } 466 } 467 468 if (firstEvent) 469 { 470 startTime = B_NOW; 471 baseTime = startTime; 472 } 473 else if (resetTime) 474 { 475 baseTime = B_NOW; 476 } 477 478 if (firstEvent || resetTime) 479 { 480 timeAdjust = baseTime - GetEventTime(event); 481 SprayEvent(event, baseTime); 482 firstEvent = false; 483 resetTime = false; 484 } 485 else 486 { 487 SprayEvent(event, GetEventTime(event) + timeAdjust); 488 } 489 490 ++currentEvent; 491 } 492 493 finished = true; 494 paused = false; 495 496 if (hookFunc != NULL) 497 { 498 (*hookFunc)(hookArg); 499 } 500 } 501 502 //------------------------------------------------------------------------------ 503 504 void BMidiStore::AddEvent(BMidiEvent* event) 505 { 506 events->AddItem(event); 507 needsSorting = true; 508 } 509 510 //------------------------------------------------------------------------------ 511 512 void BMidiStore::SprayEvent(const BMidiEvent* event, uint32 time) 513 { 514 uchar byte1 = event->byte1; 515 uchar byte2 = event->byte2; 516 uchar byte3 = event->byte3; 517 518 switch (byte1 & 0xF0) 519 { 520 case B_NOTE_OFF: 521 SprayNoteOff((byte1 & 0x0F) + 1, byte2, byte3, time); 522 return; 523 524 case B_NOTE_ON: 525 SprayNoteOn((byte1 & 0x0F) + 1, byte2, byte3, time); 526 return; 527 528 case B_KEY_PRESSURE: 529 SprayKeyPressure((byte1 & 0x0F) + 1, byte2, byte3, time); 530 return; 531 532 case B_CONTROL_CHANGE: 533 SprayControlChange((byte1 & 0x0F) + 1, byte2, byte3, time); 534 return; 535 536 case B_PROGRAM_CHANGE: 537 SprayProgramChange((byte1 & 0x0F) + 1, byte2, time); 538 return; 539 540 case B_CHANNEL_PRESSURE: 541 SprayChannelPressure((byte1 & 0x0F) + 1, byte2, time); 542 return; 543 544 case B_PITCH_BEND: 545 SprayPitchBend((byte1 & 0x0F) + 1, byte2, byte3, time); 546 return; 547 548 case 0xF0: 549 switch (byte1) 550 { 551 case B_SYS_EX_START: 552 SpraySystemExclusive(event->data, event->length, time); 553 return; 554 555 case B_MIDI_TIME_CODE: 556 case B_SONG_POSITION: 557 case B_SONG_SELECT: 558 case B_CABLE_MESSAGE: 559 case B_TUNE_REQUEST: 560 case B_SYS_EX_END: 561 SpraySystemCommon(byte1, byte2, byte3, time); 562 return; 563 564 case B_TIMING_CLOCK: 565 case B_START: 566 case B_CONTINUE: 567 case B_STOP: 568 case B_ACTIVE_SENSING: 569 SpraySystemRealTime(byte1, time); 570 return; 571 572 case B_SYSTEM_RESET: 573 if ((byte2 == 0x51) && (byte3 == 0x03)) 574 { 575 SprayTempoChange(event->tempo, time); 576 beatsPerMinute = event->tempo; 577 } 578 else 579 { 580 SpraySystemRealTime(byte1, time); 581 } 582 return; 583 } 584 return; 585 } 586 } 587 588 //------------------------------------------------------------------------------ 589 590 BMidiEvent* BMidiStore::EventAt(int32 index) const 591 { 592 return (BMidiEvent*) events->ItemAt(index); 593 } 594 595 //------------------------------------------------------------------------------ 596 597 uint32 BMidiStore::GetEventTime(const BMidiEvent* event) const 598 { 599 if (event->ticks) 600 { 601 return TicksToMilliseconds(event->time); 602 } 603 else 604 { 605 return event->time; 606 } 607 } 608 609 //------------------------------------------------------------------------------ 610 611 uint32 BMidiStore::TicksToMilliseconds(uint32 ticks) const 612 { 613 return ((uint64) ticks * 60000) / (beatsPerMinute * ticksPerBeat); 614 } 615 616 //------------------------------------------------------------------------------ 617 618 uint32 BMidiStore::MillisecondsToTicks(uint32 ms) const 619 { 620 return ((uint64) ms * beatsPerMinute * ticksPerBeat) / 60000; 621 } 622 623 //------------------------------------------------------------------------------ 624 625 void BMidiStore::ReadFourCC(char* fourcc) 626 { 627 if (file->Read(fourcc, 4) != 4) 628 { 629 throw (status_t) B_BAD_MIDI_DATA; 630 } 631 } 632 633 //------------------------------------------------------------------------------ 634 635 void BMidiStore::WriteFourCC(char a, char b, char c, char d) 636 { 637 char fourcc[4] = { a, b, c, d }; 638 if (file->Write(fourcc, 4) != 4) 639 { 640 throw (status_t) B_ERROR; 641 } 642 } 643 644 //------------------------------------------------------------------------------ 645 646 uint32 BMidiStore::Read32Bit() 647 { 648 uint8 buf[4]; 649 if (file->Read(buf, 4) != 4) 650 { 651 throw (status_t) B_BAD_MIDI_DATA; 652 } 653 654 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; 655 } 656 657 //------------------------------------------------------------------------------ 658 659 void BMidiStore::Write32Bit(uint32 val) 660 { 661 uint8 buf[4]; 662 buf[0] = (val >> 24) & 0xFF; 663 buf[1] = (val >> 16) & 0xFF; 664 buf[2] = (val >> 8) & 0xFF; 665 buf[3] = val & 0xFF; 666 667 if (file->Write(buf, 4) != 4) 668 { 669 throw (status_t) B_ERROR; 670 } 671 } 672 673 //------------------------------------------------------------------------------ 674 675 uint16 BMidiStore::Read16Bit() 676 { 677 uint8 buf[2]; 678 if (file->Read(buf, 2) != 2) 679 { 680 throw (status_t) B_BAD_MIDI_DATA; 681 } 682 683 return (buf[0] << 8) | buf[1]; 684 } 685 686 //------------------------------------------------------------------------------ 687 688 void BMidiStore::Write16Bit(uint16 val) 689 { 690 uint8 buf[2]; 691 buf[0] = (val >> 8) & 0xFF; 692 buf[1] = val & 0xFF; 693 694 if (file->Write(buf, 2) != 2) 695 { 696 throw (status_t) B_ERROR; 697 } 698 } 699 700 //------------------------------------------------------------------------------ 701 702 uint8 BMidiStore::PeekByte() 703 { 704 uint8 buf; 705 if (file->Read(&buf, 1) != 1) 706 { 707 throw (status_t) B_BAD_MIDI_DATA; 708 } 709 710 if (file->Seek(-1, SEEK_CUR) < 0) 711 { 712 throw (status_t) B_ERROR; 713 } 714 715 return buf; 716 } 717 718 //------------------------------------------------------------------------------ 719 720 uint8 BMidiStore::NextByte() 721 { 722 uint8 buf; 723 if (file->Read(&buf, 1) != 1) 724 { 725 throw (status_t) B_BAD_MIDI_DATA; 726 } 727 728 --byteCount; 729 return buf; 730 } 731 732 //------------------------------------------------------------------------------ 733 734 void BMidiStore::WriteByte(uint8 val) 735 { 736 if (file->Write(&val, 1) != 1) 737 { 738 throw (status_t) B_ERROR; 739 } 740 741 ++byteCount; 742 } 743 744 //------------------------------------------------------------------------------ 745 746 void BMidiStore::SkipBytes(uint32 length) 747 { 748 if (file->Seek(length, SEEK_CUR) < 0) 749 { 750 throw (status_t) B_BAD_MIDI_DATA; 751 } 752 753 byteCount -= length; 754 } 755 756 //------------------------------------------------------------------------------ 757 758 uint32 BMidiStore::ReadVarLength() 759 { 760 uint32 val; 761 uint8 byte; 762 763 if ((val = NextByte()) & 0x80) 764 { 765 val &= 0x7F; 766 do 767 { 768 val = (val << 7) + ((byte = NextByte()) & 0x7F); 769 } 770 while (byte & 0x80); 771 } 772 773 return val; 774 } 775 776 //------------------------------------------------------------------------------ 777 778 void BMidiStore::WriteVarLength(uint32 val) 779 { 780 uint32 buffer = val & 0x7F; 781 782 while ((val >>= 7)) 783 { 784 buffer <<= 8; 785 buffer |= ((val & 0x7F) | 0x80); 786 } 787 788 while (true) 789 { 790 WriteByte(buffer); 791 if (buffer & 0x80) 792 buffer >>= 8; 793 else 794 break; 795 } 796 } 797 798 //------------------------------------------------------------------------------ 799 800 void BMidiStore::ReadChunk() 801 { 802 char fourcc[4]; 803 ReadFourCC(fourcc); 804 805 byteCount = Read32Bit(); 806 807 if (strncmp(fourcc, "MTrk", 4) == 0) 808 { 809 ReadTrack(); 810 } 811 else 812 { 813 TRACE(("Skipping '%c%c%c%c' chunk (%lu bytes)", 814 fourcc[0], fourcc[1], fourcc[2], fourcc[3], byteCount)) 815 816 SkipBytes(byteCount); 817 } 818 } 819 820 //------------------------------------------------------------------------------ 821 822 void BMidiStore::ReadTrack() 823 { 824 uint8 status = 0; 825 uint8 data1; 826 uint8 data2; 827 BMidiEvent* event; 828 829 totalTicks = 0; 830 831 while (byteCount > 0) 832 { 833 uint32 ticks = ReadVarLength(); 834 totalTicks += ticks; 835 836 if (PeekByte() & 0x80) 837 { 838 status = NextByte(); 839 } 840 841 switch (status & 0xF0) 842 { 843 case B_NOTE_OFF: 844 case B_NOTE_ON: 845 case B_KEY_PRESSURE: 846 case B_CONTROL_CHANGE: 847 case B_PITCH_BEND: 848 data1 = NextByte(); 849 data2 = NextByte(); 850 event = new BMidiEvent; 851 event->time = totalTicks; 852 event->ticks = true; 853 event->byte1 = status; 854 event->byte2 = data1; 855 event->byte3 = data2; 856 AddEvent(event); 857 break; 858 859 case B_PROGRAM_CHANGE: 860 case B_CHANNEL_PRESSURE: 861 data1 = NextByte(); 862 event = new BMidiEvent; 863 event->time = totalTicks; 864 event->ticks = true; 865 event->byte1 = status; 866 event->byte2 = data1; 867 AddEvent(event); 868 869 if ((status & 0xF0) == B_PROGRAM_CHANGE) 870 { 871 instruments[data1] = true; 872 } 873 break; 874 875 case 0xF0: 876 switch (status) 877 { 878 case B_SYS_EX_START: 879 ReadSystemExclusive(); 880 break; 881 882 case B_TUNE_REQUEST: 883 case B_SYS_EX_END: 884 case B_TIMING_CLOCK: 885 case B_START: 886 case B_CONTINUE: 887 case B_STOP: 888 case B_ACTIVE_SENSING: 889 event = new BMidiEvent; 890 event->time = totalTicks; 891 event->ticks = true; 892 event->byte1 = status; 893 AddEvent(event); 894 break; 895 896 case B_MIDI_TIME_CODE: 897 case B_SONG_SELECT: 898 case B_CABLE_MESSAGE: 899 data1 = NextByte(); 900 event = new BMidiEvent; 901 event->time = totalTicks; 902 event->ticks = true; 903 event->byte1 = status; 904 event->byte2 = data1; 905 AddEvent(event); 906 break; 907 908 case B_SONG_POSITION: 909 data1 = NextByte(); 910 data2 = NextByte(); 911 event = new BMidiEvent; 912 event->time = totalTicks; 913 event->ticks = true; 914 event->byte1 = status; 915 event->byte2 = data1; 916 event->byte3 = data2; 917 AddEvent(event); 918 break; 919 920 case B_SYSTEM_RESET: 921 ReadMetaEvent(); 922 break; 923 } 924 break; 925 } 926 927 event = NULL; 928 } 929 930 ++currTrack; 931 } 932 933 //------------------------------------------------------------------------------ 934 935 void BMidiStore::ReadSystemExclusive() 936 { 937 // We do not import sysex's from MIDI files. 938 939 SkipBytes(ReadVarLength()); 940 } 941 942 //------------------------------------------------------------------------------ 943 944 void BMidiStore::ReadMetaEvent() 945 { 946 // We only import the Tempo Change meta event. 947 948 uint8 type = NextByte(); 949 uint32 length = ReadVarLength(); 950 951 if ((type == 0x51) && (length == 3)) 952 { 953 uchar data[3]; 954 data[0] = NextByte(); 955 data[1] = NextByte(); 956 data[2] = NextByte(); 957 uint32 val = (data[0] << 16) | (data[1] << 8) | data[2]; 958 959 BMidiEvent* event = new BMidiEvent; 960 event->time = totalTicks; 961 event->ticks = true; 962 event->byte1 = 0xFF; 963 event->byte2 = 0x51; 964 event->byte3 = 0x03; 965 event->tempo = 60000000 / val; 966 AddEvent(event); 967 } 968 else 969 { 970 SkipBytes(length); 971 } 972 } 973 974 //------------------------------------------------------------------------------ 975 976 void BMidiStore::WriteTrack() 977 { 978 WriteFourCC('M', 'T', 'r', 'k'); 979 off_t lengthPos = file->Position(); 980 Write32Bit(0); 981 982 byteCount = 0; 983 uint32 oldTime; 984 uint32 newTime; 985 986 for (uint32 t = 0; t < CountEvents(); ++t) 987 { 988 BMidiEvent* event = EventAt(t); 989 990 if (event->ticks) 991 { 992 newTime = event->time; 993 } 994 else 995 { 996 newTime = MillisecondsToTicks(event->time); 997 } 998 999 if (t == 0) 1000 { 1001 WriteVarLength(0); 1002 } 1003 else 1004 { 1005 WriteVarLength(newTime - oldTime); 1006 } 1007 1008 oldTime = newTime; 1009 1010 switch (event->byte1 & 0xF0) 1011 { 1012 case B_NOTE_OFF: 1013 case B_NOTE_ON: 1014 case B_KEY_PRESSURE: 1015 case B_CONTROL_CHANGE: 1016 case B_PITCH_BEND: 1017 WriteByte(event->byte1); 1018 WriteByte(event->byte2); 1019 WriteByte(event->byte3); 1020 break; 1021 1022 case B_PROGRAM_CHANGE: 1023 case B_CHANNEL_PRESSURE: 1024 WriteByte(event->byte1); 1025 WriteByte(event->byte2); 1026 break; 1027 1028 case 0xF0: 1029 switch (event->byte1) 1030 { 1031 case B_SYS_EX_START: 1032 // We do not export sysex's. 1033 break; 1034 1035 case B_TUNE_REQUEST: 1036 case B_SYS_EX_END: 1037 case B_TIMING_CLOCK: 1038 case B_START: 1039 case B_CONTINUE: 1040 case B_STOP: 1041 case B_ACTIVE_SENSING: 1042 WriteByte(event->byte1); 1043 break; 1044 1045 case B_MIDI_TIME_CODE: 1046 case B_SONG_SELECT: 1047 case B_CABLE_MESSAGE: 1048 WriteByte(event->byte1); 1049 WriteByte(event->byte2); 1050 break; 1051 1052 case B_SONG_POSITION: 1053 WriteByte(event->byte1); 1054 WriteByte(event->byte2); 1055 WriteByte(event->byte3); 1056 break; 1057 1058 case B_SYSTEM_RESET: 1059 WriteMetaEvent(event); 1060 break; 1061 } 1062 break; 1063 1064 } 1065 } 1066 1067 WriteVarLength(0); 1068 WriteByte(0xFF); // the end-of-track 1069 WriteByte(0x2F); // marker is required 1070 WriteByte(0x00); 1071 1072 file->Seek(lengthPos, SEEK_SET); 1073 Write32Bit(byteCount); 1074 file->Seek(0, SEEK_END); 1075 } 1076 1077 //------------------------------------------------------------------------------ 1078 1079 void BMidiStore::WriteMetaEvent(BMidiEvent* event) 1080 { 1081 // We only export the Tempo Change meta event. 1082 1083 if ((event->byte2 == 0x51) && (event->byte3 == 0x03)) 1084 { 1085 uint32 val = 60000000 / event->tempo; 1086 1087 WriteByte(0xFF); 1088 WriteByte(0x51); 1089 WriteByte(0x03); 1090 WriteByte(val >> 16); 1091 WriteByte(val >> 8); 1092 WriteByte(val); 1093 } 1094 } 1095 1096 1097 //------------------------------------------------------------------------------ 1098