xref: /haiku/src/kits/midi/MidiStore.cpp (revision fef6144999c2fa611f59ee6ffe6dd7999501385c)
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