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
36namespace drumstick { namespace File {
37
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? (only used if no THRU rec)
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 common.
Definition: alsaclient.cpp:71
Cakewalk WRK Files Input.