drumstick  2.5.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 
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  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; // 1 if last message was an unfinished SysEx
215  bool running; // 1 when running status 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  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  {
390  SMFError("Unexpected end of input");
391  }
392  }
393  emit signalSMFTrackEnd();
394 }
395 
399 void QSmf::SMFRead()
400 {
401  int i;
402  readHeader();
403  for ( i = d->m_Tracks; (i > 0) && !endOfSmf(); i--)
404  {
405  readTrack();
406  }
407 }
408 
416 void QSmf::SMFWrite()
417 {
418  int i;
419  d->m_LastStatus = 0;
420  writeHeaderChunk(d->m_fileFormat, d->m_Tracks, d->m_Division);
421  d->m_LastStatus = 0;
422  if (d->m_fileFormat == 1)
423  {
425  }
426  for (i = 0; i < d->m_Tracks; ++i)
427  {
428  writeTrackChunk(i);
429  }
430 }
431 
436 void QSmf::readFromStream(QDataStream *stream)
437 {
438  d->m_IOStream = stream;
439  SMFRead();
440 }
441 
446 void QSmf::readFromFile(const QString& fileName)
447 {
448  QFile file(fileName);
449  file.open(QIODevice::ReadOnly);
450  QDataStream ds(&file);
451  readFromStream(&ds);
452  file.close();
453 }
454 
459 void QSmf::writeToStream(QDataStream *stream)
460 {
461  d->m_IOStream = stream;
462  SMFWrite();
463 }
464 
469 void QSmf::writeToFile(const QString& fileName)
470 {
471  QFile file(fileName);
472  file.open(QIODevice::WriteOnly);
473  QDataStream ds(&file);
474  writeToStream(&ds);
475  file.close();
476 }
477 
484 void QSmf::writeHeaderChunk(int format, int ntracks, int division)
485 {
486  write32bit(MThd);
487  write32bit(6);
488  write16bit(quint16(format));
489  write16bit(quint16(ntracks));
490  write16bit(quint16(division));
491 }
492 
497 void QSmf::writeTrackChunk(int track)
498 {
499  quint32 trkhdr;
500  quint32 trklength;
501  qint64 offset;
502  qint64 place_marker;
503 
504  d->m_LastStatus = 0;
505  trkhdr = MTrk;
506  trklength = 0;
507  offset = d->m_IOStream->device()->pos();
508  write32bit(trkhdr);
509  write32bit(trklength);
510  d->m_NumBytesWritten = 0;
511 
512  emit signalSMFWriteTrack(track);
513 
514  place_marker = d->m_IOStream->device()->pos();
515  d->m_IOStream->device()->seek(offset);
516  trklength = d->m_NumBytesWritten;
517  write32bit(trkhdr);
518  write32bit(trklength);
519  d->m_IOStream->device()->seek(place_marker);
520 }
521 
528 void QSmf::writeMetaEvent(long deltaTime, int type, const QByteArray& data)
529 {
530  writeVarLen(deltaTime);
531  d->m_LastStatus = meta_event;
532  putByte(d->m_LastStatus);
533  putByte(type);
534  writeVarLen(data.size());
535  foreach(char byte, data)
536  putByte(byte);
537 }
538 
545 void QSmf::writeMetaEvent(long deltaTime, int type, const QString& data)
546 {
547  writeVarLen(deltaTime);
548  putByte(d->m_LastStatus = meta_event);
549  putByte(type);
550  QByteArray lcldata;
551  if (d->m_codec == nullptr)
552  lcldata = data.toLatin1();
553  else
554  lcldata = d->m_codec->fromUnicode(data);
555  writeVarLen(lcldata.length());
556  foreach(char byte, lcldata)
557  putByte(byte);
558 }
559 
567 void QSmf::writeMetaEvent(long deltaTime, int type, int data)
568 {
569  writeVarLen(deltaTime);
570  putByte(d->m_LastStatus = meta_event);
571  putByte(type);
572  putByte(1);
573  putByte(data);
574 }
575 
581 void QSmf::writeMetaEvent(long deltaTime, int type)
582 {
583  writeVarLen(deltaTime);
584  putByte(d->m_LastStatus = meta_event);
585  putByte(type);
586  putByte(0);
587 }
588 
596 void QSmf::writeMidiEvent(long deltaTime, int type, int chan,
597  const QByteArray& data)
598 {
599  unsigned int i, j, size;
600  quint8 c;
601  writeVarLen(quint64(deltaTime));
602  if ((type == system_exclusive) || (type == end_of_sysex))
603  {
604  c = type;
605  d->m_LastStatus = 0;
606  }
607  else
608  {
609  if (chan > 15)
610  {
611  SMFError("error: MIDI channel greater than 16");
612  }
613  c = type | chan;
614  }
615  if (d->m_LastStatus != c)
616  {
617  d->m_LastStatus = c;
618  putByte(c);
619  }
620  c = quint8(data[0]);
621  if (type == system_exclusive || type == end_of_sysex)
622  {
623  size = data.size();
624  if (type == c)
625  --size;
626  writeVarLen(size);
627  }
628  j = (c == type ? 1 : 0);
629  for (i = j; i < unsigned(data.size()); ++i)
630  {
631  putByte(quint8(data[i]));
632  }
633 }
634 
642 void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1)
643 {
644  quint8 c;
645  writeVarLen(deltaTime);
646  if ((type == system_exclusive) || (type == end_of_sysex))
647  {
648  SMFError("error: Wrong method for a system exclusive event");
649  }
650  if (chan > 15)
651  {
652  SMFError("error: MIDI channel greater than 16");
653  }
654  c = type | chan;
655  if (d->m_LastStatus != c)
656  {
657  d->m_LastStatus = c;
658  putByte(c);
659  }
660  putByte(b1);
661 }
662 
671 void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1, int b2)
672 {
673  quint8 c;
674  writeVarLen(deltaTime);
675  if ((type == system_exclusive) || (type == end_of_sysex))
676  {
677  SMFError("error: Wrong method for a system exclusive event");
678  }
679  if (chan > 15)
680  {
681  SMFError("error: MIDI channel greater than 16");
682  }
683  c = type | chan;
684  if (d->m_LastStatus != c)
685  {
686  d->m_LastStatus = c;
687  putByte(c);
688  }
689  putByte(b1);
690  putByte(b2);
691 }
692 
700 void QSmf::writeMidiEvent(long deltaTime, int type, long len, char* data)
701 {
702  unsigned int i, j, size;
703  quint8 c;
704  writeVarLen(quint64(deltaTime));
705  if ((type != system_exclusive) && (type != end_of_sysex))
706  {
707  SMFError("error: type should be system exclusive");
708  }
709  d->m_LastStatus = 0;
710  c = quint8(type);
711  putByte(c);
712  size = unsigned(len);
713  c = quint8(data[0]);
714  if (c == type)
715  --size;
716  writeVarLen(size);
717  j = (c == type ? 1 : 0);
718  for (i = j; i < unsigned(len); ++i)
719  {
720  putByte(quint8(data[i]));
721  }
722 }
723 
729 void QSmf::writeSequenceNumber(long deltaTime, int seqnum)
730 {
731  writeVarLen(deltaTime);
732  d->m_LastStatus = meta_event;
733  putByte(d->m_LastStatus);
734  putByte(sequence_number);
735  putByte(2);
736  putByte((seqnum >> 8) & 0xff);
737  putByte(seqnum & 0xff);
738 }
739 
745 void QSmf::writeTempo(long deltaTime, long tempo)
746 {
747  writeVarLen(deltaTime);
748  putByte(d->m_LastStatus = meta_event);
749  putByte(set_tempo);
750  putByte(3);
751  putByte((tempo >> 16) & 0xff);
752  putByte((tempo >> 8) & 0xff);
753  putByte(tempo & 0xff);
754 }
755 
761 void QSmf::writeBpmTempo(long deltaTime, int tempo)
762 {
763  long us_tempo = 60000000l / tempo;
764  writeTempo(deltaTime, us_tempo);
765 }
766 
775 void QSmf::writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
776 {
777  writeVarLen(deltaTime);
778  putByte(d->m_LastStatus = meta_event);
779  putByte(time_signature);
780  putByte(4);
781  putByte(num & 0xff);
782  putByte(den & 0xff);
783  putByte(cc & 0xff);
784  putByte(bb & 0xff);
785 }
786 
793 void QSmf::writeKeySignature(long deltaTime, int tone, int mode)
794 {
795  writeVarLen(quint64(deltaTime));
796  putByte(d->m_LastStatus = meta_event);
797  putByte(key_signature);
798  putByte(2);
799  putByte(quint8(tone));
800  putByte(mode & 0x01);
801 }
802 
807 void QSmf::writeVarLen(quint64 value)
808 {
809  quint64 buffer;
810 
811  buffer = value & 0x7f;
812  while ((value >>= 7) > 0)
813  {
814  buffer <<= 8;
815  buffer |= 0x80;
816  buffer += (value & 0x7f);
817  }
818  while (true)
819  {
820  putByte(buffer & 0xff);
821  if (buffer & 0x80)
822  buffer >>= 8;
823  else
824  break;
825  }
826 }
827 
828 /* These routines are used to make sure that the byte order of
829  the various data types remains constant between machines. */
830 void QSmf::write32bit(quint32 data)
831 {
832  putByte((data >> 24) & 0xff);
833  putByte((data >> 16) & 0xff);
834  putByte((data >> 8) & 0xff);
835  putByte(data & 0xff);
836 }
837 
838 void QSmf::write16bit(quint16 data)
839 {
840  putByte((data >> 8) & 0xff);
841  putByte(data & 0xff);
842 }
843 
844 quint16 QSmf::to16bit(quint8 c1, quint8 c2)
845 {
846  quint16 value;
847  value = quint16(c1 << 8);
848  value += c2;
849  return value;
850 }
851 
852 quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
853 {
854  quint32 value;
855  value = unsigned(c1 << 24);
856  value += unsigned(c2 << 16);
857  value += unsigned(c3 << 8);
858  value += c4;
859  return value;
860 }
861 
862 quint16 QSmf::read16bit()
863 {
864  quint8 c1, c2;
865  c1 = getByte();
866  c2 = getByte();
867  return to16bit(c1, c2);
868 }
869 
870 quint32 QSmf::read32bit()
871 {
872  quint8 c1, c2, c3, c4;
873  c1 = getByte();
874  c2 = getByte();
875  c3 = getByte();
876  c4 = getByte();
877  return to32bit(c1, c2, c3, c4);
878 }
879 
880 long QSmf::readVarLen()
881 {
882  quint64 value;
883  quint8 c;
884 
885  c = getByte();
886  value = c;
887  if ((c & 0x80) != 0)
888  {
889  value &= 0x7f;
890  do
891  {
892  c = getByte();
893  value = (value << 7) + (c & 0x7f);
894  } while ((c & 0x80) != 0);
895  }
896  return long(value);
897 }
898 
899 void QSmf::readExpected(const QString& s)
900 {
901  int j;
902  quint8 b;
903  for (j = 0; j < s.length(); ++j)
904  {
905  b = getByte();
906  if (QChar(b) != s[j])
907  {
908  SMFError(QString("Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
909  break;
910  }
911  }
912 }
913 
914 quint64 QSmf::findTempo()
915 {
916  quint64 result, old_tempo, new_tempo;
917  QSmfRecTempo rec = d->m_TempoList.last();
918  old_tempo = d->m_CurrTempo;
919  new_tempo = d->m_CurrTempo;
920  QList<QSmfRecTempo>::Iterator it;
921  for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
922  {
923  rec = (*it);
924  if (rec.time <= d->m_CurrTime)
925  {
926  old_tempo = rec.tempo;
927  }
928  new_tempo = rec.tempo;
929  if (rec.time > d->m_RevisedTime)
930  {
931  break;
932  }
933  }
934  if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
935  {
936  d->m_RevisedTime = d->m_CurrTime;
937  result = old_tempo;
938  }
939  else
940  {
941  d->m_RevisedTime = rec.time;
942  d->m_TempoChangeTime = d->m_RevisedTime;
943  result = new_tempo;
944  }
945  return result;
946 }
947 
948 /* This routine converts delta times in ticks into seconds. The
949  else statement is needed because the formula is different for tracks
950  based on notes and tracks based on SMPTE times. */
951 double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
952 {
953  double result;
954  double smpte_format;
955  double smpte_resolution;
956 
957  if (division > 0)
958  {
959  result = double(ticks * tempo)/(division * 1000000.0);
960  }
961  else
962  {
963  smpte_format = upperByte(division);
964  smpte_resolution = lowerByte(division);
965  result = double(ticks)/(smpte_format * smpte_resolution
966  * 1000000.0);
967  }
968  return result;
969 }
970 
971 void QSmf::SMFError(const QString& s)
972 {
973  emit signalSMFError(s);
974 }
975 
976 void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
977 {
978  quint8 chan;
979  int k;
980  chan = status & midi_channel_mask;
981  if (c1 > 127)
982  {
983  SMFError(QString("ChannelMessage with bad c1 = %1").arg(c1));
984  //c1 &= 127;
985  }
986  if (c2 > 127)
987  {
988  SMFError(QString("ChannelMessage with bad c2 = %1").arg(c2));
989  //c2 &= 127;
990  }
991  switch (status & midi_command_mask)
992  {
993  case note_off:
994  emit signalSMFNoteOff(chan, c1, c2);
995  break;
996  case note_on:
997  emit signalSMFNoteOn(chan, c1, c2);
998  break;
999  case poly_aftertouch:
1000  emit signalSMFKeyPress(chan, c1, c2);
1001  break;
1002  case control_change:
1003  emit signalSMFCtlChange(chan, c1, c2);
1004  break;
1005  case program_chng:
1006  emit signalSMFProgram(chan, c1);
1007  break;
1008  case channel_aftertouch:
1009  emit signalSMFChanPress(chan, c1);
1010  break;
1011  case pitch_wheel:
1012  k = c1 + (c2 << 7) - 8192;
1013  emit signalSMFPitchBend(chan, k);
1014  break;
1015  default:
1016  SMFError(QString("Invalid MIDI status %1. Unhandled event").arg(status));
1017  break;
1018  }
1019 }
1020 
1021 void QSmf::metaEvent(quint8 b)
1022 {
1023  QSmfRecTempo rec;
1024  QByteArray m(d->m_MsgBuff);
1025 
1026  switch (b)
1027  {
1028  case sequence_number:
1029  emit signalSMFSequenceNum(to16bit(m[0], m[1]));
1030  break;
1031  case text_event:
1032  case copyright_notice:
1033  case sequence_name:
1034  case instrument_name:
1035  case lyric:
1036  case marker:
1037  case cue_point: {
1038  QString s;
1039  if (d->m_codec == nullptr) {
1040  emit signalSMFText2(b, m);
1041  } else {
1042  s = d->m_codec->toUnicode(m);
1043  emit signalSMFText(b, s);
1044  }
1045  }
1046  break;
1047  case forced_channel:
1048  emit signalSMFforcedChannel(m[0]);
1049  break;
1050  case forced_port:
1051  emit signalSMFforcedPort(m[0]);
1052  break;
1053  case end_of_track:
1054  emit signalSMFendOfTrack();
1055  break;
1056  case set_tempo:
1057  d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
1058  emit signalSMFTempo(d->m_CurrTempo);
1059  rec = d->m_TempoList.last();
1060  if (rec.tempo == d->m_CurrTempo)
1061  {
1062  return;
1063  }
1064  if (rec.time > d->m_CurrTime)
1065  {
1066  return;
1067  }
1068  addTempo(d->m_CurrTempo, d->m_CurrTime);
1069  break;
1070  case smpte_offset:
1071  emit signalSMFSmpte(m[0], m[1], m[2], m[3], m[4]);
1072  break;
1073  case time_signature:
1074  emit signalSMFTimeSig(m[0], m[1], m[2], m[3]);
1075  break;
1076  case key_signature:
1077  emit signalSMFKeySig(m[0], m[1]);
1078  break;
1079  case sequencer_specific:
1080  emit signalSMFSeqSpecific(m);
1081  break;
1082  default:
1083  emit signalSMFMetaUnregistered(b, m);
1084  break;
1085  }
1086  emit signalSMFMetaMisc(b, m);
1087 }
1088 
1089 void QSmf::sysEx()
1090 {
1091  QByteArray varr(d->m_MsgBuff);
1092  emit signalSMFSysex(varr);
1093 }
1094 
1095 void QSmf::badByte(quint8 b, int p)
1096 {
1097  SMFError(QString("Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
1098 }
1099 
1100 quint8 QSmf::lowerByte(quint16 x)
1101 {
1102  return (x & 0xff);
1103 }
1104 
1105 quint8 QSmf::upperByte(quint16 x)
1106 {
1107  return ((x >> 8) & 0xff);
1108 }
1109 
1110 void QSmf::msgInit()
1111 {
1112  d->m_MsgBuff.truncate(0);
1113 }
1114 
1115 void QSmf::msgAdd(quint8 b)
1116 {
1117  int s = d->m_MsgBuff.size();
1118  d->m_MsgBuff.resize(s + 1);
1119  d->m_MsgBuff[s] = b;
1120 }
1121 
1122 /* public properties (accessors) */
1123 
1129 {
1130  return d->m_CurrTime;
1131 }
1132 
1138 {
1139  return d->m_CurrTempo;
1140 }
1141 
1147 {
1148  return d->m_RealTime;
1149 }
1150 
1156 {
1157  return d->m_Division;
1158 }
1159 
1164 void QSmf::setDivision(int division)
1165 {
1166  d->m_Division = division;
1167 }
1168 
1174 {
1175  return d->m_Tracks;
1176 }
1177 
1182 void QSmf::setTracks(int tracks)
1183 {
1184  d->m_Tracks = tracks;
1185 }
1186 
1192 {
1193  return d->m_fileFormat;
1194 }
1195 
1200 void QSmf::setFileFormat(int fileFormat)
1201 {
1202  d->m_fileFormat = fileFormat;
1203 }
1204 
1210 {
1211  return long(d->m_IOStream->device()->pos());
1212 }
1213 
1220 QTextCodec* QSmf::getTextCodec()
1221 {
1222  return d->m_codec;
1223 }
1224 
1233 void QSmf::setTextCodec(QTextCodec *codec)
1234 {
1235  d->m_codec = codec;
1236 }
1237 
1243 {
1244  return QStringLiteral(QT_STRINGIFY(VERSION));
1245 }
1246 
1247 } // namespace File
1248 } // namespace drumstick
1249 
1250 DISABLE_WARNING_POP
void writeMetaEvent(long deltaTime, int type, const QByteArray &data)
Writes a variable length Meta Event.
Definition: qsmf.cpp:528
void signalSMFSysex(const QByteArray &data)
Emitted after reading a System Exclusive message.
void writeTempo(long deltaTime, long tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:745
const quint8 text_event
SMF Text event.
Definition: qsmf.h:54
void signalSMFPitchBend(int chan, int value)
Emitted after reading a Bender message.
const quint8 control_change
MIDI event Control change.
Definition: qsmf.h:74
QSmf(QObject *parent=nullptr)
Constructor.
Definition: qsmf.cpp:103
long getRealTime()
Gets the real time in seconds.
Definition: qsmf.cpp:1146
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 signalSMFendOfTrack()
Emitted after reading a End-Of-Track message.
const quint8 lyric
SMF Lyric.
Definition: qsmf.h:58
void signalSMFforcedChannel(int channel)
Emitted after reading a Forced channel message.
void signalSMFSmpte(int b0, int b1, int b2, int b3, int b4)
Emitted after reading a SMPT offset message.
void writeKeySignature(long deltaTime, int tone, int mode)
Writes a key Signature message.
Definition: qsmf.cpp:793
void signalSMFTimeSig(int b0, int b1, int b2, int b3)
Emitted after reading a SMF Time signature message.
void setDivision(int division)
Sets the resolution.
Definition: qsmf.cpp:1164
void writeSequenceNumber(long deltaTime, int seqnum)
Writes a MIDI Sequence number.
Definition: qsmf.cpp:729
const quint8 key_signature
SMF Key signature.
Definition: qsmf.h:67
void signalSMFWriteTempoTrack()
Emitted to request the user to prepare the tempo track.
void signalSMFWriteTrack(int track)
Emitted to request the user to write a track.
long getCurrentTempo()
Gets the current tempo.
Definition: qsmf.cpp:1137
void signalSMFChanPress(int chan, int press)
Emitted after reading a Channel Aftertouch message.
void signalSMFProgram(int chan, int patch)
Emitted after reading a Program change message.
const quint8 meta_event
SMF Meta Event prefix.
Definition: qsmf.h:52
Q_DECL_DEPRECATED QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
Definition: qsmf.cpp:1220
const quint8 midi_command_mask
Mask to extract the command from the status byte.
Definition: qsmf.h:81
void signalSMFError(const QString &errorStr)
Emitted for a SMF read or write error.
void signalSMFSequenceNum(int seq)
Emitted after reading a Sequence number message.
The QObject class is the base class of all Qt objects.
const quint8 forced_channel
SMF Forced MIDI channel.
Definition: qsmf.h:61
void signalSMFMetaUnregistered(int typ, const QByteArray &data)
Emitted after reading an unregistered SMF Meta message.
void signalSMFSeqSpecific(const QByteArray &data)
Emitted after reading a Sequencer specific message.
const quint8 note_on
MIDI event Note On.
Definition: qsmf.h:72
const quint8 sequencer_specific
SMF Sequencer specific.
Definition: qsmf.h:68
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
Writes a Time Signature message.
Definition: qsmf.cpp:775
const quint8 instrument_name
SMF Instrument name.
Definition: qsmf.h:57
const quint8 marker
SMF Marker.
Definition: qsmf.h:59
const quint32 MThd
SMF Header prefix.
Definition: qsmf.h:48
void readFromStream(QDataStream *stream)
Reads a SMF stream.
Definition: qsmf.cpp:436
Drumstick common.
Definition: alsaclient.cpp:68
void writeMidiEvent(long deltaTime, int type, int chan, int b1)
Writes a MIDI message with a single parameter.
Definition: qsmf.cpp:642
void setTracks(int tracks)
Sets the number of tracks.
Definition: qsmf.cpp:1182
void signalSMFNoteOn(int chan, int pitch, int vol)
Emitted after reading a Note On message.
const quint8 poly_aftertouch
MIDI event Polyphonic pressure.
Definition: qsmf.h:73
void writeBpmTempo(long deltaTime, int tempo)
Writes a Tempo change message.
Definition: qsmf.cpp:761
const quint8 sequence_name
SMF Sequence name.
Definition: qsmf.h:56
const quint8 end_of_track
SMF End of track.
Definition: qsmf.h:63
const quint8 set_tempo
SMF Tempo change.
Definition: qsmf.h:64
void signalSMFTempo(int tempo)
Emitted after reading a Tempo Change message.
Q_DECL_DEPRECATED void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
Definition: qsmf.cpp:1233
const quint8 program_chng
MIDI event Program change.
Definition: qsmf.h:75
const quint8 midi_channel_mask
Mask to extract the channel from the status byte.
Definition: qsmf.h:82
void signalSMFTrackEnd()
Emitted after a track has finished.
void setFileFormat(int fileFormat)
Sets the SMF file format.
Definition: qsmf.cpp:1200
long getFilePos()
Gets the position in the SMF stream.
Definition: qsmf.cpp:1209
const quint32 MTrk
SMF Track prefix.
Definition: qsmf.h:49
const quint8 note_off
MIDI event Note Off.
Definition: qsmf.h:71
void signalSMFMetaMisc(int typ, const QByteArray &data)
Emitted after reading any SMF Meta message.
const quint8 forced_port
SMF Forced MIDI port.
Definition: qsmf.h:62
void readFromFile(const QString &fileName)
Reads a SMF stream from a disk file.
Definition: qsmf.cpp:446
void signalSMFKeySig(int b0, int b1)
Emitted after reading a SMF Key Signature smessage.
void writeToFile(const QString &fileName)
Writes a SMF stream to a disk file.
Definition: qsmf.cpp:469
const quint8 copyright_notice
SMF Copyright notice.
Definition: qsmf.h:55
void signalSMFNoteOff(int chan, int pitch, int vol)
Emitted after reading a Note Off message.
long getCurrentTime()
Gets the current time in ticks.
Definition: qsmf.cpp:1128
void signalSMFText2(int typ, const QByteArray &data)
Emitted after reading a SMF text message.
const quint8 end_of_sysex
MIDI event System Exclusive end.
Definition: qsmf.h:79
const quint8 smpte_offset
SMF SMPTE offset.
Definition: qsmf.h:65
const quint8 pitch_wheel
MIDI event Bender.
Definition: qsmf.h:77
void signalSMFforcedPort(int port)
Emitted after reading a Forced port message.
void signalSMFKeyPress(int chan, int pitch, int press)
Emitted after reading a Polyphonic Aftertouch message.
void signalSMFHeader(int format, int ntrks, int division)
Emitted after reading a SMF header.
void signalSMFCtlChange(int chan, int ctl, int value)
Emitted after reading a Control Change message.
const quint8 time_signature
SMF Time signature.
Definition: qsmf.h:66
const quint8 sequence_number
SMF Sequence number.
Definition: qsmf.h:53
const quint8 channel_aftertouch
MIDI event Channel after-touch.
Definition: qsmf.h:76
const quint8 system_exclusive
MIDI event System Exclusive begin.
Definition: qsmf.h:78
int getDivision()
Gets the resolution.
Definition: qsmf.cpp:1155
QString drumstickLibraryVersion()
drumstickLibraryVersion provides the Drumstick version as an edited QString
Definition: qsmf.cpp:1242
void writeToStream(QDataStream *stream)
Writes a SMF stream.
Definition: qsmf.cpp:459
const quint8 cue_point
SMF Cue point.
Definition: qsmf.h:60
int getFileFormat()
Gets the SMF file format.
Definition: qsmf.cpp:1191
Standard MIDI Files Input/Output.
virtual ~QSmf()
Destructor.
Definition: qsmf.cpp:111
int getTracks()
Gets the number of tracks.
Definition: qsmf.cpp:1173