149fa1748Smahlzeit /* 2*9138338cSmahlzeit * Copyright (c) 2002-2004 Matthijs Hollemans 349fa1748Smahlzeit * Copyright (c) 2002 Jerome Leveque 449fa1748Smahlzeit * Copyright (c) 2002 Paul Stadler 549fa1748Smahlzeit * 649fa1748Smahlzeit * Permission is hereby granted, free of charge, to any person obtaining a 749fa1748Smahlzeit * copy of this software and associated documentation files (the "Software"), 849fa1748Smahlzeit * to deal in the Software without restriction, including without limitation 949fa1748Smahlzeit * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1049fa1748Smahlzeit * and/or sell copies of the Software, and to permit persons to whom the 1149fa1748Smahlzeit * Software is furnished to do so, subject to the following conditions: 1249fa1748Smahlzeit * 1349fa1748Smahlzeit * The above copyright notice and this permission notice shall be included in 1449fa1748Smahlzeit * all copies or substantial portions of the Software. 1549fa1748Smahlzeit * 1649fa1748Smahlzeit * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1749fa1748Smahlzeit * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1849fa1748Smahlzeit * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1949fa1748Smahlzeit * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2049fa1748Smahlzeit * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2149fa1748Smahlzeit * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2249fa1748Smahlzeit * DEALINGS IN THE SOFTWARE. 2349fa1748Smahlzeit */ 2452a38012Sejakowatz 25eac71506Sjerl1 #include <File.h> 26eac71506Sjerl1 #include <List.h> 2749fa1748Smahlzeit #include <stdlib.h> 2849fa1748Smahlzeit #include <string.h> 29eac71506Sjerl1 3049fa1748Smahlzeit #include "MidiDefs.h" 3149fa1748Smahlzeit #include "MidiStore.h" 3249fa1748Smahlzeit #include "debug.h" 33eac71506Sjerl1 3449fa1748Smahlzeit //------------------------------------------------------------------------------ 35eac71506Sjerl1 3649fa1748Smahlzeit struct BMidiEvent 37eac71506Sjerl1 { 3849fa1748Smahlzeit BMidiEvent() 3949fa1748Smahlzeit { 4049fa1748Smahlzeit byte1 = 0; 4149fa1748Smahlzeit byte2 = 0; 4249fa1748Smahlzeit byte3 = 0; 4349fa1748Smahlzeit data = NULL; 4449fa1748Smahlzeit length = 0; 45eac71506Sjerl1 } 46eac71506Sjerl1 4749fa1748Smahlzeit ~BMidiEvent() 4849fa1748Smahlzeit { 4949fa1748Smahlzeit free(data); 5049fa1748Smahlzeit } 5149fa1748Smahlzeit 5249fa1748Smahlzeit uint32 time; // either ticks or milliseconds 5349fa1748Smahlzeit bool ticks; // event is from MIDI file 5449fa1748Smahlzeit uchar byte1; 5549fa1748Smahlzeit uchar byte2; 5649fa1748Smahlzeit uchar byte3; 5749fa1748Smahlzeit void* data; // sysex data 5849fa1748Smahlzeit size_t length; // sysex data size 5949fa1748Smahlzeit int32 tempo; // beats per minute 6049fa1748Smahlzeit }; 6149fa1748Smahlzeit 6249fa1748Smahlzeit //------------------------------------------------------------------------------ 6349fa1748Smahlzeit 6449fa1748Smahlzeit static int compare_events(const void* event1, const void* event2) 6549fa1748Smahlzeit { 6649fa1748Smahlzeit BMidiEvent* e1 = *((BMidiEvent**) event1); 6749fa1748Smahlzeit BMidiEvent* e2 = *((BMidiEvent**) event2); 6849fa1748Smahlzeit 6949fa1748Smahlzeit return (e1->time - e2->time); 7049fa1748Smahlzeit } 7149fa1748Smahlzeit 7249fa1748Smahlzeit //------------------------------------------------------------------------------ 7352a38012Sejakowatz 746ba60405Smahlzeit BMidiStore::BMidiStore() 756ba60405Smahlzeit { 7649fa1748Smahlzeit events = new BList; 7749fa1748Smahlzeit currentEvent = 0; 7849fa1748Smahlzeit startTime = 0; 7949fa1748Smahlzeit needsSorting = false; 8049fa1748Smahlzeit beatsPerMinute = 60; 8149fa1748Smahlzeit ticksPerBeat = 240; 8249fa1748Smahlzeit file = NULL; 8352a38012Sejakowatz } 8452a38012Sejakowatz 8549fa1748Smahlzeit //------------------------------------------------------------------------------ 866ba60405Smahlzeit 876ba60405Smahlzeit BMidiStore::~BMidiStore() 886ba60405Smahlzeit { 8949fa1748Smahlzeit for (int32 t = 0; t < events->CountItems(); ++t) 906ba60405Smahlzeit { 9149fa1748Smahlzeit delete EventAt(t); 9252a38012Sejakowatz } 936ba60405Smahlzeit delete events; 9452a38012Sejakowatz } 9552a38012Sejakowatz 9649fa1748Smahlzeit //------------------------------------------------------------------------------ 9752a38012Sejakowatz 9849fa1748Smahlzeit void BMidiStore::NoteOff( 9949fa1748Smahlzeit uchar channel, uchar note, uchar velocity, uint32 time) 1006ba60405Smahlzeit { 10149fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 10249fa1748Smahlzeit event->time = time; 10349fa1748Smahlzeit event->ticks = false; 10449fa1748Smahlzeit event->byte1 = B_NOTE_OFF | (channel - 1); 10549fa1748Smahlzeit event->byte2 = note; 10649fa1748Smahlzeit event->byte3 = velocity; 10749fa1748Smahlzeit AddEvent(event); 1086ba60405Smahlzeit } 1096ba60405Smahlzeit 11049fa1748Smahlzeit //------------------------------------------------------------------------------ 1116ba60405Smahlzeit 11249fa1748Smahlzeit void BMidiStore::NoteOn( 11349fa1748Smahlzeit uchar channel, uchar note, uchar velocity, uint32 time) 1146ba60405Smahlzeit { 11549fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 11649fa1748Smahlzeit event->time = time; 11749fa1748Smahlzeit event->ticks = false; 11849fa1748Smahlzeit event->byte1 = B_NOTE_ON | (channel - 1); 11949fa1748Smahlzeit event->byte2 = note; 12049fa1748Smahlzeit event->byte3 = velocity; 12149fa1748Smahlzeit AddEvent(event); 1226ba60405Smahlzeit } 1236ba60405Smahlzeit 12449fa1748Smahlzeit //------------------------------------------------------------------------------ 1256ba60405Smahlzeit 12649fa1748Smahlzeit void BMidiStore::KeyPressure( 12749fa1748Smahlzeit uchar channel, uchar note, uchar pressure, uint32 time) 1286ba60405Smahlzeit { 12949fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 13049fa1748Smahlzeit event->time = time; 13149fa1748Smahlzeit event->ticks = false; 13249fa1748Smahlzeit event->byte1 = B_KEY_PRESSURE | (channel - 1); 13349fa1748Smahlzeit event->byte2 = note; 13449fa1748Smahlzeit event->byte3 = pressure; 13549fa1748Smahlzeit AddEvent(event); 1366ba60405Smahlzeit } 1376ba60405Smahlzeit 13849fa1748Smahlzeit //------------------------------------------------------------------------------ 1396ba60405Smahlzeit 14049fa1748Smahlzeit void BMidiStore::ControlChange( 14149fa1748Smahlzeit uchar channel, uchar controlNumber, uchar controlValue, uint32 time) 1426ba60405Smahlzeit { 14349fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 14449fa1748Smahlzeit event->time = time; 14549fa1748Smahlzeit event->ticks = false; 14649fa1748Smahlzeit event->byte1 = B_CONTROL_CHANGE | (channel - 1); 14749fa1748Smahlzeit event->byte2 = controlNumber; 14849fa1748Smahlzeit event->byte3 = controlValue; 14949fa1748Smahlzeit AddEvent(event); 1506ba60405Smahlzeit } 1516ba60405Smahlzeit 15249fa1748Smahlzeit //------------------------------------------------------------------------------ 1536ba60405Smahlzeit 15449fa1748Smahlzeit void BMidiStore::ProgramChange( 15549fa1748Smahlzeit uchar channel, uchar programNumber, uint32 time) 1566ba60405Smahlzeit { 15749fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 15849fa1748Smahlzeit event->time = time; 15949fa1748Smahlzeit event->ticks = false; 16049fa1748Smahlzeit event->byte1 = B_PROGRAM_CHANGE | (channel - 1); 16149fa1748Smahlzeit event->byte2 = programNumber; 16249fa1748Smahlzeit AddEvent(event); 1636ba60405Smahlzeit } 1646ba60405Smahlzeit 16549fa1748Smahlzeit //------------------------------------------------------------------------------ 1666ba60405Smahlzeit 16749fa1748Smahlzeit void BMidiStore::ChannelPressure(uchar channel, uchar pressure, uint32 time) 1686ba60405Smahlzeit { 16949fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 17049fa1748Smahlzeit event->time = time; 17149fa1748Smahlzeit event->ticks = false; 17249fa1748Smahlzeit event->byte1 = B_CHANNEL_PRESSURE | (channel - 1); 17349fa1748Smahlzeit event->byte2 = pressure; 17449fa1748Smahlzeit AddEvent(event); 1756ba60405Smahlzeit } 1766ba60405Smahlzeit 17749fa1748Smahlzeit //------------------------------------------------------------------------------ 1786ba60405Smahlzeit 17949fa1748Smahlzeit void BMidiStore::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time) 1806ba60405Smahlzeit { 18149fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 18249fa1748Smahlzeit event->time = time; 18349fa1748Smahlzeit event->ticks = false; 18449fa1748Smahlzeit event->byte1 = B_PITCH_BEND | (channel - 1); 18549fa1748Smahlzeit event->byte2 = lsb; 18649fa1748Smahlzeit event->byte3 = msb; 18749fa1748Smahlzeit AddEvent(event); 18852a38012Sejakowatz } 18952a38012Sejakowatz 19049fa1748Smahlzeit //------------------------------------------------------------------------------ 1916ba60405Smahlzeit 19249fa1748Smahlzeit void BMidiStore::SystemExclusive(void* data, size_t length, uint32 time) 1936ba60405Smahlzeit { 19449fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 19549fa1748Smahlzeit event->time = time; 19649fa1748Smahlzeit event->ticks = false; 19749fa1748Smahlzeit event->byte1 = B_SYS_EX_START; 19849fa1748Smahlzeit event->data = malloc(length); 19949fa1748Smahlzeit event->length = length; 20049fa1748Smahlzeit memcpy(event->data, data, length); 20149fa1748Smahlzeit AddEvent(event); 20252a38012Sejakowatz } 20352a38012Sejakowatz 20449fa1748Smahlzeit //------------------------------------------------------------------------------ 2056ba60405Smahlzeit 20649fa1748Smahlzeit void BMidiStore::SystemCommon( 20749fa1748Smahlzeit uchar status, uchar data1, uchar data2, uint32 time) 2086ba60405Smahlzeit { 20949fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 21049fa1748Smahlzeit event->time = time; 21149fa1748Smahlzeit event->ticks = false; 21249fa1748Smahlzeit event->byte1 = status; 21349fa1748Smahlzeit event->byte2 = data1; 21449fa1748Smahlzeit event->byte3 = data2; 21549fa1748Smahlzeit AddEvent(event); 21652a38012Sejakowatz } 21752a38012Sejakowatz 21849fa1748Smahlzeit //------------------------------------------------------------------------------ 21952a38012Sejakowatz 22049fa1748Smahlzeit void BMidiStore::SystemRealTime(uchar status, uint32 time) 2216ba60405Smahlzeit { 22249fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 22349fa1748Smahlzeit event->time = time; 22449fa1748Smahlzeit event->ticks = false; 22549fa1748Smahlzeit event->byte1 = status; 22649fa1748Smahlzeit AddEvent(event); 22752a38012Sejakowatz } 22852a38012Sejakowatz 22949fa1748Smahlzeit //------------------------------------------------------------------------------ 23049fa1748Smahlzeit 23149fa1748Smahlzeit void BMidiStore::TempoChange(int32 beatsPerMinute, uint32 time) 23249fa1748Smahlzeit { 23349fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 23449fa1748Smahlzeit event->time = time; 23549fa1748Smahlzeit event->ticks = false; 23649fa1748Smahlzeit event->byte1 = 0xFF; 23749fa1748Smahlzeit event->byte2 = 0x51; 23849fa1748Smahlzeit event->byte3 = 0x03; 23949fa1748Smahlzeit event->tempo = beatsPerMinute; 24049fa1748Smahlzeit AddEvent(event); 24149fa1748Smahlzeit } 24249fa1748Smahlzeit 24349fa1748Smahlzeit //------------------------------------------------------------------------------ 2446ba60405Smahlzeit 2456ba60405Smahlzeit status_t BMidiStore::Import(const entry_ref* ref) 2466ba60405Smahlzeit { 24749fa1748Smahlzeit try 24849fa1748Smahlzeit { 24949fa1748Smahlzeit file = new BFile(ref, B_READ_ONLY); 25049fa1748Smahlzeit if (file->InitCheck() != B_OK) 25149fa1748Smahlzeit { 25249fa1748Smahlzeit throw file->InitCheck(); 25325767509Smahlzeit } 25425767509Smahlzeit 25549fa1748Smahlzeit char fourcc[4]; 25649fa1748Smahlzeit ReadFourCC(fourcc); 25749fa1748Smahlzeit if (strncmp(fourcc, "MThd", 4) != 0) 258eac71506Sjerl1 { 25949fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 260eac71506Sjerl1 } 26125767509Smahlzeit 26249fa1748Smahlzeit if (Read32Bit() != 6) 263eac71506Sjerl1 { 26449fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 265eac71506Sjerl1 } 266eac71506Sjerl1 26749fa1748Smahlzeit format = Read16Bit(); 26849fa1748Smahlzeit numTracks = Read16Bit(); 26949fa1748Smahlzeit ticksPerBeat = Read16Bit(); 27049fa1748Smahlzeit 27149fa1748Smahlzeit if (ticksPerBeat & 0x8000) // we don't support SMPTE 27249fa1748Smahlzeit { // time codes, only ticks 27349fa1748Smahlzeit ticksPerBeat = 240; // per quarter note 274eac71506Sjerl1 } 275eac71506Sjerl1 27649fa1748Smahlzeit currTrack = 0; 27749fa1748Smahlzeit while (currTrack < numTracks) 2786ba60405Smahlzeit { 27949fa1748Smahlzeit ReadChunk(); 28049fa1748Smahlzeit } 28149fa1748Smahlzeit } 28249fa1748Smahlzeit catch (status_t e) 28349fa1748Smahlzeit { 28449fa1748Smahlzeit delete file; 28549fa1748Smahlzeit file = NULL; 28649fa1748Smahlzeit return e; 287eac71506Sjerl1 } 288eac71506Sjerl1 289eac71506Sjerl1 SortEvents(true); 290eac71506Sjerl1 29149fa1748Smahlzeit delete file; 29249fa1748Smahlzeit file = NULL; 2936ba60405Smahlzeit return B_OK; 2946ba60405Smahlzeit } 2956ba60405Smahlzeit 29649fa1748Smahlzeit //------------------------------------------------------------------------------ 29749fa1748Smahlzeit 29849fa1748Smahlzeit status_t BMidiStore::Export(const entry_ref* ref, int32 format) 29949fa1748Smahlzeit { 30049fa1748Smahlzeit try 30149fa1748Smahlzeit { 30249fa1748Smahlzeit file = new BFile(ref, B_READ_WRITE); 30349fa1748Smahlzeit if (file->InitCheck() != B_OK) 30449fa1748Smahlzeit { 30549fa1748Smahlzeit throw file->InitCheck(); 30649fa1748Smahlzeit } 30749fa1748Smahlzeit 30849fa1748Smahlzeit SortEvents(true); 30949fa1748Smahlzeit 31049fa1748Smahlzeit WriteFourCC('M', 'T', 'h', 'd'); 31149fa1748Smahlzeit Write32Bit(6); 31249fa1748Smahlzeit Write16Bit(0); // we do only format 0 31349fa1748Smahlzeit Write16Bit(1); 31449fa1748Smahlzeit Write16Bit(ticksPerBeat); 31549fa1748Smahlzeit 31649fa1748Smahlzeit WriteTrack(); 31749fa1748Smahlzeit } 31849fa1748Smahlzeit catch (status_t e) 31949fa1748Smahlzeit { 32049fa1748Smahlzeit delete file; 32149fa1748Smahlzeit file = NULL; 32249fa1748Smahlzeit return e; 32349fa1748Smahlzeit } 32449fa1748Smahlzeit 32549fa1748Smahlzeit delete file; 32649fa1748Smahlzeit file = NULL; 32749fa1748Smahlzeit return B_OK; 32849fa1748Smahlzeit } 32949fa1748Smahlzeit 33049fa1748Smahlzeit //------------------------------------------------------------------------------ 3316ba60405Smahlzeit 3326ba60405Smahlzeit void BMidiStore::SortEvents(bool force) 3336ba60405Smahlzeit { 33449fa1748Smahlzeit if (force || needsSorting) 33549fa1748Smahlzeit { 33649fa1748Smahlzeit events->SortItems(compare_events); 33749fa1748Smahlzeit needsSorting = false; 33849fa1748Smahlzeit } 3396ba60405Smahlzeit } 3406ba60405Smahlzeit 34149fa1748Smahlzeit //------------------------------------------------------------------------------ 3426ba60405Smahlzeit 3436ba60405Smahlzeit uint32 BMidiStore::CountEvents() const 34449fa1748Smahlzeit { 3456ba60405Smahlzeit return events->CountItems(); 3466ba60405Smahlzeit } 3476ba60405Smahlzeit 34849fa1748Smahlzeit //------------------------------------------------------------------------------ 3496ba60405Smahlzeit 3506ba60405Smahlzeit uint32 BMidiStore::CurrentEvent() const 35149fa1748Smahlzeit { 35249fa1748Smahlzeit return currentEvent; 3536ba60405Smahlzeit } 3546ba60405Smahlzeit 35549fa1748Smahlzeit //------------------------------------------------------------------------------ 3566ba60405Smahlzeit 35749fa1748Smahlzeit void BMidiStore::SetCurrentEvent(uint32 eventNumber) 35849fa1748Smahlzeit { 35949fa1748Smahlzeit currentEvent = eventNumber; 3606ba60405Smahlzeit } 3616ba60405Smahlzeit 36249fa1748Smahlzeit //------------------------------------------------------------------------------ 3636ba60405Smahlzeit 36449fa1748Smahlzeit uint32 BMidiStore::DeltaOfEvent(uint32 eventNumber) const 36549fa1748Smahlzeit { 36649fa1748Smahlzeit // Even though the BeBook says that the delta is the time span between 36749fa1748Smahlzeit // an event and the first event in the list, this doesn't appear to be 36849fa1748Smahlzeit // true for events that were captured from other BMidi objects such as 36949fa1748Smahlzeit // BMidiPort. For those events, we return the absolute timestamp. The 37049fa1748Smahlzeit // BeBook is correct for events from MIDI files, though. 37149fa1748Smahlzeit 37249fa1748Smahlzeit BMidiEvent* event = EventAt(eventNumber); 37349fa1748Smahlzeit if (event != NULL) 37449fa1748Smahlzeit { 37549fa1748Smahlzeit return GetEventTime(event); 37649fa1748Smahlzeit } 37749fa1748Smahlzeit 3786ba60405Smahlzeit return 0; 3796ba60405Smahlzeit } 3806ba60405Smahlzeit 38149fa1748Smahlzeit //------------------------------------------------------------------------------ 382eac71506Sjerl1 383eac71506Sjerl1 uint32 BMidiStore::EventAtDelta(uint32 time) const 38449fa1748Smahlzeit { 38549fa1748Smahlzeit for (int32 t = 0; t < events->CountItems(); ++t) 38649fa1748Smahlzeit { 38749fa1748Smahlzeit if (GetEventTime(EventAt(t)) >= time) { return t; } 38849fa1748Smahlzeit } 38949fa1748Smahlzeit 390eac71506Sjerl1 return 0; 391eac71506Sjerl1 } 392eac71506Sjerl1 39349fa1748Smahlzeit //------------------------------------------------------------------------------ 3946ba60405Smahlzeit 3956ba60405Smahlzeit uint32 BMidiStore::BeginTime() const 39649fa1748Smahlzeit { 39749fa1748Smahlzeit return startTime; 3986ba60405Smahlzeit } 3996ba60405Smahlzeit 40049fa1748Smahlzeit //------------------------------------------------------------------------------ 4016ba60405Smahlzeit 40249fa1748Smahlzeit void BMidiStore::SetTempo(int32 beatsPerMinute_) 40349fa1748Smahlzeit { 40449fa1748Smahlzeit beatsPerMinute = beatsPerMinute_; 4056ba60405Smahlzeit } 4066ba60405Smahlzeit 40749fa1748Smahlzeit //------------------------------------------------------------------------------ 4086ba60405Smahlzeit 4096ba60405Smahlzeit int32 BMidiStore::Tempo() const 41049fa1748Smahlzeit { 41149fa1748Smahlzeit return beatsPerMinute; 4126ba60405Smahlzeit } 4136ba60405Smahlzeit 41449fa1748Smahlzeit //------------------------------------------------------------------------------ 41549fa1748Smahlzeit 41649fa1748Smahlzeit void BMidiStore::_ReservedMidiStore1() { } 41749fa1748Smahlzeit void BMidiStore::_ReservedMidiStore2() { } 41849fa1748Smahlzeit void BMidiStore::_ReservedMidiStore3() { } 41949fa1748Smahlzeit 42049fa1748Smahlzeit //------------------------------------------------------------------------------ 4216ba60405Smahlzeit 4226ba60405Smahlzeit void BMidiStore::Run() 4236ba60405Smahlzeit { 42449fa1748Smahlzeit int32 timeAdjust; 42549fa1748Smahlzeit bool firstEvent = true; 42649fa1748Smahlzeit 4276ba60405Smahlzeit while (KeepRunning()) 4286ba60405Smahlzeit { 42949fa1748Smahlzeit BMidiEvent* event = EventAt(currentEvent); 43049fa1748Smahlzeit if (event == NULL) { return; } 4316ba60405Smahlzeit 43249fa1748Smahlzeit if (firstEvent) 4336ba60405Smahlzeit { 43449fa1748Smahlzeit startTime = B_NOW; 43549fa1748Smahlzeit timeAdjust = startTime - GetEventTime(event); 43649fa1748Smahlzeit SprayEvent(event, startTime); 43749fa1748Smahlzeit firstEvent = false; 438eac71506Sjerl1 } 43949fa1748Smahlzeit else 440eac71506Sjerl1 { 44149fa1748Smahlzeit SprayEvent(event, GetEventTime(event) + timeAdjust); 4426ba60405Smahlzeit } 4436ba60405Smahlzeit 44449fa1748Smahlzeit ++currentEvent; 44549fa1748Smahlzeit } 4466ba60405Smahlzeit } 4476ba60405Smahlzeit 44849fa1748Smahlzeit //------------------------------------------------------------------------------ 4496ba60405Smahlzeit 45049fa1748Smahlzeit void BMidiStore::AddEvent(BMidiEvent* event) 45125767509Smahlzeit { 45249fa1748Smahlzeit events->AddItem(event); 45349fa1748Smahlzeit needsSorting = true; 45425767509Smahlzeit } 45525767509Smahlzeit 45649fa1748Smahlzeit //------------------------------------------------------------------------------ 45749fa1748Smahlzeit 45849fa1748Smahlzeit void BMidiStore::SprayEvent(const BMidiEvent* event, uint32 time) 45925767509Smahlzeit { 46049fa1748Smahlzeit uchar byte1 = event->byte1; 46149fa1748Smahlzeit uchar byte2 = event->byte2; 46249fa1748Smahlzeit uchar byte3 = event->byte3; 46325767509Smahlzeit 46449fa1748Smahlzeit switch (byte1 & 0xF0) 465eac71506Sjerl1 { 466eac71506Sjerl1 case B_NOTE_OFF: 46749fa1748Smahlzeit SprayNoteOff((byte1 & 0x0F) + 1, byte2, byte3, time); 46849fa1748Smahlzeit return; 46949fa1748Smahlzeit 470eac71506Sjerl1 case B_NOTE_ON: 47149fa1748Smahlzeit SprayNoteOn((byte1 & 0x0F) + 1, byte2, byte3, time); 47249fa1748Smahlzeit return; 47349fa1748Smahlzeit 474eac71506Sjerl1 case B_KEY_PRESSURE: 47549fa1748Smahlzeit SprayKeyPressure((byte1 & 0x0F) + 1, byte2, byte3, time); 47649fa1748Smahlzeit return; 47749fa1748Smahlzeit 478eac71506Sjerl1 case B_CONTROL_CHANGE: 47949fa1748Smahlzeit SprayControlChange((byte1 & 0x0F) + 1, byte2, byte3, time); 48049fa1748Smahlzeit return; 48149fa1748Smahlzeit 482eac71506Sjerl1 case B_PROGRAM_CHANGE: 48349fa1748Smahlzeit SprayProgramChange((byte1 & 0x0F) + 1, byte2, time); 48449fa1748Smahlzeit return; 48549fa1748Smahlzeit 486eac71506Sjerl1 case B_CHANNEL_PRESSURE: 48749fa1748Smahlzeit SprayChannelPressure((byte1 & 0x0F) + 1, byte2, time); 48849fa1748Smahlzeit return; 48949fa1748Smahlzeit 49049fa1748Smahlzeit case B_PITCH_BEND: 49149fa1748Smahlzeit SprayPitchBend((byte1 & 0x0F) + 1, byte2, byte3, time); 49249fa1748Smahlzeit return; 49349fa1748Smahlzeit 49449fa1748Smahlzeit case 0xF0: 49549fa1748Smahlzeit switch (byte1) 496eac71506Sjerl1 { 497eac71506Sjerl1 case B_SYS_EX_START: 49849fa1748Smahlzeit SpraySystemExclusive(event->data, event->length, time); 49949fa1748Smahlzeit return; 50049fa1748Smahlzeit 501eac71506Sjerl1 case B_MIDI_TIME_CODE: 50249fa1748Smahlzeit case B_SONG_POSITION: 503eac71506Sjerl1 case B_SONG_SELECT: 50449fa1748Smahlzeit case B_CABLE_MESSAGE: 505eac71506Sjerl1 case B_TUNE_REQUEST: 50649fa1748Smahlzeit case B_SYS_EX_END: 50749fa1748Smahlzeit SpraySystemCommon(byte1, byte2, byte3, time); 50849fa1748Smahlzeit return; 50949fa1748Smahlzeit 510eac71506Sjerl1 case B_TIMING_CLOCK: 511eac71506Sjerl1 case B_START: 512eac71506Sjerl1 case B_CONTINUE: 513eac71506Sjerl1 case B_STOP: 514eac71506Sjerl1 case B_ACTIVE_SENSING: 51549fa1748Smahlzeit SpraySystemRealTime(byte1, time); 51649fa1748Smahlzeit return; 51749fa1748Smahlzeit 518eac71506Sjerl1 case B_SYSTEM_RESET: 51949fa1748Smahlzeit if ((byte2 == 0x51) && (byte3 == 0x03)) 52049fa1748Smahlzeit { 52149fa1748Smahlzeit SprayTempoChange(event->tempo, time); 52249fa1748Smahlzeit beatsPerMinute = event->tempo; 523eac71506Sjerl1 } 524eac71506Sjerl1 else 525eac71506Sjerl1 { 52649fa1748Smahlzeit SpraySystemRealTime(byte1, time); 527eac71506Sjerl1 } 52849fa1748Smahlzeit return; 529eac71506Sjerl1 } 53049fa1748Smahlzeit return; 531eac71506Sjerl1 } 532eac71506Sjerl1 } 533eac71506Sjerl1 53449fa1748Smahlzeit //------------------------------------------------------------------------------ 535eac71506Sjerl1 53649fa1748Smahlzeit BMidiEvent* BMidiStore::EventAt(int32 index) const 537eac71506Sjerl1 { 53849fa1748Smahlzeit return (BMidiEvent*) events->ItemAt(index); 539eac71506Sjerl1 } 540eac71506Sjerl1 54149fa1748Smahlzeit //------------------------------------------------------------------------------ 542eac71506Sjerl1 54349fa1748Smahlzeit uint32 BMidiStore::GetEventTime(const BMidiEvent* event) const 544eac71506Sjerl1 { 54549fa1748Smahlzeit if (event->ticks) 54649fa1748Smahlzeit { 54749fa1748Smahlzeit return TicksToMilliseconds(event->time); 54849fa1748Smahlzeit } 549eac71506Sjerl1 else 550eac71506Sjerl1 { 55149fa1748Smahlzeit return event->time; 55249fa1748Smahlzeit } 55349fa1748Smahlzeit } 55449fa1748Smahlzeit 55549fa1748Smahlzeit //------------------------------------------------------------------------------ 55649fa1748Smahlzeit 55749fa1748Smahlzeit uint32 BMidiStore::TicksToMilliseconds(uint32 ticks) const 558eac71506Sjerl1 { 55949fa1748Smahlzeit return ((uint64) ticks * 60000) / (beatsPerMinute * ticksPerBeat); 56049fa1748Smahlzeit } 56149fa1748Smahlzeit 56249fa1748Smahlzeit //------------------------------------------------------------------------------ 56349fa1748Smahlzeit 56449fa1748Smahlzeit uint32 BMidiStore::MillisecondsToTicks(uint32 ms) const 565eac71506Sjerl1 { 56649fa1748Smahlzeit return ((uint64) ms * beatsPerMinute * ticksPerBeat) / 60000; 567eac71506Sjerl1 } 56849fa1748Smahlzeit 56949fa1748Smahlzeit //------------------------------------------------------------------------------ 57049fa1748Smahlzeit 57149fa1748Smahlzeit void BMidiStore::ReadFourCC(char* fourcc) 572eac71506Sjerl1 { 57349fa1748Smahlzeit if (file->Read(fourcc, 4) != 4) 574eac71506Sjerl1 { 57549fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 576eac71506Sjerl1 } 57749fa1748Smahlzeit } 57849fa1748Smahlzeit 57949fa1748Smahlzeit //------------------------------------------------------------------------------ 58049fa1748Smahlzeit 58149fa1748Smahlzeit void BMidiStore::WriteFourCC(char a, char b, char c, char d) 582eac71506Sjerl1 { 58349fa1748Smahlzeit char fourcc[4] = { a, b, c, d }; 58449fa1748Smahlzeit if (file->Write(fourcc, 4) != 4) 585eac71506Sjerl1 { 58649fa1748Smahlzeit throw (status_t) B_ERROR; 587eac71506Sjerl1 } 58849fa1748Smahlzeit } 58949fa1748Smahlzeit 59049fa1748Smahlzeit //------------------------------------------------------------------------------ 59149fa1748Smahlzeit 59249fa1748Smahlzeit uint32 BMidiStore::Read32Bit() 593eac71506Sjerl1 { 59449fa1748Smahlzeit uint8 buf[4]; 59549fa1748Smahlzeit if (file->Read(buf, 4) != 4) 596eac71506Sjerl1 { 59749fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 598eac71506Sjerl1 } 59949fa1748Smahlzeit 60049fa1748Smahlzeit return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; 60149fa1748Smahlzeit } 60249fa1748Smahlzeit 60349fa1748Smahlzeit //------------------------------------------------------------------------------ 60449fa1748Smahlzeit 60549fa1748Smahlzeit void BMidiStore::Write32Bit(uint32 val) 606eac71506Sjerl1 { 60749fa1748Smahlzeit uint8 buf[4]; 60849fa1748Smahlzeit buf[0] = (val >> 24) & 0xFF; 60949fa1748Smahlzeit buf[1] = (val >> 16) & 0xFF; 61049fa1748Smahlzeit buf[2] = (val >> 8) & 0xFF; 61149fa1748Smahlzeit buf[3] = val & 0xFF; 61249fa1748Smahlzeit 61349fa1748Smahlzeit if (file->Write(buf, 4) != 4) 614eac71506Sjerl1 { 61549fa1748Smahlzeit throw (status_t) B_ERROR; 616eac71506Sjerl1 } 61749fa1748Smahlzeit } 61849fa1748Smahlzeit 61949fa1748Smahlzeit //------------------------------------------------------------------------------ 62049fa1748Smahlzeit 62149fa1748Smahlzeit uint16 BMidiStore::Read16Bit() 622eac71506Sjerl1 { 62349fa1748Smahlzeit uint8 buf[2]; 62449fa1748Smahlzeit if (file->Read(buf, 2) != 2) 625eac71506Sjerl1 { 62649fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 627eac71506Sjerl1 } 628eac71506Sjerl1 62949fa1748Smahlzeit return (buf[0] << 8) | buf[1]; 630eac71506Sjerl1 } 631eac71506Sjerl1 63249fa1748Smahlzeit //------------------------------------------------------------------------------ 633eac71506Sjerl1 63449fa1748Smahlzeit void BMidiStore::Write16Bit(uint16 val) 635eac71506Sjerl1 { 63649fa1748Smahlzeit uint8 buf[2]; 63749fa1748Smahlzeit buf[0] = (val >> 8) & 0xFF; 63849fa1748Smahlzeit buf[1] = val & 0xFF; 639eac71506Sjerl1 64049fa1748Smahlzeit if (file->Write(buf, 2) != 2) 641eac71506Sjerl1 { 64249fa1748Smahlzeit throw (status_t) B_ERROR; 643eac71506Sjerl1 } 644eac71506Sjerl1 } 645eac71506Sjerl1 64649fa1748Smahlzeit //------------------------------------------------------------------------------ 647eac71506Sjerl1 64849fa1748Smahlzeit uint8 BMidiStore::PeekByte() 649eac71506Sjerl1 { 65049fa1748Smahlzeit uint8 buf; 65149fa1748Smahlzeit if (file->Read(&buf, 1) != 1) 65249fa1748Smahlzeit { 65349fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 654eac71506Sjerl1 } 655eac71506Sjerl1 65649fa1748Smahlzeit if (file->Seek(-1, SEEK_CUR) < 0) 65749fa1748Smahlzeit { 65849fa1748Smahlzeit throw (status_t) B_ERROR; 659eac71506Sjerl1 } 660eac71506Sjerl1 66149fa1748Smahlzeit return buf; 66249fa1748Smahlzeit } 663eac71506Sjerl1 66449fa1748Smahlzeit //------------------------------------------------------------------------------ 66549fa1748Smahlzeit 66649fa1748Smahlzeit uint8 BMidiStore::NextByte() 66749fa1748Smahlzeit { 66849fa1748Smahlzeit uint8 buf; 66949fa1748Smahlzeit if (file->Read(&buf, 1) != 1) 67049fa1748Smahlzeit { 67149fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 67249fa1748Smahlzeit } 67349fa1748Smahlzeit 67449fa1748Smahlzeit --byteCount; 67549fa1748Smahlzeit return buf; 67649fa1748Smahlzeit } 67749fa1748Smahlzeit 67849fa1748Smahlzeit //------------------------------------------------------------------------------ 67949fa1748Smahlzeit 68049fa1748Smahlzeit void BMidiStore::WriteByte(uint8 val) 68149fa1748Smahlzeit { 68249fa1748Smahlzeit if (file->Write(&val, 1) != 1) 68349fa1748Smahlzeit { 68449fa1748Smahlzeit throw (status_t) B_ERROR; 68549fa1748Smahlzeit } 68649fa1748Smahlzeit 68749fa1748Smahlzeit ++byteCount; 68849fa1748Smahlzeit } 68949fa1748Smahlzeit 69049fa1748Smahlzeit //------------------------------------------------------------------------------ 69149fa1748Smahlzeit 69249fa1748Smahlzeit void BMidiStore::SkipBytes(uint32 length) 69349fa1748Smahlzeit { 69449fa1748Smahlzeit if (file->Seek(length, SEEK_CUR) < 0) 69549fa1748Smahlzeit { 69649fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 69749fa1748Smahlzeit } 69849fa1748Smahlzeit 69949fa1748Smahlzeit byteCount -= length; 70049fa1748Smahlzeit } 70149fa1748Smahlzeit 70249fa1748Smahlzeit //------------------------------------------------------------------------------ 70349fa1748Smahlzeit 70449fa1748Smahlzeit uint32 BMidiStore::ReadVarLength() 70549fa1748Smahlzeit { 70649fa1748Smahlzeit uint32 val; 70749fa1748Smahlzeit uint8 byte; 70849fa1748Smahlzeit 70949fa1748Smahlzeit if ((val = NextByte()) & 0x80) 71049fa1748Smahlzeit { 71149fa1748Smahlzeit val &= 0x7F; 71249fa1748Smahlzeit do 71349fa1748Smahlzeit { 71449fa1748Smahlzeit val = (val << 7) + ((byte = NextByte()) & 0x7F); 71549fa1748Smahlzeit } 71649fa1748Smahlzeit while (byte & 0x80); 71749fa1748Smahlzeit } 71849fa1748Smahlzeit 71949fa1748Smahlzeit return val; 72049fa1748Smahlzeit } 72149fa1748Smahlzeit 72249fa1748Smahlzeit //------------------------------------------------------------------------------ 72349fa1748Smahlzeit 72449fa1748Smahlzeit void BMidiStore::WriteVarLength(uint32 val) 72549fa1748Smahlzeit { 72649fa1748Smahlzeit uint32 buffer = val & 0x7F; 72749fa1748Smahlzeit 72849fa1748Smahlzeit while ((val >>= 7)) 729eac71506Sjerl1 { 730eac71506Sjerl1 buffer <<= 8; 73149fa1748Smahlzeit buffer |= ((val & 0x7F) | 0x80); 732eac71506Sjerl1 } 73349fa1748Smahlzeit 734eac71506Sjerl1 while (true) 735eac71506Sjerl1 { 73649fa1748Smahlzeit WriteByte(buffer); 737eac71506Sjerl1 if (buffer & 0x80) 738eac71506Sjerl1 buffer >>= 8; 739eac71506Sjerl1 else 740eac71506Sjerl1 break; 74125767509Smahlzeit } 74225767509Smahlzeit } 74325767509Smahlzeit 74449fa1748Smahlzeit //------------------------------------------------------------------------------ 74525767509Smahlzeit 74649fa1748Smahlzeit void BMidiStore::ReadChunk() 747eac71506Sjerl1 { 74849fa1748Smahlzeit char fourcc[4]; 74949fa1748Smahlzeit ReadFourCC(fourcc); 750eac71506Sjerl1 75149fa1748Smahlzeit byteCount = Read32Bit(); 752eac71506Sjerl1 75349fa1748Smahlzeit if (strncmp(fourcc, "MTrk", 4) == 0) 754eac71506Sjerl1 { 75549fa1748Smahlzeit ReadTrack(); 756eac71506Sjerl1 } 75749fa1748Smahlzeit else 758eac71506Sjerl1 { 75949fa1748Smahlzeit TRACE(("Skipping '%c%c%c%c' chunk (%lu bytes)", 76049fa1748Smahlzeit fourcc[0], fourcc[1], fourcc[2], fourcc[3], byteCount)) 76149fa1748Smahlzeit 76249fa1748Smahlzeit SkipBytes(byteCount); 76349fa1748Smahlzeit } 764eac71506Sjerl1 } 765eac71506Sjerl1 76649fa1748Smahlzeit //------------------------------------------------------------------------------ 76749fa1748Smahlzeit 76849fa1748Smahlzeit void BMidiStore::ReadTrack() 76949fa1748Smahlzeit { 77049fa1748Smahlzeit uint8 status = 0; 77149fa1748Smahlzeit uint8 data1; 77249fa1748Smahlzeit uint8 data2; 77349fa1748Smahlzeit BMidiEvent* event; 77449fa1748Smahlzeit 77549fa1748Smahlzeit totalTicks = 0; 77649fa1748Smahlzeit 77749fa1748Smahlzeit while (byteCount > 0) 77849fa1748Smahlzeit { 77949fa1748Smahlzeit uint32 ticks = ReadVarLength(); 78049fa1748Smahlzeit totalTicks += ticks; 78149fa1748Smahlzeit 78249fa1748Smahlzeit if (PeekByte() & 0x80) 78349fa1748Smahlzeit { 78449fa1748Smahlzeit status = NextByte(); 78549fa1748Smahlzeit } 78649fa1748Smahlzeit 78749fa1748Smahlzeit switch (status & 0xF0) 78849fa1748Smahlzeit { 78949fa1748Smahlzeit case B_NOTE_OFF: 79049fa1748Smahlzeit case B_NOTE_ON: 79149fa1748Smahlzeit case B_KEY_PRESSURE: 79249fa1748Smahlzeit case B_CONTROL_CHANGE: 79349fa1748Smahlzeit case B_PITCH_BEND: 79449fa1748Smahlzeit data1 = NextByte(); 79549fa1748Smahlzeit data2 = NextByte(); 79649fa1748Smahlzeit event = new BMidiEvent; 79749fa1748Smahlzeit event->time = totalTicks; 79849fa1748Smahlzeit event->ticks = true; 79949fa1748Smahlzeit event->byte1 = status; 80049fa1748Smahlzeit event->byte2 = data1; 80149fa1748Smahlzeit event->byte3 = data2; 80249fa1748Smahlzeit AddEvent(event); 80349fa1748Smahlzeit break; 80449fa1748Smahlzeit 80549fa1748Smahlzeit case B_PROGRAM_CHANGE: 80649fa1748Smahlzeit case B_CHANNEL_PRESSURE: 80749fa1748Smahlzeit data1 = NextByte(); 80849fa1748Smahlzeit event = new BMidiEvent; 80949fa1748Smahlzeit event->time = totalTicks; 81049fa1748Smahlzeit event->ticks = true; 81149fa1748Smahlzeit event->byte1 = status; 81249fa1748Smahlzeit event->byte2 = data1; 81349fa1748Smahlzeit AddEvent(event); 81449fa1748Smahlzeit break; 81549fa1748Smahlzeit 81649fa1748Smahlzeit case 0xF0: 81749fa1748Smahlzeit switch (status) 81849fa1748Smahlzeit { 81949fa1748Smahlzeit case B_SYS_EX_START: 82049fa1748Smahlzeit ReadSystemExclusive(); 82149fa1748Smahlzeit break; 82249fa1748Smahlzeit 82349fa1748Smahlzeit case B_TUNE_REQUEST: 82449fa1748Smahlzeit case B_SYS_EX_END: 82549fa1748Smahlzeit case B_TIMING_CLOCK: 82649fa1748Smahlzeit case B_START: 82749fa1748Smahlzeit case B_CONTINUE: 82849fa1748Smahlzeit case B_STOP: 82949fa1748Smahlzeit case B_ACTIVE_SENSING: 83049fa1748Smahlzeit event = new BMidiEvent; 83149fa1748Smahlzeit event->time = totalTicks; 83249fa1748Smahlzeit event->ticks = true; 83349fa1748Smahlzeit event->byte1 = status; 83449fa1748Smahlzeit AddEvent(event); 83549fa1748Smahlzeit break; 83649fa1748Smahlzeit 83749fa1748Smahlzeit case B_MIDI_TIME_CODE: 83849fa1748Smahlzeit case B_SONG_SELECT: 83949fa1748Smahlzeit case B_CABLE_MESSAGE: 84049fa1748Smahlzeit data1 = NextByte(); 84149fa1748Smahlzeit event = new BMidiEvent; 84249fa1748Smahlzeit event->time = totalTicks; 84349fa1748Smahlzeit event->ticks = true; 84449fa1748Smahlzeit event->byte1 = status; 84549fa1748Smahlzeit event->byte2 = data1; 84649fa1748Smahlzeit AddEvent(event); 84749fa1748Smahlzeit break; 84849fa1748Smahlzeit 84949fa1748Smahlzeit case B_SONG_POSITION: 85049fa1748Smahlzeit data1 = NextByte(); 85149fa1748Smahlzeit data2 = NextByte(); 85249fa1748Smahlzeit event = new BMidiEvent; 85349fa1748Smahlzeit event->time = totalTicks; 85449fa1748Smahlzeit event->ticks = true; 85549fa1748Smahlzeit event->byte1 = status; 85649fa1748Smahlzeit event->byte2 = data1; 85749fa1748Smahlzeit event->byte3 = data2; 85849fa1748Smahlzeit AddEvent(event); 85949fa1748Smahlzeit break; 86049fa1748Smahlzeit 86149fa1748Smahlzeit case B_SYSTEM_RESET: 86249fa1748Smahlzeit ReadMetaEvent(); 86349fa1748Smahlzeit break; 86449fa1748Smahlzeit } 86549fa1748Smahlzeit break; 86649fa1748Smahlzeit } 86749fa1748Smahlzeit 86849fa1748Smahlzeit event = NULL; 86949fa1748Smahlzeit } 87049fa1748Smahlzeit 87149fa1748Smahlzeit ++currTrack; 87249fa1748Smahlzeit } 87349fa1748Smahlzeit 87449fa1748Smahlzeit //------------------------------------------------------------------------------ 87549fa1748Smahlzeit 87649fa1748Smahlzeit void BMidiStore::ReadSystemExclusive() 87749fa1748Smahlzeit { 87849fa1748Smahlzeit // We do not import sysex's from MIDI files. 87949fa1748Smahlzeit 88049fa1748Smahlzeit SkipBytes(ReadVarLength()); 88149fa1748Smahlzeit } 88249fa1748Smahlzeit 88349fa1748Smahlzeit //------------------------------------------------------------------------------ 88449fa1748Smahlzeit 88549fa1748Smahlzeit void BMidiStore::ReadMetaEvent() 88649fa1748Smahlzeit { 88749fa1748Smahlzeit // We only import the Tempo Change meta event. 88849fa1748Smahlzeit 88949fa1748Smahlzeit uint8 type = NextByte(); 89049fa1748Smahlzeit uint32 length = ReadVarLength(); 89149fa1748Smahlzeit 89249fa1748Smahlzeit if ((type == 0x51) && (length == 3)) 89349fa1748Smahlzeit { 89449fa1748Smahlzeit uchar data[3]; 89549fa1748Smahlzeit data[0] = NextByte(); 89649fa1748Smahlzeit data[1] = NextByte(); 89749fa1748Smahlzeit data[2] = NextByte(); 89849fa1748Smahlzeit uint32 val = (data[0] << 16) | (data[1] << 8) | data[2]; 89949fa1748Smahlzeit 90049fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 90149fa1748Smahlzeit event->time = totalTicks; 90249fa1748Smahlzeit event->ticks = true; 90349fa1748Smahlzeit event->byte1 = 0xFF; 90449fa1748Smahlzeit event->byte2 = 0x51; 90549fa1748Smahlzeit event->byte3 = 0x03; 90649fa1748Smahlzeit event->tempo = 60000000 / val; 90749fa1748Smahlzeit AddEvent(event); 90849fa1748Smahlzeit } 90949fa1748Smahlzeit else 91049fa1748Smahlzeit { 91149fa1748Smahlzeit SkipBytes(length); 91249fa1748Smahlzeit } 91349fa1748Smahlzeit } 91449fa1748Smahlzeit 91549fa1748Smahlzeit //------------------------------------------------------------------------------ 91649fa1748Smahlzeit 91749fa1748Smahlzeit void BMidiStore::WriteTrack() 91849fa1748Smahlzeit { 91949fa1748Smahlzeit WriteFourCC('M', 'T', 'r', 'k'); 92049fa1748Smahlzeit off_t lengthPos = file->Position(); 92149fa1748Smahlzeit Write32Bit(0); 92249fa1748Smahlzeit 92349fa1748Smahlzeit byteCount = 0; 92449fa1748Smahlzeit uint32 oldTime; 92549fa1748Smahlzeit uint32 newTime; 92649fa1748Smahlzeit 927*9138338cSmahlzeit for (uint32 t = 0; t < CountEvents(); ++t) 92849fa1748Smahlzeit { 92949fa1748Smahlzeit BMidiEvent* event = EventAt(t); 93049fa1748Smahlzeit 93149fa1748Smahlzeit if (event->ticks) 93249fa1748Smahlzeit { 93349fa1748Smahlzeit newTime = event->time; 93449fa1748Smahlzeit } 93549fa1748Smahlzeit else 93649fa1748Smahlzeit { 93749fa1748Smahlzeit newTime = MillisecondsToTicks(event->time); 93849fa1748Smahlzeit } 93949fa1748Smahlzeit 94049fa1748Smahlzeit if (t == 0) 94149fa1748Smahlzeit { 94249fa1748Smahlzeit WriteVarLength(0); 94349fa1748Smahlzeit } 94449fa1748Smahlzeit else 94549fa1748Smahlzeit { 94649fa1748Smahlzeit WriteVarLength(newTime - oldTime); 94749fa1748Smahlzeit } 94849fa1748Smahlzeit 94949fa1748Smahlzeit oldTime = newTime; 95049fa1748Smahlzeit 95149fa1748Smahlzeit switch (event->byte1 & 0xF0) 95249fa1748Smahlzeit { 95349fa1748Smahlzeit case B_NOTE_OFF: 95449fa1748Smahlzeit case B_NOTE_ON: 95549fa1748Smahlzeit case B_KEY_PRESSURE: 95649fa1748Smahlzeit case B_CONTROL_CHANGE: 95749fa1748Smahlzeit case B_PITCH_BEND: 95849fa1748Smahlzeit WriteByte(event->byte1); 95949fa1748Smahlzeit WriteByte(event->byte2); 96049fa1748Smahlzeit WriteByte(event->byte3); 96149fa1748Smahlzeit break; 96249fa1748Smahlzeit 96349fa1748Smahlzeit case B_PROGRAM_CHANGE: 96449fa1748Smahlzeit case B_CHANNEL_PRESSURE: 96549fa1748Smahlzeit WriteByte(event->byte1); 96649fa1748Smahlzeit WriteByte(event->byte2); 96749fa1748Smahlzeit break; 96849fa1748Smahlzeit 96949fa1748Smahlzeit case 0xF0: 97049fa1748Smahlzeit switch (event->byte1) 97149fa1748Smahlzeit { 97249fa1748Smahlzeit case B_SYS_EX_START: 97349fa1748Smahlzeit // We do not export sysex's. 97449fa1748Smahlzeit break; 97549fa1748Smahlzeit 97649fa1748Smahlzeit case B_TUNE_REQUEST: 97749fa1748Smahlzeit case B_SYS_EX_END: 97849fa1748Smahlzeit case B_TIMING_CLOCK: 97949fa1748Smahlzeit case B_START: 98049fa1748Smahlzeit case B_CONTINUE: 98149fa1748Smahlzeit case B_STOP: 98249fa1748Smahlzeit case B_ACTIVE_SENSING: 98349fa1748Smahlzeit WriteByte(event->byte1); 98449fa1748Smahlzeit break; 98549fa1748Smahlzeit 98649fa1748Smahlzeit case B_MIDI_TIME_CODE: 98749fa1748Smahlzeit case B_SONG_SELECT: 98849fa1748Smahlzeit case B_CABLE_MESSAGE: 98949fa1748Smahlzeit WriteByte(event->byte1); 99049fa1748Smahlzeit WriteByte(event->byte2); 99149fa1748Smahlzeit break; 99249fa1748Smahlzeit 99349fa1748Smahlzeit case B_SONG_POSITION: 99449fa1748Smahlzeit WriteByte(event->byte1); 99549fa1748Smahlzeit WriteByte(event->byte2); 99649fa1748Smahlzeit WriteByte(event->byte3); 99749fa1748Smahlzeit break; 99849fa1748Smahlzeit 99949fa1748Smahlzeit case B_SYSTEM_RESET: 100049fa1748Smahlzeit WriteMetaEvent(event); 100149fa1748Smahlzeit break; 100249fa1748Smahlzeit } 100349fa1748Smahlzeit break; 100449fa1748Smahlzeit 100549fa1748Smahlzeit } 100649fa1748Smahlzeit } 100749fa1748Smahlzeit 100849fa1748Smahlzeit WriteVarLength(0); 100949fa1748Smahlzeit WriteByte(0xFF); // the end-of-track 101049fa1748Smahlzeit WriteByte(0x2F); // marker is required 101149fa1748Smahlzeit WriteByte(0x00); 101249fa1748Smahlzeit 101349fa1748Smahlzeit file->Seek(lengthPos, SEEK_SET); 101449fa1748Smahlzeit Write32Bit(byteCount); 101549fa1748Smahlzeit file->Seek(0, SEEK_END); 101649fa1748Smahlzeit } 101749fa1748Smahlzeit 101849fa1748Smahlzeit //------------------------------------------------------------------------------ 101949fa1748Smahlzeit 102049fa1748Smahlzeit void BMidiStore::WriteMetaEvent(BMidiEvent* event) 102149fa1748Smahlzeit { 102249fa1748Smahlzeit // We only export the Tempo Change meta event. 102349fa1748Smahlzeit 102449fa1748Smahlzeit if ((event->byte2 == 0x51) && (event->byte3 == 0x03)) 102549fa1748Smahlzeit { 102649fa1748Smahlzeit uint32 val = 60000000 / event->tempo; 102749fa1748Smahlzeit 102849fa1748Smahlzeit WriteByte(0xFF); 102949fa1748Smahlzeit WriteByte(0x51); 103049fa1748Smahlzeit WriteByte(0x03); 103149fa1748Smahlzeit WriteByte(val >> 16); 103249fa1748Smahlzeit WriteByte(val >> 8); 103349fa1748Smahlzeit WriteByte(val); 103449fa1748Smahlzeit } 103549fa1748Smahlzeit } 103649fa1748Smahlzeit 103749fa1748Smahlzeit //------------------------------------------------------------------------------ 1038