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