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