drumstick 0.5.0
qsmf.cpp
Go to the documentation of this file.
1/*
2 Standard MIDI File component
3 Copyright (C) 2006-2010, 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 along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20*/
21
22#include "qsmf.h"
23#include <limits>
24#include <QList>
25#include <QFile>
26#include <QDataStream>
27#include <QTextCodec>
28
34namespace drumstick {
35
48class QSmf::QSmfPrivate {
49public:
50 QSmfPrivate():
51 m_Interactive(false),
52 m_CurrTime(0),
53 m_RealTime(0),
54 m_DblRealTime(0),
55 m_DblOldRealtime(0),
56 m_Division(96),
57 m_CurrTempo(500000),
58 m_OldCurrTempo(500000),
59 m_OldRealTime(0),
60 m_OldCurrTime(0),
61 m_RevisedTime(0),
62 m_TempoChangeTime(0),
63 m_ToBeRead(0),
64 m_NumBytesWritten(0),
65 m_Tracks(0),
66 m_fileFormat(0),
67 m_LastStatus(0),
68 m_codec(0),
69 m_IOStream(0)
70 { }
71
72 bool m_Interactive;
73 quint64 m_CurrTime;
74 quint64 m_RealTime;
75 double m_DblRealTime;
76 double m_DblOldRealtime;
77 int m_Division;
78 quint64 m_CurrTempo;
79 quint64 m_OldCurrTempo;
80 quint64 m_OldRealTime;
81 quint64 m_OldCurrTime;
82 quint64 m_RevisedTime;
83 quint64 m_TempoChangeTime;
84 quint64 m_ToBeRead;
85 quint64 m_NumBytesWritten;
86 int m_Tracks;
87 int m_fileFormat;
88 int m_LastStatus;
89 QTextCodec *m_codec;
90 QDataStream *m_IOStream;
91 QByteArray m_MsgBuff;
92 QList<QSmfRecTempo> m_TempoList;
93};
94
100 QObject(parent),
101 d(new QSmfPrivate)
102{ }
103
108{
109 d->m_TempoList.clear();
110 delete d;
111}
112
117bool QSmf::endOfSmf()
118{
119 return d->m_IOStream->atEnd();
120}
121
126quint8 QSmf::getByte()
127{
128 quint8 b = 0;
129 if (!d->m_IOStream->atEnd())
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}
193
197void QSmf::readTrack()
198{
199 /* This array is indexed by the high half of a status byte. It's
200 value is either the number of bytes needed (1 or 2) for a channel
201 message, or 0 (meaning it's not a channel message). */
202 static const quint8 chantype[16] =
203 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 };
204
205 quint64 lookfor;
206 quint8 c, c1, type;
207 bool sysexcontinue; // 1 if last message was an unfinished SysEx
208 bool running; // 1 when running status used
209 quint8 status; // status value (e.g. 0x90==note-on)
210 int needed;
211 double delta_secs;
212 quint64 delta_ticks, save_time, save_tempo;
213
214 sysexcontinue = false;
215 status = 0;
216 if (d->m_Interactive)
217 {
218 d->m_ToBeRead = std::numeric_limits<unsigned long long>::max();
219 }
220 else
221 {
222 readExpected("MTrk");
223 d->m_ToBeRead = read32bit();
224 }
225 d->m_CurrTime = 0;
226 d->m_RealTime = 0;
227 d->m_DblRealTime = 0;
228 d->m_DblOldRealtime = 0;
229 d->m_OldCurrTime = 0;
230 d->m_OldRealTime = 0;
231 d->m_CurrTempo = findTempo();
232
233 emit signalSMFTrackStart();
234
235 while (!endOfSmf() && (d->m_Interactive || d->m_ToBeRead > 0))
236 {
237 if (d->m_Interactive)
238 {
239 d->m_CurrTime++;
240 }
241 else
242 {
243 delta_ticks = readVarLen();
244 d->m_RevisedTime = d->m_CurrTime;
245 d->m_CurrTime += delta_ticks;
246 while (d->m_RevisedTime < d->m_CurrTime)
247 {
248 save_time = d->m_RevisedTime;
249 save_tempo = d->m_CurrTempo;
250 d->m_CurrTempo = findTempo();
251 if (d->m_CurrTempo != d->m_OldCurrTempo)
252 {
253 d->m_OldCurrTempo = d->m_CurrTempo;
254 d->m_OldRealTime = d->m_RealTime;
255 if (d->m_RevisedTime != d->m_TempoChangeTime)
256 {
257 d->m_DblOldRealtime = d->m_DblRealTime;
258 d->m_OldCurrTime = save_time;
259 }
260 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
261 d->m_Division, save_tempo);
262 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
263 d->m_RealTime = static_cast<quint64>(0.5 + d->m_DblRealTime);
264 if (d->m_RevisedTime == d->m_TempoChangeTime)
265 {
266 d->m_OldCurrTime = d->m_RevisedTime;
267 d->m_DblOldRealtime = d->m_DblRealTime;
268 }
269 }
270 else
271 {
272 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
273 d->m_Division, d->m_CurrTempo);
274 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
275 d->m_RealTime = static_cast<quint64>(0.5 + d->m_DblRealTime);
276 }
277 }
278 }
279
280 c = getByte();
281 if (sysexcontinue && (c != end_of_sysex))
282 {
283 SMFError("didn't find expected continuation of a SysEx");
284 }
285 if (c < 0xf8)
286 {
287 if ((c & 0x80) == 0)
288 {
289 if (status == 0)
290 {
291 SMFError("unexpected running status");
292 }
293 running = true;
294 }
295 else
296 {
297 status = c;
298 running = false;
299 }
300 needed = chantype[status >> 4 & 0x0f];
301 if (needed != 0)
302 {
303 if (running)
304 {
305 c1 = c;
306 }
307 else
308 {
309 c1 = getByte();
310 }
311 if (needed > 1)
312 {
313 channelMessage(status, c1, getByte());
314 }
315 else
316 {
317 channelMessage(status, c1, 0);
318 }
319 continue;
320 }
321 }
322
323 switch (c)
324 {
325 case meta_event:
326 type = getByte();
327 lookfor = readVarLen();
328 lookfor = d->m_ToBeRead - lookfor;
329 msgInit();
330 while (d->m_ToBeRead > lookfor)
331 {
332 msgAdd(getByte());
333 }
334 metaEvent(type);
335 break;
336 case system_exclusive:
337 lookfor = readVarLen();
338 lookfor = d->m_ToBeRead - lookfor;
339 msgInit();
340 msgAdd(system_exclusive);
341 while (d->m_ToBeRead > lookfor)
342 {
343 c = getByte();
344 msgAdd(c);
345 }
346 if (c == end_of_sysex)
347 {
348 sysEx();
349 }
350 else
351 {
352 sysexcontinue = true;
353 }
354 break;
355 case end_of_sysex:
356 lookfor = readVarLen();
357 lookfor = d->m_ToBeRead - lookfor;
358 if (!sysexcontinue)
359 {
360 msgInit();
361 }
362 while (d->m_ToBeRead > lookfor)
363 {
364 c = getByte();
365 msgAdd(c);
366 }
367 if (sysexcontinue)
368 {
369 if (c == end_of_sysex)
370 {
371 sysEx();
372 sysexcontinue = false;
373 }
374 }
375 break;
376 default:
377 badByte(c, d->m_IOStream->device()->pos() - 1);
378 break;
379 }
380 }
381 emit signalSMFTrackEnd();
382}
383
387void QSmf::SMFRead()
388{
389 int i;
390 readHeader();
391 for ( i = d->m_Tracks; (i > 0) && !endOfSmf(); i--)
392 {
393 readTrack();
394 }
395}
396
404void QSmf::SMFWrite()
405{
406 int i;
407 d->m_LastStatus = 0;
408 writeHeaderChunk(d->m_fileFormat, d->m_Tracks, d->m_Division);
409 d->m_LastStatus = 0;
410 if (d->m_fileFormat == 1)
411 {
413 }
414 for (i = 0; i < d->m_Tracks; ++i)
415 {
416 writeTrackChunk(i);
417 }
418}
419
424void QSmf::readFromStream(QDataStream *stream)
425{
426 d->m_IOStream = stream;
427 SMFRead();
428}
429
434void QSmf::readFromFile(const QString& fileName)
435{
436 QFile file(fileName);
437 file.open(QIODevice::ReadOnly);
438 QDataStream ds(&file);
439 readFromStream(&ds);
440 file.close();
441}
442
447void QSmf::writeToStream(QDataStream *stream)
448{
449 d->m_IOStream = stream;
450 SMFWrite();
451}
452
457void QSmf::writeToFile(const QString& fileName)
458{
459 QFile file(fileName);
460 file.open(QIODevice::WriteOnly);
461 QDataStream ds(&file);
462 writeToStream(&ds);
463 file.close();
464}
465
472void QSmf::writeHeaderChunk(int format, int ntracks, int division)
473{
474 write32bit(MThd);
475 write32bit(6);
476 write16bit(format);
477 write16bit(ntracks);
478 write16bit(division);
479}
480
485void QSmf::writeTrackChunk(int track)
486{
487 quint32 trkhdr;
488 quint32 trklength;
489 qint64 offset;
490 qint64 place_marker;
491
492 d->m_LastStatus = 0;
493 trkhdr = MTrk;
494 trklength = 0;
495 offset = d->m_IOStream->device()->pos();
496 write32bit(trkhdr);
497 write32bit(trklength);
498 d->m_NumBytesWritten = 0;
499
500 emit signalSMFWriteTrack(track);
501
502 place_marker = d->m_IOStream->device()->pos();
503 d->m_IOStream->device()->seek(offset);
504 trklength = d->m_NumBytesWritten;
505 write32bit(trkhdr);
506 write32bit(trklength);
507 d->m_IOStream->device()->seek(place_marker);
508}
509
516void QSmf::writeMetaEvent(long deltaTime, int type, const QByteArray& data)
517{
518 writeVarLen(deltaTime);
519 d->m_LastStatus = meta_event;
520 putByte(d->m_LastStatus);
521 putByte(type);
522 writeVarLen(data.size());
523 foreach(char byte, data)
524 putByte(byte);
525}
526
533void QSmf::writeMetaEvent(long deltaTime, int type, const QString& data)
534{
535 writeVarLen(deltaTime);
536 putByte(d->m_LastStatus = meta_event);
537 putByte(type);
538 QByteArray lcldata;
539 if (d->m_codec == NULL)
540 lcldata = data.toLatin1();
541 else
542 lcldata = d->m_codec->fromUnicode(data);
543 writeVarLen(lcldata.length());
544 foreach(char byte, lcldata)
545 putByte(byte);
546}
547
555void QSmf::writeMetaEvent(long deltaTime, int type, int data)
556{
557 writeVarLen(deltaTime);
558 putByte(d->m_LastStatus = meta_event);
559 putByte(type);
560 putByte(1);
561 putByte(data);
562}
563
569void QSmf::writeMetaEvent(long deltaTime, int type)
570{
571 writeVarLen(deltaTime);
572 putByte(d->m_LastStatus = meta_event);
573 putByte(type);
574 putByte(0);
575}
576
584void QSmf::writeMidiEvent(long deltaTime, int type, int chan,
585 const QByteArray& data)
586{
587 int i, j, size;
588 quint8 c;
589 writeVarLen(deltaTime);
590 if ((type == system_exclusive) || (type == end_of_sysex))
591 {
592 c = type;
593 d->m_LastStatus = 0;
594 }
595 else
596 {
597 if (chan > 15)
598 {
599 SMFError("error: MIDI channel greater than 16");
600 }
601 c = type | chan;
602 }
603 if (d->m_LastStatus != c)
604 {
605 d->m_LastStatus = c;
606 putByte(c);
607 }
608 if (type == system_exclusive || type == end_of_sysex)
609 {
610 size = data.size();
611 if (data[0] == type)
612 --size;
613 writeVarLen(size);
614 }
615 j = (data[0] == type ? 1 : 0);
616 for (i = j; i < data.size(); ++i)
617 {
618 putByte(data[i]);
619 }
620}
621
629void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1)
630{
631 quint8 c;
632 writeVarLen(deltaTime);
633 if ((type == system_exclusive) || (type == end_of_sysex))
634 {
635 SMFError("error: Wrong method for a system exclusive event");
636 }
637 if (chan > 15)
638 {
639 SMFError("error: MIDI channel greater than 16");
640 }
641 c = type | chan;
642 if (d->m_LastStatus != c)
643 {
644 d->m_LastStatus = c;
645 putByte(c);
646 }
647 putByte(b1);
648}
649
658void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1, int b2)
659{
660 quint8 c;
661 writeVarLen(deltaTime);
662 if ((type == system_exclusive) || (type == end_of_sysex))
663 {
664 SMFError("error: Wrong method for a system exclusive event");
665 }
666 if (chan > 15)
667 {
668 SMFError("error: MIDI channel greater than 16");
669 }
670 c = type | chan;
671 if (d->m_LastStatus != c)
672 {
673 d->m_LastStatus = c;
674 putByte(c);
675 }
676 putByte(b1);
677 putByte(b2);
678}
679
687void QSmf::writeMidiEvent(long deltaTime, int type, long len, char* data)
688{
689 unsigned int i, j, size;
690 quint8 c;
691 writeVarLen(deltaTime);
692 if ((type != system_exclusive) && (type != end_of_sysex))
693 {
694 SMFError("error: type should be system exclusive");
695 }
696 d->m_LastStatus = 0;
697 c = type;
698 putByte(c);
699 size = len;
700 c = (unsigned)data[0];
701 if (c == type)
702 --size;
703 writeVarLen(size);
704 j = (c == type ? 1 : 0);
705 for (i = j; i < (unsigned)len; ++i)
706 {
707 putByte(data[i]);
708 }
709}
710
716void QSmf::writeSequenceNumber(long deltaTime, int seqnum)
717{
718 writeVarLen(deltaTime);
719 d->m_LastStatus = meta_event;
720 putByte(d->m_LastStatus);
721 putByte(sequence_number);
722 putByte(2);
723 putByte((seqnum >> 8) & 0xff);
724 putByte(seqnum & 0xff);
725}
726
732void QSmf::writeTempo(long deltaTime, long tempo)
733{
734 writeVarLen(deltaTime);
735 putByte(d->m_LastStatus = meta_event);
736 putByte(set_tempo);
737 putByte(3);
738 putByte((tempo >> 16) & 0xff);
739 putByte((tempo >> 8) & 0xff);
740 putByte(tempo & 0xff);
741}
742
748void QSmf::writeBpmTempo(long deltaTime, int tempo)
749{
750 long us_tempo = 60000000l / tempo;
751 writeTempo(deltaTime, us_tempo);
752}
753
762void QSmf::writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
763{
764 writeVarLen(deltaTime);
765 putByte(d->m_LastStatus = meta_event);
766 putByte(time_signature);
767 putByte(4);
768 putByte(num & 0xff);
769 putByte(den & 0xff);
770 putByte(cc & 0xff);
771 putByte(bb & 0xff);
772}
773
780void QSmf::writeKeySignature(long deltaTime, int tone, int mode)
781{
782 writeVarLen(deltaTime);
783 putByte(d->m_LastStatus = meta_event);
784 putByte(key_signature);
785 putByte(2);
786 putByte((char)tone);
787 putByte(mode & 0x01);
788}
789
794void QSmf::writeVarLen(quint64 value)
795{
796 quint64 buffer;
797
798 buffer = value & 0x7f;
799 while ((value >>= 7) > 0)
800 {
801 buffer <<= 8;
802 buffer |= 0x80;
803 buffer += (value & 0x7f);
804 }
805 while (true)
806 {
807 putByte(buffer & 0xff);
808 if (buffer & 0x80)
809 buffer >>= 8;
810 else
811 break;
812 }
813}
814
815/* These routines are used to make sure that the byte order of
816 the various data types remains constant between machines. */
817void QSmf::write32bit(quint32 data)
818{
819 putByte((data >> 24) & 0xff);
820 putByte((data >> 16) & 0xff);
821 putByte((data >> 8) & 0xff);
822 putByte(data & 0xff);
823}
824
825void QSmf::write16bit(quint16 data)
826{
827 putByte((data >> 8) & 0xff);
828 putByte(data & 0xff);
829}
830
831quint16 QSmf::to16bit(quint8 c1, quint8 c2)
832{
833 quint16 value;
834 value = (c1 << 8);
835 value += c2;
836 return value;
837}
838
839quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
840{
841 quint32 value;
842 value = (c1 << 24);
843 value += (c2 << 16);
844 value += (c3 << 8);
845 value += c4;
846 return value;
847}
848
849quint16 QSmf::read16bit()
850{
851 quint8 c1, c2;
852 c1 = getByte();
853 c2 = getByte();
854 return to16bit(c1, c2);
855}
856
857quint32 QSmf::read32bit()
858{
859 quint8 c1, c2, c3, c4;
860 c1 = getByte();
861 c2 = getByte();
862 c3 = getByte();
863 c4 = getByte();
864 return to32bit(c1, c2, c3, c4);
865}
866
867long QSmf::readVarLen()
868{
869 long value;
870 quint8 c;
871
872 c = getByte();
873 value = c;
874 if ((c & 0x80) != 0)
875 {
876 value &= 0x7f;
877 do
878 {
879 c = getByte();
880 value = (value << 7) + (c & 0x7f);
881 } while ((c & 0x80) != 0);
882 }
883 return value;
884}
885
886void QSmf::readExpected(const QString& s)
887{
888 int j;
889 quint8 b;
890 for (j = 0; j < s.length(); ++j)
891 {
892 b = getByte();
893 if (QChar(b) != s[j])
894 {
895 SMFError(QString("Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
896 break;
897 }
898 }
899}
900
901quint64 QSmf::findTempo()
902{
903 quint64 result, old_tempo, new_tempo;
904 QSmfRecTempo rec = d->m_TempoList.last();
905 old_tempo = d->m_CurrTempo;
906 new_tempo = d->m_CurrTempo;
907 QList<QSmfRecTempo>::Iterator it;
908 for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
909 {
910 rec = (*it);
911 if (rec.time <= d->m_CurrTime)
912 {
913 old_tempo = rec.tempo;
914 }
915 new_tempo = rec.tempo;
916 if (rec.time > d->m_RevisedTime)
917 {
918 break;
919 }
920 }
921 if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
922 {
923 d->m_RevisedTime = d->m_CurrTime;
924 result = old_tempo;
925 }
926 else
927 {
928 d->m_RevisedTime = rec.time;
929 d->m_TempoChangeTime = d->m_RevisedTime;
930 result = new_tempo;
931 }
932 return result;
933}
934
935/* This routine converts delta times in ticks into seconds. The
936 else statement is needed because the formula is different for tracks
937 based on notes and tracks based on SMPTE times. */
938double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
939{
940 double result;
941 double smpte_format;
942 double smpte_resolution;
943
944 if (division > 0)
945 {
946 result = static_cast<double>(ticks * tempo)/(division * 1000000.0);
947 }
948 else
949 {
950 smpte_format = upperByte(division);
951 smpte_resolution = lowerByte(division);
952 result = static_cast<double>(ticks)/(smpte_format * smpte_resolution
953 * 1000000.0);
954 }
955 return result;
956}
957
958void QSmf::SMFError(const QString& s)
959{
960 emit signalSMFError(s);
961}
962
963void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
964{
965 quint8 chan;
966 int k;
967 chan = status & midi_channel_mask;
968 if (c1 > 127)
969 {
970 SMFError(QString("ChannelMessage with bad c1 = %1").arg(c1));
971 //c1 &= 127;
972 }
973 if (c2 > 127)
974 {
975 SMFError(QString("ChannelMessage with bad c2 = %1").arg(c2));
976 //c2 &= 127;
977 }
978 switch (status & midi_command_mask)
979 {
980 case note_off:
981 emit signalSMFNoteOff(chan, c1, c2);
982 break;
983 case note_on:
984 emit signalSMFNoteOn(chan, c1, c2);
985 break;
986 case poly_aftertouch:
987 emit signalSMFKeyPress(chan, c1, c2);
988 break;
989 case control_change:
990 emit signalSMFCtlChange(chan, c1, c2);
991 break;
992 case program_chng:
993 emit signalSMFProgram(chan, c1);
994 break;
996 emit signalSMFChanPress(chan, c1);
997 break;
998 case pitch_wheel:
999 k = c1 + (c2 << 7) - 8192;
1000 emit signalSMFPitchBend(chan, k);
1001 break;
1002 default:
1003 SMFError(QString("Invalid MIDI status %1. Unhandled event").arg(status));
1004 break;
1005 }
1006}
1007
1008void QSmf::metaEvent(quint8 b)
1009{
1010 QSmfRecTempo rec;
1011 QByteArray m(d->m_MsgBuff);
1012
1013 switch (b)
1014 {
1015 case sequence_number:
1016 emit signalSMFSequenceNum(to16bit(m[0], m[1]));
1017 break;
1018 case text_event:
1019 case copyright_notice:
1020 case sequence_name:
1021 case instrument_name:
1022 case lyric:
1023 case marker:
1024 case cue_point: {
1025 QString s;
1026 if (d->m_codec == NULL)
1027 s = QString(m);
1028 else
1029 s = d->m_codec->toUnicode(m);
1030 emit signalSMFText(b, s);
1031 }
1032 break;
1033 case forced_channel:
1034 emit signalSMFforcedChannel(m[0]);
1035 break;
1036 case forced_port:
1037 emit signalSMFforcedPort(m[0]);
1038 break;
1039 case end_of_track:
1040 emit signalSMFendOfTrack();
1041 break;
1042 case set_tempo:
1043 d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
1044 emit signalSMFTempo(d->m_CurrTempo);
1045 rec = d->m_TempoList.last();
1046 if (rec.tempo == d->m_CurrTempo)
1047 {
1048 return;
1049 }
1050 if (rec.time > d->m_CurrTime)
1051 {
1052 return;
1053 }
1054 addTempo(d->m_CurrTempo, d->m_CurrTime);
1055 break;
1056 case smpte_offset:
1057 emit signalSMFSmpte(m[0], m[1], m[2], m[3], m[4]);
1058 break;
1059 case time_signature:
1060 emit signalSMFTimeSig(m[0], m[1], m[2], m[3]);
1061 break;
1062 case key_signature:
1063 emit signalSMFKeySig(m[0], m[1]);
1064 break;
1065 case sequencer_specific:
1066 emit signalSMFSeqSpecific(m);
1067 break;
1068 default:
1069 emit signalSMFMetaUnregistered(b, m);
1070 break;
1071 }
1072 emit signalSMFMetaMisc(b, m);
1073}
1074
1075void QSmf::sysEx()
1076{
1077 QByteArray varr(d->m_MsgBuff);
1078 emit signalSMFSysex(varr);
1079}
1080
1081void QSmf::badByte(quint8 b, int p)
1082{
1083 SMFError(QString("Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1084}
1085
1086quint8 QSmf::lowerByte(quint16 x)
1087{
1088 return (x & 0xff);
1089}
1090
1091quint8 QSmf::upperByte(quint16 x)
1092{
1093 return ((x >> 8) & 0xff);
1094}
1095
1096void QSmf::msgInit()
1097{
1098 d->m_MsgBuff.truncate(0);
1099}
1100
1101void QSmf::msgAdd(quint8 b)
1102{
1103 int s = d->m_MsgBuff.size();
1104 d->m_MsgBuff.resize(s + 1);
1105 d->m_MsgBuff[s] = b;
1106}
1107
1108/* public properties (accessors) */
1109
1115{
1116 return d->m_CurrTime;
1117}
1118
1124{
1125 return d->m_CurrTempo;
1126}
1127
1133{
1134 return d->m_RealTime;
1135}
1136
1142{
1143 return d->m_Division;
1144}
1145
1150void QSmf::setDivision(int division)
1151{
1152 d->m_Division = division;
1153}
1154
1160{
1161 return d->m_Tracks;
1162}
1163
1168void QSmf::setTracks(int tracks)
1169{
1170 d->m_Tracks = tracks;
1171}
1172
1178{
1179 return d->m_fileFormat;
1180}
1181
1186void QSmf::setFileFormat(int fileFormat)
1187{
1188 d->m_fileFormat = fileFormat;
1189}
1190
1196{
1197 return (long) d->m_IOStream->device()->pos();
1198}
1199
1206{
1207 return d->m_codec;
1208}
1209
1217void QSmf::setTextCodec(QTextCodec *codec)
1218{
1219 d->m_codec = codec;
1220}
1221
1222}
The QObject class is the base class of all Qt objects.
int getTracks()
Gets the number of tracks.
Definition: qsmf.cpp:1159
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:1217
long getRealTime()
Gets the real time in seconds.
Definition: qsmf.cpp:1132
long getCurrentTempo()
Gets the current tempo.
Definition: qsmf.cpp:1123
void signalSMFforcedChannel(int channel)
Emitted after reading a Forced channel message.
void setDivision(int division)
Sets the resolution.
Definition: qsmf.cpp:1150
long getFilePos()
Gets the position in the SMF stream.
Definition: qsmf.cpp:1195
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:1114
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:1168
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
Writes a Time Signature message.
Definition: qsmf.cpp:762
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.
QSmf(QObject *parent=0)
Constructor.
Definition: qsmf.cpp:99
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:1141
void writeToFile(const QString &fileName)
Writes a SMF stream to a disk file.
Definition: qsmf.cpp:457
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:716
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:424
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:516
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:1205
virtual ~QSmf()
Destructor.
Definition: qsmf.cpp:107
void writeBpmTempo(long deltaTime, int tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:748
void readFromFile(const QString &fileName)
Reads a SMF stream from a disk file.
Definition: qsmf.cpp:434
void signalSMFSysex(const QByteArray &data)
Emitted after reading a System Exclusive message.
void writeToStream(QDataStream *stream)
Writes a SMF stream.
Definition: qsmf.cpp:447
void writeTempo(long deltaTime, long tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:732
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:780
void setFileFormat(int fileFormat)
Sets the SMF file format.
Definition: qsmf.cpp:1186
void signalSMFPitchBend(int chan, int value)
Emitted after reading a Bender message.
int getFileFormat()
Gets the SMF file format.
Definition: qsmf.cpp:1177
void writeMidiEvent(long deltaTime, int type, int chan, int b1)
Writes a MIDI message with a single parameter.
Definition: qsmf.cpp:629
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:66
#define time_signature
SMF Time signature.
Definition: qsmf.h:57
#define sequence_name
SMF Sequence name.
Definition: qsmf.h:47
#define MThd
SMF Header prefix.
Definition: qsmf.h:39
#define text_event
SMF Text event.
Definition: qsmf.h:45
#define set_tempo
SMF Tempo change.
Definition: qsmf.h:55
#define control_change
MIDI event Control change.
Definition: qsmf.h:65
#define note_off
MIDI event Note Off.
Definition: qsmf.h:62
#define system_exclusive
MIDI event System Exclusive begin.
Definition: qsmf.h:69
#define midi_command_mask
Mask to extract the command from the status byte.
Definition: qsmf.h:72
#define sequencer_specific
SMF Sequencer specific.
Definition: qsmf.h:59
#define cue_point
SMF Cue point.
Definition: qsmf.h:51
#define marker
SMF Marker.
Definition: qsmf.h:50
#define smpte_offset
SMF SMPTE offset.
Definition: qsmf.h:56
#define copyright_notice
SMF Copyright notice.
Definition: qsmf.h:46
#define end_of_track
SMF End of track.
Definition: qsmf.h:54
#define channel_aftertouch
MIDI event Channel after-touch.
Definition: qsmf.h:67
#define MTrk
SMF Track prefix.
Definition: qsmf.h:40
#define end_of_sysex
MIDI event System Exclusive end.
Definition: qsmf.h:70
#define instrument_name
SMF Instrument name.
Definition: qsmf.h:48
#define lyric
SMF Lyric.
Definition: qsmf.h:49
#define note_on
MIDI event Note On.
Definition: qsmf.h:63
#define poly_aftertouch
MIDI event Polyphonic pressure.
Definition: qsmf.h:64
#define pitch_wheel
MIDI event Bender.
Definition: qsmf.h:68
#define midi_channel_mask
Mask to extract the channel from the status byte.
Definition: qsmf.h:73
#define forced_port
SMF Forced MIDI port.
Definition: qsmf.h:53
#define sequence_number
SMF Sequence number.
Definition: qsmf.h:44
#define meta_event
SMF Meta Event prefix.
Definition: qsmf.h:43
#define key_signature
SMF Key signature.
Definition: qsmf.h:58
#define forced_channel
SMF Forced MIDI channel.
Definition: qsmf.h:52