xref: /haiku/src/kits/midi/MidiStore.cpp (revision 1a7bcf6962e1c99906cce0fe602e08c3fcda46f6)
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.
8  *
9  * Authors:
10  *		Matthijs Hollemans
11  *		Jérôme Leveque
12  *		Paul Stadler
13  */
14 
15 #include <File.h>
16 #include <List.h>
17 #include <MidiDefs.h>
18 #include <MidiStore.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #include "debug.h"
23 
24 
25 struct BMidiEvent {
BMidiEventBMidiEvent26 	BMidiEvent()
27 	{
28 		byte1  = 0;
29 		byte2  = 0;
30 		byte3  = 0;
31 		data   = NULL;
32 		length = 0;
33 	}
34 
~BMidiEventBMidiEvent35 	~BMidiEvent()
36 	{
37 		free(data);
38 	}
39 
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
48 };
49 
50 
51 static int
compare_events(const void * event1,const void * event2)52 compare_events(const void* event1, const void* event2)
53 {
54 	BMidiEvent* e1 = *((BMidiEvent**) event1);
55 	BMidiEvent* e2 = *((BMidiEvent**) event2);
56 
57 	return (e1->time - e2->time);
58 }
59 
60 
61 //	#pragma mark -
62 
63 
BMidiStore()64 BMidiStore::BMidiStore()
65 {
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];
78 }
79 
80 
~BMidiStore()81 BMidiStore::~BMidiStore()
82 {
83 	for (int32 t = 0; t < fEvents->CountItems(); ++t) {
84 		delete EventAt(t);
85 	}
86 
87 	delete fEvents;
88 	delete[] fInstruments;
89 }
90 
91 
92 void
NoteOff(uchar channel,uchar note,uchar velocity,uint32 time)93 BMidiStore::NoteOff(uchar channel, uchar note, uchar velocity,
94 	uint32 time)
95 {
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);
103 }
104 
105 
106 void
NoteOn(uchar channel,uchar note,uchar velocity,uint32 time)107 BMidiStore::NoteOn(uchar channel, uchar note,
108 	uchar velocity, uint32 time)
109 {
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);
117 }
118 
119 
120 void
KeyPressure(uchar channel,uchar note,uchar pressure,uint32 time)121 BMidiStore::KeyPressure(uchar channel, uchar note,
122 	uchar pressure, uint32 time)
123 {
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);
131 }
132 
133 
134 void
ControlChange(uchar channel,uchar controlNumber,uchar controlValue,uint32 time)135 BMidiStore::ControlChange(uchar channel, uchar controlNumber,
136 	uchar controlValue, uint32 time)
137 {
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);
145 }
146 
147 
148 void
ProgramChange(uchar channel,uchar programNumber,uint32 time)149 BMidiStore::ProgramChange(uchar channel, uchar programNumber,
150 	uint32 time)
151 {
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);
158 }
159 
160 
161 void
ChannelPressure(uchar channel,uchar pressure,uint32 time)162 BMidiStore::ChannelPressure(uchar channel, uchar pressure, uint32 time)
163 {
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);
170 }
171 
172 
173 void
PitchBend(uchar channel,uchar lsb,uchar msb,uint32 time)174 BMidiStore::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
175 {
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);
183 }
184 
185 
186 void
SystemExclusive(void * data,size_t length,uint32 time)187 BMidiStore::SystemExclusive(void* data, size_t length, uint32 time)
188 {
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);
197 }
198 
199 
200 void
SystemCommon(uchar status,uchar data1,uchar data2,uint32 time)201 BMidiStore::SystemCommon(uchar status, uchar data1,
202 	uchar data2, uint32 time)
203 {
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);
211 }
212 
213 
214 void
SystemRealTime(uchar status,uint32 time)215 BMidiStore::SystemRealTime(uchar status, uint32 time)
216 {
217 	BMidiEvent* event = new BMidiEvent;
218 	event->time  = time;
219 	event->ticks = false;
220 	event->byte1 = status;
221 	AddEvent(event);
222 }
223 
224 
225 void
TempoChange(int32 beatsPerMinute,uint32 time)226 BMidiStore::TempoChange(int32 beatsPerMinute, uint32 time)
227 {
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);
236 }
237 
238 
239 status_t
Import(const entry_ref * ref)240 BMidiStore::Import(const entry_ref* ref)
241 {
242 	memset(fInstruments, 0, 128 * sizeof(bool));
243 
244 	try {
245 		fFile = new BFile(ref, B_READ_ONLY);
246 		if (fFile->InitCheck() != B_OK)
247 			throw fFile->InitCheck();
248 
249 		char fourcc[4];
250 		ReadFourCC(fourcc);
251 		if (strncmp(fourcc, "MThd", 4) != 0)
252 			throw (status_t) B_BAD_MIDI_DATA;
253 
254 		if (Read32Bit() != 6)
255 			throw (status_t) B_BAD_MIDI_DATA;
256 
257 		fFormat = Read16Bit();
258 		fNumTracks = Read16Bit();
259 		fTicksPerBeat = Read16Bit();
260 
261 		if (fTicksPerBeat & 0x8000) {
262 			// we don't support SMPTE time codes,
263 			// only ticks per quarter note
264 			fTicksPerBeat = 240;
265 		}
266 
267 		fCurrTrack = 0;
268 		while (fCurrTrack < fNumTracks) {
269 			ReadChunk();
270 		}
271 	} catch (status_t e) {
272 		delete fFile;
273 		fFile = NULL;
274 		return e;
275 	}
276 
277 	SortEvents(true);
278 
279 	delete fFile;
280 	fFile = NULL;
281 	return B_OK;
282 }
283 
284 
285 status_t
Export(const entry_ref * ref,int32 format)286 BMidiStore::Export(const entry_ref* ref, int32 format)
287 {
288 	try {
289 		fFile = new BFile(ref, B_READ_WRITE);
290 		if (fFile->InitCheck() != B_OK)
291 			throw fFile->InitCheck();
292 
293 		SortEvents(true);
294 
295 		WriteFourCC('M', 'T', 'h', 'd');
296 		Write32Bit(6);
297 		Write16Bit(0);  // we do only format 0
298 		Write16Bit(1);
299 		Write16Bit(fTicksPerBeat);
300 
301 		WriteTrack();
302 	} catch (status_t e) {
303 		delete fFile;
304 		fFile = NULL;
305 		return e;
306 	}
307 
308 	delete fFile;
309 	fFile = NULL;
310 	return B_OK;
311 }
312 
313 
314 void
SortEvents(bool force)315 BMidiStore::SortEvents(bool force)
316 {
317 	if (force || fNeedsSorting) {
318 		fEvents->SortItems(compare_events);
319 		fNeedsSorting = false;
320 	}
321 }
322 
323 
324 uint32
CountEvents() const325 BMidiStore::CountEvents() const
326 {
327 	return fEvents->CountItems();
328 }
329 
330 
331 uint32
CurrentEvent() const332 BMidiStore::CurrentEvent() const
333 {
334 	return fCurrentEvent;
335 }
336 
337 
338 void
SetCurrentEvent(uint32 eventNumber)339 BMidiStore::SetCurrentEvent(uint32 eventNumber)
340 {
341 	fCurrentEvent = eventNumber;
342 }
343 
344 
345 uint32
DeltaOfEvent(uint32 eventNumber) const346 BMidiStore::DeltaOfEvent(uint32 eventNumber) const
347 {
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.
353 
354 	BMidiEvent* event = EventAt(eventNumber);
355 	if (event != NULL)
356 		return GetEventTime(event);
357 
358 	return 0;
359 }
360 
361 
362 uint32
EventAtDelta(uint32 time) const363 BMidiStore::EventAtDelta(uint32 time) const
364 {
365 	for (int32 t = 0; t < fEvents->CountItems(); ++t) {
366 		if (GetEventTime(EventAt(t)) >= time)
367 			return t;
368 	}
369 
370 	return 0;
371 }
372 
373 
374 uint32
BeginTime() const375 BMidiStore::BeginTime() const
376 {
377 	return fStartTime;
378 }
379 
380 
381 void
SetTempo(int32 beatsPerMinute_)382 BMidiStore::SetTempo(int32 beatsPerMinute_)
383 {
384 	fBeatsPerMinute = beatsPerMinute_;
385 }
386 
387 
388 int32
Tempo() const389 BMidiStore::Tempo() const
390 {
391 	return fBeatsPerMinute;
392 }
393 
394 
_ReservedMidiStore1()395 void BMidiStore::_ReservedMidiStore1() { }
_ReservedMidiStore2()396 void BMidiStore::_ReservedMidiStore2() { }
_ReservedMidiStore3()397 void BMidiStore::_ReservedMidiStore3() { }
398 
399 
400 void
Run()401 BMidiStore::Run()
402 {
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.
406 
407 	fPaused = false;
408 	fFinished = false;
409 
410 	int32 timeAdjust = 0;
411 	uint32 baseTime = 0;
412 	bool firstEvent = true;
413 	bool resetTime = false;
414 
415 	while (KeepRunning()) {
416 		if (fPaused) {
417 			resetTime = true;
418 			snooze(100000);
419 			continue;
420 		}
421 
422 		BMidiEvent* event = EventAt(fCurrentEvent);
423 
424 		if (event == NULL) {
425 			// no more events
426 			if (fLooping) {
427 				resetTime = true;
428 				fCurrentEvent = 0;
429 				continue;
430 			}
431 			break;
432 		}
433 
434 		if (firstEvent) {
435 			fStartTime = B_NOW;
436 			baseTime = fStartTime;
437 		} else if (resetTime)
438 			baseTime = B_NOW;
439 
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);
447 
448 		++fCurrentEvent;
449 	}
450 
451 	fFinished = true;
452 	fPaused = false;
453 
454 	if (fHookFunc != NULL)
455 		(*fHookFunc)(fHookArg);
456 }
457 
458 
459 void
AddEvent(BMidiEvent * event)460 BMidiStore::AddEvent(BMidiEvent* event)
461 {
462 	fEvents->AddItem(event);
463 	fNeedsSorting = true;
464 }
465 
466 
467 void
SprayEvent(const BMidiEvent * event,uint32 time)468 BMidiStore::SprayEvent(const BMidiEvent* event, uint32 time)
469 {
470 	uchar byte1 = event->byte1;
471 	uchar byte2 = event->byte2;
472 	uchar byte3 = event->byte3;
473 
474 	switch (byte1 & 0xF0) {
475 		case B_NOTE_OFF:
476 			SprayNoteOff((byte1 & 0x0F) + 1, byte2, byte3, time);
477 			return;
478 
479 		case B_NOTE_ON:
480 			SprayNoteOn((byte1 & 0x0F) + 1, byte2, byte3, time);
481 			return;
482 
483 		case B_KEY_PRESSURE:
484 			SprayKeyPressure((byte1 & 0x0F) + 1, byte2, byte3, time);
485 			return;
486 
487 		case B_CONTROL_CHANGE:
488 			SprayControlChange((byte1 & 0x0F) + 1, byte2, byte3, time);
489 			return;
490 
491 		case B_PROGRAM_CHANGE:
492 			SprayProgramChange((byte1 & 0x0F) + 1, byte2, time);
493 			return;
494 
495 		case B_CHANNEL_PRESSURE:
496 			SprayChannelPressure((byte1 & 0x0F) + 1, byte2, time);
497 			return;
498 
499 		case B_PITCH_BEND:
500 			SprayPitchBend((byte1 & 0x0F) + 1, byte2, byte3, time);
501 			return;
502 
503 		case 0xF0:
504 			switch (byte1) {
505 				case B_SYS_EX_START:
506 					SpraySystemExclusive(event->data, event->length, time);
507 					return;
508 
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;
517 
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;
525 
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;
533 			}
534 			return;
535 	}
536 }
537 
538 
539 BMidiEvent*
EventAt(int32 index) const540 BMidiStore::EventAt(int32 index) const
541 {
542 	return (BMidiEvent*)fEvents->ItemAt(index);
543 }
544 
545 
546 uint32
GetEventTime(const BMidiEvent * event) const547 BMidiStore::GetEventTime(const BMidiEvent* event) const
548 {
549 	if (event->ticks)
550 		return TicksToMilliseconds(event->time);
551 
552 	return event->time;
553 }
554 
555 
556 uint32
TicksToMilliseconds(uint32 ticks) const557 BMidiStore::TicksToMilliseconds(uint32 ticks) const
558 {
559 	return ((uint64)ticks * 60000) / (fBeatsPerMinute * fTicksPerBeat);
560 }
561 
562 
563 uint32
MillisecondsToTicks(uint32 ms) const564 BMidiStore::MillisecondsToTicks(uint32 ms) const
565 {
566 	return ((uint64)ms * fBeatsPerMinute * fTicksPerBeat) / 60000;
567 }
568 
569 
570 void
ReadFourCC(char * fourcc)571 BMidiStore::ReadFourCC(char* fourcc)
572 {
573 	if (fFile->Read(fourcc, 4) != 4)
574 		throw (status_t) B_BAD_MIDI_DATA;
575 }
576 
577 
578 void
WriteFourCC(char a,char b,char c,char d)579 BMidiStore::WriteFourCC(char a, char b, char c, char d)
580 {
581 	char fourcc[4] = { a, b, c, d };
582 
583 	if (fFile->Write(fourcc, 4) != 4)
584 		throw (status_t) B_ERROR;
585 }
586 
587 
588 uint32
Read32Bit()589 BMidiStore::Read32Bit()
590 {
591 	uint8 buf[4];
592 	if (fFile->Read(buf, 4) != 4)
593 		throw (status_t) B_BAD_MIDI_DATA;
594 
595 	return (buf[0] << 24L) | (buf[1] << 16L) | (buf[2] << 8L) | buf[3];
596 }
597 
598 
599 void
Write32Bit(uint32 val)600 BMidiStore::Write32Bit(uint32 val)
601 {
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;
607 
608 	if (fFile->Write(buf, 4) != 4)
609 		throw (status_t) B_ERROR;
610 }
611 
612 
613 uint16
Read16Bit()614 BMidiStore::Read16Bit()
615 {
616 	uint8 buf[2];
617 	if (fFile->Read(buf, 2) != 2)
618 		throw (status_t) B_BAD_MIDI_DATA;
619 
620 	return (buf[0] << 8) | buf[1];
621 }
622 
623 
624 void
Write16Bit(uint16 val)625 BMidiStore::Write16Bit(uint16 val)
626 {
627 	uint8 buf[2];
628 	buf[0] = (val >> 8) & 0xFF;
629 	buf[1] = val & 0xFF;
630 
631 	if (fFile->Write(buf, 2) != 2)
632 		throw (status_t) B_ERROR;
633 }
634 
635 
636 uint8
PeekByte()637 BMidiStore::PeekByte()
638 {
639 	uint8 buf;
640 	if (fFile->Read(&buf, 1) != 1)
641 		throw (status_t) B_BAD_MIDI_DATA;
642 
643 	if (fFile->Seek(-1, SEEK_CUR) < 0)
644 		throw (status_t) B_ERROR;
645 
646 	return buf;
647 }
648 
649 
650 uint8
NextByte()651 BMidiStore::NextByte()
652 {
653 	uint8 buf;
654 	if (fFile->Read(&buf, 1) != 1)
655 		throw (status_t) B_BAD_MIDI_DATA;
656 
657 	--fByteCount;
658 	return buf;
659 }
660 
661 
662 void
WriteByte(uint8 val)663 BMidiStore::WriteByte(uint8 val)
664 {
665 	if (fFile->Write(&val, 1) != 1)
666 		throw (status_t) B_ERROR;
667 
668 	++fByteCount;
669 }
670 
671 
672 void
SkipBytes(uint32 length)673 BMidiStore::SkipBytes(uint32 length)
674 {
675 	if (fFile->Seek(length, SEEK_CUR) < 0) {
676 		throw (status_t) B_BAD_MIDI_DATA;
677 	}
678 
679 	fByteCount -= length;
680 }
681 
682 
683 uint32
ReadVarLength()684 BMidiStore::ReadVarLength()
685 {
686 	uint32 val;
687 	uint8 byte;
688 
689 	if ((val = NextByte()) & 0x80) {
690 		val &= 0x7F;
691 		do {
692 			val = (val << 7) + ((byte = NextByte()) & 0x7F);
693 		} while (byte & 0x80);
694 	}
695 
696 	return val;
697 }
698 
699 
700 void
WriteVarLength(uint32 val)701 BMidiStore::WriteVarLength(uint32 val)
702 {
703 	uint32 buffer = val & 0x7F;
704 
705 	while ((val >>= 7) != 0) {
706 		buffer <<= 8;
707 		buffer |= ((val & 0x7F) | 0x80);
708 	}
709 
710 	while (true) {
711 		WriteByte(buffer);
712 		if (buffer & 0x80)
713 			buffer >>= 8;
714 		else
715 			break;
716 	}
717 }
718 
719 
720 void
ReadChunk()721 BMidiStore::ReadChunk()
722 {
723 	char fourcc[4];
724 	ReadFourCC(fourcc);
725 
726 	fByteCount = Read32Bit();
727 
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))
733 
734 		SkipBytes(fByteCount);
735 	}
736 }
737 
738 
739 void
ReadTrack()740 BMidiStore::ReadTrack()
741 {
742 	uint8 status = 0;
743 	uint8 data1;
744 	uint8 data2;
745 	BMidiEvent* event;
746 
747 	fTotalTicks = 0;
748 
749 	while (fByteCount > 0) {
750 		uint32 ticks = ReadVarLength();
751 		fTotalTicks += ticks;
752 
753 		if (PeekByte() & 0x80)
754 			status = NextByte();
755 
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;
772 
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);
782 
783 				if ((status & 0xF0) == B_PROGRAM_CHANGE)
784 					fInstruments[data1] = true;
785 				break;
786 
787 			case 0xF0:
788 				switch (status) {
789 					case B_SYS_EX_START:
790 						ReadSystemExclusive();
791 						break;
792 
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;
806 
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;
818 
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;
830 
831 					case B_SYSTEM_RESET:
832 						ReadMetaEvent();
833 						break;
834 				}
835 				break;
836 		}
837 
838 		event = NULL;
839 	}
840 
841 	++fCurrTrack;
842 }
843 
844 
845 void
ReadSystemExclusive()846 BMidiStore::ReadSystemExclusive()
847 {
848 	// We do not import sysex's from MIDI files.
849 
850 	SkipBytes(ReadVarLength());
851 }
852 
853 
854 void
ReadMetaEvent()855 BMidiStore::ReadMetaEvent()
856 {
857 	// We only import the Tempo Change meta event.
858 
859 	uint8 type = NextByte();
860 	uint32 length = ReadVarLength();
861 
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];
868 
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);
879 }
880 
881 
882 void
WriteTrack()883 BMidiStore::WriteTrack()
884 {
885 	WriteFourCC('M', 'T', 'r', 'k');
886 	off_t lengthPos = fFile->Position();
887 	Write32Bit(0);
888 
889 	fByteCount = 0;
890 	uint32 oldTime = 0;
891 	uint32 newTime;
892 
893 	for (uint32 t = 0; t < CountEvents(); ++t) {
894 		BMidiEvent* event = EventAt(t);
895 
896 		if (event->ticks)
897 			newTime = event->time;
898 		else
899 			newTime = MillisecondsToTicks(event->time);
900 
901 		if (t == 0)
902 			WriteVarLength(0);
903 		else
904 			WriteVarLength(newTime - oldTime);
905 
906 		oldTime = newTime;
907 
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;
918 
919 			case B_PROGRAM_CHANGE:
920 			case B_CHANNEL_PRESSURE:
921 				WriteByte(event->byte1);
922 				WriteByte(event->byte2);
923 				break;
924 
925 			case 0xF0:
926 				switch (event->byte1) {
927 					case B_SYS_EX_START:
928 						// We do not export sysex's.
929 						break;
930 
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;
940 
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;
947 
948 					case B_SONG_POSITION:
949 						WriteByte(event->byte1);
950 						WriteByte(event->byte2);
951 						WriteByte(event->byte3);
952 						break;
953 
954 					case B_SYSTEM_RESET:
955 						WriteMetaEvent(event);
956 						break;
957 				}
958 				break;
959 		}
960 	}
961 
962 	WriteVarLength(0);
963 	WriteByte(0xFF);   // the end-of-track
964 	WriteByte(0x2F);   // marker is required
965 	WriteByte(0x00);
966 
967 	fFile->Seek(lengthPos, SEEK_SET);
968 	Write32Bit(fByteCount);
969 	fFile->Seek(0, SEEK_END);
970 }
971 
972 
973 void
WriteMetaEvent(BMidiEvent * event)974 BMidiStore::WriteMetaEvent(BMidiEvent* event)
975 {
976 	// We only export the Tempo Change meta event.
977 
978 	if (event->byte2 == 0x51 && event->byte3 == 0x03) {
979 		uint32 val = 60000000 / event->tempo;
980 
981 		WriteByte(0xFF);
982 		WriteByte(0x51);
983 		WriteByte(0x03);
984 		WriteByte(val >> 16);
985 		WriteByte(val >> 8);
986 		WriteByte(val);
987 	}
988 }
989 
990