Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "midifile.h"
24 :
25 : #include "containers.h"
26 :
27 : #include "log.h"
28 :
29 : using namespace mu::engraving;
30 :
31 : namespace mu::iex::midi {
32 212 : MidiFile::MidiFile()
33 : {
34 212 : fp = 0;
35 212 : _division = 0;
36 212 : _isDivisionInTps = false;
37 212 : _format = 1;
38 212 : _noRunningStatus = false;
39 :
40 212 : status = 0;
41 212 : sstatus = 0;
42 212 : click = 0;
43 212 : curPos = 0;
44 212 : }
45 :
46 : //---------------------------------------------------------
47 : // write
48 : // returns true on error
49 : //---------------------------------------------------------
50 :
51 12 : bool MidiFile::write(QIODevice* out)
52 : {
53 12 : fp = out;
54 12 : write("MThd", 4);
55 12 : writeLong(6); // header len
56 12 : writeShort(_format); // format
57 12 : writeShort(static_cast<int>(_tracks.size()));
58 12 : writeShort(_division);
59 173 : for (const auto& t: _tracks) {
60 161 : if (writeTrack(t)) {
61 0 : return true;
62 : }
63 : }
64 12 : return false;
65 : }
66 :
67 : //---------------------------------------------------------
68 : // write
69 : //---------------------------------------------------------
70 :
71 2079 : void MidiFile::writeEvent(const MidiEvent& event)
72 : {
73 2079 : switch (event.type()) {
74 414 : case ME_NOTEON:
75 414 : writeStatus(ME_NOTEON, event.channel());
76 414 : put(event.pitch());
77 414 : put(event.velo());
78 414 : break;
79 :
80 0 : case ME_NOTEOFF:
81 0 : writeStatus(ME_NOTEOFF, event.channel());
82 0 : put(event.pitch());
83 0 : put(event.velo());
84 0 : break;
85 :
86 0 : case ME_PITCHBEND:
87 0 : writeStatus(ME_PITCHBEND, event.channel());
88 0 : put(event.dataA());
89 0 : put(event.dataB());
90 0 : break;
91 :
92 1151 : case ME_CONTROLLER:
93 1151 : switch (event.controller()) {
94 164 : case CTRL_PROGRAM:
95 164 : writeStatus(ME_PROGRAM, event.channel());
96 164 : put(event.value() & 0x7f);
97 164 : break;
98 0 : case CTRL_PRESS:
99 0 : writeStatus(ME_AFTERTOUCH, event.channel());
100 0 : put(event.value() & 0x7f);
101 0 : break;
102 987 : default:
103 987 : writeStatus(ME_CONTROLLER, event.channel());
104 987 : put(event.controller());
105 987 : put(event.value() & 0x7f);
106 987 : break;
107 : }
108 1151 : break;
109 :
110 514 : case ME_META:
111 514 : put(ME_META);
112 514 : put(event.metaType());
113 : // Don't null terminate text meta events
114 514 : if (event.metaType() >= 0x1 && event.metaType() <= 0x14) {
115 161 : putvl(event.len() - 1);
116 161 : write(event.edata(), event.len() - 1);
117 : } else {
118 353 : putvl(event.len());
119 353 : write(event.edata(), event.len());
120 : }
121 514 : resetRunningStatus(); // really ?!
122 514 : break;
123 :
124 0 : case ME_SYSEX:
125 0 : put(ME_SYSEX);
126 0 : putvl(event.len() + 1); // including 0xf7
127 0 : write(event.edata(), event.len());
128 0 : put(ME_ENDSYSEX);
129 0 : resetRunningStatus();
130 0 : break;
131 : }
132 2079 : }
133 :
134 : //---------------------------------------------------------
135 : // writeTrack
136 : //---------------------------------------------------------
137 :
138 161 : bool MidiFile::writeTrack(const MidiTrack& t)
139 : {
140 161 : write("MTrk", 4);
141 161 : qint64 lenpos = fp->pos();
142 161 : writeLong(0); // dummy len
143 :
144 161 : status = -1;
145 161 : int tick = 0;
146 2240 : for (const auto& i : t.events()) {
147 2079 : int ntick = i.first;
148 2079 : putvl(ntick - tick); // write tick delta
149 : //
150 : // if track channel != -1, then use this
151 : // channel for all events in this track
152 : //
153 2079 : if (t.outChannel() != -1) {
154 2079 : writeEvent(i.second);
155 : }
156 2079 : tick = ntick;
157 : }
158 :
159 : //---------------------------------------------------
160 : // write "End Of Track" Meta
161 : // write Track Len
162 : //
163 :
164 161 : putvl(1);
165 161 : put(0xff); // Meta
166 161 : put(0x2f); // EOT
167 161 : putvl(0); // len 0
168 161 : qint64 endpos = fp->pos();
169 161 : fp->seek(lenpos);
170 161 : writeLong(endpos - lenpos - 4); // tracklen
171 161 : fp->seek(endpos);
172 161 : return false;
173 : }
174 :
175 : //---------------------------------------------------------
176 : // writeStatus
177 : //---------------------------------------------------------
178 :
179 1565 : void MidiFile::writeStatus(int nstat, int c)
180 : {
181 1565 : nstat |= (c & 0xf);
182 : //
183 : // running status; except for Sysex- and Meta Events
184 : //
185 1565 : if (_noRunningStatus || (((nstat & 0xf0) != 0xf0) && (nstat != status))) {
186 706 : status = nstat;
187 706 : put(nstat);
188 : }
189 1565 : }
190 :
191 : //---------------------------------------------------------
192 : // readMidi
193 : // return false on error
194 : //---------------------------------------------------------
195 :
196 99 : bool MidiFile::read(QIODevice* in)
197 : {
198 99 : fp = in;
199 99 : _tracks.clear();
200 99 : curPos = 0;
201 :
202 : // === Read header_chunk = "MThd" + <header_length> + <format> + <n> + <division>
203 : //
204 : // "MThd" 4 bytes
205 : // the literal string MThd, or in hexadecimal notation: 0x4d546864.
206 : // These four characters at the start of the MIDI file
207 : // indicate that this is a MIDI file.
208 : // <header_length> 4 bytes
209 : // length of the header chunk (always =6 bytes long - the size of the next
210 : // three fields which are considered the header chunk).
211 : // Although the header chunk currently always contains 6 bytes of data,
212 : // this should not be assumed, this value should always be read and acted upon,
213 : // to allow for possible future extension to the standard.
214 : // <format> 2 bytes
215 : // 0 = single track file format
216 : // 1 = multiple track file format
217 : // 2 = multiple song file format (i.e., a series of type 0 files)
218 : // <n> 2 bytes
219 : // number of track chunks that follow the header chunk
220 : // <division> 2 bytes
221 : // unit of time for delta timing. If the value is positive, then it represents
222 : // the units per beat. For example, +96 would mean 96 ticks per beat.
223 : // If the value is negative, delta times are in SMPTE compatible units.
224 :
225 : char tmp[4];
226 :
227 99 : read(tmp, 4);
228 99 : int len = readLong();
229 99 : if (memcmp(tmp, "MThd", 4) || len < 6) {
230 0 : throw(QString("bad midifile: MThd expected"));
231 : }
232 :
233 99 : if (len > 6) {
234 0 : throw(QString("unsupported MIDI header data size: %1 instead of 6").arg(len));
235 : }
236 :
237 99 : _format = readShort();
238 99 : int ntracks = readShort();
239 :
240 : // ================ Read MIDI division =================
241 : //
242 : // 2 bytes
243 : // +-------+---+-------------------+-----------------+
244 : // | bit |15 | 14 8 | 7 0 |
245 : // +-------+---+-------------------------------------+
246 : // | | 0 | ticks per quarter note |
247 : // | value +---+-------------------------------------+
248 : // | | 1 | -frames/second | ticks/frame |
249 : // +-------+---+-------------------+-----------------+
250 :
251 : char firstByte;
252 99 : fp->getChar(&firstByte);
253 : char secondByte;
254 99 : fp->getChar(&secondByte);
255 99 : const char topBit = (firstByte & 0x80) >> 7;
256 :
257 99 : if (topBit == 0) { // ticks per beat
258 98 : _isDivisionInTps = false;
259 98 : _division = (firstByte << 8) | (secondByte & 0xff);
260 : } else { // ticks per second = fps * ticks per frame
261 1 : _isDivisionInTps = true;
262 1 : const int framesPerSecond = -((signed char)firstByte);
263 1 : const int ticksPerFrame = secondByte;
264 1 : if (framesPerSecond == 29) {
265 0 : _division = qRound(29.97 * ticksPerFrame);
266 : } else {
267 1 : _division = framesPerSecond * ticksPerFrame;
268 : }
269 : }
270 :
271 : // =====================================================
272 :
273 99 : switch (_format) {
274 6 : case 0:
275 6 : if (readTrack()) {
276 0 : return false;
277 : }
278 6 : break;
279 93 : case 1:
280 259 : for (int i = 0; i < ntracks; i++) {
281 168 : if (readTrack()) {
282 2 : return false;
283 : }
284 : }
285 91 : break;
286 0 : default:
287 0 : throw(QString("midi file format %1 not implemented").arg(_format));
288 :
289 : // Prevent "unreachable code" warning
290 : // return false;
291 : }
292 97 : return true;
293 : }
294 :
295 : //---------------------------------------------------------
296 : // readTrack
297 : // return true on error
298 : //---------------------------------------------------------
299 :
300 174 : bool MidiFile::readTrack()
301 : {
302 : char tmp[4];
303 174 : read(tmp, 4);
304 174 : if (memcmp(tmp, "MTrk", 4)) {
305 0 : throw(QString("bad midifile: MTrk expected"));
306 : }
307 174 : int len = readLong(); // len
308 174 : qint64 endPos = curPos + len;
309 174 : status = -1;
310 174 : sstatus = -1; // running status, will not be reset on meta or sysex
311 174 : click = 0;
312 174 : _tracks.push_back(MidiTrack());
313 :
314 174 : int port = 0;
315 174 : _tracks.back().setOutPort(port);
316 174 : _tracks.back().setOutChannel(-1);
317 :
318 : for (;;) {
319 3698 : MidiEvent event;
320 3698 : if (!readEvent(&event)) {
321 2 : return true;
322 : }
323 :
324 : // check for end of track:
325 3696 : if ((event.type() == ME_META) && (event.metaType() == META_EOT)) {
326 172 : break;
327 : }
328 3524 : _tracks.back().insert(click, event);
329 7222 : }
330 172 : if (curPos != endPos) {
331 0 : LOGW("bad track len: %lld != %lld, %lld bytes too much\n", endPos, curPos, endPos - curPos);
332 0 : if (curPos < endPos) {
333 0 : LOGW(" skip %lld\n", endPos - curPos);
334 0 : fp->skip(endPos - curPos);
335 : }
336 : }
337 172 : return false;
338 : }
339 :
340 : /*---------------------------------------------------------
341 : * read
342 : * return false on error
343 : *---------------------------------------------------------*/
344 :
345 13572 : void MidiFile::read(void* p, qint64 len)
346 : {
347 13572 : curPos += len;
348 13572 : qint64 rv = fp->read((char*)p, len);
349 13572 : if (rv != len) {
350 0 : throw(QString("bad midifile: unexpected EOF"));
351 : }
352 13572 : }
353 :
354 : //---------------------------------------------------------
355 : // write
356 : //---------------------------------------------------------
357 :
358 8806 : bool MidiFile::write(const void* p, qint64 len)
359 : {
360 8806 : qint64 rv = fp->write((char*)p, len);
361 8806 : if (rv == len) {
362 8806 : return false;
363 : }
364 0 : LOGD("write midifile failed: %s", fp->errorString().toLatin1().data());
365 0 : return true;
366 : }
367 :
368 : //---------------------------------------------------------
369 : // readShort
370 : //---------------------------------------------------------
371 :
372 198 : int MidiFile::readShort()
373 : {
374 : char c;
375 198 : int val = 0;
376 594 : for (int i = 0; i < 2; ++i) {
377 396 : fp->getChar(&c);
378 396 : val <<= 8;
379 396 : val += (c & 0xff);
380 : }
381 198 : return val;
382 : }
383 :
384 : //---------------------------------------------------------
385 : // writeShort
386 : //---------------------------------------------------------
387 :
388 36 : void MidiFile::writeShort(int i)
389 : {
390 36 : fp->putChar(i >> 8);
391 36 : fp->putChar(i);
392 36 : }
393 :
394 : //---------------------------------------------------------
395 : // readLong
396 : // writeLong
397 : //---------------------------------------------------------
398 :
399 273 : int MidiFile::readLong()
400 : {
401 : char c;
402 273 : int val = 0;
403 1365 : for (int i = 0; i < 4; ++i) {
404 1092 : fp->getChar(&c);
405 1092 : val <<= 8;
406 1092 : val += (c & 0xff);
407 : }
408 273 : return val;
409 : }
410 :
411 : //---------------------------------------------------------
412 : // writeLong
413 : //---------------------------------------------------------
414 :
415 334 : void MidiFile::writeLong(int i)
416 : {
417 334 : fp->putChar(i >> 24);
418 334 : fp->putChar(i >> 16);
419 334 : fp->putChar(i >> 8);
420 334 : fp->putChar(i);
421 334 : }
422 :
423 : /*---------------------------------------------------------
424 : * getvl
425 : * Read variable-length number (7 bits per byte, MSB first)
426 : *---------------------------------------------------------*/
427 :
428 4306 : int MidiFile::getvl()
429 : {
430 4306 : int l = 0;
431 4823 : for (int i = 0; i < 16; i++) {
432 : uchar c;
433 4823 : read(&c, 1);
434 4823 : l += (c & 0x7f);
435 4823 : if (!(c & 0x80)) {
436 4306 : return l;
437 : }
438 517 : l <<= 7;
439 : }
440 0 : return -1;
441 : }
442 :
443 : /*---------------------------------------------------------
444 : * putvl
445 : * Write variable-length number (7 bits per byte, MSB first)
446 : *---------------------------------------------------------*/
447 :
448 2915 : void MidiFile::putvl(unsigned val)
449 : {
450 2915 : unsigned long buf = val & 0x7f;
451 3097 : while ((val >>= 7) > 0) {
452 182 : buf <<= 8;
453 182 : buf |= 0x80;
454 182 : buf += (val & 0x7f);
455 : }
456 : for (;;) {
457 3097 : put(buf);
458 3097 : if (buf & 0x80) {
459 182 : buf >>= 8;
460 : } else {
461 2915 : break;
462 : }
463 : }
464 2915 : }
465 :
466 : //---------------------------------------------------------
467 : // MidiTrack
468 : //---------------------------------------------------------
469 :
470 346 : MidiTrack::MidiTrack()
471 : {
472 346 : _outChannel = -1;
473 346 : _outPort = -1;
474 346 : _drumTrack = false;
475 346 : }
476 :
477 1265 : MidiTrack::~MidiTrack()
478 : {
479 1265 : }
480 :
481 : //---------------------------------------------------------
482 : // insert
483 : //---------------------------------------------------------
484 :
485 5746 : void MidiTrack::insert(int tick, const MidiEvent& event)
486 : {
487 5746 : _events.insert({ tick, event });
488 5746 : }
489 :
490 : //---------------------------------------------------------
491 : // readEvent
492 : // return true on success
493 : //---------------------------------------------------------
494 :
495 3698 : bool MidiFile::readEvent(MidiEvent* event)
496 : {
497 : uchar me, a, b;
498 :
499 3698 : int nclick = getvl();
500 3698 : if (nclick == -1) {
501 0 : LOGD("readEvent: error 1(getvl)");
502 0 : return false;
503 : }
504 3698 : click += nclick;
505 : for (;;) {
506 3698 : read(&me, 1);
507 3698 : if (me >= 0xf1 && me <= 0xfe && me != 0xf7) {
508 0 : LOGD("MIDI: Unknown Message 0x%02x", me & 0xff);
509 : } else {
510 : break;
511 : }
512 : }
513 :
514 : int dataLen;
515 :
516 3698 : if (me == 0xf0 || me == 0xf7) {
517 41 : status = -1; // no running status
518 41 : int len = getvl();
519 41 : if (len < 1) {
520 2 : LOGD("readEvent: error 3");
521 2 : return false;
522 : }
523 39 : dataLen = len;
524 39 : std::vector<unsigned char> data(len + 1);
525 39 : read(data.data(), len);
526 39 : if (data[len - 1] != 0xf7) {
527 0 : LOGD("SYSEX does not end with 0xf7!");
528 : // more to come?
529 : } else {
530 39 : dataLen--; // don't count 0xf7
531 : }
532 39 : event->setType(ME_SYSEX);
533 39 : event->setEData(std::move(data));
534 39 : event->setLen(dataLen);
535 39 : return true;
536 39 : }
537 :
538 3657 : if (me == ME_META) {
539 567 : status = -1; // no running status
540 : uchar type;
541 567 : read(&type, 1);
542 567 : dataLen = getvl(); // read len
543 567 : if (dataLen == -1) {
544 0 : LOGD("readEvent: error 6");
545 0 : return false;
546 : }
547 567 : std::vector<unsigned char> data(dataLen + 1);
548 567 : if (dataLen) {
549 377 : read(data.data(), dataLen);
550 : }
551 :
552 567 : event->setType(ME_META);
553 567 : event->setMetaType(type);
554 567 : event->setLen(dataLen);
555 567 : event->setEData(std::move(data));
556 567 : return true;
557 567 : }
558 :
559 3090 : if (me & 0x80) { // status byte
560 832 : status = me;
561 832 : sstatus = status;
562 832 : read(&a, 1);
563 : } else {
564 2258 : if (status == -1) {
565 0 : LOGD("readEvent: no running status, read 0x%02x", me);
566 0 : LOGD("sstatus ist 0x%02x", sstatus);
567 0 : if (sstatus == -1) {
568 0 : return 0;
569 : }
570 0 : status = sstatus;
571 : }
572 2258 : a = me;
573 : }
574 3090 : int channel = status & 0x0f;
575 3090 : b = 0;
576 3090 : switch (status & 0xf0) {
577 2963 : case ME_NOTEOFF:
578 : case ME_NOTEON:
579 : case ME_POLYAFTER:
580 : case ME_CONTROLLER: // controller
581 : case ME_PITCHBEND: // pitch bend
582 2963 : read(&b, 1);
583 2963 : break;
584 : }
585 3090 : event->setType(status & 0xf0);
586 3090 : event->setChannel(channel);
587 3090 : switch (status & 0xf0) {
588 123 : case ME_NOTEOFF:
589 123 : event->setDataA(a & 0x7f);
590 123 : event->setDataB(b & 0x7f);
591 123 : break;
592 1622 : case ME_NOTEON:
593 1622 : event->setDataA(a & 0x7f);
594 1622 : event->setDataB(b & 0x7f);
595 1622 : break;
596 0 : case ME_POLYAFTER:
597 0 : event->setType(ME_CONTROLLER);
598 0 : event->setController(CTRL_POLYAFTER);
599 0 : event->setValue(((a & 0x7f) << 8) + (b & 0x7f));
600 0 : break;
601 1217 : case ME_CONTROLLER: // controller
602 1217 : event->setController(a & 0x7f);
603 1217 : event->setValue(b & 0x7f);
604 1217 : break;
605 1 : case ME_PITCHBEND: // pitch bend
606 1 : event->setDataA(a & 0x7f);
607 1 : event->setDataB(b & 0x7f);
608 1 : break;
609 127 : case ME_PROGRAM:
610 127 : event->setValue(a & 0x7f);
611 127 : break;
612 0 : case ME_AFTERTOUCH:
613 0 : event->setType(ME_CONTROLLER);
614 0 : event->setController(CTRL_PRESS);
615 0 : event->setValue(a & 0x7f);
616 0 : break;
617 0 : default: // f1 f2 f3 f4 f5 f6 f7 f8 f9
618 0 : LOGD("BAD STATUS 0x%02x, me 0x%02x", status, me);
619 0 : return false;
620 : }
621 :
622 3090 : if ((a & 0x80) || (b & 0x80)) {
623 0 : LOGD("8't bit in data set(%02x %02x): tick %d read 0x%02x status:0x%02x",
624 : a & 0xff, b & 0xff, click, me, status);
625 0 : LOGD("readEvent: error 16");
626 0 : if (b & 0x80) {
627 : // Try to fix: interpret as channel byte
628 0 : status = b;
629 0 : sstatus = status;
630 0 : return true;
631 : }
632 0 : return false;
633 : }
634 3090 : return true;
635 : }
636 :
637 : //---------------------------------------------------------
638 : // setOutChannel
639 : //---------------------------------------------------------
640 :
641 520 : void MidiTrack::setOutChannel(int n)
642 : {
643 520 : _outChannel = n;
644 520 : if (_outChannel == 9) {
645 160 : _drumTrack = true;
646 : }
647 520 : }
648 :
649 : //---------------------------------------------------------
650 : // mergeNoteOnOffAndFindMidiType
651 : // - find matching note on / note off events and merge
652 : // into a note event with tick duration
653 : //---------------------------------------------------------
654 :
655 185 : void MidiTrack::mergeNoteOnOff()
656 : {
657 185 : std::multimap<int, MidiEvent> el;
658 :
659 185 : int hbank = 0xff;
660 185 : int lbank = 0xff;
661 185 : int rpnh = -1;
662 185 : int rpnl = -1;
663 185 : int datah = 0;
664 185 : int datal = 0;
665 185 : int dataType = 0; // 0 : disabled, 0x20000 : rpn, 0x30000 : nrpn;
666 :
667 3709 : for (auto i = _events.begin(); i != _events.end(); ++i) {
668 3524 : MidiEvent& ev = i->second;
669 3524 : if (ev.type() == ME_INVALID) {
670 2642 : continue;
671 : }
672 2661 : if ((ev.type() != ME_NOTEON) && (ev.type() != ME_NOTEOFF)) {
673 1779 : if (ev.type() == ME_CONTROLLER) {
674 1217 : int val = ev.value();
675 1217 : int cn = ev.controller();
676 1217 : if (cn == CTRL_HBANK) {
677 20 : hbank = val;
678 20 : ev.setType(ME_INVALID);
679 20 : continue;
680 1197 : } else if (cn == CTRL_LBANK) {
681 20 : lbank = val;
682 20 : ev.setType(ME_INVALID);
683 20 : continue;
684 1177 : } else if (cn == CTRL_HDATA) {
685 166 : datah = val;
686 :
687 : // check if a CTRL_LDATA follows
688 : // e.g. wie have a 14 bit controller:
689 166 : auto ii = i;
690 166 : ++ii;
691 166 : bool found = false;
692 544 : for (; ii != _events.end(); ++ii) {
693 515 : MidiEvent& ev1 = ii->second;
694 515 : if (ev1.type() == ME_CONTROLLER) {
695 137 : if (ev1.controller() == CTRL_LDATA) {
696 : // handle later
697 3 : found = true;
698 : }
699 137 : break;
700 : }
701 : }
702 166 : if (!found) {
703 163 : if (rpnh == -1 || rpnl == -1) {
704 0 : LOGD("parameter number not defined, data 0x%x", datah);
705 0 : ev.setType(ME_INVALID);
706 3 : continue;
707 : } else {
708 163 : ev.setController(dataType | (rpnh << 8) | rpnl);
709 163 : ev.setValue(datah);
710 : }
711 : } else {
712 3 : ev.setType(ME_INVALID);
713 3 : continue;
714 : }
715 1011 : } else if (cn == CTRL_LDATA) {
716 3 : datal = val;
717 :
718 3 : if (rpnh == -1 || rpnl == -1) {
719 0 : LOGD("parameter number not defined, data 0x%x 0x%x, tick %d, channel %d",
720 0 : datah, datal, i->first, ev.channel());
721 0 : continue;
722 : }
723 : // assume that the sequence is always
724 : // CTRL_HDATA - CTRL_LDATA
725 : // eg. that LDATA is always send last
726 :
727 : // 14 Bit RPN/NRPN
728 3 : ev.setController((dataType + 0x30000) | (rpnh << 8) | rpnl);
729 3 : ev.setValue((datah << 7) | datal);
730 1008 : } else if (cn == CTRL_HRPN) {
731 210 : rpnh = val;
732 210 : dataType = 0x20000;
733 210 : ev.setType(ME_INVALID);
734 210 : continue;
735 798 : } else if (cn == CTRL_LRPN) {
736 210 : rpnl = val;
737 210 : dataType = 0x20000;
738 210 : ev.setType(ME_INVALID);
739 210 : continue;
740 588 : } else if (cn == CTRL_HNRPN) {
741 6 : rpnh = val;
742 6 : dataType = 0x30000;
743 6 : ev.setType(ME_INVALID);
744 6 : continue;
745 582 : } else if (cn == CTRL_LNRPN) {
746 6 : rpnl = val;
747 6 : dataType = 0x30000;
748 6 : ev.setType(ME_INVALID);
749 6 : continue;
750 576 : } else if (cn == CTRL_PROGRAM) {
751 0 : ev.setValue((hbank << 16) | (lbank << 8) | ev.value());
752 : // TODO el.insert(ev);
753 0 : ev.setType(ME_INVALID);
754 0 : continue;
755 : }
756 562 : } else if (ev.type() == ME_SYSEX) {
757 39 : int len = ev.len();
758 39 : const uchar* buffer = ev.edata();
759 : // Yamaha
760 39 : if (buffer[0] == 0x43) {
761 1 : int type = buffer[1] & 0xf0;
762 1 : if (type == 0x10) {
763 1 : if (len == 7 && buffer[2] == 0x4c && buffer[3] == 0x08 && buffer[5] == 7) {
764 : // part mode
765 : // 0 - normal
766 : // 1 - DRUM
767 : // 2 - DRUM 1
768 : // 3 - DRUM 2
769 : // 4 - DRUM 3
770 : // 5 - DRUM 4
771 0 : if (buffer[6] != 0 && buffer[4] == ev.channel()) {
772 0 : _drumTrack = true;
773 : }
774 0 : ev.setType(ME_INVALID);
775 0 : continue;
776 : }
777 : }
778 : }
779 : }
780 1304 : el.insert(std::pair<int, MidiEvent>(i->first, ev));
781 1304 : ev.setType(ME_INVALID);
782 1304 : continue;
783 1304 : }
784 882 : int tick = i->first;
785 882 : if (ev.type() == ME_NOTEOFF || ev.velo() == 0) {
786 0 : LOGD("-extra note off at %d", tick);
787 0 : ev.setType(ME_INVALID);
788 0 : continue;
789 : }
790 882 : MidiEvent note(ME_NOTE, ev.channel(), ev.dataA(), ev.dataB());
791 :
792 882 : auto k = i;
793 882 : ++k;
794 3111 : for (; k != _events.end(); ++k) {
795 3092 : MidiEvent& e = k->second;
796 3092 : if (e.type() != ME_NOTEON && e.type() != ME_NOTEOFF) {
797 1130 : continue;
798 : }
799 3778 : if ((e.type() == ME_NOTEOFF || (e.type() == ME_NOTEON && e.velo() == 0))
800 3778 : && (e.pitch() == note.pitch())) {
801 863 : int t = k->first - tick;
802 863 : if (t <= 0) {
803 0 : t = 1;
804 : }
805 863 : note.setLen(t);
806 863 : e.setType(ME_INVALID);
807 863 : break;
808 : }
809 : }
810 882 : if (k == _events.end()) {
811 19 : LOGD("-no note-off for note at %d", tick);
812 19 : note.setLen(1);
813 : }
814 882 : el.insert(std::pair<int, MidiEvent>(tick, note));
815 882 : ev.setType(ME_INVALID);
816 882 : }
817 185 : _events = el;
818 185 : }
819 :
820 : //---------------------------------------------------------
821 : // separateChannel
822 : // if a track contains events for different midi channels,
823 : // then split events into separate tracks
824 : //---------------------------------------------------------
825 :
826 99 : void MidiFile::separateChannel()
827 : {
828 273 : for (size_t i = 0; i < _tracks.size(); ++i) {
829 : // create a list of channels used in current track
830 174 : std::vector<int> channel;
831 174 : MidiTrack& midiTrack = _tracks[i]; // current track
832 3698 : for (const auto& ie : midiTrack.events()) {
833 3524 : const MidiEvent& e = ie.second;
834 3524 : if (e.isChannelEvent() && !muse::contains(channel, static_cast<int>(e.channel()))) {
835 156 : channel.push_back(e.channel());
836 : }
837 : }
838 174 : midiTrack.setOutChannel(channel.empty() ? 0 : channel[0]);
839 174 : size_t nn = channel.size();
840 174 : if (nn <= 1) {
841 168 : continue;
842 : }
843 6 : std::sort(channel.begin(), channel.end());
844 : // -- split --
845 : // insert additional tracks, assign to them found channels
846 17 : for (size_t ii = 1; ii < nn; ++ii) {
847 11 : MidiTrack t;
848 11 : t.setOutChannel(channel[ii]);
849 11 : _tracks.insert(_tracks.begin() + i + ii, t);
850 11 : }
851 :
852 : //! NOTE: Midi track memory area may be invalid after inserting new elements into tracks
853 : //! Let's get the actual track data again
854 6 : MidiTrack& actualMidiTrack = _tracks[i];
855 :
856 : // extract all different channel events from current track to inserted tracks
857 266 : for (auto ie = actualMidiTrack.events().begin(); ie != actualMidiTrack.events().end();) {
858 260 : const MidiEvent& e = ie->second;
859 260 : if (e.isChannelEvent()) {
860 235 : int ch = e.channel();
861 235 : size_t idx = muse::indexOf(channel, ch);
862 235 : MidiTrack& t = _tracks[i + idx];
863 235 : if (&t != &actualMidiTrack) {
864 143 : t.insert(ie->first, e);
865 143 : ie = actualMidiTrack.events().erase(ie);
866 143 : continue;
867 : }
868 : }
869 117 : ++ie;
870 : }
871 6 : i += nn - 1;
872 174 : }
873 99 : }
874 : } // namespace mu::iex::midi
|