1 /*
2 Copyright (c) 2003-2006 yuno
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 1. Redistributions of source code must retain the above copyright notice,
8    this list of conditions and the following disclaimer.
9 2. Redistributions in binary form must reproduce the above copyright notice,
10    this list of conditions and the following disclaimer in the documentation
11    and/or other materials provided with the distribution.
12 3. Neither the name of copyright holders nor the names of its contributors
13    may be used to endorse or promote products derived from this software
14    without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #include "system.h"
29 
30 #include "midisequencer.h"
31 #include "output.h"
32 
33 #include <cassert>
34 #include <algorithm>
35 
36 using namespace std::chrono_literals;
37 
38 namespace midisequencer{
read_variable_value(void * fp,int (* fgetc)(void *),uint_least32_t * track_length,const char * errtext)39     static uint_least32_t read_variable_value(void* fp, int(*fgetc)(void*), uint_least32_t* track_length, const char* errtext)
40     {
41         int ret = 0;
42         int d;
43         do{
44             --*track_length;
45             d = fgetc(fp);
46             if(d == EOF){
47                 Output::Warning("Midi sequencer: {}", errtext);
48             }
49             ret <<= 7;
50             ret |= (d & 0x7F);
51         }while(d & 0x80);
52         return ret;
53     }
54 
operator <(const midi_message & a,const midi_message & b)55     inline bool operator<(const midi_message& a, const midi_message& b)
56     {
57         return a.time < b.time;
58     }
59 
sequencer()60     sequencer::sequencer():
61         position(messages.begin())
62     {
63         loop_position = position;
64     }
clear()65     void sequencer::clear()
66     {
67         messages.clear();
68         long_messages.clear();
69         position = messages.begin();
70     }
rewind()71     void sequencer::rewind()
72     {
73         position = messages.begin();
74     }
75 
rewind_to_loop()76     std::vector<midi_message>::iterator sequencer::rewind_to_loop()
77     {
78         position = loop_position;
79         if (position != messages.begin()) {
80             position--;
81         }
82         return loop_position;
83     }
84 
is_at_end()85     bool sequencer::is_at_end()
86     {
87         return position == messages.end();
88     }
load(void * fp,int (* fgetc)(void *))89     bool sequencer::load(void* fp, int(*fgetc)(void*))
90     {
91         bool result = false;
92         clear();
93         int b0 = fgetc(fp);
94         int b1 = fgetc(fp);
95         int b2 = fgetc(fp);
96         int b3 = fgetc(fp);
97         if(b0 == 0x4D && b1 == 0x54 && b2 == 0x68 && b3 == 0x64){
98             load_smf(fp, fgetc);
99             result = true;
100         }else{
101             Output::Warning("Midi sequencer: unsupported format");
102         }
103         if(!result){
104             clear();
105         }
106         position = messages.begin();
107         return result;
108     }
fpfgetc(void * fp)109     static int fpfgetc(void* fp)
110     {
111         return getc(static_cast<std::FILE*>(fp));
112     }
is_loop_start(uint_least32_t msg)113     static bool is_loop_start(uint_least32_t msg) {
114         // If the message matches the de facto standard MIDI loop instruction:
115         // Which is a Control Change on any channel with Value 111
116         uint8_t event_type = (msg & 0x0000F0) >> 4;
117         uint8_t value1 = (msg & 0x00FF00) >> 8;
118         return event_type == 0b1011 && value1 == 111;
119     }
load(std::FILE * fp)120     bool sequencer::load(std::FILE* fp)
121     {
122         return load(fp, fpfgetc);
123     }
get_num_ports() const124     int sequencer::get_num_ports()const
125     {
126         int ret = 0;
127         for(const auto& message: messages){
128             if(ret < message.port){
129                 ret = message.port;
130             }
131         }
132         return ret + 1;
133     }
get_total_time() const134     std::chrono::microseconds sequencer::get_total_time()const
135     {
136         if(messages.empty()){
137             return 0us;
138         }else{
139             return messages.back().time;
140         }
141     }
get_title() const142     std::string sequencer::get_title()const
143     {
144         for(const auto& message: messages){
145             if(message.track == 0 && (message.message & 0xFF) == 0xFF){
146                 assert((message.message >> 8) < long_messages.size());
147                 const std::string& s = long_messages[message.message >> 8];
148                 if(s.size() > 1 && s[0] == 0x03){
149                     return s.substr(1);
150                 }
151             }
152         }
153         return std::string();
154     }
get_copyright() const155     std::string sequencer::get_copyright()const
156     {
157         for(const auto& message: messages){
158             if(message.track == 0 && (message.message & 0xFF) == 0xFF){
159                 assert((message.message >> 8) < long_messages.size());
160                 const std::string& s = long_messages[message.message >> 8];
161                 if(s.size() > 1 && s[0] == 0x02){
162                     return s.substr(1);
163                 }
164             }
165         }
166         return std::string();
167     }
get_song() const168     std::string sequencer::get_song()const
169     {
170         std::string ret;
171         for(const auto& message: messages){
172             if(message.track == 0 && (message.message & 0xFF) == 0xFF){
173                 assert((message.message >> 8) < long_messages.size());
174                 const std::string& s = long_messages[message.message >> 8];
175                 assert(s.size() >= 1);
176                 if(s[0] == 0x05){
177                     ret += s.substr(1);
178                 }
179             }
180         }
181         return ret;
182     }
play(std::chrono::microseconds time,output * out)183     void sequencer::play(std::chrono::microseconds time, output* out)
184     {
185         if(position != messages.begin() && (position - 1)->time >= time){
186             position = messages.begin();
187         }
188         if(position == messages.begin() && position != messages.end() && position->time < time){
189             out->reset();
190         }
191 
192         while(position != messages.end() && position->time < time){
193             uint_least32_t message = position->message;
194             int port = position->port;
195             ++position;
196 
197             switch(message & 0xFF){
198             case 0xF0:
199                 {
200                     assert((message >> 8) < long_messages.size());
201                     const std::string& s = long_messages[static_cast<int>(message >> 8)];
202                     out->sysex_message(port, s.data(), s.size());
203                 }
204                 break;
205             case 0xFF:
206                 {
207                     assert((message >> 8) < long_messages.size());
208                     const std::string& s = long_messages[static_cast<int>(message >> 8)];
209                     assert(s.size() >= 1);
210                     out->meta_event(static_cast<unsigned char>(s[0]), s.data() + 1, s.size() - 1);
211                 }
212                 break;
213             default:
214                 out->midi_message(port, message);
215                 break;
216             }
217         }
218     }
219 
set_time(std::chrono::microseconds time,output * out)220     void sequencer::set_time(std::chrono::microseconds time, output* out)
221     {
222         if(position != messages.begin() && (position - 1)->time >= time){
223             position = messages.begin();
224         }
225         if(position == messages.begin() && position != messages.end() && position->time < time){
226             out->reset();
227         }
228 
229         if(position->time > time)
230             position = messages.begin();
231 
232         while(position != messages.end() && position->time < time){
233             uint_least32_t message = position->message;
234             int port = position->port;
235             ++position;
236 
237             switch(message & 0xFF){
238                 case 0xF0:
239                 {
240                     assert((message >> 8) < long_messages.size());
241                     const std::string& s = long_messages[static_cast<int>(message >> 8)];
242                     out->sysex_message(port, s.data(), s.size());
243                 }
244                     break;
245                 case 0xFF:
246                 {
247                     assert((message >> 8) < long_messages.size());
248                     const std::string& s = long_messages[static_cast<int>(message >> 8)];
249                     assert(s.size() >= 1);
250                     out->meta_event(static_cast<unsigned char>(s[0]), s.data() + 1, s.size() - 1);
251                 }
252                     break;
253                 default:
254 
255                     if((message & 0xF0) == 0x80 || (message & 0xF0) == 0x90)
256                     {
257                         out->meta_event(META_EVENT_ALL_NOTE_OFF, NULL, 0);
258                         break;
259                     }
260 
261                     out->midi_message(port, message);
262                     break;
263             }
264         }
265     }
266 
get_start_skipping_silence()267     std::chrono::microseconds sequencer::get_start_skipping_silence() {
268         std::vector<midi_message> m;
269 
270         for (auto& msg: messages) {
271             // If we find Loop Start before the first NoteOn, just start there
272             if (is_loop_start(msg.message)) {
273                 std::chrono::microseconds time = msg.time;
274                 // RPG_RT always rewinds "a little"
275                 // This amount is based on the tempo, and this 2100000 divisor
276                 // I determined experimentally.
277                 time = std::max(0us, std::chrono::microseconds(static_cast<int>(time.count() - (msg.tempo / 2.1f))));
278                 return time;
279             } else if ((msg.message & 0xFF) == 0xF0) {
280                 // SysEx message. RPG_RT doesn't skip silence if there's a SysEx
281                 // message in the beginning, so neither should we...
282                 return 0us;
283             } else if ((msg.message & 0xF0) == 0x90) {
284                 // NoteOn -- found the first note!
285                 std::chrono::microseconds time = msg.time;
286                 // RPG_RT always rewinds "a little"
287                 // This amount is based on the tempo, and this 2100000 divisor
288                 // I determined experimentally.
289                 time = std::max(0us, std::chrono::microseconds(static_cast<int>(time.count() - (msg.tempo / 2.1f))));
290                 return time;
291             }
292         }
293         return 0us;
294     }
295 
load_smf(void * fp,int (* fgetc)(void *))296     void sequencer::load_smf(void* fp, int(*fgetc)(void*))
297     {
298         if(fgetc(fp) != 0
299         || fgetc(fp) != 0
300         || fgetc(fp) != 0
301         || fgetc(fp) != 6
302         || fgetc(fp) != 0){
303             Output::Warning("Midi sequencer: invalid file header");
304         }
305         int format = fgetc(fp);
306         if(format != 0 && format != 1){
307             Output::Warning("Midi sequencer: unsupported format type");
308         }
309         int t0 = fgetc(fp);
310         int t1 = fgetc(fp);
311         unsigned num_tracks = (t0 << 8) | t1;
312         int d0 = fgetc(fp);
313         int d1 = fgetc(fp);
314         division = (d0 << 8) | d1;
315         for(unsigned track = 0; track < num_tracks; ++track){
316             if(fgetc(fp) != 0x4D || fgetc(fp) != 0x54 || fgetc(fp) != 0x72 || fgetc(fp) != 0x6B){
317                 Output::Warning("Midi sequencer: invalid track header");
318             }
319             int l0 = fgetc(fp);
320             int l1 = fgetc(fp);
321             int l2 = fgetc(fp);
322             int l3 = fgetc(fp);
323             uint_least32_t track_length = (static_cast<uint_least32_t>(l0) << 24)
324                                         | (static_cast<uint_least32_t>(l1) << 16)
325                                         | (l2 << 8)
326                                         | l3;
327             int running_status = 0;
328             double time_offset = 0;
329             uint_least32_t time = 0;
330             midi_message msg;
331             msg.port = 0;
332             msg.track = track;
333             for(;;){
334                 if(track_length < 4){
335                     Output::Warning("Midi sequencer: unexpected EOF (track_length)");
336                 }
337                 uint_least32_t delta = read_variable_value(fp, fgetc, &track_length, "unexpected EOF (deltatime)");
338                 time += delta;
339                 if(division & 0x8000){
340                     int fps = ~(division >> 8) + 1;
341                     int frames = division & 0xFF;
342                     msg.time = std::chrono::microseconds(static_cast<int>(time / (frames * fps) + time_offset));
343                 }else{
344                     msg.time = std::chrono::microseconds(time);
345                 }
346                 int param = fgetc(fp);
347                 --track_length;
348                 switch(param){
349                 case 0xF0:
350                     {
351                         int n = read_variable_value(fp, fgetc, &track_length, "unexpected EOF (sysex length)");
352                         std::string s(n + 1, '\0');
353                         s[0] = static_cast<char>(0xF0);
354                         for(int i = 1; i <= n; ++i){
355                             s[i] = static_cast<char>(fgetc(fp));
356                         }
357                         if(s[n] != '\xF7'){
358                             Output::Debug("Midi sequencer: missing sysex terminator");
359                             s += static_cast<char>(0xF7);
360                         }
361                         track_length -= n;
362                         msg.message = 0xF0 | (long_messages.size() << 8);
363                         messages.push_back(msg);
364                         long_messages.push_back(s);
365                     }
366                     break;
367                 case 0xF7:
368                     /* unsupported */
369                     /*
370                     {
371                         int n = read_variable_value(fp, fgetc, &track_length, "unexpected EOF (sysex-F7 length)");
372                         std::string s(n, '\0');
373                         for(int i = 0; i < n; ++i){
374                             s[i] = fgetc(fp);
375                         }
376                         track_length -= n;
377                         msg.message = 0xF0 | (long_messages.size() << 8);
378                         messages.push_back(msg);
379                         long_messages.push_back(s);
380                     }
381                     */
382                     break;
383                 case 0xFF:
384                     {
385                         int type = fgetc(fp);
386                         --track_length;
387                         int n = read_variable_value(fp, fgetc, &track_length, "unexpected EOF (metaevent)");
388                         std::string s(n + 1, '\0');
389                         s[0] = static_cast<char>(type);
390                         for(int i = 1; i <= n; ++i){
391                             s[i] = static_cast<char>(fgetc(fp));
392                         }
393                         track_length -= n;
394                         msg.message = 0xFF | (long_messages.size() << 8);
395                         messages.push_back(msg);
396                         long_messages.push_back(s);
397                         switch(type){
398                         case 0x21:
399                             if(n == 1){
400                                 msg.port = static_cast<unsigned char>(s[1]);
401                             }
402                             break;
403                         case 0x2F:
404                             goto next_track;
405                         case 0x54:
406                             if(n != 5){
407                                 Output::Warning("Midi sequencer: invalid SMTPE offset metaevent length");
408                             }
409                             if(msg.time == 0us && (division & 0x8000)){
410                                 int hour = static_cast<unsigned char>(s[1]);
411                                 int min = static_cast<unsigned char>(s[2]);
412                                 int sec = static_cast<unsigned char>(s[3]);
413                                 int frame = static_cast<unsigned char>(s[4]);
414                                 int subframe = static_cast<unsigned char>(s[5]);
415                                 double fps;
416                                 switch(hour >> 5){
417                                 default: // line added by nextvolume (2015-02-25)
418                                 case 0:
419                                     fps = 24;
420                                     break;
421                                 case 1:
422                                     fps = 25;
423                                     break;
424                                 case 2:
425                                     fps = 29.97;
426                                     break;
427                                 case 3:
428                                     fps = 30;
429                                     break;
430                                 }
431                                 time = 0;
432                                 time_offset = (hour & 0x1F) * 3600 + min * 60 + sec + (frame + subframe / 100.0) * fps;
433                             }
434                             break;
435                         }
436                     }
437                     break;
438                 default:
439                     if(param & 0x80){
440                         running_status = param;
441                         param = fgetc(fp);
442                         --track_length;
443                     }
444                     switch(running_status & 0xF0){
445                     case 0xC0:
446                     case 0xD0:
447                         msg.message = running_status | (param << 8);
448                         break;
449                     case 0x80:
450                     case 0x90:
451                     case 0xA0:
452                     case 0xB0:
453                     case 0xE0:
454                         msg.message = running_status | (param << 8) | (fgetc(fp) << 16);
455                         --track_length;
456                         break;
457                     default:
458                         Output::Warning("Midi sequencer: invalid midi message");
459                     }
460                     messages.push_back(msg);
461                     break;
462                 }
463             }
464         next_track:
465             while(track_length > 0){
466                 if(fgetc(fp) == EOF){
467                     Output::Warning("Midi sequencer: unexpected EOF (tailer padding)");
468                 }
469                 --track_length;
470             }
471         }
472         std::stable_sort(messages.begin(), messages.end());
473         loop_position = messages.begin();
474         if(!(division & 0x8000)){
475             uint_least32_t tempo = 500000;
476             std::chrono::microseconds time_offset = 0us;
477             std::chrono::microseconds base = 0us;
478             for(auto i = messages.begin(); i != messages.end(); ++i){
479                 std::chrono::microseconds org_time = i->time;
480                 i->time = std::chrono::microseconds(static_cast<int>(static_cast<double>((i->time.count() - base.count())) * tempo / division + time_offset.count()));
481                 if((i->message & 0xFF) == 0xFF){
482                     assert((i->message >> 8) < long_messages.size());
483                     const std::string& s = long_messages[i->message >> 8];
484                     if(s.size() == 4 && s[0] == 0x51){
485                         tempo = (static_cast<uint_least32_t>(static_cast<unsigned char>(s[1])) << 16)
486                               | (static_cast<unsigned char>(s[2]) << 8)
487                               | static_cast<unsigned char>(s[3]);
488                         base = org_time;
489                         time_offset = i->time;
490                     }
491                 }
492                 i->tempo = tempo;
493                 if (is_loop_start(i->message)) {
494                     // Loop backwards through the messages to find the first message with the same
495                     // timestamp as the loop message
496                     for (auto j = i; j != messages.begin() && j->time >= i->time; j--) {
497                         loop_position = j;
498                     }
499                 }
500             }
501         }
502     }
503 
get_division() const504     uint32_t sequencer::get_division() const {
505         return division;
506     }
507 }
508