drumstick  2.1.0
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  int i, j, size;
597  quint8 c;
598  writeVarLen(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  if (type == system_exclusive || type == end_of_sysex)
618  {
619  size = data.size();
620  if (data[0] == type)
621  --size;
622  writeVarLen(size);
623  }
624  j = (data[0] == type ? 1 : 0);
625  for (i = j; i < data.size(); ++i)
626  {
627  putByte(data[i]);
628  }
629 }
630 
638 void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1)
639 {
640  quint8 c;
641  writeVarLen(deltaTime);
642  if ((type == system_exclusive) || (type == end_of_sysex))
643  {
644  SMFError("error: Wrong method for a system exclusive event");
645  }
646  if (chan > 15)
647  {
648  SMFError("error: MIDI channel greater than 16");
649  }
650  c = type | chan;
651  if (d->m_LastStatus != c)
652  {
653  d->m_LastStatus = c;
654  putByte(c);
655  }
656  putByte(b1);
657 }
658 
667 void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1, int b2)
668 {
669  quint8 c;
670  writeVarLen(deltaTime);
671  if ((type == system_exclusive) || (type == end_of_sysex))
672  {
673  SMFError("error: Wrong method for a system exclusive event");
674  }
675  if (chan > 15)
676  {
677  SMFError("error: MIDI channel greater than 16");
678  }
679  c = type | chan;
680  if (d->m_LastStatus != c)
681  {
682  d->m_LastStatus = c;
683  putByte(c);
684  }
685  putByte(b1);
686  putByte(b2);
687 }
688 
696 void QSmf::writeMidiEvent(long deltaTime, int type, long len, char* data)
697 {
698  unsigned int i, j, size;
699  quint8 c;
700  writeVarLen(quint64(deltaTime));
701  if ((type != system_exclusive) && (type != end_of_sysex))
702  {
703  SMFError("error: type should be system exclusive");
704  }
705  d->m_LastStatus = 0;
706  c = quint8(type);
707  putByte(c);
708  size = unsigned(len);
709  c = quint8(data[0]);
710  if (c == type)
711  --size;
712  writeVarLen(size);
713  j = (c == type ? 1 : 0);
714  for (i = j; i < unsigned(len); ++i)
715  {
716  putByte(quint8(data[i]));
717  }
718 }
719 
725 void QSmf::writeSequenceNumber(long deltaTime, int seqnum)
726 {
727  writeVarLen(deltaTime);
728  d->m_LastStatus = meta_event;
729  putByte(d->m_LastStatus);
730  putByte(sequence_number);
731  putByte(2);
732  putByte((seqnum >> 8) & 0xff);
733  putByte(seqnum & 0xff);
734 }
735 
741 void QSmf::writeTempo(long deltaTime, long tempo)
742 {
743  writeVarLen(deltaTime);
744  putByte(d->m_LastStatus = meta_event);
745  putByte(set_tempo);
746  putByte(3);
747  putByte((tempo >> 16) & 0xff);
748  putByte((tempo >> 8) & 0xff);
749  putByte(tempo & 0xff);
750 }
751 
757 void QSmf::writeBpmTempo(long deltaTime, int tempo)
758 {
759  long us_tempo = 60000000l / tempo;
760  writeTempo(deltaTime, us_tempo);
761 }
762 
771 void QSmf::writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
772 {
773  writeVarLen(deltaTime);
774  putByte(d->m_LastStatus = meta_event);
775  putByte(time_signature);
776  putByte(4);
777  putByte(num & 0xff);
778  putByte(den & 0xff);
779  putByte(cc & 0xff);
780  putByte(bb & 0xff);
781 }
782 
789 void QSmf::writeKeySignature(long deltaTime, int tone, int mode)
790 {
791  writeVarLen(quint64(deltaTime));
792  putByte(d->m_LastStatus = meta_event);
793  putByte(key_signature);
794  putByte(2);
795  putByte(quint8(tone));
796  putByte(mode & 0x01);
797 }
798 
803 void QSmf::writeVarLen(quint64 value)
804 {
805  quint64 buffer;
806 
807  buffer = value & 0x7f;
808  while ((value >>= 7) > 0)
809  {
810  buffer <<= 8;
811  buffer |= 0x80;
812  buffer += (value & 0x7f);
813  }
814  while (true)
815  {
816  putByte(buffer & 0xff);
817  if (buffer & 0x80)
818  buffer >>= 8;
819  else
820  break;
821  }
822 }
823 
824 /* These routines are used to make sure that the byte order of
825  the various data types remains constant between machines. */
826 void QSmf::write32bit(quint32 data)
827 {
828  putByte((data >> 24) & 0xff);
829  putByte((data >> 16) & 0xff);
830  putByte((data >> 8) & 0xff);
831  putByte(data & 0xff);
832 }
833 
834 void QSmf::write16bit(quint16 data)
835 {
836  putByte((data >> 8) & 0xff);
837  putByte(data & 0xff);
838 }
839 
840 quint16 QSmf::to16bit(quint8 c1, quint8 c2)
841 {
842  quint16 value;
843  value = quint16(c1 << 8);
844  value += c2;
845  return value;
846 }
847 
848 quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
849 {
850  quint32 value;
851  value = unsigned(c1 << 24);
852  value += unsigned(c2 << 16);
853  value += unsigned(c3 << 8);
854  value += c4;
855  return value;
856 }
857 
858 quint16 QSmf::read16bit()
859 {
860  quint8 c1, c2;
861  c1 = getByte();
862  c2 = getByte();
863  return to16bit(c1, c2);
864 }
865 
866 quint32 QSmf::read32bit()
867 {
868  quint8 c1, c2, c3, c4;
869  c1 = getByte();
870  c2 = getByte();
871  c3 = getByte();
872  c4 = getByte();
873  return to32bit(c1, c2, c3, c4);
874 }
875 
876 long QSmf::readVarLen()
877 {
878  quint64 value;
879  quint8 c;
880 
881  c = getByte();
882  value = c;
883  if ((c & 0x80) != 0)
884  {
885  value &= 0x7f;
886  do
887  {
888  c = getByte();
889  value = (value << 7) + (c & 0x7f);
890  } while ((c & 0x80) != 0);
891  }
892  return long(value);
893 }
894 
895 void QSmf::readExpected(const QString& s)
896 {
897  int j;
898  quint8 b;
899  for (j = 0; j < s.length(); ++j)
900  {
901  b = getByte();
902  if (QChar(b) != s[j])
903  {
904  SMFError(QString("Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
905  break;
906  }
907  }
908 }
909 
910 quint64 QSmf::findTempo()
911 {
912  quint64 result, old_tempo, new_tempo;
913  QSmfRecTempo rec = d->m_TempoList.last();
914  old_tempo = d->m_CurrTempo;
915  new_tempo = d->m_CurrTempo;
916  QList<QSmfRecTempo>::Iterator it;
917  for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
918  {
919  rec = (*it);
920  if (rec.time <= d->m_CurrTime)
921  {
922  old_tempo = rec.tempo;
923  }
924  new_tempo = rec.tempo;
925  if (rec.time > d->m_RevisedTime)
926  {
927  break;
928  }
929  }
930  if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
931  {
932  d->m_RevisedTime = d->m_CurrTime;
933  result = old_tempo;
934  }
935  else
936  {
937  d->m_RevisedTime = rec.time;
938  d->m_TempoChangeTime = d->m_RevisedTime;
939  result = new_tempo;
940  }
941  return result;
942 }
943 
944 /* This routine converts delta times in ticks into seconds. The
945  else statement is needed because the formula is different for tracks
946  based on notes and tracks based on SMPTE times. */
947 double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
948 {
949  double result;
950  double smpte_format;
951  double smpte_resolution;
952 
953  if (division > 0)
954  {
955  result = double(ticks * tempo)/(division * 1000000.0);
956  }
957  else
958  {
959  smpte_format = upperByte(division);
960  smpte_resolution = lowerByte(division);
961  result = double(ticks)/(smpte_format * smpte_resolution
962  * 1000000.0);
963  }
964  return result;
965 }
966 
967 void QSmf::SMFError(const QString& s)
968 {
969  emit signalSMFError(s);
970 }
971 
972 void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
973 {
974  quint8 chan;
975  int k;
976  chan = status & midi_channel_mask;
977  if (c1 > 127)
978  {
979  SMFError(QString("ChannelMessage with bad c1 = %1").arg(c1));
980  //c1 &= 127;
981  }
982  if (c2 > 127)
983  {
984  SMFError(QString("ChannelMessage with bad c2 = %1").arg(c2));
985  //c2 &= 127;
986  }
987  switch (status & midi_command_mask)
988  {
989  case note_off:
990  emit signalSMFNoteOff(chan, c1, c2);
991  break;
992  case note_on:
993  emit signalSMFNoteOn(chan, c1, c2);
994  break;
995  case poly_aftertouch:
996  emit signalSMFKeyPress(chan, c1, c2);
997  break;
998  case control_change:
999  emit signalSMFCtlChange(chan, c1, c2);
1000  break;
1001  case program_chng:
1002  emit signalSMFProgram(chan, c1);
1003  break;
1004  case channel_aftertouch:
1005  emit signalSMFChanPress(chan, c1);
1006  break;
1007  case pitch_wheel:
1008  k = c1 + (c2 << 7) - 8192;
1009  emit signalSMFPitchBend(chan, k);
1010  break;
1011  default:
1012  SMFError(QString("Invalid MIDI status %1. Unhandled event").arg(status));
1013  break;
1014  }
1015 }
1016 
1017 void QSmf::metaEvent(quint8 b)
1018 {
1019  QSmfRecTempo rec;
1020  QByteArray m(d->m_MsgBuff);
1021 
1022  switch (b)
1023  {
1024  case sequence_number:
1025  emit signalSMFSequenceNum(to16bit(m[0], m[1]));
1026  break;
1027  case text_event:
1028  case copyright_notice:
1029  case sequence_name:
1030  case instrument_name:
1031  case lyric:
1032  case marker:
1033  case cue_point: {
1034  QString s;
1035  if (d->m_codec == nullptr)
1036  s = QString(m);
1037  else
1038  s = d->m_codec->toUnicode(m);
1039  emit signalSMFText(b, s);
1040  }
1041  break;
1042  case forced_channel:
1043  emit signalSMFforcedChannel(m[0]);
1044  break;
1045  case forced_port:
1046  emit signalSMFforcedPort(m[0]);
1047  break;
1048  case end_of_track:
1049  emit signalSMFendOfTrack();
1050  break;
1051  case set_tempo:
1052  d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
1053  emit signalSMFTempo(d->m_CurrTempo);
1054  rec = d->m_TempoList.last();
1055  if (rec.tempo == d->m_CurrTempo)
1056  {
1057  return;
1058  }
1059  if (rec.time > d->m_CurrTime)
1060  {
1061  return;
1062  }
1063  addTempo(d->m_CurrTempo, d->m_CurrTime);
1064  break;
1065  case smpte_offset:
1066  emit signalSMFSmpte(m[0], m[1], m[2], m[3], m[4]);
1067  break;
1068  case time_signature:
1069  emit signalSMFTimeSig(m[0], m[1], m[2], m[3]);
1070  break;
1071  case key_signature:
1072  emit signalSMFKeySig(m[0], m[1]);
1073  break;
1074  case sequencer_specific:
1075  emit signalSMFSeqSpecific(m);
1076  break;
1077  default:
1078  emit signalSMFMetaUnregistered(b, m);
1079  break;
1080  }
1081  emit signalSMFMetaMisc(b, m);
1082 }
1083 
1084 void QSmf::sysEx()
1085 {
1086  QByteArray varr(d->m_MsgBuff);
1087  emit signalSMFSysex(varr);
1088 }
1089 
1090 void QSmf::badByte(quint8 b, int p)
1091 {
1092  SMFError(QString("Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1093 }
1094 
1095 quint8 QSmf::lowerByte(quint16 x)
1096 {
1097  return (x & 0xff);
1098 }
1099 
1100 quint8 QSmf::upperByte(quint16 x)
1101 {
1102  return ((x >> 8) & 0xff);
1103 }
1104 
1105 void QSmf::msgInit()
1106 {
1107  d->m_MsgBuff.truncate(0);
1108 }
1109 
1110 void QSmf::msgAdd(quint8 b)
1111 {
1112  int s = d->m_MsgBuff.size();
1113  d->m_MsgBuff.resize(s + 1);
1114  d->m_MsgBuff[s] = b;
1115 }
1116 
1117 /* public properties (accessors) */
1118 
1124 {
1125  return d->m_CurrTime;
1126 }
1127 
1133 {
1134  return d->m_CurrTempo;
1135 }
1136 
1142 {
1143  return d->m_RealTime;
1144 }
1145 
1151 {
1152  return d->m_Division;
1153 }
1154 
1159 void QSmf::setDivision(int division)
1160 {
1161  d->m_Division = division;
1162 }
1163 
1169 {
1170  return d->m_Tracks;
1171 }
1172 
1177 void QSmf::setTracks(int tracks)
1178 {
1179  d->m_Tracks = tracks;
1180 }
1181 
1187 {
1188  return d->m_fileFormat;
1189 }
1190 
1195 void QSmf::setFileFormat(int fileFormat)
1196 {
1197  d->m_fileFormat = fileFormat;
1198 }
1199 
1205 {
1206  return long(d->m_IOStream->device()->pos());
1207 }
1208 
1214 QTextCodec* QSmf::getTextCodec()
1215 {
1216  return d->m_codec;
1217 }
1218 
1226 void QSmf::setTextCodec(QTextCodec *codec)
1227 {
1228  d->m_codec = codec;
1229 }
1230 
1231 } // namespace File
1232 } // namespace drumstick
The QObject class is the base class of all Qt objects.
int getTracks()
Gets the number of tracks.
Definition: qsmf.cpp:1168
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:1226
long getRealTime()
Gets the real time in seconds.
Definition: qsmf.cpp:1141
long getCurrentTempo()
Gets the current tempo.
Definition: qsmf.cpp:1132
void signalSMFforcedChannel(int channel)
Emitted after reading a Forced channel message.
void setDivision(int division)
Sets the resolution.
Definition: qsmf.cpp:1159
long getFilePos()
Gets the position in the SMF stream.
Definition: qsmf.cpp:1204
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:1123
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:1177
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
Writes a Time Signature message.
Definition: qsmf.cpp:771
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:1150
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 write the tempo track.
void signalSMFendOfTrack()
Emitted after reading a End-Of-Track message.
void writeSequenceNumber(long deltaTime, int seqnum)
Writes a MIDI Sequence number.
Definition: qsmf.cpp:725
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:1214
virtual ~QSmf()
Destructor.
Definition: qsmf.cpp:108
void writeBpmTempo(long deltaTime, int tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:757
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:741
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:789
void setFileFormat(int fileFormat)
Sets the SMF file format.
Definition: qsmf.cpp:1195
void signalSMFPitchBend(int chan, int value)
Emitted after reading a Bender message.
int getFileFormat()
Gets the SMF file format.
Definition: qsmf.cpp:1186
void writeMidiEvent(long deltaTime, int type, int chan, int b1)
Writes a MIDI message with a single parameter.
Definition: qsmf.cpp:638
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:59
const quint8 system_exclusive
MIDI event System Exclusive begin.
Definition: qsmf.h:77
const quint8 sequencer_specific
SMF Sequencer specific.
Definition: qsmf.h:67
const quint32 MTrk
SMF Track prefix.
Definition: qsmf.h:48
const quint8 forced_channel
SMF Forced MIDI channel.
Definition: qsmf.h:60
const quint8 midi_channel_mask
Mask to extract the channel from the status byte.
Definition: qsmf.h:81
const quint8 note_on
MIDI event Note On.
Definition: qsmf.h:71
const quint8 control_change
MIDI event Control change.
Definition: qsmf.h:73
const quint8 note_off
MIDI event Note Off.
Definition: qsmf.h:70
const quint8 smpte_offset
SMF SMPTE offset.
Definition: qsmf.h:64
const quint8 sequence_number
SMF Sequence number.
Definition: qsmf.h:52
const quint8 sequence_name
SMF Sequence name.
Definition: qsmf.h:55
const quint8 pitch_wheel
MIDI event Bender.
Definition: qsmf.h:76
const quint8 meta_event
SMF Meta Event prefix.
Definition: qsmf.h:51
const quint8 time_signature
SMF Time signature.
Definition: qsmf.h:65
const quint8 end_of_track
SMF End of track.
Definition: qsmf.h:62
const quint32 MThd
SMF Header prefix.
Definition: qsmf.h:47
const quint8 poly_aftertouch
MIDI event Polyphonic pressure.
Definition: qsmf.h:72
const quint8 key_signature
SMF Key signature.
Definition: qsmf.h:66
const quint8 text_event
SMF Text event.
Definition: qsmf.h:53
const quint8 channel_aftertouch
MIDI event Channel after-touch.
Definition: qsmf.h:75
const quint8 instrument_name
SMF Instrument name.
Definition: qsmf.h:56
const quint8 marker
SMF Marker.
Definition: qsmf.h:58
const quint8 forced_port
SMF Forced MIDI port.
Definition: qsmf.h:61
const quint8 copyright_notice
SMF Copyright notice.
Definition: qsmf.h:54
const quint8 program_chng
MIDI event Program change.
Definition: qsmf.h:74
const quint8 midi_command_mask
Mask to extract the command from the status byte.
Definition: qsmf.h:80
const quint8 end_of_sysex
MIDI event System Exclusive end.
Definition: qsmf.h:78
const quint8 lyric
SMF Lyric.
Definition: qsmf.h:57
const quint8 set_tempo
SMF Tempo change.
Definition: qsmf.h:63
Drumstick common.
Definition: alsaclient.cpp:68
Standard MIDI Files Input/Output.