xref: /haiku/src/kits/midi/MidiStore.cpp (revision 7120e97489acbf17d86d3f33e3b2e68974fd4b23)
1 #include "MidiStore.h"
2 #include "MidiEvent.h"
3 
4 #include <File.h>
5 #include <string.h> //For strcmp(...)
6 #include <stdio.h> //For printf(...)
7 #include <Debug.h>
8 #include <List.h>
9 
10 //-----------------------------------------------
11 
12 //-----------------------------------------------
13 //-----------------------------------------------
14 //-----------------------------------------------
15 
16 int CompareEvents(const void* event1, const void* event2)
17 {
18 	return ((BMidiEvent*)event1)->time - ((BMidiEvent*)event2)->time;
19 }
20 
21 //-----------------------------------------------
22 
23 BMidiStore::BMidiStore()
24 {
25 	events = new BList();
26 	fFile = NULL;
27 	fFileBuffer = NULL;
28 	fFileBufferMax = 0;
29 	fNeedsSorting = false;
30 	fDivision = 480;
31 	fNumTracks = 1;
32 	fStartTime = 0;
33 	fCurrEvent = 0;
34 }
35 
36 //-----------------------------------------------
37 
38 BMidiStore::~BMidiStore()
39 {
40 	int32 count = events->CountItems();
41 	for (int i = count - 1; i >= 0; i--)
42 	{
43 		delete (BMidiEvent*) events->RemoveItem(i);
44 	}
45 	delete events;
46 }
47 
48 //-----------------------------------------------
49 
50 void BMidiStore::NoteOff(uchar chan, uchar note, uchar vel, uint32 time)
51 {
52 	AddEvent(time, true, BMidiEvent::OP_NOTE_OFF, chan, note, vel);
53 }
54 
55 //-----------------------------------------------
56 
57 void BMidiStore::NoteOn(uchar chan, uchar note, uchar vel, uint32 time)
58 {
59 	AddEvent(time, true, BMidiEvent::OP_NOTE_ON, chan, note, vel);
60 }
61 
62 //-----------------------------------------------
63 
64 void BMidiStore::KeyPressure(uchar chan, uchar note, uchar pres, uint32 time)
65 {
66 	AddEvent(time, true, BMidiEvent::OP_KEY_PRESSURE, chan, note, pres);
67 }
68 
69 //-----------------------------------------------
70 
71 void BMidiStore::ControlChange(uchar chan, uchar ctrl_num, uchar ctrl_val, uint32 time)
72 {
73 	AddEvent(time, true, BMidiEvent::OP_CONTROL_CHANGE, chan, ctrl_num, ctrl_val);
74 }
75 
76 //-----------------------------------------------
77 
78 void BMidiStore::ProgramChange(uchar chan, uchar prog_num, uint32 time)
79 {
80 	AddEvent(time, true, BMidiEvent::OP_PROGRAM_CHANGE, chan, prog_num);
81 }
82 
83 //-----------------------------------------------
84 
85 void BMidiStore::ChannelPressure(uchar chan, uchar pres, uint32 time)
86 {
87 	AddEvent(time, true, BMidiEvent::OP_CHANNEL_PRESSURE, chan, pres);
88 }
89 
90 //-----------------------------------------------
91 
92 void BMidiStore::PitchBend(uchar chan, uchar lsb, uchar msb, uint32 time)
93 {
94 	AddEvent(time, true, BMidiEvent::OP_PITCH_BEND, chan, lsb, msb);
95 }
96 //-----------------------------------------------
97 
98 void BMidiStore::SystemExclusive(void *data, size_t data_len, uint32 time)
99 {
100 	BMidiEvent *e = new BMidiEvent;
101 	e->opcode = BMidiEvent::OP_SYSTEM_EXCLUSIVE;
102 	e->time = time;
103 	e->systemExclusive.data = new uint8[data_len];
104 	memcpy(e->systemExclusive.data, data, data_len);
105 	e->systemExclusive.dataLength = data_len;
106 	AddSystemExclusive(e, sizeof(BMidiEvent));
107 }
108 
109 //-----------------------------------------------
110 
111 void BMidiStore::SystemCommon(uchar stat_byte, uchar data1, uchar data2, uint32 time)
112 {
113 	AddEvent(time, true, BMidiEvent::OP_SYSTEM_COMMON, stat_byte, data1, data2);
114 }
115 
116 //-----------------------------------------------
117 
118 void BMidiStore::SystemRealTime(uchar stat_byte, uint32 time)
119 {
120 	AddEvent(time, true, BMidiEvent::OP_SYSTEM_REAL_TIME, stat_byte);
121 }
122 
123 //-----------------------------------------------
124 
125 void BMidiStore::TempoChange(int32 bpm, uint32 time)
126 {
127 	AddEvent(time, true, BMidiEvent::OP_TEMPO_CHANGE, bpm);
128 }
129 
130 //-----------------------------------------------
131 
132 status_t BMidiStore::Import(const entry_ref *ref)
133 {//ToTest
134 status_t status = B_NO_ERROR;
135 
136 	fFile = new BFile(ref, B_READ_ONLY);
137 
138 	status = fFile->InitCheck();
139 	if (status != B_OK)
140 	{
141 		delete fFile;
142 		return status;
143 	}
144 
145 	status = ReadHeader();
146 	if (status != B_OK)
147 	{
148 		delete fFile;
149 		return status;
150 	}
151 
152 	Read16Bit(); //Format of the MidiFile
153 	fNumTracks = Read16Bit();
154 	fDivision = Read16Bit();
155 	fDivisionFactor = 1 / fDivision;
156 
157 	status = B_OK;
158 	for(fCurrTrack = 0; fCurrTrack < fNumTracks; fCurrTrack++)
159 	{
160 	char mtrk[4];
161 		if (ReadMT(mtrk) == false)
162 		{
163 			PRINT(("Error while reading MTrk\n"));
164 			status = B_BAD_MIDI_DATA;
165 			break;
166 		}
167 		PRINT(("Printing Track %ld\n", fCurrTrack));
168 
169 		fFileBufferSize = Read32Bit();
170 		if (fFileBufferSize > fFileBufferMax)
171 		{
172 			fFileBufferMax = fFileBufferSize;
173 			delete fFileBuffer;
174 			fFileBuffer = new uchar[fFileBufferSize];
175 		}
176 		if (ReadTrack() == false)
177 		{
178 			PRINT(("Error while reading Trak %ld\n", fCurrTrack));
179 			status = B_BAD_MIDI_DATA;
180 			break;
181 		}
182 	}
183 
184 	delete fFile;
185 	delete fFileBuffer;
186 	fFileBuffer = NULL;
187 	SortEvents(true);
188 return status;
189 }
190 
191 //-----------------------------------------------
192 
193 status_t BMidiStore::Export(const entry_ref *ref, int32 format)
194 {//ToDo
195 	fFile = new BFile(ref, B_READ_WRITE);
196 	status_t status = fFile->InitCheck();
197 	if (status != B_OK)
198 	{
199 		delete fFile;
200 		return status;
201 	}
202 
203 	SortEvents(true);
204 	WriteHeaderChunk(format);
205 
206 off_t position_of_length = 0;
207 
208 	if (format == 0)
209 	{//Format is 0 just one track
210 		position_of_length = fFile->Position() + 4;
211 		WriteTrack(-1);
212 		fFile->Seek(position_of_length, SEEK_SET);
213 		Write32Bit(fNumBytesWritten);
214 		fFile->Seek(0, SEEK_END);
215 	}
216 
217 	if (format == 1)
218 	{//Format is 1, number of track is fNumTracks initialized when import file
219 		for (int32 i = 0; i < fNumTracks; i++)
220 		{
221 			position_of_length = fFile->Position() + 4;
222 			WriteTrack(i);
223 			fFile->Seek(position_of_length, SEEK_SET);
224 			Write32Bit(fNumBytesWritten);
225 			fFile->Seek(0, SEEK_END);
226 		}
227 	}
228 
229 return B_OK;
230 }
231 
232 //-----------------------------------------------
233 
234 void BMidiStore::SortEvents(bool force)
235 {
236 	events->SortItems(CompareEvents);
237 }
238 
239 //-----------------------------------------------
240 
241 uint32 BMidiStore::CountEvents() const
242 {//ToTest
243 return events->CountItems();
244 }
245 
246 //-----------------------------------------------
247 
248 uint32 BMidiStore::CurrentEvent() const
249 {//ToTest
250 	return fCurrEvent;
251 }
252 
253 //-----------------------------------------------
254 
255 void BMidiStore::SetCurrentEvent(uint32 event_num)
256 {//ToTest
257 	fCurrEvent = event_num;
258 }
259 
260 //-----------------------------------------------
261 
262 uint32 BMidiStore::DeltaOfEvent(uint32 event_num) const
263 {//ToDo
264 return 0;
265 }
266 
267 //-----------------------------------------------
268 
269 uint32 BMidiStore::EventAtDelta(uint32 time) const
270 {//ToDo
271 return 0;
272 }
273 
274 //-----------------------------------------------
275 
276 uint32 BMidiStore::BeginTime() const
277 {//ToTest
278 		return fStartTime;
279 }
280 
281 //-----------------------------------------------
282 
283 void BMidiStore::SetTempo(int32 bpm)
284 {//ToTest
285 	fTempo = bpm;
286 }
287 
288 //-----------------------------------------------
289 
290 int32 BMidiStore::Tempo() const
291 {//ToTest
292 	return fTempo;
293 }
294 
295 //-----------------------------------------------
296 //-----------------------------------------------
297 //-----------------------------------------------
298 //-----------------------------------------------
299 
300 void BMidiStore::Run()
301 {
302 	fStartTime = B_NOW;
303 	SortEvents(true);
304 	while (KeepRunning())
305 	{
306 		BMidiEvent* event = (BMidiEvent*)events->ItemAt(fCurrEvent);
307 
308 		if (event == NULL) return;
309 
310 		printf("Curr Event : %ld, Time : %ld\n", fCurrEvent, event->time);
311 
312 		fCurrTime = event->time;
313 		event->time += fStartTime;
314 //		SprayMidiEvent(event);
315 		event->time = fCurrTime;
316 
317 		fCurrEvent++;
318 	}
319 }
320 
321 //-----------------------------------------------
322 
323 void BMidiStore::AddEvent(uint32 time, bool inMS, uchar type, uchar data1 = 0, uchar data2 = 0, uchar data3 = 0, uchar data4 = 0)
324 {//ToTest
325 	if (!inMS)
326 	{
327 		time = TicksToMilliseconds(time);
328 	}
329 	BMidiEvent *e = new BMidiEvent();
330 	e->time = time;
331 	switch (type)
332 	{
333 		case BMidiEvent::OP_NOTE_OFF :
334 					e->opcode = BMidiEvent::OP_NOTE_OFF;
335 					e->noteOff.channel = data1;
336 					e->noteOff.note = data2;
337 					e->noteOff.velocity = data3;
338 					break;
339 		case BMidiEvent::OP_NOTE_ON :
340 					e->opcode = BMidiEvent::OP_NOTE_ON;
341 					e->noteOn.channel = data1;
342 					e->noteOn.note = data2;
343 					e->noteOn.velocity = data3;
344 					break;
345 		case BMidiEvent::OP_KEY_PRESSURE :
346 					e->opcode = BMidiEvent::OP_KEY_PRESSURE;
347 					e->keyPressure.channel = data1;
348 					e->keyPressure.note = data2;
349 					e->keyPressure.pressure = data3;
350 					break;
351 		case BMidiEvent::OP_CONTROL_CHANGE :
352 					e->opcode = BMidiEvent::OP_CONTROL_CHANGE;
353 					e->controlChange.channel = data1;
354 					e->controlChange.controlNumber = data2;
355 					e->controlChange.controlValue = data3;
356 					break;
357 		case BMidiEvent::OP_PROGRAM_CHANGE :
358 					e->opcode = BMidiEvent::OP_PROGRAM_CHANGE;
359 					e->programChange.channel = data1;
360 					e->programChange.programNumber = data2;
361 					break;
362 		case BMidiEvent::OP_CHANNEL_PRESSURE :
363 					e->opcode = BMidiEvent::OP_CHANNEL_PRESSURE;
364 					e->channelPressure.channel = data1;
365 					e->channelPressure.pressure = data2;
366 					break;
367 		case BMidiEvent::OP_PITCH_BEND :
368 					e->opcode = BMidiEvent::OP_PITCH_BEND;
369 					e->pitchBend.channel = data1;
370 					e->pitchBend.lsb = data2;
371 					e->pitchBend.msb = data3;
372 					break;
373 		case BMidiEvent::OP_SYSTEM_COMMON :
374 					e->opcode = BMidiEvent::OP_SYSTEM_COMMON;
375 					e->systemCommon.status = data1;
376 					e->systemCommon.data1 = data2;
377 					e->systemCommon.data2 = data3;
378 					break;
379 		case BMidiEvent::OP_SYSTEM_REAL_TIME :
380 					e->opcode = BMidiEvent::OP_SYSTEM_REAL_TIME;
381 					e->systemRealTime.status = data1;
382 					break;
383 		case BMidiEvent::OP_TEMPO_CHANGE :
384 					e->opcode = BMidiEvent::OP_TEMPO_CHANGE;
385 					e->tempoChange.beatsPerMinute = data1;
386 					break;
387 		case BMidiEvent::OP_ALL_NOTES_OFF :
388 					e->opcode = BMidiEvent::OP_ALL_NOTES_OFF;
389 					e->allNotesOff.justChannel = data1;
390 					break;
391 		default :
392 			delete e;
393 			return;
394 	}
395 	events->AddItem(e);
396 }
397 
398 //-----------------------------------------------
399 
400 void BMidiStore::AddSystemExclusive(void* data, size_t dataLength)
401 {//ToTest
402 //	BMidiEvent *e = new BMidiEvent();
403 //	e->time = 0;
404 //	e->systemExclusive.data = (uint8*)data;
405 //	e->systemExclusive.dataLength = dataLength;
406 	events->AddItem(data);
407 }
408 
409 //-----------------------------------------------
410 
411 status_t BMidiStore::ReadHeader()
412 {//ToTest
413 char mthd[4];
414 	if (ReadMT(mthd) == false)
415 		return B_ERROR;
416 	if(strncmp(mthd, "MThd", 4) != 0)
417 	{
418 		return B_BAD_MIDI_DATA;
419 	}
420 
421 int32 length = Read32Bit();
422 	if (length != 6)
423 	{
424 		return B_BAD_MIDI_DATA;
425 	}
426 return B_OK;
427 }
428 
429 //-----------------------------------------------
430 
431 bool BMidiStore::ReadMT(char *data)
432 {//ToTest
433 	return fFile->Read(data, 4) == 4;
434 }
435 
436 //-----------------------------------------------
437 
438 int32 BMidiStore::Read32Bit()
439 {//ToTest
440 uchar char32bit[4];
441 	fFile->Read(char32bit, 4);
442 return To32Bit(char32bit[0], char32bit[1], char32bit[2], char32bit[3]);
443 }
444 
445 //-----------------------------------------------
446 
447 int32 BMidiStore::EGetC()
448 {//ToDo
449 return 0;
450 }
451 
452 //-----------------------------------------------
453 
454 int32 BMidiStore::To32Bit(int32 data1, int32 data2, int32 data3, int32 data4)
455 {//ToTest
456 	return data1 << 24 | data2 << 16 | data3 << 8 | data4;
457 }
458 
459 //-----------------------------------------------
460 
461 int32 BMidiStore::Read16Bit()
462 {//ToTest
463 uchar char16bit[2];
464 	fFile->Read(char16bit, 2);
465 return To16Bit(char16bit[0], char16bit[1]);
466 }
467 
468 //-----------------------------------------------
469 
470 int32 BMidiStore::To16Bit(int32 data1, int32 data2)
471 {//ToTest
472 	return (uint32)data1 << 8 | (uint32)data2;
473 }
474 
475 //-----------------------------------------------
476 
477 bool BMidiStore::ReadTrack()
478 {//ToTest
479 	if (fFile->Read(fFileBuffer, fFileBufferSize) != fFileBufferSize)
480 		return false;
481 fNeedsSorting = true;
482 fFileBufferIndex = 0;
483 uint32 ticks = 0;
484 uint32 time = 0; //in ms
485 uchar data = 0;
486 uint32 ForTempo = 0;
487 //fStartTime = 0;
488 	while (fFileBufferIndex < (fFileBufferSize - 3))
489 	{
490 		ticks += ReadVariNum();
491 		time = /*fStartTime + */TicksToMilliseconds(ticks);
492 		uchar temp = fFileBuffer[fFileBufferIndex];
493 		if (temp > 0x7F)
494 		{
495 			data = temp;
496 			fFileBufferIndex++;
497 		}
498 		if (data < 0x80)
499 		{
500 			PRINT(("Big Problem, data : %d, Index : %ld\n", data, fFileBufferIndex));
501 			return false;
502 		}
503 		switch (data & 0xF0)
504 		{
505 			case B_NOTE_OFF :
506 				NoteOff(data & 0x0F, fFileBuffer[fFileBufferIndex],
507 							fFileBuffer[fFileBufferIndex + 1], time);
508 				fFileBufferIndex += 2;
509 				break;
510 			case B_NOTE_ON :
511 				NoteOn(data & 0x0F, fFileBuffer[fFileBufferIndex],
512 							fFileBuffer[fFileBufferIndex + 1], time);
513 				fFileBufferIndex += 2;
514 				break;
515 			case B_KEY_PRESSURE :
516 				KeyPressure(data & 0x0F, fFileBuffer[fFileBufferIndex],
517 							fFileBuffer[fFileBufferIndex + 1], time);
518 				fFileBufferIndex += 2;
519 				break;
520 			case B_CONTROL_CHANGE :
521 				ControlChange(data & 0x0F, fFileBuffer[fFileBufferIndex],
522 							fFileBuffer[fFileBufferIndex + 1], time);
523 				fFileBufferIndex += 2;
524 				break;
525 			case B_PITCH_BEND :
526 				PitchBend(data & 0x0F, fFileBuffer[fFileBufferIndex],
527 							fFileBuffer[fFileBufferIndex + 1], time);
528 				fFileBufferIndex += 2;
529 				break;
530 			case B_PROGRAM_CHANGE :
531 				ProgramChange(data & 0x0F, fFileBuffer[fFileBufferIndex], time);
532 				fFileBufferIndex += 2;
533 				break;
534 			case B_CHANNEL_PRESSURE :
535 				ChannelPressure(data & 0x0F, fFileBuffer[fFileBufferIndex], time);
536 				fFileBufferIndex += 1;
537 				break;
538 		}
539 		switch (data)
540 		{
541 			case B_SYS_EX_START :
542 				temp = MsgLength();
543 				SystemExclusive(&fFileBuffer[fFileBufferIndex - 1], temp + 2, time);
544 				fFileBufferIndex += temp;
545 				break;
546 			case B_SONG_POSITION :
547 				SystemCommon(data, fFileBuffer[fFileBufferIndex], fFileBuffer[fFileBufferIndex + 1], time);
548 				fFileBufferIndex += 2;
549 				break;
550 			case B_MIDI_TIME_CODE :
551 			case B_SONG_SELECT :
552 				SystemCommon(data, fFileBuffer[fFileBufferIndex], 0, time);
553 				fFileBufferIndex += 1;
554 				break;
555 			case B_TUNE_REQUEST :
556 			case B_TIMING_CLOCK :
557 				SystemCommon(data, 0, 0, time);
558 				break;
559 			case B_START :
560 			case B_CONTINUE :
561 			case B_STOP :
562 			case B_ACTIVE_SENSING :
563 				SystemRealTime(data, time);
564 				break;
565 			case B_SYSTEM_RESET :
566 				temp = fFileBuffer[fFileBufferIndex];
567 				if (temp == 0x2F)
568 					return true;
569 				if (temp == 0x51)
570 				{//Calcul of the tempo is wrong
571 					fFileBufferIndex +=2;
572 					ForTempo = fFileBuffer[fFileBufferIndex++] << 8;
573 					ForTempo |= fFileBuffer[fFileBufferIndex++];
574 					ForTempo = (ForTempo << 8) | fFileBuffer[fFileBufferIndex++];
575 //					ForTempo /= 2500;
576 					TempoChange(ForTempo, time);
577 				}
578 				else
579 				{
580 					temp = fFileBuffer[fFileBufferIndex + 1] + 3;
581 					SystemExclusive(&fFileBuffer[fFileBufferIndex - 1], temp, time);
582 					fFileBufferIndex += temp - 1;
583 				}
584 				break;
585 			default :
586 				if (data >= 0xF0)
587 					printf("Midi Data not Defined\n");
588 		}
589 	}
590 return true;
591 }
592 
593 //-----------------------------------------------
594 
595 int32 BMidiStore::ReadVariNum()
596 {//ToTest
597 int32 result = 0;
598 uchar tempo = 0;
599 	while (fFileBufferIndex < fFileBufferSize)
600 	{
601 		tempo = fFileBuffer[fFileBufferIndex++];
602 		result |= tempo & 0x7F;
603 		if ((tempo & 0x80) == 0)
604 			return result;
605 		result <<= 7;
606 	}
607 return B_ERROR;
608 }
609 
610 //-----------------------------------------------
611 
612 void BMidiStore::ChannelMessage(int32, int32, int32)
613 {//ToDo
614 
615 }
616 
617 //-----------------------------------------------
618 
619 void BMidiStore::MsgInit()
620 {//ToDo
621 
622 }
623 
624 //-----------------------------------------------
625 
626 void BMidiStore::MsgAdd(int32)
627 {//ToDo
628 
629 }
630 
631 //-----------------------------------------------
632 
633 void BMidiStore::BiggerMsg()
634 {//ToDo
635 
636 }
637 
638 //-----------------------------------------------
639 
640 void BMidiStore::MetaEvent(int32)
641 {//ToDo
642 
643 }
644 
645 //-----------------------------------------------
646 
647 int32 BMidiStore::MsgLength()
648 {//ToTest
649 int32 t = 0;
650 	while (fFileBuffer[fFileBufferIndex + t] != 0xF7)
651 	{
652 		if (fFileBufferIndex + t > fFileBufferSize - 3)
653 			return -1;
654 		else
655 			t++;
656 	}
657 return t;
658 }
659 
660 //-----------------------------------------------
661 
662 uchar *BMidiStore::Msg()
663 {//ToDo
664 return 0;
665 }
666 
667 //-----------------------------------------------
668 
669 void BMidiStore::BadByte(int32)
670 {//ToDo
671 
672 }
673 
674 //-----------------------------------------------
675 
676 
677 int32 BMidiStore::PutC(int32 c)
678 {//ToDo
679 return 0;
680 }
681 
682 //-----------------------------------------------
683 
684 bool BMidiStore::WriteTrack(int32 track)
685 {//ToTest
686 uchar temp[4] = {0x00, 0x00, 0x00, 0x00};
687 	WriteTrackChunk(track);
688 	fNumBytesWritten = 0;
689 uint32 ticks = 0;
690 int32 i = 0;
691 // If track == -1 write all events
692 BMidiEvent *event = (BMidiEvent*)events->ItemAt(i++);
693 	if (event != NULL)
694 		fCurrTime = event->time;
695 	while (event != NULL)
696 	{
697 		ticks = MillisecondsToTicks(event->time - fCurrTime);
698 		switch(event->opcode)
699 		{
700 			case BMidiEvent::OP_NOTE_OFF :
701 					if ((track == -1) || (track == event->noteOff.channel))
702 					{
703 						temp[0] = event->noteOff.note;
704 						temp[1] = event->noteOff.velocity;
705 						WriteMidiEvent(ticks, B_NOTE_OFF, event->noteOff.channel, temp, 2);
706 					}
707 					break;
708 			case BMidiEvent::OP_NOTE_ON :
709 					if ((track == -1) || (track == event->noteOn.channel))
710 					{
711 						temp[0] = event->noteOn.note;
712 						temp[1] = event->noteOn.velocity;
713 						WriteMidiEvent(ticks, B_NOTE_ON, event->noteOn.channel, temp, 2);
714 					}
715 					break;
716 			case BMidiEvent::OP_KEY_PRESSURE :
717 					if ((track == -1) || (track == event->keyPressure.channel))
718 					{
719 						temp[0] = event->keyPressure.note;
720 						temp[1] = event->keyPressure.pressure;
721 						WriteMidiEvent(ticks, B_KEY_PRESSURE, event->keyPressure.channel, temp, 2);
722 					}
723 					break;
724 			case BMidiEvent::OP_CONTROL_CHANGE :
725 					if ((track == -1) || (track == event->controlChange.channel))
726 					{
727 						temp[0] = event->controlChange.controlNumber;
728 						temp[1] = event->controlChange.controlValue;
729 						WriteMidiEvent(ticks, B_CONTROL_CHANGE, event->controlChange.channel, temp, 2);
730 					}
731 					break;
732 			case BMidiEvent::OP_PROGRAM_CHANGE :
733 					if ((track == -1) || (track == event->programChange.channel))
734 					{
735 						temp[0] = event->programChange.programNumber;
736 						WriteMidiEvent(ticks, B_PROGRAM_CHANGE, event->programChange.channel, temp, 1);
737 					}
738 					break;
739 			case BMidiEvent::OP_CHANNEL_PRESSURE :
740 					if ((track == -1) || (track == event->channelPressure.channel))
741 					{
742 						temp[0] = event->channelPressure.pressure;
743 						WriteMidiEvent(ticks, B_CHANNEL_PRESSURE, event->channelPressure.channel, temp, 1);
744 					}
745 					break;
746 			case BMidiEvent::OP_PITCH_BEND :
747 					if ((track == -1) || (track == event->pitchBend.channel))
748 					{
749 						temp[0] = event->pitchBend.lsb;
750 						temp[1] = event->pitchBend.msb;
751 						WriteMidiEvent(ticks, B_PITCH_BEND, event->pitchBend.channel, temp, 2);
752 					}
753 					break;
754 			case BMidiEvent::OP_SYSTEM_COMMON :
755 					if ((track == -1) || (track == 0))
756 					{
757 						temp[0] = event->systemCommon.data1;
758 						temp[1] = event->systemCommon.data2;
759 						WriteMetaEvent(ticks, event->systemCommon.status, temp, 2);
760 					}
761 					break;
762 			case BMidiEvent::OP_SYSTEM_REAL_TIME :
763 					if ((track == -1) || (track == 0))
764 					{
765 						WriteMetaEvent(ticks, event->systemRealTime.status, temp, 0);
766 					}
767 					break;
768 			case BMidiEvent::OP_SYSTEM_EXCLUSIVE :
769 					if ((track == -1) || (track == 0))
770 					{
771 						WriteSystemExclusiveEvent(ticks, event->systemExclusive.data, event->systemExclusive.dataLength);
772 					}
773 					break;
774 			case BMidiEvent::OP_TEMPO_CHANGE :
775 					if ((track == -1) || (track == 0))
776 					{
777 						WriteTempo(ticks, event->tempoChange.beatsPerMinute);
778 					}
779 					break;
780 //Not used
781 			case BMidiEvent::OP_NONE :
782 			case BMidiEvent::OP_ALL_NOTES_OFF :
783 			case BMidiEvent::OP_TRACK_END :
784 					break;
785 		}
786 //		}
787 		fCurrTime = event->time;
788 		event = (BMidiEvent*)events->ItemAt(i++);
789 	}
790 
791 	Write16Bit(0xFF2F);
792 	EPutC(0);
793 return true;
794 }
795 
796 //-----------------------------------------------
797 
798 void BMidiStore::WriteTempoTrack()
799 {//ToDo
800 }
801 
802 //-----------------------------------------------
803 
804 bool BMidiStore::WriteTrackChunk(int32 whichTrack)
805 {//ToTest
806 	Write32Bit('MTrk');
807 	Write32Bit(6);
808 return true;
809 }
810 
811 //-----------------------------------------------
812 
813 void BMidiStore::WriteHeaderChunk(int32 format)
814 {//ToTest
815 	Write32Bit('MThd');
816 	Write32Bit(6);
817 	Write16Bit(format);
818 	if (format == 0)
819 		fNumTracks = 1;
820 	Write16Bit(fNumTracks);
821 	Write16Bit(fDivision);
822 }
823 
824 //-----------------------------------------------
825 
826 bool BMidiStore::WriteMidiEvent(uint32 deltaTime, uint32 type, uint32 channel, uchar* data, uint32 size)
827 {//ToTest
828 	WriteVarLen(deltaTime);
829 	if (EPutC(type | channel) != 1)
830 		return false;
831 	while (size > 0)
832 	{
833 		if (EPutC(*data) != 1)
834 			return false;
835 		data++;
836 		size--;
837 	}
838 return true;
839 }
840 
841 //-----------------------------------------------
842 
843 bool BMidiStore::WriteMetaEvent(uint32 deltaTime, uint32 type, uchar* data, uint32 size)
844 {//ToTest
845 	WriteVarLen(deltaTime);
846 	if (EPutC(type) != 1)
847 		return false;
848 	while (size > 0)
849 	{
850 		if (EPutC(*data) != 1)
851 			return false;
852 		data++;
853 		size--;
854 	}
855 return true;
856 }
857 
858 //-----------------------------------------------
859 
860 bool BMidiStore::WriteSystemExclusiveEvent(uint32 deltaTime, uchar* data, uint32 size)
861 {//ToTest
862 	WriteVarLen(deltaTime);
863 	while (size > 0)
864 	{
865 		if (EPutC(*data) != 1)
866 			return false;
867 		data++;
868 		size--;
869 	}
870 return true;
871 }
872 
873 //-----------------------------------------------
874 
875 void BMidiStore::WriteTempo(uint32 deltaTime, int32 tempo)
876 {//ToTest
877 	WriteVarLen(deltaTime);
878 	Write16Bit(0xFF51);
879 	EPutC(3);
880 	EPutC((tempo >> 16) & 0xFF);
881 	EPutC((tempo >> 8) & 0xFF);
882 	EPutC(tempo & 0xFF);
883 }
884 
885 //-----------------------------------------------
886 
887 void BMidiStore::WriteVarLen(uint32 value)
888 {//ToTest
889 uint32 buffer = value & 0x7F;
890 	while ( (value >>= 7) )
891 	{
892 		buffer <<= 8;
893 		buffer |= ((value & 0x7F) | 0x80);
894 	}
895 	while (true)
896 	{
897 		EPutC(buffer);
898 		if (buffer & 0x80)
899 			buffer >>= 8;
900 		else
901 			break;
902 	}
903 }
904 
905 //-----------------------------------------------
906 
907 void BMidiStore::Write32Bit(uint32 data)
908 {//ToTest
909 	EPutC((data >> 24) & 0xFF);
910 	EPutC((data >> 16) & 0xFF);
911 	EPutC((data >> 8) & 0xFF);
912 	EPutC(data & 0xFF);
913 }
914 
915 //-----------------------------------------------
916 
917 void BMidiStore::Write16Bit(ushort data)
918 {//ToTest
919 	EPutC((data >> 8) & 0xFF);
920 	EPutC(data & 0xFF);
921 }
922 
923 //-----------------------------------------------
924 
925 int32 BMidiStore::EPutC(uchar c)
926 {//ToTest
927 	fNumBytesWritten++;
928 return fFile->Write(&c, 1);
929 }
930 
931 //-----------------------------------------------
932 
933 
934 uint32 BMidiStore::TicksToMilliseconds(uint32 ticks) const
935 {//ToTest
936 	return ((uint64)ticks * 1000) / fDivision;
937 }
938 
939 //-----------------------------------------------
940 
941 uint32 BMidiStore::MillisecondsToTicks(uint32 ms) const
942 {//ToTest
943 	return ((uint64)ms * fDivision) / 1000;
944 }
945 
946 //-----------------------------------------------
947 
948 void BMidiStore::_ReservedMidiStore1()
949 {
950 }
951 
952 //-----------------------------------------------
953 
954 void BMidiStore::_ReservedMidiStore2()
955 {
956 }
957 
958 //-----------------------------------------------
959 
960 void BMidiStore::_ReservedMidiStore3()
961 {
962 }
963 
964 //-----------------------------------------------
965 //-----------------------------------------------
966 //-----------------------------------------------
967 //-----------------------------------------------
968 //-----------------------------------------------
969 //-----------------------------------------------
970 //-----------------------------------------------
971 //-----------------------------------------------
972 //-----------------------------------------------
973 //-----------------------------------------------
974