drumstick 2.7.2
qsmf.cpp
Go to the documentation of this file.
1/*
2 Standard MIDI File component
3 Copyright (C) 2006-2022, Pedro Lopez-Cabanillas <plcl@users.sf.net>
4
5 Based on midifile.c by Tim Thompson, M.Czeiszperger and Greg Lee
6
7 This library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <QDataStream>
22#include <QFile>
23#include <QList>
24#include <QTextCodec>
25#include <cmath>
26#include <drumstick/qsmf.h>
27#include <limits>
28
29DISABLE_WARNING_PUSH
30DISABLE_WARNING_DEPRECATED_DECLARATIONS
31
37namespace drumstick {
38namespace File {
39
52class QSmf::QSmfPrivate {
53public:
54 QSmfPrivate():
55 m_Interactive(false),
56 m_CurrTime(0),
57 m_RealTime(0),
58 m_DblRealTime(0),
59 m_DblOldRealtime(0),
60 m_Division(96),
61 m_CurrTempo(500000),
62 m_OldCurrTempo(500000),
63 m_OldRealTime(0),
64 m_OldCurrTime(0),
65 m_RevisedTime(0),
66 m_TempoChangeTime(0),
67 m_ToBeRead(0),
68 m_NumBytesWritten(0),
69 m_Tracks(0),
70 m_fileFormat(0),
71 m_LastStatus(0),
72 m_codec(nullptr),
73 m_IOStream(nullptr)
74 { }
75
76 bool m_Interactive;
77 quint64 m_CurrTime;
78 quint64 m_RealTime;
79 double m_DblRealTime;
80 double m_DblOldRealtime;
81 int m_Division;
82 quint64 m_CurrTempo;
83 quint64 m_OldCurrTempo;
84 quint64 m_OldRealTime;
85 quint64 m_OldCurrTime;
86 quint64 m_RevisedTime;
87 quint64 m_TempoChangeTime;
88 quint64 m_ToBeRead;
89 quint64 m_NumBytesWritten;
90 int m_Tracks;
91 int m_fileFormat;
92 int m_LastStatus;
93 QTextCodec *m_codec;
94 QDataStream *m_IOStream;
95 QByteArray m_MsgBuff;
96 QList<QSmfRecTempo> m_TempoList;
97};
98
104 QObject(parent),
105 d(new QSmfPrivate)
106{ }
107
112{
113 d->m_TempoList.clear();
114}
115
120bool QSmf::endOfSmf()
121{
122 return d->m_IOStream->atEnd();
123}
124
129quint8 QSmf::getByte()
130{
131 quint8 b = 0;
132 if (!endOfSmf())
133 {
134 *d->m_IOStream >> b;
135 d->m_ToBeRead--;
136 }
137 return b;
138}
139
144void QSmf::putByte(quint8 value)
145{
146 *d->m_IOStream << value;
147 d->m_NumBytesWritten++;
148}
149
155void QSmf::addTempo(quint64 tempo, quint64 time)
156{
157 QSmfRecTempo tempoRec;
158 tempoRec.tempo = tempo;
159 tempoRec.time = time;
160 d->m_TempoList.append(tempoRec);
161}
162
166void QSmf::readHeader()
167{
168 d->m_CurrTime = 0;
169 d->m_RealTime = 0;
170 d->m_Division = 96;
171 d->m_CurrTempo = 500000;
172 d->m_OldCurrTempo = 500000;
173 addTempo(d->m_CurrTempo, 0);
174 if (d->m_Interactive)
175 {
176 d->m_fileFormat= 0;
177 d->m_Tracks = 1;
178 d->m_Division = 96;
179 }
180 else
181 {
182 readExpected("MThd");
183 d->m_ToBeRead = read32bit();
184 d->m_fileFormat = read16bit();
185 d->m_Tracks = read16bit();
186 d->m_Division = read16bit();
187 }
188 emit signalSMFHeader(d->m_fileFormat, d->m_Tracks, d->m_Division);
189
190 /* flush any extra stuff, in case the length of header is not */
191 while ((d->m_ToBeRead > 0) && !endOfSmf())
192 {
193 getByte();
194 }
195 if (d->m_ToBeRead > 0)
196 {
197 SMFError("Unexpected end of input");
198 }
199}
200
204void QSmf::readTrack()
205{
206 /* This array is indexed by the high half of a status byte. It's
207 value is either the number of bytes needed (1 or 2) for a channel
208 message, or 0 (meaning it's not a channel message). */
209 static const quint8 chantype[16] =
210 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 };
211
212 quint64 lookfor;
213 quint8 c, c1, type;
214 bool sysexcontinue; // 1 if last message was an unfinished SysEx
215 bool running; // 1 when running status used
216 quint8 status; // status value (e.g. 0x90==note-on)
217 int needed;
218 double delta_secs;
219 quint64 delta_ticks, save_time, save_tempo;
220
221 sysexcontinue = false;
222 status = 0;
223 if (d->m_Interactive)
224 {
225 d->m_ToBeRead = std::numeric_limits<unsigned long long>::max();
226 }
227 else
228 {
229 readExpected("MTrk");
230 d->m_ToBeRead = read32bit();
231 }
232 d->m_CurrTime = 0;
233 d->m_RealTime = 0;
234 d->m_DblRealTime = 0;
235 d->m_DblOldRealtime = 0;
236 d->m_OldCurrTime = 0;
237 d->m_OldRealTime = 0;
238 d->m_CurrTempo = findTempo();
239
240 emit signalSMFTrackStart();
241
242 while (!endOfSmf() && (d->m_Interactive || d->m_ToBeRead > 0))
243 {
244 lookfor = 0;
245 if (d->m_Interactive)
246 {
247 d->m_CurrTime++;
248 }
249 else
250 {
251 delta_ticks = unsigned(readVarLen());
252 d->m_RevisedTime = d->m_CurrTime;
253 d->m_CurrTime += delta_ticks;
254 while (d->m_RevisedTime < d->m_CurrTime)
255 {
256 save_time = d->m_RevisedTime;
257 save_tempo = d->m_CurrTempo;
258 d->m_CurrTempo = findTempo();
259 if (d->m_CurrTempo != d->m_OldCurrTempo)
260 {
261 d->m_OldCurrTempo = d->m_CurrTempo;
262 d->m_OldRealTime = d->m_RealTime;
263 if (d->m_RevisedTime != d->m_TempoChangeTime)
264 {
265 d->m_DblOldRealtime = d->m_DblRealTime;
266 d->m_OldCurrTime = save_time;
267 }
268 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
269 quint16(d->m_Division), save_tempo);
270 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
271 d->m_RealTime = llround(d->m_DblRealTime);
272 if (d->m_RevisedTime == d->m_TempoChangeTime)
273 {
274 d->m_OldCurrTime = d->m_RevisedTime;
275 d->m_DblOldRealtime = d->m_DblRealTime;
276 }
277 }
278 else
279 {
280 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
281 quint16(d->m_Division), d->m_CurrTempo);
282 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
283 d->m_RealTime = llround(d->m_DblRealTime);
284 }
285 }
286 }
287
288 c = getByte();
289 if (sysexcontinue && (c != end_of_sysex))
290 {
291 SMFError("didn't find expected continuation of a SysEx");
292 }
293 if (c < 0xf8)
294 {
295 if ((c & 0x80) == 0)
296 {
297 if (status == 0)
298 {
299 SMFError("unexpected running status");
300 }
301 running = true;
302 }
303 else
304 {
305 status = c;
306 running = false;
307 }
308 needed = chantype[status >> 4 & 0x0f];
309 if (needed != 0)
310 {
311 if (running)
312 {
313 c1 = c;
314 }
315 else
316 {
317 c1 = getByte();
318 }
319 if (needed > 1)
320 {
321 channelMessage(status, c1, getByte());
322 }
323 else
324 {
325 channelMessage(status, c1, 0);
326 }
327 continue;
328 }
329 }
330
331 switch (c)
332 {
333 case meta_event:
334 type = getByte();
335 lookfor = quint64(readVarLen());
336 lookfor = d->m_ToBeRead - lookfor;
337 msgInit();
338 while ((d->m_ToBeRead > lookfor) && !endOfSmf())
339 {
340 msgAdd(getByte());
341 }
342 metaEvent(type);
343 break;
344 case system_exclusive:
345 lookfor = quint64(readVarLen());
346 lookfor = d->m_ToBeRead - lookfor;
347 msgInit();
348 msgAdd(system_exclusive);
349 while ((d->m_ToBeRead > lookfor) && !endOfSmf())
350 {
351 c = getByte();
352 msgAdd(c);
353 }
354 if (c == end_of_sysex)
355 {
356 sysEx();
357 }
358 else
359 {
360 sysexcontinue = true;
361 }
362 break;
363 case end_of_sysex:
364 lookfor = readVarLen();
365 lookfor = d->m_ToBeRead - lookfor;
366 if (!sysexcontinue)
367 {
368 msgInit();
369 }
370 while ((d->m_ToBeRead > lookfor) && !endOfSmf())
371 {
372 c = getByte();
373 msgAdd(c);
374 }
375 if (sysexcontinue)
376 {
377 if (c == end_of_sysex)
378 {
379 sysEx();
380 sysexcontinue = false;
381 }
382 }
383 break;
384 default:
385 badByte(c, d->m_IOStream->device()->pos() - 1);
386 break;
387 }
388 if ((d->m_ToBeRead > lookfor) && endOfSmf())
389 {
390 SMFError("Unexpected end of input");
391 }
392 }
393 emit signalSMFTrackEnd();
394}
395
399void QSmf::SMFRead()
400{
401 int i;
402 readHeader();
403 for ( i = d->m_Tracks; (i > 0) && !endOfSmf(); i--)
404 {
405 readTrack();
406 }
407}
408
416void QSmf::SMFWrite()
417{
418 int i;
419 d->m_LastStatus = 0;
420 writeHeaderChunk(d->m_fileFormat, d->m_Tracks, d->m_Division);
421 d->m_LastStatus = 0;
422 if (d->m_fileFormat == 1)
423 {
425 }
426 for (i = 0; i < d->m_Tracks; ++i)
427 {
428 writeTrackChunk(i);
429 }
430}
431
436void QSmf::readFromStream(QDataStream *stream)
437{
438 d->m_IOStream = stream;
439 SMFRead();
440}
441
446void QSmf::readFromFile(const QString& fileName)
447{
448 QFile file(fileName);
449 file.open(QIODevice::ReadOnly);
450 QDataStream ds(&file);
451 readFromStream(&ds);
452 file.close();
453}
454
459void QSmf::writeToStream(QDataStream *stream)
460{
461 d->m_IOStream = stream;
462 SMFWrite();
463}
464
469void QSmf::writeToFile(const QString& fileName)
470{
471 QFile file(fileName);
472 file.open(QIODevice::WriteOnly);
473 QDataStream ds(&file);
474 writeToStream(&ds);
475 file.close();
476}
477
484void QSmf::writeHeaderChunk(int format, int ntracks, int division)
485{
486 write32bit(MThd);
487 write32bit(6);
488 write16bit(quint16(format));
489 write16bit(quint16(ntracks));
490 write16bit(quint16(division));
491}
492
497void QSmf::writeTrackChunk(int track)
498{
499 quint32 trkhdr;
500 quint32 trklength;
501 qint64 offset;
502 qint64 place_marker;
503
504 d->m_LastStatus = 0;
505 trkhdr = MTrk;
506 trklength = 0;
507 offset = d->m_IOStream->device()->pos();
508 write32bit(trkhdr);
509 write32bit(trklength);
510 d->m_NumBytesWritten = 0;
511
512 emit signalSMFWriteTrack(track);
513
514 place_marker = d->m_IOStream->device()->pos();
515 d->m_IOStream->device()->seek(offset);
516 trklength = d->m_NumBytesWritten;
517 write32bit(trkhdr);
518 write32bit(trklength);
519 d->m_IOStream->device()->seek(place_marker);
520}
521
528void QSmf::writeMetaEvent(long deltaTime, int type, const QByteArray& data)
529{
530 writeVarLen(deltaTime);
531 d->m_LastStatus = meta_event;
532 putByte(d->m_LastStatus);
533 putByte(type);
534 writeVarLen(data.size());
535 foreach(char byte, data)
536 putByte(byte);
537}
538
545void QSmf::writeMetaEvent(long deltaTime, int type, const QString& data)
546{
547 writeVarLen(deltaTime);
548 putByte(d->m_LastStatus = meta_event);
549 putByte(type);
550 QByteArray lcldata;
551 if (d->m_codec == nullptr)
552 lcldata = data.toLatin1();
553 else
554 lcldata = d->m_codec->fromUnicode(data);
555 writeVarLen(lcldata.length());
556 foreach(char byte, lcldata)
557 putByte(byte);
558}
559
567void QSmf::writeMetaEvent(long deltaTime, int type, int data)
568{
569 writeVarLen(deltaTime);
570 putByte(d->m_LastStatus = meta_event);
571 putByte(type);
572 putByte(1);
573 putByte(data);
574}
575
581void QSmf::writeMetaEvent(long deltaTime, int type)
582{
583 writeVarLen(deltaTime);
584 putByte(d->m_LastStatus = meta_event);
585 putByte(type);
586 putByte(0);
587}
588
596void QSmf::writeMidiEvent(long deltaTime, int type, int chan,
597 const QByteArray& data)
598{
599 unsigned int i, j, size;
600 quint8 c;
601 writeVarLen(quint64(deltaTime));
602 if ((type == system_exclusive) || (type == end_of_sysex))
603 {
604 c = type;
605 d->m_LastStatus = 0;
606 }
607 else
608 {
609 if (chan > 15)
610 {
611 SMFError("error: MIDI channel greater than 16");
612 }
613 c = type | chan;
614 }
615 if (d->m_LastStatus != c)
616 {
617 d->m_LastStatus = c;
618 putByte(c);
619 }
620 c = quint8(data[0]);
621 if (type == system_exclusive || type == end_of_sysex)
622 {
623 size = data.size();
624 if (type == c)
625 --size;
626 writeVarLen(size);
627 }
628 j = (c == type ? 1 : 0);
629 for (i = j; i < unsigned(data.size()); ++i)
630 {
631 putByte(quint8(data[i]));
632 }
633}
634
642void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1)
643{
644 quint8 c;
645 writeVarLen(deltaTime);
646 if ((type == system_exclusive) || (type == end_of_sysex))
647 {
648 SMFError("error: Wrong method for a system exclusive event");
649 }
650 if (chan > 15)
651 {
652 SMFError("error: MIDI channel greater than 16");
653 }
654 c = type | chan;
655 if (d->m_LastStatus != c)
656 {
657 d->m_LastStatus = c;
658 putByte(c);
659 }
660 putByte(b1);
661}
662
671void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1, int b2)
672{
673 quint8 c;
674 writeVarLen(deltaTime);
675 if ((type == system_exclusive) || (type == end_of_sysex))
676 {
677 SMFError("error: Wrong method for a system exclusive event");
678 }
679 if (chan > 15)
680 {
681 SMFError("error: MIDI channel greater than 16");
682 }
683 c = type | chan;
684 if (d->m_LastStatus != c)
685 {
686 d->m_LastStatus = c;
687 putByte(c);
688 }
689 putByte(b1);
690 putByte(b2);
691}
692
700void QSmf::writeMidiEvent(long deltaTime, int type, long len, char* data)
701{
702 unsigned int i, j, size;
703 quint8 c;
704 writeVarLen(quint64(deltaTime));
705 if ((type != system_exclusive) && (type != end_of_sysex))
706 {
707 SMFError("error: type should be system exclusive");
708 }
709 d->m_LastStatus = 0;
710 c = quint8(type);
711 putByte(c);
712 size = unsigned(len);
713 c = quint8(data[0]);
714 if (c == type)
715 --size;
716 writeVarLen(size);
717 j = (c == type ? 1 : 0);
718 for (i = j; i < unsigned(len); ++i)
719 {
720 putByte(quint8(data[i]));
721 }
722}
723
729void QSmf::writeSequenceNumber(long deltaTime, int seqnum)
730{
731 writeVarLen(deltaTime);
732 d->m_LastStatus = meta_event;
733 putByte(d->m_LastStatus);
734 putByte(sequence_number);
735 putByte(2);
736 putByte((seqnum >> 8) & 0xff);
737 putByte(seqnum & 0xff);
738}
739
745void QSmf::writeTempo(long deltaTime, long tempo)
746{
747 writeVarLen(deltaTime);
748 putByte(d->m_LastStatus = meta_event);
749 putByte(set_tempo);
750 putByte(3);
751 putByte((tempo >> 16) & 0xff);
752 putByte((tempo >> 8) & 0xff);
753 putByte(tempo & 0xff);
754}
755
761void QSmf::writeBpmTempo(long deltaTime, int tempo)
762{
763 long us_tempo = 60000000l / tempo;
764 writeTempo(deltaTime, us_tempo);
765}
766
775void QSmf::writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
776{
777 writeVarLen(deltaTime);
778 putByte(d->m_LastStatus = meta_event);
779 putByte(time_signature);
780 putByte(4);
781 putByte(num & 0xff);
782 putByte(den & 0xff);
783 putByte(cc & 0xff);
784 putByte(bb & 0xff);
785}
786
793void QSmf::writeKeySignature(long deltaTime, int tone, int mode)
794{
795 writeVarLen(quint64(deltaTime));
796 putByte(d->m_LastStatus = meta_event);
797 putByte(key_signature);
798 putByte(2);
799 putByte(quint8(tone));
800 putByte(mode & 0x01);
801}
802
807void QSmf::writeVarLen(quint64 value)
808{
809 quint64 buffer;
810
811 buffer = value & 0x7f;
812 while ((value >>= 7) > 0)
813 {
814 buffer <<= 8;
815 buffer |= 0x80;
816 buffer += (value & 0x7f);
817 }
818 while (true)
819 {
820 putByte(buffer & 0xff);
821 if (buffer & 0x80)
822 buffer >>= 8;
823 else
824 break;
825 }
826}
827
828/* These routines are used to make sure that the byte order of
829 the various data types remains constant between machines. */
830void QSmf::write32bit(quint32 data)
831{
832 putByte((data >> 24) & 0xff);
833 putByte((data >> 16) & 0xff);
834 putByte((data >> 8) & 0xff);
835 putByte(data & 0xff);
836}
837
838void QSmf::write16bit(quint16 data)
839{
840 putByte((data >> 8) & 0xff);
841 putByte(data & 0xff);
842}
843
844quint16 QSmf::to16bit(quint8 c1, quint8 c2)
845{
846 quint16 value;
847 value = quint16(c1 << 8);
848 value += c2;
849 return value;
850}
851
852quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
853{
854 quint32 value;
855 value = unsigned(c1 << 24);
856 value += unsigned(c2 << 16);
857 value += unsigned(c3 << 8);
858 value += c4;
859 return value;
860}
861
862quint16 QSmf::read16bit()
863{
864 quint8 c1, c2;
865 c1 = getByte();
866 c2 = getByte();
867 return to16bit(c1, c2);
868}
869
870quint32 QSmf::read32bit()
871{
872 quint8 c1, c2, c3, c4;
873 c1 = getByte();
874 c2 = getByte();
875 c3 = getByte();
876 c4 = getByte();
877 return to32bit(c1, c2, c3, c4);
878}
879
880long QSmf::readVarLen()
881{
882 quint64 value;
883 quint8 c;
884
885 c = getByte();
886 value = c;
887 if ((c & 0x80) != 0)
888 {
889 value &= 0x7f;
890 do
891 {
892 c = getByte();
893 value = (value << 7) + (c & 0x7f);
894 } while ((c & 0x80) != 0);
895 }
896 return long(value);
897}
898
899void QSmf::readExpected(const QString& s)
900{
901 int j;
902 quint8 b;
903 for (j = 0; j < s.length(); ++j)
904 {
905 b = getByte();
906 if (QChar(b) != s[j])
907 {
908 SMFError(QString("Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
909 break;
910 }
911 }
912}
913
914quint64 QSmf::findTempo()
915{
916 quint64 result, old_tempo, new_tempo;
917 QSmfRecTempo rec = d->m_TempoList.last();
918 old_tempo = d->m_CurrTempo;
919 new_tempo = d->m_CurrTempo;
920 QList<QSmfRecTempo>::Iterator it;
921 for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
922 {
923 rec = (*it);
924 if (rec.time <= d->m_CurrTime)
925 {
926 old_tempo = rec.tempo;
927 }
928 new_tempo = rec.tempo;
929 if (rec.time > d->m_RevisedTime)
930 {
931 break;
932 }
933 }
934 if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
935 {
936 d->m_RevisedTime = d->m_CurrTime;
937 result = old_tempo;
938 }
939 else
940 {
941 d->m_RevisedTime = rec.time;
942 d->m_TempoChangeTime = d->m_RevisedTime;
943 result = new_tempo;
944 }
945 return result;
946}
947
948/* This routine converts delta times in ticks into seconds. The
949 else statement is needed because the formula is different for tracks
950 based on notes and tracks based on SMPTE times. */
951double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
952{
953 double result;
954 double smpte_format;
955 double smpte_resolution;
956
957 if (division > 0)
958 {
959 result = double(ticks * tempo)/(division * 1000000.0);
960 }
961 else
962 {
963 smpte_format = upperByte(division);
964 smpte_resolution = lowerByte(division);
965 result = double(ticks)/(smpte_format * smpte_resolution
966 * 1000000.0);
967 }
968 return result;
969}
970
971void QSmf::SMFError(const QString& s)
972{
973 emit signalSMFError(s);
974}
975
976void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
977{
978 quint8 chan;
979 int k;
980 chan = status & midi_channel_mask;
981 if (c1 > 127)
982 {
983 SMFError(QString("ChannelMessage with bad c1 = %1").arg(c1));
984 //c1 &= 127;
985 }
986 if (c2 > 127)
987 {
988 SMFError(QString("ChannelMessage with bad c2 = %1").arg(c2));
989 //c2 &= 127;
990 }
991 switch (status & midi_command_mask)
992 {
993 case note_off:
994 emit signalSMFNoteOff(chan, c1, c2);
995 break;
996 case note_on:
997 emit signalSMFNoteOn(chan, c1, c2);
998 break;
999 case poly_aftertouch:
1000 emit signalSMFKeyPress(chan, c1, c2);
1001 break;
1002 case control_change:
1003 emit signalSMFCtlChange(chan, c1, c2);
1004 break;
1005 case program_chng:
1006 emit signalSMFProgram(chan, c1);
1007 break;
1008 case channel_aftertouch:
1009 emit signalSMFChanPress(chan, c1);
1010 break;
1011 case pitch_wheel:
1012 k = c1 + (c2 << 7) - 8192;
1013 emit signalSMFPitchBend(chan, k);
1014 break;
1015 default:
1016 SMFError(QString("Invalid MIDI status %1. Unhandled event").arg(status));
1017 break;
1018 }
1019}
1020
1021void QSmf::metaEvent(quint8 b)
1022{
1023 QSmfRecTempo rec;
1024 QByteArray m(d->m_MsgBuff);
1025
1026 switch (b)
1027 {
1028 case sequence_number:
1029 emit signalSMFSequenceNum(to16bit(m[0], m[1]));
1030 break;
1031 case text_event:
1032 case copyright_notice:
1033 case sequence_name:
1034 case instrument_name:
1035 case lyric:
1036 case marker:
1037 case cue_point: {
1038 QString s;
1039 if (d->m_codec == nullptr) {
1040 emit signalSMFText2(b, m);
1041 } else {
1042 s = d->m_codec->toUnicode(m);
1043 emit signalSMFText(b, s);
1044 }
1045 }
1046 break;
1047 case forced_channel:
1048 emit signalSMFforcedChannel(m[0]);
1049 break;
1050 case forced_port:
1051 emit signalSMFforcedPort(m[0]);
1052 break;
1053 case end_of_track:
1054 emit signalSMFendOfTrack();
1055 break;
1056 case set_tempo:
1057 d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
1058 emit signalSMFTempo(d->m_CurrTempo);
1059 rec = d->m_TempoList.last();
1060 if (rec.tempo == d->m_CurrTempo)
1061 {
1062 return;
1063 }
1064 if (rec.time > d->m_CurrTime)
1065 {
1066 return;
1067 }
1068 addTempo(d->m_CurrTempo, d->m_CurrTime);
1069 break;
1070 case smpte_offset:
1071 emit signalSMFSmpte(m[0], m[1], m[2], m[3], m[4]);
1072 break;
1073 case time_signature:
1074 emit signalSMFTimeSig(m[0], m[1], m[2], m[3]);
1075 break;
1076 case key_signature:
1077 emit signalSMFKeySig(m[0], m[1]);
1078 break;
1079 case sequencer_specific:
1080 emit signalSMFSeqSpecific(m);
1081 break;
1082 default:
1083 emit signalSMFMetaUnregistered(b, m);
1084 break;
1085 }
1086 emit signalSMFMetaMisc(b, m);
1087}
1088
1089void QSmf::sysEx()
1090{
1091 QByteArray varr(d->m_MsgBuff);
1092 emit signalSMFSysex(varr);
1093}
1094
1095void QSmf::badByte(quint8 b, int p)
1096{
1097 SMFError(QString("Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1098}
1099
1100quint8 QSmf::lowerByte(quint16 x)
1101{
1102 return (x & 0xff);
1103}
1104
1105quint8 QSmf::upperByte(quint16 x)
1106{
1107 return ((x >> 8) & 0xff);
1108}
1109
1110void QSmf::msgInit()
1111{
1112 d->m_MsgBuff.truncate(0);
1113}
1114
1115void QSmf::msgAdd(quint8 b)
1116{
1117 int s = d->m_MsgBuff.size();
1118 d->m_MsgBuff.resize(s + 1);
1119 d->m_MsgBuff[s] = b;
1120}
1121
1122/* public properties (accessors) */
1123
1129{
1130 return d->m_CurrTime;
1131}
1132
1138{
1139 return d->m_CurrTempo;
1140}
1141
1147{
1148 return d->m_RealTime;
1149}
1150
1156{
1157 return d->m_Division;
1158}
1159
1164void QSmf::setDivision(int division)
1165{
1166 d->m_Division = division;
1167}
1168
1174{
1175 return d->m_Tracks;
1176}
1177
1182void QSmf::setTracks(int tracks)
1183{
1184 d->m_Tracks = tracks;
1185}
1186
1192{
1193 return d->m_fileFormat;
1194}
1195
1200void QSmf::setFileFormat(int fileFormat)
1201{
1202 d->m_fileFormat = fileFormat;
1203}
1204
1210{
1211 return long(d->m_IOStream->device()->pos());
1212}
1213
1221{
1222 return d->m_codec;
1223}
1224
1233void QSmf::setTextCodec(QTextCodec *codec)
1234{
1235 d->m_codec = codec;
1236}
1237
1243{
1244 return QStringLiteral(QT_STRINGIFY(VERSION));
1245}
1246
1247} // namespace File
1248} // namespace drumstick
1249
1250DISABLE_WARNING_POP
The QObject class is the base class of all Qt objects.
int getTracks()
Gets the number of tracks.
Definition: qsmf.cpp:1173
void signalSMFKeyPress(int chan, int pitch, int press)
Emitted after reading a Polyphonic Aftertouch message.
Q_DECL_DEPRECATED void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
Definition: qsmf.cpp:1233
long getRealTime()
Gets the real time in seconds.
Definition: qsmf.cpp:1146
long getCurrentTempo()
Gets the current tempo.
Definition: qsmf.cpp:1137
void signalSMFforcedChannel(int channel)
Emitted after reading a Forced channel message.
void setDivision(int division)
Sets the resolution.
Definition: qsmf.cpp:1164
long getFilePos()
Gets the position in the SMF stream.
Definition: qsmf.cpp:1209
void signalSMFforcedPort(int port)
Emitted after reading a Forced port message.
void signalSMFTimeSig(int b0, int b1, int b2, int b3)
Emitted after reading a SMF Time signature message.
void signalSMFKeySig(int b0, int b1)
Emitted after reading a SMF Key Signature smessage.
long getCurrentTime()
Gets the current time in ticks.
Definition: qsmf.cpp:1128
void signalSMFChanPress(int chan, int press)
Emitted after reading a Channel Aftertouch message.
void setTracks(int tracks)
Sets the number of tracks.
Definition: qsmf.cpp:1182
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
Writes a Time Signature message.
Definition: qsmf.cpp:775
void signalSMFTrackEnd()
Emitted after a track has finished.
void signalSMFNoteOn(int chan, int pitch, int vol)
Emitted after reading a Note On message.
void signalSMFTempo(int tempo)
Emitted after reading a Tempo Change message.
void signalSMFWriteTrack(int track)
Emitted to request the user to write a track.
Q_DECL_DEPRECATED void signalSMFText(int typ, const QString &data)
Emitted after reading a SMF text message.
void signalSMFTrackStart()
Emitted after reading a track prefix.
void signalSMFError(const QString &errorStr)
Emitted for a SMF read or write error.
int getDivision()
Gets the resolution.
Definition: qsmf.cpp:1155
QSmf(QObject *parent=nullptr)
Constructor.
Definition: qsmf.cpp:103
void writeToFile(const QString &fileName)
Writes a SMF stream to a disk file.
Definition: qsmf.cpp:469
void signalSMFSeqSpecific(const QByteArray &data)
Emitted after reading a Sequencer specific message.
void signalSMFWriteTempoTrack()
Emitted to request the user to prepare the tempo track.
void signalSMFendOfTrack()
Emitted after reading a End-Of-Track message.
void writeSequenceNumber(long deltaTime, int seqnum)
Writes a MIDI Sequence number.
Definition: qsmf.cpp:729
void signalSMFHeader(int format, int ntrks, int division)
Emitted after reading a SMF header.
void readFromStream(QDataStream *stream)
Reads a SMF stream.
Definition: qsmf.cpp:436
void signalSMFProgram(int chan, int patch)
Emitted after reading a Program change message.
void signalSMFText2(int typ, const QByteArray &data)
Emitted after reading a SMF text message.
void signalSMFNoteOff(int chan, int pitch, int vol)
Emitted after reading a Note Off message.
void writeMetaEvent(long deltaTime, int type, const QByteArray &data)
Writes a variable length Meta Event.
Definition: qsmf.cpp:528
void signalSMFSequenceNum(int seq)
Emitted after reading a Sequence number message.
void signalSMFMetaMisc(int typ, const QByteArray &data)
Emitted after reading any SMF Meta message.
Q_DECL_DEPRECATED QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
Definition: qsmf.cpp:1220
virtual ~QSmf()
Destructor.
Definition: qsmf.cpp:111
void writeBpmTempo(long deltaTime, int tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:761
void readFromFile(const QString &fileName)
Reads a SMF stream from a disk file.
Definition: qsmf.cpp:446
void signalSMFSysex(const QByteArray &data)
Emitted after reading a System Exclusive message.
void writeToStream(QDataStream *stream)
Writes a SMF stream.
Definition: qsmf.cpp:459
void writeTempo(long deltaTime, long tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:745
void signalSMFCtlChange(int chan, int ctl, int value)
Emitted after reading a Control Change message.
void writeKeySignature(long deltaTime, int tone, int mode)
Writes a key Signature message.
Definition: qsmf.cpp:793
void setFileFormat(int fileFormat)
Sets the SMF file format.
Definition: qsmf.cpp:1200
void signalSMFPitchBend(int chan, int value)
Emitted after reading a Bender message.
int getFileFormat()
Gets the SMF file format.
Definition: qsmf.cpp:1191
void writeMidiEvent(long deltaTime, int type, int chan, int b1)
Writes a MIDI message with a single parameter.
Definition: qsmf.cpp:642
void signalSMFMetaUnregistered(int typ, const QByteArray &data)
Emitted after reading an unregistered SMF Meta message.
void signalSMFSmpte(int b0, int b1, int b2, int b3, int b4)
Emitted after reading a SMPT offset message.
const quint8 cue_point
SMF Cue point.
Definition: qsmf.h:60
const quint8 system_exclusive
MIDI event System Exclusive begin.
Definition: qsmf.h:78
const quint8 sequencer_specific
SMF Sequencer specific.
Definition: qsmf.h:68
const quint32 MTrk
SMF Track prefix.
Definition: qsmf.h:49
const quint8 forced_channel
SMF Forced MIDI channel.
Definition: qsmf.h:61
const quint8 midi_channel_mask
Mask to extract the channel from the status byte.
Definition: qsmf.h:82
const quint8 note_on
MIDI event Note On.
Definition: qsmf.h:72
const quint8 control_change
MIDI event Control change.
Definition: qsmf.h:74
const quint8 note_off
MIDI event Note Off.
Definition: qsmf.h:71
const quint8 smpte_offset
SMF SMPTE offset.
Definition: qsmf.h:65
const quint8 sequence_number
SMF Sequence number.
Definition: qsmf.h:53
const quint8 sequence_name
SMF Sequence name.
Definition: qsmf.h:56
const quint8 pitch_wheel
MIDI event Bender.
Definition: qsmf.h:77
const quint8 meta_event
SMF Meta Event prefix.
Definition: qsmf.h:52
const quint8 time_signature
SMF Time signature.
Definition: qsmf.h:66
const quint8 end_of_track
SMF End of track.
Definition: qsmf.h:63
const quint32 MThd
SMF Header prefix.
Definition: qsmf.h:48
const quint8 poly_aftertouch
MIDI event Polyphonic pressure.
Definition: qsmf.h:73
QString drumstickLibraryVersion()
drumstickLibraryVersion provides the Drumstick version as an edited QString
Definition: qsmf.cpp:1242
const quint8 key_signature
SMF Key signature.
Definition: qsmf.h:67
const quint8 text_event
SMF Text event.
Definition: qsmf.h:54
const quint8 channel_aftertouch
MIDI event Channel after-touch.
Definition: qsmf.h:76
const quint8 instrument_name
SMF Instrument name.
Definition: qsmf.h:57
const quint8 marker
SMF Marker.
Definition: qsmf.h:59
const quint8 forced_port
SMF Forced MIDI port.
Definition: qsmf.h:62
const quint8 copyright_notice
SMF Copyright notice.
Definition: qsmf.h:55
const quint8 program_chng
MIDI event Program change.
Definition: qsmf.h:75
const quint8 midi_command_mask
Mask to extract the command from the status byte.
Definition: qsmf.h:81
const quint8 end_of_sysex
MIDI event System Exclusive end.
Definition: qsmf.h:79
const quint8 lyric
SMF Lyric.
Definition: qsmf.h:58
const quint8 set_tempo
SMF Tempo change.
Definition: qsmf.h:64
Drumstick common.
Definition: alsaclient.cpp:68
Standard MIDI Files Input/Output.