54class QSmf::QSmfPrivate {
64 m_OldCurrTempo(500000),
82 double m_DblOldRealtime;
85 quint64 m_OldCurrTempo;
86 quint64 m_OldRealTime;
87 quint64 m_OldCurrTime;
88 quint64 m_RevisedTime;
89 quint64 m_TempoChangeTime;
91 quint64 m_NumBytesWritten;
96 QDataStream *m_IOStream;
98 QList<QSmfRecTempo> m_TempoList;
115 d->m_TempoList.clear();
124 return d->m_IOStream->atEnd();
131quint8 QSmf::getByte()
146void QSmf::putByte(quint8 value)
148 *d->m_IOStream << value;
149 d->m_NumBytesWritten++;
157void QSmf::addTempo(quint64 tempo, quint64 time)
159 QSmfRecTempo tempoRec;
160 tempoRec.tempo = tempo;
161 tempoRec.time = time;
162 d->m_TempoList.append(tempoRec);
168void QSmf::readHeader()
173 d->m_CurrTempo = 500000;
174 d->m_OldCurrTempo = 500000;
175 addTempo(d->m_CurrTempo, 0);
176 if (d->m_Interactive)
184 readExpected(
"MThd");
185 d->m_ToBeRead = read32bit();
186 d->m_fileFormat = read16bit();
187 d->m_Tracks = read16bit();
188 d->m_Division = read16bit();
193 while ((d->m_ToBeRead > 0) && !endOfSmf())
197 if (d->m_ToBeRead > 0)
199 SMFError(
"Unexpected end of input");
206void QSmf::readTrack()
211 static const quint8 chantype[16] =
212 { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 };
221 quint64 delta_ticks, save_time, save_tempo;
223 sysexcontinue =
false;
225 if (d->m_Interactive)
227 d->m_ToBeRead = std::numeric_limits<unsigned long long>::max();
231 readExpected(
"MTrk");
232 d->m_ToBeRead = read32bit();
236 d->m_DblRealTime = 0;
237 d->m_DblOldRealtime = 0;
238 d->m_OldCurrTime = 0;
239 d->m_OldRealTime = 0;
240 d->m_CurrTempo = findTempo();
244 while (!endOfSmf() && (d->m_Interactive || d->m_ToBeRead > 0))
247 if (d->m_Interactive)
253 delta_ticks = unsigned(readVarLen());
254 d->m_RevisedTime = d->m_CurrTime;
255 d->m_CurrTime += delta_ticks;
256 while (d->m_RevisedTime < d->m_CurrTime)
258 save_time = d->m_RevisedTime;
259 save_tempo = d->m_CurrTempo;
260 d->m_CurrTempo = findTempo();
261 if (d->m_CurrTempo != d->m_OldCurrTempo)
263 d->m_OldCurrTempo = d->m_CurrTempo;
264 d->m_OldRealTime = d->m_RealTime;
265 if (d->m_RevisedTime != d->m_TempoChangeTime)
267 d->m_DblOldRealtime = d->m_DblRealTime;
268 d->m_OldCurrTime = save_time;
270 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
271 quint16(d->m_Division), save_tempo);
272 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
273 d->m_RealTime = llround(d->m_DblRealTime);
274 if (d->m_RevisedTime == d->m_TempoChangeTime)
276 d->m_OldCurrTime = d->m_RevisedTime;
277 d->m_DblOldRealtime = d->m_DblRealTime;
282 delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
283 quint16(d->m_Division), d->m_CurrTempo);
284 d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
285 d->m_RealTime = llround(d->m_DblRealTime);
293 SMFError(
"didn't find expected continuation of a SysEx");
301 SMFError(
"unexpected running status");
310 needed = chantype[status >> 4 & 0x0f];
323 channelMessage(status, c1, getByte());
327 channelMessage(status, c1, 0);
337 lookfor = quint64(readVarLen());
338 lookfor = d->m_ToBeRead - lookfor;
340 while ((d->m_ToBeRead > lookfor) && !endOfSmf())
347 lookfor = quint64(readVarLen());
348 lookfor = d->m_ToBeRead - lookfor;
351 while ((d->m_ToBeRead > lookfor) && !endOfSmf())
362 sysexcontinue =
true;
366 lookfor = readVarLen();
367 lookfor = d->m_ToBeRead - lookfor;
372 while ((d->m_ToBeRead > lookfor) && !endOfSmf())
382 sysexcontinue =
false;
387 badByte(c, d->m_IOStream->device()->pos() - 1);
390 if ((d->m_ToBeRead > lookfor) && endOfSmf()) {
391 SMFError(
"Unexpected end of input");
394 if (d->m_ToBeRead > 0) {
395 SMFError(QStringLiteral(
"Track ended before reading last %1 bytes").arg(d->m_ToBeRead));
407 for ( i = d->m_Tracks; (i > 0) && !endOfSmf(); i--)
413 QStringLiteral(
"%1 tracks out of a total of %2 are missing").arg(i).arg(d->m_Tracks));
428 writeHeaderChunk(d->m_fileFormat, d->m_Tracks, d->m_Division);
430 if (d->m_fileFormat == 1)
434 for (i = 0; i < d->m_Tracks; ++i)
446 d->m_IOStream = stream;
456 QFile file(fileName);
457 auto ok = file.open(QIODevice::ReadOnly);
459 QDataStream ds(&file);
463 qCritical() <<
"cannot open file" << fileName;
473 d->m_IOStream = stream;
483 QFile file(fileName);
484 auto ok = file.open(QIODevice::WriteOnly);
486 QDataStream ds(&file);
490 qCritical() <<
"cannot open file" << fileName;
500void QSmf::writeHeaderChunk(
int format,
int ntracks,
int division)
504 write16bit(quint16(format));
505 write16bit(quint16(ntracks));
506 write16bit(quint16(division));
513void QSmf::writeTrackChunk(
int track)
523 offset = d->m_IOStream->device()->pos();
525 write32bit(trklength);
526 d->m_NumBytesWritten = 0;
530 place_marker = d->m_IOStream->device()->pos();
531 d->m_IOStream->device()->seek(offset);
532 trklength = d->m_NumBytesWritten;
534 write32bit(trklength);
535 d->m_IOStream->device()->seek(place_marker);
546 writeVarLen(deltaTime);
548 putByte(d->m_LastStatus);
550 writeVarLen(data.size());
551 foreach(
char byte, data)
563 writeVarLen(deltaTime);
567 if (d->m_codec ==
nullptr)
568 lcldata = data.toLatin1();
570 lcldata = d->m_codec->fromUnicode(data);
571 writeVarLen(lcldata.length());
572 foreach(
char byte, lcldata)
585 writeVarLen(deltaTime);
599 writeVarLen(deltaTime);
613 const QByteArray& data)
615 unsigned int i, j, size;
617 writeVarLen(quint64(deltaTime));
627 SMFError(
"error: MIDI channel greater than 16");
631 if (d->m_LastStatus != c)
644 j = (c == type ? 1 : 0);
645 for (i = j; i < unsigned(data.size()); ++i)
647 putByte(quint8(data[i]));
661 writeVarLen(deltaTime);
664 SMFError(
"error: Wrong method for a system exclusive event");
668 SMFError(
"error: MIDI channel greater than 16");
671 if (d->m_LastStatus != c)
690 writeVarLen(deltaTime);
693 SMFError(
"error: Wrong method for a system exclusive event");
697 SMFError(
"error: MIDI channel greater than 16");
700 if (d->m_LastStatus != c)
718 unsigned int i, j, size;
720 writeVarLen(quint64(deltaTime));
723 SMFError(
"error: type should be system exclusive");
728 size = unsigned(len);
733 j = (c == type ? 1 : 0);
734 for (i = j; i < unsigned(len); ++i)
736 putByte(quint8(data[i]));
747 writeVarLen(deltaTime);
749 putByte(d->m_LastStatus);
752 putByte((seqnum >> 8) & 0xff);
753 putByte(seqnum & 0xff);
763 writeVarLen(deltaTime);
767 putByte((tempo >> 16) & 0xff);
768 putByte((tempo >> 8) & 0xff);
769 putByte(tempo & 0xff);
779 long us_tempo = 60000000l / tempo;
793 writeVarLen(deltaTime);
811 writeVarLen(quint64(deltaTime));
815 putByte(quint8(tone));
816 putByte(mode & 0x01);
823void QSmf::writeVarLen(quint64 value)
827 buffer = value & 0x7f;
828 while ((value >>= 7) > 0)
832 buffer += (value & 0x7f);
836 putByte(buffer & 0xff);
846void QSmf::write32bit(quint32 data)
848 putByte((data >> 24) & 0xff);
849 putByte((data >> 16) & 0xff);
850 putByte((data >> 8) & 0xff);
851 putByte(data & 0xff);
854void QSmf::write16bit(quint16 data)
856 putByte((data >> 8) & 0xff);
857 putByte(data & 0xff);
860quint16 QSmf::to16bit(quint8 c1, quint8 c2)
863 value = quint16(c1 << 8);
868quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
871 value = unsigned(c1 << 24);
872 value += unsigned(c2 << 16);
873 value += unsigned(c3 << 8);
878quint16 QSmf::read16bit()
883 return to16bit(c1, c2);
886quint32 QSmf::read32bit()
888 quint8 c1, c2, c3, c4;
893 return to32bit(c1, c2, c3, c4);
896long QSmf::readVarLen()
909 value = (value << 7) + (c & 0x7f);
910 }
while ((c & 0x80) != 0);
915void QSmf::readExpected(
const QString& s)
919 for (j = 0; j < s.length(); ++j)
922 if (QChar(b) != s[j])
924 SMFError(QString(
"Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
930quint64 QSmf::findTempo()
932 quint64 result, old_tempo, new_tempo;
933 QSmfRecTempo rec = d->m_TempoList.last();
934 old_tempo = d->m_CurrTempo;
935 new_tempo = d->m_CurrTempo;
936 QList<QSmfRecTempo>::Iterator it;
937 for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
940 if (rec.time <= d->m_CurrTime)
942 old_tempo = rec.tempo;
944 new_tempo = rec.tempo;
945 if (rec.time > d->m_RevisedTime)
950 if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
952 d->m_RevisedTime = d->m_CurrTime;
957 d->m_RevisedTime = rec.time;
958 d->m_TempoChangeTime = d->m_RevisedTime;
967double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
971 double smpte_resolution;
975 result = double(ticks * tempo)/(division * 1000000.0);
979 smpte_format = upperByte(division);
980 smpte_resolution = lowerByte(division);
981 result = double(ticks)/(smpte_format * smpte_resolution
987void QSmf::SMFError(
const QString& s)
992void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
999 SMFError(QString(
"ChannelMessage with bad c1 = %1").arg(c1));
1004 SMFError(QString(
"ChannelMessage with bad c2 = %1").arg(c2));
1028 k = c1 + (c2 << 7) - 8192;
1032 SMFError(QString(
"Invalid MIDI status %1. Unhandled event").arg(status));
1037void QSmf::metaEvent(quint8 b)
1040 QByteArray m(d->m_MsgBuff);
1055 if (d->m_codec ==
nullptr) {
1058 s = d->m_codec->toUnicode(m);
1073 d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
1075 rec = d->m_TempoList.last();
1076 if (rec.tempo == d->m_CurrTempo)
1080 if (rec.time > d->m_CurrTime)
1084 addTempo(d->m_CurrTempo, d->m_CurrTime);
1107 QByteArray varr(d->m_MsgBuff);
1111void QSmf::badByte(quint8 b,
int p)
1113 SMFError(QString(
"Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1116quint8 QSmf::lowerByte(quint16 x)
1121quint8 QSmf::upperByte(quint16 x)
1123 return ((x >> 8) & 0xff);
1128 d->m_MsgBuff.truncate(0);
1131void QSmf::msgAdd(quint8 b)
1133 int s = d->m_MsgBuff.size();
1134 d->m_MsgBuff.resize(s + 1);
1135 d->m_MsgBuff[s] = b;
1146 return d->m_CurrTime;
1155 return d->m_CurrTempo;
1164 return d->m_RealTime;
1173 return d->m_Division;
1182 d->m_Division = division;
1200 d->m_Tracks = tracks;
1209 return d->m_fileFormat;
1218 d->m_fileFormat = fileFormat;
1227 return long(d->m_IOStream->device()->pos());
1260 return QStringLiteral(QT_STRINGIFY(VERSION));