From 854698cd752d8dc641b4067383758c3c0361c1d0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 12 Mar 2023 19:11:05 -0500 Subject: [PATCH] S3M import? no, it's not there yet --- src/engine/engine.h | 2 + src/engine/fileOps.cpp | 227 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) diff --git a/src/engine/engine.h b/src/engine/engine.h index f1e5e91f..0ff399bf 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -52,6 +52,7 @@ // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 +#define DIV_VERSION_S3M 0xff03 // "Namco C163" #define DIV_C163_DEFAULT_NAME "Namco 163" @@ -457,6 +458,7 @@ class DivEngine { bool loadDMF(unsigned char* file, size_t len); bool loadFur(unsigned char* file, size_t len); bool loadMod(unsigned char* file, size_t len); + bool loadS3M(unsigned char* file, size_t len); bool loadFTM(unsigned char* file, size_t len); bool loadFC(unsigned char* file, size_t len); diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index c1ce3489..4db52313 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -30,6 +30,7 @@ #define DIV_FTM_MAGIC "FamiTracker Module" #define DIV_FC13_MAGIC "SMOD" #define DIV_FC14_MAGIC "FC14" +#define DIV_S3M_MAGIC "SCRM" struct InflateBlock { unsigned char* buf; @@ -3226,6 +3227,232 @@ void generateFCPresetWave(int index, DivWavetable* wave) { } } +bool DivEngine::loadS3M(unsigned char* file, size_t len) { + struct InvalidHeaderException {}; + bool success=false; + char magic[4]={0,0,0,0}; + SafeReader reader=SafeReader(file,len); + warnings=""; + + unsigned char chanSettings[32]; + unsigned char ord[256]; + unsigned short insPtr[256]; + unsigned short panPtr[256]; + unsigned char chanPan[16]; + unsigned char defVol[256]; + + try { + DivSong ds; + ds.version=DIV_VERSION_S3M; + ds.linearPitch=0; + ds.pitchMacroIsLinear=false; + ds.noSlidesOnFirstTick=true; + ds.rowResetsArpPos=true; + ds.ignoreJumpAtEnd=false; + + // load here + if (!reader.seek(0x2c,SEEK_SET)) { + logE("premature end of file!"); + lastError="incomplete file"; + delete[] file; + return false; + } + reader.read(magic,4); + + if (memcmp(magic,DIV_S3M_MAGIC,4)!=0) { + logW("the magic isn't complete"); + throw EndOfFileException(&reader,reader.tell()); + } + + if (!reader.seek(0,SEEK_SET)) { + logE("premature end of file!"); + lastError="incomplete file"; + delete[] file; + return false; + } + + ds.name=reader.readString(28); + + reader.readC(); // 0x1a + if (reader.readC()!=16) { + logW("type is wrong!"); + } + reader.readS(); // x + + unsigned short ordersLen=reader.readS(); + ds.insLen=reader.readS(); + + if (ds.insLen<0 || ds.insLen>256) { + logE("invalid instrument count!"); + lastError="invalid instrument count!"; + delete[] file; + return false; + } + + unsigned short patCount=reader.readS(); + + unsigned short flags=reader.readS(); + unsigned short version=reader.readS(); + bool signedSamples=(reader.readS()==1); + + if ((flags&64) || version==0x1300) { + ds.noSlidesOnFirstTick=false; + } + + reader.readI(); // "SCRM" + + unsigned char globalVol=reader.readC(); + + ds.subsong[0]->speeds.val[0]=(unsigned char)reader.readC(); + ds.subsong[0]->hz=((double)reader.readC())/2.5; + ds.subsong[0]->customTempo=true; + + unsigned char masterVol=reader.readC(); + + reader.readC(); // UC + bool defaultPan=(((unsigned char)reader.readC())==252); + + reader.readS(); // reserved + reader.readI(); + reader.readI(); // the last 2 bytes is Special. we don't read that. + + reader.read(chanSettings,32); + + for (int i=0; i=32) continue; + if ((chanSettings[i]&127)>=16) { + hasFM=true; + } else { + hasPCM=true; + } + + if (hasFM && hasPCM) break; + } + + ds.systemName="PC"; + if (hasPCM) { + ds.system[ds.systemLen]=DIV_SYSTEM_ES5506; + ds.systemVol[ds.systemLen]=1.0f; + ds.systemPan[ds.systemLen]=0; + ds.systemLen++; + } + if (hasFM) { + ds.system[ds.systemLen]=DIV_SYSTEM_OPL2; + ds.systemVol[ds.systemLen]=1.0f; + ds.systemPan[ds.systemLen]=0; + ds.systemLen++; + } + + // load instruments/samples + for (int i=0; itype=DIV_INS_ES5506; + } else if (memcmp(magic,"SCRI",4)==0) { + ins->type=DIV_INS_OPL; + } else { + ins->type=DIV_INS_ES5506; + ds.ins.push_back(ins); + continue; + } + + if (!reader.seek(insPtr[i]*16,SEEK_SET)) { + logE("premature end of file!"); + lastError="incomplete file"; + delete ins; + delete[] file; + return false; + } + + String dosName=reader.readString(13); + + if (ins->type==DIV_INS_ES5506) { + unsigned int memSeg=0; + memSeg=(unsigned char)reader.readC(); + memSeg|=((unsigned short)reader.readS())<<8; + + unsigned int length=reader.readI(); + + DivSample* s=new DivSample; + s->depth=DIV_SAMPLE_DEPTH_8BIT; + s->init(length); + + s->loopStart=reader.readI(); + s->loopEnd=reader.readI(); + defVol[i]=reader.readC(); + + reader.readC(); // x + } else { + + } + + ds.ins.push_back(ins); + } + + if (active) quitDispatch(); + BUSY_BEGIN_SOFT; + saveLock.lock(); + song.unload(); + song=ds; + changeSong(0); + recalcChans(); + saveLock.unlock(); + BUSY_END; + if (active) { + initDispatch(); + BUSY_BEGIN; + renderSamples(); + reset(); + BUSY_END; + } + success=true; + } catch (EndOfFileException& e) { + //logE("premature end of file!"); + lastError="incomplete file"; + } catch (InvalidHeaderException& e) { + //logE("invalid header!"); + lastError="invalid header!"; + } + return success; +} + bool DivEngine::loadFC(unsigned char* file, size_t len) { struct InvalidHeaderException {}; bool success=false;