drumstick  2.9.0
C++ MIDI libraries using Qt objects, idioms, and style.
qsmf.cpp
Go to the documentation of this file.
1 /*
2  Standard MIDI File component
3  Copyright (C) 2006-2023, 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 
29 DISABLE_WARNING_PUSH
30 DISABLE_WARNING_DEPRECATED_DECLARATIONS
31 
37 namespace drumstick {
38 namespace File {
39 
52 class QSmf::QSmfPrivate {
53 public:
54  QSmfPrivate():
55  m_Interactive(false),
56  m_CurrTime(0),
57  m_RealTime(0),
58  m_DblRealTime(0),
59  m_DblOldRealtime(0),
60  m_Division(96),
61  m_CurrTempo(500000),
62  m_OldCurrTempo(500000),
63  m_OldRealTime(0),
64  m_OldCurrTime(0),
65  m_RevisedTime(0),
66  m_TempoChangeTime(0),
67  m_ToBeRead(0),
68  m_NumBytesWritten(0),
69  m_Tracks(0),
70  m_fileFormat(0),
71  m_LastStatus(0),
72  m_codec(nullptr),
73  m_IOStream(nullptr)
74  { }
75 
76  bool m_Interactive;
77  quint64 m_CurrTime;
78  quint64 m_RealTime;
79  double m_DblRealTime;
80  double m_DblOldRealtime;
81  int m_Division;
82  quint64 m_CurrTempo;
83  quint64 m_OldCurrTempo;
84  quint64 m_OldRealTime;
85  quint64 m_OldCurrTime;
86  quint64 m_RevisedTime;
87  quint64 m_TempoChangeTime;
88  quint64 m_ToBeRead;
89  quint64 m_NumBytesWritten;
90  int m_Tracks;
91  int m_fileFormat;
92  int m_LastStatus;
93  QTextCodec *m_codec;
94  QDataStream *m_IOStream;
95  QByteArray m_MsgBuff;
96  QList<QSmfRecTempo> m_TempoList;
97 };
98 
103 QSmf::QSmf(QObject * parent) :
104  QObject(parent),
105  d(new QSmfPrivate)
106 { }
107 
112 {
113  d->m_TempoList.clear();
114 }
115 
120 bool QSmf::endOfSmf()
121 {
122  return d->m_IOStream->atEnd();
123 }
124 
129 quint8 QSmf::getByte()
130 {
131  quint8 b = 0;
132  if (!endOfSmf())
133  {
134  *d->m_IOStream >> b;
135  d->m_ToBeRead--;
136  }
137  return b;
138 }
139 
144 void QSmf::putByte(quint8 value)
145 {
146  *d->m_IOStream << value;
147  d->m_NumBytesWritten++;
148 }
149 
155 void QSmf::addTempo(quint64 tempo, quint64 time)
156 {
157  QSmfRecTempo tempoRec;
158  tempoRec.tempo = tempo;
159  tempoRec.time = time;
160  d->m_TempoList.append(tempoRec);
161 }
162 
166 void QSmf::readHeader()
167 {
168  d->m_CurrTime = 0;
169  d->m_RealTime = 0;
170  d->m_Division = 96;
171  d->m_CurrTempo = 500000;
172  d->m_OldCurrTempo = 500000;
173  addTempo(d->m_CurrTempo, 0);
174  if (d->m_Interactive)
175  {
176  d->m_fileFormat= 0;
177  d->m_Tracks = 1;
178  d->m_Division = 96;
179  }
180  else
181  {
182  readExpected("MThd");
183  d->m_ToBeRead = read32bit();
184  d->m_fileFormat = read16bit();
185  d->m_Tracks = read16bit();
186  d->m_Division = read16bit();
187  }
188  Q_EMIT signalSMFHeader(d->m_fileFormat, d->m_Tracks, d->m_Division);
189 
190  /* flush any extra stuff, in case the length of header is not */
191  while ((d->m_ToBeRead > 0) && !endOfSmf())
192  {
193  getByte();
194  }
195  if (d->m_ToBeRead > 0)
196  {
197  SMFError("Unexpected end of input");
198  }
199 }
200 
204 void QSmf::readTrack()
205 {
206  /* This array is indexed by the high half of a status byte. It's
207  value is either the number of bytes needed (1 or 2) for a channel
208  message, or 0 (meaning it's not a channel message). */
209  static const quint8 chantype[16] =
210  { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 };
211 
212  quint64 lookfor;
213  quint8 c, c1, type;
214  bool sysexcontinue; // true if last message was an unfinished SysEx
215  bool running; // true when running status is used
216  quint8 status; // status value (e.g. 0x90==note-on)
217  int needed;
218  double delta_secs;
219  quint64 delta_ticks, save_time, save_tempo;
220 
221  sysexcontinue = false;
222  status = 0;
223  if (d->m_Interactive)
224  {
225  d->m_ToBeRead = std::numeric_limits<unsigned long long>::max();
226  }
227  else
228  {
229  readExpected("MTrk");
230  d->m_ToBeRead = read32bit();
231  }
232  d->m_CurrTime = 0;
233  d->m_RealTime = 0;
234  d->m_DblRealTime = 0;
235  d->m_DblOldRealtime = 0;
236  d->m_OldCurrTime = 0;
237  d->m_OldRealTime = 0;
238  d->m_CurrTempo = findTempo();
239 
240  Q_EMIT signalSMFTrackStart();
241 
242  while (!endOfSmf() && (d->m_Interactive || d->m_ToBeRead > 0))
243  {
244  lookfor = 0;
245  if (d->m_Interactive)
246  {
247  d->m_CurrTime++;
248  }
249  else
250  {
251  delta_ticks = unsigned(readVarLen());
252  d->m_RevisedTime = d->m_CurrTime;
253  d->m_CurrTime += delta_ticks;
254  while (d->m_RevisedTime < d->m_CurrTime)
255  {
256  save_time = d->m_RevisedTime;
257  save_tempo = d->m_CurrTempo;
258  d->m_CurrTempo = findTempo();
259  if (d->m_CurrTempo != d->m_OldCurrTempo)
260  {
261  d->m_OldCurrTempo = d->m_CurrTempo;
262  d->m_OldRealTime = d->m_RealTime;
263  if (d->m_RevisedTime != d->m_TempoChangeTime)
264  {
265  d->m_DblOldRealtime = d->m_DblRealTime;
266  d->m_OldCurrTime = save_time;
267  }
268  delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
269  quint16(d->m_Division), save_tempo);
270  d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
271  d->m_RealTime = llround(d->m_DblRealTime);
272  if (d->m_RevisedTime == d->m_TempoChangeTime)
273  {
274  d->m_OldCurrTime = d->m_RevisedTime;
275  d->m_DblOldRealtime = d->m_DblRealTime;
276  }
277  }
278  else
279  {
280  delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
281  quint16(d->m_Division), d->m_CurrTempo);
282  d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
283  d->m_RealTime = llround(d->m_DblRealTime);
284  }
285  }
286  }
287 
288  c = getByte();
289  if (sysexcontinue && (c != end_of_sysex))
290  {
291  SMFError("didn't find expected continuation of a SysEx");
292  }
293  if (c < 0xf8)
294  {
295  if ((c & 0x80) == 0)
296  {
297  if (status == 0)
298  {
299  SMFError("unexpected running status");
300  }
301  running = true;
302  }
303  else
304  {
305  status = c;
306  running = false;
307  }
308  needed = chantype[status >> 4 & 0x0f];
309  if (needed != 0)
310  {
311  if (running)
312  {
313  c1 = c;
314  }
315  else
316  {
317  c1 = getByte();
318  }
319  if (needed > 1)
320  {
321  channelMessage(status, c1, getByte());
322  }
323  else
324  {
325  channelMessage(status, c1, 0);
326  }
327  continue;
328  }
329  }
330 
331  switch (c)
332  {
333  case meta_event:
334  type = getByte();
335  lookfor = quint64(readVarLen());
336  lookfor = d->m_ToBeRead - lookfor;
337  msgInit();
338  while ((d->m_ToBeRead > lookfor) && !endOfSmf())
339  {
340  msgAdd(getByte());
341  }
342  metaEvent(type);
343  break;
344  case system_exclusive:
345  lookfor = quint64(readVarLen());
346  lookfor = d->m_ToBeRead - lookfor;
347  msgInit();
348  msgAdd(system_exclusive);
349  while ((d->m_ToBeRead > lookfor) && !endOfSmf())
350  {
351  c = getByte();
352  msgAdd(c);
353  }
354  if (c == end_of_sysex)
355  {
356  sysEx();
357  }
358  else
359  {
360  sysexcontinue = true;
361  }
362  break;
363  case end_of_sysex:
364  lookfor = readVarLen();
365  lookfor = d->m_ToBeRead - lookfor;
366  if (!sysexcontinue)
367  {
368  msgInit();
369  }
370  while ((d->m_ToBeRead > lookfor) && !endOfSmf())
371  {
372  c = getByte();
373  msgAdd(c);
374  }
375  if (sysexcontinue)
376  {
377  if (c == end_of_sysex)
378  {
379  sysEx();
380  sysexcontinue = false;
381  }
382  }
383  break;
384  default:
385  badByte(c, d->m_IOStream->device()->pos() - 1);
386  break;
387  }
388  if ((d->m_ToBeRead > lookfor) && endOfSmf()) {
389  SMFError("Unexpected end of input");
390  }
391  }
392  if (d->m_ToBeRead > 0) {
393  SMFError(QStringLiteral("Track ended before reading last %1 bytes").arg(d->m_ToBeRead));
394  }
395  Q_EMIT signalSMFTrackEnd();
396 }
397 
401 void QSmf::SMFRead()
402 {
403  int i;
404  readHeader();
405  for ( i = d->m_Tracks; (i > 0) && !endOfSmf(); i--)
406  {
407  readTrack();
408  }
409  if (i > 0) {
410  SMFError(
411  QStringLiteral("%1 tracks out of a total of %2 are missing").arg(i).arg(d->m_Tracks));
412  }
413 }
414 
422 void QSmf::SMFWrite()
423 {
424  int i;
425  d->m_LastStatus = 0;
426  writeHeaderChunk(d->m_fileFormat, d->m_Tracks, d->m_Division);
427  d->m_LastStatus = 0;
428  if (d->m_fileFormat == 1)
429  {
430  Q_EMIT signalSMFWriteTempoTrack();
431  }
432  for (i = 0; i < d->m_Tracks; ++i)
433  {
434  writeTrackChunk(i);
435  }
436 }
437 
442 void QSmf::readFromStream(QDataStream *stream)
443 {
444  d->m_IOStream = stream;
445  SMFRead();
446 }
447 
452 void QSmf::readFromFile(const QString& fileName)
453 {
454  QFile file(fileName);
455  file.open(QIODevice::ReadOnly);
456  QDataStream ds(&file);
457  readFromStream(&ds);
458  file.close();
459 }
460 
465 void QSmf::writeToStream(QDataStream *stream)
466 {
467  d->m_IOStream = stream;
468  SMFWrite();
469 }
470 
475 void QSmf::writeToFile(const QString& fileName)
476 {
477  QFile file(fileName);
478  file.open(QIODevice::WriteOnly);
479  QDataStream ds(&file);
480  writeToStream(&ds);
481  file.close();
482 }
483 
490 void QSmf::writeHeaderChunk(int format, int ntracks, int division)
491 {
492  write32bit(MThd);
493  write32bit(6);
494  write16bit(quint16(format));
495  write16bit(quint16(ntracks));
496  write16bit(quint16(division));
497 }
498 
503 void QSmf::writeTrackChunk(int track)
504 {
505  quint32 trkhdr;
506  quint32 trklength;
507  qint64 offset;
508  qint64 place_marker;
509 
510  d->m_LastStatus = 0;
511  trkhdr = MTrk;
512  trklength = 0;
513  offset = d->m_IOStream->device()->pos();
514  write32bit(trkhdr);
515  write32bit(trklength);
516  d->m_NumBytesWritten = 0;
517 
518  Q_EMIT signalSMFWriteTrack(track);
519 
520  place_marker = d->m_IOStream->device()->pos();
521  d->m_IOStream->device()->seek(offset);
522  trklength = d->m_NumBytesWritten;
523  write32bit(trkhdr);
524  write32bit(trklength);
525  d->m_IOStream->device()->seek(place_marker);
526 }
527 
534 void QSmf::writeMetaEvent(long deltaTime, int type, const QByteArray& data)
535 {
536  writeVarLen(deltaTime);
537  d->m_LastStatus = meta_event;
538  putByte(d->m_LastStatus);
539  putByte(type);
540  writeVarLen(data.size());
541  foreach(char byte, data)
542  putByte(byte);
543 }
544 
551 void QSmf::writeMetaEvent(long deltaTime, int type, const QString& data)
552 {
553  writeVarLen(deltaTime);
554  putByte(d->m_LastStatus = meta_event);
555  putByte(type);
556  QByteArray lcldata;
557  if (d->m_codec == nullptr)
558  lcldata = data.toLatin1();
559  else
560  lcldata = d->m_codec->fromUnicode(data);
561  writeVarLen(lcldata.length());
562  foreach(char byte, lcldata)
563  putByte(byte);
564 }
565 
573 void QSmf::writeMetaEvent(long deltaTime, int type, int data)
574 {
575  writeVarLen(deltaTime);
576  putByte(d->m_LastStatus = meta_event);
577  putByte(type);
578  putByte(1);
579  putByte(data);
580 }
581 
587 void QSmf::writeMetaEvent(long deltaTime, int type)
588 {
589  writeVarLen(deltaTime);
590  putByte(d->m_LastStatus = meta_event);
591  putByte(type);
592  putByte(0);
593 }
594 
602 void QSmf::writeMidiEvent(long deltaTime, int type, int chan,
603  const QByteArray& data)
604 {
605  unsigned int i, j, size;
606  quint8 c;
607  writeVarLen(quint64(deltaTime));
608  if ((type == system_exclusive) || (type == end_of_sysex))
609  {
610  c = type;
611  d->m_LastStatus = 0;
612  }
613  else
614  {
615  if (chan > 15)
616  {
617  SMFError("error: MIDI channel greater than 16");
618  }
619  c = type | chan;
620  }
621  if (d->m_LastStatus != c)
622  {
623  d->m_LastStatus = c;
624  putByte(c);
625  }
626  c = quint8(data[0]);
627  if (type == system_exclusive || type == end_of_sysex)
628  {
629  size = data.size();
630  if (type == c)
631  --size;
632  writeVarLen(size);
633  }
634  j = (c == type ? 1 : 0);
635  for (i = j; i < unsigned(data.size()); ++i)
636  {
637  putByte(quint8(data[i]));
638  }
639 }
640 
648 void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1)
649 {
650  quint8 c;
651  writeVarLen(deltaTime);
652  if ((type == system_exclusive) || (type == end_of_sysex))
653  {
654  SMFError("error: Wrong method for a system exclusive event");
655  }
656  if (chan > 15)
657  {
658  SMFError("error: MIDI channel greater than 16");
659  }
660  c = type | chan;
661  if (d->m_LastStatus != c)
662  {
663  d->m_LastStatus = c;
664  putByte(c);
665  }
666  putByte(b1);
667 }
668 
677 void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1, int b2)
678 {
679  quint8 c;
680  writeVarLen(deltaTime);
681  if ((type == system_exclusive) || (type == end_of_sysex))
682  {
683  SMFError("error: Wrong method for a system exclusive event");
684  }
685  if (chan > 15)
686  {
687  SMFError("error: MIDI channel greater than 16");
688  }
689  c = type | chan;
690  if (d->m_LastStatus != c)
691  {
692  d->m_LastStatus = c;
693  putByte(c);
694  }
695  putByte(b1);
696  putByte(b2);
697 }
698 
706 void QSmf::writeMidiEvent(long deltaTime, int type, long len, char* data)
707 {
708  unsigned int i, j, size;
709  quint8 c;
710  writeVarLen(quint64(deltaTime));
711  if ((type != system_exclusive) && (type != end_of_sysex))
712  {
713  SMFError("error: type should be system exclusive");
714  }
715  d->m_LastStatus = 0;
716  c = quint8(type);
717  putByte(c);
718  size = unsigned(len);
719  c = quint8(data[0]);
720  if (c == type)
721  --size;
722  writeVarLen(size);
723  j = (c == type ? 1 : 0);
724  for (i = j; i < unsigned(len); ++i)
725  {
726  putByte(quint8(data[i]));
727  }
728 }
729 
735 void QSmf::writeSequenceNumber(long deltaTime, int seqnum)
736 {
737  writeVarLen(deltaTime);
738  d->m_LastStatus = meta_event;
739  putByte(d->m_LastStatus);
740  putByte(sequence_number);
741  putByte(2);
742  putByte((seqnum >> 8) & 0xff);
743  putByte(seqnum & 0xff);
744 }
745 
751 void QSmf::writeTempo(long deltaTime, long tempo)
752 {
753  writeVarLen(deltaTime);
754  putByte(d->m_LastStatus = meta_event);
755  putByte(set_tempo);
756  putByte(3);
757  putByte((tempo >> 16) & 0xff);
758  putByte((tempo >> 8) & 0xff);
759  putByte(tempo & 0xff);
760 }
761 
767 void QSmf::writeBpmTempo(long deltaTime, int tempo)
768 {
769  long us_tempo = 60000000l / tempo;
770  writeTempo(deltaTime, us_tempo);
771 }
772 
781 void QSmf::writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
782 {
783  writeVarLen(deltaTime);
784  putByte(d->m_LastStatus = meta_event);
785  putByte(time_signature);
786  putByte(4);
787  putByte(num & 0xff);
788  putByte(den & 0xff);
789  putByte(cc & 0xff);
790  putByte(bb & 0xff);
791 }
792 
799 void QSmf::writeKeySignature(long deltaTime, int tone, int mode)
800 {
801  writeVarLen(quint64(deltaTime));
802  putByte(d->m_LastStatus = meta_event);
803  putByte(key_signature);
804  putByte(2);
805  putByte(quint8(tone));
806  putByte(mode & 0x01);
807 }
808 
813 void QSmf::writeVarLen(quint64 value)
814 {
815  quint64 buffer;
816 
817  buffer = value & 0x7f;
818  while ((value >>= 7) > 0)
819  {
820  buffer <<= 8;
821  buffer |= 0x80;
822  buffer += (value & 0x7f);
823  }
824  while (true)
825  {
826  putByte(buffer & 0xff);
827  if (buffer & 0x80)
828  buffer >>= 8;
829  else
830  break;
831  }
832 }
833 
834 /* These routines are used to make sure that the byte order of
835  the various data types remains constant between machines. */
836 void QSmf::write32bit(quint32 data)
837 {
838  putByte((data >> 24) & 0xff);
839  putByte((data >> 16) & 0xff);
840  putByte((data >> 8) & 0xff);
841  putByte(data & 0xff);
842 }
843 
844 void QSmf::write16bit(quint16 data)
845 {
846  putByte((data >> 8) & 0xff);
847  putByte(data & 0xff);
848 }
849 
850 quint16 QSmf::to16bit(quint8 c1, quint8 c2)
851 {
852  quint16 value;
853  value = quint16(c1 << 8);
854  value += c2;
855  return value;
856 }
857 
858 quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
859 {
860  quint32 value;
861  value = unsigned(c1 << 24);
862  value += unsigned(c2 << 16);
863  value += unsigned(c3 << 8);
864  value += c4;
865  return value;
866 }
867 
868 quint16 QSmf::read16bit()
869 {
870  quint8 c1, c2;
871  c1 = getByte();
872  c2 = getByte();
873  return to16bit(c1, c2);
874 }
875 
876 quint32 QSmf::read32bit()
877 {
878  quint8 c1, c2, c3, c4;
879  c1 = getByte();
880  c2 = getByte();
881  c3 = getByte();
882  c4 = getByte();
883  return to32bit(c1, c2, c3, c4);
884 }
885 
886 long QSmf::readVarLen()
887 {
888  quint64 value;
889  quint8 c;
890 
891  c = getByte();
892  value = c;
893  if ((c & 0x80) != 0)
894  {
895  value &= 0x7f;
896  do
897  {
898  c = getByte();
899  value = (value << 7) + (c & 0x7f);
900  } while ((c & 0x80) != 0);
901  }
902  return long(value);
903 }
904 
905 void QSmf::readExpected(const QString& s)
906 {
907  int j;
908  quint8 b;
909  for (j = 0; j < s.length(); ++j)
910  {
911  b = getByte();
912  if (QChar(b) != s[j])
913  {
914  SMFError(QString("Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
915  break;
916  }
917  }
918 }
919 
920 quint64 QSmf::findTempo()
921 {
922  quint64 result, old_tempo, new_tempo;
923  QSmfRecTempo rec = d->m_TempoList.last();
924  old_tempo = d->m_CurrTempo;
925  new_tempo = d->m_CurrTempo;
926  QList<QSmfRecTempo>::Iterator it;
927  for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
928  {
929  rec = (*it);
930  if (rec.time <= d->m_CurrTime)
931  {
932  old_tempo = rec.tempo;
933  }
934  new_tempo = rec.tempo;
935  if (rec.time > d->m_RevisedTime)
936  {
937  break;
938  }
939  }
940  if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
941  {
942  d->m_RevisedTime = d->m_CurrTime;
943  result = old_tempo;
944  }
945  else
946  {
947  d->m_RevisedTime = rec.time;
948  d->m_TempoChangeTime = d->m_RevisedTime;
949  result = new_tempo;
950  }
951  return result;
952 }
953 
954 /* This routine converts delta times in ticks into seconds. The
955  else statement is needed because the formula is different for tracks
956  based on notes and tracks based on SMPTE times. */
957 double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
958 {
959  double result;
960  double smpte_format;
961  double smpte_resolution;
962 
963  if (division > 0)
964  {
965  result = double(ticks * tempo)/(division * 1000000.0);
966  }
967  else
968  {
969  smpte_format = upperByte(division);
970  smpte_resolution = lowerByte(division);
971  result = double(ticks)/(smpte_format * smpte_resolution
972  * 1000000.0);
973  }
974  return result;
975 }
976 
977 void QSmf::SMFError(const QString& s)
978 {
979  Q_EMIT signalSMFError(s);
980 }
981 
982 void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
983 {
984  quint8 chan;
985  int k;
986  chan = status & midi_channel_mask;
987  if (c1 > 127)
988  {
989  SMFError(QString("ChannelMessage with bad c1 = %1").arg(c1));
990  //c1 &= 127;
991  }
992  if (c2 > 127)
993  {
994  SMFError(QString("ChannelMessage with bad c2 = %1").arg(c2));
995  //c2 &= 127;
996  }
997  switch (status & midi_command_mask)
998  {
999  case note_off:
1000  Q_EMIT signalSMFNoteOff(chan, c1, c2);
1001  break;
1002  case note_on:
1003  Q_EMIT signalSMFNoteOn(chan, c1, c2);
1004  break;
1005  case poly_aftertouch:
1006  Q_EMIT signalSMFKeyPress(chan, c1, c2);
1007  break;
1008  case control_change:
1009  Q_EMIT signalSMFCtlChange(chan, c1, c2);
1010  break;
1011  case program_chng:
1012  Q_EMIT signalSMFProgram(chan, c1);
1013  break;
1014  case channel_aftertouch:
1015  Q_EMIT signalSMFChanPress(chan, c1);
1016  break;
1017  case pitch_wheel:
1018  k = c1 + (c2 << 7) - 8192;
1019  Q_EMIT signalSMFPitchBend(chan, k);
1020  break;
1021  default:
1022  SMFError(QString("Invalid MIDI status %1. Unhandled event").arg(status));
1023  break;
1024  }
1025 }
1026 
1027 void QSmf::metaEvent(quint8 b)
1028 {
1029  QSmfRecTempo rec;
1030  QByteArray m(d->m_MsgBuff);
1031 
1032  switch (b)
1033  {
1034  case sequence_number:
1035  Q_EMIT signalSMFSequenceNum(to16bit(m[0], m[1]));
1036  break;
1037  case text_event:
1038  case copyright_notice:
1039  case sequence_name:
1040  case instrument_name:
1041  case lyric:
1042  case marker:
1043  case cue_point: {
1044  QString s;
1045  if (d->m_codec == nullptr) {
1046  Q_EMIT signalSMFText2(b, m);
1047  } else {
1048  s = d->m_codec->toUnicode(m);
1049  Q_EMIT signalSMFText(b, s);
1050  }
1051  }
1052  break;
1053  case forced_channel:
1054  Q_EMIT signalSMFforcedChannel(m[0]);
1055  break;
1056  case forced_port:
1057  Q_EMIT signalSMFforcedPort(m[0]);
1058  break;
1059  case end_of_track:
1060  Q_EMIT signalSMFendOfTrack();
1061  break;
1062  case set_tempo:
1063  d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
1064  Q_EMIT signalSMFTempo(d->m_CurrTempo);
1065  rec = d->m_TempoList.last();
1066  if (rec.tempo == d->m_CurrTempo)
1067  {
1068  return;
1069  }
1070  if (rec.time > d->m_CurrTime)
1071  {
1072  return;
1073  }
1074  addTempo(d->m_CurrTempo, d->m_CurrTime);
1075  break;
1076  case smpte_offset:
1077  Q_EMIT signalSMFSmpte(m[0], m[1], m[2], m[3], m[4]);
1078  break;
1079  case time_signature:
1080  Q_EMIT signalSMFTimeSig(m[0], m[1], m[2], m[3]);
1081  break;
1082  case key_signature:
1083  Q_EMIT signalSMFKeySig(m[0], m[1]);
1084  break;
1085  case sequencer_specific:
1086  Q_EMIT signalSMFSeqSpecific(m);
1087  break;
1088  default:
1089  Q_EMIT signalSMFMetaUnregistered(b, m);
1090  break;
1091  }
1092  Q_EMIT signalSMFMetaMisc(b, m);
1093 }
1094 
1095 void QSmf::sysEx()
1096 {
1097  QByteArray varr(d->m_MsgBuff);
1098  Q_EMIT signalSMFSysex(varr);
1099 }
1100 
1101 void QSmf::badByte(quint8 b, int p)
1102 {
1103  SMFError(QString("Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1104 }
1105 
1106 quint8 QSmf::lowerByte(quint16 x)
1107 {
1108  return (x & 0xff);
1109 }
1110 
1111 quint8 QSmf::upperByte(quint16 x)
1112 {
1113  return ((x >> 8) & 0xff);
1114 }
1115 
1116 void QSmf::msgInit()
1117 {
1118  d->m_MsgBuff.truncate(0);
1119 }
1120 
1121 void QSmf::msgAdd(quint8 b)
1122 {
1123  int s = d->m_MsgBuff.size();
1124  d->m_MsgBuff.resize(s + 1);
1125  d->m_MsgBuff[s] = b;
1126 }
1127 
1128 /* public properties (accessors) */
1129 
1135 {
1136  return d->m_CurrTime;
1137 }
1138 
1144 {
1145  return d->m_CurrTempo;
1146 }
1147 
1153 {
1154  return d->m_RealTime;
1155 }
1156 
1162 {
1163  return d->m_Division;
1164 }
1165 
1170 void QSmf::setDivision(int division)
1171 {
1172  d->m_Division = division;
1173 }
1174 
1180 {
1181  return d->m_Tracks;
1182 }
1183 
1188 void QSmf::setTracks(int tracks)
1189 {
1190  d->m_Tracks = tracks;
1191 }
1192 
1198 {
1199  return d->m_fileFormat;
1200 }
1201 
1206 void QSmf::setFileFormat(int fileFormat)
1207 {
1208  d->m_fileFormat = fileFormat;
1209 }
1210 
1216 {
1217  return long(d->m_IOStream->device()->pos());
1218 }
1219 
1226 QTextCodec* QSmf::getTextCodec()
1227 {
1228  return d->m_codec;
1229 }
1230 
1239 void QSmf::setTextCodec(QTextCodec *codec)
1240 {
1241  d->m_codec = codec;
1242 }
1243 
1249 {
1250  return QStringLiteral(QT_STRINGIFY(VERSION));
1251 }
1252 
1253 } // namespace File
1254 } // namespace drumstick
1255 
1256 DISABLE_WARNING_POP
The QObject class is the base class of all Qt objects.
int getTracks()
Gets the number of tracks.
Definition: qsmf.cpp:1179
void signalSMFKeyPress(int chan, int pitch, int press)
Emitted after reading a Polyphonic Aftertouch message.
Q_DECL_DEPRECATED void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
Definition: qsmf.cpp:1239
long getRealTime()
Gets the real time in seconds.
Definition: qsmf.cpp:1152
long getCurrentTempo()
Gets the current tempo.
Definition: qsmf.cpp:1143
void signalSMFforcedChannel(int channel)
Emitted after reading a Forced channel message.
void setDivision(int division)
Sets the resolution.
Definition: qsmf.cpp:1170
long getFilePos()
Gets the position in the SMF stream.
Definition: qsmf.cpp:1215
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 signalSMFKeySig(int b0, int b1)
Emitted after reading a SMF Key Signature smessage.
long getCurrentTime()
Gets the current time in ticks.
Definition: qsmf.cpp:1134
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:1188
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
Writes a Time Signature message.
Definition: qsmf.cpp:781
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.
Q_DECL_DEPRECATED void signalSMFText(int typ, const QString &data)
Emitted after reading a SMF text message.
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:1161
QSmf(QObject *parent=nullptr)
Constructor.
Definition: qsmf.cpp:103
void writeToFile(const QString &fileName)
Writes a SMF stream to a disk file.
Definition: qsmf.cpp:475
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:735
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:442
void signalSMFProgram(int chan, int patch)
Emitted after reading a Program change message.
void signalSMFText2(int typ, const QByteArray &data)
Emitted after reading a SMF text 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:534
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.
Q_DECL_DEPRECATED QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
Definition: qsmf.cpp:1226
virtual ~QSmf()
Destructor.
Definition: qsmf.cpp:111
void writeBpmTempo(long deltaTime, int tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:767
void readFromFile(const QString &fileName)
Reads a SMF stream from a disk file.
Definition: qsmf.cpp:452
void signalSMFSysex(const QByteArray &data)
Emitted after reading a System Exclusive message.
void writeToStream(QDataStream *stream)
Writes a SMF stream.
Definition: qsmf.cpp:465
void writeTempo(long deltaTime, long tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:751
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:799
void setFileFormat(int fileFormat)
Sets the SMF file format.
Definition: qsmf.cpp:1206
void signalSMFPitchBend(int chan, int value)
Emitted after reading a Bender message.
int getFileFormat()
Gets the SMF file format.
Definition: qsmf.cpp:1197
void writeMidiEvent(long deltaTime, int type, int chan, int b1)
Writes a MIDI message with a single parameter.
Definition: qsmf.cpp:648
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:70
const quint8 system_exclusive
MIDI event System Exclusive begin.
Definition: qsmf.h:88
const quint8 sequencer_specific
SMF Sequencer specific.
Definition: qsmf.h:78
const quint32 MTrk
SMF Track prefix.
Definition: qsmf.h:59
const quint8 forced_channel
SMF Forced MIDI channel.
Definition: qsmf.h:71
const quint8 midi_channel_mask
Mask to extract the channel from the status byte.
Definition: qsmf.h:92
QString drumstickLibraryVersion()
drumstickLibraryVersion provides the Drumstick version as an edited QString
Definition: qsmf.cpp:1248
const quint8 note_on
MIDI event Note On.
Definition: qsmf.h:82
const quint8 control_change
MIDI event Control change.
Definition: qsmf.h:84
const quint8 note_off
MIDI event Note Off.
Definition: qsmf.h:81
const quint8 smpte_offset
SMF SMPTE offset.
Definition: qsmf.h:75
const quint8 sequence_number
SMF Sequence number.
Definition: qsmf.h:63
const quint8 sequence_name
SMF Sequence name.
Definition: qsmf.h:66
const quint8 pitch_wheel
MIDI event Bender.
Definition: qsmf.h:87
const quint8 meta_event
SMF Meta Event prefix.
Definition: qsmf.h:62
const quint8 time_signature
SMF Time signature.
Definition: qsmf.h:76
const quint8 end_of_track
SMF End of track.
Definition: qsmf.h:73
const quint32 MThd
SMF Header prefix.
Definition: qsmf.h:58
const quint8 poly_aftertouch
MIDI event Polyphonic pressure.
Definition: qsmf.h:83
const quint8 key_signature
SMF Key signature.
Definition: qsmf.h:77
const quint8 text_event
SMF Text event.
Definition: qsmf.h:64
const quint8 channel_aftertouch
MIDI event Channel after-touch.
Definition: qsmf.h:86
const quint8 instrument_name
SMF Instrument name.
Definition: qsmf.h:67
const quint8 marker
SMF Marker.
Definition: qsmf.h:69
const quint8 forced_port
SMF Forced MIDI port.
Definition: qsmf.h:72
const quint8 copyright_notice
SMF Copyright notice.
Definition: qsmf.h:65
const quint8 program_chng
MIDI event Program change.
Definition: qsmf.h:85
const quint8 midi_command_mask
Mask to extract the command from the status byte.
Definition: qsmf.h:91
const quint8 end_of_sysex
MIDI event System Exclusive end.
Definition: qsmf.h:89
const quint8 lyric
SMF Lyric.
Definition: qsmf.h:68
const quint8 set_tempo
SMF Tempo change.
Definition: qsmf.h:74
Drumstick common.
Definition: alsaclient.cpp:68
Standard MIDI Files Input/Output.