drumstick 2.3.1
qsmf.cpp
Go to the documentation of this file.
1/*
2 Standard MIDI File component
3 Copyright (C) 2006-2021, 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
34namespace drumstick {
35namespace File {
36
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 unsigned int i, j, size;
597 quint8 c;
598 writeVarLen(quint64(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 c = quint8(data[0]);
618 if (type == system_exclusive || type == end_of_sysex)
619 {
620 size = data.size();
621 if (type == c)
622 --size;
623 writeVarLen(size);
624 }
625 j = (c == type ? 1 : 0);
626 for (i = j; i < unsigned(data.size()); ++i)
627 {
628 putByte(quint8(data[i]));
629 }
630}
631
639void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1)
640{
641 quint8 c;
642 writeVarLen(deltaTime);
643 if ((type == system_exclusive) || (type == end_of_sysex))
644 {
645 SMFError("error: Wrong method for a system exclusive event");
646 }
647 if (chan > 15)
648 {
649 SMFError("error: MIDI channel greater than 16");
650 }
651 c = type | chan;
652 if (d->m_LastStatus != c)
653 {
654 d->m_LastStatus = c;
655 putByte(c);
656 }
657 putByte(b1);
658}
659
668void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1, int b2)
669{
670 quint8 c;
671 writeVarLen(deltaTime);
672 if ((type == system_exclusive) || (type == end_of_sysex))
673 {
674 SMFError("error: Wrong method for a system exclusive event");
675 }
676 if (chan > 15)
677 {
678 SMFError("error: MIDI channel greater than 16");
679 }
680 c = type | chan;
681 if (d->m_LastStatus != c)
682 {
683 d->m_LastStatus = c;
684 putByte(c);
685 }
686 putByte(b1);
687 putByte(b2);
688}
689
697void QSmf::writeMidiEvent(long deltaTime, int type, long len, char* data)
698{
699 unsigned int i, j, size;
700 quint8 c;
701 writeVarLen(quint64(deltaTime));
702 if ((type != system_exclusive) && (type != end_of_sysex))
703 {
704 SMFError("error: type should be system exclusive");
705 }
706 d->m_LastStatus = 0;
707 c = quint8(type);
708 putByte(c);
709 size = unsigned(len);
710 c = quint8(data[0]);
711 if (c == type)
712 --size;
713 writeVarLen(size);
714 j = (c == type ? 1 : 0);
715 for (i = j; i < unsigned(len); ++i)
716 {
717 putByte(quint8(data[i]));
718 }
719}
720
726void QSmf::writeSequenceNumber(long deltaTime, int seqnum)
727{
728 writeVarLen(deltaTime);
729 d->m_LastStatus = meta_event;
730 putByte(d->m_LastStatus);
731 putByte(sequence_number);
732 putByte(2);
733 putByte((seqnum >> 8) & 0xff);
734 putByte(seqnum & 0xff);
735}
736
742void QSmf::writeTempo(long deltaTime, long tempo)
743{
744 writeVarLen(deltaTime);
745 putByte(d->m_LastStatus = meta_event);
746 putByte(set_tempo);
747 putByte(3);
748 putByte((tempo >> 16) & 0xff);
749 putByte((tempo >> 8) & 0xff);
750 putByte(tempo & 0xff);
751}
752
758void QSmf::writeBpmTempo(long deltaTime, int tempo)
759{
760 long us_tempo = 60000000l / tempo;
761 writeTempo(deltaTime, us_tempo);
762}
763
772void QSmf::writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
773{
774 writeVarLen(deltaTime);
775 putByte(d->m_LastStatus = meta_event);
776 putByte(time_signature);
777 putByte(4);
778 putByte(num & 0xff);
779 putByte(den & 0xff);
780 putByte(cc & 0xff);
781 putByte(bb & 0xff);
782}
783
790void QSmf::writeKeySignature(long deltaTime, int tone, int mode)
791{
792 writeVarLen(quint64(deltaTime));
793 putByte(d->m_LastStatus = meta_event);
794 putByte(key_signature);
795 putByte(2);
796 putByte(quint8(tone));
797 putByte(mode & 0x01);
798}
799
804void QSmf::writeVarLen(quint64 value)
805{
806 quint64 buffer;
807
808 buffer = value & 0x7f;
809 while ((value >>= 7) > 0)
810 {
811 buffer <<= 8;
812 buffer |= 0x80;
813 buffer += (value & 0x7f);
814 }
815 while (true)
816 {
817 putByte(buffer & 0xff);
818 if (buffer & 0x80)
819 buffer >>= 8;
820 else
821 break;
822 }
823}
824
825/* These routines are used to make sure that the byte order of
826 the various data types remains constant between machines. */
827void QSmf::write32bit(quint32 data)
828{
829 putByte((data >> 24) & 0xff);
830 putByte((data >> 16) & 0xff);
831 putByte((data >> 8) & 0xff);
832 putByte(data & 0xff);
833}
834
835void QSmf::write16bit(quint16 data)
836{
837 putByte((data >> 8) & 0xff);
838 putByte(data & 0xff);
839}
840
841quint16 QSmf::to16bit(quint8 c1, quint8 c2)
842{
843 quint16 value;
844 value = quint16(c1 << 8);
845 value += c2;
846 return value;
847}
848
849quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
850{
851 quint32 value;
852 value = unsigned(c1 << 24);
853 value += unsigned(c2 << 16);
854 value += unsigned(c3 << 8);
855 value += c4;
856 return value;
857}
858
859quint16 QSmf::read16bit()
860{
861 quint8 c1, c2;
862 c1 = getByte();
863 c2 = getByte();
864 return to16bit(c1, c2);
865}
866
867quint32 QSmf::read32bit()
868{
869 quint8 c1, c2, c3, c4;
870 c1 = getByte();
871 c2 = getByte();
872 c3 = getByte();
873 c4 = getByte();
874 return to32bit(c1, c2, c3, c4);
875}
876
877long QSmf::readVarLen()
878{
879 quint64 value;
880 quint8 c;
881
882 c = getByte();
883 value = c;
884 if ((c & 0x80) != 0)
885 {
886 value &= 0x7f;
887 do
888 {
889 c = getByte();
890 value = (value << 7) + (c & 0x7f);
891 } while ((c & 0x80) != 0);
892 }
893 return long(value);
894}
895
896void QSmf::readExpected(const QString& s)
897{
898 int j;
899 quint8 b;
900 for (j = 0; j < s.length(); ++j)
901 {
902 b = getByte();
903 if (QChar(b) != s[j])
904 {
905 SMFError(QString("Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
906 break;
907 }
908 }
909}
910
911quint64 QSmf::findTempo()
912{
913 quint64 result, old_tempo, new_tempo;
914 QSmfRecTempo rec = d->m_TempoList.last();
915 old_tempo = d->m_CurrTempo;
916 new_tempo = d->m_CurrTempo;
917 QList<QSmfRecTempo>::Iterator it;
918 for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
919 {
920 rec = (*it);
921 if (rec.time <= d->m_CurrTime)
922 {
923 old_tempo = rec.tempo;
924 }
925 new_tempo = rec.tempo;
926 if (rec.time > d->m_RevisedTime)
927 {
928 break;
929 }
930 }
931 if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
932 {
933 d->m_RevisedTime = d->m_CurrTime;
934 result = old_tempo;
935 }
936 else
937 {
938 d->m_RevisedTime = rec.time;
939 d->m_TempoChangeTime = d->m_RevisedTime;
940 result = new_tempo;
941 }
942 return result;
943}
944
945/* This routine converts delta times in ticks into seconds. The
946 else statement is needed because the formula is different for tracks
947 based on notes and tracks based on SMPTE times. */
948double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
949{
950 double result;
951 double smpte_format;
952 double smpte_resolution;
953
954 if (division > 0)
955 {
956 result = double(ticks * tempo)/(division * 1000000.0);
957 }
958 else
959 {
960 smpte_format = upperByte(division);
961 smpte_resolution = lowerByte(division);
962 result = double(ticks)/(smpte_format * smpte_resolution
963 * 1000000.0);
964 }
965 return result;
966}
967
968void QSmf::SMFError(const QString& s)
969{
970 emit signalSMFError(s);
971}
972
973void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
974{
975 quint8 chan;
976 int k;
977 chan = status & midi_channel_mask;
978 if (c1 > 127)
979 {
980 SMFError(QString("ChannelMessage with bad c1 = %1").arg(c1));
981 //c1 &= 127;
982 }
983 if (c2 > 127)
984 {
985 SMFError(QString("ChannelMessage with bad c2 = %1").arg(c2));
986 //c2 &= 127;
987 }
988 switch (status & midi_command_mask)
989 {
990 case note_off:
991 emit signalSMFNoteOff(chan, c1, c2);
992 break;
993 case note_on:
994 emit signalSMFNoteOn(chan, c1, c2);
995 break;
996 case poly_aftertouch:
997 emit signalSMFKeyPress(chan, c1, c2);
998 break;
999 case control_change:
1000 emit signalSMFCtlChange(chan, c1, c2);
1001 break;
1002 case program_chng:
1003 emit signalSMFProgram(chan, c1);
1004 break;
1005 case channel_aftertouch:
1006 emit signalSMFChanPress(chan, c1);
1007 break;
1008 case pitch_wheel:
1009 k = c1 + (c2 << 7) - 8192;
1010 emit signalSMFPitchBend(chan, k);
1011 break;
1012 default:
1013 SMFError(QString("Invalid MIDI status %1. Unhandled event").arg(status));
1014 break;
1015 }
1016}
1017
1018void QSmf::metaEvent(quint8 b)
1019{
1020 QSmfRecTempo rec;
1021 QByteArray m(d->m_MsgBuff);
1022
1023 switch (b)
1024 {
1025 case sequence_number:
1026 emit signalSMFSequenceNum(to16bit(m[0], m[1]));
1027 break;
1028 case text_event:
1029 case copyright_notice:
1030 case sequence_name:
1031 case instrument_name:
1032 case lyric:
1033 case marker:
1034 case cue_point: {
1035 QString s;
1036 if (d->m_codec == nullptr)
1037 s = QString::fromLatin1(m);
1038 else
1039 s = d->m_codec->toUnicode(m);
1040 emit signalSMFText(b, s);
1041 }
1042 break;
1043 case forced_channel:
1044 emit signalSMFforcedChannel(m[0]);
1045 break;
1046 case forced_port:
1047 emit signalSMFforcedPort(m[0]);
1048 break;
1049 case end_of_track:
1050 emit signalSMFendOfTrack();
1051 break;
1052 case set_tempo:
1053 d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
1054 emit signalSMFTempo(d->m_CurrTempo);
1055 rec = d->m_TempoList.last();
1056 if (rec.tempo == d->m_CurrTempo)
1057 {
1058 return;
1059 }
1060 if (rec.time > d->m_CurrTime)
1061 {
1062 return;
1063 }
1064 addTempo(d->m_CurrTempo, d->m_CurrTime);
1065 break;
1066 case smpte_offset:
1067 emit signalSMFSmpte(m[0], m[1], m[2], m[3], m[4]);
1068 break;
1069 case time_signature:
1070 emit signalSMFTimeSig(m[0], m[1], m[2], m[3]);
1071 break;
1072 case key_signature:
1073 emit signalSMFKeySig(m[0], m[1]);
1074 break;
1075 case sequencer_specific:
1076 emit signalSMFSeqSpecific(m);
1077 break;
1078 default:
1079 emit signalSMFMetaUnregistered(b, m);
1080 break;
1081 }
1082 emit signalSMFMetaMisc(b, m);
1083}
1084
1085void QSmf::sysEx()
1086{
1087 QByteArray varr(d->m_MsgBuff);
1088 emit signalSMFSysex(varr);
1089}
1090
1091void QSmf::badByte(quint8 b, int p)
1092{
1093 SMFError(QString("Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1094}
1095
1096quint8 QSmf::lowerByte(quint16 x)
1097{
1098 return (x & 0xff);
1099}
1100
1101quint8 QSmf::upperByte(quint16 x)
1102{
1103 return ((x >> 8) & 0xff);
1104}
1105
1106void QSmf::msgInit()
1107{
1108 d->m_MsgBuff.truncate(0);
1109}
1110
1111void QSmf::msgAdd(quint8 b)
1112{
1113 int s = d->m_MsgBuff.size();
1114 d->m_MsgBuff.resize(s + 1);
1115 d->m_MsgBuff[s] = b;
1116}
1117
1118/* public properties (accessors) */
1119
1125{
1126 return d->m_CurrTime;
1127}
1128
1134{
1135 return d->m_CurrTempo;
1136}
1137
1143{
1144 return d->m_RealTime;
1145}
1146
1152{
1153 return d->m_Division;
1154}
1155
1160void QSmf::setDivision(int division)
1161{
1162 d->m_Division = division;
1163}
1164
1170{
1171 return d->m_Tracks;
1172}
1173
1178void QSmf::setTracks(int tracks)
1179{
1180 d->m_Tracks = tracks;
1181}
1182
1188{
1189 return d->m_fileFormat;
1190}
1191
1196void QSmf::setFileFormat(int fileFormat)
1197{
1198 d->m_fileFormat = fileFormat;
1199}
1200
1206{
1207 return long(d->m_IOStream->device()->pos());
1208}
1209
1216{
1217 return d->m_codec;
1218}
1219
1227void QSmf::setTextCodec(QTextCodec *codec)
1228{
1229 d->m_codec = codec;
1230}
1231
1232} // namespace File
1233} // namespace drumstick
The QObject class is the base class of all Qt objects.
int getTracks()
Gets the number of tracks.
Definition: qsmf.cpp:1169
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:1227
long getRealTime()
Gets the real time in seconds.
Definition: qsmf.cpp:1142
long getCurrentTempo()
Gets the current tempo.
Definition: qsmf.cpp:1133
void signalSMFforcedChannel(int channel)
Emitted after reading a Forced channel message.
void setDivision(int division)
Sets the resolution.
Definition: qsmf.cpp:1160
long getFilePos()
Gets the position in the SMF stream.
Definition: qsmf.cpp:1205
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:1124
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:1178
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
Writes a Time Signature message.
Definition: qsmf.cpp:772
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:1151
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 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:726
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:1215
virtual ~QSmf()
Destructor.
Definition: qsmf.cpp:108
void writeBpmTempo(long deltaTime, int tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:758
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:742
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:790
void setFileFormat(int fileFormat)
Sets the SMF file format.
Definition: qsmf.cpp:1196
void signalSMFPitchBend(int chan, int value)
Emitted after reading a Bender message.
int getFileFormat()
Gets the SMF file format.
Definition: qsmf.cpp:1187
void writeMidiEvent(long deltaTime, int type, int chan, int b1)
Writes a MIDI message with a single parameter.
Definition: qsmf.cpp:639
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
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.