From 334d8708e277d8be7c53a2b84e9c3ea971f0211b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 16 Nov 2025 07:13:30 -0500 Subject: [PATCH] giga-refactor, part 12 loading works --- src/engine/fileOps/fur.cpp | 161 +++++++++++++++++++------------------ src/engine/song.cpp | 156 ++++++++++++++++++++++++++++++++++- src/engine/song.h | 18 ++++- 3 files changed, 250 insertions(+), 85 deletions(-) diff --git a/src/engine/fileOps/fur.cpp b/src/engine/fileOps/fur.cpp index 4eba95539..34ca3c62e 100644 --- a/src/engine/fileOps/fur.cpp +++ b/src/engine/fileOps/fur.cpp @@ -883,11 +883,19 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { ds.chans=(unsigned short)reader.readS(); ds.systemLen=(unsigned short)reader.readS(); + if (ds.systemLen<1) { + logE("zero chips!"); + lastError="zero chips!"; + delete[] file; + return false; + } + // TODO: remove after implementing dynamic stuff for (int i=0; i0xff || sysID==0) { @@ -923,6 +931,8 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { ds.systemChans[i]=(unsigned short)reader.readS(); tchans+=ds.systemChans[i]; + logD("- %d: %.2x (%s, %d channels)",i,sysID,getSystemName(ds.system[i]),ds.systemChans[i]); + if (ds.systemChans[i]<1) { logE("invalid channel count for chip"); lastError=fmt::sprintf("invalid channel count for chip!"); @@ -952,13 +962,28 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { // elements bool hasElement=true; + bool seenElement[DIV_ELEMENT_MAX]; + memset(seenElement,0,DIV_ELEMENT_MAX*sizeof(bool)); + logD("elements present in this song:"); while (hasElement) { DivFileElementType elementType=(DivFileElementType)reader.readC(); + if (elementType256) { logE("invalid instrument count!"); @@ -981,6 +1008,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { ds.insLen=insPtr.size(); break; case DIV_ELEMENT_WAVETABLE: + logD("- wavetables"); READ_ELEMENT_PTRS(wavePtr); if (wavePtr.size()>32768) { logE("invalid wavetable count!"); @@ -991,6 +1019,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { ds.waveLen=wavePtr.size(); break; case DIV_ELEMENT_SAMPLE: + logD("- samples"); READ_ELEMENT_PTRS(samplePtr); if (samplePtr.size()>32768) { logE("invalid sample count!"); @@ -1001,22 +1030,42 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { ds.sampleLen=samplePtr.size(); break; case DIV_ELEMENT_PATTERN: + logD("- patterns"); READ_ELEMENT_PTRS(patPtr); break; case DIV_ELEMENT_COMPAT_FLAGS: + logD("- compat flags"); READ_ELEMENT_UNIQUE(compatFlagPtr); break; case DIV_ELEMENT_COMMENTS: + logD("- song comments"); READ_ELEMENT_UNIQUE(commentPtr); break; case DIV_ELEMENT_GROOVE: + logD("- grooves"); READ_ELEMENT_PTRS(groovePtr); break; case DIV_ELEMENT_END: hasElement=false; break; + default: { + logD("- UNKNOWN"); + // skip element + unsigned int numElements=reader.readI(); + for (unsigned int i=0; itimeBase=reader.readC(); subSong->speeds.len=2; - subSong->speeds.val[0]=reader.readC(); - subSong->speeds.val[1]=reader.readC(); + subSong->speeds.val[0]=(unsigned char)reader.readC(); + subSong->speeds.val[1]=(unsigned char)reader.readC(); subSong->arpLen=reader.readC(); subSong->hz=reader.readF(); @@ -1048,7 +1097,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { if (subSong->patLen<0) { logE("pattern length is negative!"); - lastError="pattern lengrh is negative!"; + lastError="pattern length is negative!"; delete[] file; return false; } @@ -1182,7 +1231,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { } } - // TODO: don't call this ds.initDefaultSystemChans(); ds.name=reader.readString(); @@ -1576,7 +1624,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { if (ds.version>=139) { subSong->speeds.len=reader.readC(); for (int i=0; i<16; i++) { - subSong->speeds.val[i]=reader.readC(); + subSong->speeds.val[i]=(unsigned char)reader.readC(); } // grooves @@ -1584,9 +1632,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { ds.grooves.reserve(grooveCount); for (int i=0; i=119) { @@ -1736,7 +1805,8 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { if (ds.version>=95) { ds.subsong.reserve(subSongPtr.size()); for (size_t i=0; ireadData(reader,ds.version,ds.chans)) { + logE("%d: invalid subsong data!",i); + lastError="invalid subsong data!"; ds.unload(); delete[] file; return false; } - reader.readI(); - - subSong=ds.subsong[i+1]; - subSong->timeBase=reader.readC(); - subSong->speeds.len=2; - subSong->speeds.val[0]=reader.readC(); - subSong->speeds.val[1]=reader.readC(); - subSong->arpLen=reader.readC(); - subSong->hz=reader.readF(); - - subSong->patLen=reader.readS(); - subSong->ordersLen=reader.readS(); - - subSong->hilightA=reader.readC(); - subSong->hilightB=reader.readC(); - - if (ds.version>=96) { - subSong->virtualTempoN=reader.readS(); - subSong->virtualTempoD=reader.readS(); - } else { - reader.readI(); - } - - subSong->name=reader.readString(); - subSong->notes=reader.readString(); - - logD("reading orders of subsong %d (%d)...",i+1,subSong->ordersLen); - for (int j=0; jordersLen; k++) { - subSong->orders.ord[j][k]=reader.readC(); - } - } - - for (int i=0; ipat[i].effectCols=reader.readC(); - } - - for (int i=0; ichanShow[i]=reader.readC(); - subSong->chanShowChanOsc[i]=subSong->chanShow[i]; - } else { - unsigned char tempchar=reader.readC(); - subSong->chanShow[i]=tempchar&1; - subSong->chanShowChanOsc[i]=tempchar&2; - } - } - - for (int i=0; ichanCollapse[i]=reader.readC(); - } - - for (int i=0; ichanName[i]=reader.readString(); - } - - for (int i=0; ichanShortName[i]=reader.readString(); - } - - if (ds.version>=139) { - subSong->speeds.len=reader.readC(); - for (int i=0; i<16; i++) { - subSong->speeds.val[i]=reader.readC(); - } - } } } diff --git a/src/engine/song.cpp b/src/engine/song.cpp index c9cdb02dc..8d682c749 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -451,6 +451,142 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove logV("song length: %s; %" PRIu64 " ticks",ts.totalTime.toString(6,TA_TIME_FORMAT_AUTO),ts.totalTicks); } +bool DivSubSong::readData(SafeReader& reader, int version, int chans) { + unsigned char magic[4]; + + reader.read(magic,4); + + if (version>=240) { + if (memcmp(magic,"SNG2",4)!=0) { + logE("invalid subsong header!"); + return false; + } + reader.readI(); + + hz=reader.readF(); + arpLen=reader.readC(); + timeBase=reader.readC(); + + patLen=reader.readS(); + ordersLen=reader.readS(); + + hilightA=reader.readC(); + hilightB=reader.readC(); + + virtualTempoN=reader.readS(); + virtualTempoD=reader.readS(); + + speeds.len=reader.readC(); + for (int i=0; i<16; i++) { + speeds.val[i]=reader.readS(); + } + + name=reader.readString(); + notes=reader.readString(); + + logD("reading orders (%d)...",ordersLen); + for (int j=0; j=96) { + virtualTempoN=reader.readS(); + virtualTempoD=reader.readS(); + } else { + reader.readI(); + } + + name=reader.readString(); + notes=reader.readString(); + + logD("reading orders (%d)...",ordersLen); + for (int j=0; j=139) { + speeds.len=reader.readC(); + for (int i=0; i<16; i++) { + speeds.val[i]=(unsigned char)reader.readC(); + } + } + } + + return true; +} + void DivSubSong::putData(SafeWriter* w, int chans) { size_t blockStartSeek, blockEndSeek; w->write("SNG2",4); @@ -468,7 +604,7 @@ void DivSubSong::putData(SafeWriter* w, int chans) { w->writeS(virtualTempoD); // speeds - w->writeS(speeds.len); + w->writeC(speeds.len); for (int i=0; i<16; i++) { w->writeS(speeds.val[i]); } @@ -873,13 +1009,29 @@ void DivSong::unload() { subsong.clear(); } +bool DivGroovePattern::readData(SafeReader& reader) { + unsigned char magic[4]; + + reader.read(magic,4); + + if (memcmp(magic,"GROV",4)!=0) { + logE("invalid groove header!"); + return false; + } + reader.readI(); + + + + return true; +} + void DivGroovePattern::putData(SafeWriter* w) { size_t blockStartSeek, blockEndSeek; w->write("GROV",4); blockStartSeek=w->tell(); w->writeI(0); - w->writeS(len); + w->writeC(len); for (int i=0; i<16; i++) { w->writeS(val[i]); } diff --git a/src/engine/song.h b/src/engine/song.h index 15bd303e3..e8499700b 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -171,17 +171,22 @@ enum DivFileElementType: unsigned char { DIV_ELEMENT_PATTERN, DIV_ELEMENT_COMPAT_FLAGS, DIV_ELEMENT_COMMENTS, - DIV_ELEMENT_GROOVE + DIV_ELEMENT_GROOVE, + + DIV_ELEMENT_MAX }; struct DivGroovePattern { - unsigned char val[16]; - unsigned char len; + unsigned short val[16]; + unsigned short len; + bool readData(SafeReader& reader); void putData(SafeWriter* w); DivGroovePattern(): len(1) { - memset(val,6,16); + for (int i=0; i<16; i++) { + val[i]=6; } + } }; struct DivSongTimestamps { @@ -244,6 +249,11 @@ struct DivSubSong { */ 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. */