drumstick 2.0.0
qsmf.cpp
Go to the documentation of this file.
1/*
2 Standard MIDI File component
3 Copyright (C) 2006-2020, 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
33
34namespace drumstick {
35namespace File {
36
48
49class QSmf::QSmfPrivate {
50public:
51 QSmfPrivate():
52 m_Interactive(false),
53 m_CurrTime(0),
54 m_RealTime(0),
55 m_DblRealTime(0),
56 m_DblOldRealtime(0),
57 m_Division(96),
58 m_CurrTempo(500000),
59 m_OldCurrTempo(500000),
60 m_OldRealTime(0),
61 m_OldCurrTime(0),
62 m_RevisedTime(0),
63 m_TempoChangeTime(0),
64 m_ToBeRead(0),
65 m_NumBytesWritten(0),
66 m_Tracks(0),
67 m_fileFormat(0),
68 m_LastStatus(0),
69 m_codec(nullptr),
70 m_IOStream(nullptr)
71 { }
72
73 bool m_Interactive;
74 quint64 m_CurrTime;
75 quint64 m_RealTime;
76 double m_DblRealTime;
77 double m_DblOldRealtime;
78 int m_Division;
79 quint64 m_CurrTempo;
80 quint64 m_OldCurrTempo;
81 quint64 m_OldRealTime;
82 quint64 m_OldCurrTime;
83 quint64 m_RevisedTime;
84 quint64 m_TempoChangeTime;
85 quint64 m_ToBeRead;
86 quint64 m_NumBytesWritten;
87 int m_Tracks;
88 int m_fileFormat;
89 int m_LastStatus;
90 QTextCodec *m_codec;
91 QDataStream *m_IOStream;
92 QByteArray m_MsgBuff;
93 QList<QSmfRecTempo> m_TempoList;
94};
95
101 QObject(parent),
102 d(new QSmfPrivate)
103{ }
104
109{
110 d->m_TempoList.clear();
111}
112
117bool QSmf::endOfSmf()
118{
119 return d->m_IOStream->atEnd();
120}
121
126quint8 QSmf::getByte()
127{
128 quint8 b = 0;
129 if (!endOfSmf())
130 {
131 *d->m_IOStream >> b;
132 d->m_ToBeRead--;
133 }
134 return b;
135}
136
141void QSmf::putByte(quint8 value)
142{
143 *d->m_IOStream << value;
144 d->m_NumBytesWritten++;
145}
146
152void QSmf::addTempo(quint64 tempo, quint64 time)
153{
154 QSmfRecTempo tempoRec;
155 tempoRec.tempo = tempo;
156 tempoRec.time = time;
157 d->m_TempoList.append(tempoRec);
158}
159
163void QSmf::readHeader()
164{
165 d->m_CurrTime = 0;
166 d->m_RealTime = 0;
167 d->m_Division = 96;
168 d->m_CurrTempo = 500000;
169 d->m_OldCurrTempo = 500000;
170 addTempo(d->m_CurrTempo, 0);
171 if (d->m_Interactive)
172 {
173 d->m_fileFormat= 0;
174 d->m_Tracks = 1;
175 d->m_Division = 96;
176 }
177 else
178 {
179 readExpected("MThd");
180 d->m_ToBeRead = read32bit();
181 d->m_fileFormat = read16bit();
182 d->m_Tracks = read16bit();
183 d->m_Division = read16bit();
184 }
185 emit signalSMFHeader(d->m_fileFormat, d->m_Tracks, d->m_Division);
186
187 /* flush any extra stuff, in case the length of header is not */
188 while ((d->m_ToBeRead > 0) && !endOfSmf())
189 {
190 getByte();
191 }
192 if (d->m_ToBeRead > 0)
193 {
194 SMFError("Unexpected end of input");
195 }
196}
197
201void QSmf::readTrack()
202{
203 /* This array is indexed by the high half of a status byte. It's
204 value is either the number of bytes needed (1 or 2) for a channel
205 message, or 0 (meaning it's not a channel message). */
206 static const quint8 chantype[16] =
207 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 };
208
209 quint64 lookfor;
210 quint8 c, c1, type;
211 bool sysexcontinue; // 1 if last message was an unfinished SysEx
212 bool running; // 1 when running status used
213 quint8 status; // status value (e.g. 0x90==note-on)
214 int needed;
215 double delta_secs;
216 quint64 delta_ticks, save_time, save_tempo;
217
218 sysexcontinue = false;
219 status = 0;
220 if (d->m_Interactive)
221 {
222 d->m_ToBeRead = std::numeric_limits<unsigned long long>::max();
223 }
224 else
225 {
226 readExpected("MTrk");
227 d->m_ToBeRead = read32bit();
228 }
229 d->m_CurrTime = 0;
230 d->m_RealTime = 0;
231 d->m_DblRealTime = 0;
232 d->m_DblOldRealtime = 0;
233 d->m_OldCurrTime = 0;
234 d->m_OldRealTime = 0;
235 d->m_CurrTempo = findTempo();
236
237 emit signalSMFTrackStart();
238
239 while (!endOfSmf() && (d->m_Interactive || d->m_ToBeRead > 0))
240 {
241 lookfor = 0;
242 if (d->m_Interactive)
243 {
244 d->m_CurrTime++;
245 }
246 else
247 {
248 delta_ticks = unsigned(readVarLen());
249 d->m_RevisedTime = d->m_CurrTime;
250 d->m_CurrTime += delta_ticks;
251 while (d->m_RevisedTime < d->m_CurrTime)
252 {
253 save_time = d->m_RevisedTime;
254 save_tempo = d->m_CurrTempo;
255 d->m_CurrTempo = findTempo();
256 if (d->m_CurrTempo != d->m_OldCurrTempo)
257 {
258 d->m_OldCurrTempo = d->m_CurrTempo;
259 d->m_OldRealTime = d->m_RealTime;
260 if (d->m_RevisedTime != d->m_TempoChangeTime)
261 {
262 d->m_DblOldRealtime = d->m_DblRealTime;
263 d->m_OldCurrTime = save_time;
264 }
265 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
266 quint16(d->m_Division), save_tempo);
267 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
268 d->m_RealTime = llround(d->m_DblRealTime);
269 if (d->m_RevisedTime == d->m_TempoChangeTime)
270 {
271 d->m_OldCurrTime = d->m_RevisedTime;
272 d->m_DblOldRealtime = d->m_DblRealTime;
273 }
274 }
275 else
276 {
277 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
278 quint16(d->m_Division), d->m_CurrTempo);
279 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
280 d->m_RealTime = llround(d->m_DblRealTime);
281 }
282 }
283 }
284
285 c = getByte();
286 if (sysexcontinue && (c != end_of_sysex))
287 {
288 SMFError("didn't find expected continuation of a SysEx");
289 }
290 if (c < 0xf8)
291 {
292 if ((c & 0x80) == 0)
293 {
294 if (status == 0)
295 {
296 SMFError("unexpected running status");
297 }
298 running = true;
299 }
300 else
301 {
302 status = c;
303 running = false;
304 }
305 needed = chantype[status >> 4 & 0x0f];
306 if (needed != 0)
307 {
308 if (running)
309 {
310 c1 = c;
311 }
312 else
313 {
314 c1 = getByte();
315 }
316 if (needed > 1)
317 {
318 channelMessage(status, c1, getByte());
319 }
320 else
321 {
322 channelMessage(status, c1, 0);
323 }
324 continue;
325 }
326 }
327
328 switch (c)
329 {
330 case meta_event:
331 type = getByte();
332 lookfor = quint64(readVarLen());
333 lookfor = d->m_ToBeRead - lookfor;
334 msgInit();
335 while ((d->m_ToBeRead > lookfor) && !endOfSmf())
336 {
337 msgAdd(getByte());
338 }
339 metaEvent(type);
340 break;
341 case system_exclusive:
342 lookfor = quint64(readVarLen());
343 lookfor = d->m_ToBeRead - lookfor;
344 msgInit();
345 msgAdd(system_exclusive);
346 while ((d->m_ToBeRead > lookfor) && !endOfSmf())
347 {
348 c = getByte();
349 msgAdd(c);
350 }
351 if (c == end_of_sysex)
352 {
353 sysEx();
354 }
355 else
356 {
357 sysexcontinue = true;
358 }
359 break;
360 case end_of_sysex:
361 lookfor = readVarLen();
362 lookfor = d->m_ToBeRead - lookfor;
363 if (!sysexcontinue)
364 {
365 msgInit();
366 }
367 while ((d->m_ToBeRead > lookfor) && !endOfSmf())
368 {
369 c = getByte();
370 msgAdd(c);
371 }
372 if (sysexcontinue)
373 {
374 if (c == end_of_sysex)
375 {
376 sysEx();
377 sysexcontinue = false;
378 }
379 }
380 break;
381 default:
382 badByte(c, d->m_IOStream->device()->pos() - 1);
383 break;
384 }
385 if ((d->m_ToBeRead > lookfor) && endOfSmf())
386 {
387 SMFError("Unexpected end of input");
388 }
389 }
390 emit signalSMFTrackEnd();
391}
392
396void QSmf::SMFRead()
397{
398 int i;
399 readHeader();
400 for ( i = d->m_Tracks; (i > 0) && !endOfSmf(); i--)
401 {
402 readTrack();
403 }
404}
405
413void QSmf::SMFWrite()
414{
415 int i;
416 d->m_LastStatus = 0;
417 writeHeaderChunk(d->m_fileFormat, d->m_Tracks, d->m_Division);
418 d->m_LastStatus = 0;
419 if (d->m_fileFormat == 1)
420 {
422 }
423 for (i = 0; i < d->m_Tracks; ++i)
424 {
425 writeTrackChunk(i);
426 }
427}
428
433void QSmf::readFromStream(QDataStream *stream)
434{
435 d->m_IOStream = stream;
436 SMFRead();
437}
438
443void QSmf::readFromFile(const QString& fileName)
444{
445 QFile file(fileName);
446 file.open(QIODevice::ReadOnly);
447 QDataStream ds(&file);
448 readFromStream(&ds);
449 file.close();
450}
451
456void QSmf::writeToStream(QDataStream *stream)
457{
458 d->m_IOStream = stream;
459 SMFWrite();
460}
461
466void QSmf::writeToFile(const QString& fileName)
467{
468 QFile file(fileName);
469 file.open(QIODevice::WriteOnly);
470 QDataStream ds(&file);
471 writeToStream(&ds);
472 file.close();
473}
474
481void QSmf::writeHeaderChunk(int format, int ntracks, int division)
482{
483 write32bit(MThd);
484 write32bit(6);
485 write16bit(quint16(format));
486 write16bit(quint16(ntracks));
487 write16bit(quint16(division));
488}
489
494void QSmf::writeTrackChunk(int track)
495{
496 quint32 trkhdr;
497 quint32 trklength;
498 qint64 offset;
499 qint64 place_marker;
500
501 d->m_LastStatus = 0;
502 trkhdr = MTrk;
503 trklength = 0;
504 offset = d->m_IOStream->device()->pos();
505 write32bit(trkhdr);
506 write32bit(trklength);
507 d->m_NumBytesWritten = 0;
508
509 emit signalSMFWriteTrack(track);
510
511 place_marker = d->m_IOStream->device()->pos();
512 d->m_IOStream->device()->seek(offset);
513 trklength = d->m_NumBytesWritten;
514 write32bit(trkhdr);
515 write32bit(trklength);
516 d->m_IOStream->device()->seek(place_marker);
517}
518
525void QSmf::writeMetaEvent(long deltaTime, int type, const QByteArray& data)
526{
527 writeVarLen(deltaTime);
528 d->m_LastStatus = meta_event;
529 putByte(d->m_LastStatus);
530 putByte(type);
531 writeVarLen(data.size());
532 foreach(char byte, data)
533 putByte(byte);
534}
535
542void QSmf::writeMetaEvent(long deltaTime, int type, const QString& data)
543{
544 writeVarLen(deltaTime);
545 putByte(d->m_LastStatus = meta_event);
546 putByte(type);
547 QByteArray lcldata;
548 if (d->m_codec == nullptr)
549 lcldata = data.toLatin1();
550 else
551 lcldata = d->m_codec->fromUnicode(data);
552 writeVarLen(lcldata.length());
553 foreach(char byte, lcldata)
554 putByte(byte);
555}
556
564void QSmf::writeMetaEvent(long deltaTime, int type, int data)
565{
566 writeVarLen(deltaTime);
567 putByte(d->m_LastStatus = meta_event);
568 putByte(type);
569 putByte(1);
570 putByte(data);
571}
572
578void QSmf::writeMetaEvent(long deltaTime, int type)
579{
580 writeVarLen(deltaTime);
581 putByte(d->m_LastStatus = meta_event);
582 putByte(type);
583 putByte(0);
584}
585
593void QSmf::writeMidiEvent(long deltaTime, int type, int chan,
594 const QByteArray& data)
595{
596 int i, j, size;
597 quint8 c;
598 writeVarLen(deltaTime);
599 if ((type == system_exclusive) || (type == end_of_sysex))
600 {
601 c = type;
602 d->m_LastStatus = 0;
603 }
604 else
605 {
606 if (chan > 15)
607 {
608 SMFError("error: MIDI channel greater than 16");
609 }
610 c = type | chan;
611 }
612 if (d->m_LastStatus != c)
613 {
614 d->m_LastStatus = c;
615 putByte(c);
616 }
617 if (type == system_exclusive || type == end_of_sysex)
618 {
619 size = data.size();
620 if (data[0] == type)
621 --size;
622 writeVarLen(size);
623 }
624 j = (data[0] == type ? 1 : 0);
625 for (i = j; i < data.size(); ++i)
626 {
627 putByte(data[i]);
628 }
629}
630
638void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1)
639{
640 quint8 c;
641 writeVarLen(deltaTime);
642 if ((type == system_exclusive) || (type == end_of_sysex))
643 {
644 SMFError("error: Wrong method for a system exclusive event");
645 }
646 if (chan > 15)
647 {
648 SMFError("error: MIDI channel greater than 16");
649 }
650 c = type | chan;
651 if (d->m_LastStatus != c)
652 {
653 d->m_LastStatus = c;
654 putByte(c);
655 }
656 putByte(b1);
657}
658
667void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1, int b2)
668{
669 quint8 c;
670 writeVarLen(deltaTime);
671 if ((type == system_exclusive) || (type == end_of_sysex))
672 {
673 SMFError("error: Wrong method for a system exclusive event");
674 }
675 if (chan > 15)
676 {
677 SMFError("error: MIDI channel greater than 16");
678 }
679 c = type | chan;
680 if (d->m_LastStatus != c)
681 {
682 d->m_LastStatus = c;
683 putByte(c);
684 }
685 putByte(b1);
686 putByte(b2);
687}
688
696void QSmf::writeMidiEvent(long deltaTime, int type, long len, char* data)
697{
698 unsigned int i, j, size;
699 quint8 c;
700 writeVarLen(quint64(deltaTime));
701 if ((type != system_exclusive) && (type != end_of_sysex))
702 {
703 SMFError("error: type should be system exclusive");
704 }
705 d->m_LastStatus = 0;
706 c = quint8(type);
707 putByte(c);
708 size = unsigned(len);
709 c = quint8(data[0]);
710 if (c == type)
711 --size;
712 writeVarLen(size);
713 j = (c == type ? 1 : 0);
714 for (i = j; i < unsigned(len); ++i)
715 {
716 putByte(quint8(data[i]));
717 }
718}
719
725void QSmf::writeSequenceNumber(long deltaTime, int seqnum)
726{
727 writeVarLen(deltaTime);
728 d->m_LastStatus = meta_event;
729 putByte(d->m_LastStatus);
730 putByte(sequence_number);
731 putByte(2);
732 putByte((seqnum >> 8) & 0xff);
733 putByte(seqnum & 0xff);
734}
735
741void QSmf::writeTempo(long deltaTime, long tempo)
742{
743 writeVarLen(deltaTime);
744 putByte(d->m_LastStatus = meta_event);
745 putByte(set_tempo);
746 putByte(3);
747 putByte((tempo >> 16) & 0xff);
748 putByte((tempo >> 8) & 0xff);
749 putByte(tempo & 0xff);
750}
751
757void QSmf::writeBpmTempo(long deltaTime, int tempo)
758{
759 long us_tempo = 60000000l / tempo;
760 writeTempo(deltaTime, us_tempo);
761}
762
771void QSmf::writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
772{
773 writeVarLen(deltaTime);
774 putByte(d->m_LastStatus = meta_event);
775 putByte(time_signature);
776 putByte(4);
777 putByte(num & 0xff);
778 putByte(den & 0xff);
779 putByte(cc & 0xff);
780 putByte(bb & 0xff);
781}
782
789void QSmf::writeKeySignature(long deltaTime, int tone, int mode)
790{
791 writeVarLen(quint64(deltaTime));
792 putByte(d->m_LastStatus = meta_event);
793 putByte(key_signature);
794 putByte(2);
795 putByte(quint8(tone));
796 putByte(mode & 0x01);
797}
798
803void QSmf::writeVarLen(quint64 value)
804{
805 quint64 buffer;
806
807 buffer = value & 0x7f;
808 while ((value >>= 7) > 0)
809 {
810 buffer <<= 8;
811 buffer |= 0x80;
812 buffer += (value & 0x7f);
813 }
814 while (true)
815 {
816 putByte(buffer & 0xff);
817 if (buffer & 0x80)
818 buffer >>= 8;
819 else
820 break;
821 }
822}
823
824/* These routines are used to make sure that the byte order of
825 the various data types remains constant between machines. */
826void QSmf::write32bit(quint32 data)
827{
828 putByte((data >> 24) & 0xff);
829 putByte((data >> 16) & 0xff);
830 putByte((data >> 8) & 0xff);
831 putByte(data & 0xff);
832}
833
834void QSmf::write16bit(quint16 data)
835{
836 putByte((data >> 8) & 0xff);
837 putByte(data & 0xff);
838}
839
840quint16 QSmf::to16bit(quint8 c1, quint8 c2)
841{
842 quint16 value;
843 value = quint16(c1 << 8);
844 value += c2;
845 return value;
846}
847
848quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
849{
850 quint32 value;
851 value = unsigned(c1 << 24);
852 value += unsigned(c2 << 16);
853 value += unsigned(c3 << 8);
854 value += c4;
855 return value;
856}
857
858quint16 QSmf::read16bit()
859{
860 quint8 c1, c2;
861 c1 = getByte();
862 c2 = getByte();
863 return to16bit(c1, c2);
864}
865
866quint32 QSmf::read32bit()
867{
868 quint8 c1, c2, c3, c4;
869 c1 = getByte();
870 c2 = getByte();
871 c3 = getByte();
872 c4 = getByte();
873 return to32bit(c1, c2, c3, c4);
874}
875
876long QSmf::readVarLen()
877{
878 quint64 value;
879 quint8 c;
880
881 c = getByte();
882 value = c;
883 if ((c & 0x80) != 0)
884 {
885 value &= 0x7f;
886 do
887 {
888 c = getByte();
889 value = (value << 7) + (c & 0x7f);
890 } while ((c & 0x80) != 0);
891 }
892 return long(value);
893}
894
895void QSmf::readExpected(const QString& s)
896{
897 int j;
898 quint8 b;
899 for (j = 0; j < s.length(); ++j)
900 {
901 b = getByte();
902 if (QChar(b) != s[j])
903 {
904 SMFError(QString("Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
905 break;
906 }
907 }
908}
909
910quint64 QSmf::findTempo()
911{
912 quint64 result, old_tempo, new_tempo;
913 QSmfRecTempo rec = d->m_TempoList.last();
914 old_tempo = d->m_CurrTempo;
915 new_tempo = d->m_CurrTempo;
916 QList<QSmfRecTempo>::Iterator it;
917 for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
918 {
919 rec = (*it);
920 if (rec.time <= d->m_CurrTime)
921 {
922 old_tempo = rec.tempo;
923 }
924 new_tempo = rec.tempo;
925 if (rec.time > d->m_RevisedTime)
926 {
927 break;
928 }
929 }
930 if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
931 {
932 d->m_RevisedTime = d->m_CurrTime;
933 result = old_tempo;
934 }
935 else
936 {
937 d->m_RevisedTime = rec.time;
938 d->m_TempoChangeTime = d->m_RevisedTime;
939 result = new_tempo;
940 }
941 return result;
942}
943
944/* This routine converts delta times in ticks into seconds. The
945 else statement is needed because the formula is different for tracks
946 based on notes and tracks based on SMPTE times. */
947double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
948{
949 double result;
950 double smpte_format;
951 double smpte_resolution;
952
953 if (division > 0)
954 {
955 result = double(ticks * tempo)/(division * 1000000.0);
956 }
957 else
958 {
959 smpte_format = upperByte(division);
960 smpte_resolution = lowerByte(division);
961 result = double(ticks)/(smpte_format * smpte_resolution
962 * 1000000.0);
963 }
964 return result;
965}
966
967void QSmf::SMFError(const QString& s)
968{
969 emit signalSMFError(s);
970}
971
972void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
973{
974 quint8 chan;
975 int k;
976 chan = status & midi_channel_mask;
977 if (c1 > 127)
978 {
979 SMFError(QString("ChannelMessage with bad c1 = %1").arg(c1));
980 //c1 &= 127;
981 }
982 if (c2 > 127)
983 {
984 SMFError(QString("ChannelMessage with bad c2 = %1").arg(c2));
985 //c2 &= 127;
986 }
987 switch (status & midi_command_mask)
988 {
989 case note_off:
990 emit signalSMFNoteOff(chan, c1, c2);
991 break;
992 case note_on:
993 emit signalSMFNoteOn(chan, c1, c2);
994 break;
995 case poly_aftertouch:
996 emit signalSMFKeyPress(chan, c1, c2);
997 break;
998 case control_change:
999 emit signalSMFCtlChange(chan, c1, c2);
1000 break;
1001 case program_chng:
1002 emit signalSMFProgram(chan, c1);
1003 break;
1004 case channel_aftertouch:
1005 emit signalSMFChanPress(chan, c1);
1006 break;
1007 case pitch_wheel:
1008 k = c1 + (c2 << 7) - 8192;
1009 emit signalSMFPitchBend(chan, k);
1010 break;
1011 default:
1012 SMFError(QString("Invalid MIDI status %1. Unhandled event").arg(status));
1013 break;
1014 }
1015}
1016
1017void QSmf::metaEvent(quint8 b)
1018{
1019 QSmfRecTempo rec;
1020 QByteArray m(d->m_MsgBuff);
1021
1022 switch (b)
1023 {
1024 case sequence_number:
1025 emit signalSMFSequenceNum(to16bit(m[0], m[1]));
1026 break;
1027 case text_event:
1028 case copyright_notice:
1029 case sequence_name:
1030 case instrument_name:
1031 case lyric:
1032 case marker:
1033 case cue_point: {
1034 QString s;
1035 if (d->m_codec == nullptr)
1036 s = QString(m);
1037 else
1038 s = d->m_codec->toUnicode(m);
1039 emit signalSMFText(b, s);
1040 }
1041 break;
1042 case forced_channel:
1043 emit signalSMFforcedChannel(m[0]);
1044 break;
1045 case forced_port:
1046 emit signalSMFforcedPort(m[0]);
1047 break;
1048 case end_of_track:
1049 emit signalSMFendOfTrack();
1050 break;
1051 case set_tempo:
1052 d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
1053 emit signalSMFTempo(d->m_CurrTempo);
1054 rec = d->m_TempoList.last();
1055 if (rec.tempo == d->m_CurrTempo)
1056 {
1057 return;
1058 }
1059 if (rec.time > d->m_CurrTime)
1060 {
1061 return;
1062 }
1063 addTempo(d->m_CurrTempo, d->m_CurrTime);
1064 break;
1065 case smpte_offset:
1066 emit signalSMFSmpte(m[0], m[1], m[2], m[3], m[4]);
1067 break;
1068 case time_signature:
1069 emit signalSMFTimeSig(m[0], m[1], m[2], m[3]);
1070 break;
1071 case key_signature:
1072 emit signalSMFKeySig(m[0], m[1]);
1073 break;
1074 case sequencer_specific:
1075 emit signalSMFSeqSpecific(m);
1076 break;
1077 default:
1078 emit signalSMFMetaUnregistered(b, m);
1079 break;
1080 }
1081 emit signalSMFMetaMisc(b, m);
1082}
1083
1084void QSmf::sysEx()
1085{
1086 QByteArray varr(d->m_MsgBuff);
1087 emit signalSMFSysex(varr);
1088}
1089
1090void QSmf::badByte(quint8 b, int p)
1091{
1092 SMFError(QString("Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1093}
1094
1095quint8 QSmf::lowerByte(quint16 x)
1096{
1097 return (x & 0xff);
1098}
1099
1100quint8 QSmf::upperByte(quint16 x)
1101{
1102 return ((x >> 8) & 0xff);
1103}
1104
1105void QSmf::msgInit()
1106{
1107 d->m_MsgBuff.truncate(0);
1108}
1109
1110void QSmf::msgAdd(quint8 b)
1111{
1112 int s = d->m_MsgBuff.size();
1113 d->m_MsgBuff.resize(s + 1);
1114 d->m_MsgBuff[s] = b;
1115}
1116
1117/* public properties (accessors) */
1118
1124{
1125 return d->m_CurrTime;
1126}
1127
1133{
1134 return d->m_CurrTempo;
1135}
1136
1142{
1143 return d->m_RealTime;
1144}
1145
1151{
1152 return d->m_Division;
1153}
1154
1159void QSmf::setDivision(int division)
1160{
1161 d->m_Division = division;
1162}
1163
1169{
1170 return d->m_Tracks;
1171}
1172
1177void QSmf::setTracks(int tracks)
1178{
1179 d->m_Tracks = tracks;
1180}
1181
1187{
1188 return d->m_fileFormat;
1189}
1190
1195void QSmf::setFileFormat(int fileFormat)
1196{
1197 d->m_fileFormat = fileFormat;
1198}
1199
1205{
1206 return long(d->m_IOStream->device()->pos());
1207}
1208
1215{
1216 return d->m_codec;
1217}
1218
1226void QSmf::setTextCodec(QTextCodec *codec)
1227{
1228 d->m_codec = codec;
1229}
1230
1231} // namespace File
1232} // namespace drumstick
The QObject class is the base class of all Qt objects.
int getTracks()
Gets the number of tracks.
Definition qsmf.cpp:1168
void signalSMFKeyPress(int chan, int pitch, int press)
Emitted after reading a Polyphonic Aftertouch message.
void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
Definition qsmf.cpp:1226
long getRealTime()
Gets the real time in seconds.
Definition qsmf.cpp:1141
long getCurrentTempo()
Gets the current tempo.
Definition qsmf.cpp:1132
void signalSMFforcedChannel(int channel)
Emitted after reading a Forced channel message.
void setDivision(int division)
Sets the resolution.
Definition qsmf.cpp:1159
long getFilePos()
Gets the position in the SMF stream.
Definition qsmf.cpp:1204
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 signalSMFText(int typ, const QString &data)
Emitted after reading a SMF text 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:1123
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:1177
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
Writes a Time Signature message.
Definition qsmf.cpp:771
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.
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:1150
QSmf(QObject *parent=nullptr)
Constructor.
Definition qsmf.cpp:100
void writeToFile(const QString &fileName)
Writes a SMF stream to a disk file.
Definition qsmf.cpp:466
void signalSMFSeqSpecific(const QByteArray &data)
Emitted after reading a Sequencer specific message.
void signalSMFWriteTempoTrack()
Emitted to request the user to write 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:725
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:433
void signalSMFProgram(int chan, int patch)
Emitted after reading a Program change 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:525
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.
QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
Definition qsmf.cpp:1214
virtual ~QSmf()
Destructor.
Definition qsmf.cpp:108
void writeBpmTempo(long deltaTime, int tempo)
Writes a Tempo change message.
Definition qsmf.cpp:757
void readFromFile(const QString &fileName)
Reads a SMF stream from a disk file.
Definition qsmf.cpp:443
void signalSMFSysex(const QByteArray &data)
Emitted after reading a System Exclusive message.
void writeToStream(QDataStream *stream)
Writes a SMF stream.
Definition qsmf.cpp:456
void writeTempo(long deltaTime, long tempo)
Writes a Tempo change message.
Definition qsmf.cpp:741
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:789
void setFileFormat(int fileFormat)
Sets the SMF file format.
Definition qsmf.cpp:1195
void signalSMFPitchBend(int chan, int value)
Emitted after reading a Bender message.
int getFileFormat()
Gets the SMF file format.
Definition qsmf.cpp:1186
void writeMidiEvent(long deltaTime, int type, int chan, int b1)
Writes a MIDI message with a single parameter.
Definition qsmf.cpp:638
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:59
const quint8 system_exclusive
MIDI event System Exclusive begin.
Definition qsmf.h:77
const quint8 sequencer_specific
SMF Sequencer specific.
Definition qsmf.h:67
const quint32 MTrk
SMF Track prefix.
Definition qsmf.h:48
const quint8 forced_channel
SMF Forced MIDI channel.
Definition qsmf.h:60
const quint8 midi_channel_mask
Mask to extract the channel from the status byte.
Definition qsmf.h:81
const quint8 note_on
MIDI event Note On.
Definition qsmf.h:71
const quint8 control_change
MIDI event Control change.
Definition qsmf.h:73
const quint8 note_off
MIDI event Note Off.
Definition qsmf.h:70
const quint8 smpte_offset
SMF SMPTE offset.
Definition qsmf.h:64
const quint8 sequence_number
SMF Sequence number.
Definition qsmf.h:52
const quint8 sequence_name
SMF Sequence name.
Definition qsmf.h:55
const quint8 pitch_wheel
MIDI event Bender.
Definition qsmf.h:76
const quint8 meta_event
SMF Meta Event prefix.
Definition qsmf.h:51
const quint8 time_signature
SMF Time signature.
Definition qsmf.h:65
const quint8 end_of_track
SMF End of track.
Definition qsmf.h:62
const quint32 MThd
SMF Header prefix.
Definition qsmf.h:47
const quint8 poly_aftertouch
MIDI event Polyphonic pressure.
Definition qsmf.h:72
const quint8 key_signature
SMF Key signature.
Definition qsmf.h:66
const quint8 text_event
SMF Text event.
Definition qsmf.h:53
const quint8 channel_aftertouch
MIDI event Channel after-touch.
Definition qsmf.h:75
const quint8 instrument_name
SMF Instrument name.
Definition qsmf.h:56
const quint8 marker
SMF Marker.
Definition qsmf.h:58
const quint8 forced_port
SMF Forced MIDI port.
Definition qsmf.h:61
const quint8 copyright_notice
SMF Copyright notice.
Definition qsmf.h:54
const quint8 program_chng
MIDI event Program change.
Definition qsmf.h:74
const quint8 midi_command_mask
Mask to extract the command from the status byte.
Definition qsmf.h:80
const quint8 end_of_sysex
MIDI event System Exclusive end.
Definition qsmf.h:78
const quint8 lyric
SMF Lyric.
Definition qsmf.h:57
const quint8 set_tempo
SMF Tempo change.
Definition qsmf.h:63
Drumstick File library.
Definition qsmf.cpp:35
Drumstick common.
Standard MIDI Files Input/Output.