19 #include <QDataStream>
22 #include <QStringList>
24 #include <QTextStream>
47 class QWrk::QWrkPrivate {
62 m_StopTime(4294967295U),
75 m_PunchEnabled(false),
105 quint8 m_CurTempoOfs;
110 quint32 m_PunchInTime;
111 quint32 m_PunchOutTime;
112 quint32 m_EndAllTime;
116 QDataStream *m_IOStream;
117 QByteArray m_lastChunkData;
118 QList<RecTempo> m_tempos;
120 qint64 m_lastChunkPos;
121 qint64 internalFilePos();
166 return d->m_lastChunkData;
172 void QWrk::readRawData(
int size)
175 d->m_lastChunkData = d->m_IOStream->device()->read(size);
177 d->m_lastChunkData.clear();
233 return d->m_AutoSave;
242 return d->m_PlayDelay;
251 return d->m_ZeroCtrls;
269 return d->m_SendCont;
278 return d->m_PatchSearch;
287 return d->m_AutoStop;
296 return d->m_StopTime;
305 return d->m_AutoRewind;
314 return d->m_RewindTime;
323 return d->m_MetroPlay;
332 return d->m_MetroRecord;
341 return d->m_MetroAccent;
368 return d->m_AutoRestart;
377 return d->m_CurTempoOfs;
396 return d->m_TempoOfs1;
415 return d->m_TempoOfs2;
434 return d->m_TempoOfs3;
443 return d->m_PunchEnabled;
452 return d->m_PunchInTime;
461 return d->m_PunchOutTime;
470 return d->m_EndAllTime;
477 quint8 QWrk::readByte()
480 if (!d->m_IOStream->atEnd())
491 quint16 QWrk::to16bit(quint8 c1, quint8 c2)
493 quint16 value = (c1 << 8);
506 quint32 QWrk::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
508 quint32 value = (c1 << 24);
519 quint16 QWrk::read16bit()
524 return to16bit(c2, c1);
531 quint32 QWrk::read24bit()
537 return to32bit(0, c3, c2, c1);
544 quint32 QWrk::read32bit()
546 quint8 c1, c2, c3, c4;
551 return to32bit(c4, c3, c2, c1);
558 QString QWrk::readString(
int len)
562 QByteArray data = readByteArray(len);
563 if (d->m_codec ==
nullptr) {
564 s = QString::fromLatin1(data);
566 s = d->m_codec->toUnicode(data);
576 QByteArray QWrk::readByteArray(
int len)
581 for (
int i = 0; i < len && c != 0 && !atEnd(); ++i ) {
595 QString QWrk::readVarString()
598 QByteArray data = readVarByteArray();
599 if (d->m_codec ==
nullptr) {
600 s = QString::fromLatin1(data);
602 s = d->m_codec->toUnicode(data);
611 QByteArray QWrk::readVarByteArray()
619 }
while (b != 0 && !atEnd());
629 return d->internalFilePos();
636 void QWrk::seek(qint64 pos)
638 if (!d->m_IOStream->device()->seek(pos)) {
649 return d->m_IOStream->atEnd();
656 void QWrk::readGap(
int size)
659 seek( d->internalFilePos() + size );
668 d->m_IOStream = stream;
678 QFile file(fileName);
679 file.open(QIODevice::ReadOnly);
680 QDataStream ds(&file);
685 void QWrk::processTrackChunk()
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);
705 name[i] = readString(namelen);
708 channel = readByte() & 0x0f;
710 velocity = 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) {
718 trackno, channel, pitch,
719 velocity, port, selected,
723 trackno, channel, pitch,
724 velocity, port, selected,
729 void QWrk::processVarsChunk()
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();
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();
752 d->m_ThruOn = (readByte() != 0);
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();
760 d->m_PunchEnabled = (readByte() != 0);
761 d->m_PunchInTime = read32bit();
762 d->m_PunchOutTime = read32bit();
763 d->m_EndAllTime = read32bit();
768 void QWrk::processTimebaseChunk()
770 quint16 timebase = read16bit();
771 d->m_division = timebase;
775 void QWrk::processNoteArray(
int track,
int events)
778 quint8 status = 0, data1 = 0, data2 = 0, i = 0;
780 int value = 0, type = 0, channel = 0, len = 0;
783 for ( i = 0; (i < events) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i ) {
787 if (status >= 0x90) {
788 type = status & 0xf0;
789 channel = status & 0x0f;
791 if (type == 0x90 || type == 0xA0 || type == 0xB0 || type == 0xE0)
797 Q_EMIT
signalWRKNote(track, time, channel, data1, data2, dur);
812 value = (data2 << 7) + data1 - 8192;
819 }
else if (status == 5) {
820 int code = read16bit();
822 if (d->m_codec ==
nullptr) {
823 data = readByteArray(len);
826 text = readString(len);
829 }
else if (status == 6) {
830 int code = read16bit();
834 }
else if (status == 7) {
836 text = readString(len);
838 for(
int j=0; j<13; ++j) {
839 int byte = readByte();
843 }
else if (status == 8) {
846 for(
int j=0; j<len; ++j) {
847 int byte = readByte();
853 if (d->m_codec ==
nullptr) {
854 data = readByteArray(len);
857 text = readString(len);
862 if ((i < events) && atEnd()) {
868 void QWrk::processStreamChunk()
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 ) {
881 type = status & 0xf0;
882 channel = status & 0x0f;
885 Q_EMIT
signalWRKNote(track, time, channel, data1, data2, dur);
900 value = (data2 << 7) + data1 - 8192;
908 if ((i < events) && atEnd()) {
914 void QWrk::processMeterChunk()
916 int count = read16bit();
917 for (
int i = 0; i < count; ++i) {
919 int measure = read16bit();
920 int num = readByte();
921 int den = pow(2.0, readByte());
927 void QWrk::processMeterKeyChunk()
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();
940 double QWrk::getRealTime(
long ticks)
const
942 double division = 1.0 * d->m_division;
947 if (!d->m_tempos.isEmpty()) {
948 foreach(
const RecTempo& rec, d->m_tempos) {
949 if (rec.time >= ticks)
954 return last.seconds + (((ticks - last.time) / division) * (60.0 / last.tempo));
957 void QWrk::processTempoChunk(
int factor)
959 double division = 1.0 * d->m_division;
960 int count = read16bit();
962 for (
int i = 0; i < count; ++i) {
964 long time = read32bit();
966 long tempo = read16bit() * factor;
970 next.tempo = tempo / 100.0;
973 last.tempo = next.tempo;
975 if (! d->m_tempos.isEmpty()) {
976 foreach(
const RecTempo& rec, d->m_tempos) {
977 if (rec.time >= time)
981 next.seconds = last.seconds +
982 (((time - last.time) / division) * (60.0 / last.tempo));
984 d->m_tempos.append(next);
990 void QWrk::processSysexChunk()
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();
1007 void QWrk::processSysex2Chunk()
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();
1026 void QWrk::processNewSysexChunk()
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();
1044 void QWrk::processThruChunk()
1047 qint8 port = readByte();
1048 qint8 channel = readByte();
1049 qint8 keyPlus = readByte();
1050 qint8 velPlus = readByte();
1051 qint8 localPort = readByte();
1052 qint8 mode = readByte();
1053 Q_EMIT
signalWRKThru(mode, port, channel, keyPlus, velPlus, localPort);
1056 void QWrk::processTrackOffset()
1058 quint16 track = read16bit();
1059 qint16 offset = read16bit();
1063 void QWrk::processTrackReps()
1065 quint16 track = read16bit();
1066 quint16 reps = read16bit();
1070 void QWrk::processTrackPatch()
1072 quint16 track = read16bit();
1073 qint8 patch = readByte();
1077 void QWrk::processTimeFormat()
1079 quint16 fmt = read16bit();
1080 quint16 ofs = read16bit();
1084 void QWrk::processComments()
1086 int len = read16bit();
1087 if (d->m_codec ==
nullptr) {
1088 QByteArray data = readByteArray(len);
1091 QString text = readString(len);
1096 void QWrk::processVariableRecord(
int max)
1098 int datalen = max - 32;
1100 QString name = readVarString();
1101 readGap(31 - name.length());
1102 for (
int i = 0; i < datalen; ++i )
1107 void QWrk::processUnknown(
int id)
1112 void QWrk::processNewTrack()
1124 bool selected =
false;
1127 quint16 track = read16bit();
1128 quint8 len = readByte();
1129 if (d->m_codec ==
nullptr) {
1130 data = readByteArray(len);
1132 name = readString(len);
1135 patch = read16bit();
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);
1147 Q_EMIT
signalWRKNewTrack(name, track, channel, key, vel, port, selected, muted, loop);
1159 void QWrk::processSoftVer()
1161 int len = readByte();
1162 QString vers = readString(len);
1166 void QWrk::processTrackName()
1168 int track = read16bit();
1169 int len = readByte();
1170 if (d->m_codec ==
nullptr) {
1171 QByteArray data = readByteArray(len);
1174 QString name = readString(len);
1179 void QWrk::processStringTable()
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);
1188 table.insert(i, name);
1193 int rows = read16bit();
1194 for (
int i = 0; i < rows; ++i) {
1195 int len = readByte();
1196 QString name = readString(len);
1198 table.insert(i, name);
1204 void QWrk::processLyricsStream()
1206 quint16 track = read16bit();
1207 int events = read32bit();
1208 processNoteArray(track, events);
1211 void QWrk::processTrackVol()
1213 quint16 track = read16bit();
1214 int vol = read16bit();
1218 void QWrk::processNewTrackOffset()
1220 quint16 track = read16bit();
1221 int offset = read32bit();
1225 void QWrk::processTrackBank()
1227 quint16 track = read16bit();
1228 int bank = read16bit();
1232 void QWrk::processSegmentChunk()
1236 int track = read16bit();
1237 int offset = read32bit();
1239 int len = readByte();
1240 if (d->m_codec ==
nullptr) {
1241 data = readByteArray(len);
1243 name = readString(len);
1246 if (d->m_codec ==
nullptr) {
1251 int events = read32bit();
1252 processNoteArray(track, events);
1255 void QWrk::processNewStream()
1259 int track = read16bit();
1260 int len = readByte();
1261 if (d->m_codec ==
nullptr) {
1262 data = readByteArray(len);
1265 name = readString(len);
1268 int events = read32bit();
1269 processNoteArray(track, events);
1272 void QWrk::processEndChunk()
1277 int QWrk::readChunk()
1279 qint64 start_pos = d->internalFilePos();
1280 int ck = readByte();
1282 quint32 ck_len = read32bit();
1283 if (ck_len > d->m_IOStream->device()->bytesAvailable()) {
1288 start_pos = d->internalFilePos();
1289 d->m_lastChunkPos = start_pos + ck_len;
1290 readRawData(ck_len);
1294 processTrackChunk();
1300 processTimebaseChunk();
1303 processStreamChunk();
1306 processMeterChunk();
1309 processTempoChunk(100);
1312 processTempoChunk();
1315 processSysexChunk();
1321 processTrackOffset();
1327 processTrackPatch();
1330 processTimeFormat();
1336 processVariableRecord(ck_len);
1348 processStringTable();
1351 processLyricsStream();
1357 processNewTrackOffset();
1363 processMeterKeyChunk();
1366 processSysex2Chunk();
1369 processNewSysexChunk();
1372 processSegmentChunk();
1380 if (d->internalFilePos() != d->m_lastChunkPos) {
1382 seek(d->m_lastChunkPos);
1388 void QWrk::wrkRead()
1390 QByteArray hdr(
HEADER.length(),
' ');
1391 d->m_tempos.clear();
1392 d->m_IOStream->device()->read(hdr.data(),
HEADER.length());
1401 ck_id = readChunk();
1402 }
while ((ck_id !=
END_CHUNK) && !atEnd());
1405 readRawData(d->m_IOStream->device()->bytesAvailable());
1406 processUnknown(ck_id);
1413 qint64 QWrk::QWrkPrivate::internalFilePos()
1415 return m_IOStream->device()->pos();
1418 const QByteArray
QWrk::HEADER = QByteArrayLiteral(
"CAKEWALK");
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?
bool getPunchEnabled() const
Auto-Punch enabled?
void signalWRKText(int track, long time, int type, const QString &data)
Emitted after reading a text message.
int getRewindTime() const
Auto-rewind time.
bool getZeroCtrls() const
Zero continuous controllers?
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.
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.
void setTextCodec(QTextCodec *codec)
Sets the text codec for text meta-events.
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)
long getFilePos()
Current position in the data stream.
bool getThruOn() const
MIDI Thru enabled? (only used if no THRU rec)
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.
int getPunchOutTime() const
Punch-out time.
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?
int getEndAllTime() const
Time of latest event (incl.
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.
bool getSendSPP() const
Send Song Position Pointer?
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.
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.
int getThru() const
Thru marker time.
bool getSendCont() const
Send MIDI Continue?
int getTempoOfs2() const
Fixed-point ratio value of tempo offset 2.
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?
void readFromStream(QDataStream *stream)
Reads a stream.
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.
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.
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)
bool getAutoRewind() const
Auto-rewind?
bool getMetroPlay() const
Metronome on during playback?
QTextCodec * getTextCodec()
Gets the text codec used for text meta-events I/O.
int getFrom() const
From marker time.
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.
int getCountIn() const
Measures of count-in (0=no count-in)
int getCurTempoOfs() const
Which of the 3 tempo offsets is used: 0..2.
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?
int getClock() const
Clock Source (0=Int, 1=MIDI, 2=FSK, 3=SMPTE)
int getKeySig() const
Key signature (0=C, 1=C#, ...
void signalWRKStringTable2(const QList< QByteArray > &strs)
Emitted after reading a string event types chunk.
bool getMetroAccent() const
Metronome accents primary beats?
int getTempoOfs1() const
Fixed-point ratio value of tempo offset 1.
@ NTRKOFS_CHUNK
Track offset.
@ NTRACK_CHUNK
Track prefix.
@ TRKPATCH_CHUNK
Track patch.
@ STRTAB_CHUNK
Table of text event types.
@ NTEMPO_CHUNK
New Tempo map.
@ VARS_CHUNK
Global variables.
@ TRKBANK_CHUNK
Track bank.
@ COMMENTS_CHUNK
Comments.
@ SGMNT_CHUNK
Segment prefix.
@ SOFTVER_CHUNK
Software version which saved the file.
@ TRKNAME_CHUNK
Track name.
@ TIMEFMT_CHUNK
SMPTE time format.
@ END_CHUNK
Last chunk, end of file.
@ STREAM_CHUNK
Events stream.
@ TRACK_CHUNK
Track prefix.
@ TIMEBASE_CHUNK
Timebase. If present is the first chunk in the file.
@ TRKOFFS_CHUNK
Track offset.
@ NSYSEX_CHUNK
System exclusive bank.
@ THRU_CHUNK
Extended thru parameters.
@ SYSEX2_CHUNK
System exclusive bank.
@ NSTREAM_CHUNK
Events stream.
@ VARIABLE_CHUNK
Variable record chunk.
@ METERKEY_CHUNK
Meter/Key map.
@ TRKREPS_CHUNK
Track repetitions.
@ TRKVOL_CHUNK
Track volume.
@ SYSEX_CHUNK
System exclusive bank.
@ LYRICS_CHUNK
Events stream with lyrics.
Cakewalk WRK Files Input.