From 8a49522e5956b271a76645f2588aa30f893a4154 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 01:41:45 -0500 Subject: [PATCH] beta 1-3 .dmf loading i did it --- src/engine/fileOps.cpp | 309 ++++++++++++++++++++++++++--------------- 1 file changed, 195 insertions(+), 114 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 8514d91ab..356e40e7e 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -53,6 +53,10 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { warnings=""; try { DivSong ds; + unsigned char historicColIns[DIV_MAX_CHANS]; + for (int i=0; i0x03) { + if (ds.version>0x05) { ds.speed2=reader.readC(); ds.pal=reader.readC(); ds.hz=(ds.pal)?60:50; @@ -258,7 +262,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { addWarning("Yamaha YMU759 emulation is incomplete! please migrate your song to the OPL3 system."); } - logI("reading pattern matrix (%d)...",ds.ordersLen); + logV("%x",reader.tell()); + + logI("reading pattern matrix (%d * %d = %d)...",ds.ordersLen,getChannelCount(ds.system[0]),ds.ordersLen*getChannelCount(ds.system[0])); for (int i=0; iname=reader.readString((unsigned char)reader.readC()); } } + if (ds.version>0x03 && ds.version<0x06 && i<16) { + historicColIns[i]=reader.readC(); + } } - if (ds.version>0x03) { + logV("%x",reader.tell()); + + if (ds.version>0x05) { ds.insLen=(unsigned char)reader.readC(); } else { ds.insLen=16; @@ -282,7 +293,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { logI("reading instruments (%d)...",ds.insLen); for (int i=0; i0x03) { + if (ds.version>0x05) { ins->name=reader.readString((unsigned char)reader.readC()); } logD("%d name: %s",i,ins->name.c_str()); @@ -319,29 +330,41 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } if (ins->mode) { // FM - ins->fm.alg=reader.readC(); - if (ds.version<0x13) { - reader.readC(); - } - ins->fm.fb=reader.readC(); - if (ds.version<0x13) { - reader.readC(); - } - ins->fm.fms=reader.readC(); - if (ds.version<0x13) { - reader.readC(); - ins->fm.ops=2+reader.readC()*2; - if (ds.system[0]!=DIV_SYSTEM_YMU759) ins->fm.ops=4; + if (ds.version>0x05) { + ins->fm.alg=reader.readC(); + if (ds.version<0x13) { + reader.readC(); + } + ins->fm.fb=reader.readC(); + if (ds.version<0x13) { + reader.readC(); + } + ins->fm.fms=reader.readC(); + if (ds.version<0x13) { + reader.readC(); + ins->fm.ops=2+reader.readC()*2; + if (ds.system[0]!=DIV_SYSTEM_YMU759) ins->fm.ops=4; + } else { + ins->fm.ops=4; + } + ins->fm.ams=reader.readC(); } else { - ins->fm.ops=4; + ins->fm.alg=reader.readC(); + reader.readC(); + ins->fm.fb=reader.readC(); + reader.readC(); // apparently an index of sorts starting from 0x59? + ins->fm.fms=reader.readC(); + reader.readC(); // 0x59+index? + ins->fm.ops=2+reader.readC()*2; } + + logD("ALG %d FB %d FMS %d AMS %d OPS %d",ins->fm.alg,ins->fm.fb,ins->fm.fms,ins->fm.ams,ins->fm.ops); if (ins->fm.ops!=2 && ins->fm.ops!=4) { logE("invalid op count %d. did we read it wrong?",ins->fm.ops); lastError="file is corrupt or unreadable at operators"; delete[] file; return false; } - ins->fm.ams=reader.readC(); for (int j=0; jfm.ops; j++) { ins->fm.op[j].am=reader.readC(); @@ -385,7 +408,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->fm.op[j].dt2=reader.readC(); } } - if (ds.version>0x03) { + if (ds.version>0x05) { if (ds.system[0]==DIV_SYSTEM_SMS_OPLL || ds.system[0]==DIV_SYSTEM_NES_VRC7) { ins->fm.op[j].ksr=reader.readC(); ins->fm.op[j].vib=reader.readC(); @@ -588,6 +611,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } + logV("%x",reader.tell()); + logI("reading patterns (%d channels, %d orders)...",getChannelCount(ds.system[0]),ds.ordersLen); for (int i=0; i4 || chan.effectRows<1) { @@ -606,79 +630,110 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } for (int j=0; jdata[k][0]=reader.readS(); - // octave - pat->data[k][1]=reader.readS(); - if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && pat->data[k][1]>0) { - // apparently it was up one octave before - pat->data[k][1]--; - } else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && pat->data[k][1]>0 && i>5) { - // ditto - pat->data[k][1]--; - } - if (ds.version<0x12) { - if (ds.system[0]==DIV_SYSTEM_GB && i==3 && pat->data[k][1]>0) { - // back then noise was 2 octaves lower - pat->data[k][1]-=2; + if (ds.version>0x05) { // current pattern format + for (int k=0; kdata[k][0]=reader.readS(); + // octave + pat->data[k][1]=reader.readS(); + if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && pat->data[k][1]>0) { + // apparently it was up one octave before + pat->data[k][1]--; + } else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && pat->data[k][1]>0 && i>5) { + // ditto + pat->data[k][1]--; + } + if (ds.version<0x12) { + if (ds.system[0]==DIV_SYSTEM_GB && i==3 && pat->data[k][1]>0) { + // back then noise was 2 octaves lower + pat->data[k][1]-=2; + } + } + if (ds.system[0]==DIV_SYSTEM_YMU759 && pat->data[k][0]!=0) { + // apparently YMU759 is stored 2 octaves lower + pat->data[k][1]+=2; + } + if (pat->data[k][0]==0 && pat->data[k][1]!=0) { + logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); + pat->data[k][0]=12; + pat->data[k][1]--; + } + // volume + pat->data[k][3]=reader.readS(); + if (ds.version<0x0a) { + // back then volume was stored as 00-ff instead of 00-7f/0-f + if (i>5) { + pat->data[k][3]>>=4; + } else { + pat->data[k][3]>>=1; + } + } + if (ds.version<0x12) { + if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->data[k][3]>0) { + // volume range of GB wave channel was 0-3 rather than 0-F + pat->data[k][3]=(pat->data[k][3]&3)*5; + } + } + for (int l=0; ldata[k][4+(l<<1)]=reader.readS(); + pat->data[k][5+(l<<1)]=reader.readS(); + + if (ds.version<0x14) { + if (pat->data[k][4+(l<<1)]==0xe5 && pat->data[k][5+(l<<1)]!=-1) { + pat->data[k][5+(l<<1)]=128+((pat->data[k][5+(l<<1)]-128)/4); + } + } + } + // instrument + pat->data[k][2]=reader.readS(); + + // this is sad + if (ds.system[0]==DIV_SYSTEM_NES_FDS) { + if (i==5 && pat->data[k][2]!=-1) { + if (pat->data[k][2]>=0 && pat->data[k][2]data[k][2]]->type=DIV_INS_FDS; + } + } } } - if (ds.system[0]==DIV_SYSTEM_YMU759 && pat->data[k][0]!=0) { - // apparently YMU759 is stored 2 octaves lower - pat->data[k][1]+=2; - } - if (pat->data[k][0]==0 && pat->data[k][1]!=0) { - logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); - pat->data[k][0]=12; - pat->data[k][1]--; - } - // volume - pat->data[k][3]=reader.readS(); - if (ds.version<0x0a) { - // back then volume was stored as 00-ff instead of 00-7f/0-f - if (i>5) { - pat->data[k][3]>>=4; - } else { - pat->data[k][3]>>=1; + } else { // historic pattern format + if (i<16) pat->data[0][2]=historicColIns[i]; + for (int k=0; kdata[k][0]=reader.readC(); + // octave + pat->data[k][1]=reader.readC(); + if (pat->data[k][0]!=0) { + // YMU759 is stored 2 octaves lower + pat->data[k][1]+=2; } - } - if (ds.version<0x12) { - if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->data[k][3]>0) { - // volume range of GB wave channel was 0-3 rather than 0-F - pat->data[k][3]=(pat->data[k][3]&3)*5; + if (pat->data[k][0]==0 && pat->data[k][1]!=0) { + logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); + pat->data[k][0]=12; + pat->data[k][1]--; } - } - for (int l=0; ldata[k][3]=(vol==0x80)?-1:vol; // effect - pat->data[k][4+(l<<1)]=reader.readS(); - pat->data[k][5+(l<<1)]=reader.readS(); - - if (ds.version<0x14) { - if (pat->data[k][4+(l<<1)]==0xe5 && pat->data[k][5+(l<<1)]!=-1) { - pat->data[k][5+(l<<1)]=128+((pat->data[k][5+(l<<1)]-128)/4); - } - } - } - // instrument - pat->data[k][2]=reader.readS(); - - // this is sad - if (ds.system[0]==DIV_SYSTEM_NES_FDS) { - if (i==5 && pat->data[k][2]!=-1) { - if (pat->data[k][2]>=0 && pat->data[k][2]data[k][2]]->type=DIV_INS_FDS; - } - } + pat->data[k][4]=(fx==0x80)?-1:fx; + pat->data[k][5]=(fxVal==0x80)?-1:fxVal; + // instrument wasn't stored back then } } } } + int ymuSampleRate=20; + ds.sampleLen=(unsigned char)reader.readC(); logI("reading samples (%d)...",ds.sampleLen); - if (ds.version<0x0b && ds.sampleLen>0) { // TODO what is this for? - reader.readC(); + if (ds.version<0x0b && ds.sampleLen>0) { + // it appears this byte stored the YMU759 sample rate + ymuSampleRate=reader.readC(); } for (int i=0; irate=ymuSampleRate*400; + } if (ds.version>0x15) { sample->depth=reader.readC(); if (sample->depth!=8 && sample->depth!=16) { @@ -711,43 +770,65 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { sample->depth=16; } } else { - sample->depth=16; + if (ds.version>0x05) { + sample->depth=16; + } else { + // it appears samples were stored as ADPCM back then + sample->depth=6; + } } if (length>0) { - if (ds.version<0x0b) { - data=new short[1+(length/2)]; - reader.read(data,length); - length/=2; - } else { - data=new short[length]; - reader.read(data,length*2); - } - - if (pitch!=5) { - logD("%d: scaling from %d...",i,pitch); - } - - // render data - if (!sample->init((double)length/samplePitches[pitch])) { - logE("%d: error while initializing sample!",i); - } - - unsigned int k=0; - float mult=(float)(vol)/50.0f; - for (double j=0; j=sample->samples) { - break; - } - if (sample->depth==8) { - float next=(float)(data[(unsigned int)j]-0x80)*mult; - sample->data8[k++]=fmin(fmax(next,-128),127); + if (ds.version>0x05) { + if (ds.version<0x0b) { + data=new short[1+(length/2)]; + reader.read(data,length); + length/=2; } else { - float next=(float)data[(unsigned int)j]*mult; - sample->data16[k++]=fmin(fmax(next,-32768),32767); + data=new short[length]; + reader.read(data,length*2); } - } - delete[] data; + if (pitch!=5) { + logD("%d: scaling from %d...",i,pitch); + } + + // render data + if (!sample->init((double)length/samplePitches[pitch])) { + logE("%d: error while initializing sample!",i); + } + + unsigned int k=0; + float mult=(float)(vol)/50.0f; + for (double j=0; j=sample->samples) { + break; + } + if (sample->depth==8) { + float next=(float)(data[(unsigned int)j]-0x80)*mult; + sample->data8[k++]=fmin(fmax(next,-128),127); + } else { + float next=(float)data[(unsigned int)j]*mult; + sample->data16[k++]=fmin(fmax(next,-32768),32767); + } + } + + delete[] data; + } else { + // ADPCM? + // it appears to be a slightly modified version of ADPCM-B! + adpcmData=new unsigned char[length]; + logV("%x",reader.tell()); + reader.read(adpcmData,length); + for (int i=0; i>4); + } + if (!sample->init(length*2)) { + logE("%d: error while initializing sample!",i); + } + + memcpy(sample->dataB,adpcmData,length); + delete[] adpcmData; + } } ds.sample.push_back(sample); }