tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / midi / MidiStore.cpp
blob51ec5a56b7caab9b722f929577decb3c9d1190dc
1 /*
2 * Copyright 2005-2006, Haiku.
3 *
4 * Copyright (c) 2002-2004 Matthijs Hollemans
5 * Copyright (c) 2002 Jerome Leveque
6 * Copyright (c) 2002 Paul Stadler
7 * Distributed under the terms of the MIT License.
9 * Authors:
10 * Matthijs Hollemans
11 * Jérôme Leveque
12 * Paul Stadler
15 #include <File.h>
16 #include <List.h>
17 #include <MidiDefs.h>
18 #include <MidiStore.h>
19 #include <stdlib.h>
20 #include <string.h>
22 #include "debug.h"
25 struct BMidiEvent {
26 BMidiEvent()
28 byte1 = 0;
29 byte2 = 0;
30 byte3 = 0;
31 data = NULL;
32 length = 0;
35 ~BMidiEvent()
37 free(data);
40 uint32 time; // either ticks or milliseconds
41 bool ticks; // event is from MIDI file
42 uchar byte1;
43 uchar byte2;
44 uchar byte3;
45 void* data; // sysex data
46 size_t length; // sysex data size
47 int32 tempo; // beats per minute
51 static int
52 compare_events(const void* event1, const void* event2)
54 BMidiEvent* e1 = *((BMidiEvent**) event1);
55 BMidiEvent* e2 = *((BMidiEvent**) event2);
57 return (e1->time - e2->time);
61 // #pragma mark -
64 BMidiStore::BMidiStore()
66 fEvents = new BList;
67 fCurrentEvent = 0;
68 fStartTime = 0;
69 fNeedsSorting = false;
70 fBeatsPerMinute = 60;
71 fTicksPerBeat = 240;
72 fFile = NULL;
73 fHookFunc = NULL;
74 fLooping = false;
75 fPaused = false;
76 fFinished = false;
77 fInstruments = new bool[128];
81 BMidiStore::~BMidiStore()
83 for (int32 t = 0; t < fEvents->CountItems(); ++t) {
84 delete EventAt(t);
87 delete fEvents;
88 delete[] fInstruments;
92 void
93 BMidiStore::NoteOff(uchar channel, uchar note, uchar velocity,
94 uint32 time)
96 BMidiEvent* event = new BMidiEvent;
97 event->time = time;
98 event->ticks = false;
99 event->byte1 = B_NOTE_OFF | (channel - 1);
100 event->byte2 = note;
101 event->byte3 = velocity;
102 AddEvent(event);
106 void
107 BMidiStore::NoteOn(uchar channel, uchar note,
108 uchar velocity, uint32 time)
110 BMidiEvent* event = new BMidiEvent;
111 event->time = time;
112 event->ticks = false;
113 event->byte1 = B_NOTE_ON | (channel - 1);
114 event->byte2 = note;
115 event->byte3 = velocity;
116 AddEvent(event);
120 void
121 BMidiStore::KeyPressure(uchar channel, uchar note,
122 uchar pressure, uint32 time)
124 BMidiEvent* event = new BMidiEvent;
125 event->time = time;
126 event->ticks = false;
127 event->byte1 = B_KEY_PRESSURE | (channel - 1);
128 event->byte2 = note;
129 event->byte3 = pressure;
130 AddEvent(event);
134 void
135 BMidiStore::ControlChange(uchar channel, uchar controlNumber,
136 uchar controlValue, uint32 time)
138 BMidiEvent* event = new BMidiEvent;
139 event->time = time;
140 event->ticks = false;
141 event->byte1 = B_CONTROL_CHANGE | (channel - 1);
142 event->byte2 = controlNumber;
143 event->byte3 = controlValue;
144 AddEvent(event);
148 void
149 BMidiStore::ProgramChange(uchar channel, uchar programNumber,
150 uint32 time)
152 BMidiEvent* event = new BMidiEvent;
153 event->time = time;
154 event->ticks = false;
155 event->byte1 = B_PROGRAM_CHANGE | (channel - 1);
156 event->byte2 = programNumber;
157 AddEvent(event);
161 void
162 BMidiStore::ChannelPressure(uchar channel, uchar pressure, uint32 time)
164 BMidiEvent* event = new BMidiEvent;
165 event->time = time;
166 event->ticks = false;
167 event->byte1 = B_CHANNEL_PRESSURE | (channel - 1);
168 event->byte2 = pressure;
169 AddEvent(event);
173 void
174 BMidiStore::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
176 BMidiEvent* event = new BMidiEvent;
177 event->time = time;
178 event->ticks = false;
179 event->byte1 = B_PITCH_BEND | (channel - 1);
180 event->byte2 = lsb;
181 event->byte3 = msb;
182 AddEvent(event);
186 void
187 BMidiStore::SystemExclusive(void* data, size_t length, uint32 time)
189 BMidiEvent* event = new BMidiEvent;
190 event->time = time;
191 event->ticks = false;
192 event->byte1 = B_SYS_EX_START;
193 event->data = malloc(length);
194 event->length = length;
195 memcpy(event->data, data, length);
196 AddEvent(event);
200 void
201 BMidiStore::SystemCommon(uchar status, uchar data1,
202 uchar data2, uint32 time)
204 BMidiEvent* event = new BMidiEvent;
205 event->time = time;
206 event->ticks = false;
207 event->byte1 = status;
208 event->byte2 = data1;
209 event->byte3 = data2;
210 AddEvent(event);
214 void
215 BMidiStore::SystemRealTime(uchar status, uint32 time)
217 BMidiEvent* event = new BMidiEvent;
218 event->time = time;
219 event->ticks = false;
220 event->byte1 = status;
221 AddEvent(event);
225 void
226 BMidiStore::TempoChange(int32 beatsPerMinute, uint32 time)
228 BMidiEvent* event = new BMidiEvent;
229 event->time = time;
230 event->ticks = false;
231 event->byte1 = 0xFF;
232 event->byte2 = 0x51;
233 event->byte3 = 0x03;
234 event->tempo = beatsPerMinute;
235 AddEvent(event);
239 status_t
240 BMidiStore::Import(const entry_ref* ref)
242 memset(fInstruments, 0, 128 * sizeof(bool));
244 try {
245 fFile = new BFile(ref, B_READ_ONLY);
246 if (fFile->InitCheck() != B_OK)
247 throw fFile->InitCheck();
249 char fourcc[4];
250 ReadFourCC(fourcc);
251 if (strncmp(fourcc, "MThd", 4) != 0)
252 throw (status_t) B_BAD_MIDI_DATA;
254 if (Read32Bit() != 6)
255 throw (status_t) B_BAD_MIDI_DATA;
257 fFormat = Read16Bit();
258 fNumTracks = Read16Bit();
259 fTicksPerBeat = Read16Bit();
261 if (fTicksPerBeat & 0x8000) {
262 // we don't support SMPTE time codes,
263 // only ticks per quarter note
264 fTicksPerBeat = 240;
267 fCurrTrack = 0;
268 while (fCurrTrack < fNumTracks) {
269 ReadChunk();
271 } catch (status_t e) {
272 delete fFile;
273 fFile = NULL;
274 return e;
277 SortEvents(true);
279 delete fFile;
280 fFile = NULL;
281 return B_OK;
285 status_t
286 BMidiStore::Export(const entry_ref* ref, int32 format)
288 try {
289 fFile = new BFile(ref, B_READ_WRITE);
290 if (fFile->InitCheck() != B_OK)
291 throw fFile->InitCheck();
293 SortEvents(true);
295 WriteFourCC('M', 'T', 'h', 'd');
296 Write32Bit(6);
297 Write16Bit(0); // we do only format 0
298 Write16Bit(1);
299 Write16Bit(fTicksPerBeat);
301 WriteTrack();
302 } catch (status_t e) {
303 delete fFile;
304 fFile = NULL;
305 return e;
308 delete fFile;
309 fFile = NULL;
310 return B_OK;
314 void
315 BMidiStore::SortEvents(bool force)
317 if (force || fNeedsSorting) {
318 fEvents->SortItems(compare_events);
319 fNeedsSorting = false;
324 uint32
325 BMidiStore::CountEvents() const
327 return fEvents->CountItems();
331 uint32
332 BMidiStore::CurrentEvent() const
334 return fCurrentEvent;
338 void
339 BMidiStore::SetCurrentEvent(uint32 eventNumber)
341 fCurrentEvent = eventNumber;
345 uint32
346 BMidiStore::DeltaOfEvent(uint32 eventNumber) const
348 // Even though the BeBook says that the delta is the time span between
349 // an event and the first event in the list, this doesn't appear to be
350 // true for events that were captured from other BMidi objects such as
351 // BMidiPort. For those events, we return the absolute timestamp. The
352 // BeBook is correct for events from MIDI files, though.
354 BMidiEvent* event = EventAt(eventNumber);
355 if (event != NULL)
356 return GetEventTime(event);
358 return 0;
362 uint32
363 BMidiStore::EventAtDelta(uint32 time) const
365 for (int32 t = 0; t < fEvents->CountItems(); ++t) {
366 if (GetEventTime(EventAt(t)) >= time)
367 return t;
370 return 0;
374 uint32
375 BMidiStore::BeginTime() const
377 return fStartTime;
381 void
382 BMidiStore::SetTempo(int32 beatsPerMinute_)
384 fBeatsPerMinute = beatsPerMinute_;
388 int32
389 BMidiStore::Tempo() const
391 return fBeatsPerMinute;
395 void BMidiStore::_ReservedMidiStore1() { }
396 void BMidiStore::_ReservedMidiStore2() { }
397 void BMidiStore::_ReservedMidiStore3() { }
400 void
401 BMidiStore::Run()
403 // This rather compilicated Run() loop is not only used by BMidiStore
404 // but also by BMidiSynthFile. The "paused", "finished", and "looping"
405 // flags, and the "stop hook" are especially provided for the latter.
407 fPaused = false;
408 fFinished = false;
410 int32 timeAdjust = 0;
411 uint32 baseTime = 0;
412 bool firstEvent = true;
413 bool resetTime = false;
415 while (KeepRunning()) {
416 if (fPaused) {
417 resetTime = true;
418 snooze(100000);
419 continue;
422 BMidiEvent* event = EventAt(fCurrentEvent);
424 if (event == NULL) {
425 // no more events
426 if (fLooping) {
427 resetTime = true;
428 fCurrentEvent = 0;
429 continue;
431 break;
434 if (firstEvent) {
435 fStartTime = B_NOW;
436 baseTime = fStartTime;
437 } else if (resetTime)
438 baseTime = B_NOW;
440 if (firstEvent || resetTime) {
441 timeAdjust = baseTime - GetEventTime(event);
442 SprayEvent(event, baseTime);
443 firstEvent = false;
444 resetTime = false;
445 } else
446 SprayEvent(event, GetEventTime(event) + timeAdjust);
448 ++fCurrentEvent;
451 fFinished = true;
452 fPaused = false;
454 if (fHookFunc != NULL)
455 (*fHookFunc)(fHookArg);
459 void
460 BMidiStore::AddEvent(BMidiEvent* event)
462 fEvents->AddItem(event);
463 fNeedsSorting = true;
467 void
468 BMidiStore::SprayEvent(const BMidiEvent* event, uint32 time)
470 uchar byte1 = event->byte1;
471 uchar byte2 = event->byte2;
472 uchar byte3 = event->byte3;
474 switch (byte1 & 0xF0) {
475 case B_NOTE_OFF:
476 SprayNoteOff((byte1 & 0x0F) + 1, byte2, byte3, time);
477 return;
479 case B_NOTE_ON:
480 SprayNoteOn((byte1 & 0x0F) + 1, byte2, byte3, time);
481 return;
483 case B_KEY_PRESSURE:
484 SprayKeyPressure((byte1 & 0x0F) + 1, byte2, byte3, time);
485 return;
487 case B_CONTROL_CHANGE:
488 SprayControlChange((byte1 & 0x0F) + 1, byte2, byte3, time);
489 return;
491 case B_PROGRAM_CHANGE:
492 SprayProgramChange((byte1 & 0x0F) + 1, byte2, time);
493 return;
495 case B_CHANNEL_PRESSURE:
496 SprayChannelPressure((byte1 & 0x0F) + 1, byte2, time);
497 return;
499 case B_PITCH_BEND:
500 SprayPitchBend((byte1 & 0x0F) + 1, byte2, byte3, time);
501 return;
503 case 0xF0:
504 switch (byte1) {
505 case B_SYS_EX_START:
506 SpraySystemExclusive(event->data, event->length, time);
507 return;
509 case B_MIDI_TIME_CODE:
510 case B_SONG_POSITION:
511 case B_SONG_SELECT:
512 case B_CABLE_MESSAGE:
513 case B_TUNE_REQUEST:
514 case B_SYS_EX_END:
515 SpraySystemCommon(byte1, byte2, byte3, time);
516 return;
518 case B_TIMING_CLOCK:
519 case B_START:
520 case B_CONTINUE:
521 case B_STOP:
522 case B_ACTIVE_SENSING:
523 SpraySystemRealTime(byte1, time);
524 return;
526 case B_SYSTEM_RESET:
527 if (byte2 == 0x51 && byte3 == 0x03) {
528 SprayTempoChange(event->tempo, time);
529 fBeatsPerMinute = event->tempo;
530 } else
531 SpraySystemRealTime(byte1, time);
532 return;
534 return;
539 BMidiEvent*
540 BMidiStore::EventAt(int32 index) const
542 return (BMidiEvent*)fEvents->ItemAt(index);
546 uint32
547 BMidiStore::GetEventTime(const BMidiEvent* event) const
549 if (event->ticks)
550 return TicksToMilliseconds(event->time);
552 return event->time;
556 uint32
557 BMidiStore::TicksToMilliseconds(uint32 ticks) const
559 return ((uint64)ticks * 60000) / (fBeatsPerMinute * fTicksPerBeat);
563 uint32
564 BMidiStore::MillisecondsToTicks(uint32 ms) const
566 return ((uint64)ms * fBeatsPerMinute * fTicksPerBeat) / 60000;
570 void
571 BMidiStore::ReadFourCC(char* fourcc)
573 if (fFile->Read(fourcc, 4) != 4)
574 throw (status_t) B_BAD_MIDI_DATA;
578 void
579 BMidiStore::WriteFourCC(char a, char b, char c, char d)
581 char fourcc[4] = { a, b, c, d };
583 if (fFile->Write(fourcc, 4) != 4)
584 throw (status_t) B_ERROR;
588 uint32
589 BMidiStore::Read32Bit()
591 uint8 buf[4];
592 if (fFile->Read(buf, 4) != 4)
593 throw (status_t) B_BAD_MIDI_DATA;
595 return (buf[0] << 24L) | (buf[1] << 16L) | (buf[2] << 8L) | buf[3];
599 void
600 BMidiStore::Write32Bit(uint32 val)
602 uint8 buf[4];
603 buf[0] = (val >> 24) & 0xFF;
604 buf[1] = (val >> 16) & 0xFF;
605 buf[2] = (val >> 8) & 0xFF;
606 buf[3] = val & 0xFF;
608 if (fFile->Write(buf, 4) != 4)
609 throw (status_t) B_ERROR;
613 uint16
614 BMidiStore::Read16Bit()
616 uint8 buf[2];
617 if (fFile->Read(buf, 2) != 2)
618 throw (status_t) B_BAD_MIDI_DATA;
620 return (buf[0] << 8) | buf[1];
624 void
625 BMidiStore::Write16Bit(uint16 val)
627 uint8 buf[2];
628 buf[0] = (val >> 8) & 0xFF;
629 buf[1] = val & 0xFF;
631 if (fFile->Write(buf, 2) != 2)
632 throw (status_t) B_ERROR;
636 uint8
637 BMidiStore::PeekByte()
639 uint8 buf;
640 if (fFile->Read(&buf, 1) != 1)
641 throw (status_t) B_BAD_MIDI_DATA;
643 if (fFile->Seek(-1, SEEK_CUR) < 0)
644 throw (status_t) B_ERROR;
646 return buf;
650 uint8
651 BMidiStore::NextByte()
653 uint8 buf;
654 if (fFile->Read(&buf, 1) != 1)
655 throw (status_t) B_BAD_MIDI_DATA;
657 --fByteCount;
658 return buf;
662 void
663 BMidiStore::WriteByte(uint8 val)
665 if (fFile->Write(&val, 1) != 1)
666 throw (status_t) B_ERROR;
668 ++fByteCount;
672 void
673 BMidiStore::SkipBytes(uint32 length)
675 if (fFile->Seek(length, SEEK_CUR) < 0) {
676 throw (status_t) B_BAD_MIDI_DATA;
679 fByteCount -= length;
683 uint32
684 BMidiStore::ReadVarLength()
686 uint32 val;
687 uint8 byte;
689 if ((val = NextByte()) & 0x80) {
690 val &= 0x7F;
691 do {
692 val = (val << 7) + ((byte = NextByte()) & 0x7F);
693 } while (byte & 0x80);
696 return val;
700 void
701 BMidiStore::WriteVarLength(uint32 val)
703 uint32 buffer = val & 0x7F;
705 while ((val >>= 7) != 0) {
706 buffer <<= 8;
707 buffer |= ((val & 0x7F) | 0x80);
710 while (true) {
711 WriteByte(buffer);
712 if (buffer & 0x80)
713 buffer >>= 8;
714 else
715 break;
720 void
721 BMidiStore::ReadChunk()
723 char fourcc[4];
724 ReadFourCC(fourcc);
726 fByteCount = Read32Bit();
728 if (strncmp(fourcc, "MTrk", 4) == 0)
729 ReadTrack();
730 else {
731 TRACE(("Skipping '%c%c%c%c' chunk (%" B_PRIu32 " bytes)",
732 fourcc[0], fourcc[1], fourcc[2], fourcc[3], fByteCount))
734 SkipBytes(fByteCount);
739 void
740 BMidiStore::ReadTrack()
742 uint8 status = 0;
743 uint8 data1;
744 uint8 data2;
745 BMidiEvent* event;
747 fTotalTicks = 0;
749 while (fByteCount > 0) {
750 uint32 ticks = ReadVarLength();
751 fTotalTicks += ticks;
753 if (PeekByte() & 0x80)
754 status = NextByte();
756 switch (status & 0xF0) {
757 case B_NOTE_OFF:
758 case B_NOTE_ON:
759 case B_KEY_PRESSURE:
760 case B_CONTROL_CHANGE:
761 case B_PITCH_BEND:
762 data1 = NextByte();
763 data2 = NextByte();
764 event = new BMidiEvent;
765 event->time = fTotalTicks;
766 event->ticks = true;
767 event->byte1 = status;
768 event->byte2 = data1;
769 event->byte3 = data2;
770 AddEvent(event);
771 break;
773 case B_PROGRAM_CHANGE:
774 case B_CHANNEL_PRESSURE:
775 data1 = NextByte();
776 event = new BMidiEvent;
777 event->time = fTotalTicks;
778 event->ticks = true;
779 event->byte1 = status;
780 event->byte2 = data1;
781 AddEvent(event);
783 if ((status & 0xF0) == B_PROGRAM_CHANGE)
784 fInstruments[data1] = true;
785 break;
787 case 0xF0:
788 switch (status) {
789 case B_SYS_EX_START:
790 ReadSystemExclusive();
791 break;
793 case B_TUNE_REQUEST:
794 case B_SYS_EX_END:
795 case B_TIMING_CLOCK:
796 case B_START:
797 case B_CONTINUE:
798 case B_STOP:
799 case B_ACTIVE_SENSING:
800 event = new BMidiEvent;
801 event->time = fTotalTicks;
802 event->ticks = true;
803 event->byte1 = status;
804 AddEvent(event);
805 break;
807 case B_MIDI_TIME_CODE:
808 case B_SONG_SELECT:
809 case B_CABLE_MESSAGE:
810 data1 = NextByte();
811 event = new BMidiEvent;
812 event->time = fTotalTicks;
813 event->ticks = true;
814 event->byte1 = status;
815 event->byte2 = data1;
816 AddEvent(event);
817 break;
819 case B_SONG_POSITION:
820 data1 = NextByte();
821 data2 = NextByte();
822 event = new BMidiEvent;
823 event->time = fTotalTicks;
824 event->ticks = true;
825 event->byte1 = status;
826 event->byte2 = data1;
827 event->byte3 = data2;
828 AddEvent(event);
829 break;
831 case B_SYSTEM_RESET:
832 ReadMetaEvent();
833 break;
835 break;
838 event = NULL;
841 ++fCurrTrack;
845 void
846 BMidiStore::ReadSystemExclusive()
848 // We do not import sysex's from MIDI files.
850 SkipBytes(ReadVarLength());
854 void
855 BMidiStore::ReadMetaEvent()
857 // We only import the Tempo Change meta event.
859 uint8 type = NextByte();
860 uint32 length = ReadVarLength();
862 if (type == 0x51 && length == 3) {
863 uchar data[3];
864 data[0] = NextByte();
865 data[1] = NextByte();
866 data[2] = NextByte();
867 uint32 val = (data[0] << 16) | (data[1] << 8) | data[2];
869 BMidiEvent* event = new BMidiEvent;
870 event->time = fTotalTicks;
871 event->ticks = true;
872 event->byte1 = 0xFF;
873 event->byte2 = 0x51;
874 event->byte3 = 0x03;
875 event->tempo = 60000000 / val;
876 AddEvent(event);
877 } else
878 SkipBytes(length);
882 void
883 BMidiStore::WriteTrack()
885 WriteFourCC('M', 'T', 'r', 'k');
886 off_t lengthPos = fFile->Position();
887 Write32Bit(0);
889 fByteCount = 0;
890 uint32 oldTime = 0;
891 uint32 newTime;
893 for (uint32 t = 0; t < CountEvents(); ++t) {
894 BMidiEvent* event = EventAt(t);
896 if (event->ticks)
897 newTime = event->time;
898 else
899 newTime = MillisecondsToTicks(event->time);
901 if (t == 0)
902 WriteVarLength(0);
903 else
904 WriteVarLength(newTime - oldTime);
906 oldTime = newTime;
908 switch (event->byte1 & 0xF0) {
909 case B_NOTE_OFF:
910 case B_NOTE_ON:
911 case B_KEY_PRESSURE:
912 case B_CONTROL_CHANGE:
913 case B_PITCH_BEND:
914 WriteByte(event->byte1);
915 WriteByte(event->byte2);
916 WriteByte(event->byte3);
917 break;
919 case B_PROGRAM_CHANGE:
920 case B_CHANNEL_PRESSURE:
921 WriteByte(event->byte1);
922 WriteByte(event->byte2);
923 break;
925 case 0xF0:
926 switch (event->byte1) {
927 case B_SYS_EX_START:
928 // We do not export sysex's.
929 break;
931 case B_TUNE_REQUEST:
932 case B_SYS_EX_END:
933 case B_TIMING_CLOCK:
934 case B_START:
935 case B_CONTINUE:
936 case B_STOP:
937 case B_ACTIVE_SENSING:
938 WriteByte(event->byte1);
939 break;
941 case B_MIDI_TIME_CODE:
942 case B_SONG_SELECT:
943 case B_CABLE_MESSAGE:
944 WriteByte(event->byte1);
945 WriteByte(event->byte2);
946 break;
948 case B_SONG_POSITION:
949 WriteByte(event->byte1);
950 WriteByte(event->byte2);
951 WriteByte(event->byte3);
952 break;
954 case B_SYSTEM_RESET:
955 WriteMetaEvent(event);
956 break;
958 break;
962 WriteVarLength(0);
963 WriteByte(0xFF); // the end-of-track
964 WriteByte(0x2F); // marker is required
965 WriteByte(0x00);
967 fFile->Seek(lengthPos, SEEK_SET);
968 Write32Bit(fByteCount);
969 fFile->Seek(0, SEEK_END);
973 void
974 BMidiStore::WriteMetaEvent(BMidiEvent* event)
976 // We only export the Tempo Change meta event.
978 if (event->byte2 == 0x51 && event->byte3 == 0x03) {
979 uint32 val = 60000000 / event->tempo;
981 WriteByte(0xFF);
982 WriteByte(0x51);
983 WriteByte(0x03);
984 WriteByte(val >> 16);
985 WriteByte(val >> 8);
986 WriteByte(val);