149fa1748Smahlzeit /* 29138338cSmahlzeit * 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; 83b178e190Smahlzeit hookFunc = NULL; 84b178e190Smahlzeit looping = false; 85b178e190Smahlzeit paused = false; 86b178e190Smahlzeit finished = false; 87*f9b2179cSmahlzeit instruments = new bool[128]; 8852a38012Sejakowatz } 8952a38012Sejakowatz 9049fa1748Smahlzeit //------------------------------------------------------------------------------ 916ba60405Smahlzeit 926ba60405Smahlzeit BMidiStore::~BMidiStore() 936ba60405Smahlzeit { 9449fa1748Smahlzeit for (int32 t = 0; t < events->CountItems(); ++t) 956ba60405Smahlzeit { 9649fa1748Smahlzeit delete EventAt(t); 9752a38012Sejakowatz } 986ba60405Smahlzeit delete events; 99*f9b2179cSmahlzeit delete[] instruments; 10052a38012Sejakowatz } 10152a38012Sejakowatz 10249fa1748Smahlzeit //------------------------------------------------------------------------------ 10352a38012Sejakowatz 10449fa1748Smahlzeit void BMidiStore::NoteOff( 10549fa1748Smahlzeit uchar channel, uchar note, uchar velocity, uint32 time) 1066ba60405Smahlzeit { 10749fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 10849fa1748Smahlzeit event->time = time; 10949fa1748Smahlzeit event->ticks = false; 11049fa1748Smahlzeit event->byte1 = B_NOTE_OFF | (channel - 1); 11149fa1748Smahlzeit event->byte2 = note; 11249fa1748Smahlzeit event->byte3 = velocity; 11349fa1748Smahlzeit AddEvent(event); 1146ba60405Smahlzeit } 1156ba60405Smahlzeit 11649fa1748Smahlzeit //------------------------------------------------------------------------------ 1176ba60405Smahlzeit 11849fa1748Smahlzeit void BMidiStore::NoteOn( 11949fa1748Smahlzeit uchar channel, uchar note, uchar velocity, uint32 time) 1206ba60405Smahlzeit { 12149fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 12249fa1748Smahlzeit event->time = time; 12349fa1748Smahlzeit event->ticks = false; 12449fa1748Smahlzeit event->byte1 = B_NOTE_ON | (channel - 1); 12549fa1748Smahlzeit event->byte2 = note; 12649fa1748Smahlzeit event->byte3 = velocity; 12749fa1748Smahlzeit AddEvent(event); 1286ba60405Smahlzeit } 1296ba60405Smahlzeit 13049fa1748Smahlzeit //------------------------------------------------------------------------------ 1316ba60405Smahlzeit 13249fa1748Smahlzeit void BMidiStore::KeyPressure( 13349fa1748Smahlzeit uchar channel, uchar note, uchar pressure, uint32 time) 1346ba60405Smahlzeit { 13549fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 13649fa1748Smahlzeit event->time = time; 13749fa1748Smahlzeit event->ticks = false; 13849fa1748Smahlzeit event->byte1 = B_KEY_PRESSURE | (channel - 1); 13949fa1748Smahlzeit event->byte2 = note; 14049fa1748Smahlzeit event->byte3 = pressure; 14149fa1748Smahlzeit AddEvent(event); 1426ba60405Smahlzeit } 1436ba60405Smahlzeit 14449fa1748Smahlzeit //------------------------------------------------------------------------------ 1456ba60405Smahlzeit 14649fa1748Smahlzeit void BMidiStore::ControlChange( 14749fa1748Smahlzeit uchar channel, uchar controlNumber, uchar controlValue, uint32 time) 1486ba60405Smahlzeit { 14949fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 15049fa1748Smahlzeit event->time = time; 15149fa1748Smahlzeit event->ticks = false; 15249fa1748Smahlzeit event->byte1 = B_CONTROL_CHANGE | (channel - 1); 15349fa1748Smahlzeit event->byte2 = controlNumber; 15449fa1748Smahlzeit event->byte3 = controlValue; 15549fa1748Smahlzeit AddEvent(event); 1566ba60405Smahlzeit } 1576ba60405Smahlzeit 15849fa1748Smahlzeit //------------------------------------------------------------------------------ 1596ba60405Smahlzeit 16049fa1748Smahlzeit void BMidiStore::ProgramChange( 16149fa1748Smahlzeit uchar channel, uchar programNumber, uint32 time) 1626ba60405Smahlzeit { 16349fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 16449fa1748Smahlzeit event->time = time; 16549fa1748Smahlzeit event->ticks = false; 16649fa1748Smahlzeit event->byte1 = B_PROGRAM_CHANGE | (channel - 1); 16749fa1748Smahlzeit event->byte2 = programNumber; 16849fa1748Smahlzeit AddEvent(event); 1696ba60405Smahlzeit } 1706ba60405Smahlzeit 17149fa1748Smahlzeit //------------------------------------------------------------------------------ 1726ba60405Smahlzeit 17349fa1748Smahlzeit void BMidiStore::ChannelPressure(uchar channel, uchar pressure, uint32 time) 1746ba60405Smahlzeit { 17549fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 17649fa1748Smahlzeit event->time = time; 17749fa1748Smahlzeit event->ticks = false; 17849fa1748Smahlzeit event->byte1 = B_CHANNEL_PRESSURE | (channel - 1); 17949fa1748Smahlzeit event->byte2 = pressure; 18049fa1748Smahlzeit AddEvent(event); 1816ba60405Smahlzeit } 1826ba60405Smahlzeit 18349fa1748Smahlzeit //------------------------------------------------------------------------------ 1846ba60405Smahlzeit 18549fa1748Smahlzeit void BMidiStore::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time) 1866ba60405Smahlzeit { 18749fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 18849fa1748Smahlzeit event->time = time; 18949fa1748Smahlzeit event->ticks = false; 19049fa1748Smahlzeit event->byte1 = B_PITCH_BEND | (channel - 1); 19149fa1748Smahlzeit event->byte2 = lsb; 19249fa1748Smahlzeit event->byte3 = msb; 19349fa1748Smahlzeit AddEvent(event); 19452a38012Sejakowatz } 19552a38012Sejakowatz 19649fa1748Smahlzeit //------------------------------------------------------------------------------ 1976ba60405Smahlzeit 19849fa1748Smahlzeit void BMidiStore::SystemExclusive(void* data, size_t length, uint32 time) 1996ba60405Smahlzeit { 20049fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 20149fa1748Smahlzeit event->time = time; 20249fa1748Smahlzeit event->ticks = false; 20349fa1748Smahlzeit event->byte1 = B_SYS_EX_START; 20449fa1748Smahlzeit event->data = malloc(length); 20549fa1748Smahlzeit event->length = length; 20649fa1748Smahlzeit memcpy(event->data, data, length); 20749fa1748Smahlzeit AddEvent(event); 20852a38012Sejakowatz } 20952a38012Sejakowatz 21049fa1748Smahlzeit //------------------------------------------------------------------------------ 2116ba60405Smahlzeit 21249fa1748Smahlzeit void BMidiStore::SystemCommon( 21349fa1748Smahlzeit uchar status, uchar data1, uchar data2, uint32 time) 2146ba60405Smahlzeit { 21549fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 21649fa1748Smahlzeit event->time = time; 21749fa1748Smahlzeit event->ticks = false; 21849fa1748Smahlzeit event->byte1 = status; 21949fa1748Smahlzeit event->byte2 = data1; 22049fa1748Smahlzeit event->byte3 = data2; 22149fa1748Smahlzeit AddEvent(event); 22252a38012Sejakowatz } 22352a38012Sejakowatz 22449fa1748Smahlzeit //------------------------------------------------------------------------------ 22552a38012Sejakowatz 22649fa1748Smahlzeit void BMidiStore::SystemRealTime(uchar status, uint32 time) 2276ba60405Smahlzeit { 22849fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 22949fa1748Smahlzeit event->time = time; 23049fa1748Smahlzeit event->ticks = false; 23149fa1748Smahlzeit event->byte1 = status; 23249fa1748Smahlzeit AddEvent(event); 23352a38012Sejakowatz } 23452a38012Sejakowatz 23549fa1748Smahlzeit //------------------------------------------------------------------------------ 23649fa1748Smahlzeit 23749fa1748Smahlzeit void BMidiStore::TempoChange(int32 beatsPerMinute, uint32 time) 23849fa1748Smahlzeit { 23949fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 24049fa1748Smahlzeit event->time = time; 24149fa1748Smahlzeit event->ticks = false; 24249fa1748Smahlzeit event->byte1 = 0xFF; 24349fa1748Smahlzeit event->byte2 = 0x51; 24449fa1748Smahlzeit event->byte3 = 0x03; 24549fa1748Smahlzeit event->tempo = beatsPerMinute; 24649fa1748Smahlzeit AddEvent(event); 24749fa1748Smahlzeit } 24849fa1748Smahlzeit 24949fa1748Smahlzeit //------------------------------------------------------------------------------ 2506ba60405Smahlzeit 2516ba60405Smahlzeit status_t BMidiStore::Import(const entry_ref* ref) 2526ba60405Smahlzeit { 253*f9b2179cSmahlzeit memset(instruments, 0, 128 * sizeof(bool)); 254*f9b2179cSmahlzeit 25549fa1748Smahlzeit try 25649fa1748Smahlzeit { 25749fa1748Smahlzeit file = new BFile(ref, B_READ_ONLY); 25849fa1748Smahlzeit if (file->InitCheck() != B_OK) 25949fa1748Smahlzeit { 26049fa1748Smahlzeit throw file->InitCheck(); 26125767509Smahlzeit } 26225767509Smahlzeit 26349fa1748Smahlzeit char fourcc[4]; 26449fa1748Smahlzeit ReadFourCC(fourcc); 26549fa1748Smahlzeit if (strncmp(fourcc, "MThd", 4) != 0) 266eac71506Sjerl1 { 26749fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 268eac71506Sjerl1 } 26925767509Smahlzeit 27049fa1748Smahlzeit if (Read32Bit() != 6) 271eac71506Sjerl1 { 27249fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 273eac71506Sjerl1 } 274eac71506Sjerl1 27549fa1748Smahlzeit format = Read16Bit(); 27649fa1748Smahlzeit numTracks = Read16Bit(); 27749fa1748Smahlzeit ticksPerBeat = Read16Bit(); 27849fa1748Smahlzeit 27949fa1748Smahlzeit if (ticksPerBeat & 0x8000) // we don't support SMPTE 28049fa1748Smahlzeit { // time codes, only ticks 28149fa1748Smahlzeit ticksPerBeat = 240; // per quarter note 282eac71506Sjerl1 } 283eac71506Sjerl1 28449fa1748Smahlzeit currTrack = 0; 28549fa1748Smahlzeit while (currTrack < numTracks) 2866ba60405Smahlzeit { 28749fa1748Smahlzeit ReadChunk(); 28849fa1748Smahlzeit } 28949fa1748Smahlzeit } 29049fa1748Smahlzeit catch (status_t e) 29149fa1748Smahlzeit { 29249fa1748Smahlzeit delete file; 29349fa1748Smahlzeit file = NULL; 29449fa1748Smahlzeit return e; 295eac71506Sjerl1 } 296eac71506Sjerl1 297eac71506Sjerl1 SortEvents(true); 298eac71506Sjerl1 29949fa1748Smahlzeit delete file; 30049fa1748Smahlzeit file = NULL; 3016ba60405Smahlzeit return B_OK; 3026ba60405Smahlzeit } 3036ba60405Smahlzeit 30449fa1748Smahlzeit //------------------------------------------------------------------------------ 30549fa1748Smahlzeit 30649fa1748Smahlzeit status_t BMidiStore::Export(const entry_ref* ref, int32 format) 30749fa1748Smahlzeit { 30849fa1748Smahlzeit try 30949fa1748Smahlzeit { 31049fa1748Smahlzeit file = new BFile(ref, B_READ_WRITE); 31149fa1748Smahlzeit if (file->InitCheck() != B_OK) 31249fa1748Smahlzeit { 31349fa1748Smahlzeit throw file->InitCheck(); 31449fa1748Smahlzeit } 31549fa1748Smahlzeit 31649fa1748Smahlzeit SortEvents(true); 31749fa1748Smahlzeit 31849fa1748Smahlzeit WriteFourCC('M', 'T', 'h', 'd'); 31949fa1748Smahlzeit Write32Bit(6); 32049fa1748Smahlzeit Write16Bit(0); // we do only format 0 32149fa1748Smahlzeit Write16Bit(1); 32249fa1748Smahlzeit Write16Bit(ticksPerBeat); 32349fa1748Smahlzeit 32449fa1748Smahlzeit WriteTrack(); 32549fa1748Smahlzeit } 32649fa1748Smahlzeit catch (status_t e) 32749fa1748Smahlzeit { 32849fa1748Smahlzeit delete file; 32949fa1748Smahlzeit file = NULL; 33049fa1748Smahlzeit return e; 33149fa1748Smahlzeit } 33249fa1748Smahlzeit 33349fa1748Smahlzeit delete file; 33449fa1748Smahlzeit file = NULL; 33549fa1748Smahlzeit return B_OK; 33649fa1748Smahlzeit } 33749fa1748Smahlzeit 33849fa1748Smahlzeit //------------------------------------------------------------------------------ 3396ba60405Smahlzeit 3406ba60405Smahlzeit void BMidiStore::SortEvents(bool force) 3416ba60405Smahlzeit { 34249fa1748Smahlzeit if (force || needsSorting) 34349fa1748Smahlzeit { 34449fa1748Smahlzeit events->SortItems(compare_events); 34549fa1748Smahlzeit needsSorting = false; 34649fa1748Smahlzeit } 3476ba60405Smahlzeit } 3486ba60405Smahlzeit 34949fa1748Smahlzeit //------------------------------------------------------------------------------ 3506ba60405Smahlzeit 3516ba60405Smahlzeit uint32 BMidiStore::CountEvents() const 35249fa1748Smahlzeit { 3536ba60405Smahlzeit return events->CountItems(); 3546ba60405Smahlzeit } 3556ba60405Smahlzeit 35649fa1748Smahlzeit //------------------------------------------------------------------------------ 3576ba60405Smahlzeit 3586ba60405Smahlzeit uint32 BMidiStore::CurrentEvent() const 35949fa1748Smahlzeit { 36049fa1748Smahlzeit return currentEvent; 3616ba60405Smahlzeit } 3626ba60405Smahlzeit 36349fa1748Smahlzeit //------------------------------------------------------------------------------ 3646ba60405Smahlzeit 36549fa1748Smahlzeit void BMidiStore::SetCurrentEvent(uint32 eventNumber) 36649fa1748Smahlzeit { 36749fa1748Smahlzeit currentEvent = eventNumber; 3686ba60405Smahlzeit } 3696ba60405Smahlzeit 37049fa1748Smahlzeit //------------------------------------------------------------------------------ 3716ba60405Smahlzeit 37249fa1748Smahlzeit uint32 BMidiStore::DeltaOfEvent(uint32 eventNumber) const 37349fa1748Smahlzeit { 37449fa1748Smahlzeit // Even though the BeBook says that the delta is the time span between 37549fa1748Smahlzeit // an event and the first event in the list, this doesn't appear to be 37649fa1748Smahlzeit // true for events that were captured from other BMidi objects such as 37749fa1748Smahlzeit // BMidiPort. For those events, we return the absolute timestamp. The 37849fa1748Smahlzeit // BeBook is correct for events from MIDI files, though. 37949fa1748Smahlzeit 38049fa1748Smahlzeit BMidiEvent* event = EventAt(eventNumber); 38149fa1748Smahlzeit if (event != NULL) 38249fa1748Smahlzeit { 38349fa1748Smahlzeit return GetEventTime(event); 38449fa1748Smahlzeit } 38549fa1748Smahlzeit 3866ba60405Smahlzeit return 0; 3876ba60405Smahlzeit } 3886ba60405Smahlzeit 38949fa1748Smahlzeit //------------------------------------------------------------------------------ 390eac71506Sjerl1 391eac71506Sjerl1 uint32 BMidiStore::EventAtDelta(uint32 time) const 39249fa1748Smahlzeit { 39349fa1748Smahlzeit for (int32 t = 0; t < events->CountItems(); ++t) 39449fa1748Smahlzeit { 39549fa1748Smahlzeit if (GetEventTime(EventAt(t)) >= time) { return t; } 39649fa1748Smahlzeit } 39749fa1748Smahlzeit 398eac71506Sjerl1 return 0; 399eac71506Sjerl1 } 400eac71506Sjerl1 40149fa1748Smahlzeit //------------------------------------------------------------------------------ 4026ba60405Smahlzeit 4036ba60405Smahlzeit uint32 BMidiStore::BeginTime() const 40449fa1748Smahlzeit { 40549fa1748Smahlzeit return startTime; 4066ba60405Smahlzeit } 4076ba60405Smahlzeit 40849fa1748Smahlzeit //------------------------------------------------------------------------------ 4096ba60405Smahlzeit 41049fa1748Smahlzeit void BMidiStore::SetTempo(int32 beatsPerMinute_) 41149fa1748Smahlzeit { 41249fa1748Smahlzeit beatsPerMinute = beatsPerMinute_; 4136ba60405Smahlzeit } 4146ba60405Smahlzeit 41549fa1748Smahlzeit //------------------------------------------------------------------------------ 4166ba60405Smahlzeit 4176ba60405Smahlzeit int32 BMidiStore::Tempo() const 41849fa1748Smahlzeit { 41949fa1748Smahlzeit return beatsPerMinute; 4206ba60405Smahlzeit } 4216ba60405Smahlzeit 42249fa1748Smahlzeit //------------------------------------------------------------------------------ 42349fa1748Smahlzeit 42449fa1748Smahlzeit void BMidiStore::_ReservedMidiStore1() { } 42549fa1748Smahlzeit void BMidiStore::_ReservedMidiStore2() { } 42649fa1748Smahlzeit void BMidiStore::_ReservedMidiStore3() { } 42749fa1748Smahlzeit 42849fa1748Smahlzeit //------------------------------------------------------------------------------ 4296ba60405Smahlzeit 4306ba60405Smahlzeit void BMidiStore::Run() 4316ba60405Smahlzeit { 432b178e190Smahlzeit // This rather compilicated Run() loop is not only used by BMidiStore 433b178e190Smahlzeit // but also by BMidiSynthFile. The "paused", "finished", and "looping" 434b178e190Smahlzeit // flags, and the "stop hook" are especially provided for the latter. 435b178e190Smahlzeit 436b178e190Smahlzeit paused = false; 437b178e190Smahlzeit finished = false; 438b178e190Smahlzeit 43949fa1748Smahlzeit int32 timeAdjust; 440b178e190Smahlzeit uint32 baseTime; 44149fa1748Smahlzeit bool firstEvent = true; 442b178e190Smahlzeit bool resetTime = false; 44349fa1748Smahlzeit 4446ba60405Smahlzeit while (KeepRunning()) 4456ba60405Smahlzeit { 446b178e190Smahlzeit if (paused) 447b178e190Smahlzeit { 448b178e190Smahlzeit resetTime = true; 449b178e190Smahlzeit snooze(100000); 450b178e190Smahlzeit continue; 451b178e190Smahlzeit } 452b178e190Smahlzeit 45349fa1748Smahlzeit BMidiEvent* event = EventAt(currentEvent); 454b178e190Smahlzeit 455b178e190Smahlzeit if (event == NULL) // no more events 456b178e190Smahlzeit { 457b178e190Smahlzeit if (looping) 458b178e190Smahlzeit { 459b178e190Smahlzeit resetTime = true; 460b178e190Smahlzeit currentEvent = 0; 461b178e190Smahlzeit } 462b178e190Smahlzeit else 463b178e190Smahlzeit { 464b178e190Smahlzeit break; 465b178e190Smahlzeit } 466b178e190Smahlzeit } 4676ba60405Smahlzeit 46849fa1748Smahlzeit if (firstEvent) 4696ba60405Smahlzeit { 47049fa1748Smahlzeit startTime = B_NOW; 471b178e190Smahlzeit baseTime = startTime; 472b178e190Smahlzeit } 473b178e190Smahlzeit else if (resetTime) 474b178e190Smahlzeit { 475b178e190Smahlzeit baseTime = B_NOW; 476b178e190Smahlzeit } 477b178e190Smahlzeit 478b178e190Smahlzeit if (firstEvent || resetTime) 479b178e190Smahlzeit { 480b178e190Smahlzeit timeAdjust = baseTime - GetEventTime(event); 481b178e190Smahlzeit SprayEvent(event, baseTime); 48249fa1748Smahlzeit firstEvent = false; 483b178e190Smahlzeit resetTime = false; 484eac71506Sjerl1 } 48549fa1748Smahlzeit else 486eac71506Sjerl1 { 48749fa1748Smahlzeit SprayEvent(event, GetEventTime(event) + timeAdjust); 4886ba60405Smahlzeit } 4896ba60405Smahlzeit 49049fa1748Smahlzeit ++currentEvent; 49149fa1748Smahlzeit } 492b178e190Smahlzeit 493b178e190Smahlzeit finished = true; 494b178e190Smahlzeit paused = false; 495b178e190Smahlzeit 496b178e190Smahlzeit if (hookFunc != NULL) 497b178e190Smahlzeit { 498b178e190Smahlzeit (*hookFunc)(hookArg); 499b178e190Smahlzeit } 5006ba60405Smahlzeit } 5016ba60405Smahlzeit 50249fa1748Smahlzeit //------------------------------------------------------------------------------ 5036ba60405Smahlzeit 50449fa1748Smahlzeit void BMidiStore::AddEvent(BMidiEvent* event) 50525767509Smahlzeit { 50649fa1748Smahlzeit events->AddItem(event); 50749fa1748Smahlzeit needsSorting = true; 50825767509Smahlzeit } 50925767509Smahlzeit 51049fa1748Smahlzeit //------------------------------------------------------------------------------ 51149fa1748Smahlzeit 51249fa1748Smahlzeit void BMidiStore::SprayEvent(const BMidiEvent* event, uint32 time) 51325767509Smahlzeit { 51449fa1748Smahlzeit uchar byte1 = event->byte1; 51549fa1748Smahlzeit uchar byte2 = event->byte2; 51649fa1748Smahlzeit uchar byte3 = event->byte3; 51725767509Smahlzeit 51849fa1748Smahlzeit switch (byte1 & 0xF0) 519eac71506Sjerl1 { 520eac71506Sjerl1 case B_NOTE_OFF: 52149fa1748Smahlzeit SprayNoteOff((byte1 & 0x0F) + 1, byte2, byte3, time); 52249fa1748Smahlzeit return; 52349fa1748Smahlzeit 524eac71506Sjerl1 case B_NOTE_ON: 52549fa1748Smahlzeit SprayNoteOn((byte1 & 0x0F) + 1, byte2, byte3, time); 52649fa1748Smahlzeit return; 52749fa1748Smahlzeit 528eac71506Sjerl1 case B_KEY_PRESSURE: 52949fa1748Smahlzeit SprayKeyPressure((byte1 & 0x0F) + 1, byte2, byte3, time); 53049fa1748Smahlzeit return; 53149fa1748Smahlzeit 532eac71506Sjerl1 case B_CONTROL_CHANGE: 53349fa1748Smahlzeit SprayControlChange((byte1 & 0x0F) + 1, byte2, byte3, time); 53449fa1748Smahlzeit return; 53549fa1748Smahlzeit 536eac71506Sjerl1 case B_PROGRAM_CHANGE: 53749fa1748Smahlzeit SprayProgramChange((byte1 & 0x0F) + 1, byte2, time); 53849fa1748Smahlzeit return; 53949fa1748Smahlzeit 540eac71506Sjerl1 case B_CHANNEL_PRESSURE: 54149fa1748Smahlzeit SprayChannelPressure((byte1 & 0x0F) + 1, byte2, time); 54249fa1748Smahlzeit return; 54349fa1748Smahlzeit 54449fa1748Smahlzeit case B_PITCH_BEND: 54549fa1748Smahlzeit SprayPitchBend((byte1 & 0x0F) + 1, byte2, byte3, time); 54649fa1748Smahlzeit return; 54749fa1748Smahlzeit 54849fa1748Smahlzeit case 0xF0: 54949fa1748Smahlzeit switch (byte1) 550eac71506Sjerl1 { 551eac71506Sjerl1 case B_SYS_EX_START: 55249fa1748Smahlzeit SpraySystemExclusive(event->data, event->length, time); 55349fa1748Smahlzeit return; 55449fa1748Smahlzeit 555eac71506Sjerl1 case B_MIDI_TIME_CODE: 55649fa1748Smahlzeit case B_SONG_POSITION: 557eac71506Sjerl1 case B_SONG_SELECT: 55849fa1748Smahlzeit case B_CABLE_MESSAGE: 559eac71506Sjerl1 case B_TUNE_REQUEST: 56049fa1748Smahlzeit case B_SYS_EX_END: 56149fa1748Smahlzeit SpraySystemCommon(byte1, byte2, byte3, time); 56249fa1748Smahlzeit return; 56349fa1748Smahlzeit 564eac71506Sjerl1 case B_TIMING_CLOCK: 565eac71506Sjerl1 case B_START: 566eac71506Sjerl1 case B_CONTINUE: 567eac71506Sjerl1 case B_STOP: 568eac71506Sjerl1 case B_ACTIVE_SENSING: 56949fa1748Smahlzeit SpraySystemRealTime(byte1, time); 57049fa1748Smahlzeit return; 57149fa1748Smahlzeit 572eac71506Sjerl1 case B_SYSTEM_RESET: 57349fa1748Smahlzeit if ((byte2 == 0x51) && (byte3 == 0x03)) 57449fa1748Smahlzeit { 57549fa1748Smahlzeit SprayTempoChange(event->tempo, time); 57649fa1748Smahlzeit beatsPerMinute = event->tempo; 577eac71506Sjerl1 } 578eac71506Sjerl1 else 579eac71506Sjerl1 { 58049fa1748Smahlzeit SpraySystemRealTime(byte1, time); 581eac71506Sjerl1 } 58249fa1748Smahlzeit return; 583eac71506Sjerl1 } 58449fa1748Smahlzeit return; 585eac71506Sjerl1 } 586eac71506Sjerl1 } 587eac71506Sjerl1 58849fa1748Smahlzeit //------------------------------------------------------------------------------ 589eac71506Sjerl1 59049fa1748Smahlzeit BMidiEvent* BMidiStore::EventAt(int32 index) const 591eac71506Sjerl1 { 59249fa1748Smahlzeit return (BMidiEvent*) events->ItemAt(index); 593eac71506Sjerl1 } 594eac71506Sjerl1 59549fa1748Smahlzeit //------------------------------------------------------------------------------ 596eac71506Sjerl1 59749fa1748Smahlzeit uint32 BMidiStore::GetEventTime(const BMidiEvent* event) const 598eac71506Sjerl1 { 59949fa1748Smahlzeit if (event->ticks) 60049fa1748Smahlzeit { 60149fa1748Smahlzeit return TicksToMilliseconds(event->time); 60249fa1748Smahlzeit } 603eac71506Sjerl1 else 604eac71506Sjerl1 { 60549fa1748Smahlzeit return event->time; 60649fa1748Smahlzeit } 60749fa1748Smahlzeit } 60849fa1748Smahlzeit 60949fa1748Smahlzeit //------------------------------------------------------------------------------ 61049fa1748Smahlzeit 61149fa1748Smahlzeit uint32 BMidiStore::TicksToMilliseconds(uint32 ticks) const 612eac71506Sjerl1 { 61349fa1748Smahlzeit return ((uint64) ticks * 60000) / (beatsPerMinute * ticksPerBeat); 61449fa1748Smahlzeit } 61549fa1748Smahlzeit 61649fa1748Smahlzeit //------------------------------------------------------------------------------ 61749fa1748Smahlzeit 61849fa1748Smahlzeit uint32 BMidiStore::MillisecondsToTicks(uint32 ms) const 619eac71506Sjerl1 { 62049fa1748Smahlzeit return ((uint64) ms * beatsPerMinute * ticksPerBeat) / 60000; 621eac71506Sjerl1 } 62249fa1748Smahlzeit 62349fa1748Smahlzeit //------------------------------------------------------------------------------ 62449fa1748Smahlzeit 62549fa1748Smahlzeit void BMidiStore::ReadFourCC(char* fourcc) 626eac71506Sjerl1 { 62749fa1748Smahlzeit if (file->Read(fourcc, 4) != 4) 628eac71506Sjerl1 { 62949fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 630eac71506Sjerl1 } 63149fa1748Smahlzeit } 63249fa1748Smahlzeit 63349fa1748Smahlzeit //------------------------------------------------------------------------------ 63449fa1748Smahlzeit 63549fa1748Smahlzeit void BMidiStore::WriteFourCC(char a, char b, char c, char d) 636eac71506Sjerl1 { 63749fa1748Smahlzeit char fourcc[4] = { a, b, c, d }; 63849fa1748Smahlzeit if (file->Write(fourcc, 4) != 4) 639eac71506Sjerl1 { 64049fa1748Smahlzeit throw (status_t) B_ERROR; 641eac71506Sjerl1 } 64249fa1748Smahlzeit } 64349fa1748Smahlzeit 64449fa1748Smahlzeit //------------------------------------------------------------------------------ 64549fa1748Smahlzeit 64649fa1748Smahlzeit uint32 BMidiStore::Read32Bit() 647eac71506Sjerl1 { 64849fa1748Smahlzeit uint8 buf[4]; 64949fa1748Smahlzeit if (file->Read(buf, 4) != 4) 650eac71506Sjerl1 { 65149fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 652eac71506Sjerl1 } 65349fa1748Smahlzeit 65449fa1748Smahlzeit return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; 65549fa1748Smahlzeit } 65649fa1748Smahlzeit 65749fa1748Smahlzeit //------------------------------------------------------------------------------ 65849fa1748Smahlzeit 65949fa1748Smahlzeit void BMidiStore::Write32Bit(uint32 val) 660eac71506Sjerl1 { 66149fa1748Smahlzeit uint8 buf[4]; 66249fa1748Smahlzeit buf[0] = (val >> 24) & 0xFF; 66349fa1748Smahlzeit buf[1] = (val >> 16) & 0xFF; 66449fa1748Smahlzeit buf[2] = (val >> 8) & 0xFF; 66549fa1748Smahlzeit buf[3] = val & 0xFF; 66649fa1748Smahlzeit 66749fa1748Smahlzeit if (file->Write(buf, 4) != 4) 668eac71506Sjerl1 { 66949fa1748Smahlzeit throw (status_t) B_ERROR; 670eac71506Sjerl1 } 67149fa1748Smahlzeit } 67249fa1748Smahlzeit 67349fa1748Smahlzeit //------------------------------------------------------------------------------ 67449fa1748Smahlzeit 67549fa1748Smahlzeit uint16 BMidiStore::Read16Bit() 676eac71506Sjerl1 { 67749fa1748Smahlzeit uint8 buf[2]; 67849fa1748Smahlzeit if (file->Read(buf, 2) != 2) 679eac71506Sjerl1 { 68049fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 681eac71506Sjerl1 } 682eac71506Sjerl1 68349fa1748Smahlzeit return (buf[0] << 8) | buf[1]; 684eac71506Sjerl1 } 685eac71506Sjerl1 68649fa1748Smahlzeit //------------------------------------------------------------------------------ 687eac71506Sjerl1 68849fa1748Smahlzeit void BMidiStore::Write16Bit(uint16 val) 689eac71506Sjerl1 { 69049fa1748Smahlzeit uint8 buf[2]; 69149fa1748Smahlzeit buf[0] = (val >> 8) & 0xFF; 69249fa1748Smahlzeit buf[1] = val & 0xFF; 693eac71506Sjerl1 69449fa1748Smahlzeit if (file->Write(buf, 2) != 2) 695eac71506Sjerl1 { 69649fa1748Smahlzeit throw (status_t) B_ERROR; 697eac71506Sjerl1 } 698eac71506Sjerl1 } 699eac71506Sjerl1 70049fa1748Smahlzeit //------------------------------------------------------------------------------ 701eac71506Sjerl1 70249fa1748Smahlzeit uint8 BMidiStore::PeekByte() 703eac71506Sjerl1 { 70449fa1748Smahlzeit uint8 buf; 70549fa1748Smahlzeit if (file->Read(&buf, 1) != 1) 70649fa1748Smahlzeit { 70749fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 708eac71506Sjerl1 } 709eac71506Sjerl1 71049fa1748Smahlzeit if (file->Seek(-1, SEEK_CUR) < 0) 71149fa1748Smahlzeit { 71249fa1748Smahlzeit throw (status_t) B_ERROR; 713eac71506Sjerl1 } 714eac71506Sjerl1 71549fa1748Smahlzeit return buf; 71649fa1748Smahlzeit } 717eac71506Sjerl1 71849fa1748Smahlzeit //------------------------------------------------------------------------------ 71949fa1748Smahlzeit 72049fa1748Smahlzeit uint8 BMidiStore::NextByte() 72149fa1748Smahlzeit { 72249fa1748Smahlzeit uint8 buf; 72349fa1748Smahlzeit if (file->Read(&buf, 1) != 1) 72449fa1748Smahlzeit { 72549fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 72649fa1748Smahlzeit } 72749fa1748Smahlzeit 72849fa1748Smahlzeit --byteCount; 72949fa1748Smahlzeit return buf; 73049fa1748Smahlzeit } 73149fa1748Smahlzeit 73249fa1748Smahlzeit //------------------------------------------------------------------------------ 73349fa1748Smahlzeit 73449fa1748Smahlzeit void BMidiStore::WriteByte(uint8 val) 73549fa1748Smahlzeit { 73649fa1748Smahlzeit if (file->Write(&val, 1) != 1) 73749fa1748Smahlzeit { 73849fa1748Smahlzeit throw (status_t) B_ERROR; 73949fa1748Smahlzeit } 74049fa1748Smahlzeit 74149fa1748Smahlzeit ++byteCount; 74249fa1748Smahlzeit } 74349fa1748Smahlzeit 74449fa1748Smahlzeit //------------------------------------------------------------------------------ 74549fa1748Smahlzeit 74649fa1748Smahlzeit void BMidiStore::SkipBytes(uint32 length) 74749fa1748Smahlzeit { 74849fa1748Smahlzeit if (file->Seek(length, SEEK_CUR) < 0) 74949fa1748Smahlzeit { 75049fa1748Smahlzeit throw (status_t) B_BAD_MIDI_DATA; 75149fa1748Smahlzeit } 75249fa1748Smahlzeit 75349fa1748Smahlzeit byteCount -= length; 75449fa1748Smahlzeit } 75549fa1748Smahlzeit 75649fa1748Smahlzeit //------------------------------------------------------------------------------ 75749fa1748Smahlzeit 75849fa1748Smahlzeit uint32 BMidiStore::ReadVarLength() 75949fa1748Smahlzeit { 76049fa1748Smahlzeit uint32 val; 76149fa1748Smahlzeit uint8 byte; 76249fa1748Smahlzeit 76349fa1748Smahlzeit if ((val = NextByte()) & 0x80) 76449fa1748Smahlzeit { 76549fa1748Smahlzeit val &= 0x7F; 76649fa1748Smahlzeit do 76749fa1748Smahlzeit { 76849fa1748Smahlzeit val = (val << 7) + ((byte = NextByte()) & 0x7F); 76949fa1748Smahlzeit } 77049fa1748Smahlzeit while (byte & 0x80); 77149fa1748Smahlzeit } 77249fa1748Smahlzeit 77349fa1748Smahlzeit return val; 77449fa1748Smahlzeit } 77549fa1748Smahlzeit 77649fa1748Smahlzeit //------------------------------------------------------------------------------ 77749fa1748Smahlzeit 77849fa1748Smahlzeit void BMidiStore::WriteVarLength(uint32 val) 77949fa1748Smahlzeit { 78049fa1748Smahlzeit uint32 buffer = val & 0x7F; 78149fa1748Smahlzeit 78249fa1748Smahlzeit while ((val >>= 7)) 783eac71506Sjerl1 { 784eac71506Sjerl1 buffer <<= 8; 78549fa1748Smahlzeit buffer |= ((val & 0x7F) | 0x80); 786eac71506Sjerl1 } 78749fa1748Smahlzeit 788eac71506Sjerl1 while (true) 789eac71506Sjerl1 { 79049fa1748Smahlzeit WriteByte(buffer); 791eac71506Sjerl1 if (buffer & 0x80) 792eac71506Sjerl1 buffer >>= 8; 793eac71506Sjerl1 else 794eac71506Sjerl1 break; 79525767509Smahlzeit } 79625767509Smahlzeit } 79725767509Smahlzeit 79849fa1748Smahlzeit //------------------------------------------------------------------------------ 79925767509Smahlzeit 80049fa1748Smahlzeit void BMidiStore::ReadChunk() 801eac71506Sjerl1 { 80249fa1748Smahlzeit char fourcc[4]; 80349fa1748Smahlzeit ReadFourCC(fourcc); 804eac71506Sjerl1 80549fa1748Smahlzeit byteCount = Read32Bit(); 806eac71506Sjerl1 80749fa1748Smahlzeit if (strncmp(fourcc, "MTrk", 4) == 0) 808eac71506Sjerl1 { 80949fa1748Smahlzeit ReadTrack(); 810eac71506Sjerl1 } 81149fa1748Smahlzeit else 812eac71506Sjerl1 { 81349fa1748Smahlzeit TRACE(("Skipping '%c%c%c%c' chunk (%lu bytes)", 81449fa1748Smahlzeit fourcc[0], fourcc[1], fourcc[2], fourcc[3], byteCount)) 81549fa1748Smahlzeit 81649fa1748Smahlzeit SkipBytes(byteCount); 81749fa1748Smahlzeit } 818eac71506Sjerl1 } 819eac71506Sjerl1 82049fa1748Smahlzeit //------------------------------------------------------------------------------ 82149fa1748Smahlzeit 82249fa1748Smahlzeit void BMidiStore::ReadTrack() 82349fa1748Smahlzeit { 82449fa1748Smahlzeit uint8 status = 0; 82549fa1748Smahlzeit uint8 data1; 82649fa1748Smahlzeit uint8 data2; 82749fa1748Smahlzeit BMidiEvent* event; 82849fa1748Smahlzeit 82949fa1748Smahlzeit totalTicks = 0; 83049fa1748Smahlzeit 83149fa1748Smahlzeit while (byteCount > 0) 83249fa1748Smahlzeit { 83349fa1748Smahlzeit uint32 ticks = ReadVarLength(); 83449fa1748Smahlzeit totalTicks += ticks; 83549fa1748Smahlzeit 83649fa1748Smahlzeit if (PeekByte() & 0x80) 83749fa1748Smahlzeit { 83849fa1748Smahlzeit status = NextByte(); 83949fa1748Smahlzeit } 84049fa1748Smahlzeit 84149fa1748Smahlzeit switch (status & 0xF0) 84249fa1748Smahlzeit { 84349fa1748Smahlzeit case B_NOTE_OFF: 84449fa1748Smahlzeit case B_NOTE_ON: 84549fa1748Smahlzeit case B_KEY_PRESSURE: 84649fa1748Smahlzeit case B_CONTROL_CHANGE: 84749fa1748Smahlzeit case B_PITCH_BEND: 84849fa1748Smahlzeit data1 = NextByte(); 84949fa1748Smahlzeit data2 = NextByte(); 85049fa1748Smahlzeit event = new BMidiEvent; 85149fa1748Smahlzeit event->time = totalTicks; 85249fa1748Smahlzeit event->ticks = true; 85349fa1748Smahlzeit event->byte1 = status; 85449fa1748Smahlzeit event->byte2 = data1; 85549fa1748Smahlzeit event->byte3 = data2; 85649fa1748Smahlzeit AddEvent(event); 85749fa1748Smahlzeit break; 85849fa1748Smahlzeit 85949fa1748Smahlzeit case B_PROGRAM_CHANGE: 86049fa1748Smahlzeit case B_CHANNEL_PRESSURE: 86149fa1748Smahlzeit data1 = NextByte(); 86249fa1748Smahlzeit event = new BMidiEvent; 86349fa1748Smahlzeit event->time = totalTicks; 86449fa1748Smahlzeit event->ticks = true; 86549fa1748Smahlzeit event->byte1 = status; 86649fa1748Smahlzeit event->byte2 = data1; 86749fa1748Smahlzeit AddEvent(event); 868*f9b2179cSmahlzeit 869*f9b2179cSmahlzeit if ((status & 0xF0) == B_PROGRAM_CHANGE) 870*f9b2179cSmahlzeit { 871*f9b2179cSmahlzeit instruments[data1] = true; 872*f9b2179cSmahlzeit } 87349fa1748Smahlzeit break; 87449fa1748Smahlzeit 87549fa1748Smahlzeit case 0xF0: 87649fa1748Smahlzeit switch (status) 87749fa1748Smahlzeit { 87849fa1748Smahlzeit case B_SYS_EX_START: 87949fa1748Smahlzeit ReadSystemExclusive(); 88049fa1748Smahlzeit break; 88149fa1748Smahlzeit 88249fa1748Smahlzeit case B_TUNE_REQUEST: 88349fa1748Smahlzeit case B_SYS_EX_END: 88449fa1748Smahlzeit case B_TIMING_CLOCK: 88549fa1748Smahlzeit case B_START: 88649fa1748Smahlzeit case B_CONTINUE: 88749fa1748Smahlzeit case B_STOP: 88849fa1748Smahlzeit case B_ACTIVE_SENSING: 88949fa1748Smahlzeit event = new BMidiEvent; 89049fa1748Smahlzeit event->time = totalTicks; 89149fa1748Smahlzeit event->ticks = true; 89249fa1748Smahlzeit event->byte1 = status; 89349fa1748Smahlzeit AddEvent(event); 89449fa1748Smahlzeit break; 89549fa1748Smahlzeit 89649fa1748Smahlzeit case B_MIDI_TIME_CODE: 89749fa1748Smahlzeit case B_SONG_SELECT: 89849fa1748Smahlzeit case B_CABLE_MESSAGE: 89949fa1748Smahlzeit data1 = NextByte(); 90049fa1748Smahlzeit event = new BMidiEvent; 90149fa1748Smahlzeit event->time = totalTicks; 90249fa1748Smahlzeit event->ticks = true; 90349fa1748Smahlzeit event->byte1 = status; 90449fa1748Smahlzeit event->byte2 = data1; 90549fa1748Smahlzeit AddEvent(event); 90649fa1748Smahlzeit break; 90749fa1748Smahlzeit 90849fa1748Smahlzeit case B_SONG_POSITION: 90949fa1748Smahlzeit data1 = NextByte(); 91049fa1748Smahlzeit data2 = NextByte(); 91149fa1748Smahlzeit event = new BMidiEvent; 91249fa1748Smahlzeit event->time = totalTicks; 91349fa1748Smahlzeit event->ticks = true; 91449fa1748Smahlzeit event->byte1 = status; 91549fa1748Smahlzeit event->byte2 = data1; 91649fa1748Smahlzeit event->byte3 = data2; 91749fa1748Smahlzeit AddEvent(event); 91849fa1748Smahlzeit break; 91949fa1748Smahlzeit 92049fa1748Smahlzeit case B_SYSTEM_RESET: 92149fa1748Smahlzeit ReadMetaEvent(); 92249fa1748Smahlzeit break; 92349fa1748Smahlzeit } 92449fa1748Smahlzeit break; 92549fa1748Smahlzeit } 92649fa1748Smahlzeit 92749fa1748Smahlzeit event = NULL; 92849fa1748Smahlzeit } 92949fa1748Smahlzeit 93049fa1748Smahlzeit ++currTrack; 93149fa1748Smahlzeit } 93249fa1748Smahlzeit 93349fa1748Smahlzeit //------------------------------------------------------------------------------ 93449fa1748Smahlzeit 93549fa1748Smahlzeit void BMidiStore::ReadSystemExclusive() 93649fa1748Smahlzeit { 93749fa1748Smahlzeit // We do not import sysex's from MIDI files. 93849fa1748Smahlzeit 93949fa1748Smahlzeit SkipBytes(ReadVarLength()); 94049fa1748Smahlzeit } 94149fa1748Smahlzeit 94249fa1748Smahlzeit //------------------------------------------------------------------------------ 94349fa1748Smahlzeit 94449fa1748Smahlzeit void BMidiStore::ReadMetaEvent() 94549fa1748Smahlzeit { 94649fa1748Smahlzeit // We only import the Tempo Change meta event. 94749fa1748Smahlzeit 94849fa1748Smahlzeit uint8 type = NextByte(); 94949fa1748Smahlzeit uint32 length = ReadVarLength(); 95049fa1748Smahlzeit 95149fa1748Smahlzeit if ((type == 0x51) && (length == 3)) 95249fa1748Smahlzeit { 95349fa1748Smahlzeit uchar data[3]; 95449fa1748Smahlzeit data[0] = NextByte(); 95549fa1748Smahlzeit data[1] = NextByte(); 95649fa1748Smahlzeit data[2] = NextByte(); 95749fa1748Smahlzeit uint32 val = (data[0] << 16) | (data[1] << 8) | data[2]; 95849fa1748Smahlzeit 95949fa1748Smahlzeit BMidiEvent* event = new BMidiEvent; 96049fa1748Smahlzeit event->time = totalTicks; 96149fa1748Smahlzeit event->ticks = true; 96249fa1748Smahlzeit event->byte1 = 0xFF; 96349fa1748Smahlzeit event->byte2 = 0x51; 96449fa1748Smahlzeit event->byte3 = 0x03; 96549fa1748Smahlzeit event->tempo = 60000000 / val; 96649fa1748Smahlzeit AddEvent(event); 96749fa1748Smahlzeit } 96849fa1748Smahlzeit else 96949fa1748Smahlzeit { 97049fa1748Smahlzeit SkipBytes(length); 97149fa1748Smahlzeit } 97249fa1748Smahlzeit } 97349fa1748Smahlzeit 97449fa1748Smahlzeit //------------------------------------------------------------------------------ 97549fa1748Smahlzeit 97649fa1748Smahlzeit void BMidiStore::WriteTrack() 97749fa1748Smahlzeit { 97849fa1748Smahlzeit WriteFourCC('M', 'T', 'r', 'k'); 97949fa1748Smahlzeit off_t lengthPos = file->Position(); 98049fa1748Smahlzeit Write32Bit(0); 98149fa1748Smahlzeit 98249fa1748Smahlzeit byteCount = 0; 98349fa1748Smahlzeit uint32 oldTime; 98449fa1748Smahlzeit uint32 newTime; 98549fa1748Smahlzeit 9869138338cSmahlzeit for (uint32 t = 0; t < CountEvents(); ++t) 98749fa1748Smahlzeit { 98849fa1748Smahlzeit BMidiEvent* event = EventAt(t); 98949fa1748Smahlzeit 99049fa1748Smahlzeit if (event->ticks) 99149fa1748Smahlzeit { 99249fa1748Smahlzeit newTime = event->time; 99349fa1748Smahlzeit } 99449fa1748Smahlzeit else 99549fa1748Smahlzeit { 99649fa1748Smahlzeit newTime = MillisecondsToTicks(event->time); 99749fa1748Smahlzeit } 99849fa1748Smahlzeit 99949fa1748Smahlzeit if (t == 0) 100049fa1748Smahlzeit { 100149fa1748Smahlzeit WriteVarLength(0); 100249fa1748Smahlzeit } 100349fa1748Smahlzeit else 100449fa1748Smahlzeit { 100549fa1748Smahlzeit WriteVarLength(newTime - oldTime); 100649fa1748Smahlzeit } 100749fa1748Smahlzeit 100849fa1748Smahlzeit oldTime = newTime; 100949fa1748Smahlzeit 101049fa1748Smahlzeit switch (event->byte1 & 0xF0) 101149fa1748Smahlzeit { 101249fa1748Smahlzeit case B_NOTE_OFF: 101349fa1748Smahlzeit case B_NOTE_ON: 101449fa1748Smahlzeit case B_KEY_PRESSURE: 101549fa1748Smahlzeit case B_CONTROL_CHANGE: 101649fa1748Smahlzeit case B_PITCH_BEND: 101749fa1748Smahlzeit WriteByte(event->byte1); 101849fa1748Smahlzeit WriteByte(event->byte2); 101949fa1748Smahlzeit WriteByte(event->byte3); 102049fa1748Smahlzeit break; 102149fa1748Smahlzeit 102249fa1748Smahlzeit case B_PROGRAM_CHANGE: 102349fa1748Smahlzeit case B_CHANNEL_PRESSURE: 102449fa1748Smahlzeit WriteByte(event->byte1); 102549fa1748Smahlzeit WriteByte(event->byte2); 102649fa1748Smahlzeit break; 102749fa1748Smahlzeit 102849fa1748Smahlzeit case 0xF0: 102949fa1748Smahlzeit switch (event->byte1) 103049fa1748Smahlzeit { 103149fa1748Smahlzeit case B_SYS_EX_START: 103249fa1748Smahlzeit // We do not export sysex's. 103349fa1748Smahlzeit break; 103449fa1748Smahlzeit 103549fa1748Smahlzeit case B_TUNE_REQUEST: 103649fa1748Smahlzeit case B_SYS_EX_END: 103749fa1748Smahlzeit case B_TIMING_CLOCK: 103849fa1748Smahlzeit case B_START: 103949fa1748Smahlzeit case B_CONTINUE: 104049fa1748Smahlzeit case B_STOP: 104149fa1748Smahlzeit case B_ACTIVE_SENSING: 104249fa1748Smahlzeit WriteByte(event->byte1); 104349fa1748Smahlzeit break; 104449fa1748Smahlzeit 104549fa1748Smahlzeit case B_MIDI_TIME_CODE: 104649fa1748Smahlzeit case B_SONG_SELECT: 104749fa1748Smahlzeit case B_CABLE_MESSAGE: 104849fa1748Smahlzeit WriteByte(event->byte1); 104949fa1748Smahlzeit WriteByte(event->byte2); 105049fa1748Smahlzeit break; 105149fa1748Smahlzeit 105249fa1748Smahlzeit case B_SONG_POSITION: 105349fa1748Smahlzeit WriteByte(event->byte1); 105449fa1748Smahlzeit WriteByte(event->byte2); 105549fa1748Smahlzeit WriteByte(event->byte3); 105649fa1748Smahlzeit break; 105749fa1748Smahlzeit 105849fa1748Smahlzeit case B_SYSTEM_RESET: 105949fa1748Smahlzeit WriteMetaEvent(event); 106049fa1748Smahlzeit break; 106149fa1748Smahlzeit } 106249fa1748Smahlzeit break; 106349fa1748Smahlzeit 106449fa1748Smahlzeit } 106549fa1748Smahlzeit } 106649fa1748Smahlzeit 106749fa1748Smahlzeit WriteVarLength(0); 106849fa1748Smahlzeit WriteByte(0xFF); // the end-of-track 106949fa1748Smahlzeit WriteByte(0x2F); // marker is required 107049fa1748Smahlzeit WriteByte(0x00); 107149fa1748Smahlzeit 107249fa1748Smahlzeit file->Seek(lengthPos, SEEK_SET); 107349fa1748Smahlzeit Write32Bit(byteCount); 107449fa1748Smahlzeit file->Seek(0, SEEK_END); 107549fa1748Smahlzeit } 107649fa1748Smahlzeit 107749fa1748Smahlzeit //------------------------------------------------------------------------------ 107849fa1748Smahlzeit 107949fa1748Smahlzeit void BMidiStore::WriteMetaEvent(BMidiEvent* event) 108049fa1748Smahlzeit { 108149fa1748Smahlzeit // We only export the Tempo Change meta event. 108249fa1748Smahlzeit 108349fa1748Smahlzeit if ((event->byte2 == 0x51) && (event->byte3 == 0x03)) 108449fa1748Smahlzeit { 108549fa1748Smahlzeit uint32 val = 60000000 / event->tempo; 108649fa1748Smahlzeit 108749fa1748Smahlzeit WriteByte(0xFF); 108849fa1748Smahlzeit WriteByte(0x51); 108949fa1748Smahlzeit WriteByte(0x03); 109049fa1748Smahlzeit WriteByte(val >> 16); 109149fa1748Smahlzeit WriteByte(val >> 8); 109249fa1748Smahlzeit WriteByte(val); 109349fa1748Smahlzeit } 109449fa1748Smahlzeit } 109549fa1748Smahlzeit 1096b178e190Smahlzeit 109749fa1748Smahlzeit //------------------------------------------------------------------------------ 1098