drumstick  2.7.0
qwrk.cpp
Go to the documentation of this file.
1 /*
2  WRK File component
3  Copyright (C) 2010-2022, 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  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
void signalWRKVariableRecord(const QString &name, const QByteArray &data)
Emitted after reading a variable chunk.
void signalWRKTrackReps(int track, int reps)
Emitted after reading a track offset chunk.
Events stream.
Definition: qwrk.h:45
Q_DECL_DEPRECATED void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
Definition: qwrk.cpp:160
int getEndAllTime() const
Time of latest event (incl.
Definition: qwrk.cpp:474
int getClock() const
Clock Source (0=Int, 1=MIDI, 2=FSK, 3=SMPTE)
Definition: qwrk.cpp:228
void signalWRKChord(int track, long time, const QString &name, const QByteArray &data)
Emitted after reading a chord diagram chunk.
void signalWRKGlobalVars()
Emitted after reading the global variables chunk.
Q_DECL_DEPRECATED QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
Definition: qwrk.cpp:148
bool getMetroAccent() const
Metronome accents primary beats?
Definition: qwrk.cpp:345
void signalWRKSysex(int bank, const QString &name, bool autosend, int port, const QByteArray &data)
Emitted after reading a System Exclusive Bank.
int getTempoOfs1() const
Fixed-point ratio value of tempo offset 1.
Definition: qwrk.cpp:400
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
int getKeySig() const
Key signature (0=C, 1=C#, ...
Definition: qwrk.cpp:219
System exclusive bank.
Definition: qwrk.h:70
int getFrom() const
From marker time.
Definition: qwrk.cpp:201
void signalWRKTimeFormat(int frames, int offset)
Emitted after reading a SMPTE time format chunk.
Track repetitions.
Definition: qwrk.h:55
void signalWRKKeyPress(int track, long time, int chan, int pitch, int press)
Emitted after reading a Polyphonic Aftertouch message.
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...
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 signalWRKThru(int mode, int port, int channel, int keyPlus, int velPlus, int localPort)
Emitted after reading an Extended Thru parameters chunk.
Track prefix.
Definition: qwrk.h:44
void signalWRKStreamEnd(long time)
Emitted after reading the last event of a event stream.
Meter/Key map.
Definition: qwrk.h:64
QByteArray getLastChunkRawData() const
Gets the last chunk raw data (undecoded)
Definition: qwrk.cpp:170
int getPunchOutTime() const
Punch-out time.
Definition: qwrk.cpp:465
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.
static const QByteArray HEADER
Cakewalk WRK file format header string id.
Definition: qwrk.h:135
Q_DECL_DEPRECATED void signalWRKExpression(int track, long time, int code, const QString &text)
Emitted after reading an expression indication (notation) chunk.
void signalWRKKeySig(int bar, int alt)
Emitted after reading a WRK Key Signature.
Track prefix.
Definition: qwrk.h:69
bool getMetroPlay() const
Metronome on during playback?
Definition: qwrk.cpp:327
void signalWRKUnknownChunk(int type, const QByteArray &data)
Emitted after reading an unknown chunk.
The QObject class is the base class of all Qt objects.
Events stream.
Definition: qwrk.h:71
void signalWRKTimeSig(int bar, int num, int den)
Emitted after reading a WRK Time signature.
Track offset.
Definition: qwrk.h:67
bool getThruOn() const
MIDI Thru enabled? (only used if no THRU rec)
Definition: qwrk.cpp:363
int getTempoOfs3() const
Fixed-point ratio value of tempo offset 3.
Definition: qwrk.cpp:438
void signalWRKSysexEvent(int track, long time, int bank)
Emitted after reading a System Exclusive event.
void signalWRKComments2(const QByteArray &data)
Emitted after reading a comments chunk This signal is emitted when getTextCodec() is nullptr...
int getThru() const
Thru marker time.
Definition: qwrk.cpp:210
Q_DECL_DEPRECATED void signalWRKStringTable(const QStringList &strs)
Emitted after reading a string event types chunk.
SMPTE time format.
Definition: qwrk.h:54
System exclusive bank.
Definition: qwrk.h:61
void signalWRKCtlChange(int track, long time, int chan, int ctl, int value)
Emitted after reading a Control Change message.
System exclusive bank.
Definition: qwrk.h:49
Timebase. If present is the first chunk in the file.
Definition: qwrk.h:53
int getAutoSave() const
Auto save (0=disabled, 1..256=minutes)
Definition: qwrk.cpp:237
Drumstick common.
Definition: alsaclient.cpp:68
Global variables.
Definition: qwrk.h:46
void signalWRKTrackVol(int track, int vol)
Emitted after reading a track volume chunk.
Cakewalk WRK Files Input.
bool getZeroCtrls() const
Zero continuous controllers?
Definition: qwrk.cpp:255
QWrk(QObject *parent=nullptr)
Constructor.
Definition: qwrk.cpp:131
void signalWRKHeader(int verh, int verl)
Emitted after reading a WRK header.
void readFromStream(QDataStream *stream)
Reads a stream.
Definition: qwrk.cpp:691
Events stream with lyrics.
Definition: qwrk.h:59
New Tempo map.
Definition: qwrk.h:57
Software version which saved the file.
Definition: qwrk.h:73
bool getAutoRestart() const
Auto-restart?
Definition: qwrk.cpp:372
Track offset.
Definition: qwrk.h:52
void signalWRKPitchBend(int track, long time, int chan, int value)
Emitted after reading a Bender message.
Track volume.
Definition: qwrk.h:60
void signalWRKTrackName2(int track, const QByteArray &name)
Emitted after reading a track name chunk.
bool getSendSPP() const
Send Song Position Pointer?
Definition: qwrk.cpp:264
Q_DECL_DEPRECATED void signalWRKTrackName(int track, const QString &name)
Emitted after reading a track name chunk.
Last chunk, end of file.
Definition: qwrk.h:74
void signalWRKExpression2(int track, long time, int code, const QByteArray &text)
Emitted after reading an expression indication (notation) chunk.
bool getAutoRewind() const
Auto-rewind?
Definition: qwrk.cpp:309
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 ...
void signalWRKChanPress(int track, long time, int chan, int press)
Emitted after reading a Channel Aftertouch message.
Q_DECL_DEPRECATED void signalWRKComments(const QString &data)
Emitted after reading a comments chunk.
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...
int getCountIn() const
Measures of count-in (0=no count-in)
Definition: qwrk.cpp:354
void signalWRKTrackPatch(int track, int patch)
Emitted after reading a track patch chunk.
bool getSendCont() const
Send MIDI Continue?
Definition: qwrk.cpp:273
Q_DECL_DEPRECATED void signalWRKText(int track, long time, int type, const QString &data)
Emitted after reading a text message.
bool getPunchEnabled() const
Auto-Punch enabled?
Definition: qwrk.cpp:447
void signalWRKTrackBank(int track, int bank)
Emitted after reading a track bank chunk.
void signalWRKStringTable2(const QList< QByteArray > &strs)
Emitted after reading a string event types chunk.
void signalWRKSoftVer(const QString &version)
Emitted after reading a software version chunk.
bool getMetroRecord() const
Metronome on during recording?
Definition: qwrk.cpp:336
void signalWRKNote(int track, long time, int chan, int pitch, int vol, int dur)
Emitted after reading a Note message.
void readFromFile(const QString &fileName)
Reads a stream from a disk file.
Definition: qwrk.cpp:701
int getCurTempoOfs() const
Which of the 3 tempo offsets is used: 0..2.
Definition: qwrk.cpp:381
int getNow() const
Now marker time.
Definition: qwrk.cpp:192
void signalWRKSegment2(int track, long time, const QByteArray &name)
Emitted after reading a segment prefix chunk.
bool getAutoStop() const
Auto-stop?
Definition: qwrk.cpp:291
void signalWRKError(const QString &errorStr)
Emitted for a WRK file read error.
void signalWRKEnd()
Emitted after reading the last chunk of a WRK file.
int getRewindTime() const
Auto-rewind time.
Definition: qwrk.cpp:318
void signalWRKTrackOffset(int track, int offset)
Emitted after reading a track offset chunk.
unsigned int getStopTime() const
Auto-stop time.
Definition: qwrk.cpp:300
Table of text event types.
Definition: qwrk.h:63
Segment prefix.
Definition: qwrk.h:72
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.
Extended thru parameters.
Definition: qwrk.h:58
Q_DECL_DEPRECATED void signalWRKSegment(int track, long time, const QString &name)
Emitted after reading a segment prefix chunk.
int getPunchInTime() const
Punch-in time.
Definition: qwrk.cpp:456
Variable record chunk.
Definition: qwrk.h:66
void signalWRKHairpin(int track, long time, int code, int dur)
Emitted after reading a hairpin symbol (notation) chunk.
void signalWRKProgram(int track, long time, int chan, int patch)
Emitted after reading a Program change message.
virtual ~QWrk()
Destructor.
Definition: qwrk.cpp:139
int getPlayDelay() const
Play Delay.
Definition: qwrk.cpp:246
void signalWRKTimeBase(int timebase)
Emitted after reading the timebase chunk.
int getTempoOfs2() const
Fixed-point ratio value of tempo offset 2.
Definition: qwrk.cpp:419
void signalWRKTempo(long time, int tempo)
Emitted after reading a Tempo Change message.
bool getPatchSearch() const
Patch/controller search-back?
Definition: qwrk.cpp:282