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 #ifndef DRUMSTICK_QWRK_H 20 #define DRUMSTICK_QWRK_H 21 22 #include "macros.h" 23 #include <QObject> 24 #include <QScopedPointer> 25 26 class QTextCodec; 27 class QDataStream; 28 29 /** 30 * @file qwrk.h 31 * Cakewalk WRK Files Input 32 */ 33 34 namespace drumstick { namespace File { 35 36 /** 37 * @addtogroup WRK Cakewalk WRK File Parser (Input) 38 * @{ 39 * 40 * @enum WrkChunkType 41 * Record types within a WRK file 42 */ 43 enum WrkChunkType { 44 TRACK_CHUNK = 1, ///< Track prefix 45 STREAM_CHUNK = 2, ///< Events stream 46 VARS_CHUNK = 3, ///< Global variables 47 TEMPO_CHUNK = 4, ///< Tempo map 48 METER_CHUNK = 5, ///< Meter map 49 SYSEX_CHUNK = 6, ///< System exclusive bank 50 MEMRGN_CHUNK = 7, ///< Memory region 51 COMMENTS_CHUNK = 8, ///< Comments 52 TRKOFFS_CHUNK = 9, ///< Track offset 53 TIMEBASE_CHUNK = 10, ///< Timebase. If present is the first chunk in the file. 54 TIMEFMT_CHUNK = 11, ///< SMPTE time format 55 TRKREPS_CHUNK = 12, ///< Track repetitions 56 TRKPATCH_CHUNK = 14, ///< Track patch 57 NTEMPO_CHUNK = 15, ///< New Tempo map 58 THRU_CHUNK = 16, ///< Extended thru parameters 59 LYRICS_CHUNK = 18, ///< Events stream with lyrics 60 TRKVOL_CHUNK = 19, ///< Track volume 61 SYSEX2_CHUNK = 20, ///< System exclusive bank 62 MARKERS_CHUNK = 21, ///< Markers 63 STRTAB_CHUNK = 22, ///< Table of text event types 64 METERKEY_CHUNK = 23, ///< Meter/Key map 65 TRKNAME_CHUNK = 24, ///< Track name 66 VARIABLE_CHUNK = 26, ///< Variable record chunk 67 NTRKOFS_CHUNK = 27, ///< Track offset 68 TRKBANK_CHUNK = 30, ///< Track bank 69 NTRACK_CHUNK = 36, ///< Track prefix 70 NSYSEX_CHUNK = 44, ///< System exclusive bank 71 NSTREAM_CHUNK = 45, ///< Events stream 72 SGMNT_CHUNK = 49, ///< Segment prefix 73 SOFTVER_CHUNK = 74, ///< Software version which saved the file 74 END_CHUNK = 255 ///< Last chunk, end of file 75 }; 76 77 /** 78 * Cakewalk WRK file format (input only) 79 * 80 * This class is used to parse Cakewalk WRK Files. 81 * Signals with QString parameters are deprecated because the class QTextCodec was removed from QtCore since Qt6. 82 * 83 * @since 0.3.0 84 */ 85 class DRUMSTICK_EXPORT QWrk : public QObject 86 { 87 Q_OBJECT 88 Q_ENUM(WrkChunkType) 89 public: 90 explicit QWrk(QObject * parent = nullptr); 91 virtual ~QWrk(); 92 93 void readFromStream(QDataStream *stream); 94 void readFromFile(const QString& fileName); 95 Q_DECL_DEPRECATED QTextCodec* getTextCodec(); 96 Q_DECL_DEPRECATED void setTextCodec(QTextCodec *codec); 97 long getFilePos(); 98 99 int getNow() const; 100 int getFrom() const; 101 int getThru() const; 102 int getKeySig() const; 103 int getClock() const; 104 int getAutoSave() const; 105 int getPlayDelay() const; 106 bool getZeroCtrls() const; 107 bool getSendSPP() const; 108 bool getSendCont() const; 109 bool getPatchSearch() const; 110 bool getAutoStop() const; 111 unsigned int getStopTime() const; 112 bool getAutoRewind() const; 113 int getRewindTime() const; 114 bool getMetroPlay() const; 115 bool getMetroRecord() const; 116 bool getMetroAccent() const; 117 int getCountIn() const; 118 bool getThruOn() const; 119 bool getAutoRestart() const; 120 int getCurTempoOfs() const; 121 int getTempoOfs1() const; 122 int getTempoOfs2() const; 123 int getTempoOfs3() const; 124 bool getPunchEnabled() const; 125 int getPunchInTime() const; 126 int getPunchOutTime() const; 127 int getEndAllTime() const; 128 129 QByteArray getLastChunkRawData() const; 130 double getRealTime(long ticks) const; 131 132 /** 133 * Cakewalk WRK file format header string id 134 */ 135 static const QByteArray HEADER; ///< Cakewalk WRK File header id 136 137 Q_SIGNALS: 138 139 /** 140 * Emitted for a WRK file read error 141 * 142 * @param errorStr Error string 143 */ 144 void signalWRKError(const QString& errorStr); 145 146 /** 147 * Emitted after reading an unknown chunk 148 * 149 * @param type chunk type 150 * @param data chunk data (not decoded) 151 */ 152 void signalWRKUnknownChunk(int type, const QByteArray& data); 153 154 /** 155 * Emitted after reading a WRK header 156 * 157 * @param verh WRK file format version major 158 * @param verl WRK file format version minor 159 */ 160 void signalWRKHeader(int verh, int verl); 161 162 /** 163 * Emitted after reading the last chunk of a WRK file 164 */ 165 void signalWRKEnd(); 166 167 /** 168 * Emitted after reading the last event of a event stream 169 * @param time musical time 170 */ 171 void signalWRKStreamEnd(long time); 172 173 /** 174 * Emitted after reading a Note message 175 * 176 * @param track track number 177 * @param time musical time 178 * @param chan MIDI Channel 179 * @param pitch MIDI Note 180 * @param vol Velocity 181 * @param dur Duration 182 */ 183 void signalWRKNote(int track, long time, int chan, int pitch, int vol, int dur); 184 185 /** 186 * Emitted after reading a Polyphonic Aftertouch message 187 * 188 * @param track track number 189 * @param time musical time 190 * @param chan MIDI Channel 191 * @param pitch MIDI Note 192 * @param press Pressure amount 193 */ 194 void signalWRKKeyPress(int track, long time, int chan, int pitch, int press); 195 196 /** 197 * Emitted after reading a Control Change message 198 * 199 * @param track track number 200 * @param time musical time 201 * @param chan MIDI Channel 202 * @param ctl MIDI Controller 203 * @param value Control value 204 */ 205 void signalWRKCtlChange(int track, long time, int chan, int ctl, int value); 206 207 /** 208 * Emitted after reading a Bender message 209 * 210 * @param track track number 211 * @param time musical time 212 * @param chan MIDI Channel 213 * @param value Bender value 214 */ 215 void signalWRKPitchBend(int track, long time, int chan, int value); 216 217 /** 218 * Emitted after reading a Program change message 219 * 220 * @param track track number 221 * @param time musical time 222 * @param chan MIDI Channel 223 * @param patch Program number 224 */ 225 void signalWRKProgram(int track, long time, int chan, int patch); 226 227 /** 228 * Emitted after reading a Channel Aftertouch message 229 * 230 * @param track track number 231 * @param time musical time 232 * @param chan MIDI Channel 233 * @param press Pressure amount 234 */ 235 void signalWRKChanPress(int track, long time, int chan, int press); 236 237 /** 238 * Emitted after reading a System Exclusive event 239 * 240 * @param track track number 241 * @param time musical time 242 * @param bank Sysex Bank number 243 */ 244 void signalWRKSysexEvent(int track, long time, int bank); 245 246 /** 247 * Emitted after reading a System Exclusive Bank 248 * 249 * @param bank Sysex Bank number 250 * @param name Sysex Bank name 251 * @param autosend Send automatically after loading the song 252 * @param port MIDI output port 253 * @param data Sysex bytes 254 */ 255 void signalWRKSysex(int bank, const QString& name, bool autosend, int port, const QByteArray& data); 256 257 /** 258 * Emitted after reading a text message 259 * 260 * @param track track number 261 * @param time musical time 262 * @param type Text type 263 * @param data Text data 264 * @deprecated because the class QTextCodec was removed from QtCore since Qt6. 265 * use signalWRKText2() instead 266 */ 267 Q_DECL_DEPRECATED void signalWRKText(int track, long time, int type, const QString& data); 268 269 /** 270 * Emitted after reading a WRK Time signature 271 * 272 * @param bar Measure number 273 * @param num Numerator 274 * @param den Denominator (exponent in a power of two) 275 */ 276 void signalWRKTimeSig(int bar, int num, int den); 277 278 /** 279 * Emitted after reading a WRK Key Signature 280 * 281 * @param bar Measure number 282 * @param alt Number of alterations (negative=flats, positive=sharps) 283 */ 284 void signalWRKKeySig(int bar, int alt); 285 286 /** 287 * Emitted after reading a Tempo Change message. 288 * 289 * Tempo units are given in beats * 100 per minute, so to obtain BPM 290 * it is necessary to divide by 100 the tempo. 291 * 292 * @param time musical time 293 * @param tempo beats per minute multiplied by 100 294 */ 295 void signalWRKTempo(long time, int tempo); 296 297 /** 298 * Emitted after reading a track prefix chunk 299 * 300 * @param name1 track 1st name 301 * @param name2 track 2nd name 302 * @param trackno track number 303 * @param channel track forced channel (-1=no forced) 304 * @param pitch track pitch transpose in semitones (-127..127) 305 * @param velocity track velocity increment (-127..127) 306 * @param port track forced port 307 * @param selected true if track is selected 308 * @param muted true if track is muted 309 * @param loop true if loop is enabled 310 * @deprecated because the class QTextCodec was removed from QtCore since Qt6. 311 * use signalWRKTrack2() instead 312 */ 313 Q_DECL_DEPRECATED 314 void signalWRKTrack(const QString& name1, 315 const QString& name2, 316 int trackno, int channel, int pitch, 317 int velocity, int port, 318 bool selected, bool muted, bool loop ); 319 320 /** 321 * Emitted after reading the timebase chunk 322 * 323 * @param timebase ticks per quarter note 324 */ 325 void signalWRKTimeBase(int timebase); 326 327 /** 328 * Emitted after reading the global variables chunk. 329 * 330 * This record contains miscellaneous Cakewalk global variables that can 331 * be retrieved using individual getters. 332 * 333 * @see getNow(), getFrom(), getThru() 334 */ 335 void signalWRKGlobalVars(); 336 337 /** 338 * Emitted after reading an Extended Thru parameters chunk. 339 * 340 * It was introduced in Cakewalk version 4.0. These parameters are 341 * intended to override the global vars Thruon value, so this record should 342 * come after the VARS_CHUNK record. It is optional. 343 * 344 * @param mode (auto, off, on) 345 * @param port MIDI port 346 * @param channel MIDI channel 347 * @param keyPlus Note transpose 348 * @param velPlus Velocity transpose 349 * @param localPort MIDI local port 350 */ 351 void signalWRKThru(int mode, int port, int channel, int keyPlus, int velPlus, int localPort); 352 353 /** 354 * Emitted after reading a track offset chunk 355 * 356 * @param track track number 357 * @param offset time offset 358 */ 359 void signalWRKTrackOffset(int track, int offset); 360 361 /** 362 * Emitted after reading a track offset chunk 363 * 364 * @param track track number 365 * @param reps number of repetitions 366 */ 367 void signalWRKTrackReps(int track, int reps); 368 369 /** 370 * Emitted after reading a track patch chunk 371 * 372 * @param track track number 373 * @param patch 374 */ 375 void signalWRKTrackPatch(int track, int patch); 376 377 /** 378 * Emitted after reading a track bank chunk 379 * 380 * @param track track number 381 * @param bank 382 */ 383 void signalWRKTrackBank(int track, int bank); 384 385 /** 386 * Emitted after reading a SMPTE time format chunk 387 * 388 * @param frames frames/sec (24, 25, 29=30-drop, 30) 389 * @param offset frames of offset 390 */ 391 void signalWRKTimeFormat(int frames, int offset); 392 393 /** 394 * Emitted after reading a comments chunk 395 * 396 * @param data file text comments 397 * @deprecated because the class QTextCodec was removed from QtCore since Qt6. 398 * use signalWRKComments2() instead 399 */ 400 Q_DECL_DEPRECATED void signalWRKComments(const QString& data); 401 402 /** 403 * Emitted after reading a variable chunk. 404 * This record may contain data in text or binary format. 405 * 406 * @param name record identifier 407 * @param data record variable data 408 */ 409 void signalWRKVariableRecord(const QString& name, const QByteArray& data); 410 411 /** 412 * Emitted after reading a track volume chunk. 413 * 414 * @param track track number 415 * @param vol initial volume 416 */ 417 void signalWRKTrackVol(int track, int vol); 418 419 /** 420 * Emitted after reading a new track prefix 421 * 422 * @param name track name 423 * @param trackno track number 424 * @param channel forced MIDI channel 425 * @param pitch Note transposition 426 * @param velocity Velocity increment 427 * @param port MIDI port number 428 * @param selected track is selected 429 * @param muted track is muted 430 * @param loop track loop enabled 431 * @deprecated because the class QTextCodec was removed from QtCore since Qt6. 432 * use signalWRKNewTrack2() instead 433 */ 434 Q_DECL_DEPRECATED 435 void signalWRKNewTrack( const QString& name, 436 int trackno, int channel, int pitch, 437 int velocity, int port, 438 bool selected, bool muted, bool loop ); 439 440 /** 441 * Emitted after reading a software version chunk. 442 * 443 * @param version software version string 444 */ 445 void signalWRKSoftVer(const QString& version); 446 447 /** 448 * Emitted after reading a track name chunk. 449 * 450 * @param track track number 451 * @param name track name 452 * @deprecated because the class QTextCodec was removed from QtCore since Qt6. 453 * use signalWRKTrackName2() instead 454 */ 455 Q_DECL_DEPRECATED void signalWRKTrackName(int track, const QString& name); 456 457 /** 458 * Emitted after reading a string event types chunk. 459 * 460 * @param strs list of declared string event types 461 * @deprecated because the class QTextCodec was removed from QtCore since Qt6. 462 * use signalWRKStringTable2() instead 463 */ 464 Q_DECL_DEPRECATED void signalWRKStringTable(const QStringList& strs); 465 466 /** 467 * Emitted after reading a segment prefix chunk. 468 * 469 * @param track track number 470 * @param time segment time offset 471 * @param name segment name 472 * @deprecated because the class QTextCodec was removed from QtCore since Qt6. 473 * use signalWRKSegment2() instead 474 */ 475 Q_DECL_DEPRECATED void signalWRKSegment(int track, long time, const QString& name); 476 477 /** 478 * Emitted after reading a chord diagram chunk. 479 * 480 * @param track track number 481 * @param time event time in ticks 482 * @param name chord name 483 * @param data chord data definition (not decoded) 484 */ 485 void signalWRKChord(int track, long time, const QString& name, const QByteArray& data); 486 487 /** 488 * Emitted after reading an expression indication (notation) chunk. 489 * 490 * @param track track number 491 * @param time event time in ticks 492 * @param code expression event code 493 * @param text expression text 494 * @deprecated because the class QTextCodec was removed from QtCore since Qt6. 495 * use signalWRKExpression2() instead 496 */ 497 Q_DECL_DEPRECATED void signalWRKExpression(int track, long time, int code, const QString& text); 498 499 /** 500 * Emitted after reading a hairpin symbol (notation) chunk. 501 * 502 * @param track track number 503 * @param time event time in ticks 504 * @param code hairpin code 505 * @param dur duration 506 */ 507 void signalWRKHairpin(int track, long time, int code, int dur); 508 509 /** 510 * Emitted after reading a text message 511 * This signal is emitted when getTextCodec() is nullptr 512 * 513 * @param track track number 514 * @param time musical time 515 * @param type Text type 516 * @param data Text data 517 */ 518 void signalWRKText2(int track, long time, int type, const QByteArray& data); 519 520 /** 521 * Emitted after reading a track prefix chunk 522 * This signal is emitted when getTextCodec() is nullptr 523 * 524 * @param name1 track 1st name 525 * @param name2 track 2nd name 526 * @param trackno track number 527 * @param channel track forced channel (-1=no forced) 528 * @param pitch track pitch transpose in semitones (-127..127) 529 * @param velocity track velocity increment (-127..127) 530 * @param port track forced port 531 * @param selected true if track is selected 532 * @param muted true if track is muted 533 * @param loop true if loop is enabled 534 */ 535 void signalWRKTrack2(const QByteArray& name1, 536 const QByteArray& name2, 537 int trackno, int channel, int pitch, 538 int velocity, int port, 539 bool selected, bool muted, bool loop ); 540 541 /** 542 * Emitted after reading a comments chunk 543 * This signal is emitted when getTextCodec() is nullptr 544 * 545 * @param data file text comments 546 */ 547 void signalWRKComments2(const QByteArray& data); 548 549 /** 550 * Emitted after reading a new track prefix 551 * This signal is emitted when getTextCodec() is nullptr 552 * 553 * @param name track name 554 * @param trackno track number 555 * @param channel forced MIDI channel 556 * @param pitch Note transposition 557 * @param velocity Velocity increment 558 * @param port MIDI port number 559 * @param selected track is selected 560 * @param muted track is muted 561 * @param loop track loop enabled 562 */ 563 void signalWRKNewTrack2(const QByteArray& name, 564 int trackno, int channel, int pitch, 565 int velocity, int port, 566 bool selected, bool muted, bool loop ); 567 /** 568 * Emitted after reading a track name chunk. 569 * This signal is emitted when getTextCodec() is nullptr 570 * 571 * @param track track number 572 * @param name track name 573 */ 574 void signalWRKTrackName2(int track, const QByteArray& name); 575 576 /** 577 * Emitted after reading a string event types chunk. 578 * This signal is emitted when getTextCodec() is nullptr 579 * 580 * @param strs list of declared string event types 581 */ 582 void signalWRKStringTable2(const QList<QByteArray>& strs); 583 584 /** 585 * Emitted after reading a segment prefix chunk. 586 * This signal is emitted when getTextCodec() is nullptr 587 * 588 * @param track track number 589 * @param time segment time offset 590 * @param name segment name 591 */ 592 void signalWRKSegment2(int track, long time, const QByteArray& name); 593 594 /** 595 * Emitted after reading an expression indication (notation) chunk. 596 * This signal is emitted when getTextCodec() is nullptr 597 * 598 * @param track track number 599 * @param time event time in ticks 600 * @param code expression event code 601 * @param text expression text 602 */ 603 void signalWRKExpression2(int track, long time, int code, const QByteArray& text); 604 605 /** 606 * Emitted after reading a text marker 607 * This is deprecated because the class QTextCodec was removed from QtCore since Qt6 608 * Use signalWRKMarker2() instead 609 * 610 * @param time event time in ticks or smpte 611 * @param type tipe of time: 0=ticks or 1=smpte 612 * @param data marker text 613 * @deprecated because the class QTextCodec was removed from QtCore since Qt6. 614 * use signalWRKMarker2() instead 615 */ 616 Q_DECL_DEPRECATED void signalWRKMarker(long time, int type, const QString& data); 617 618 /** 619 * Emitted after reading a text marker 620 * This signal is emitted when getTextCodec() is nullptr 621 * 622 * @param time event time in ticks or smpte 623 * @param type tipe of time: 0=ticks or 1=smpte 624 * @param data marker text 625 */ 626 void signalWRKMarker2(long time, int type, const QByteArray& data); 627 628 private: 629 quint8 readByte(); 630 quint16 to16bit(quint8 c1, quint8 c2); 631 quint32 to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4); 632 quint16 read16bit(); 633 quint32 read24bit(); 634 quint32 read32bit(); 635 QString readString(int len); 636 QString readVarString(); 637 void readRawData(int size); 638 void readGap(int size); 639 bool atEnd(); 640 void seek(qint64 pos); 641 642 int readChunk(); 643 void processTrackChunk(); 644 void processVarsChunk(); 645 void processTimebaseChunk(); 646 void processNoteArray(int track, int events); 647 void processStreamChunk(); 648 void processMeterChunk(); 649 void processTempoChunk(int factor = 1); 650 void processSysexChunk(); 651 void processSysex2Chunk(); 652 void processNewSysexChunk(); 653 void processThruChunk(); 654 void processTrackOffset(); 655 void processTrackReps(); 656 void processTrackPatch(); 657 void processTrackBank(); 658 void processTimeFormat(); 659 void processComments(); 660 void processVariableRecord(int max); 661 void processNewTrack(); 662 void processSoftVer(); 663 void processTrackName(); 664 void processStringTable(); 665 void processLyricsStream(); 666 void processTrackVol(); 667 void processNewTrackOffset(); 668 void processMeterKeyChunk(); 669 void processSegmentChunk(); 670 void processNewStream(); 671 void processUnknown(int id); 672 void processEndChunk(); 673 void wrkRead(); 674 QByteArray readByteArray(int len); 675 QByteArray readVarByteArray(); 676 void processMarkers(); 677 678 struct RecTempo { 679 long time; 680 double tempo; 681 double seconds; 682 }; 683 684 class QWrkPrivate; 685 QScopedPointer<QWrkPrivate> d; 686 }; 687 688 /** @} */ 689 690 }} // namespace drumstick::File 691 692 #endif // DRUMSTICK_QWRK_H 693