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