drumstick  2.9.0
C++ MIDI libraries using Qt objects, idioms, and style.
qwrk.cpp
Go to the documentation of this file.
1 /*
2  WRK File component
3  Copyright (C) 2010-2023, Pedro Lopez-Cabanillas <plcl@users.sf.net>
4 
5  This library is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 3 of the License, or
8  (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <QDataStream>
20 #include <QFile>
21 #include <QIODevice>
22 #include <QStringList>
23 #include <QTextCodec>
24 #include <QTextStream>
25 #include <cmath>
26 #include <drumstick/qwrk.h>
27 
28 DISABLE_WARNING_PUSH
29 DISABLE_WARNING_DEPRECATED_DECLARATIONS
30 
36 namespace drumstick { namespace File {
37 
50 class QWrk::QWrkPrivate {
51 public:
52  QWrkPrivate():
53  m_Now(0),
54  m_From(0),
55  m_Thru(11930),
56  m_KeySig(0),
57  m_Clock(0),
58  m_AutoSave(0),
59  m_PlayDelay(0),
60  m_ZeroCtrls(false),
61  m_SendSPP(true),
62  m_SendCont(true),
63  m_PatchSearch(false),
64  m_AutoStop(false),
65  m_StopTime(4294967295U),
66  m_AutoRewind(false),
67  m_RewindTime(0),
68  m_MetroPlay(false),
69  m_MetroRecord(true),
70  m_MetroAccent(false),
71  m_CountIn(1),
72  m_ThruOn(true),
73  m_AutoRestart(false),
74  m_CurTempoOfs(1),
75  m_TempoOfs1(32),
76  m_TempoOfs2(64),
77  m_TempoOfs3(128),
78  m_PunchEnabled(false),
79  m_PunchInTime(0),
80  m_PunchOutTime(0),
81  m_EndAllTime(0),
82  m_division(120),
83  m_codec(nullptr),
84  m_IOStream(nullptr)
85  { }
86 
87  quint32 m_Now;
88  quint32 m_From;
89  quint32 m_Thru;
90  quint8 m_KeySig;
91  quint8 m_Clock;
92  quint8 m_AutoSave;
93  quint8 m_PlayDelay;
94  bool m_ZeroCtrls;
95  bool m_SendSPP;
96  bool m_SendCont;
97  bool m_PatchSearch;
98  bool m_AutoStop;
99  quint32 m_StopTime;
100  bool m_AutoRewind;
101  quint32 m_RewindTime;
102  bool m_MetroPlay;
103  bool m_MetroRecord;
104  bool m_MetroAccent;
105  quint8 m_CountIn;
106  bool m_ThruOn;
107  bool m_AutoRestart;
108  quint8 m_CurTempoOfs;
109  quint8 m_TempoOfs1;
110  quint8 m_TempoOfs2;
111  quint8 m_TempoOfs3;
112  bool m_PunchEnabled;
113  quint32 m_PunchInTime;
114  quint32 m_PunchOutTime;
115  quint32 m_EndAllTime;
116 
117  int m_division;
118  QTextCodec *m_codec;
119  QDataStream *m_IOStream;
120  QByteArray m_lastChunkData;
121  QList<RecTempo> m_tempos;
122 
123  qint64 m_lastChunkPos;
124  qint64 internalFilePos();
125 };
126 
131 QWrk::QWrk(QObject * parent) :
132  QObject(parent),
133  d(new QWrkPrivate)
134 { }
135 
140 { }
141 
148 QTextCodec* QWrk::getTextCodec()
149 {
150  return d->m_codec;
151 }
152 
160 void QWrk::setTextCodec(QTextCodec *codec)
161 {
162  d->m_codec = codec;
163 }
164 
170 QByteArray QWrk::getLastChunkRawData() const
171 {
172  return d->m_lastChunkData;
173 }
174 
178 void QWrk::readRawData(int size)
179 {
180  if (size > 0) {
181  d->m_lastChunkData = d->m_IOStream->device()->read(size);
182  } else {
183  d->m_lastChunkData.clear();
184  //qDebug() << Q_FUNC_INFO << "Size error:" << size;
185  }
186 }
187 
192 int QWrk::getNow() const
193 {
194  return d->m_Now;
195 }
196 
201 int QWrk::getFrom() const
202 {
203  return d->m_From;
204 }
205 
210 int QWrk::getThru() const
211 {
212  return d->m_Thru;
213 }
214 
219 int QWrk::getKeySig() const
220 {
221  return d->m_KeySig;
222 }
223 
228 int QWrk::getClock() const
229 {
230  return d->m_Clock;
231 }
232 
237 int QWrk::getAutoSave() const
238 {
239  return d->m_AutoSave;
240 }
241 
247 {
248  return d->m_PlayDelay;
249 }
250 
255 bool QWrk::getZeroCtrls() const
256 {
257  return d->m_ZeroCtrls;
258 }
259 
264 bool QWrk::getSendSPP() const
265 {
266  return d->m_SendSPP;
267 }
268 
273 bool QWrk::getSendCont() const
274 {
275  return d->m_SendCont;
276 }
277 
283 {
284  return d->m_PatchSearch;
285 }
286 
291 bool QWrk::getAutoStop() const
292 {
293  return d->m_AutoStop;
294 }
295 
300 unsigned int QWrk::getStopTime() const
301 {
302  return d->m_StopTime;
303 }
304 
310 {
311  return d->m_AutoRewind;
312 }
313 
319 {
320  return d->m_RewindTime;
321 }
322 
327 bool QWrk::getMetroPlay() const
328 {
329  return d->m_MetroPlay;
330 }
331 
337 {
338  return d->m_MetroRecord;
339 }
340 
346 {
347  return d->m_MetroAccent;
348 }
349 
354 int QWrk::getCountIn() const
355 {
356  return d->m_CountIn;
357 }
358 
363 bool QWrk::getThruOn() const
364 {
365  return d->m_ThruOn;
366 }
367 
373 {
374  return d->m_AutoRestart;
375 }
376 
382 {
383  return d->m_CurTempoOfs;
384 }
385 
401 {
402  return d->m_TempoOfs1;
403 }
404 
420 {
421  return d->m_TempoOfs2;
422 }
423 
439 {
440  return d->m_TempoOfs3;
441 }
442 
448 {
449  return d->m_PunchEnabled;
450 }
451 
457 {
458  return d->m_PunchInTime;
459 }
460 
466 {
467  return d->m_PunchOutTime;
468 }
469 
475 {
476  return d->m_EndAllTime;
477 }
478 
483 quint8 QWrk::readByte()
484 {
485  quint8 b = 0xff;
486  if (!d->m_IOStream->atEnd())
487  *d->m_IOStream >> b;
488  return b;
489 }
490 
497 quint16 QWrk::to16bit(quint8 c1, quint8 c2)
498 {
499  quint16 value = (c1 << 8);
500  value += c2;
501  return value;
502 }
503 
512 quint32 QWrk::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
513 {
514  quint32 value = (c1 << 24);
515  value += (c2 << 16);
516  value += (c3 << 8);
517  value += c4;
518  return value;
519 }
520 
525 quint16 QWrk::read16bit()
526 {
527  quint8 c1, c2;
528  c1 = readByte();
529  c2 = readByte();
530  return to16bit(c2, c1);
531 }
532 
537 quint32 QWrk::read24bit()
538 {
539  quint8 c1, c2, c3;
540  c1 = readByte();
541  c2 = readByte();
542  c3 = readByte();
543  return to32bit(0, c3, c2, c1);
544 }
545 
550 quint32 QWrk::read32bit()
551 {
552  quint8 c1, c2, c3, c4;
553  c1 = readByte();
554  c2 = readByte();
555  c3 = readByte();
556  c4 = readByte();
557  return to32bit(c4, c3, c2, c1);
558 }
559 
564 QString QWrk::readString(int len)
565 {
566  QString s;
567  if ( len > 0 ) {
568  QByteArray data = readByteArray(len);
569  if (d->m_codec == nullptr) {
570  s = QString::fromLatin1(data);
571  } else {
572  s = d->m_codec->toUnicode(data);
573  }
574  }
575  return s;
576 }
577 
582 QByteArray QWrk::readByteArray(int len)
583 {
584  QByteArray data;
585  if ( len > 0 ) {
586  quint8 c = 0xff;
587  for ( int i = 0; i < len && c != 0 && !atEnd(); ++i ) {
588  c = readByte();
589  if ( c != 0)
590  data += c;
591  }
592  }
593  return data;
594 }
595 
601 QString QWrk::readVarString()
602 {
603  QString s;
604  QByteArray data = readVarByteArray();
605  if (d->m_codec == nullptr) {
606  s = QString::fromLatin1(data);
607  } else {
608  s = d->m_codec->toUnicode(data);
609  }
610  return s;
611 }
612 
617 QByteArray QWrk::readVarByteArray()
618 {
619  QByteArray data;
620  quint8 b;
621  do {
622  b = readByte();
623  if (b != 0)
624  data += b;
625  } while (b != 0 && !atEnd());
626  return data;
627 }
628 
629 void QWrk::processMarkers()
630 {
631  int num = read32bit();
632  for (int i = 0; (i < num) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i) {
633  int smpte = readByte();
634  readGap(1);
635  long time = read24bit();
636  readGap(5);
637  int len = readByte();
638  if (d->m_codec == nullptr) {
639  QByteArray data = readByteArray(len);
640  Q_EMIT signalWRKMarker2(time, smpte, data);
641  } else {
642  QString name = readString(len);
643  Q_EMIT signalWRKMarker(time, smpte, name);
644  }
645  }
646 }
647 
653 {
654  return d->internalFilePos();
655 }
656 
661 void QWrk::seek(qint64 pos)
662 {
663  if (!d->m_IOStream->device()->seek(pos)) {
664  //qDebug() << Q_FUNC_INFO << "Error, pos:" << pos;
665  }
666 }
667 
672 bool QWrk::atEnd()
673 {
674  return d->m_IOStream->atEnd();
675 }
676 
681 void QWrk::readGap(int size)
682 {
683  if ( size > 0)
684  seek( d->internalFilePos() + size );
685 }
686 
691 void QWrk::readFromStream(QDataStream *stream)
692 {
693  d->m_IOStream = stream;
694  wrkRead();
695 }
696 
701 void QWrk::readFromFile(const QString& fileName)
702 {
703  QFile file(fileName);
704  file.open(QIODevice::ReadOnly);
705  QDataStream ds(&file);
706  readFromStream(&ds);
707  file.close();
708 }
709 
710 void QWrk::processTrackChunk()
711 {
712  int namelen;
713  QString name[2];
714  QByteArray data[2];
715  int trackno;
716  int channel;
717  int pitch;
718  int velocity;
719  int port;
720  bool selected;
721  bool muted;
722  bool loop;
723 
724  trackno = read16bit();
725  for(int i=0; i<2; ++i) {
726  namelen = readByte();
727  if (d->m_codec == nullptr) {
728  data[i] = readByteArray(namelen);
729  } else {
730  name[i] = readString(namelen);
731  }
732  }
733  channel = readByte() & 0x0f;
734  pitch = readByte();
735  velocity = readByte();
736  port = readByte();
737  quint8 flags = readByte();
738  selected = ((flags & 1) != 0);
739  muted = ((flags & 2) != 0);
740  loop = ((flags & 4) != 0);
741  if (d->m_codec == nullptr) {
742  Q_EMIT signalWRKTrack2( data[0], data[1],
743  trackno, channel, pitch,
744  velocity, port, selected,
745  muted, loop );
746  } else {
747  Q_EMIT signalWRKTrack( name[0], name[1],
748  trackno, channel, pitch,
749  velocity, port, selected,
750  muted, loop );
751  }
752 }
753 
754 void QWrk::processVarsChunk()
755 {
756  d->m_Now = read32bit();
757  d->m_From = read32bit();
758  d->m_Thru = read32bit();
759  d->m_KeySig = readByte();
760  d->m_Clock = readByte();
761  d->m_AutoSave = readByte();
762  d->m_PlayDelay = readByte();
763  readGap(1);
764  d->m_ZeroCtrls = (readByte() != 0);
765  d->m_SendSPP = (readByte() != 0);
766  d->m_SendCont = (readByte() != 0);
767  d->m_PatchSearch = (readByte() != 0);
768  d->m_AutoStop = (readByte() != 0);
769  d->m_StopTime = read32bit();
770  d->m_AutoRewind = (readByte() != 0);
771  d->m_RewindTime = read32bit();
772  d->m_MetroPlay = (readByte() != 0);
773  d->m_MetroRecord = (readByte() != 0);
774  d->m_MetroAccent = (readByte() != 0);
775  d->m_CountIn = readByte();
776  readGap(2);
777  d->m_ThruOn = (readByte() != 0);
778  readGap(19);
779  d->m_AutoRestart = (readByte() != 0);
780  d->m_CurTempoOfs = readByte();
781  d->m_TempoOfs1 = readByte();
782  d->m_TempoOfs2 = readByte();
783  d->m_TempoOfs3 = readByte();
784  readGap(2);
785  d->m_PunchEnabled = (readByte() != 0);
786  d->m_PunchInTime = read32bit();
787  d->m_PunchOutTime = read32bit();
788  d->m_EndAllTime = read32bit();
789 
790  Q_EMIT signalWRKGlobalVars();
791 }
792 
793 void QWrk::processTimebaseChunk()
794 {
795  quint16 timebase = read16bit();
796  d->m_division = timebase;
797  Q_EMIT signalWRKTimeBase(timebase);
798 }
799 
800 void QWrk::processNoteArray(int track, int events)
801 {
802  quint32 time = 0;
803  quint8 status = 0, data1 = 0, data2 = 0, i = 0;
804  quint16 dur = 0;
805  int value = 0, type = 0, channel = 0, len = 0;
806  QString text;
807  QByteArray data;
808  for ( i = 0; (i < events) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i ) {
809  time = read24bit();
810  status = readByte();
811  dur = 0;
812  if (status >= 0x90) {
813  type = status & 0xf0;
814  channel = status & 0x0f;
815  data1 = readByte();
816  if (type == 0x90 || type == 0xA0 || type == 0xB0 || type == 0xE0)
817  data2 = readByte();
818  if (type == 0x90)
819  dur = read16bit();
820  switch (type) {
821  case 0x90:
822  Q_EMIT signalWRKNote(track, time, channel, data1, data2, dur);
823  break;
824  case 0xA0:
825  Q_EMIT signalWRKKeyPress(track, time, channel, data1, data2);
826  break;
827  case 0xB0:
828  Q_EMIT signalWRKCtlChange(track, time, channel, data1, data2);
829  break;
830  case 0xC0:
831  Q_EMIT signalWRKProgram(track, time, channel, data1);
832  break;
833  case 0xD0:
834  Q_EMIT signalWRKChanPress(track, time, channel, data1);
835  break;
836  case 0xE0:
837  value = (data2 << 7) + data1 - 8192;
838  Q_EMIT signalWRKPitchBend(track, time, channel, value);
839  break;
840  case 0xF0:
841  Q_EMIT signalWRKSysexEvent(track, time, data1);
842  break;
843  }
844  } else if (status == 5) {
845  int code = read16bit();
846  len = read32bit();
847  if (d->m_codec == nullptr) {
848  data = readByteArray(len);
849  Q_EMIT signalWRKExpression2(track, time, code, data);
850  } else {
851  text = readString(len);
852  Q_EMIT signalWRKExpression(track, time, code, text);
853  }
854  } else if (status == 6) {
855  int code = read16bit();
856  dur = read16bit();
857  readGap(4);
858  Q_EMIT signalWRKHairpin(track, time, code, dur);
859  } else if (status == 7) {
860  len = read32bit();
861  text = readString(len);
862  data.clear();
863  for(int j=0; j<13; ++j) {
864  int byte = readByte();
865  data += byte;
866  }
867  Q_EMIT signalWRKChord(track, time, text, data);
868  } else if (status == 8) {
869  len = read16bit();
870  data.clear();
871  for(int j=0; j<len; ++j) {
872  int byte = readByte();
873  data += byte;
874  }
875  Q_EMIT signalWRKSysex(0, QString(), false, 0, data);
876  } else {
877  len = read32bit();
878  if (d->m_codec == nullptr) {
879  data = readByteArray(len);
880  Q_EMIT signalWRKText2(track, time, status, data);
881  } else {
882  text = readString(len);
883  Q_EMIT signalWRKText(track, time, status, text);
884  }
885  }
886  }
887  if ((i < events) && atEnd()) {
888  Q_EMIT signalWRKError("Corrupted file");
889  }
890  Q_EMIT signalWRKStreamEnd(time + dur);
891 }
892 
893 void QWrk::processStreamChunk()
894 {
895  long time = 0;
896  int dur = 0, value = 0, type = 0, channel = 0, i = 0;
897  quint8 status = 0, data1 = 0, data2 = 0;
898  quint16 track = read16bit();
899  int events = read16bit();
900  for ( i = 0; (i < events) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i ) {
901  time = read24bit();
902  status = readByte();
903  data1 = readByte();
904  data2 = readByte();
905  dur = read16bit();
906  type = status & 0xf0;
907  channel = status & 0x0f;
908  switch (type) {
909  case 0x90:
910  Q_EMIT signalWRKNote(track, time, channel, data1, data2, dur);
911  break;
912  case 0xA0:
913  Q_EMIT signalWRKKeyPress(track, time, channel, data1, data2);
914  break;
915  case 0xB0:
916  Q_EMIT signalWRKCtlChange(track, time, channel, data1, data2);
917  break;
918  case 0xC0:
919  Q_EMIT signalWRKProgram(track, time, channel, data1);
920  break;
921  case 0xD0:
922  Q_EMIT signalWRKChanPress(track, time, channel, data1);
923  break;
924  case 0xE0:
925  value = (data2 << 7) + data1 - 8192;
926  Q_EMIT signalWRKPitchBend(track, time, channel, value);
927  break;
928  case 0xF0:
929  Q_EMIT signalWRKSysexEvent(track, time, data1);
930  break;
931  }
932  }
933  if ((i < events) && atEnd()) {
934  Q_EMIT signalWRKError("Corrupted file");
935  }
936  Q_EMIT signalWRKStreamEnd(time + dur);
937 }
938 
939 void QWrk::processMeterChunk()
940 {
941  int count = read16bit();
942  for (int i = 0; i < count; ++i) {
943  readGap(4);
944  int measure = read16bit();
945  int num = readByte();
946  int den = pow(2.0, readByte());
947  readGap(4);
948  Q_EMIT signalWRKTimeSig(measure, num, den);
949  }
950 }
951 
952 void QWrk::processMeterKeyChunk()
953 {
954  int count = read16bit();
955  for (int i = 0; i < count; ++i) {
956  int measure = read16bit();
957  int num = readByte();
958  int den = pow(2.0, readByte());
959  qint8 alt = readByte();
960  Q_EMIT signalWRKTimeSig(measure, num, den);
961  Q_EMIT signalWRKKeySig(measure, alt);
962  }
963 }
964 
965 double QWrk::getRealTime(long ticks) const
966 {
967  double division = 1.0 * d->m_division;
968  RecTempo last;
969  last.time = 0;
970  last.tempo = 100.0;
971  last.seconds = 0.0;
972  if (!d->m_tempos.isEmpty()) {
973  foreach(const RecTempo& rec, d->m_tempos) {
974  if (rec.time >= ticks)
975  break;
976  last = rec;
977  }
978  }
979  return last.seconds + (((ticks - last.time) / division) * (60.0 / last.tempo));
980 }
981 
982 void QWrk::processTempoChunk(int factor)
983 {
984  double division = 1.0 * d->m_division;
985  int count = read16bit();
986  RecTempo last, next;
987  for (int i = 0; i < count; ++i) {
988 
989  long time = read32bit();
990  readGap(4);
991  long tempo = read16bit() * factor;
992  readGap(8);
993 
994  next.time = time;
995  next.tempo = tempo / 100.0;
996  next.seconds = 0.0;
997  last.time = 0;
998  last.tempo = next.tempo;
999  last.seconds = 0.0;
1000  if (! d->m_tempos.isEmpty()) {
1001  foreach(const RecTempo& rec, d->m_tempos) {
1002  if (rec.time >= time)
1003  break;
1004  last = rec;
1005  }
1006  next.seconds = last.seconds +
1007  (((time - last.time) / division) * (60.0 / last.tempo));
1008  }
1009  d->m_tempos.append(next);
1010 
1011  Q_EMIT signalWRKTempo(time, tempo);
1012  }
1013 }
1014 
1015 void QWrk::processSysexChunk()
1016 {
1017  int j;
1018  QString name;
1019  QByteArray data;
1020  int bank = readByte();
1021  int length = read16bit();
1022  bool autosend = (readByte() != 0);
1023  int namelen = readByte();
1024  name = readString(namelen);
1025  for(j=0; j<length; ++j) {
1026  int byte = readByte();
1027  data += byte;
1028  }
1029  Q_EMIT signalWRKSysex(bank, name, autosend, 0, data);
1030 }
1031 
1032 void QWrk::processSysex2Chunk()
1033 {
1034  int j;
1035  QString name;
1036  QByteArray data;
1037  int bank = read16bit();
1038  int length = read32bit();
1039  quint8 b = readByte();
1040  int port = ( b & 0xf0 ) >> 4;
1041  bool autosend = ( (b & 0x0f) != 0);
1042  int namelen = readByte();
1043  name = readString(namelen);
1044  for(j=0; j<length; ++j) {
1045  int byte = readByte();
1046  data += byte;
1047  }
1048  Q_EMIT signalWRKSysex(bank, name, autosend, port, data);
1049 }
1050 
1051 void QWrk::processNewSysexChunk()
1052 {
1053  int j;
1054  QString name;
1055  QByteArray data;
1056  int bank = read16bit();
1057  int length = read32bit();
1058  int port = read16bit();
1059  bool autosend = (readByte() != 0);
1060  int namelen = readByte();
1061  name = readString(namelen);
1062  for(j=0; j<length; ++j) {
1063  int byte = readByte();
1064  data += byte;
1065  }
1066  Q_EMIT signalWRKSysex(bank, name, autosend, port, data);
1067 }
1068 
1069 void QWrk::processThruChunk()
1070 {
1071  readGap(2);
1072  qint8 port = readByte(); // 0->127
1073  qint8 channel = readByte(); // -1, 0->15
1074  qint8 keyPlus = readByte(); // 0->127
1075  qint8 velPlus = readByte(); // 0->127
1076  qint8 localPort = readByte();
1077  qint8 mode = readByte();
1078  Q_EMIT signalWRKThru(mode, port, channel, keyPlus, velPlus, localPort);
1079 }
1080 
1081 void QWrk::processTrackOffset()
1082 {
1083  quint16 track = read16bit();
1084  qint16 offset = read16bit();
1085  Q_EMIT signalWRKTrackOffset(track, offset);
1086 }
1087 
1088 void QWrk::processTrackReps()
1089 {
1090  quint16 track = read16bit();
1091  quint16 reps = read16bit();
1092  Q_EMIT signalWRKTrackReps(track, reps);
1093 }
1094 
1095 void QWrk::processTrackPatch()
1096 {
1097  quint16 track = read16bit();
1098  qint8 patch = readByte();
1099  Q_EMIT signalWRKTrackPatch(track, patch);
1100 }
1101 
1102 void QWrk::processTimeFormat()
1103 {
1104  quint16 fmt = read16bit();
1105  quint16 ofs = read16bit();
1106  Q_EMIT signalWRKTimeFormat(fmt, ofs);
1107 }
1108 
1109 void QWrk::processComments()
1110 {
1111  int len = read16bit();
1112  if (d->m_codec == nullptr) {
1113  QByteArray data = readByteArray(len);
1114  Q_EMIT signalWRKComments2(data);
1115  } else {
1116  QString text = readString(len);
1117  Q_EMIT signalWRKComments(text);
1118  }
1119 }
1120 
1121 void QWrk::processVariableRecord(int max)
1122 {
1123  int datalen = max - 32;
1124  QByteArray data;
1125  QString name = readVarString();
1126  readGap(31 - name.length());
1127  for ( int i = 0; i < datalen; ++i ) {
1128  data += readByte();
1129  }
1130  while (data.endsWith('\0')) {
1131  data.chop(1);
1132  }
1133  Q_EMIT signalWRKVariableRecord(name, data);
1134 }
1135 
1136 void QWrk::processUnknown(int id)
1137 {
1138  Q_EMIT signalWRKUnknownChunk(id, d->m_lastChunkData);
1139 }
1140 
1141 void QWrk::processNewTrack()
1142 {
1143  QByteArray data;
1144  QString name;
1145  qint16 bank = -1;
1146  qint16 patch = -1;
1147  //qint16 vol = -1;
1148  //qint16 pan = -1;
1149  qint8 key = -1;
1150  qint8 vel = 0;
1151  quint8 port = 0;
1152  qint8 channel = 0;
1153  bool selected = false;
1154  bool muted = false;
1155  bool loop = false;
1156  quint16 track = read16bit();
1157  quint8 len = readByte();
1158  if (d->m_codec == nullptr) {
1159  data = readByteArray(len);
1160  } else {
1161  name = readString(len);
1162  }
1163  bank = read16bit();
1164  patch = read16bit();
1165  /*vol =*/ read16bit();
1166  /*pan =*/ read16bit();
1167  key = readByte();
1168  vel = readByte();
1169  readGap(7);
1170  port = readByte();
1171  channel = readByte();
1172  muted = (readByte() != 0);
1173  if (d->m_codec == nullptr) {
1174  Q_EMIT signalWRKNewTrack2(data, track, channel, key, vel, port, selected, muted, loop);
1175  } else {
1176  Q_EMIT signalWRKNewTrack(name, track, channel, key, vel, port, selected, muted, loop);
1177  }
1178  if (bank > -1)
1179  Q_EMIT signalWRKTrackBank(track, bank);
1180  if (patch > -1) {
1181  if (channel > -1)
1182  Q_EMIT signalWRKProgram(track, 0, channel, patch);
1183  else
1184  Q_EMIT signalWRKTrackPatch(track, patch);
1185  }
1186 }
1187 
1188 void QWrk::processSoftVer()
1189 {
1190  int len = readByte();
1191  QString vers = readString(len);
1192  Q_EMIT signalWRKSoftVer(vers);
1193 }
1194 
1195 void QWrk::processTrackName()
1196 {
1197  int track = read16bit();
1198  int len = readByte();
1199  if (d->m_codec == nullptr) {
1200  QByteArray data = readByteArray(len);
1201  Q_EMIT signalWRKTrackName2(track, data);
1202  } else {
1203  QString name = readString(len);
1204  Q_EMIT signalWRKTrackName(track, name);
1205  }
1206 }
1207 
1208 void QWrk::processStringTable()
1209 {
1210  if (d->m_codec == nullptr) {
1211  QList<QByteArray> table;
1212  int rows = read16bit();
1213  for (int i = 0; i < rows; ++i) {
1214  int len = readByte();
1215  QByteArray name = readByteArray(len);
1216  /*int idx =*/ readByte();
1217  table.insert(i, name);
1218  }
1219  Q_EMIT signalWRKStringTable2(table);
1220  } else {
1221  QStringList table;
1222  int rows = read16bit();
1223  for (int i = 0; i < rows; ++i) {
1224  int len = readByte();
1225  QString name = readString(len);
1226  /*int idx =*/ readByte();
1227  table.insert(i, name);
1228  }
1229  Q_EMIT signalWRKStringTable(table);
1230  }
1231 }
1232 
1233 void QWrk::processLyricsStream()
1234 {
1235  quint16 track = read16bit();
1236  int events = read32bit();
1237  processNoteArray(track, events);
1238 }
1239 
1240 void QWrk::processTrackVol()
1241 {
1242  quint16 track = read16bit();
1243  int vol = read16bit();
1244  Q_EMIT signalWRKTrackVol(track, vol);
1245 }
1246 
1247 void QWrk::processNewTrackOffset()
1248 {
1249  quint16 track = read16bit();
1250  int offset = read32bit();
1251  Q_EMIT signalWRKTrackOffset(track, offset);
1252 }
1253 
1254 void QWrk::processTrackBank()
1255 {
1256  quint16 track = read16bit();
1257  int bank = read16bit();
1258  Q_EMIT signalWRKTrackBank(track, bank);
1259 }
1260 
1261 void QWrk::processSegmentChunk()
1262 {
1263  QString name;
1264  QByteArray data;
1265  int track = read16bit();
1266  int offset = read32bit();
1267  readGap(8);
1268  int len = readByte();
1269  if (d->m_codec == nullptr) {
1270  data = readByteArray(len);
1271  } else {
1272  name = readString(len);
1273  }
1274  readGap(20);
1275  if (d->m_codec == nullptr) {
1276  Q_EMIT signalWRKSegment2(track, offset, data);
1277  } else {
1278  Q_EMIT signalWRKSegment(track, offset, name);
1279  }
1280  int events = read32bit();
1281  processNoteArray(track, events);
1282 }
1283 
1284 void QWrk::processNewStream()
1285 {
1286  QString name;
1287  QByteArray data;
1288  int track = read16bit();
1289  int len = readByte();
1290  if (d->m_codec == nullptr) {
1291  data = readByteArray(len);
1292  Q_EMIT signalWRKSegment2(track, 0, data);
1293  } else {
1294  name = readString(len);
1295  Q_EMIT signalWRKSegment(track, 0, name);
1296  }
1297  int events = read32bit();
1298  processNoteArray(track, events);
1299 }
1300 
1301 void QWrk::processEndChunk()
1302 {
1303  Q_EMIT signalWRKEnd();
1304 }
1305 
1306 int QWrk::readChunk()
1307 {
1308  qint64 start_pos = d->internalFilePos();
1309  int ck = readByte();
1310  if (ck != END_CHUNK) {
1311  quint32 ck_len = read32bit();
1312  if (ck_len > d->m_IOStream->device()->bytesAvailable()) {
1313  Q_EMIT signalWRKError("Corrupted file");
1314  seek(start_pos);
1315  return END_CHUNK;
1316  }
1317  start_pos = d->internalFilePos();
1318  d->m_lastChunkPos = start_pos + ck_len;
1319  readRawData(ck_len);
1320  seek(start_pos);
1321  switch (ck) {
1322  case TRACK_CHUNK:
1323  processTrackChunk();
1324  break;
1325  case VARS_CHUNK:
1326  processVarsChunk();
1327  break;
1328  case TIMEBASE_CHUNK:
1329  processTimebaseChunk();
1330  break;
1331  case STREAM_CHUNK:
1332  processStreamChunk();
1333  break;
1334  case METER_CHUNK:
1335  processMeterChunk();
1336  break;
1337  case TEMPO_CHUNK:
1338  processTempoChunk(100);
1339  break;
1340  case NTEMPO_CHUNK:
1341  processTempoChunk();
1342  break;
1343  case SYSEX_CHUNK:
1344  processSysexChunk();
1345  break;
1346  case THRU_CHUNK:
1347  processThruChunk();
1348  break;
1349  case TRKOFFS_CHUNK:
1350  processTrackOffset();
1351  break;
1352  case TRKREPS_CHUNK:
1353  processTrackReps();
1354  break;
1355  case TRKPATCH_CHUNK:
1356  processTrackPatch();
1357  break;
1358  case TIMEFMT_CHUNK:
1359  processTimeFormat();
1360  break;
1361  case COMMENTS_CHUNK:
1362  processComments();
1363  break;
1364  case VARIABLE_CHUNK:
1365  processVariableRecord(ck_len);
1366  break;
1367  case NTRACK_CHUNK:
1368  processNewTrack();
1369  break;
1370  case SOFTVER_CHUNK:
1371  processSoftVer();
1372  break;
1373  case TRKNAME_CHUNK:
1374  processTrackName();
1375  break;
1376  case STRTAB_CHUNK:
1377  processStringTable();
1378  break;
1379  case LYRICS_CHUNK:
1380  processLyricsStream();
1381  break;
1382  case TRKVOL_CHUNK:
1383  processTrackVol();
1384  break;
1385  case NTRKOFS_CHUNK:
1386  processNewTrackOffset();
1387  break;
1388  case TRKBANK_CHUNK:
1389  processTrackBank();
1390  break;
1391  case METERKEY_CHUNK:
1392  processMeterKeyChunk();
1393  break;
1394  case SYSEX2_CHUNK:
1395  processSysex2Chunk();
1396  break;
1397  case NSYSEX_CHUNK:
1398  processNewSysexChunk();
1399  break;
1400  case SGMNT_CHUNK:
1401  processSegmentChunk();
1402  break;
1403  case NSTREAM_CHUNK:
1404  processNewStream();
1405  break;
1406  case MARKERS_CHUNK:
1407  processMarkers();
1408  break;
1409  default:
1410  processUnknown(ck);
1411  }
1412  if (d->internalFilePos() != d->m_lastChunkPos) {
1413  //qDebug() << Q_FUNC_INFO << "Current pos:" << d->internalFilePos() << "should be:" << d->m_lastChunkPos;
1414  seek(d->m_lastChunkPos);
1415  }
1416  }
1417  return ck;
1418 }
1419 
1420 void QWrk::wrkRead()
1421 {
1422  QByteArray hdr(HEADER.length(), ' ');
1423  d->m_tempos.clear();
1424  d->m_IOStream->device()->read(hdr.data(), HEADER.length());
1425  if (hdr == HEADER) {
1426  int vma, vme;
1427  int ck_id;
1428  readGap(1);
1429  vme = readByte();
1430  vma = readByte();
1431  Q_EMIT signalWRKHeader(vma, vme);
1432  do {
1433  ck_id = readChunk();
1434  } while ((ck_id != END_CHUNK) && !atEnd());
1435  if (!atEnd()) {
1436  //qDebug() << Q_FUNC_INFO << "extra junk past the end at" << d->internalFilePos();
1437  readRawData(d->m_IOStream->device()->bytesAvailable());
1438  processUnknown(ck_id);
1439  }
1440  processEndChunk();
1441  } else
1442  Q_EMIT signalWRKError("Invalid file format");
1443 }
1444 
1445 qint64 QWrk::QWrkPrivate::internalFilePos()
1446 {
1447  return m_IOStream->device()->pos();
1448 }
1449 
1450 const QByteArray QWrk::HEADER = QByteArrayLiteral("CAKEWALK");
1451 
1452 } // namespace File
1453 } // namespace drumstick
1454 
1455 DISABLE_WARNING_POP
The QObject class is the base class of all Qt objects.
void signalWRKTrackPatch(int track, int patch)
Emitted after reading a track patch chunk.
bool getMetroRecord() const
Metronome on during recording?
Definition: qwrk.cpp:336
bool getPunchEnabled() const
Auto-Punch enabled?
Definition: qwrk.cpp:447
int getRewindTime() const
Auto-rewind time.
Definition: qwrk.cpp:318
bool getZeroCtrls() const
Zero continuous controllers?
Definition: qwrk.cpp:255
QWrk(QObject *parent=nullptr)
Constructor.
Definition: qwrk.cpp:131
Q_DECL_DEPRECATED void signalWRKSegment(int track, long time, const QString &name)
Emitted after reading a segment prefix chunk.
void signalWRKProgram(int track, long time, int chan, int patch)
Emitted after reading a Program change message.
void signalWRKChord(int track, long time, const QString &name, const QByteArray &data)
Emitted after reading a chord diagram chunk.
static const QByteArray HEADER
Cakewalk WRK file format header string id.
Definition: qwrk.h:145
Q_DECL_DEPRECATED void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
Definition: qwrk.cpp:160
void signalWRKHeader(int verh, int verl)
Emitted after reading a WRK header.
void signalWRKSysexEvent(int track, long time, int bank)
Emitted after reading a System Exclusive event.
int getAutoSave() const
Auto save (0=disabled, 1..256=minutes)
Definition: qwrk.cpp:237
void signalWRKMarker2(long time, int type, const QByteArray &data)
Emitted after reading a text marker This signal is emitted when getTextCodec() is nullptr.
long getFilePos()
Current position in the data stream.
Definition: qwrk.cpp:652
bool getThruOn() const
MIDI Thru enabled? (only used if no THRU rec)
Definition: qwrk.cpp:363
void signalWRKGlobalVars()
Emitted after reading the global variables chunk.
void signalWRKSoftVer(const QString &version)
Emitted after reading a software version chunk.
void signalWRKSegment2(int track, long time, const QByteArray &name)
Emitted after reading a segment prefix chunk.
int getNow() const
Now marker time.
Definition: qwrk.cpp:192
int getPunchOutTime() const
Punch-out time.
Definition: qwrk.cpp:465
void signalWRKTrackOffset(int track, int offset)
Emitted after reading a track offset chunk.
void signalWRKChanPress(int track, long time, int chan, int press)
Emitted after reading a Channel Aftertouch message.
void signalWRKStreamEnd(long time)
Emitted after reading the last event of a event stream.
void signalWRKText2(int track, long time, int type, const QByteArray &data)
Emitted after reading a text message This signal is emitted when getTextCodec() is nullptr.
bool getAutoStop() const
Auto-stop?
Definition: qwrk.cpp:291
int getEndAllTime() const
Time of latest event (incl.
Definition: qwrk.cpp:474
void signalWRKKeyPress(int track, long time, int chan, int pitch, int press)
Emitted after reading a Polyphonic Aftertouch message.
void signalWRKVariableRecord(const QString &name, const QByteArray &data)
Emitted after reading a variable chunk.
void signalWRKTrackVol(int track, int vol)
Emitted after reading a track volume chunk.
void signalWRKExpression2(int track, long time, int code, const QByteArray &text)
Emitted after reading an expression indication (notation) chunk.
void signalWRKTrackName2(int track, const QByteArray &name)
Emitted after reading a track name chunk.
int getPlayDelay() const
Play Delay.
Definition: qwrk.cpp:246
bool getSendSPP() const
Send Song Position Pointer?
Definition: qwrk.cpp:264
Q_DECL_DEPRECATED void signalWRKNewTrack(const QString &name, int trackno, int channel, int pitch, int velocity, int port, bool selected, bool muted, bool loop)
Emitted after reading a new track prefix.
void signalWRKTrack2(const QByteArray &name1, const QByteArray &name2, int trackno, int channel, int pitch, int velocity, int port, bool selected, bool muted, bool loop)
Emitted after reading a track prefix chunk This signal is emitted when getTextCodec() is nullptr.
void signalWRKError(const QString &errorStr)
Emitted for a WRK file read error.
virtual ~QWrk()
Destructor.
Definition: qwrk.cpp:139
void signalWRKTempo(long time, int tempo)
Emitted after reading a Tempo Change message.
void signalWRKTimeSig(int bar, int num, int den)
Emitted after reading a WRK Time signature.
void signalWRKHairpin(int track, long time, int code, int dur)
Emitted after reading a hairpin symbol (notation) chunk.
void signalWRKPitchBend(int track, long time, int chan, int value)
Emitted after reading a Bender message.
void signalWRKEnd()
Emitted after reading the last chunk of a WRK file.
int getTempoOfs3() const
Fixed-point ratio value of tempo offset 3.
Definition: qwrk.cpp:438
Q_DECL_DEPRECATED void signalWRKTrackName(int track, const QString &name)
Emitted after reading a track name chunk.
int getThru() const
Thru marker time.
Definition: qwrk.cpp:210
bool getSendCont() const
Send MIDI Continue?
Definition: qwrk.cpp:273
int getTempoOfs2() const
Fixed-point ratio value of tempo offset 2.
Definition: qwrk.cpp:419
void signalWRKNewTrack2(const QByteArray &name, int trackno, int channel, int pitch, int velocity, int port, bool selected, bool muted, bool loop)
Emitted after reading a new track prefix This signal is emitted when getTextCodec() is nullptr.
bool getPatchSearch() const
Patch/controller search-back?
Definition: qwrk.cpp:282
void readFromStream(QDataStream *stream)
Reads a stream.
Definition: qwrk.cpp:691
void signalWRKThru(int mode, int port, int channel, int keyPlus, int velPlus, int localPort)
Emitted after reading an Extended Thru parameters chunk.
int getPunchInTime() const
Punch-in time.
Definition: qwrk.cpp:456
void signalWRKNote(int track, long time, int chan, int pitch, int vol, int dur)
Emitted after reading a Note message.
Q_DECL_DEPRECATED void signalWRKStringTable(const QStringList &strs)
Emitted after reading a string event types chunk.
unsigned int getStopTime() const
Auto-stop time.
Definition: qwrk.cpp:300
void signalWRKUnknownChunk(int type, const QByteArray &data)
Emitted after reading an unknown chunk.
void signalWRKTrackBank(int track, int bank)
Emitted after reading a track bank chunk.
void signalWRKComments2(const QByteArray &data)
Emitted after reading a comments chunk This signal is emitted when getTextCodec() is nullptr.
void signalWRKTimeBase(int timebase)
Emitted after reading the timebase chunk.
QByteArray getLastChunkRawData() const
Gets the last chunk raw data (undecoded)
Definition: qwrk.cpp:170
Q_DECL_DEPRECATED void signalWRKExpression(int track, long time, int code, const QString &text)
Emitted after reading an expression indication (notation) chunk.
bool getAutoRewind() const
Auto-rewind?
Definition: qwrk.cpp:309
bool getMetroPlay() const
Metronome on during playback?
Definition: qwrk.cpp:327
Q_DECL_DEPRECATED QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
Definition: qwrk.cpp:148
int getFrom() const
From marker time.
Definition: qwrk.cpp:201
Q_DECL_DEPRECATED void signalWRKText(int track, long time, int type, const QString &data)
Emitted after reading a text message.
void signalWRKTimeFormat(int frames, int offset)
Emitted after reading a SMPTE time format chunk.
void signalWRKSysex(int bank, const QString &name, bool autosend, int port, const QByteArray &data)
Emitted after reading a System Exclusive Bank.
void readFromFile(const QString &fileName)
Reads a stream from a disk file.
Definition: qwrk.cpp:701
int getCountIn() const
Measures of count-in (0=no count-in)
Definition: qwrk.cpp:354
int getCurTempoOfs() const
Which of the 3 tempo offsets is used: 0..2.
Definition: qwrk.cpp:381
Q_DECL_DEPRECATED void signalWRKComments(const QString &data)
Emitted after reading a comments chunk.
void signalWRKCtlChange(int track, long time, int chan, int ctl, int value)
Emitted after reading a Control Change message.
void signalWRKTrackReps(int track, int reps)
Emitted after reading a track offset chunk.
void signalWRKKeySig(int bar, int alt)
Emitted after reading a WRK Key Signature.
bool getAutoRestart() const
Auto-restart?
Definition: qwrk.cpp:372
Q_DECL_DEPRECATED void signalWRKTrack(const QString &name1, const QString &name2, int trackno, int channel, int pitch, int velocity, int port, bool selected, bool muted, bool loop)
Emitted after reading a track prefix chunk.
int getClock() const
Clock Source (0=Int, 1=MIDI, 2=FSK, 3=SMPTE)
Definition: qwrk.cpp:228
Q_DECL_DEPRECATED void signalWRKMarker(long time, int type, const QString &data)
Emitted after reading a text marker This is deprecated because the class QTextCodec was removed from ...
int getKeySig() const
Key signature (0=C, 1=C#, ...
Definition: qwrk.cpp:219
void signalWRKStringTable2(const QList< QByteArray > &strs)
Emitted after reading a string event types chunk.
bool getMetroAccent() const
Metronome accents primary beats?
Definition: qwrk.cpp:345
int getTempoOfs1() const
Fixed-point ratio value of tempo offset 1.
Definition: qwrk.cpp:400
@ NTRKOFS_CHUNK
Track offset.
Definition: qwrk.h:77
@ NTRACK_CHUNK
Track prefix.
Definition: qwrk.h:79
@ TRKPATCH_CHUNK
Track patch.
Definition: qwrk.h:66
@ MARKERS_CHUNK
Markers.
Definition: qwrk.h:72
@ STRTAB_CHUNK
Table of text event types.
Definition: qwrk.h:73
@ NTEMPO_CHUNK
New Tempo map.
Definition: qwrk.h:67
@ VARS_CHUNK
Global variables.
Definition: qwrk.h:56
@ TRKBANK_CHUNK
Track bank.
Definition: qwrk.h:78
@ COMMENTS_CHUNK
Comments.
Definition: qwrk.h:61
@ SGMNT_CHUNK
Segment prefix.
Definition: qwrk.h:82
@ SOFTVER_CHUNK
Software version which saved the file.
Definition: qwrk.h:83
@ TRKNAME_CHUNK
Track name.
Definition: qwrk.h:75
@ TIMEFMT_CHUNK
SMPTE time format.
Definition: qwrk.h:64
@ END_CHUNK
Last chunk, end of file.
Definition: qwrk.h:84
@ STREAM_CHUNK
Events stream.
Definition: qwrk.h:55
@ TRACK_CHUNK
Track prefix.
Definition: qwrk.h:54
@ TIMEBASE_CHUNK
Timebase. If present is the first chunk in the file.
Definition: qwrk.h:63
@ TRKOFFS_CHUNK
Track offset.
Definition: qwrk.h:62
@ NSYSEX_CHUNK
System exclusive bank.
Definition: qwrk.h:80
@ THRU_CHUNK
Extended thru parameters.
Definition: qwrk.h:68
@ SYSEX2_CHUNK
System exclusive bank.
Definition: qwrk.h:71
@ NSTREAM_CHUNK
Events stream.
Definition: qwrk.h:81
@ TEMPO_CHUNK
Tempo map.
Definition: qwrk.h:57
@ VARIABLE_CHUNK
Variable record chunk.
Definition: qwrk.h:76
@ METER_CHUNK
Meter map.
Definition: qwrk.h:58
@ METERKEY_CHUNK
Meter/Key map.
Definition: qwrk.h:74
@ TRKREPS_CHUNK
Track repetitions.
Definition: qwrk.h:65
@ TRKVOL_CHUNK
Track volume.
Definition: qwrk.h:70
@ SYSEX_CHUNK
System exclusive bank.
Definition: qwrk.h:59
@ LYRICS_CHUNK
Events stream with lyrics.
Definition: qwrk.h:69
Drumstick common.
Definition: alsaclient.cpp:68
Cakewalk WRK Files Input.