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 
33 namespace drumstick {
34 
47 class QSmf::QSmfPrivate {
48 public:
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 
98 QSmf::QSmf(QObject * parent) :
99  QObject(parent),
100  d(new QSmfPrivate)
101 { }
102 
107 {
108  d->m_TempoList.clear();
109  delete d;
110 }
111 
116 bool QSmf::endOfSmf()
117 {
118  return d->m_IOStream->atEnd();
119 }
120 
125 quint8 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 
140 void QSmf::putByte(quint8 value)
141 {
142  *d->m_IOStream << value;
143  d->m_NumBytesWritten++;
144 }
145 
151 void 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 
162 void 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 
200 void 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 
395 void QSmf::SMFRead()
396 {
397  int i;
398  readHeader();
399  for ( i = d->m_Tracks; (i > 0) && !endOfSmf(); i--)
400  {
401  readTrack();
402  }
403 }
404 
412 void 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 
432 void QSmf::readFromStream(QDataStream *stream)
433 {
434  d->m_IOStream = stream;
435  SMFRead();
436 }
437 
442 void 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 
455 void QSmf::writeToStream(QDataStream *stream)
456 {
457  d->m_IOStream = stream;
458  SMFWrite();
459 }
460 
465 void 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 
480 void 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 
493 void 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 
524 void 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 
541 void 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 
563 void 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 
577 void 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 
592 void 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 
637 void 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 
666 void 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 
695 void 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 
724 void 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 
740 void 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 
756 void QSmf::writeBpmTempo(long deltaTime, int tempo)
757 {
758  long us_tempo = 60000000l / tempo;
759  writeTempo(deltaTime, us_tempo);
760 }
761 
770 void 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 
788 void 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 
802 void 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. */
825 void 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 
833 void QSmf::write16bit(quint16 data)
834 {
835  putByte((data >> 8) & 0xff);
836  putByte(data & 0xff);
837 }
838 
839 quint16 QSmf::to16bit(quint8 c1, quint8 c2)
840 {
841  quint16 value;
842  value = quint16(c1 << 8);
843  value += c2;
844  return value;
845 }
846 
847 quint32 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 
857 quint16 QSmf::read16bit()
858 {
859  quint8 c1, c2;
860  c1 = getByte();
861  c2 = getByte();
862  return to16bit(c1, c2);
863 }
864 
865 quint32 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 
875 long 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 
894 void 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 
909 quint64 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. */
946 double 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 
966 void QSmf::SMFError(const QString& s)
967 {
968  emit signalSMFError(s);
969 }
970 
971 void 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 
1016 void 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 
1083 void QSmf::sysEx()
1084 {
1085  QByteArray varr(d->m_MsgBuff);
1086  emit signalSMFSysex(varr);
1087 }
1088 
1089 void QSmf::badByte(quint8 b, int p)
1090 {
1091  SMFError(QString("Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1092 }
1093 
1094 quint8 QSmf::lowerByte(quint16 x)
1095 {
1096  return (x & 0xff);
1097 }
1098 
1099 quint8 QSmf::upperByte(quint16 x)
1100 {
1101  return ((x >> 8) & 0xff);
1102 }
1103 
1104 void QSmf::msgInit()
1105 {
1106  d->m_MsgBuff.truncate(0);
1107 }
1108 
1109 void 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 
1158 void QSmf::setDivision(int division)
1159 {
1160  d->m_Division = division;
1161 }
1162 
1168 {
1169  return d->m_Tracks;
1170 }
1171 
1176 void QSmf::setTracks(int tracks)
1177 {
1178  d->m_Tracks = tracks;
1179 }
1180 
1186 {
1187  return d->m_fileFormat;
1188 }
1189 
1194 void QSmf::setFileFormat(int fileFormat)
1195 {
1196  d->m_fileFormat = fileFormat;
1197 }
1198 
1204 {
1205  return long(d->m_IOStream->device()->pos());
1206 }
1207 
1213 QTextCodec* QSmf::getTextCodec()
1214 {
1215  return d->m_codec;
1216 }
1217 
1225 void QSmf::setTextCodec(QTextCodec *codec)
1226 {
1227  d->m_codec = codec;
1228 }
1229 
1230 }
QSmf(QObject *parent=nullptr)
Constructor.
Definition: qsmf.cpp:98
void signalSMFNoteOff(int chan, int pitch, int vol)
Emitted after reading a Note Off message.
Definition: moc_qsmf.cpp:463
void signalSMFSeqSpecific(const QByteArray &data)
Emitted after reading a Sequencer specific message.
Definition: moc_qsmf.cpp:512
long getRealTime()
Gets the real time in seconds.
Definition: qsmf.cpp:1140
#define forced_port
SMF Forced MIDI port.
Definition: qsmf.h:52
void writeTempo(long deltaTime, long tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:740
#define midi_command_mask
Mask to extract the command from the status byte.
Definition: qsmf.h:71
void signalSMFHeader(int format, int ntrks, int division)
Emitted after reading a SMF header.
Definition: moc_qsmf.cpp:449
#define forced_channel
SMF Forced MIDI channel.
Definition: qsmf.h:51
void signalSMFforcedPort(int port)
Emitted after reading a Forced port message.
Definition: moc_qsmf.cpp:547
void writeToStream(QDataStream *stream)
Writes a SMF stream.
Definition: qsmf.cpp:455
void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
Definition: qsmf.cpp:1225
#define marker
SMF Marker.
Definition: qsmf.h:49
#define channel_aftertouch
MIDI event Channel after-touch.
Definition: qsmf.h:66
long getCurrentTime()
Gets the current time in ticks.
Definition: qsmf.cpp:1122
void signalSMFText(int typ, const QString &data)
Emitted after reading a SMF text message.
Definition: moc_qsmf.cpp:554
The QObject class is the base class of all Qt objects.
void signalSMFTrackStart()
Emitted after reading a track prefix.
Definition: moc_qsmf.cpp:595
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
Writes a Time Signature message.
Definition: qsmf.cpp:770
#define key_signature
SMF Key signature.
Definition: qsmf.h:57
void signalSMFforcedChannel(int channel)
Emitted after reading a Forced channel message.
Definition: moc_qsmf.cpp:540
int getTracks()
Gets the number of tracks.
Definition: qsmf.cpp:1167
void signalSMFSmpte(int b0, int b1, int b2, int b3, int b4)
Emitted after reading a SMPT offset message.
Definition: moc_qsmf.cpp:561
void signalSMFWriteTrack(int track)
Emitted to request the user to write a track.
Definition: moc_qsmf.cpp:613
long getFilePos()
Gets the position in the SMF stream.
Definition: qsmf.cpp:1203
void setTracks(int tracks)
Sets the number of tracks.
Definition: qsmf.cpp:1176
#define control_change
MIDI event Control change.
Definition: qsmf.h:64
long getCurrentTempo()
Gets the current tempo.
Definition: qsmf.cpp:1131
void signalSMFPitchBend(int chan, int value)
Emitted after reading a Bender message.
Definition: moc_qsmf.cpp:484
void signalSMFProgram(int chan, int patch)
Emitted after reading a Program change message.
Definition: moc_qsmf.cpp:491
void signalSMFError(const QString &errorStr)
Emitted for a SMF read or write error.
Definition: moc_qsmf.cpp:442
#define sequencer_specific
SMF Sequencer specific.
Definition: qsmf.h:58
#define MTrk
SMF Track prefix.
Definition: qsmf.h:39
virtual ~QSmf()
Destructor.
Definition: qsmf.cpp:106
void writeToFile(const QString &fileName)
Writes a SMF stream to a disk file.
Definition: qsmf.cpp:465
void signalSMFKeyPress(int chan, int pitch, int press)
Emitted after reading a Polyphonic Aftertouch message.
Definition: moc_qsmf.cpp:470
void signalSMFNoteOn(int chan, int pitch, int vol)
Emitted after reading a Note On message.
Definition: moc_qsmf.cpp:456
void readFromStream(QDataStream *stream)
Reads a SMF stream.
Definition: qsmf.cpp:432
#define time_signature
SMF Time signature.
Definition: qsmf.h:56
#define smpte_offset
SMF SMPTE offset.
Definition: qsmf.h:55
void writeKeySignature(long deltaTime, int tone, int mode)
Writes a key Signature message.
Definition: qsmf.cpp:788
void signalSMFSequenceNum(int seq)
Emitted after reading a Sequence number message.
Definition: moc_qsmf.cpp:533
void signalSMFSysex(const QByteArray &data)
Emitted after reading a System Exclusive message.
Definition: moc_qsmf.cpp:505
int getFileFormat()
Gets the SMF file format.
Definition: qsmf.cpp:1185
#define end_of_track
SMF End of track.
Definition: qsmf.h:53
void signalSMFKeySig(int b0, int b1)
Emitted after reading a SMF Key Signature smessage.
Definition: moc_qsmf.cpp:575
#define sequence_number
SMF Sequence number.
Definition: qsmf.h:43
void signalSMFTempo(int tempo)
Emitted after reading a Tempo Change message.
Definition: moc_qsmf.cpp:582
void signalSMFWriteTempoTrack()
Emitted to request the user to write the tempo track.
Definition: moc_qsmf.cpp:607
#define text_event
SMF Text event.
Definition: qsmf.h:44
#define note_off
MIDI event Note Off.
Definition: qsmf.h:61
void signalSMFTrackEnd()
Emitted after a track has finished.
Definition: moc_qsmf.cpp:601
#define poly_aftertouch
MIDI event Polyphonic pressure.
Definition: qsmf.h:63
#define end_of_sysex
MIDI event System Exclusive end.
Definition: qsmf.h:69
void signalSMFChanPress(int chan, int press)
Emitted after reading a Channel Aftertouch message.
Definition: moc_qsmf.cpp:498
#define meta_event
SMF Meta Event prefix.
Definition: qsmf.h:42
#define pitch_wheel
MIDI event Bender.
Definition: qsmf.h:67
void signalSMFMetaMisc(int typ, const QByteArray &data)
Emitted after reading any SMF Meta message.
Definition: moc_qsmf.cpp:526
QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
Definition: qsmf.cpp:1213
void signalSMFMetaUnregistered(int typ, const QByteArray &data)
Emitted after reading an unregistered SMF Meta message.
Definition: moc_qsmf.cpp:519
#define set_tempo
SMF Tempo change.
Definition: qsmf.h:54
void writeSequenceNumber(long deltaTime, int seqnum)
Writes a MIDI Sequence number.
Definition: qsmf.cpp:724
#define instrument_name
SMF Instrument name.
Definition: qsmf.h:47
void setDivision(int division)
Sets the resolution.
Definition: qsmf.cpp:1158
void writeMidiEvent(long deltaTime, int type, int chan, int b1)
Writes a MIDI message with a single parameter.
Definition: qsmf.cpp:637
void signalSMFTimeSig(int b0, int b1, int b2, int b3)
Emitted after reading a SMF Time signature message.
Definition: moc_qsmf.cpp:568
#define lyric
SMF Lyric.
Definition: qsmf.h:48
void writeMetaEvent(long deltaTime, int type, const QByteArray &data)
Writes a variable length Meta Event.
Definition: qsmf.cpp:524
#define midi_channel_mask
Mask to extract the channel from the status byte.
Definition: qsmf.h:72
void signalSMFCtlChange(int chan, int ctl, int value)
Emitted after reading a Control Change message.
Definition: moc_qsmf.cpp:477
void readFromFile(const QString &fileName)
Reads a SMF stream from a disk file.
Definition: qsmf.cpp:442
void writeBpmTempo(long deltaTime, int tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:756
void signalSMFendOfTrack()
Emitted after reading a End-Of-Track message.
Definition: moc_qsmf.cpp:589
#define note_on
MIDI event Note On.
Definition: qsmf.h:62
#define system_exclusive
MIDI event System Exclusive begin.
Definition: qsmf.h:68
#define cue_point
SMF Cue point.
Definition: qsmf.h:50
void setFileFormat(int fileFormat)
Sets the SMF file format.
Definition: qsmf.cpp:1194
#define program_chng
MIDI event Program change.
Definition: qsmf.h:65
#define sequence_name
SMF Sequence name.
Definition: qsmf.h:46
Standard MIDI Files Input/Output.
int getDivision()
Gets the resolution.
Definition: qsmf.cpp:1149
#define MThd
SMF Header prefix.
Definition: qsmf.h:38
#define copyright_notice
SMF Copyright notice.
Definition: qsmf.h:45