/** * Furnace Tracker - multi-system chiptune tracker * Copyright (C) 2021-2026 tildearrow and contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _SONG_H #define _SONG_H #include #include "../pch.h" #include "defines.h" #include "../timeutils.h" #include "../ta-utils.h" #include "config.h" #include "assetDir.h" #include "orders.h" #include "instrument.h" #include "pattern.h" #include "wavetable.h" #include "sample.h" #include "sysDef.h" enum DivEffectType: unsigned short { DIV_EFFECT_NULL=0, DIV_EFFECT_DUMMY, DIV_EFFECT_EXTERNAL, DIV_EFFECT_VOLUME, DIV_EFFECT_FILTER }; enum DivFileElementType: unsigned char { DIV_ELEMENT_END=0, DIV_ELEMENT_SUBSONG, DIV_ELEMENT_CHIP_FLAGS, DIV_ELEMENT_ASSET_DIR, DIV_ELEMENT_INSTRUMENT, DIV_ELEMENT_WAVETABLE, DIV_ELEMENT_SAMPLE, DIV_ELEMENT_PATTERN, DIV_ELEMENT_COMPAT_FLAGS, DIV_ELEMENT_COMMENTS, DIV_ELEMENT_GROOVE, DIV_ELEMENT_MAX }; struct DivGroovePattern { unsigned short val[16]; unsigned short len; bool readData(SafeReader& reader); void putData(SafeWriter* w); DivGroovePattern(): len(1) { for (int i=0; i<16; i++) { val[i]=6; } } }; struct DivSongTimestamps { // song duration (in seconds and microseconds) TimeMicros totalTime; uint64_t totalTicks; int totalRows; // loop region (order/row positions) struct Position { int order, row; Position(): order(0), row(0) {} } loopStart, loopEnd; // set to true if a 0Bxx effect is found and it defines a loop region bool isLoopDefined; // set to false if FFxx is found bool isLoopable; // timestamp of a row // DO NOT ACCESS DIRECTLY! use the functions instead. // if seconds is -1, it means this row is not touched at all. TimeMicros* orders[DIV_MAX_PATTERNS]; TimeMicros loopStartTime; // the furthest row that the playhead goes through in an order. unsigned char maxRow[DIV_MAX_PATTERNS]; // call this function to get the timestamp of a row. TimeMicros getTimes(int order, int row); DivSongTimestamps(); ~DivSongTimestamps(); }; struct DivSubSong { String name, notes; unsigned char hilightA, hilightB; unsigned char effectDivider, arpLen; DivGroovePattern speeds; short virtualTempoN, virtualTempoD; float hz; int patLen, ordersLen; DivOrders orders; DivChannelData pat[DIV_MAX_CHANS]; bool chanShow[DIV_MAX_CHANS]; bool chanShowChanOsc[DIV_MAX_CHANS]; unsigned char chanCollapse[DIV_MAX_CHANS]; String chanName[DIV_MAX_CHANS]; String chanShortName[DIV_MAX_CHANS]; unsigned int chanColor[DIV_MAX_CHANS]; // song timestamps DivSongTimestamps ts; /** * calculate timestamps (loop position, song length and more). */ void calcTimestamps(int chans, std::vector& grooves, int jumpTreatment, int ignoreJumpAtEnd, int brokenSpeedSel, int delayBehavior, int firstPat=0); /** * read sub-song data. */ bool readData(SafeReader& reader, int version, int chans); /** * write sub-song block to a SafeWriter. */ void putData(SafeWriter* w, int chans); void clearData(); void removeUnusedPatterns(); void optimizePatterns(); void rearrangePatterns(); void sortOrders(); void makePatUnique(); DivSubSong(): hilightA(4), hilightB(16), effectDivider(0), arpLen(1), virtualTempoN(150), virtualTempoD(150), hz(60.0), patLen(64), ordersLen(1) { for (int i=0; i game name // writer -> ripper // createdDate -> year String carrier, composer, vendor, category, writer, arranger, copyright, manGroup, manInfo, createdDate, revisionDate; // more VGM specific stuff String nameJ, authorJ, categoryJ, systemNameJ; // other things String notes; // module details int insLen, waveLen, sampleLen; float masterVol; float tuning; bool autoSystem; bool patchbayAuto; // compatibility flags DivCompatFlags compatFlags; std::vector ins; std::vector wave; std::vector sample; std::vector subsong; std::vector patchbay; std::vector grooves; std::vector insDir; std::vector waveDir; std::vector sampleDir; std::vector effects; /** * INTERNAL STATE - do not modify. */ // default/"null" instruments (when instrument is none/-1) DivInstrument nullIns, nullInsOPLL, nullInsOPL, nullInsOPLDrums, nullInsQSound, nullInsESFM; // default assets, returned by getWave()/getSample() in DivEngine DivWavetable nullWave; DivSample nullSample; // channel information arrays. // chip of a channel DivSystem sysOfChan[DIV_MAX_CHANS]; // dispatch (chip index) of a channel int dispatchOfChan[DIV_MAX_CHANS]; // tracker channel to chip channel mapping // -1 means "nowhere". int dispatchChanOfChan[DIV_MAX_CHANS]; // the first channel of a chip, indexed per channel int dispatchFirstChan[DIV_MAX_CHANS]; // cached DivChanDef for each channel. DivChanDef chanDef[DIV_MAX_CHANS]; std::vector possibleInsTypes; /** * find data past 0Bxx effects and place that into new sub-songs. */ void findSubSongs(); /** * clear orders and patterns. */ void clearSongData(); /** * clear instruments. */ void clearInstruments(); /** * clear wavetables. */ void clearWavetables(); /** * clear samples. */ void clearSamples(); /** * set systemChans[] to default values. * call recalcChans() afterwards. */ void initDefaultSystemChans(); /** * recalculate channel count and internal state. * call after editing system[] or systemChans[]. */ void recalcChans(); /** * unloads the song, freeing all memory associated with it. * use before destroying the object. */ void unload(); DivSong(): version(0), isDMF(false), chans(0), systemLen(2), name(""), author(""), systemName(""), carrier(""), composer(""), vendor(""), category(""), writer(""), arranger(""), copyright(""), manGroup(""), manInfo(""), createdDate(""), revisionDate(""), insLen(0), waveLen(0), sampleLen(0), masterVol(1.0f), tuning(440.0f), autoSystem(true), patchbayAuto(true) { memset(dispatchFirstChan,0,DIV_MAX_CHANS*sizeof(int)); memset(dispatchChanOfChan,0,DIV_MAX_CHANS*sizeof(int)); memset(dispatchOfChan,0,DIV_MAX_CHANS*sizeof(int)); memset(sysOfChan,0,DIV_MAX_CHANS*sizeof(int)); for (int i=0; i