20 #include <QDataStream>
23 #include <QStringList>
25 #include <QTextStream>
48 class QWrk::QWrkPrivate {
63 m_StopTime(4294967295U),
76 m_PunchEnabled(false),
106 quint8 m_CurTempoOfs;
111 quint32 m_PunchInTime;
112 quint32 m_PunchOutTime;
113 quint32 m_EndAllTime;
117 QDataStream *m_IOStream;
118 QByteArray m_lastChunkData;
119 QList<RecTempo> m_tempos;
121 qint64 m_lastChunkPos;
122 qint64 internalFilePos();
167 return d->m_lastChunkData;
173 void QWrk::readRawData(
int size)
176 d->m_lastChunkData = d->m_IOStream->device()->read(size);
178 d->m_lastChunkData.clear();
234 return d->m_AutoSave;
243 return d->m_PlayDelay;
252 return d->m_ZeroCtrls;
270 return d->m_SendCont;
279 return d->m_PatchSearch;
288 return d->m_AutoStop;
297 return d->m_StopTime;
306 return d->m_AutoRewind;
315 return d->m_RewindTime;
324 return d->m_MetroPlay;
333 return d->m_MetroRecord;
342 return d->m_MetroAccent;
369 return d->m_AutoRestart;
378 return d->m_CurTempoOfs;
397 return d->m_TempoOfs1;
416 return d->m_TempoOfs2;
435 return d->m_TempoOfs3;
444 return d->m_PunchEnabled;
453 return d->m_PunchInTime;
462 return d->m_PunchOutTime;
471 return d->m_EndAllTime;
478 quint8 QWrk::readByte()
481 if (!d->m_IOStream->atEnd())
492 quint16 QWrk::to16bit(quint8 c1, quint8 c2)
494 quint16 value = (c1 << 8);
507 quint32 QWrk::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
509 quint32 value = (c1 << 24);
520 quint16 QWrk::read16bit()
525 return to16bit(c2, c1);
532 quint32 QWrk::read24bit()
538 return to32bit(0, c3, c2, c1);
545 quint32 QWrk::read32bit()
547 quint8 c1, c2, c3, c4;
552 return to32bit(c4, c3, c2, c1);
559 QString QWrk::readString(
int len)
565 for (
int i = 0; i < len && c != 0 && !atEnd(); ++i ) {
570 if (d->m_codec ==
nullptr)
573 s = d->m_codec->toUnicode(data);
582 QString QWrk::readVarString()
591 }
while (b != 0 && !atEnd());
592 if (d->m_codec ==
nullptr)
595 s = d->m_codec->toUnicode(data);
605 return d->internalFilePos();
612 void QWrk::seek(qint64 pos)
614 if (!d->m_IOStream->device()->seek(pos)) {
625 return d->m_IOStream->atEnd();
632 void QWrk::readGap(
int size)
635 seek( d->internalFilePos() + size );
644 d->m_IOStream = stream;
654 QFile file(fileName);
655 file.open(QIODevice::ReadOnly);
656 QDataStream ds(&file);
661 void QWrk::processTrackChunk()
674 trackno = read16bit();
675 for(
int i=0; i<2; ++i) {
676 namelen = readByte();
677 name[i] = readString(namelen);
679 channel = readByte() & 0x0f;
681 velocity = readByte();
683 quint8 flags = readByte();
684 selected = ((flags & 1) != 0);
685 muted = ((flags & 2) != 0);
686 loop = ((flags & 4) != 0);
688 trackno, channel, pitch,
689 velocity, port, selected,
693 void QWrk::processVarsChunk()
695 d->m_Now = read32bit();
696 d->m_From = read32bit();
697 d->m_Thru = read32bit();
698 d->m_KeySig = readByte();
699 d->m_Clock = readByte();
700 d->m_AutoSave = readByte();
701 d->m_PlayDelay = readByte();
703 d->m_ZeroCtrls = (readByte() != 0);
704 d->m_SendSPP = (readByte() != 0);
705 d->m_SendCont = (readByte() != 0);
706 d->m_PatchSearch = (readByte() != 0);
707 d->m_AutoStop = (readByte() != 0);
708 d->m_StopTime = read32bit();
709 d->m_AutoRewind = (readByte() != 0);
710 d->m_RewindTime = read32bit();
711 d->m_MetroPlay = (readByte() != 0);
712 d->m_MetroRecord = (readByte() != 0);
713 d->m_MetroAccent = (readByte() != 0);
714 d->m_CountIn = readByte();
716 d->m_ThruOn = (readByte() != 0);
718 d->m_AutoRestart = (readByte() != 0);
719 d->m_CurTempoOfs = readByte();
720 d->m_TempoOfs1 = readByte();
721 d->m_TempoOfs2 = readByte();
722 d->m_TempoOfs3 = readByte();
724 d->m_PunchEnabled = (readByte() != 0);
725 d->m_PunchInTime = read32bit();
726 d->m_PunchOutTime = read32bit();
727 d->m_EndAllTime = read32bit();
732 void QWrk::processTimebaseChunk()
734 quint16 timebase = read16bit();
735 d->m_division = timebase;
739 void QWrk::processNoteArray(
int track,
int events)
742 quint8 status = 0, data1 = 0, data2 = 0, i = 0;
744 int value = 0, type = 0, channel = 0, len = 0;
747 for ( i = 0; (i < events) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i ) {
751 if (status >= 0x90) {
752 type = status & 0xf0;
753 channel = status & 0x0f;
755 if (type == 0x90 || type == 0xA0 || type == 0xB0 || type == 0xE0)
761 Q_EMIT
signalWRKNote(track, time, channel, data1, data2, dur);
776 value = (data2 << 7) + data1 - 8192;
783 }
else if (status == 5) {
784 int code = read16bit();
786 text = readString(len);
788 }
else if (status == 6) {
789 int code = read16bit();
793 }
else if (status == 7) {
795 text = readString(len);
797 for(
int j=0; j<13; ++j) {
798 int byte = readByte();
802 }
else if (status == 8) {
805 for(
int j=0; j<len; ++j) {
806 int byte = readByte();
812 text = readString(len);
816 if ((i < events) && atEnd()) {
822 void QWrk::processStreamChunk()
825 int dur = 0, value = 0, type = 0, channel = 0, i = 0;
826 quint8 status = 0, data1 = 0, data2 = 0;
827 quint16 track = read16bit();
828 int events = read16bit();
829 for ( i = 0; (i < events) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i ) {
835 type = status & 0xf0;
836 channel = status & 0x0f;
839 Q_EMIT
signalWRKNote(track, time, channel, data1, data2, dur);
854 value = (data2 << 7) + data1 - 8192;
862 if ((i < events) && atEnd()) {
868 void QWrk::processMeterChunk()
870 int count = read16bit();
871 for (
int i = 0; i < count; ++i) {
873 int measure = read16bit();
874 int num = readByte();
875 int den = pow(2.0, readByte());
881 void QWrk::processMeterKeyChunk()
883 int count = read16bit();
884 for (
int i = 0; i < count; ++i) {
885 int measure = read16bit();
886 int num = readByte();
887 int den = pow(2.0, readByte());
888 qint8 alt = readByte();
894 double QWrk::getRealTime(
long ticks)
const
896 double division = 1.0 * d->m_division;
901 if (!d->m_tempos.isEmpty()) {
902 foreach(
const RecTempo& rec, d->m_tempos) {
903 if (rec.time >= ticks)
908 return last.seconds + (((ticks - last.time) / division) * (60.0 / last.tempo));
911 void QWrk::processTempoChunk(
int factor)
913 double division = 1.0 * d->m_division;
914 int count = read16bit();
916 for (
int i = 0; i < count; ++i) {
918 long time = read32bit();
920 long tempo = read16bit() * factor;
924 next.tempo = tempo / 100.0;
927 last.tempo = next.tempo;
929 if (! d->m_tempos.isEmpty()) {
930 foreach(
const RecTempo& rec, d->m_tempos) {
931 if (rec.time >= time)
935 next.seconds = last.seconds +
936 (((time - last.time) / division) * (60.0 / last.tempo));
938 d->m_tempos.append(next);
944 void QWrk::processSysexChunk()
949 int bank = readByte();
950 int length = read16bit();
951 bool autosend = (readByte() != 0);
952 int namelen = readByte();
953 name = readString(namelen);
954 for(j=0; j<length; ++j) {
955 int byte = readByte();
961 void QWrk::processSysex2Chunk()
966 int bank = read16bit();
967 int length = read32bit();
968 quint8 b = readByte();
969 int port = ( b & 0xf0 ) >> 4;
970 bool autosend = ( (b & 0x0f) != 0);
971 int namelen = readByte();
972 name = readString(namelen);
973 for(j=0; j<length; ++j) {
974 int byte = readByte();
980 void QWrk::processNewSysexChunk()
985 int bank = read16bit();
986 int length = read32bit();
987 int port = read16bit();
988 bool autosend = (readByte() != 0);
989 int namelen = readByte();
990 name = readString(namelen);
991 for(j=0; j<length; ++j) {
992 int byte = readByte();
998 void QWrk::processThruChunk()
1001 qint8 port = readByte();
1002 qint8 channel = readByte();
1003 qint8 keyPlus = readByte();
1004 qint8 velPlus = readByte();
1005 qint8 localPort = readByte();
1006 qint8 mode = readByte();
1007 Q_EMIT
signalWRKThru(mode, port, channel, keyPlus, velPlus, localPort);
1010 void QWrk::processTrackOffset()
1012 quint16 track = read16bit();
1013 qint16 offset = read16bit();
1017 void QWrk::processTrackReps()
1019 quint16 track = read16bit();
1020 quint16 reps = read16bit();
1024 void QWrk::processTrackPatch()
1026 quint16 track = read16bit();
1027 qint8 patch = readByte();
1031 void QWrk::processTimeFormat()
1033 quint16 fmt = read16bit();
1034 quint16 ofs = read16bit();
1038 void QWrk::processComments()
1040 int len = read16bit();
1041 QString text = readString(len);
1045 void QWrk::processVariableRecord(
int max)
1047 int datalen = max - 32;
1049 QString name = readVarString();
1050 readGap(31 - name.length());
1051 for (
int i = 0; i < datalen; ++i )
1056 void QWrk::processUnknown(
int id)
1061 void QWrk::processNewTrack()
1071 bool selected =
false;
1074 quint16 track = read16bit();
1075 quint8 len = readByte();
1076 QString name = readString(len);
1078 patch = read16bit();
1085 channel = readByte();
1086 muted = (readByte() != 0);
1087 Q_EMIT
signalWRKNewTrack(name, track, channel, key, vel, port, selected, muted, loop);
1098 void QWrk::processSoftVer()
1100 int len = readByte();
1101 QString vers = readString(len);
1105 void QWrk::processTrackName()
1107 int track = read16bit();
1108 int len = readByte();
1109 QString name = readString(len);
1113 void QWrk::processStringTable()
1116 int rows = read16bit();
1117 for (
int i = 0; i < rows; ++i) {
1118 int len = readByte();
1119 QString name = readString(len);
1120 int idx = readByte();
1121 table.insert(idx, name);
1126 void QWrk::processLyricsStream()
1128 quint16 track = read16bit();
1129 int events = read32bit();
1130 processNoteArray(track, events);
1133 void QWrk::processTrackVol()
1135 quint16 track = read16bit();
1136 int vol = read16bit();
1140 void QWrk::processNewTrackOffset()
1142 quint16 track = read16bit();
1143 int offset = read32bit();
1147 void QWrk::processTrackBank()
1149 quint16 track = read16bit();
1150 int bank = read16bit();
1154 void QWrk::processSegmentChunk()
1157 int track = read16bit();
1158 int offset = read32bit();
1160 int len = readByte();
1161 name = readString(len);
1164 int events = read32bit();
1165 processNoteArray(track, events);
1168 void QWrk::processNewStream()
1171 int track = read16bit();
1172 int len = readByte();
1173 name = readString(len);
1175 int events = read32bit();
1176 processNoteArray(track, events);
1179 void QWrk::processEndChunk()
1184 int QWrk::readChunk()
1186 qint64 start_pos = d->internalFilePos();
1187 int ck = readByte();
1189 quint32 ck_len = read32bit();
1190 if (ck_len > d->m_IOStream->device()->bytesAvailable()) {
1195 start_pos = d->internalFilePos();
1196 d->m_lastChunkPos = start_pos + ck_len;
1197 readRawData(ck_len);
1201 processTrackChunk();
1207 processTimebaseChunk();
1210 processStreamChunk();
1213 processMeterChunk();
1216 processTempoChunk(100);
1219 processTempoChunk();
1222 processSysexChunk();
1228 processTrackOffset();
1234 processTrackPatch();
1237 processTimeFormat();
1243 processVariableRecord(ck_len);
1255 processStringTable();
1258 processLyricsStream();
1264 processNewTrackOffset();
1270 processMeterKeyChunk();
1273 processSysex2Chunk();
1276 processNewSysexChunk();
1279 processSegmentChunk();
1287 if (d->internalFilePos() != d->m_lastChunkPos) {
1289 seek(d->m_lastChunkPos);
1295 void QWrk::wrkRead()
1297 QByteArray hdr(
HEADER.length(),
' ');
1298 d->m_tempos.clear();
1299 d->m_IOStream->device()->read(hdr.data(),
HEADER.length());
1308 ck_id = readChunk();
1309 }
while ((ck_id !=
END_CHUNK) && !atEnd());
1312 readRawData(d->m_IOStream->device()->bytesAvailable());
1313 processUnknown(ck_id);
1320 qint64 QWrk::QWrkPrivate::internalFilePos()
1322 return m_IOStream->device()->pos();
1325 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.
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.
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 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 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.
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 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#, ...
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.