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