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 BMidiEvent() 38 { 39 byte1 = 0; 40 byte2 = 0; 41 byte3 = 0; 42 data = NULL; 43 length = 0; 44 } 45 46 ~BMidiEvent() 47 { 48 free(data); 49 } 50 51 uint32 time; // either ticks or milliseconds 52 bool ticks; // event is from MIDI file 53 uchar byte1; 54 uchar byte2; 55 uchar byte3; 56 void* data; // sysex data 57 size_t length; // sysex data size 58 int32 tempo; // beats per minute 59 }; 60 61 62 static int 63 compare_events(const void* event1, const void* event2) 64 { 65 BMidiEvent* e1 = *((BMidiEvent**) event1); 66 BMidiEvent* e2 = *((BMidiEvent**) event2); 67 68 return (e1->time - e2->time); 69 } 70 71 72 // #pragma mark - 73 74 75 BMidiStore::BMidiStore() 76 { 77 events = new BList; 78 currentEvent = 0; 79 startTime = 0; 80 needsSorting = false; 81 beatsPerMinute = 60; 82 ticksPerBeat = 240; 83 file = NULL; 84 hookFunc = NULL; 85 looping = false; 86 paused = false; 87 finished = false; 88 instruments = new bool[128]; 89 } 90 91 92 BMidiStore::~BMidiStore() 93 { 94 for (int32 t = 0; t < events->CountItems(); ++t) { 95 delete EventAt(t); 96 } 97 98 delete events; 99 delete[] instruments; 100 } 101 102 103 void 104 BMidiStore::NoteOff(uchar channel, uchar note, uchar velocity, 105 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 void 118 BMidiStore::NoteOn(uchar channel, uchar note, 119 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 void 132 BMidiStore::KeyPressure(uchar channel, uchar note, 133 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 void 146 BMidiStore::ControlChange(uchar channel, uchar controlNumber, 147 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 void 160 BMidiStore::ProgramChange(uchar channel, uchar programNumber, 161 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 void 173 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 void 185 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 void 198 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 void 212 BMidiStore::SystemCommon(uchar status, uchar data1, 213 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 void 226 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 void 237 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 status_t 251 BMidiStore::Import(const entry_ref* ref) 252 { 253 memset(instruments, 0, 128 * sizeof(bool)); 254 255 try { 256 file = new BFile(ref, B_READ_ONLY); 257 if (file->InitCheck() != B_OK) 258 throw file->InitCheck(); 259 260 char fourcc[4]; 261 ReadFourCC(fourcc); 262 if (strncmp(fourcc, "MThd", 4) != 0) 263 throw (status_t) B_BAD_MIDI_DATA; 264 265 if (Read32Bit() != 6) 266 throw (status_t) B_BAD_MIDI_DATA; 267 268 format = Read16Bit(); 269 numTracks = Read16Bit(); 270 ticksPerBeat = Read16Bit(); 271 272 if (ticksPerBeat & 0x8000) { 273 // we don't support SMPTE time codes, 274 // only ticks per quarter note 275 ticksPerBeat = 240; 276 } 277 278 currTrack = 0; 279 while (currTrack < numTracks) { 280 ReadChunk(); 281 } 282 } catch (status_t e) { 283 delete file; 284 file = NULL; 285 return e; 286 } 287 288 SortEvents(true); 289 290 delete file; 291 file = NULL; 292 return B_OK; 293 } 294 295 296 status_t 297 BMidiStore::Export(const entry_ref* ref, int32 format) 298 { 299 try { 300 file = new BFile(ref, B_READ_WRITE); 301 if (file->InitCheck() != B_OK) 302 throw file->InitCheck(); 303 304 SortEvents(true); 305 306 WriteFourCC('M', 'T', 'h', 'd'); 307 Write32Bit(6); 308 Write16Bit(0); // we do only format 0 309 Write16Bit(1); 310 Write16Bit(ticksPerBeat); 311 312 WriteTrack(); 313 } catch (status_t e) { 314 delete file; 315 file = NULL; 316 return e; 317 } 318 319 delete file; 320 file = NULL; 321 return B_OK; 322 } 323 324 325 void 326 BMidiStore::SortEvents(bool force) 327 { 328 if (force || needsSorting) { 329 events->SortItems(compare_events); 330 needsSorting = false; 331 } 332 } 333 334 335 uint32 336 BMidiStore::CountEvents() const 337 { 338 return events->CountItems(); 339 } 340 341 342 uint32 343 BMidiStore::CurrentEvent() const 344 { 345 return currentEvent; 346 } 347 348 349 void 350 BMidiStore::SetCurrentEvent(uint32 eventNumber) 351 { 352 currentEvent = eventNumber; 353 } 354 355 356 uint32 357 BMidiStore::DeltaOfEvent(uint32 eventNumber) const 358 { 359 // Even though the BeBook says that the delta is the time span between 360 // an event and the first event in the list, this doesn't appear to be 361 // true for events that were captured from other BMidi objects such as 362 // BMidiPort. For those events, we return the absolute timestamp. The 363 // BeBook is correct for events from MIDI files, though. 364 365 BMidiEvent* event = EventAt(eventNumber); 366 if (event != NULL) 367 return GetEventTime(event); 368 369 return 0; 370 } 371 372 373 uint32 374 BMidiStore::EventAtDelta(uint32 time) const 375 { 376 for (int32 t = 0; t < events->CountItems(); ++t) { 377 if (GetEventTime(EventAt(t)) >= time) 378 return t; 379 } 380 381 return 0; 382 } 383 384 385 uint32 386 BMidiStore::BeginTime() const 387 { 388 return startTime; 389 } 390 391 392 void 393 BMidiStore::SetTempo(int32 beatsPerMinute_) 394 { 395 beatsPerMinute = beatsPerMinute_; 396 } 397 398 399 int32 400 BMidiStore::Tempo() const 401 { 402 return beatsPerMinute; 403 } 404 405 //------------------------------------------------------------------------------ 406 407 void BMidiStore::_ReservedMidiStore1() { } 408 void BMidiStore::_ReservedMidiStore2() { } 409 void BMidiStore::_ReservedMidiStore3() { } 410 411 //------------------------------------------------------------------------------ 412 413 void 414 BMidiStore::Run() 415 { 416 // This rather compilicated Run() loop is not only used by BMidiStore 417 // but also by BMidiSynthFile. The "paused", "finished", and "looping" 418 // flags, and the "stop hook" are especially provided for the latter. 419 420 paused = false; 421 finished = false; 422 423 int32 timeAdjust = 0; 424 uint32 baseTime = 0; 425 bool firstEvent = true; 426 bool resetTime = false; 427 428 while (KeepRunning()) { 429 if (paused) { 430 resetTime = true; 431 snooze(100000); 432 continue; 433 } 434 435 BMidiEvent* event = EventAt(currentEvent); 436 437 if (event == NULL) { 438 // no more events 439 if (looping) { 440 resetTime = true; 441 currentEvent = 0; 442 } else 443 break; 444 } 445 446 if (firstEvent) { 447 startTime = B_NOW; 448 baseTime = startTime; 449 } else if (resetTime) 450 baseTime = B_NOW; 451 452 if (firstEvent || resetTime) { 453 timeAdjust = baseTime - GetEventTime(event); 454 SprayEvent(event, baseTime); 455 firstEvent = false; 456 resetTime = false; 457 } else 458 SprayEvent(event, GetEventTime(event) + timeAdjust); 459 460 ++currentEvent; 461 } 462 463 finished = true; 464 paused = false; 465 466 if (hookFunc != NULL) 467 (*hookFunc)(hookArg); 468 } 469 470 471 void 472 BMidiStore::AddEvent(BMidiEvent* event) 473 { 474 events->AddItem(event); 475 needsSorting = true; 476 } 477 478 479 void 480 BMidiStore::SprayEvent(const BMidiEvent* event, uint32 time) 481 { 482 uchar byte1 = event->byte1; 483 uchar byte2 = event->byte2; 484 uchar byte3 = event->byte3; 485 486 switch (byte1 & 0xF0) { 487 case B_NOTE_OFF: 488 SprayNoteOff((byte1 & 0x0F) + 1, byte2, byte3, time); 489 return; 490 491 case B_NOTE_ON: 492 SprayNoteOn((byte1 & 0x0F) + 1, byte2, byte3, time); 493 return; 494 495 case B_KEY_PRESSURE: 496 SprayKeyPressure((byte1 & 0x0F) + 1, byte2, byte3, time); 497 return; 498 499 case B_CONTROL_CHANGE: 500 SprayControlChange((byte1 & 0x0F) + 1, byte2, byte3, time); 501 return; 502 503 case B_PROGRAM_CHANGE: 504 SprayProgramChange((byte1 & 0x0F) + 1, byte2, time); 505 return; 506 507 case B_CHANNEL_PRESSURE: 508 SprayChannelPressure((byte1 & 0x0F) + 1, byte2, time); 509 return; 510 511 case B_PITCH_BEND: 512 SprayPitchBend((byte1 & 0x0F) + 1, byte2, byte3, time); 513 return; 514 515 case 0xF0: 516 switch (byte1) { 517 case B_SYS_EX_START: 518 SpraySystemExclusive(event->data, event->length, time); 519 return; 520 521 case B_MIDI_TIME_CODE: 522 case B_SONG_POSITION: 523 case B_SONG_SELECT: 524 case B_CABLE_MESSAGE: 525 case B_TUNE_REQUEST: 526 case B_SYS_EX_END: 527 SpraySystemCommon(byte1, byte2, byte3, time); 528 return; 529 530 case B_TIMING_CLOCK: 531 case B_START: 532 case B_CONTINUE: 533 case B_STOP: 534 case B_ACTIVE_SENSING: 535 SpraySystemRealTime(byte1, time); 536 return; 537 538 case B_SYSTEM_RESET: 539 if (byte2 == 0x51 && byte3 == 0x03) { 540 SprayTempoChange(event->tempo, time); 541 beatsPerMinute = event->tempo; 542 } else 543 SpraySystemRealTime(byte1, time); 544 return; 545 } 546 return; 547 } 548 } 549 550 551 BMidiEvent* 552 BMidiStore::EventAt(int32 index) const 553 { 554 return (BMidiEvent*)events->ItemAt(index); 555 } 556 557 558 uint32 559 BMidiStore::GetEventTime(const BMidiEvent* event) const 560 { 561 if (event->ticks) 562 return TicksToMilliseconds(event->time); 563 564 return event->time; 565 } 566 567 568 uint32 569 BMidiStore::TicksToMilliseconds(uint32 ticks) const 570 { 571 return ((uint64)ticks * 60000) / (beatsPerMinute * ticksPerBeat); 572 } 573 574 575 uint32 576 BMidiStore::MillisecondsToTicks(uint32 ms) const 577 { 578 return ((uint64)ms * beatsPerMinute * ticksPerBeat) / 60000; 579 } 580 581 582 void 583 BMidiStore::ReadFourCC(char* fourcc) 584 { 585 if (file->Read(fourcc, 4) != 4) 586 throw (status_t) B_BAD_MIDI_DATA; 587 } 588 589 590 void 591 BMidiStore::WriteFourCC(char a, char b, char c, char d) 592 { 593 char fourcc[4] = { a, b, c, d }; 594 595 if (file->Write(fourcc, 4) != 4) 596 throw (status_t) B_ERROR; 597 } 598 599 600 uint32 601 BMidiStore::Read32Bit() 602 { 603 uint8 buf[4]; 604 if (file->Read(buf, 4) != 4) 605 throw (status_t) B_BAD_MIDI_DATA; 606 607 return (buf[0] << 24L) | (buf[1] << 16L) | (buf[2] << 8L) | buf[3]; 608 } 609 610 611 void 612 BMidiStore::Write32Bit(uint32 val) 613 { 614 uint8 buf[4]; 615 buf[0] = (val >> 24) & 0xFF; 616 buf[1] = (val >> 16) & 0xFF; 617 buf[2] = (val >> 8) & 0xFF; 618 buf[3] = val & 0xFF; 619 620 if (file->Write(buf, 4) != 4) 621 throw (status_t) B_ERROR; 622 } 623 624 625 uint16 626 BMidiStore::Read16Bit() 627 { 628 uint8 buf[2]; 629 if (file->Read(buf, 2) != 2) 630 throw (status_t) B_BAD_MIDI_DATA; 631 632 return (buf[0] << 8) | buf[1]; 633 } 634 635 636 void 637 BMidiStore::Write16Bit(uint16 val) 638 { 639 uint8 buf[2]; 640 buf[0] = (val >> 8) & 0xFF; 641 buf[1] = val & 0xFF; 642 643 if (file->Write(buf, 2) != 2) 644 throw (status_t) B_ERROR; 645 } 646 647 648 uint8 649 BMidiStore::PeekByte() 650 { 651 uint8 buf; 652 if (file->Read(&buf, 1) != 1) 653 throw (status_t) B_BAD_MIDI_DATA; 654 655 if (file->Seek(-1, SEEK_CUR) < 0) 656 throw (status_t) B_ERROR; 657 658 return buf; 659 } 660 661 662 uint8 663 BMidiStore::NextByte() 664 { 665 uint8 buf; 666 if (file->Read(&buf, 1) != 1) 667 throw (status_t) B_BAD_MIDI_DATA; 668 669 --byteCount; 670 return buf; 671 } 672 673 674 void 675 BMidiStore::WriteByte(uint8 val) 676 { 677 if (file->Write(&val, 1) != 1) 678 throw (status_t) B_ERROR; 679 680 ++byteCount; 681 } 682 683 684 void 685 BMidiStore::SkipBytes(uint32 length) 686 { 687 if (file->Seek(length, SEEK_CUR) < 0) { 688 throw (status_t) B_BAD_MIDI_DATA; 689 } 690 691 byteCount -= length; 692 } 693 694 695 uint32 696 BMidiStore::ReadVarLength() 697 { 698 uint32 val; 699 uint8 byte; 700 701 if ((val = NextByte()) & 0x80) { 702 val &= 0x7F; 703 do { 704 val = (val << 7) + ((byte = NextByte()) & 0x7F); 705 } while (byte & 0x80); 706 } 707 708 return val; 709 } 710 711 712 void 713 BMidiStore::WriteVarLength(uint32 val) 714 { 715 uint32 buffer = val & 0x7F; 716 717 while ((val >>= 7) != 0) { 718 buffer <<= 8; 719 buffer |= ((val & 0x7F) | 0x80); 720 } 721 722 while (true) { 723 WriteByte(buffer); 724 if (buffer & 0x80) 725 buffer >>= 8; 726 else 727 break; 728 } 729 } 730 731 732 void 733 BMidiStore::ReadChunk() 734 { 735 char fourcc[4]; 736 ReadFourCC(fourcc); 737 738 byteCount = Read32Bit(); 739 740 if (strncmp(fourcc, "MTrk", 4) == 0) 741 ReadTrack(); 742 else { 743 TRACE(("Skipping '%c%c%c%c' chunk (%lu bytes)", 744 fourcc[0], fourcc[1], fourcc[2], fourcc[3], byteCount)) 745 746 SkipBytes(byteCount); 747 } 748 } 749 750 751 void 752 BMidiStore::ReadTrack() 753 { 754 uint8 status = 0; 755 uint8 data1; 756 uint8 data2; 757 BMidiEvent* event; 758 759 totalTicks = 0; 760 761 while (byteCount > 0) { 762 uint32 ticks = ReadVarLength(); 763 totalTicks += ticks; 764 765 if (PeekByte() & 0x80) 766 status = NextByte(); 767 768 switch (status & 0xF0) { 769 case B_NOTE_OFF: 770 case B_NOTE_ON: 771 case B_KEY_PRESSURE: 772 case B_CONTROL_CHANGE: 773 case B_PITCH_BEND: 774 data1 = NextByte(); 775 data2 = NextByte(); 776 event = new BMidiEvent; 777 event->time = totalTicks; 778 event->ticks = true; 779 event->byte1 = status; 780 event->byte2 = data1; 781 event->byte3 = data2; 782 AddEvent(event); 783 break; 784 785 case B_PROGRAM_CHANGE: 786 case B_CHANNEL_PRESSURE: 787 data1 = NextByte(); 788 event = new BMidiEvent; 789 event->time = totalTicks; 790 event->ticks = true; 791 event->byte1 = status; 792 event->byte2 = data1; 793 AddEvent(event); 794 795 if ((status & 0xF0) == B_PROGRAM_CHANGE) 796 instruments[data1] = true; 797 break; 798 799 case 0xF0: 800 switch (status) { 801 case B_SYS_EX_START: 802 ReadSystemExclusive(); 803 break; 804 805 case B_TUNE_REQUEST: 806 case B_SYS_EX_END: 807 case B_TIMING_CLOCK: 808 case B_START: 809 case B_CONTINUE: 810 case B_STOP: 811 case B_ACTIVE_SENSING: 812 event = new BMidiEvent; 813 event->time = totalTicks; 814 event->ticks = true; 815 event->byte1 = status; 816 AddEvent(event); 817 break; 818 819 case B_MIDI_TIME_CODE: 820 case B_SONG_SELECT: 821 case B_CABLE_MESSAGE: 822 data1 = NextByte(); 823 event = new BMidiEvent; 824 event->time = totalTicks; 825 event->ticks = true; 826 event->byte1 = status; 827 event->byte2 = data1; 828 AddEvent(event); 829 break; 830 831 case B_SONG_POSITION: 832 data1 = NextByte(); 833 data2 = NextByte(); 834 event = new BMidiEvent; 835 event->time = totalTicks; 836 event->ticks = true; 837 event->byte1 = status; 838 event->byte2 = data1; 839 event->byte3 = data2; 840 AddEvent(event); 841 break; 842 843 case B_SYSTEM_RESET: 844 ReadMetaEvent(); 845 break; 846 } 847 break; 848 } 849 850 event = NULL; 851 } 852 853 ++currTrack; 854 } 855 856 857 void 858 BMidiStore::ReadSystemExclusive() 859 { 860 // We do not import sysex's from MIDI files. 861 862 SkipBytes(ReadVarLength()); 863 } 864 865 866 void 867 BMidiStore::ReadMetaEvent() 868 { 869 // We only import the Tempo Change meta event. 870 871 uint8 type = NextByte(); 872 uint32 length = ReadVarLength(); 873 874 if (type == 0x51 && length == 3) { 875 uchar data[3]; 876 data[0] = NextByte(); 877 data[1] = NextByte(); 878 data[2] = NextByte(); 879 uint32 val = (data[0] << 16) | (data[1] << 8) | data[2]; 880 881 BMidiEvent* event = new BMidiEvent; 882 event->time = totalTicks; 883 event->ticks = true; 884 event->byte1 = 0xFF; 885 event->byte2 = 0x51; 886 event->byte3 = 0x03; 887 event->tempo = 60000000 / val; 888 AddEvent(event); 889 } else 890 SkipBytes(length); 891 } 892 893 894 void 895 BMidiStore::WriteTrack() 896 { 897 WriteFourCC('M', 'T', 'r', 'k'); 898 off_t lengthPos = file->Position(); 899 Write32Bit(0); 900 901 byteCount = 0; 902 uint32 oldTime = 0; 903 uint32 newTime; 904 905 for (uint32 t = 0; t < CountEvents(); ++t) { 906 BMidiEvent* event = EventAt(t); 907 908 if (event->ticks) 909 newTime = event->time; 910 else 911 newTime = MillisecondsToTicks(event->time); 912 913 if (t == 0) 914 WriteVarLength(0); 915 else 916 WriteVarLength(newTime - oldTime); 917 918 oldTime = newTime; 919 920 switch (event->byte1 & 0xF0) { 921 case B_NOTE_OFF: 922 case B_NOTE_ON: 923 case B_KEY_PRESSURE: 924 case B_CONTROL_CHANGE: 925 case B_PITCH_BEND: 926 WriteByte(event->byte1); 927 WriteByte(event->byte2); 928 WriteByte(event->byte3); 929 break; 930 931 case B_PROGRAM_CHANGE: 932 case B_CHANNEL_PRESSURE: 933 WriteByte(event->byte1); 934 WriteByte(event->byte2); 935 break; 936 937 case 0xF0: 938 switch (event->byte1) { 939 case B_SYS_EX_START: 940 // We do not export sysex's. 941 break; 942 943 case B_TUNE_REQUEST: 944 case B_SYS_EX_END: 945 case B_TIMING_CLOCK: 946 case B_START: 947 case B_CONTINUE: 948 case B_STOP: 949 case B_ACTIVE_SENSING: 950 WriteByte(event->byte1); 951 break; 952 953 case B_MIDI_TIME_CODE: 954 case B_SONG_SELECT: 955 case B_CABLE_MESSAGE: 956 WriteByte(event->byte1); 957 WriteByte(event->byte2); 958 break; 959 960 case B_SONG_POSITION: 961 WriteByte(event->byte1); 962 WriteByte(event->byte2); 963 WriteByte(event->byte3); 964 break; 965 966 case B_SYSTEM_RESET: 967 WriteMetaEvent(event); 968 break; 969 } 970 break; 971 } 972 } 973 974 WriteVarLength(0); 975 WriteByte(0xFF); // the end-of-track 976 WriteByte(0x2F); // marker is required 977 WriteByte(0x00); 978 979 file->Seek(lengthPos, SEEK_SET); 980 Write32Bit(byteCount); 981 file->Seek(0, SEEK_END); 982 } 983 984 985 void 986 BMidiStore::WriteMetaEvent(BMidiEvent* event) 987 { 988 // We only export the Tempo Change meta event. 989 990 if (event->byte2 == 0x51 && event->byte3 == 0x03) { 991 uint32 val = 60000000 / event->tempo; 992 993 WriteByte(0xFF); 994 WriteByte(0x51); 995 WriteByte(0x03); 996 WriteByte(val >> 16); 997 WriteByte(val >> 8); 998 WriteByte(val); 999 } 1000 } 1001 1002