1 /*
2 * BW_Midi_Sequencer - MIDI Sequencer for C++
3 *
4 * Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "midi_sequencer.hpp"
26 #include <stdio.h>
27 #include <memory>
28 #include <cstring>
29 #include <cerrno>
30 #include <iterator> // std::back_inserter
31 #include <algorithm> // std::copy
32 #include <set>
33 #include <assert.h>
34
35 #if defined(_WIN32) && !defined(__WATCOMC__)
36 # ifdef _MSC_VER
37 # ifdef _WIN64
38 typedef __int64 ssize_t;
39 # else
40 typedef __int32 ssize_t;
41 # endif
42 # else
43 # ifdef _WIN64
44 typedef int64_t ssize_t;
45 # else
46 typedef int32_t ssize_t;
47 # endif
48 # endif
49 #endif
50
51 #ifndef BWMIDI_DISABLE_MUS_SUPPORT
52 #include "cvt_mus2mid.hpp"
53 #endif//MUS
54
55 #ifndef BWMIDI_DISABLE_XMI_SUPPORT
56 #include "cvt_xmi2mid.hpp"
57 #endif//XMI
58
59 /**
60 * @brief Utility function to read Big-Endian integer from raw binary data
61 * @param buffer Pointer to raw binary buffer
62 * @param nbytes Count of bytes to parse integer
63 * @return Extracted unsigned integer
64 */
readBEint(const void * buffer,size_t nbytes)65 static inline uint64_t readBEint(const void *buffer, size_t nbytes)
66 {
67 uint64_t result = 0;
68 const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer);
69
70 for(size_t n = 0; n < nbytes; ++n)
71 result = (result << 8) + data[n];
72
73 return result;
74 }
75
76 /**
77 * @brief Utility function to read Little-Endian integer from raw binary data
78 * @param buffer Pointer to raw binary buffer
79 * @param nbytes Count of bytes to parse integer
80 * @return Extracted unsigned integer
81 */
readLEint(const void * buffer,size_t nbytes)82 static inline uint64_t readLEint(const void *buffer, size_t nbytes)
83 {
84 uint64_t result = 0;
85 const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer);
86
87 for(size_t n = 0; n < nbytes; ++n)
88 result = result + static_cast<uint64_t>(data[n] << (n * 8));
89
90 return result;
91 }
92
93 /**
94 * @brief Secure Standard MIDI Variable-Length numeric value parser with anti-out-of-range protection
95 * @param [_inout] ptr Pointer to memory block that contains begin of variable-length value, will be iterated forward
96 * @param [_in end Pointer to end of memory block where variable-length value is stored (after end of track)
97 * @param [_out] ok Reference to boolean which takes result of variable-length value parsing
98 * @return Unsigned integer that conains parsed variable-length value
99 */
readVarLenEx(const uint8_t ** ptr,const uint8_t * end,bool & ok)100 static inline uint64_t readVarLenEx(const uint8_t **ptr, const uint8_t *end, bool &ok)
101 {
102 uint64_t result = 0;
103 ok = false;
104
105 for(;;)
106 {
107 if(*ptr >= end)
108 return 2;
109 unsigned char byte = *((*ptr)++);
110 result = (result << 7) + (byte & 0x7F);
111 if(!(byte & 0x80))
112 break;
113 }
114
115 ok = true;
116 return result;
117 }
118
MidiEvent()119 BW_MidiSequencer::MidiEvent::MidiEvent() :
120 type(T_UNKNOWN),
121 subtype(T_UNKNOWN),
122 channel(0),
123 isValid(1),
124 absPosition(0)
125 {}
126
MidiTrackRow()127 BW_MidiSequencer::MidiTrackRow::MidiTrackRow() :
128 time(0.0),
129 delay(0),
130 absPos(0),
131 timeDelay(0.0)
132 {}
133
clear()134 void BW_MidiSequencer::MidiTrackRow::clear()
135 {
136 time = 0.0;
137 delay = 0;
138 absPos = 0;
139 timeDelay = 0.0;
140 events.clear();
141 }
142
sortEvents(bool * noteStates)143 void BW_MidiSequencer::MidiTrackRow::sortEvents(bool *noteStates)
144 {
145 typedef std::vector<MidiEvent> EvtArr;
146 EvtArr sysEx;
147 EvtArr metas;
148 EvtArr noteOffs;
149 EvtArr controllers;
150 EvtArr anyOther;
151
152 for(size_t i = 0; i < events.size(); i++)
153 {
154 if(events[i].type == MidiEvent::T_NOTEOFF)
155 {
156 if(noteOffs.capacity() == 0)
157 noteOffs.reserve(events.size());
158 noteOffs.push_back(events[i]);
159 }
160 else if(events[i].type == MidiEvent::T_SYSEX ||
161 events[i].type == MidiEvent::T_SYSEX2)
162 {
163 if(sysEx.capacity() == 0)
164 sysEx.reserve(events.size());
165 sysEx.push_back(events[i]);
166 }
167 else if((events[i].type == MidiEvent::T_CTRLCHANGE)
168 || (events[i].type == MidiEvent::T_PATCHCHANGE)
169 || (events[i].type == MidiEvent::T_WHEEL)
170 || (events[i].type == MidiEvent::T_CHANAFTTOUCH))
171 {
172 if(controllers.capacity() == 0)
173 controllers.reserve(events.size());
174 controllers.push_back(events[i]);
175 }
176 else if((events[i].type == MidiEvent::T_SPECIAL) && (
177 (events[i].subtype == MidiEvent::ST_MARKER) ||
178 (events[i].subtype == MidiEvent::ST_DEVICESWITCH) ||
179 (events[i].subtype == MidiEvent::ST_LOOPSTART) ||
180 (events[i].subtype == MidiEvent::ST_LOOPEND) ||
181 (events[i].subtype == MidiEvent::ST_LOOPSTACK_BEGIN) ||
182 (events[i].subtype == MidiEvent::ST_LOOPSTACK_END) ||
183 (events[i].subtype == MidiEvent::ST_LOOPSTACK_BREAK)
184 ))
185 {
186 if(metas.capacity() == 0)
187 metas.reserve(events.size());
188 metas.push_back(events[i]);
189 }
190 else
191 {
192 if(anyOther.capacity() == 0)
193 anyOther.reserve(events.size());
194 anyOther.push_back(events[i]);
195 }
196 }
197
198 /*
199 * If Note-Off and it's Note-On is on the same row - move this damned note off down!
200 */
201 if(noteStates)
202 {
203 std::set<size_t> markAsOn;
204 for(size_t i = 0; i < anyOther.size(); i++)
205 {
206 const MidiEvent e = anyOther[i];
207 if(e.type == MidiEvent::T_NOTEON)
208 {
209 const size_t note_i = (e.channel * 255) + (e.data[0] & 0x7F);
210 //Check, was previously note is on or off
211 bool wasOn = noteStates[note_i];
212 markAsOn.insert(note_i);
213 // Detect zero-length notes are following previously pressed note
214 int noteOffsOnSameNote = 0;
215 for(EvtArr::iterator j = noteOffs.begin(); j != noteOffs.end();)
216 {
217 //If note was off, and note-off on same row with note-on - move it down!
218 if(
219 ((*j).channel == e.channel) &&
220 ((*j).data[0] == e.data[0])
221 )
222 {
223 //If note is already off OR more than one note-off on same row and same note
224 if(!wasOn || (noteOffsOnSameNote != 0))
225 {
226 anyOther.push_back(*j);
227 j = noteOffs.erase(j);
228 markAsOn.erase(note_i);
229 continue;
230 }
231 else
232 {
233 //When same row has many note-offs on same row
234 //that means a zero-length note follows previous note
235 //it must be shuted down
236 noteOffsOnSameNote++;
237 }
238 }
239 j++;
240 }
241 }
242 }
243
244 //Mark other notes as released
245 for(EvtArr::iterator j = noteOffs.begin(); j != noteOffs.end(); j++)
246 {
247 size_t note_i = (j->channel * 255) + (j->data[0] & 0x7F);
248 noteStates[note_i] = false;
249 }
250
251 for(std::set<size_t>::iterator j = markAsOn.begin(); j != markAsOn.end(); j++)
252 noteStates[*j] = true;
253 }
254 /***********************************************************************************/
255
256 events.clear();
257 if(!sysEx.empty())
258 events.insert(events.end(), sysEx.begin(), sysEx.end());
259 if(!noteOffs.empty())
260 events.insert(events.end(), noteOffs.begin(), noteOffs.end());
261 if(!metas.empty())
262 events.insert(events.end(), metas.begin(), metas.end());
263 if(!controllers.empty())
264 events.insert(events.end(), controllers.begin(), controllers.end());
265 if(!anyOther.empty())
266 events.insert(events.end(), anyOther.begin(), anyOther.end());
267 }
268
BW_MidiSequencer()269 BW_MidiSequencer::BW_MidiSequencer() :
270 m_interface(NULL),
271 m_format(Format_MIDI),
272 m_smfFormat(0),
273 m_loopEnabled(false),
274 m_fullSongTimeLength(0.0),
275 m_postSongWaitDelay(1.0),
276 m_loopStartTime(-1.0),
277 m_loopEndTime(-1.0),
278 m_tempoMultiplier(1.0),
279 m_atEnd(false),
280 m_trackSolo(~(size_t)0)
281 {
282 m_loop.reset();
283 m_loop.invalidLoop = false;
284 }
285
~BW_MidiSequencer()286 BW_MidiSequencer::~BW_MidiSequencer()
287 {}
288
setInterface(const BW_MidiRtInterface * intrf)289 void BW_MidiSequencer::setInterface(const BW_MidiRtInterface *intrf)
290 {
291 // Interface must NOT be NULL
292 assert(intrf);
293
294 //Note ON hook is REQUIRED
295 assert(intrf->rt_noteOn);
296 //Note OFF hook is REQUIRED
297 assert(intrf->rt_noteOff);
298 //Note Aftertouch hook is REQUIRED
299 assert(intrf->rt_noteAfterTouch);
300 //Channel Aftertouch hook is REQUIRED
301 assert(intrf->rt_channelAfterTouch);
302 //Controller change hook is REQUIRED
303 assert(intrf->rt_controllerChange);
304 //Patch change hook is REQUIRED
305 assert(intrf->rt_patchChange);
306 //Pitch bend hook is REQUIRED
307 assert(intrf->rt_pitchBend);
308 //System Exclusive hook is REQUIRED
309 assert(intrf->rt_systemExclusive);
310
311 m_interface = intrf;
312 }
313
getFormat()314 BW_MidiSequencer::FileFormat BW_MidiSequencer::getFormat()
315 {
316 return m_format;
317 }
318
getTrackCount() const319 size_t BW_MidiSequencer::getTrackCount() const
320 {
321 return m_trackData.size();
322 }
323
setTrackEnabled(size_t track,bool enable)324 bool BW_MidiSequencer::setTrackEnabled(size_t track, bool enable)
325 {
326 size_t trackCount = m_trackData.size();
327 if(track >= trackCount)
328 return false;
329 m_trackDisable[track] = !enable;
330 return true;
331 }
332
setSoloTrack(size_t track)333 void BW_MidiSequencer::setSoloTrack(size_t track)
334 {
335 m_trackSolo = track;
336 }
337
getRawCmfInstruments()338 const std::vector<BW_MidiSequencer::CmfInstrument> BW_MidiSequencer::getRawCmfInstruments()
339 {
340 return m_cmfInstruments;
341 }
342
getErrorString()343 const std::string &BW_MidiSequencer::getErrorString()
344 {
345 return m_errorString;
346 }
347
getLoopEnabled()348 bool BW_MidiSequencer::getLoopEnabled()
349 {
350 return m_loopEnabled;
351 }
352
setLoopEnabled(bool enabled)353 void BW_MidiSequencer::setLoopEnabled(bool enabled)
354 {
355 m_loopEnabled = enabled;
356 }
357
getMusicTitle()358 const std::string &BW_MidiSequencer::getMusicTitle()
359 {
360 return m_musTitle;
361 }
362
getMusicCopyright()363 const std::string &BW_MidiSequencer::getMusicCopyright()
364 {
365 return m_musCopyright;
366 }
367
getTrackTitles()368 const std::vector<std::string> &BW_MidiSequencer::getTrackTitles()
369 {
370 return m_musTrackTitles;
371 }
372
getMarkers()373 const std::vector<BW_MidiSequencer::MIDI_MarkerEntry> &BW_MidiSequencer::getMarkers()
374 {
375 return m_musMarkers;
376 }
377
positionAtEnd()378 bool BW_MidiSequencer::positionAtEnd()
379 {
380 return m_atEnd;
381 }
382
getTempoMultiplier()383 double BW_MidiSequencer::getTempoMultiplier()
384 {
385 return m_tempoMultiplier;
386 }
387
buildTrackData(const std::vector<std::vector<uint8_t>> & trackData)388 bool BW_MidiSequencer::buildTrackData(const std::vector<std::vector<uint8_t> > &trackData)
389 {
390 m_fullSongTimeLength = 0.0;
391 m_loopStartTime = -1.0;
392 m_loopEndTime = -1.0;
393 m_trackDisable.clear();
394 m_trackSolo = ~(size_t)0;
395 m_musTitle.clear();
396 m_musCopyright.clear();
397 m_musTrackTitles.clear();
398 m_musMarkers.clear();
399 m_trackData.clear();
400 const size_t trackCount = trackData.size();
401 m_trackData.resize(trackCount, MidiTrackQueue());
402 m_trackDisable.resize(trackCount);
403
404 m_loop.reset();
405 m_loop.invalidLoop = false;
406
407 bool gotGlobalLoopStart = false,
408 gotGlobalLoopEnd = false,
409 gotStackLoopStart = false,
410 gotLoopEventInThisRow = false;
411 //! Tick position of loop start tag
412 uint64_t loopStartTicks = 0;
413 //! Tick position of loop end tag
414 uint64_t loopEndTicks = 0;
415 //! Full length of song in ticks
416 uint64_t ticksSongLength = 0;
417 //! Cache for error message strign
418 char error[150];
419
420 m_currentPosition.track.clear();
421 m_currentPosition.track.resize(trackCount);
422
423 //! Caches note on/off states.
424 bool noteStates[16 * 255];
425 /* This is required to carefully detect zero-length notes *
426 * and avoid a move of "note-off" event over "note-on" while sort. *
427 * Otherwise, after sort those notes will play infinite sound */
428
429 //Tempo change events
430 std::vector<MidiEvent> tempos;
431
432 /*
433 * TODO: Make this be safer for memory in case of broken input data
434 * which may cause going away of available track data (and then give a crash!)
435 *
436 * POST: Check this more carefully for possible vulnuabilities are can crash this
437 */
438 for(size_t tk = 0; tk < trackCount; ++tk)
439 {
440 uint64_t abs_position = 0;
441 int status = 0;
442 MidiEvent event;
443 bool ok = false;
444 const uint8_t *end = trackData[tk].data() + trackData[tk].size();
445 const uint8_t *trackPtr = trackData[tk].data();
446 std::memset(noteStates, 0, sizeof(noteStates));
447
448 //Time delay that follows the first event in the track
449 {
450 MidiTrackRow evtPos;
451 if(m_format == Format_RSXX)
452 ok = true;
453 else
454 evtPos.delay = readVarLenEx(&trackPtr, end, ok);
455 if(!ok)
456 {
457 int len = snprintf(error, 150, "buildTrackData: Can't read variable-length value at begin of track %d.\n", (int)tk);
458 if((len > 0) && (len < 150))
459 m_parsingErrorsString += std::string(error, (size_t)len);
460 return false;
461 }
462
463 //HACK: Begin every track with "Reset all controllers" event to avoid controllers state break came from end of song
464 for(uint8_t chan = 0; chan < 16; chan++)
465 {
466 MidiEvent event;
467 event.type = MidiEvent::T_CTRLCHANGE;
468 event.channel = chan;
469 event.data.push_back(121);
470 event.data.push_back(0);
471 evtPos.events.push_back(event);
472 }
473
474 evtPos.absPos = abs_position;
475 abs_position += evtPos.delay;
476 m_trackData[tk].push_back(evtPos);
477 }
478
479 MidiTrackRow evtPos;
480 do
481 {
482 event = parseEvent(&trackPtr, end, status);
483 if(!event.isValid)
484 {
485 int len = snprintf(error, 150, "buildTrackData: Fail to parse event in the track %d.\n", (int)tk);
486 if((len > 0) && (len < 150))
487 m_parsingErrorsString += std::string(error, (size_t)len);
488 return false;
489 }
490
491 evtPos.events.push_back(event);
492 if(event.type == MidiEvent::T_SPECIAL)
493 {
494 if(event.subtype == MidiEvent::ST_TEMPOCHANGE)
495 {
496 event.absPosition = abs_position;
497 tempos.push_back(event);
498 }
499 else if(!m_loop.invalidLoop && (event.subtype == MidiEvent::ST_LOOPSTART))
500 {
501 /*
502 * loopStart is invalid when:
503 * - starts together with loopEnd
504 * - appears more than one time in same MIDI file
505 */
506 if(gotGlobalLoopStart || gotLoopEventInThisRow)
507 m_loop.invalidLoop = true;
508 else
509 {
510 gotGlobalLoopStart = true;
511 loopStartTicks = abs_position;
512 }
513 //In this row we got loop event, register this!
514 gotLoopEventInThisRow = true;
515 }
516 else if(!m_loop.invalidLoop && (event.subtype == MidiEvent::ST_LOOPEND))
517 {
518 /*
519 * loopEnd is invalid when:
520 * - starts before loopStart
521 * - starts together with loopStart
522 * - appars more than one time in same MIDI file
523 */
524 if(gotGlobalLoopEnd || gotLoopEventInThisRow)
525 {
526 m_loop.invalidLoop = true;
527 if(m_interface->onDebugMessage)
528 {
529 m_interface->onDebugMessage(
530 m_interface->onDebugMessage_userData,
531 "== Invalid loop detected! %s %s ==",
532 (gotGlobalLoopEnd ? "[Caught more than 1 loopEnd!]" : ""),
533 (gotLoopEventInThisRow ? "[loopEnd in same row as loopStart!]" : "")
534 );
535 }
536 }
537 else
538 {
539 gotGlobalLoopEnd = true;
540 loopEndTicks = abs_position;
541 }
542 // In this row we got loop event, register this!
543 gotLoopEventInThisRow = true;
544 }
545 else if(!m_loop.invalidLoop && (event.subtype == MidiEvent::ST_LOOPSTACK_BEGIN))
546 {
547 if(!gotStackLoopStart)
548 {
549 if(!gotGlobalLoopStart)
550 loopStartTicks = abs_position;
551 gotStackLoopStart = true;
552 }
553
554 m_loop.stackUp();
555 if(m_loop.stackLevel >= static_cast<int>(m_loop.stack.size()))
556 {
557 LoopStackEntry e;
558 e.loops = event.data[0];
559 e.infinity = (event.data[0] == 0);
560 e.start = abs_position;
561 e.end = abs_position;
562 m_loop.stack.push_back(e);
563 }
564 }
565 else if(!m_loop.invalidLoop &&
566 ((event.subtype == MidiEvent::ST_LOOPSTACK_END) ||
567 (event.subtype == MidiEvent::ST_LOOPSTACK_BREAK))
568 )
569 {
570 if(m_loop.stackLevel <= -1)
571 {
572 m_loop.invalidLoop = true; // Caught loop end without of loop start!
573 if(m_interface->onDebugMessage)
574 {
575 m_interface->onDebugMessage(
576 m_interface->onDebugMessage_userData,
577 "== Invalid loop detected! [Caught loop end without of loop start] =="
578 );
579 }
580 }
581 else
582 {
583 if(loopEndTicks < abs_position)
584 loopEndTicks = abs_position;
585 m_loop.getCurStack().end = abs_position;
586 m_loop.stackDown();
587 }
588 }
589 }
590
591 if(event.subtype != MidiEvent::ST_ENDTRACK)//Don't try to read delta after EndOfTrack event!
592 {
593 evtPos.delay = readVarLenEx(&trackPtr, end, ok);
594 if(!ok)
595 {
596 /* End of track has been reached! However, there is no EOT event presented */
597 event.type = MidiEvent::T_SPECIAL;
598 event.subtype = MidiEvent::ST_ENDTRACK;
599 }
600 }
601
602 if((evtPos.delay > 0) || (event.subtype == MidiEvent::ST_ENDTRACK))
603 {
604 evtPos.absPos = abs_position;
605 abs_position += evtPos.delay;
606 evtPos.sortEvents(noteStates);
607 m_trackData[tk].push_back(evtPos);
608 evtPos.clear();
609 gotLoopEventInThisRow = false;
610 }
611 }
612 while((trackPtr <= end) && (event.subtype != MidiEvent::ST_ENDTRACK));
613
614 if(ticksSongLength < abs_position)
615 ticksSongLength = abs_position;
616 //Set the chain of events begin
617 if(m_trackData[tk].size() > 0)
618 m_currentPosition.track[tk].pos = m_trackData[tk].begin();
619 }
620
621 if(gotGlobalLoopStart && !gotGlobalLoopEnd)
622 {
623 gotGlobalLoopEnd = true;
624 loopEndTicks = ticksSongLength;
625 }
626
627 //loopStart must be located before loopEnd!
628 if(loopStartTicks >= loopEndTicks)
629 {
630 m_loop.invalidLoop = true;
631 if(m_interface->onDebugMessage && (gotGlobalLoopStart || gotGlobalLoopEnd))
632 {
633 m_interface->onDebugMessage(
634 m_interface->onDebugMessage_userData,
635 "== Invalid loop detected! [loopEnd is going before loopStart] =="
636 );
637 }
638 }
639
640 /********************************************************************************/
641 //Calculate time basing on collected tempo events
642 /********************************************************************************/
643 for(size_t tk = 0; tk < trackCount; ++tk)
644 {
645 fraction<uint64_t> currentTempo = m_tempo;
646 double time = 0.0;
647 uint64_t abs_position = 0;
648 size_t tempo_change_index = 0;
649 MidiTrackQueue &track = m_trackData[tk];
650 if(track.empty())
651 continue;//Empty track is useless!
652
653 #ifdef DEBUG_TIME_CALCULATION
654 std::fprintf(stdout, "\n============Track %" PRIuPTR "=============\n", tk);
655 std::fflush(stdout);
656 #endif
657
658 MidiTrackRow *posPrev = &(*(track.begin()));//First element
659 for(MidiTrackQueue::iterator it = track.begin(); it != track.end(); it++)
660 {
661 #ifdef DEBUG_TIME_CALCULATION
662 bool tempoChanged = false;
663 #endif
664 MidiTrackRow &pos = *it;
665 if((posPrev != &pos) && //Skip first event
666 (!tempos.empty()) && //Only when in-track tempo events are available
667 (tempo_change_index < tempos.size())
668 )
669 {
670 // If tempo event is going between of current and previous event
671 if(tempos[tempo_change_index].absPosition <= pos.absPos)
672 {
673 //Stop points: begin point and tempo change points are before end point
674 std::vector<TempoChangePoint> points;
675 fraction<uint64_t> t;
676 TempoChangePoint firstPoint = {posPrev->absPos, currentTempo};
677 points.push_back(firstPoint);
678
679 //Collect tempo change points between previous and current events
680 do
681 {
682 TempoChangePoint tempoMarker;
683 MidiEvent &tempoPoint = tempos[tempo_change_index];
684 tempoMarker.absPos = tempoPoint.absPosition;
685 tempoMarker.tempo = m_invDeltaTicks * fraction<uint64_t>(readBEint(tempoPoint.data.data(), tempoPoint.data.size()));
686 points.push_back(tempoMarker);
687 tempo_change_index++;
688 }
689 while((tempo_change_index < tempos.size()) &&
690 (tempos[tempo_change_index].absPosition <= pos.absPos));
691
692 // Re-calculate time delay of previous event
693 time -= posPrev->timeDelay;
694 posPrev->timeDelay = 0.0;
695
696 for(size_t i = 0, j = 1; j < points.size(); i++, j++)
697 {
698 /* If one or more tempo events are appears between of two events,
699 * calculate delays between each tempo point, begin and end */
700 uint64_t midDelay = 0;
701 //Delay between points
702 midDelay = points[j].absPos - points[i].absPos;
703 //Time delay between points
704 t = midDelay * currentTempo;
705 posPrev->timeDelay += t.value();
706
707 //Apply next tempo
708 currentTempo = points[j].tempo;
709 #ifdef DEBUG_TIME_CALCULATION
710 tempoChanged = true;
711 #endif
712 }
713 //Then calculate time between last tempo change point and end point
714 TempoChangePoint tailTempo = points.back();
715 uint64_t postDelay = pos.absPos - tailTempo.absPos;
716 t = postDelay * currentTempo;
717 posPrev->timeDelay += t.value();
718
719 //Store Common time delay
720 posPrev->time = time;
721 time += posPrev->timeDelay;
722 }
723 }
724
725 fraction<uint64_t> t = pos.delay * currentTempo;
726 pos.timeDelay = t.value();
727 pos.time = time;
728 time += pos.timeDelay;
729
730 //Capture markers after time value calculation
731 for(size_t i = 0; i < pos.events.size(); i++)
732 {
733 MidiEvent &e = pos.events[i];
734 if((e.type == MidiEvent::T_SPECIAL) && (e.subtype == MidiEvent::ST_MARKER))
735 {
736 MIDI_MarkerEntry marker;
737 marker.label = std::string((char *)e.data.data(), e.data.size());
738 marker.pos_ticks = pos.absPos;
739 marker.pos_time = pos.time;
740 m_musMarkers.push_back(marker);
741 }
742 }
743
744 //Capture loop points time positions
745 if(!m_loop.invalidLoop)
746 {
747 // Set loop points times
748 if(loopStartTicks == pos.absPos)
749 m_loopStartTime = pos.time;
750 else if(loopEndTicks == pos.absPos)
751 m_loopEndTime = pos.time;
752 }
753
754 #ifdef DEBUG_TIME_CALCULATION
755 std::fprintf(stdout, "= %10" PRId64 " = %10f%s\n", pos.absPos, pos.time, tempoChanged ? " <----TEMPO CHANGED" : "");
756 std::fflush(stdout);
757 #endif
758
759 abs_position += pos.delay;
760 posPrev = &pos;
761 }
762
763 if(time > m_fullSongTimeLength)
764 m_fullSongTimeLength = time;
765 }
766
767 m_fullSongTimeLength += m_postSongWaitDelay;
768 //Set begin of the music
769 m_trackBeginPosition = m_currentPosition;
770 //Initial loop position will begin at begin of track until passing of the loop point
771 m_loopBeginPosition = m_currentPosition;
772
773 /********************************************************************************/
774 //Resolve "hell of all times" of too short drum notes:
775 //move too short percussion note-offs far far away as possible
776 /********************************************************************************/
777 #if 1 //Use this to record WAVEs for comparison before/after implementing of this
778 if(m_format == Format_MIDI)//Percussion fix is needed for MIDI only, not for IMF/RSXX or CMF
779 {
780 //! Minimal real time in seconds
781 #define DRUM_NOTE_MIN_TIME 0.03
782 //! Minimal ticks count
783 #define DRUM_NOTE_MIN_TICKS 15
784 struct NoteState
785 {
786 double delay;
787 uint64_t delayTicks;
788 bool isOn;
789 char ___pad[7];
790 } drNotes[255];
791 size_t banks[16];
792
793 for(size_t tk = 0; tk < trackCount; ++tk)
794 {
795 std::memset(drNotes, 0, sizeof(drNotes));
796 std::memset(banks, 0, sizeof(banks));
797 MidiTrackQueue &track = m_trackData[tk];
798 if(track.empty())
799 continue;//Empty track is useless!
800
801 for(MidiTrackQueue::iterator it = track.begin(); it != track.end(); it++)
802 {
803 MidiTrackRow &pos = *it;
804
805 for(ssize_t e = 0; e < (ssize_t)pos.events.size(); e++)
806 {
807 MidiEvent *et = &pos.events[(size_t)e];
808
809 /* Set MSB/LSB bank */
810 if(et->type == MidiEvent::T_CTRLCHANGE)
811 {
812 uint8_t ctrlno = et->data[0];
813 uint8_t value = et->data[1];
814 switch(ctrlno)
815 {
816 case 0: // Set bank msb (GM bank)
817 banks[et->channel] = (value << 8) | (banks[et->channel] & 0x00FF);
818 break;
819 case 32: // Set bank lsb (XG bank)
820 banks[et->channel] = (banks[et->channel] & 0xFF00) | (value & 0x00FF);
821 break;
822 }
823 continue;
824 }
825
826 bool percussion = (et->channel == 9) ||
827 banks[et->channel] == 0x7E00 || //XG SFX1/SFX2 channel (16128 signed decimal)
828 banks[et->channel] == 0x7F00; //XG Percussion channel (16256 signed decimal)
829 if(!percussion)
830 continue;
831
832 if(et->type == MidiEvent::T_NOTEON)
833 {
834 uint8_t note = et->data[0] & 0x7F;
835 NoteState &ns = drNotes[note];
836 ns.isOn = true;
837 ns.delay = 0.0;
838 ns.delayTicks = 0;
839 }
840 else if(et->type == MidiEvent::T_NOTEOFF)
841 {
842 uint8_t note = et->data[0] & 0x7F;
843 NoteState &ns = drNotes[note];
844 if(ns.isOn)
845 {
846 ns.isOn = false;
847 if(ns.delayTicks < DRUM_NOTE_MIN_TICKS || ns.delay < DRUM_NOTE_MIN_TIME)//If note is too short
848 {
849 //Move it into next event position if that possible
850 for(MidiTrackQueue::iterator itNext = it;
851 itNext != track.end();
852 itNext++)
853 {
854 MidiTrackRow &posN = *itNext;
855 if(ns.delayTicks > DRUM_NOTE_MIN_TICKS && ns.delay > DRUM_NOTE_MIN_TIME)
856 {
857 //Put note-off into begin of next event list
858 posN.events.insert(posN.events.begin(), pos.events[(size_t)e]);
859 //Renive this event from a current row
860 pos.events.erase(pos.events.begin() + (int)e);
861 e--;
862 break;
863 }
864 ns.delay += posN.timeDelay;
865 ns.delayTicks += posN.delay;
866 }
867 }
868 ns.delay = 0.0;
869 ns.delayTicks = 0;
870 }
871 }
872 }
873
874 //Append time delays to sustaining notes
875 for(size_t no = 0; no < 128; no++)
876 {
877 NoteState &ns = drNotes[no];
878 if(ns.isOn)
879 {
880 ns.delay += pos.timeDelay;
881 ns.delayTicks += pos.delay;
882 }
883 }
884 }
885 }
886 #undef DRUM_NOTE_MIN_TIME
887 #undef DRUM_NOTE_MIN_TICKS
888 }
889 #endif
890
891 return true;
892 }
893
processEvents(bool isSeek)894 bool BW_MidiSequencer::processEvents(bool isSeek)
895 {
896 if(m_currentPosition.track.size() == 0)
897 m_atEnd = true;//No MIDI track data to play
898 if(m_atEnd)
899 return false;//No more events in the queue
900
901 m_loop.caughtEnd = false;
902 const size_t TrackCount = m_currentPosition.track.size();
903 const Position rowBeginPosition(m_currentPosition);
904 bool doLoopJump = false;
905 unsigned caughLoopStart = 0;
906 unsigned caughLoopStackStart = 0;
907 unsigned caughLoopStackEnds = 0;
908 unsigned caughLoopStackBreaks = 0;
909
910 #ifdef DEBUG_TIME_CALCULATION
911 double maxTime = 0.0;
912 #endif
913
914 for(size_t tk = 0; tk < TrackCount; ++tk)
915 {
916 Position::TrackInfo &track = m_currentPosition.track[tk];
917 if((track.lastHandledEvent >= 0) && (track.delay <= 0))
918 {
919 //Check is an end of track has been reached
920 if(track.pos == m_trackData[tk].end())
921 {
922 track.lastHandledEvent = -1;
923 break;
924 }
925
926 // Handle event
927 for(size_t i = 0; i < track.pos->events.size(); i++)
928 {
929 const MidiEvent &evt = track.pos->events[i];
930 #ifdef ENABLE_BEGIN_SILENCE_SKIPPING
931 if(!m_currentPosition.began && (evt.type == MidiEvent::T_NOTEON))
932 m_currentPosition.began = true;
933 #endif
934 if(isSeek && (evt.type == MidiEvent::T_NOTEON))
935 continue;
936 handleEvent(tk, evt, track.lastHandledEvent);
937
938 if(m_loop.caughtStart)
939 {
940 caughLoopStart++;
941 m_loop.caughtStart = false;
942 }
943
944 if(m_loop.caughtStackStart)
945 {
946 caughLoopStackStart++;
947 m_loop.caughtStackStart = false;
948 }
949
950 if(m_loop.caughtStackBreak)
951 {
952 caughLoopStackBreaks++;
953 m_loop.caughtStackBreak = false;
954 }
955
956 if(m_loop.caughtEnd || m_loop.isStackEnd() || m_loop.caughtStackEnd)
957 {
958 if(m_loop.caughtStackEnd)
959 {
960 m_loop.caughtStackEnd = false;
961 caughLoopStackEnds++;
962 }
963 doLoopJump = true;
964 break;//Stop event handling on catching loopEnd event!
965 }
966 }
967
968 #ifdef DEBUG_TIME_CALCULATION
969 if(maxTime < track.pos->time)
970 maxTime = track.pos->time;
971 #endif
972 // Read next event time (unless the track just ended)
973 if(track.lastHandledEvent >= 0)
974 {
975 track.delay += track.pos->delay;
976 track.pos++;
977 }
978
979 if(doLoopJump)
980 break;
981 }
982 }
983
984 #ifdef DEBUG_TIME_CALCULATION
985 std::fprintf(stdout, " \r");
986 std::fprintf(stdout, "Time: %10f; Audio: %10f\r", maxTime, m_currentPosition.absTimePosition);
987 std::fflush(stdout);
988 #endif
989
990 // Find shortest delay from all track
991 uint64_t shortest = 0;
992 bool shortest_no = true;
993
994 for(size_t tk = 0; tk < TrackCount; ++tk)
995 {
996 Position::TrackInfo &track = m_currentPosition.track[tk];
997 if((track.lastHandledEvent >= 0) && (shortest_no || track.delay < shortest))
998 {
999 shortest = track.delay;
1000 shortest_no = false;
1001 }
1002 }
1003
1004 //if(shortest > 0) UI.PrintLn("shortest: %ld", shortest);
1005
1006 // Schedule the next playevent to be processed after that delay
1007 for(size_t tk = 0; tk < TrackCount; ++tk)
1008 m_currentPosition.track[tk].delay -= shortest;
1009
1010 fraction<uint64_t> t = shortest * m_tempo;
1011
1012 #ifdef ENABLE_BEGIN_SILENCE_SKIPPING
1013 if(m_currentPosition.began)
1014 #endif
1015 m_currentPosition.wait += t.value();
1016
1017 //if(shortest > 0) UI.PrintLn("Delay %ld (%g)", shortest, (double)t.valuel());
1018 if(caughLoopStart > 0)
1019 m_loopBeginPosition = rowBeginPosition;
1020
1021 if(caughLoopStackStart > 0)
1022 {
1023 while(caughLoopStackStart > 0)
1024 {
1025 m_loop.stackUp();
1026 LoopStackEntry &s = m_loop.getCurStack();
1027 s.startPosition = rowBeginPosition;
1028 caughLoopStackStart--;
1029 }
1030 return true;
1031 }
1032
1033 if(caughLoopStackBreaks > 0)
1034 {
1035 while(caughLoopStackBreaks > 0)
1036 {
1037 LoopStackEntry &s = m_loop.getCurStack();
1038 s.loops = 0;
1039 s.infinity = false;
1040 // Quit the loop
1041 m_loop.stackDown();
1042 caughLoopStackBreaks--;
1043 }
1044 }
1045
1046 if(caughLoopStackEnds > 0)
1047 {
1048 while(caughLoopStackEnds > 0)
1049 {
1050 LoopStackEntry &s = m_loop.getCurStack();
1051 if(s.infinity)
1052 {
1053 m_currentPosition = s.startPosition;
1054 m_loop.skipStackStart = true;
1055 return true;
1056 }
1057 else
1058 if(s.loops >= 0)
1059 {
1060 s.loops--;
1061 if(s.loops > 0)
1062 {
1063 m_currentPosition = s.startPosition;
1064 m_loop.skipStackStart = true;
1065 return true;
1066 }
1067 else
1068 {
1069 // Quit the loop
1070 m_loop.stackDown();
1071 }
1072 }
1073 else
1074 {
1075 // Quit the loop
1076 m_loop.stackDown();
1077 }
1078 caughLoopStackEnds--;
1079 }
1080
1081 return true;
1082 }
1083
1084 if(shortest_no || m_loop.caughtEnd)
1085 {
1086 //Loop if song end or loop end point has reached
1087 m_loop.caughtEnd = false;
1088 shortest = 0;
1089 if(!m_loopEnabled)
1090 {
1091 m_atEnd = true; //Don't handle events anymore
1092 m_currentPosition.wait += m_postSongWaitDelay;//One second delay until stop playing
1093 return true;//We have caugh end here!
1094 }
1095 m_currentPosition = m_loopBeginPosition;
1096 }
1097
1098 return true;//Has events in queue
1099 }
1100
parseEvent(const uint8_t ** pptr,const uint8_t * end,int & status)1101 BW_MidiSequencer::MidiEvent BW_MidiSequencer::parseEvent(const uint8_t **pptr, const uint8_t *end, int &status)
1102 {
1103 const uint8_t *&ptr = *pptr;
1104 BW_MidiSequencer::MidiEvent evt;
1105
1106 if(ptr + 1 > end)
1107 {
1108 //When track doesn't ends on the middle of event data, it's must be fine
1109 evt.type = MidiEvent::T_SPECIAL;
1110 evt.subtype = MidiEvent::ST_ENDTRACK;
1111 return evt;
1112 }
1113
1114 unsigned char byte = *(ptr++);
1115 bool ok = false;
1116
1117 if(byte == MidiEvent::T_SYSEX || byte == MidiEvent::T_SYSEX2)// Ignore SysEx
1118 {
1119 uint64_t length = readVarLenEx(pptr, end, ok);
1120 if(!ok || (ptr + length > end))
1121 {
1122 m_parsingErrorsString += "parseEvent: Can't read SysEx event - Unexpected end of track data.\n";
1123 evt.isValid = 0;
1124 return evt;
1125 }
1126 evt.type = MidiEvent::T_SYSEX;
1127 evt.data.clear();
1128 evt.data.push_back(byte);
1129 std::copy(ptr, ptr + length, std::back_inserter(evt.data));
1130 ptr += (size_t)length;
1131 return evt;
1132 }
1133
1134 if(byte == MidiEvent::T_SPECIAL)
1135 {
1136 // Special event FF
1137 uint8_t evtype = *(ptr++);
1138 uint64_t length = readVarLenEx(pptr, end, ok);
1139 if(!ok || (ptr + length > end))
1140 {
1141 m_parsingErrorsString += "parseEvent: Can't read Special event - Unexpected end of track data.\n";
1142 evt.isValid = 0;
1143 return evt;
1144 }
1145 std::string data(length ? (const char *)ptr : 0, (size_t)length);
1146 ptr += (size_t)length;
1147
1148 evt.type = byte;
1149 evt.subtype = evtype;
1150 evt.data.insert(evt.data.begin(), data.begin(), data.end());
1151
1152 #if 0 /* Print all tempo events */
1153 if(evt.subtype == MidiEvent::ST_TEMPOCHANGE)
1154 {
1155 if(hooks.onDebugMessage)
1156 hooks.onDebugMessage(hooks.onDebugMessage_userData, "Temp Change: %02X%02X%02X", evt.data[0], evt.data[1], evt.data[2]);
1157 }
1158 #endif
1159
1160 /* TODO: Store those meta-strings separately and give ability to read them
1161 * by external functions (to display song title and copyright in the player) */
1162 if(evt.subtype == MidiEvent::ST_COPYRIGHT)
1163 {
1164 if(m_musCopyright.empty())
1165 {
1166 m_musCopyright = std::string((const char *)evt.data.data(), evt.data.size());
1167 if(m_interface->onDebugMessage)
1168 m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Music copyright: %s", m_musCopyright.c_str());
1169 }
1170 else if(m_interface->onDebugMessage)
1171 {
1172 std::string str((const char *)evt.data.data(), evt.data.size());
1173 m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Extra copyright event: %s", str.c_str());
1174 }
1175 }
1176 else if(evt.subtype == MidiEvent::ST_SQTRKTITLE)
1177 {
1178 if(m_musTitle.empty())
1179 {
1180 m_musTitle = std::string((const char *)evt.data.data(), evt.data.size());
1181 if(m_interface->onDebugMessage)
1182 m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Music title: %s", m_musTitle.c_str());
1183 }
1184 else if(m_interface->onDebugMessage)
1185 {
1186 //TODO: Store track titles and associate them with each track and make API to retreive them
1187 std::string str((const char *)evt.data.data(), evt.data.size());
1188 m_musTrackTitles.push_back(str);
1189 m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Track title: %s", str.c_str());
1190 }
1191 }
1192 else if(evt.subtype == MidiEvent::ST_INSTRTITLE)
1193 {
1194 if(m_interface->onDebugMessage)
1195 {
1196 std::string str((const char *)evt.data.data(), evt.data.size());
1197 m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Instrument: %s", str.c_str());
1198 }
1199 }
1200 else if(evt.subtype == MidiEvent::ST_MARKER)
1201 {
1202 //To lower
1203 for(size_t i = 0; i < data.size(); i++)
1204 {
1205 if(data[i] <= 'Z' && data[i] >= 'A')
1206 data[i] = static_cast<char>(data[i] - ('Z' - 'z'));
1207 }
1208
1209 if(data == "loopstart")
1210 {
1211 //Return a custom Loop Start event instead of Marker
1212 evt.subtype = MidiEvent::ST_LOOPSTART;
1213 evt.data.clear();//Data is not needed
1214 return evt;
1215 }
1216
1217 if(data == "loopend")
1218 {
1219 //Return a custom Loop End event instead of Marker
1220 evt.subtype = MidiEvent::ST_LOOPEND;
1221 evt.data.clear();//Data is not needed
1222 return evt;
1223 }
1224
1225 if(!data.compare(0, 10, "loopstart="))
1226 {
1227 evt.type = MidiEvent::T_SPECIAL;
1228 evt.subtype = MidiEvent::ST_LOOPSTACK_BEGIN;
1229 uint8_t loops = static_cast<uint8_t>(atoi(data.substr(10).c_str()));
1230 evt.data.clear();
1231 evt.data.push_back(loops);
1232
1233 if(m_interface->onDebugMessage)
1234 {
1235 m_interface->onDebugMessage(
1236 m_interface->onDebugMessage_userData,
1237 "Stack Marker Loop Start at %d to %d level with %d loops",
1238 m_loop.stackLevel,
1239 m_loop.stackLevel + 1,
1240 loops
1241 );
1242 }
1243 return evt;
1244 }
1245
1246 if(!data.compare(0, 8, "loopend="))
1247 {
1248 evt.type = MidiEvent::T_SPECIAL;
1249 evt.subtype = MidiEvent::ST_LOOPSTACK_END;
1250 evt.data.clear();
1251
1252 if(m_interface->onDebugMessage)
1253 {
1254 m_interface->onDebugMessage(
1255 m_interface->onDebugMessage_userData,
1256 "Stack Marker Loop %s at %d to %d level",
1257 (evt.subtype == MidiEvent::ST_LOOPSTACK_END ? "End" : "Break"),
1258 m_loop.stackLevel,
1259 m_loop.stackLevel - 1
1260 );
1261 }
1262 return evt;
1263 }
1264 }
1265
1266 if(evtype == MidiEvent::ST_ENDTRACK)
1267 status = -1;//Finalize track
1268
1269 return evt;
1270 }
1271
1272 // Any normal event (80..EF)
1273 if(byte < 0x80)
1274 {
1275 byte = static_cast<uint8_t>(status | 0x80);
1276 ptr--;
1277 }
1278
1279 //Sys Com Song Select(Song #) [0-127]
1280 if(byte == MidiEvent::T_SYSCOMSNGSEL)
1281 {
1282 if(ptr + 1 > end)
1283 {
1284 m_parsingErrorsString += "parseEvent: Can't read System Command Song Select event - Unexpected end of track data.\n";
1285 evt.isValid = 0;
1286 return evt;
1287 }
1288 evt.type = byte;
1289 evt.data.push_back(*(ptr++));
1290 return evt;
1291 }
1292
1293 //Sys Com Song Position Pntr [LSB, MSB]
1294 if(byte == MidiEvent::T_SYSCOMSPOSPTR)
1295 {
1296 if(ptr + 2 > end)
1297 {
1298 m_parsingErrorsString += "parseEvent: Can't read System Command Position Pointer event - Unexpected end of track data.\n";
1299 evt.isValid = 0;
1300 return evt;
1301 }
1302 evt.type = byte;
1303 evt.data.push_back(*(ptr++));
1304 evt.data.push_back(*(ptr++));
1305 return evt;
1306 }
1307
1308 uint8_t midCh = byte & 0x0F, evType = (byte >> 4) & 0x0F;
1309 status = byte;
1310 evt.channel = midCh;
1311 evt.type = evType;
1312
1313 switch(evType)
1314 {
1315 case MidiEvent::T_NOTEOFF://2 byte length
1316 case MidiEvent::T_NOTEON:
1317 case MidiEvent::T_NOTETOUCH:
1318 case MidiEvent::T_CTRLCHANGE:
1319 case MidiEvent::T_WHEEL:
1320 if(ptr + 2 > end)
1321 {
1322 m_parsingErrorsString += "parseEvent: Can't read regular 2-byte event - Unexpected end of track data.\n";
1323 evt.isValid = 0;
1324 return evt;
1325 }
1326
1327 evt.data.push_back(*(ptr++));
1328 evt.data.push_back(*(ptr++));
1329
1330 if((evType == MidiEvent::T_NOTEON) && (evt.data[1] == 0))
1331 {
1332 evt.type = MidiEvent::T_NOTEOFF; // Note ON with zero velocity is Note OFF!
1333 }
1334 else
1335 if(evType == MidiEvent::T_CTRLCHANGE)
1336 {
1337 //111'th loopStart controller (RPG Maker and others)
1338 if((m_format == Format_MIDI) && (evt.data[0] == 111))
1339 {
1340 //Change event type to custom Loop Start event and clear data
1341 evt.type = MidiEvent::T_SPECIAL;
1342 evt.subtype = MidiEvent::ST_LOOPSTART;
1343 evt.data.clear();
1344 }
1345
1346 if(m_format == Format_XMIDI)
1347 {
1348 if(evt.data[0] == 116)
1349 {
1350 evt.type = MidiEvent::T_SPECIAL;
1351 evt.subtype = MidiEvent::ST_LOOPSTACK_BEGIN;
1352 evt.data[0] = evt.data[1];
1353 evt.data.pop_back();
1354
1355 if(m_interface->onDebugMessage)
1356 {
1357 m_interface->onDebugMessage(
1358 m_interface->onDebugMessage_userData,
1359 "Stack XMI Loop Start at %d to %d level with %d loops",
1360 m_loop.stackLevel,
1361 m_loop.stackLevel + 1,
1362 evt.data[0]
1363 );
1364 }
1365 }
1366
1367 if(evt.data[0] == 117)
1368 {
1369 evt.type = MidiEvent::T_SPECIAL;
1370 evt.subtype = evt.data[1] < 64 ?
1371 MidiEvent::ST_LOOPSTACK_BREAK :
1372 MidiEvent::ST_LOOPSTACK_END;
1373 evt.data.clear();
1374
1375 if(m_interface->onDebugMessage)
1376 {
1377 m_interface->onDebugMessage(
1378 m_interface->onDebugMessage_userData,
1379 "Stack XMI Loop %s at %d to %d level",
1380 (evt.subtype == MidiEvent::ST_LOOPSTACK_END ? "End" : "Break"),
1381 m_loop.stackLevel,
1382 m_loop.stackLevel - 1
1383 );
1384 }
1385 }
1386 }
1387 }
1388
1389 return evt;
1390 case MidiEvent::T_PATCHCHANGE://1 byte length
1391 case MidiEvent::T_CHANAFTTOUCH:
1392 if(ptr + 1 > end)
1393 {
1394 m_parsingErrorsString += "parseEvent: Can't read regular 1-byte event - Unexpected end of track data.\n";
1395 evt.isValid = 0;
1396 return evt;
1397 }
1398 evt.data.push_back(*(ptr++));
1399 return evt;
1400 }
1401
1402 return evt;
1403 }
1404
handleEvent(size_t track,const BW_MidiSequencer::MidiEvent & evt,int32_t & status)1405 void BW_MidiSequencer::handleEvent(size_t track, const BW_MidiSequencer::MidiEvent &evt, int32_t &status)
1406 {
1407
1408 // CC: Call the callback for XMI Controller
1409 if(track == 0 && (evt.type == 0xB || evt.type == 0xC) && (evt.data[1] == 119))
1410 {
1411 if(MidiCallback != NULL) {
1412 MidiCallback();
1413 }
1414 return;
1415 }
1416
1417 if(track == 0 && m_smfFormat < 2 && evt.type == MidiEvent::T_SPECIAL &&
1418 (evt.subtype == MidiEvent::ST_TEMPOCHANGE || evt.subtype == MidiEvent::ST_TIMESIGNATURE))
1419 {
1420 /* never reject track 0 timing events on SMF format != 2
1421 note: multi-track XMI convert to format 2 SMF */
1422 }
1423 else
1424 {
1425 if(m_trackSolo != ~(size_t)0 && track != m_trackSolo)
1426 return;
1427 if(m_trackDisable[track])
1428 return;
1429 }
1430
1431 if(m_interface->onEvent)
1432 {
1433 m_interface->onEvent(m_interface->onEvent_userData,
1434 evt.type, evt.subtype, evt.channel,
1435 evt.data.data(), evt.data.size());
1436 }
1437
1438 if(evt.type == MidiEvent::T_SYSEX || evt.type == MidiEvent::T_SYSEX2) // Ignore SysEx
1439 {
1440 //std::string data( length?(const char*) &TrackData[track][CurrentPosition.track[track].ptr]:0, length );
1441 //UI.PrintLn("SysEx %02X: %u bytes", byte, length/*, data.c_str()*/);
1442 #if 0
1443 std::fputs("SysEx:", stderr);
1444 for(size_t i = 0; i < evt.data.size(); ++i)
1445 std::fprintf(stderr, " %02X", evt.data[i]);
1446 std::fputc('\n', stderr);
1447 #endif
1448 m_interface->rt_systemExclusive(m_interface->rtUserData, evt.data.data(), evt.data.size());
1449 return;
1450 }
1451
1452 if(evt.type == MidiEvent::T_SPECIAL)
1453 {
1454 // Special event FF
1455 uint8_t evtype = evt.subtype;
1456 uint64_t length = (uint64_t)evt.data.size();
1457 const char *data(length ? (const char *)evt.data.data() : "");
1458
1459 if(evtype == MidiEvent::ST_ENDTRACK)//End Of Track
1460 {
1461 status = -1;
1462 return;
1463 }
1464
1465 if(evtype == MidiEvent::ST_TEMPOCHANGE)//Tempo change
1466 {
1467 m_tempo = m_invDeltaTicks * fraction<uint64_t>(readBEint(evt.data.data(), evt.data.size()));
1468 return;
1469 }
1470
1471 if(evtype == MidiEvent::ST_MARKER)//Meta event
1472 {
1473 //Do nothing! :-P
1474 return;
1475 }
1476
1477 if(evtype == MidiEvent::ST_DEVICESWITCH)
1478 {
1479 if(m_interface->onDebugMessage)
1480 m_interface->onDebugMessage(m_interface->onDebugMessage_userData, "Switching another device: %s", data);
1481 if(m_interface->rt_deviceSwitch)
1482 m_interface->rt_deviceSwitch(m_interface->rtUserData, track, data, length);
1483 return;
1484 }
1485
1486 //if(evtype >= 1 && evtype <= 6)
1487 // UI.PrintLn("Meta %d: %s", evtype, data.c_str());
1488
1489 //Turn on Loop handling when loop is enabled
1490 if(m_loopEnabled && !m_loop.invalidLoop)
1491 {
1492 if(evtype == MidiEvent::ST_LOOPSTART) // Special non-spec MIDI loop Start point
1493 {
1494 m_loop.caughtStart = true;
1495 return;
1496 }
1497
1498 if(evtype == MidiEvent::ST_LOOPEND) // Special non-spec MIDI loop End point
1499 {
1500 m_loop.caughtEnd = true;
1501 return;
1502 }
1503
1504 if(evtype == MidiEvent::ST_LOOPSTACK_BEGIN)
1505 {
1506 if(m_loop.skipStackStart)
1507 {
1508 m_loop.skipStackStart = false;
1509 return;
1510 }
1511
1512 LoopStackEntry &s = m_loop.stack[(m_loop.stackLevel + 1)];
1513 s.loops = (int)data[0];
1514 s.infinity = (data[0] == 0);
1515 m_loop.caughtStackStart = true;
1516 return;
1517 }
1518
1519 if(evtype == MidiEvent::ST_LOOPSTACK_END)
1520 {
1521 m_loop.caughtStackEnd = true;
1522 return;
1523 }
1524
1525 if(evtype == MidiEvent::ST_LOOPSTACK_BREAK)
1526 {
1527 m_loop.caughtStackBreak = true;
1528 return;
1529 }
1530 }
1531
1532 if(evtype == MidiEvent::ST_RAWOPL) // Special non-spec ADLMIDI special for IMF playback: Direct poke to AdLib
1533 {
1534 if(m_interface->rt_rawOPL)
1535 m_interface->rt_rawOPL(m_interface->rtUserData, static_cast<uint8_t>(data[0]), static_cast<uint8_t>(data[1]));
1536 return;
1537 }
1538
1539 return;
1540 }
1541
1542 // Any normal event (80..EF)
1543 // if(evt.type < 0x80)
1544 // {
1545 // byte = static_cast<uint8_t>(CurrentPosition.track[track].status | 0x80);
1546 // CurrentPosition.track[track].ptr--;
1547 // }
1548
1549 if(evt.type == MidiEvent::T_SYSCOMSNGSEL ||
1550 evt.type == MidiEvent::T_SYSCOMSPOSPTR)
1551 return;
1552
1553 /*UI.PrintLn("@%X Track %u: %02X %02X",
1554 CurrentPosition.track[track].ptr-1, (unsigned)track, byte,
1555 TrackData[track][CurrentPosition.track[track].ptr]);*/
1556 size_t midCh = evt.channel;//byte & 0x0F, EvType = byte >> 4;
1557 if(m_interface->rt_currentDevice)
1558 midCh += m_interface->rt_currentDevice(m_interface->rtUserData, track);
1559 status = evt.type;
1560
1561 switch(evt.type)
1562 {
1563 case MidiEvent::T_NOTEOFF: // Note off
1564 {
1565 uint8_t note = evt.data[0];
1566 m_interface->rt_noteOff(m_interface->rtUserData, static_cast<uint8_t>(midCh), note);
1567 break;
1568 }
1569
1570 case MidiEvent::T_NOTEON: // Note on
1571 {
1572 uint8_t note = evt.data[0];
1573 uint8_t vol = evt.data[1];
1574 m_interface->rt_noteOn(m_interface->rtUserData, static_cast<uint8_t>(midCh), note, vol);
1575 break;
1576 }
1577
1578 case MidiEvent::T_NOTETOUCH: // Note touch
1579 {
1580 uint8_t note = evt.data[0];
1581 uint8_t vol = evt.data[1];
1582 m_interface->rt_noteAfterTouch(m_interface->rtUserData, static_cast<uint8_t>(midCh), note, vol);
1583 break;
1584 }
1585
1586 case MidiEvent::T_CTRLCHANGE: // Controller change
1587 {
1588 uint8_t ctrlno = evt.data[0];
1589 uint8_t value = evt.data[1];
1590 m_interface->rt_controllerChange(m_interface->rtUserData, static_cast<uint8_t>(midCh), ctrlno, value);
1591 break;
1592 }
1593
1594 case MidiEvent::T_PATCHCHANGE: // Patch change
1595 {
1596 m_interface->rt_patchChange(m_interface->rtUserData, static_cast<uint8_t>(midCh), evt.data[0]);
1597 break;
1598 }
1599
1600 case MidiEvent::T_CHANAFTTOUCH: // Channel after-touch
1601 {
1602 uint8_t chanat = evt.data[0];
1603 m_interface->rt_channelAfterTouch(m_interface->rtUserData, static_cast<uint8_t>(midCh), chanat);
1604 break;
1605 }
1606
1607 case MidiEvent::T_WHEEL: // Wheel/pitch bend
1608 {
1609 uint8_t a = evt.data[0];
1610 uint8_t b = evt.data[1];
1611 m_interface->rt_pitchBend(m_interface->rtUserData, static_cast<uint8_t>(midCh), b, a);
1612 break;
1613 }
1614 }//switch
1615 }
1616
Tick(double s,double granularity)1617 double BW_MidiSequencer::Tick(double s, double granularity)
1618 {
1619 assert(m_interface);// MIDI output interface must be defined!
1620
1621 s *= m_tempoMultiplier;
1622 #ifdef ENABLE_BEGIN_SILENCE_SKIPPING
1623 if(CurrentPositionNew.began)
1624 #endif
1625 m_currentPosition.wait -= s;
1626 m_currentPosition.absTimePosition += s;
1627
1628 int antiFreezeCounter = 10000;//Limit 10000 loops to avoid freezing
1629 while((m_currentPosition.wait <= granularity * 0.5) && (antiFreezeCounter > 0))
1630 {
1631 //std::fprintf(stderr, "wait = %g...\n", CurrentPosition.wait);
1632 if(!processEvents())
1633 break;
1634 if(m_currentPosition.wait <= 0.0)
1635 antiFreezeCounter--;
1636 }
1637
1638 if(antiFreezeCounter <= 0)
1639 m_currentPosition.wait += 1.0;/* Add extra 1 second when over 10000 events
1640 with zero delay are been detected */
1641
1642 if(m_currentPosition.wait < 0.0)//Avoid negative delay value!
1643 return 0.0;
1644
1645 return m_currentPosition.wait;
1646 }
1647
1648
seek(double seconds,const double granularity)1649 double BW_MidiSequencer::seek(double seconds, const double granularity)
1650 {
1651 if(seconds < 0.0)
1652 return 0.0;//Seeking negative position is forbidden! :-P
1653 const double granualityHalf = granularity * 0.5,
1654 s = seconds;//m_setup.delay < m_setup.maxdelay ? m_setup.delay : m_setup.maxdelay;
1655
1656 /* Attempt to go away out of song end must rewind position to begin */
1657 if(seconds > m_fullSongTimeLength)
1658 {
1659 rewind();
1660 return 0.0;
1661 }
1662
1663 bool loopFlagState = m_loopEnabled;
1664 // Turn loop pooints off because it causes wrong position rememberin on a quick seek
1665 m_loopEnabled = false;
1666
1667 /*
1668 * Seeking search is similar to regular ticking, except of next things:
1669 * - We don't processsing arpeggio and vibrato
1670 * - To keep correctness of the state after seek, begin every search from begin
1671 * - All sustaining notes must be killed
1672 * - Ignore Note-On events
1673 */
1674 rewind();
1675
1676 /*
1677 * Set "loop Start" to false to prevent overwrite of loopStart position with
1678 * seek destinition position
1679 *
1680 * TODO: Detect & set loopStart position on load time to don't break loop while seeking
1681 */
1682 m_loop.caughtStart = false;
1683
1684 while((m_currentPosition.absTimePosition < seconds) &&
1685 (m_currentPosition.absTimePosition < m_fullSongTimeLength))
1686 {
1687 m_currentPosition.wait -= s;
1688 m_currentPosition.absTimePosition += s;
1689 int antiFreezeCounter = 10000;//Limit 10000 loops to avoid freezing
1690 double dstWait = m_currentPosition.wait + granualityHalf;
1691 while((m_currentPosition.wait <= granualityHalf)/*&& (antiFreezeCounter > 0)*/)
1692 {
1693 //std::fprintf(stderr, "wait = %g...\n", CurrentPosition.wait);
1694 if(!processEvents(true))
1695 break;
1696 //Avoid freeze because of no waiting increasing in more than 10000 cycles
1697 if(m_currentPosition.wait <= dstWait)
1698 antiFreezeCounter--;
1699 else
1700 {
1701 dstWait = m_currentPosition.wait + granualityHalf;
1702 antiFreezeCounter = 10000;
1703 }
1704 }
1705 if(antiFreezeCounter <= 0)
1706 m_currentPosition.wait += 1.0;/* Add extra 1 second when over 10000 events
1707 with zero delay are been detected */
1708 }
1709
1710 if(m_currentPosition.wait < 0.0)
1711 m_currentPosition.wait = 0.0;
1712
1713 m_loopEnabled = loopFlagState;
1714 return m_currentPosition.wait;
1715 }
1716
tell()1717 double BW_MidiSequencer::tell()
1718 {
1719 return m_currentPosition.absTimePosition;
1720 }
1721
timeLength()1722 double BW_MidiSequencer::timeLength()
1723 {
1724 return m_fullSongTimeLength;
1725 }
1726
getLoopStart()1727 double BW_MidiSequencer::getLoopStart()
1728 {
1729 return m_loopStartTime;
1730 }
1731
getLoopEnd()1732 double BW_MidiSequencer::getLoopEnd()
1733 {
1734 return m_loopEndTime;
1735 }
1736
rewind()1737 void BW_MidiSequencer::rewind()
1738 {
1739 m_currentPosition = m_trackBeginPosition;
1740 m_atEnd = false;
1741
1742 m_loop.reset();
1743 m_loop.caughtStart = true;
1744 }
1745
setTempo(double tempo)1746 void BW_MidiSequencer::setTempo(double tempo)
1747 {
1748 m_tempoMultiplier = tempo;
1749 }
1750
loadMIDI(const std::string & filename)1751 bool BW_MidiSequencer::loadMIDI(const std::string &filename)
1752 {
1753 FileAndMemReader file;
1754 file.openFile(filename.c_str());
1755 if(!loadMIDI(file))
1756 return false;
1757 return true;
1758 }
1759
loadMIDI(const void * data,size_t size)1760 bool BW_MidiSequencer::loadMIDI(const void *data, size_t size)
1761 {
1762 FileAndMemReader file;
1763 file.openData(data, size);
1764 return loadMIDI(file);
1765 }
1766
1767 template<class T>
1768 class BufferGuard
1769 {
1770 T *m_ptr;
1771 public:
BufferGuard()1772 BufferGuard() : m_ptr(NULL)
1773 {}
1774
~BufferGuard()1775 ~BufferGuard()
1776 {
1777 set();
1778 }
1779
set(T * p=NULL)1780 void set(T *p = NULL)
1781 {
1782 if(m_ptr)
1783 free(m_ptr);
1784 m_ptr = p;
1785 }
1786 };
1787
loadMIDI(FileAndMemReader & fr)1788 bool BW_MidiSequencer::loadMIDI(FileAndMemReader &fr)
1789 {
1790 size_t fsize;
1791 BW_MidiSequencer_UNUSED(fsize);
1792 std::vector<std::vector<uint8_t> > rawTrackData;
1793 //! Temp buffer for conversion
1794 BufferGuard<uint8_t> cvt_buf;
1795 m_parsingErrorsString.clear();
1796
1797 assert(m_interface);// MIDI output interface must be defined!
1798
1799 if(!fr.isValid())
1800 {
1801 m_errorString = "Invalid data stream!\n";
1802 #ifndef _WIN32
1803 m_errorString += std::strerror(errno);
1804 #endif
1805 return false;
1806 }
1807
1808 m_atEnd = false;
1809 m_loop.fullReset();
1810 m_loop.caughtStart = true;
1811
1812 m_format = Format_MIDI;
1813
1814 bool is_GMF = false; // GMD/MUS files (ScummVM)
1815 bool is_IMF = false; // IMF
1816 bool is_CMF = false; // Creative Music format (CMF/CTMF)
1817 bool is_RSXX = false; // RSXX, such as Cartooners
1818
1819 const size_t headerSize = 4 + 4 + 2 + 2 + 2; // 14
1820 char headerBuf[headerSize] = "";
1821 size_t DeltaTicks = 192, TrackCount = 1;
1822 unsigned smfFormat = 0;
1823
1824 riffskip:
1825 fsize = fr.read(headerBuf, 1, headerSize);
1826 if(fsize < headerSize)
1827 {
1828 m_errorString = "Unexpected end of file at header!\n";
1829 return false;
1830 }
1831
1832 if(std::memcmp(headerBuf, "RIFF", 4) == 0)
1833 {
1834 fr.seek(6l, FileAndMemReader::CUR);
1835 goto riffskip;
1836 }
1837
1838 if(std::memcmp(headerBuf, "GMF\x1", 4) == 0)
1839 {
1840 // GMD/MUS files (ScummVM)
1841 fr.seek(7 - static_cast<long>(headerSize), FileAndMemReader::CUR);
1842 is_GMF = true;
1843 }
1844 #ifndef BWMIDI_DISABLE_MUS_SUPPORT
1845 else if(std::memcmp(headerBuf, "MUS\x1A", 4) == 0)
1846 {
1847 // MUS/DMX files (Doom)
1848 size_t mus_len = fr.fileSize();
1849 fr.seek(0, FileAndMemReader::SET);
1850 uint8_t *mus = (uint8_t *)malloc(mus_len);
1851 if(!mus)
1852 {
1853 m_errorString = "Out of memory!";
1854 return false;
1855 }
1856 fsize = fr.read(mus, 1, mus_len);
1857 if(fsize < mus_len)
1858 {
1859 fr.close();
1860 m_errorString = "Failed to read MUS file data!\n";
1861 return false;
1862 }
1863
1864 //Close source stream
1865 fr.close();
1866
1867 uint8_t *mid = NULL;
1868 uint32_t mid_len = 0;
1869 int m2mret = Convert_mus2midi(mus, static_cast<uint32_t>(mus_len),
1870 &mid, &mid_len, 0);
1871 if(mus)
1872 free(mus);
1873 if(m2mret < 0)
1874 {
1875 m_errorString = "Invalid MUS/DMX data format!";
1876 return false;
1877 }
1878 cvt_buf.set(mid);
1879 //Open converted MIDI file
1880 fr.openData(mid, static_cast<size_t>(mid_len));
1881 //Re-Read header again!
1882 goto riffskip;
1883 }
1884 #endif //BWMIDI_DISABLE_MUS_SUPPORT
1885
1886 #ifndef BWMIDI_DISABLE_XMI_SUPPORT
1887 else if(std::memcmp(headerBuf, "FORM", 4) == 0)
1888 {
1889 if(std::memcmp(headerBuf + 8, "XDIR", 4) != 0)
1890 {
1891 fr.close();
1892 m_errorString = fr.fileName() + ": Invalid format\n";
1893 return false;
1894 }
1895
1896 size_t mus_len = fr.fileSize();
1897 fr.seek(0, FileAndMemReader::SET);
1898
1899 uint8_t *mus = (uint8_t*)malloc(mus_len);
1900 if(!mus)
1901 {
1902 m_errorString = "Out of memory!";
1903 return false;
1904 }
1905 fsize = fr.read(mus, 1, mus_len);
1906 if(fsize < mus_len)
1907 {
1908 fr.close();
1909 m_errorString = "Failed to read XMI file data!\n";
1910 return false;
1911 }
1912
1913 //Close source stream
1914 fr.close();
1915
1916 uint8_t *mid = NULL;
1917 uint32_t mid_len = 0;
1918 int m2mret = Convert_xmi2midi(mus, static_cast<uint32_t>(mus_len),
1919 &mid, &mid_len, XMIDI_CONVERT_NOCONVERSION);
1920 if(mus) free(mus);
1921 if(m2mret < 0)
1922 {
1923 m_errorString = "Invalid XMI data format!";
1924 return false;
1925 }
1926 cvt_buf.set(mid);
1927 //Open converted MIDI file
1928 fr.openData(mid, static_cast<size_t>(mid_len));
1929 //Set format as XMIDI
1930 m_format = Format_XMIDI;
1931 //Re-Read header again!
1932 goto riffskip;
1933 }
1934 #endif //BWMIDI_DISABLE_XMI_SUPPORT
1935
1936 else if(std::memcmp(headerBuf, "CTMF", 4) == 0)
1937 {
1938 // Creative Music Format (CMF).
1939 // When playing CTMF files, use the following commandline:
1940 // adlmidi song8.ctmf -p -v 1 1 0
1941 // i.e. enable percussion mode, deeper vibrato, and use only 1 card.
1942 is_CMF = true;
1943 m_format = Format_CMF;
1944 //unsigned version = ReadLEint(HeaderBuf+4, 2);
1945 uint64_t ins_start = readLEint(headerBuf + 6, 2);
1946 uint64_t mus_start = readLEint(headerBuf + 8, 2);
1947 //unsigned deltas = ReadLEint(HeaderBuf+10, 2);
1948 uint64_t ticks = readLEint(headerBuf + 12, 2);
1949 // Read title, author, remarks start offsets in file
1950 fsize = fr.read(headerBuf, 1, 6);
1951 if(fsize < 6)
1952 {
1953 fr.close();
1954 m_errorString = "Unexpected file ending on attempt to read CTMF header!";
1955 return false;
1956 }
1957
1958 //unsigned long notes_starts[3] = {ReadLEint(HeaderBuf+0,2),ReadLEint(HeaderBuf+0,4),ReadLEint(HeaderBuf+0,6)};
1959 fr.seek(16, FileAndMemReader::CUR); // Skip the channels-in-use table
1960 fsize = fr.read(headerBuf, 1, 4);
1961 if(fsize < 4)
1962 {
1963 fr.close();
1964 m_errorString = "Unexpected file ending on attempt to read CMF instruments block header!";
1965 return false;
1966 }
1967
1968 uint64_t ins_count = readLEint(headerBuf + 0, 2); //, basictempo = ReadLEint(HeaderBuf+2, 2);
1969 fr.seek(static_cast<long>(ins_start), FileAndMemReader::SET);
1970
1971 m_cmfInstruments.reserve(static_cast<size_t>(ins_count));
1972 for(uint64_t i = 0; i < ins_count; ++i)
1973 {
1974 CmfInstrument inst;
1975 fsize = fr.read(inst.data, 1, 16);
1976 if(fsize < 16)
1977 {
1978 fr.close();
1979 m_errorString = "Unexpected file ending on attempt to read CMF instruments raw data!";
1980 return false;
1981 }
1982 m_cmfInstruments.push_back(inst);
1983 }
1984
1985 fr.seeku(mus_start, FileAndMemReader::SET);
1986 TrackCount = 1;
1987 DeltaTicks = (size_t)ticks;
1988 }
1989 else
1990 {
1991 // Try to identify RSXX format
1992 if(headerBuf[0] == 0x7D)
1993 {
1994 fr.seek(0x6D, FileAndMemReader::SET);
1995 fr.read(headerBuf, 1, 6);
1996 if(std::memcmp(headerBuf, "rsxx}u", 6) == 0)
1997 {
1998 is_RSXX = true;
1999 m_format = Format_RSXX;
2000 fr.seek(0x7D, FileAndMemReader::SET);
2001 TrackCount = 1;
2002 DeltaTicks = 60;
2003 }
2004 }
2005
2006 // Try parsing as an IMF file
2007 if(!is_RSXX)
2008 {
2009 do
2010 {
2011 uint8_t raw[4];
2012 size_t end = static_cast<size_t>(headerBuf[0]) + 256 * static_cast<size_t>(headerBuf[1]);
2013
2014 if(!end || (end & 3))
2015 break;
2016
2017 size_t backup_pos = fr.tell();
2018 int64_t sum1 = 0, sum2 = 0;
2019 fr.seek(2, FileAndMemReader::SET);
2020
2021 for(unsigned n = 0; n < 42; ++n)
2022 {
2023 if(fr.read(raw, 1, 4) != 4)
2024 break;
2025 int64_t value1 = raw[0];
2026 value1 += raw[1] << 8;
2027 sum1 += value1;
2028 int64_t value2 = raw[2];
2029 value2 += raw[3] << 8;
2030 sum2 += value2;
2031 }
2032
2033 fr.seek(static_cast<long>(backup_pos), FileAndMemReader::SET);
2034
2035 if(sum1 > sum2)
2036 {
2037 is_IMF = true;
2038 m_format = Format_IMF;
2039 DeltaTicks = 1;
2040 }
2041 } while(false);
2042 }
2043
2044 if(!is_IMF && !is_RSXX)
2045 {
2046 if(std::memcmp(headerBuf, "MThd\0\0\0\6", 8) != 0)
2047 {
2048 fr.close();
2049 m_errorString = fr.fileName() + ": Invalid format, Header signature is unknown!\n";
2050 return false;
2051 }
2052
2053 smfFormat = (unsigned)readBEint(headerBuf + 8, 2);
2054 TrackCount = (size_t)readBEint(headerBuf + 10, 2);
2055 DeltaTicks = (size_t)readBEint(headerBuf + 12, 2);
2056
2057 if(smfFormat > 2)
2058 smfFormat = 1;
2059 }
2060 }
2061
2062 rawTrackData.clear();
2063 rawTrackData.resize(TrackCount, std::vector<uint8_t>());
2064 m_invDeltaTicks = fraction<uint64_t>(1, 1000000l * static_cast<uint64_t>(DeltaTicks));
2065 if(is_CMF || is_RSXX)
2066 m_tempo = fraction<uint64_t>(1, static_cast<uint64_t>(DeltaTicks));
2067 else
2068 m_tempo = fraction<uint64_t>(1, static_cast<uint64_t>(DeltaTicks) * 2);
2069 static const unsigned char EndTag[4] = {0xFF, 0x2F, 0x00, 0x00};
2070 size_t totalGotten = 0;
2071
2072 for(size_t tk = 0; tk < TrackCount; ++tk)
2073 {
2074 // Read track header
2075 size_t trackLength;
2076
2077 if(is_IMF)
2078 {
2079 //std::fprintf(stderr, "Reading IMF file...\n");
2080 size_t end = static_cast<size_t>(headerBuf[0]) + 256 * static_cast<size_t>(headerBuf[1]);
2081 unsigned IMF_tempo = 1428;
2082 static const unsigned char imf_tempo[] = {0x0,//Zero delay!
2083 MidiEvent::T_SPECIAL, MidiEvent::ST_TEMPOCHANGE, 0x4,
2084 static_cast<uint8_t>(IMF_tempo >> 24),
2085 static_cast<uint8_t>(IMF_tempo >> 16),
2086 static_cast<uint8_t>(IMF_tempo >> 8),
2087 static_cast<uint8_t>(IMF_tempo)
2088 };
2089 rawTrackData[tk].insert(rawTrackData[tk].end(), imf_tempo, imf_tempo + sizeof(imf_tempo));
2090 rawTrackData[tk].push_back(0x00);
2091 fr.seek(2, FileAndMemReader::SET);
2092
2093 while(fr.tell() < end && !fr.eof())
2094 {
2095 uint8_t special_event_buf[5];
2096 uint8_t raw[4];
2097 special_event_buf[0] = MidiEvent::T_SPECIAL;
2098 special_event_buf[1] = MidiEvent::ST_RAWOPL;
2099 special_event_buf[2] = 0x02;
2100 if(fr.read(raw, 1, 4) != 4)
2101 break;
2102 special_event_buf[3] = raw[0]; // port index
2103 special_event_buf[4] = raw[1]; // port value
2104 uint32_t delay = static_cast<uint32_t>(raw[2]);
2105 delay += 256 * static_cast<uint32_t>(raw[3]);
2106 totalGotten += 4;
2107 //if(special_event_buf[3] <= 8) continue;
2108 //fprintf(stderr, "Put %02X <- %02X, plus %04X delay\n", special_event_buf[3],special_event_buf[4], delay);
2109 rawTrackData[tk].insert(rawTrackData[tk].end(), special_event_buf, special_event_buf + 5);
2110 //if(delay>>21) TrackData[tk].push_back( 0x80 | ((delay>>21) & 0x7F ) );
2111 if(delay >> 14)
2112 rawTrackData[tk].push_back(static_cast<uint8_t>(0x80 | ((delay >> 14) & 0x7F)));
2113 if(delay >> 7)
2114 rawTrackData[tk].push_back(static_cast<uint8_t>(0x80 | ((delay >> 7) & 0x7F)));
2115 rawTrackData[tk].push_back(static_cast<uint8_t>(((delay >> 0) & 0x7F)));
2116 }
2117
2118 rawTrackData[tk].insert(rawTrackData[tk].end(), EndTag + 0, EndTag + 4);
2119 }
2120 else
2121 {
2122 // Take the rest of the file
2123 if(is_GMF || is_CMF || is_RSXX)
2124 {
2125 size_t pos = fr.tell();
2126 fr.seek(0, FileAndMemReader::END);
2127 trackLength = fr.tell() - pos;
2128 fr.seek(static_cast<long>(pos), FileAndMemReader::SET);
2129 }
2130 else
2131 {
2132 fsize = fr.read(headerBuf, 1, 8);
2133 if((fsize < 8) || (std::memcmp(headerBuf, "MTrk", 4) != 0))
2134 {
2135 fr.close();
2136 m_errorString = fr.fileName() + ": Invalid format, MTrk signature is not found!\n";
2137 return false;
2138 }
2139 trackLength = (size_t)readBEint(headerBuf + 4, 4);
2140 }
2141
2142 // Read track data
2143 rawTrackData[tk].resize(trackLength);
2144 fsize = fr.read(&rawTrackData[tk][0], 1, trackLength);
2145 if(fsize < trackLength)
2146 {
2147 fr.close();
2148 m_errorString = fr.fileName() + ": Unexpected file ending while getting raw track data!\n";
2149 return false;
2150 }
2151 totalGotten += fsize;
2152
2153 if(is_GMF/*|| is_MUS*/) // Note: CMF does include the track end tag.
2154 rawTrackData[tk].insert(rawTrackData[tk].end(), EndTag + 0, EndTag + 4);
2155 if(is_RSXX)//Finalize raw track data with a zero
2156 rawTrackData[tk].push_back(0);
2157 }
2158 }
2159
2160 for(size_t tk = 0; tk < TrackCount; ++tk)
2161 totalGotten += rawTrackData[tk].size();
2162
2163 if(totalGotten == 0)
2164 {
2165 m_errorString = fr.fileName() + ": Empty track data";
2166 return false;
2167 }
2168
2169 // Build new MIDI events table
2170 if(!buildTrackData(rawTrackData))
2171 {
2172 m_errorString = fr.fileName() + ": MIDI data parsing error has occouped!\n" + m_parsingErrorsString;
2173 return false;
2174 }
2175
2176 m_smfFormat = smfFormat;
2177 m_loop.stackLevel = -1;
2178
2179 return true;
2180 }
2181