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