drumstick  2.3.1
qwrk.cpp
Go to the documentation of this file.
1 /*
2  WRK File component
3  Copyright (C) 2010-2021, 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 
33 namespace drumstick { namespace File {
34 
47 class QWrk::QWrkPrivate {
48 public:
49  QWrkPrivate():
50  m_Now(0),
51  m_From(0),
52  m_Thru(11930),
53  m_KeySig(0),
54  m_Clock(0),
55  m_AutoSave(0),
56  m_PlayDelay(0),
57  m_ZeroCtrls(false),
58  m_SendSPP(true),
59  m_SendCont(true),
60  m_PatchSearch(false),
61  m_AutoStop(false),
62  m_StopTime(4294967295U),
63  m_AutoRewind(false),
64  m_RewindTime(0),
65  m_MetroPlay(false),
66  m_MetroRecord(true),
67  m_MetroAccent(false),
68  m_CountIn(1),
69  m_ThruOn(true),
70  m_AutoRestart(false),
71  m_CurTempoOfs(1),
72  m_TempoOfs1(32),
73  m_TempoOfs2(64),
74  m_TempoOfs3(128),
75  m_PunchEnabled(false),
76  m_PunchInTime(0),
77  m_PunchOutTime(0),
78  m_EndAllTime(0),
79  m_division(120),
80  m_codec(nullptr),
81  m_IOStream(nullptr)
82  { }
83 
84  quint32 m_Now;
85  quint32 m_From;
86  quint32 m_Thru;
87  quint8 m_KeySig;
88  quint8 m_Clock;
89  quint8 m_AutoSave;
90  quint8 m_PlayDelay;
91  bool m_ZeroCtrls;
92  bool m_SendSPP;
93  bool m_SendCont;
94  bool m_PatchSearch;
95  bool m_AutoStop;
96  quint32 m_StopTime;
97  bool m_AutoRewind;
98  quint32 m_RewindTime;
99  bool m_MetroPlay;
100  bool m_MetroRecord;
101  bool m_MetroAccent;
102  quint8 m_CountIn;
103  bool m_ThruOn;
104  bool m_AutoRestart;
105  quint8 m_CurTempoOfs;
106  quint8 m_TempoOfs1;
107  quint8 m_TempoOfs2;
108  quint8 m_TempoOfs3;
109  bool m_PunchEnabled;
110  quint32 m_PunchInTime;
111  quint32 m_PunchOutTime;
112  quint32 m_EndAllTime;
113 
114  int m_division;
115  QTextCodec *m_codec;
116  QDataStream *m_IOStream;
117  QByteArray m_lastChunkData;
118  QList<RecTempo> m_tempos;
119 
120  qint64 m_lastChunkPos;
121  qint64 internalFilePos();
122 };
123 
128 QWrk::QWrk(QObject * parent) :
129  QObject(parent),
130  d(new QWrkPrivate)
131 { }
132 
137 { }
138 
143 QTextCodec* QWrk::getTextCodec()
144 {
145  return d->m_codec;
146 }
147 
154 void QWrk::setTextCodec(QTextCodec *codec)
155 {
156  d->m_codec = codec;
157 }
158 
164 QByteArray QWrk::getLastChunkRawData() const
165 {
166  return d->m_lastChunkData;
167 }
168 
172 void QWrk::readRawData(int size)
173 {
174  if (size > 0) {
175  d->m_lastChunkData = d->m_IOStream->device()->read(size);
176  } else {
177  d->m_lastChunkData.clear();
178  //qDebug() << Q_FUNC_INFO << "Size error:" << size;
179  }
180 }
181 
186 int QWrk::getNow() const
187 {
188  return d->m_Now;
189 }
190 
195 int QWrk::getFrom() const
196 {
197  return d->m_From;
198 }
199 
204 int QWrk::getThru() const
205 {
206  return d->m_Thru;
207 }
208 
213 int QWrk::getKeySig() const
214 {
215  return d->m_KeySig;
216 }
217 
222 int QWrk::getClock() const
223 {
224  return d->m_Clock;
225 }
226 
231 int QWrk::getAutoSave() const
232 {
233  return d->m_AutoSave;
234 }
235 
241 {
242  return d->m_PlayDelay;
243 }
244 
249 bool QWrk::getZeroCtrls() const
250 {
251  return d->m_ZeroCtrls;
252 }
253 
258 bool QWrk::getSendSPP() const
259 {
260  return d->m_SendSPP;
261 }
262 
267 bool QWrk::getSendCont() const
268 {
269  return d->m_SendCont;
270 }
271 
277 {
278  return d->m_PatchSearch;
279 }
280 
285 bool QWrk::getAutoStop() const
286 {
287  return d->m_AutoStop;
288 }
289 
294 unsigned int QWrk::getStopTime() const
295 {
296  return d->m_StopTime;
297 }
298 
304 {
305  return d->m_AutoRewind;
306 }
307 
313 {
314  return d->m_RewindTime;
315 }
316 
321 bool QWrk::getMetroPlay() const
322 {
323  return d->m_MetroPlay;
324 }
325 
331 {
332  return d->m_MetroRecord;
333 }
334 
340 {
341  return d->m_MetroAccent;
342 }
343 
348 int QWrk::getCountIn() const
349 {
350  return d->m_CountIn;
351 }
352 
357 bool QWrk::getThruOn() const
358 {
359  return d->m_ThruOn;
360 }
361 
367 {
368  return d->m_AutoRestart;
369 }
370 
376 {
377  return d->m_CurTempoOfs;
378 }
379 
395 {
396  return d->m_TempoOfs1;
397 }
398 
414 {
415  return d->m_TempoOfs2;
416 }
417 
433 {
434  return d->m_TempoOfs3;
435 }
436 
442 {
443  return d->m_PunchEnabled;
444 }
445 
451 {
452  return d->m_PunchInTime;
453 }
454 
460 {
461  return d->m_PunchOutTime;
462 }
463 
469 {
470  return d->m_EndAllTime;
471 }
472 
477 quint8 QWrk::readByte()
478 {
479  quint8 b = 0xff;
480  if (!d->m_IOStream->atEnd())
481  *d->m_IOStream >> b;
482  return b;
483 }
484 
491 quint16 QWrk::to16bit(quint8 c1, quint8 c2)
492 {
493  quint16 value = (c1 << 8);
494  value += c2;
495  return value;
496 }
497 
506 quint32 QWrk::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
507 {
508  quint32 value = (c1 << 24);
509  value += (c2 << 16);
510  value += (c3 << 8);
511  value += c4;
512  return value;
513 }
514 
519 quint16 QWrk::read16bit()
520 {
521  quint8 c1, c2;
522  c1 = readByte();
523  c2 = readByte();
524  return to16bit(c2, c1);
525 }
526 
531 quint32 QWrk::read24bit()
532 {
533  quint8 c1, c2, c3;
534  c1 = readByte();
535  c2 = readByte();
536  c3 = readByte();
537  return to32bit(0, c3, c2, c1);
538 }
539 
544 quint32 QWrk::read32bit()
545 {
546  quint8 c1, c2, c3, c4;
547  c1 = readByte();
548  c2 = readByte();
549  c3 = readByte();
550  c4 = readByte();
551  return to32bit(c4, c3, c2, c1);
552 }
553 
558 QString QWrk::readString(int len)
559 {
560  QString s;
561  if ( len > 0 ) {
562  QByteArray data = readByteArray(len);
563  if (d->m_codec == nullptr) {
564  s = QString::fromLatin1(data);
565  } else {
566  s = d->m_codec->toUnicode(data);
567  }
568  }
569  return s;
570 }
571 
576 QByteArray QWrk::readByteArray(int len)
577 {
578  QByteArray data;
579  if ( len > 0 ) {
580  quint8 c = 0xff;
581  for ( int i = 0; i < len && c != 0 && !atEnd(); ++i ) {
582  c = readByte();
583  if ( c != 0)
584  data += c;
585  }
586  }
587  return data;
588 }
589 
595 QString QWrk::readVarString()
596 {
597  QString s;
598  QByteArray data = readVarByteArray();
599  if (d->m_codec == nullptr) {
600  s = QString::fromLatin1(data);
601  } else {
602  s = d->m_codec->toUnicode(data);
603  }
604  return s;
605 }
606 
611 QByteArray QWrk::readVarByteArray()
612 {
613  QByteArray data;
614  quint8 b;
615  do {
616  b = readByte();
617  if (b != 0)
618  data += b;
619  } while (b != 0 && !atEnd());
620  return data;
621 }
622 
628 {
629  return d->internalFilePos();
630 }
631 
636 void QWrk::seek(qint64 pos)
637 {
638  if (!d->m_IOStream->device()->seek(pos)) {
639  //qDebug() << Q_FUNC_INFO << "Error, pos:" << pos;
640  }
641 }
642 
647 bool QWrk::atEnd()
648 {
649  return d->m_IOStream->atEnd();
650 }
651 
656 void QWrk::readGap(int size)
657 {
658  if ( size > 0)
659  seek( d->internalFilePos() + size );
660 }
661 
666 void QWrk::readFromStream(QDataStream *stream)
667 {
668  d->m_IOStream = stream;
669  wrkRead();
670 }
671 
676 void QWrk::readFromFile(const QString& fileName)
677 {
678  QFile file(fileName);
679  file.open(QIODevice::ReadOnly);
680  QDataStream ds(&file);
681  readFromStream(&ds);
682  file.close();
683 }
684 
685 void QWrk::processTrackChunk()
686 {
687  int namelen;
688  QString name[2];
689  QByteArray data[2];
690  int trackno;
691  int channel;
692  int pitch;
693  int velocity;
694  int port;
695  bool selected;
696  bool muted;
697  bool loop;
698 
699  trackno = read16bit();
700  for(int i=0; i<2; ++i) {
701  namelen = readByte();
702  if (d->m_codec == nullptr) {
703  data[i] = readByteArray(namelen);
704  } else {
705  name[i] = readString(namelen);
706  }
707  }
708  channel = readByte() & 0x0f;
709  pitch = readByte();
710  velocity = readByte();
711  port = readByte();
712  quint8 flags = readByte();
713  selected = ((flags & 1) != 0);
714  muted = ((flags & 2) != 0);
715  loop = ((flags & 4) != 0);
716  if (d->m_codec == nullptr) {
717  Q_EMIT signalWRKTrack2( data[0], data[1],
718  trackno, channel, pitch,
719  velocity, port, selected,
720  muted, loop );
721  } else {
722  Q_EMIT signalWRKTrack( name[0], name[1],
723  trackno, channel, pitch,
724  velocity, port, selected,
725  muted, loop );
726  }
727 }
728 
729 void QWrk::processVarsChunk()
730 {
731  d->m_Now = read32bit();
732  d->m_From = read32bit();
733  d->m_Thru = read32bit();
734  d->m_KeySig = readByte();
735  d->m_Clock = readByte();
736  d->m_AutoSave = readByte();
737  d->m_PlayDelay = readByte();
738  readGap(1);
739  d->m_ZeroCtrls = (readByte() != 0);
740  d->m_SendSPP = (readByte() != 0);
741  d->m_SendCont = (readByte() != 0);
742  d->m_PatchSearch = (readByte() != 0);
743  d->m_AutoStop = (readByte() != 0);
744  d->m_StopTime = read32bit();
745  d->m_AutoRewind = (readByte() != 0);
746  d->m_RewindTime = read32bit();
747  d->m_MetroPlay = (readByte() != 0);
748  d->m_MetroRecord = (readByte() != 0);
749  d->m_MetroAccent = (readByte() != 0);
750  d->m_CountIn = readByte();
751  readGap(2);
752  d->m_ThruOn = (readByte() != 0);
753  readGap(19);
754  d->m_AutoRestart = (readByte() != 0);
755  d->m_CurTempoOfs = readByte();
756  d->m_TempoOfs1 = readByte();
757  d->m_TempoOfs2 = readByte();
758  d->m_TempoOfs3 = readByte();
759  readGap(2);
760  d->m_PunchEnabled = (readByte() != 0);
761  d->m_PunchInTime = read32bit();
762  d->m_PunchOutTime = read32bit();
763  d->m_EndAllTime = read32bit();
764 
765  Q_EMIT signalWRKGlobalVars();
766 }
767 
768 void QWrk::processTimebaseChunk()
769 {
770  quint16 timebase = read16bit();
771  d->m_division = timebase;
772  Q_EMIT signalWRKTimeBase(timebase);
773 }
774 
775 void QWrk::processNoteArray(int track, int events)
776 {
777  quint32 time = 0;
778  quint8 status = 0, data1 = 0, data2 = 0, i = 0;
779  quint16 dur = 0;
780  int value = 0, type = 0, channel = 0, len = 0;
781  QString text;
782  QByteArray data;
783  for ( i = 0; (i < events) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i ) {
784  time = read24bit();
785  status = readByte();
786  dur = 0;
787  if (status >= 0x90) {
788  type = status & 0xf0;
789  channel = status & 0x0f;
790  data1 = readByte();
791  if (type == 0x90 || type == 0xA0 || type == 0xB0 || type == 0xE0)
792  data2 = readByte();
793  if (type == 0x90)
794  dur = read16bit();
795  switch (type) {
796  case 0x90:
797  Q_EMIT signalWRKNote(track, time, channel, data1, data2, dur);
798  break;
799  case 0xA0:
800  Q_EMIT signalWRKKeyPress(track, time, channel, data1, data2);
801  break;
802  case 0xB0:
803  Q_EMIT signalWRKCtlChange(track, time, channel, data1, data2);
804  break;
805  case 0xC0:
806  Q_EMIT signalWRKProgram(track, time, channel, data1);
807  break;
808  case 0xD0:
809  Q_EMIT signalWRKChanPress(track, time, channel, data1);
810  break;
811  case 0xE0:
812  value = (data2 << 7) + data1 - 8192;
813  Q_EMIT signalWRKPitchBend(track, time, channel, value);
814  break;
815  case 0xF0:
816  Q_EMIT signalWRKSysexEvent(track, time, data1);
817  break;
818  }
819  } else if (status == 5) {
820  int code = read16bit();
821  len = read32bit();
822  if (d->m_codec == nullptr) {
823  data = readByteArray(len);
824  Q_EMIT signalWRKExpression2(track, time, code, data);
825  } else {
826  text = readString(len);
827  Q_EMIT signalWRKExpression(track, time, code, text);
828  }
829  } else if (status == 6) {
830  int code = read16bit();
831  dur = read16bit();
832  readGap(4);
833  Q_EMIT signalWRKHairpin(track, time, code, dur);
834  } else if (status == 7) {
835  len = read32bit();
836  text = readString(len);
837  data.clear();
838  for(int j=0; j<13; ++j) {
839  int byte = readByte();
840  data += byte;
841  }
842  Q_EMIT signalWRKChord(track, time, text, data);
843  } else if (status == 8) {
844  len = read16bit();
845  data.clear();
846  for(int j=0; j<len; ++j) {
847  int byte = readByte();
848  data += byte;
849  }
850  Q_EMIT signalWRKSysex(0, QString(), false, 0, data);
851  } else {
852  len = read32bit();
853  if (d->m_codec == nullptr) {
854  data = readByteArray(len);
855  Q_EMIT signalWRKText2(track, time, status, data);
856  } else {
857  text = readString(len);
858  Q_EMIT signalWRKText(track, time, status, text);
859  }
860  }
861  }
862  if ((i < events) && atEnd()) {
863  Q_EMIT signalWRKError("Corrupted file");
864  }
865  Q_EMIT signalWRKStreamEnd(time + dur);
866 }
867 
868 void QWrk::processStreamChunk()
869 {
870  long time = 0;
871  int dur = 0, value = 0, type = 0, channel = 0, i = 0;
872  quint8 status = 0, data1 = 0, data2 = 0;
873  quint16 track = read16bit();
874  int events = read16bit();
875  for ( i = 0; (i < events) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i ) {
876  time = read24bit();
877  status = readByte();
878  data1 = readByte();
879  data2 = readByte();
880  dur = read16bit();
881  type = status & 0xf0;
882  channel = status & 0x0f;
883  switch (type) {
884  case 0x90:
885  Q_EMIT signalWRKNote(track, time, channel, data1, data2, dur);
886  break;
887  case 0xA0:
888  Q_EMIT signalWRKKeyPress(track, time, channel, data1, data2);
889  break;
890  case 0xB0:
891  Q_EMIT signalWRKCtlChange(track, time, channel, data1, data2);
892  break;
893  case 0xC0:
894  Q_EMIT signalWRKProgram(track, time, channel, data1);
895  break;
896  case 0xD0:
897  Q_EMIT signalWRKChanPress(track, time, channel, data1);
898  break;
899  case 0xE0:
900  value = (data2 << 7) + data1 - 8192;
901  Q_EMIT signalWRKPitchBend(track, time, channel, value);
902  break;
903  case 0xF0:
904  Q_EMIT signalWRKSysexEvent(track, time, data1);
905  break;
906  }
907  }
908  if ((i < events) && atEnd()) {
909  Q_EMIT signalWRKError("Corrupted file");
910  }
911  Q_EMIT signalWRKStreamEnd(time + dur);
912 }
913 
914 void QWrk::processMeterChunk()
915 {
916  int count = read16bit();
917  for (int i = 0; i < count; ++i) {
918  readGap(4);
919  int measure = read16bit();
920  int num = readByte();
921  int den = pow(2.0, readByte());
922  readGap(4);
923  Q_EMIT signalWRKTimeSig(measure, num, den);
924  }
925 }
926 
927 void QWrk::processMeterKeyChunk()
928 {
929  int count = read16bit();
930  for (int i = 0; i < count; ++i) {
931  int measure = read16bit();
932  int num = readByte();
933  int den = pow(2.0, readByte());
934  qint8 alt = readByte();
935  Q_EMIT signalWRKTimeSig(measure, num, den);
936  Q_EMIT signalWRKKeySig(measure, alt);
937  }
938 }
939 
940 double QWrk::getRealTime(long ticks) const
941 {
942  double division = 1.0 * d->m_division;
943  RecTempo last;
944  last.time = 0;
945  last.tempo = 100.0;
946  last.seconds = 0.0;
947  if (!d->m_tempos.isEmpty()) {
948  foreach(const RecTempo& rec, d->m_tempos) {
949  if (rec.time >= ticks)
950  break;
951  last = rec;
952  }
953  }
954  return last.seconds + (((ticks - last.time) / division) * (60.0 / last.tempo));
955 }
956 
957 void QWrk::processTempoChunk(int factor)
958 {
959  double division = 1.0 * d->m_division;
960  int count = read16bit();
961  RecTempo last, next;
962  for (int i = 0; i < count; ++i) {
963 
964  long time = read32bit();
965  readGap(4);
966  long tempo = read16bit() * factor;
967  readGap(8);
968 
969  next.time = time;
970  next.tempo = tempo / 100.0;
971  next.seconds = 0.0;
972  last.time = 0;
973  last.tempo = next.tempo;
974  last.seconds = 0.0;
975  if (! d->m_tempos.isEmpty()) {
976  foreach(const RecTempo& rec, d->m_tempos) {
977  if (rec.time >= time)
978  break;
979  last = rec;
980  }
981  next.seconds = last.seconds +
982  (((time - last.time) / division) * (60.0 / last.tempo));
983  }
984  d->m_tempos.append(next);
985 
986  Q_EMIT signalWRKTempo(time, tempo);
987  }
988 }
989 
990 void QWrk::processSysexChunk()
991 {
992  int j;
993  QString name;
994  QByteArray data;
995  int bank = readByte();
996  int length = read16bit();
997  bool autosend = (readByte() != 0);
998  int namelen = readByte();
999  name = readString(namelen);
1000  for(j=0; j<length; ++j) {
1001  int byte = readByte();
1002  data += byte;
1003  }
1004  Q_EMIT signalWRKSysex(bank, name, autosend, 0, data);
1005 }
1006 
1007 void QWrk::processSysex2Chunk()
1008 {
1009  int j;
1010  QString name;
1011  QByteArray data;
1012  int bank = read16bit();
1013  int length = read32bit();
1014  quint8 b = readByte();
1015  int port = ( b & 0xf0 ) >> 4;
1016  bool autosend = ( (b & 0x0f) != 0);
1017  int namelen = readByte();
1018  name = readString(namelen);
1019  for(j=0; j<length; ++j) {
1020  int byte = readByte();
1021  data += byte;
1022  }
1023  Q_EMIT signalWRKSysex(bank, name, autosend, port, data);
1024 }
1025 
1026 void QWrk::processNewSysexChunk()
1027 {
1028  int j;
1029  QString name;
1030  QByteArray data;
1031  int bank = read16bit();
1032  int length = read32bit();
1033  int port = read16bit();
1034  bool autosend = (readByte() != 0);
1035  int namelen = readByte();
1036  name = readString(namelen);
1037  for(j=0; j<length; ++j) {
1038  int byte = readByte();
1039  data += byte;
1040  }
1041  Q_EMIT signalWRKSysex(bank, name, autosend, port, data);
1042 }
1043 
1044 void QWrk::processThruChunk()
1045 {
1046  readGap(2);
1047  qint8 port = readByte(); // 0->127
1048  qint8 channel = readByte(); // -1, 0->15
1049  qint8 keyPlus = readByte(); // 0->127
1050  qint8 velPlus = readByte(); // 0->127
1051  qint8 localPort = readByte();
1052  qint8 mode = readByte();
1053  Q_EMIT signalWRKThru(mode, port, channel, keyPlus, velPlus, localPort);
1054 }
1055 
1056 void QWrk::processTrackOffset()
1057 {
1058  quint16 track = read16bit();
1059  qint16 offset = read16bit();
1060  Q_EMIT signalWRKTrackOffset(track, offset);
1061 }
1062 
1063 void QWrk::processTrackReps()
1064 {
1065  quint16 track = read16bit();
1066  quint16 reps = read16bit();
1067  Q_EMIT signalWRKTrackReps(track, reps);
1068 }
1069 
1070 void QWrk::processTrackPatch()
1071 {
1072  quint16 track = read16bit();
1073  qint8 patch = readByte();
1074  Q_EMIT signalWRKTrackPatch(track, patch);
1075 }
1076 
1077 void QWrk::processTimeFormat()
1078 {
1079  quint16 fmt = read16bit();
1080  quint16 ofs = read16bit();
1081  Q_EMIT signalWRKTimeFormat(fmt, ofs);
1082 }
1083 
1084 void QWrk::processComments()
1085 {
1086  int len = read16bit();
1087  if (d->m_codec == nullptr) {
1088  QByteArray data = readByteArray(len);
1089  Q_EMIT signalWRKComments2(data);
1090  } else {
1091  QString text = readString(len);
1092  Q_EMIT signalWRKComments(text);
1093  }
1094 }
1095 
1096 void QWrk::processVariableRecord(int max)
1097 {
1098  int datalen = max - 32;
1099  QByteArray data;
1100  QString name = readVarString();
1101  readGap(31 - name.length());
1102  for ( int i = 0; i < datalen; ++i )
1103  data += readByte();
1104  Q_EMIT signalWRKVariableRecord(name, data);
1105 }
1106 
1107 void QWrk::processUnknown(int id)
1108 {
1109  Q_EMIT signalWRKUnknownChunk(id, d->m_lastChunkData);
1110 }
1111 
1112 void QWrk::processNewTrack()
1113 {
1114  QByteArray data;
1115  QString name;
1116  qint16 bank = -1;
1117  qint16 patch = -1;
1118  //qint16 vol = -1;
1119  //qint16 pan = -1;
1120  qint8 key = -1;
1121  qint8 vel = 0;
1122  quint8 port = 0;
1123  qint8 channel = 0;
1124  bool selected = false;
1125  bool muted = false;
1126  bool loop = false;
1127  quint16 track = read16bit();
1128  quint8 len = readByte();
1129  if (d->m_codec == nullptr) {
1130  data = readByteArray(len);
1131  } else {
1132  name = readString(len);
1133  }
1134  bank = read16bit();
1135  patch = read16bit();
1136  /*vol =*/ read16bit();
1137  /*pan =*/ read16bit();
1138  key = readByte();
1139  vel = readByte();
1140  readGap(7);
1141  port = readByte();
1142  channel = readByte();
1143  muted = (readByte() != 0);
1144  if (d->m_codec == nullptr) {
1145  Q_EMIT signalWRKNewTrack2(data, track, channel, key, vel, port, selected, muted, loop);
1146  } else {
1147  Q_EMIT signalWRKNewTrack(name, track, channel, key, vel, port, selected, muted, loop);
1148  }
1149  if (bank > -1)
1150  Q_EMIT signalWRKTrackBank(track, bank);
1151  if (patch > -1) {
1152  if (channel > -1)
1153  Q_EMIT signalWRKProgram(track, 0, channel, patch);
1154  else
1155  Q_EMIT signalWRKTrackPatch(track, patch);
1156  }
1157 }
1158 
1159 void QWrk::processSoftVer()
1160 {
1161  int len = readByte();
1162  QString vers = readString(len);
1163  Q_EMIT signalWRKSoftVer(vers);
1164 }
1165 
1166 void QWrk::processTrackName()
1167 {
1168  int track = read16bit();
1169  int len = readByte();
1170  if (d->m_codec == nullptr) {
1171  QByteArray data = readByteArray(len);
1172  Q_EMIT signalWRKTrackName2(track, data);
1173  } else {
1174  QString name = readString(len);
1175  Q_EMIT signalWRKTrackName(track, name);
1176  }
1177 }
1178 
1179 void QWrk::processStringTable()
1180 {
1181  if (d->m_codec == nullptr) {
1182  QList<QByteArray> table;
1183  int rows = read16bit();
1184  for (int i = 0; i < rows; ++i) {
1185  int len = readByte();
1186  QByteArray name = readByteArray(len);
1187  /*int idx =*/ readByte();
1188  table.insert(i, name);
1189  }
1190  Q_EMIT signalWRKStringTable2(table);
1191  } else {
1192  QStringList table;
1193  int rows = read16bit();
1194  for (int i = 0; i < rows; ++i) {
1195  int len = readByte();
1196  QString name = readString(len);
1197  /*int idx =*/ readByte();
1198  table.insert(i, name);
1199  }
1200  Q_EMIT signalWRKStringTable(table);
1201  }
1202 }
1203 
1204 void QWrk::processLyricsStream()
1205 {
1206  quint16 track = read16bit();
1207  int events = read32bit();
1208  processNoteArray(track, events);
1209 }
1210 
1211 void QWrk::processTrackVol()
1212 {
1213  quint16 track = read16bit();
1214  int vol = read16bit();
1215  Q_EMIT signalWRKTrackVol(track, vol);
1216 }
1217 
1218 void QWrk::processNewTrackOffset()
1219 {
1220  quint16 track = read16bit();
1221  int offset = read32bit();
1222  Q_EMIT signalWRKTrackOffset(track, offset);
1223 }
1224 
1225 void QWrk::processTrackBank()
1226 {
1227  quint16 track = read16bit();
1228  int bank = read16bit();
1229  Q_EMIT signalWRKTrackBank(track, bank);
1230 }
1231 
1232 void QWrk::processSegmentChunk()
1233 {
1234  QString name;
1235  QByteArray data;
1236  int track = read16bit();
1237  int offset = read32bit();
1238  readGap(8);
1239  int len = readByte();
1240  if (d->m_codec == nullptr) {
1241  data = readByteArray(len);
1242  } else {
1243  name = readString(len);
1244  }
1245  readGap(20);
1246  if (d->m_codec == nullptr) {
1247  Q_EMIT signalWRKSegment2(track, offset, data);
1248  } else {
1249  Q_EMIT signalWRKSegment(track, offset, name);
1250  }
1251  int events = read32bit();
1252  processNoteArray(track, events);
1253 }
1254 
1255 void QWrk::processNewStream()
1256 {
1257  QString name;
1258  QByteArray data;
1259  int track = read16bit();
1260  int len = readByte();
1261  if (d->m_codec == nullptr) {
1262  data = readByteArray(len);
1263  Q_EMIT signalWRKSegment2(track, 0, data);
1264  } else {
1265  name = readString(len);
1266  Q_EMIT signalWRKSegment(track, 0, name);
1267  }
1268  int events = read32bit();
1269  processNoteArray(track, events);
1270 }
1271 
1272 void QWrk::processEndChunk()
1273 {
1274  emit signalWRKEnd();
1275 }
1276 
1277 int QWrk::readChunk()
1278 {
1279  qint64 start_pos = d->internalFilePos();
1280  int ck = readByte();
1281  if (ck != END_CHUNK) {
1282  quint32 ck_len = read32bit();
1283  if (ck_len > d->m_IOStream->device()->bytesAvailable()) {
1284  Q_EMIT signalWRKError("Corrupted file");
1285  seek(start_pos);
1286  return END_CHUNK;
1287  }
1288  start_pos = d->internalFilePos();
1289  d->m_lastChunkPos = start_pos + ck_len;
1290  readRawData(ck_len);
1291  seek(start_pos);
1292  switch (ck) {
1293  case TRACK_CHUNK:
1294  processTrackChunk();
1295  break;
1296  case VARS_CHUNK:
1297  processVarsChunk();
1298  break;
1299  case TIMEBASE_CHUNK:
1300  processTimebaseChunk();
1301  break;
1302  case STREAM_CHUNK:
1303  processStreamChunk();
1304  break;
1305  case METER_CHUNK:
1306  processMeterChunk();
1307  break;
1308  case TEMPO_CHUNK:
1309  processTempoChunk(100);
1310  break;
1311  case NTEMPO_CHUNK:
1312  processTempoChunk();
1313  break;
1314  case SYSEX_CHUNK:
1315  processSysexChunk();
1316  break;
1317  case THRU_CHUNK:
1318  processThruChunk();
1319  break;
1320  case TRKOFFS_CHUNK:
1321  processTrackOffset();
1322  break;
1323  case TRKREPS_CHUNK:
1324  processTrackReps();
1325  break;
1326  case TRKPATCH_CHUNK:
1327  processTrackPatch();
1328  break;
1329  case TIMEFMT_CHUNK:
1330  processTimeFormat();
1331  break;
1332  case COMMENTS_CHUNK:
1333  processComments();
1334  break;
1335  case VARIABLE_CHUNK:
1336  processVariableRecord(ck_len);
1337  break;
1338  case NTRACK_CHUNK:
1339  processNewTrack();
1340  break;
1341  case SOFTVER_CHUNK:
1342  processSoftVer();
1343  break;
1344  case TRKNAME_CHUNK:
1345  processTrackName();
1346  break;
1347  case STRTAB_CHUNK:
1348  processStringTable();
1349  break;
1350  case LYRICS_CHUNK:
1351  processLyricsStream();
1352  break;
1353  case TRKVOL_CHUNK:
1354  processTrackVol();
1355  break;
1356  case NTRKOFS_CHUNK:
1357  processNewTrackOffset();
1358  break;
1359  case TRKBANK_CHUNK:
1360  processTrackBank();
1361  break;
1362  case METERKEY_CHUNK:
1363  processMeterKeyChunk();
1364  break;
1365  case SYSEX2_CHUNK:
1366  processSysex2Chunk();
1367  break;
1368  case NSYSEX_CHUNK:
1369  processNewSysexChunk();
1370  break;
1371  case SGMNT_CHUNK:
1372  processSegmentChunk();
1373  break;
1374  case NSTREAM_CHUNK:
1375  processNewStream();
1376  break;
1377  default:
1378  processUnknown(ck);
1379  }
1380  if (d->internalFilePos() != d->m_lastChunkPos) {
1381  //qDebug() << Q_FUNC_INFO << "Current pos:" << d->internalFilePos() << "should be:" << d->m_lastChunkPos;
1382  seek(d->m_lastChunkPos);
1383  }
1384  }
1385  return ck;
1386 }
1387 
1388 void QWrk::wrkRead()
1389 {
1390  QByteArray hdr(HEADER.length(), ' ');
1391  d->m_tempos.clear();
1392  d->m_IOStream->device()->read(hdr.data(), HEADER.length());
1393  if (hdr == HEADER) {
1394  int vma, vme;
1395  int ck_id;
1396  readGap(1);
1397  vme = readByte();
1398  vma = readByte();
1399  Q_EMIT signalWRKHeader(vma, vme);
1400  do {
1401  ck_id = readChunk();
1402  } while ((ck_id != END_CHUNK) && !atEnd());
1403  if (!atEnd()) {
1404  //qDebug() << Q_FUNC_INFO << "extra junk past the end at" << d->internalFilePos();
1405  readRawData(d->m_IOStream->device()->bytesAvailable());
1406  processUnknown(ck_id);
1407  }
1408  processEndChunk();
1409  } else
1410  Q_EMIT signalWRKError("Invalid file format");
1411 }
1412 
1413 qint64 QWrk::QWrkPrivate::internalFilePos()
1414 {
1415  return m_IOStream->device()->pos();
1416 }
1417 
1418 const QByteArray QWrk::HEADER = QByteArrayLiteral("CAKEWALK");
1419 
1420 } // namespace File
1421 } // namespace drumstick
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:330
bool getPunchEnabled() const
Auto-Punch enabled?
Definition: qwrk.cpp:441
void signalWRKText(int track, long time, int type, const QString &data)
Emitted after reading a text message.
int getRewindTime() const
Auto-rewind time.
Definition: qwrk.cpp:312
bool getZeroCtrls() const
Zero continuous controllers?
Definition: qwrk.cpp:249
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.
QWrk(QObject *parent=nullptr)
Constructor.
Definition: qwrk.cpp:128
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:132
void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
Definition: qwrk.cpp:154
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:231
long getFilePos()
Current position in the data stream.
Definition: qwrk.cpp:627
bool getThruOn() const
MIDI Thru enabled? (only used if no THRU rec)
Definition: qwrk.cpp:357
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:186
int getPunchOutTime() const
Punch-out time.
Definition: qwrk.cpp:459
void signalWRKComments(const QString &data)
Emitted after reading a comments chunk.
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:285
int getEndAllTime() const
Time of latest event (incl.
Definition: qwrk.cpp:468
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.
void signalWRKStringTable(const QStringList &strs)
Emitted after reading a string event types chunk.
int getPlayDelay() const
Play Delay.
Definition: qwrk.cpp:240
bool getSendSPP() const
Send Song Position Pointer?
Definition: qwrk.cpp:258
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:136
void signalWRKSegment(int track, long time, const QString &name)
Emitted after reading a segment prefix chunk.
void signalWRKTempo(long time, int tempo)
Emitted after reading a Tempo Change message.
void signalWRKExpression(int track, long time, int code, const QString &text)
Emitted after reading an expression indication (notation) chunk.
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:432
int getThru() const
Thru marker time.
Definition: qwrk.cpp:204
bool getSendCont() const
Send MIDI Continue?
Definition: qwrk.cpp:267
int getTempoOfs2() const
Fixed-point ratio value of tempo offset 2.
Definition: qwrk.cpp:413
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:276
void readFromStream(QDataStream *stream)
Reads a stream.
Definition: qwrk.cpp:666
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:450
void signalWRKNote(int track, long time, int chan, int pitch, int vol, int dur)
Emitted after reading a Note message.
unsigned int getStopTime() const
Auto-stop time.
Definition: qwrk.cpp:294
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 signalWRKTrackName(int track, const QString &name)
Emitted after reading a track name 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:164
bool getAutoRewind() const
Auto-rewind?
Definition: qwrk.cpp:303
bool getMetroPlay() const
Metronome on during playback?
Definition: qwrk.cpp:321
QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
Definition: qwrk.cpp:143
int getFrom() const
From marker time.
Definition: qwrk.cpp:195
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:676
int getCountIn() const
Measures of count-in (0=no count-in)
Definition: qwrk.cpp:348
int getCurTempoOfs() const
Which of the 3 tempo offsets is used: 0..2.
Definition: qwrk.cpp:375
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 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 signalWRKKeySig(int bar, int alt)
Emitted after reading a WRK Key Signature.
bool getAutoRestart() const
Auto-restart?
Definition: qwrk.cpp:366
int getClock() const
Clock Source (0=Int, 1=MIDI, 2=FSK, 3=SMPTE)
Definition: qwrk.cpp:222
int getKeySig() const
Key signature (0=C, 1=C#, ...
Definition: qwrk.cpp:213
void signalWRKStringTable2(const QList< QByteArray > &strs)
Emitted after reading a string event types chunk.
bool getMetroAccent() const
Metronome accents primary beats?
Definition: qwrk.cpp:339
int getTempoOfs1() const
Fixed-point ratio value of tempo offset 1.
Definition: qwrk.cpp:394
@ NTRKOFS_CHUNK
Track offset.
Definition: qwrk.h:66
@ NTRACK_CHUNK
Track prefix.
Definition: qwrk.h:68
@ TRKPATCH_CHUNK
Track patch.
Definition: qwrk.h:56
@ STRTAB_CHUNK
Table of text event types.
Definition: qwrk.h:62
@ NTEMPO_CHUNK
New Tempo map.
Definition: qwrk.h:57
@ VARS_CHUNK
Global variables.
Definition: qwrk.h:46
@ TRKBANK_CHUNK
Track bank.
Definition: qwrk.h:67
@ COMMENTS_CHUNK
Comments.
Definition: qwrk.h:51
@ SGMNT_CHUNK
Segment prefix.
Definition: qwrk.h:71
@ SOFTVER_CHUNK
Software version which saved the file.
Definition: qwrk.h:72
@ TRKNAME_CHUNK
Track name.
Definition: qwrk.h:64
@ TIMEFMT_CHUNK
SMPTE time format.
Definition: qwrk.h:54
@ END_CHUNK
Last chunk, end of file.
Definition: qwrk.h:73
@ STREAM_CHUNK
Events stream.
Definition: qwrk.h:45
@ TRACK_CHUNK
Track prefix.
Definition: qwrk.h:44
@ TIMEBASE_CHUNK
Timebase. If present is the first chunk in the file.
Definition: qwrk.h:53
@ TRKOFFS_CHUNK
Track offset.
Definition: qwrk.h:52
@ NSYSEX_CHUNK
System exclusive bank.
Definition: qwrk.h:69
@ THRU_CHUNK
Extended thru parameters.
Definition: qwrk.h:58
@ SYSEX2_CHUNK
System exclusive bank.
Definition: qwrk.h:61
@ NSTREAM_CHUNK
Events stream.
Definition: qwrk.h:70
@ TEMPO_CHUNK
Tempo map.
Definition: qwrk.h:47
@ VARIABLE_CHUNK
Variable record chunk.
Definition: qwrk.h:65
@ METER_CHUNK
Meter map.
Definition: qwrk.h:48
@ METERKEY_CHUNK
Meter/Key map.
Definition: qwrk.h:63
@ TRKREPS_CHUNK
Track repetitions.
Definition: qwrk.h:55
@ TRKVOL_CHUNK
Track volume.
Definition: qwrk.h:60
@ SYSEX_CHUNK
System exclusive bank.
Definition: qwrk.h:49
@ LYRICS_CHUNK
Events stream with lyrics.
Definition: qwrk.h:59
Drumstick common.
Definition: alsaclient.cpp:68
Cakewalk WRK Files Input.