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