From 7ffbaf65b785a101fb5c2a5c1457689ec6d3f326 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 22 Jun 2024 02:01:26 -0500 Subject: [PATCH] S3M import: we load samples --- src/engine/fileOps/fileOpsCommon.cpp | 6 +- src/engine/fileOps/s3m.cpp | 120 ++++++++++++++++++++++++--- 2 files changed, 114 insertions(+), 12 deletions(-) diff --git a/src/engine/fileOps/fileOpsCommon.cpp b/src/engine/fileOps/fileOpsCommon.cpp index bc470bae3..38a324200 100644 --- a/src/engine/fileOps/fileOpsCommon.cpp +++ b/src/engine/fileOps/fileOpsCommon.cpp @@ -139,7 +139,7 @@ bool DivEngine::load(unsigned char* f, size_t slen, const char* nameHint) { len=slen; } - // step 2: try loading as .fur or .dmf + // step 2: try loading as .fur, .dmf, or another magic-ful format if (memcmp(file,DIV_DMF_MAGIC,16)==0) { return loadDMF(file,len); } else if (memcmp(file,DIV_FTM_MAGIC,18)==0) { @@ -154,6 +154,10 @@ bool DivEngine::load(unsigned char* f, size_t slen, const char* nameHint) { return loadFC(file,len); } else if (memcmp(file,DIV_TFM_MAGIC,8)==0) { return loadTFMv2(file,len); + } else if (len>=48) { + if (memcmp(&file[0x2c],DIV_S3M_MAGIC,4)==0) { + return loadS3M(file,len); + } } // step 3: try loading as .mod or TFEv1 (if the file extension matches) diff --git a/src/engine/fileOps/s3m.cpp b/src/engine/fileOps/s3m.cpp index fcebea9b7..5def3357e 100644 --- a/src/engine/fileOps/s3m.cpp +++ b/src/engine/fileOps/s3m.cpp @@ -28,8 +28,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { unsigned char chanSettings[32]; unsigned char ord[256]; - unsigned short insPtr[256]; - unsigned short patPtr[256]; + unsigned int insPtr[256]; + unsigned int patPtr[256]; unsigned char chanPan[16]; unsigned char defVol[256]; @@ -42,6 +42,8 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { ds.rowResetsArpPos=true; ds.ignoreJumpAtEnd=false; + logV("Scream Tracker 3 module"); + // load here if (!reader.seek(0x2c,SEEK_SET)) { logE("premature end of file!"); @@ -74,6 +76,9 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { unsigned short ordersLen=reader.readS(); ds.insLen=reader.readS(); + logV("orders: %d",ordersLen); + logV("instruments: %d",ds.insLen); + if (ds.insLen<0 || ds.insLen>256) { logE("invalid instrument count!"); lastError="invalid instrument count!"; @@ -83,10 +88,20 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { unsigned short patCount=reader.readS(); + logV("patterns: %d",patCount); + unsigned short flags=reader.readS(); unsigned short version=reader.readS(); bool signedSamples=(reader.readS()==1); + logV("flags: %x",flags); + logV("version: %x",flags); + if (signedSamples) { + logV("signed samples: yes"); + } else { + logV("signed samples: no"); + } + if ((flags&64) || version==0x1300) { ds.noSlidesOnFirstTick=false; } @@ -96,6 +111,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { unsigned char globalVol=reader.readC(); ds.subsong[0]->speeds.val[0]=(unsigned char)reader.readC(); + ds.subsong[0]->speeds.len=1; ds.subsong[0]->hz=((double)reader.readC())/2.5; unsigned char masterVol=reader.readC(); @@ -105,7 +121,9 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { logV("globalVol: %d",globalVol); reader.readC(); // UC - bool defaultPan=(((unsigned char)reader.readC())==252); + unsigned char defaultPan=(unsigned char)reader.readC(); + + logV("defaultPan: %d",defaultPan); reader.readS(); // reserved reader.readI(); @@ -113,6 +131,11 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { reader.read(chanSettings,32); + logD("channel settings:"); + for (int i=0; i<32; i++) { + logV("%d. %x",i,chanSettings[i]); + } + logD("reading orders..."); for (int i=0; i=32) continue; if ((chanSettings[i]&127)>=16) { hasFM=true; @@ -174,8 +199,9 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { // load instruments/samples ds.ins.reserve(ds.insLen); for (int i=0; i>=4; // ??? + + logV("memSeg: %x",memSeg); unsigned int length=reader.readI(); + logV("length: %x",length); + DivSample* s=new DivSample; s->depth=DIV_SAMPLE_DEPTH_8BIT; s->init(length); @@ -225,13 +255,81 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { logV("defVol: %d",defVol[i]); reader.readC(); // x + + bool isPacked=reader.readC(); + unsigned char flags=reader.readC(); + + s->centerRate=reader.readI(); + + // reserved + reader.readI(); // x + reader.readI(); + reader.readI(); + + String name=reader.readString(28); + s->name=name; + ins->name=name; + + // "SCRS" + reader.readI(); + + // read sample data + if (!reader.seek(memSeg,SEEK_SET)) { + logE("premature end of file!"); + lastError="incomplete file"; + delete ins; + delete s; + delete[] file; + return false; + } + + s->loop=flags&1; + s->depth=(flags&4)?DIV_SAMPLE_DEPTH_16BIT:DIV_SAMPLE_DEPTH_8BIT; + s->init(length>>(s->depth==DIV_SAMPLE_DEPTH_16BIT?1:0)); + + if (flags&2) { + logE("stereo sample!"); + lastError="stereo sample"; + delete ins; + delete s; + delete[] file; + return false; + } + + if (isPacked) { + logE("ADPCM not supported!"); + lastError="ADPCM sample"; + delete ins; + delete s; + delete[] file; + return false; + } + + reader.read(s->getCurBuf(),length); + + if (!signedSamples) { + if (s->depth==DIV_SAMPLE_DEPTH_16BIT) { + for (unsigned int i=0; isamples; i++) { + s->data16[i]^=0x8000; + } + } else { + for (unsigned int i=0; isamples; i++) { + s->data8[i]^=0x80; + } + } + } + + ins->amiga.initSample=ds.sample.size(); + ds.sample.push_back(s); } else { - + // TODO: OPL } ds.ins.push_back(ins); } + ds.sampleLen=ds.sample.size(); + if (active) quitDispatch(); BUSY_BEGIN_SOFT; saveLock.lock();