drumstick 2.10.0
C++ MIDI libraries using Qt objects, idioms, and style.
qwrk.cpp
Go to the documentation of this file.
1/*
2 WRK File component
3 Copyright (C) 2010-2024, 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
28DISABLE_WARNING_PUSH
29DISABLE_WARNING_DEPRECATED_DECLARATIONS
30
35
36namespace drumstick { namespace File {
37
49
50class QWrk::QWrkPrivate {
51public:
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
132 QObject(parent),
133 d(new QWrkPrivate)
134{ }
135
140{ }
141
149{
150 return d->m_codec;
151}
152
160void QWrk::setTextCodec(QTextCodec *codec)
161{
162 d->m_codec = codec;
163}
164
171{
172 return d->m_lastChunkData;
173}
174
178void 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
192int QWrk::getNow() const
193{
194 return d->m_Now;
195}
196
201int QWrk::getFrom() const
202{
203 return d->m_From;
204}
205
210int QWrk::getThru() const
211{
212 return d->m_Thru;
213}
214
220{
221 return d->m_KeySig;
222}
223
228int QWrk::getClock() const
229{
230 return d->m_Clock;
231}
232
238{
239 return d->m_AutoSave;
240}
241
247{
248 return d->m_PlayDelay;
249}
250
256{
257 return d->m_ZeroCtrls;
258}
259
265{
266 return d->m_SendSPP;
267}
268
274{
275 return d->m_SendCont;
276}
277
283{
284 return d->m_PatchSearch;
285}
286
292{
293 return d->m_AutoStop;
294}
295
300unsigned 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
328{
329 return d->m_MetroPlay;
330}
331
337{
338 return d->m_MetroRecord;
339}
340
346{
347 return d->m_MetroAccent;
348}
349
355{
356 return d->m_CountIn;
357}
358
363bool 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
483quint8 QWrk::readByte()
484{
485 quint8 b = 0xff;
486 if (!d->m_IOStream->atEnd())
487 *d->m_IOStream >> b;
488 return b;
489}
490
497quint16 QWrk::to16bit(quint8 c1, quint8 c2)
498{
499 quint16 value = (c1 << 8);
500 value += c2;
501 return value;
502}
503
512quint32 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
525quint16 QWrk::read16bit()
526{
527 quint8 c1, c2;
528 c1 = readByte();
529 c2 = readByte();
530 return to16bit(c2, c1);
531}
532
537quint32 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
550quint32 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
564QString 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
582QByteArray 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
601QString 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
617QByteArray 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
629void 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
661void QWrk::seek(qint64 pos)
662{
663 if (!d->m_IOStream->device()->seek(pos)) {
664 //qDebug() << Q_FUNC_INFO << "Error, pos:" << pos;
665 }
666}
667
672bool QWrk::atEnd()
673{
674 return d->m_IOStream->atEnd();
675}
676
681void QWrk::readGap(int size)
682{
683 if ( size > 0)
684 seek( d->internalFilePos() + size );
685}
686
691void QWrk::readFromStream(QDataStream *stream)
692{
693 d->m_IOStream = stream;
694 wrkRead();
695}
696
701void 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
710void 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
754void 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
793void QWrk::processTimebaseChunk()
794{
795 quint16 timebase = read16bit();
796 d->m_division = timebase;
797 Q_EMIT signalWRKTimeBase(timebase);
798}
799
800void 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
893void 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
939void 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
952void 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
965double 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
982void 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
1015void 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
1032void 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
1051void 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
1069void 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
1081void QWrk::processTrackOffset()
1082{
1083 quint16 track = read16bit();
1084 qint16 offset = read16bit();
1085 Q_EMIT signalWRKTrackOffset(track, offset);
1086}
1087
1088void QWrk::processTrackReps()
1089{
1090 quint16 track = read16bit();
1091 quint16 reps = read16bit();
1092 Q_EMIT signalWRKTrackReps(track, reps);
1093}
1094
1095void QWrk::processTrackPatch()
1096{
1097 quint16 track = read16bit();
1098 qint8 patch = readByte();
1099 Q_EMIT signalWRKTrackPatch(track, patch);
1100}
1101
1102void QWrk::processTimeFormat()
1103{
1104 quint16 fmt = read16bit();
1105 quint16 ofs = read16bit();
1106 Q_EMIT signalWRKTimeFormat(fmt, ofs);
1107}
1108
1109void 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
1121void 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
1136void QWrk::processUnknown(int id)
1137{
1138 Q_EMIT signalWRKUnknownChunk(id, d->m_lastChunkData);
1139}
1140
1141void 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
1188void QWrk::processSoftVer()
1189{
1190 int len = readByte();
1191 QString vers = readString(len);
1192 Q_EMIT signalWRKSoftVer(vers);
1193}
1194
1195void 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
1208void 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
1233void QWrk::processLyricsStream()
1234{
1235 quint16 track = read16bit();
1236 int events = read32bit();
1237 processNoteArray(track, events);
1238}
1239
1240void QWrk::processTrackVol()
1241{
1242 quint16 track = read16bit();
1243 int vol = read16bit();
1244 Q_EMIT signalWRKTrackVol(track, vol);
1245}
1246
1247void QWrk::processNewTrackOffset()
1248{
1249 quint16 track = read16bit();
1250 int offset = read32bit();
1251 Q_EMIT signalWRKTrackOffset(track, offset);
1252}
1253
1254void QWrk::processTrackBank()
1255{
1256 quint16 track = read16bit();
1257 int bank = read16bit();
1258 Q_EMIT signalWRKTrackBank(track, bank);
1259}
1260
1261void 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
1284void 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
1301void QWrk::processEndChunk()
1302{
1303 Q_EMIT signalWRKEnd();
1304}
1305
1306int 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
1420void 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
1445qint64 QWrk::QWrkPrivate::internalFilePos()
1446{
1447 return m_IOStream->device()->pos();
1448}
1449
1450const QByteArray QWrk::HEADER = QByteArrayLiteral("CAKEWALK");
1451
1452} // namespace File
1453} // namespace drumstick
1454
1455DISABLE_WARNING_POP
The QObject class is the base class of all Qt objects.
void signalWRKTrackPatch(int track, int patch)
Emitted after reading a track patch chunk.
bool getMetroRecord() const
Metronome on during recording?
Definition qwrk.cpp:336
bool getPunchEnabled() const
Auto-Punch enabled?
Definition qwrk.cpp:447
int getRewindTime() const
Auto-rewind time.
Definition qwrk.cpp:318
bool getZeroCtrls() const
Zero continuous controllers?
Definition qwrk.cpp:255
QWrk(QObject *parent=nullptr)
Constructor.
Definition qwrk.cpp:131
Q_DECL_DEPRECATED void signalWRKSegment(int track, long time, const QString &name)
Emitted after reading a segment prefix chunk.
void signalWRKProgram(int track, long time, int chan, int patch)
Emitted after reading a Program change message.
void signalWRKChord(int track, long time, const QString &name, const QByteArray &data)
Emitted after reading a chord diagram chunk.
static const QByteArray HEADER
Cakewalk WRK file format header string id.
Definition qwrk.h:145
Q_DECL_DEPRECATED void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
Definition qwrk.cpp:160
void signalWRKHeader(int verh, int verl)
Emitted after reading a WRK header.
void signalWRKSysexEvent(int track, long time, int bank)
Emitted after reading a System Exclusive event.
int getAutoSave() const
Auto save (0=disabled, 1..256=minutes)
Definition qwrk.cpp:237
void signalWRKMarker2(long time, int type, const QByteArray &data)
Emitted after reading a text marker This signal is emitted when getTextCodec() is nullptr.
long getFilePos()
Current position in the data stream.
Definition qwrk.cpp:652
bool getThruOn() const
MIDI Thru enabled?
Definition qwrk.cpp:363
void signalWRKGlobalVars()
Emitted after reading the global variables chunk.
void signalWRKSoftVer(const QString &version)
Emitted after reading a software version chunk.
void signalWRKSegment2(int track, long time, const QByteArray &name)
Emitted after reading a segment prefix chunk.
int getNow() const
Now marker time.
Definition qwrk.cpp:192
int getPunchOutTime() const
Punch-out time.
Definition qwrk.cpp:465
void signalWRKTrackOffset(int track, int offset)
Emitted after reading a track offset chunk.
void signalWRKChanPress(int track, long time, int chan, int press)
Emitted after reading a Channel Aftertouch message.
void signalWRKStreamEnd(long time)
Emitted after reading the last event of a event stream.
void signalWRKText2(int track, long time, int type, const QByteArray &data)
Emitted after reading a text message This signal is emitted when getTextCodec() is nullptr.
bool getAutoStop() const
Auto-stop?
Definition qwrk.cpp:291
int getEndAllTime() const
Time of latest event (incl.
Definition qwrk.cpp:474
void signalWRKKeyPress(int track, long time, int chan, int pitch, int press)
Emitted after reading a Polyphonic Aftertouch message.
void signalWRKVariableRecord(const QString &name, const QByteArray &data)
Emitted after reading a variable chunk.
void signalWRKTrackVol(int track, int vol)
Emitted after reading a track volume chunk.
void signalWRKExpression2(int track, long time, int code, const QByteArray &text)
Emitted after reading an expression indication (notation) chunk.
void signalWRKTrackName2(int track, const QByteArray &name)
Emitted after reading a track name chunk.
int getPlayDelay() const
Play Delay.
Definition qwrk.cpp:246
bool getSendSPP() const
Send Song Position Pointer?
Definition qwrk.cpp:264
Q_DECL_DEPRECATED void signalWRKNewTrack(const QString &name, int trackno, int channel, int pitch, int velocity, int port, bool selected, bool muted, bool loop)
Emitted after reading a new track prefix.
void signalWRKTrack2(const QByteArray &name1, const QByteArray &name2, int trackno, int channel, int pitch, int velocity, int port, bool selected, bool muted, bool loop)
Emitted after reading a track prefix chunk This signal is emitted when getTextCodec() is nullptr.
void signalWRKError(const QString &errorStr)
Emitted for a WRK file read error.
virtual ~QWrk()
Destructor.
Definition qwrk.cpp:139
void signalWRKTempo(long time, int tempo)
Emitted after reading a Tempo Change message.
void signalWRKTimeSig(int bar, int num, int den)
Emitted after reading a WRK Time signature.
void signalWRKHairpin(int track, long time, int code, int dur)
Emitted after reading a hairpin symbol (notation) chunk.
void signalWRKPitchBend(int track, long time, int chan, int value)
Emitted after reading a Bender message.
void signalWRKEnd()
Emitted after reading the last chunk of a WRK file.
int getTempoOfs3() const
Fixed-point ratio value of tempo offset 3.
Definition qwrk.cpp:438
Q_DECL_DEPRECATED void signalWRKTrackName(int track, const QString &name)
Emitted after reading a track name chunk.
int getThru() const
Thru marker time.
Definition qwrk.cpp:210
bool getSendCont() const
Send MIDI Continue?
Definition qwrk.cpp:273
int getTempoOfs2() const
Fixed-point ratio value of tempo offset 2.
Definition qwrk.cpp:419
void signalWRKNewTrack2(const QByteArray &name, int trackno, int channel, int pitch, int velocity, int port, bool selected, bool muted, bool loop)
Emitted after reading a new track prefix This signal is emitted when getTextCodec() is nullptr.
bool getPatchSearch() const
Patch/controller search-back?
Definition qwrk.cpp:282
void readFromStream(QDataStream *stream)
Reads a stream.
Definition qwrk.cpp:691
void signalWRKThru(int mode, int port, int channel, int keyPlus, int velPlus, int localPort)
Emitted after reading an Extended Thru parameters chunk.
int getPunchInTime() const
Punch-in time.
Definition qwrk.cpp:456
void signalWRKNote(int track, long time, int chan, int pitch, int vol, int dur)
Emitted after reading a Note message.
Q_DECL_DEPRECATED void signalWRKStringTable(const QStringList &strs)
Emitted after reading a string event types chunk.
unsigned int getStopTime() const
Auto-stop time.
Definition qwrk.cpp:300
void signalWRKUnknownChunk(int type, const QByteArray &data)
Emitted after reading an unknown chunk.
void signalWRKTrackBank(int track, int bank)
Emitted after reading a track bank chunk.
void signalWRKComments2(const QByteArray &data)
Emitted after reading a comments chunk This signal is emitted when getTextCodec() is nullptr.
void signalWRKTimeBase(int timebase)
Emitted after reading the timebase chunk.
QByteArray getLastChunkRawData() const
Gets the last chunk raw data (undecoded)
Definition qwrk.cpp:170
Q_DECL_DEPRECATED void signalWRKExpression(int track, long time, int code, const QString &text)
Emitted after reading an expression indication (notation) chunk.
bool getAutoRewind() const
Auto-rewind?
Definition qwrk.cpp:309
bool getMetroPlay() const
Metronome on during playback?
Definition qwrk.cpp:327
Q_DECL_DEPRECATED QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
Definition qwrk.cpp:148
int getFrom() const
From marker time.
Definition qwrk.cpp:201
Q_DECL_DEPRECATED void signalWRKText(int track, long time, int type, const QString &data)
Emitted after reading a text message.
void signalWRKTimeFormat(int frames, int offset)
Emitted after reading a SMPTE time format chunk.
void signalWRKSysex(int bank, const QString &name, bool autosend, int port, const QByteArray &data)
Emitted after reading a System Exclusive Bank.
void readFromFile(const QString &fileName)
Reads a stream from a disk file.
Definition qwrk.cpp:701
int getCountIn() const
Measures of count-in (0=no count-in)
Definition qwrk.cpp:354
int getCurTempoOfs() const
Which of the 3 tempo offsets is used: 0..2.
Definition qwrk.cpp:381
Q_DECL_DEPRECATED void signalWRKComments(const QString &data)
Emitted after reading a comments chunk.
void signalWRKCtlChange(int track, long time, int chan, int ctl, int value)
Emitted after reading a Control Change message.
void signalWRKTrackReps(int track, int reps)
Emitted after reading a track offset chunk.
void signalWRKKeySig(int bar, int alt)
Emitted after reading a WRK Key Signature.
bool getAutoRestart() const
Auto-restart?
Definition qwrk.cpp:372
Q_DECL_DEPRECATED void signalWRKTrack(const QString &name1, const QString &name2, int trackno, int channel, int pitch, int velocity, int port, bool selected, bool muted, bool loop)
Emitted after reading a track prefix chunk.
int getClock() const
Clock Source (0=Int, 1=MIDI, 2=FSK, 3=SMPTE)
Definition qwrk.cpp:228
Q_DECL_DEPRECATED void signalWRKMarker(long time, int type, const QString &data)
Emitted after reading a text marker This is deprecated because the class QTextCodec was removed from ...
int getKeySig() const
Key signature (0=C, 1=C#, ... 11=B)
Definition qwrk.cpp:219
void signalWRKStringTable2(const QList< QByteArray > &strs)
Emitted after reading a string event types chunk.
bool getMetroAccent() const
Metronome accents primary beats?
Definition qwrk.cpp:345
int getTempoOfs1() const
Fixed-point ratio value of tempo offset 1.
Definition qwrk.cpp:400
@ NTRKOFS_CHUNK
Track offset.
Definition qwrk.h:77
@ NTRACK_CHUNK
Track prefix.
Definition qwrk.h:79
@ TRKPATCH_CHUNK
Track patch.
Definition qwrk.h:66
@ MARKERS_CHUNK
Markers.
Definition qwrk.h:72
@ STRTAB_CHUNK
Table of text event types.
Definition qwrk.h:73
@ NTEMPO_CHUNK
New Tempo map.
Definition qwrk.h:67
@ VARS_CHUNK
Global variables.
Definition qwrk.h:56
@ TRKBANK_CHUNK
Track bank.
Definition qwrk.h:78
@ COMMENTS_CHUNK
Comments.
Definition qwrk.h:61
@ SGMNT_CHUNK
Segment prefix.
Definition qwrk.h:82
@ SOFTVER_CHUNK
Software version which saved the file.
Definition qwrk.h:83
@ TRKNAME_CHUNK
Track name.
Definition qwrk.h:75
@ TIMEFMT_CHUNK
SMPTE time format.
Definition qwrk.h:64
@ END_CHUNK
Last chunk, end of file.
Definition qwrk.h:84
@ STREAM_CHUNK
Events stream.
Definition qwrk.h:55
@ TRACK_CHUNK
Track prefix.
Definition qwrk.h:54
@ TIMEBASE_CHUNK
Timebase. If present is the first chunk in the file.
Definition qwrk.h:63
@ TRKOFFS_CHUNK
Track offset.
Definition qwrk.h:62
@ NSYSEX_CHUNK
System exclusive bank.
Definition qwrk.h:80
@ THRU_CHUNK
Extended thru parameters.
Definition qwrk.h:68
@ SYSEX2_CHUNK
System exclusive bank.
Definition qwrk.h:71
@ NSTREAM_CHUNK
Events stream.
Definition qwrk.h:81
@ TEMPO_CHUNK
Tempo map.
Definition qwrk.h:57
@ VARIABLE_CHUNK
Variable record chunk.
Definition qwrk.h:76
@ METER_CHUNK
Meter map.
Definition qwrk.h:58
@ METERKEY_CHUNK
Meter/Key map.
Definition qwrk.h:74
@ TRKREPS_CHUNK
Track repetitions.
Definition qwrk.h:65
@ TRKVOL_CHUNK
Track volume.
Definition qwrk.h:70
@ SYSEX_CHUNK
System exclusive bank.
Definition qwrk.h:59
@ LYRICS_CHUNK
Events stream with lyrics.
Definition qwrk.h:69
Drumstick File library.
Definition qsmf.cpp:38
Drumstick common.
Cakewalk WRK Files Input.