From 08e23a68cd22b533c4905eff16bde18ae7c056fd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 26 Sep 2022 04:07:51 -0500 Subject: [PATCH 01/23] SNES: get some of echo working --- src/engine/platform/snes.cpp | 103 +++++++++++++++++++++++++++++++---- src/engine/platform/snes.h | 6 ++ 2 files changed, 97 insertions(+), 12 deletions(-) diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index d8dcd374f..1a9dc9de7 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -83,7 +83,7 @@ void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len bufL[h]=out[0]; bufR[h]=out[1]; for (int i=0; i<8; i++) { - int next=chOut[i*2]+chOut[i*2+1]; + int next=(3*(chOut[i*2]+chOut[i*2+1]))>>2; if (next<-32768) next=-32768; if (next>32767) next=32767; next=(next*254)/MAX(1,globalVolL+globalVolR); @@ -228,7 +228,7 @@ void DivPlatformSNES::tick(bool sysTick) { } } if (writeControl) { - unsigned char control=noiseFreq&0x1f; + unsigned char control=(noiseFreq&0x1f)|(echoOn?0:0x20); rWrite(0x6c,control); writeControl=false; } @@ -305,8 +305,7 @@ int DivPlatformSNES::dispatch(DivCommand c) { } if (chan[c.chan].insChanged) { chan[c.chan].state=ins->snes; - } - if (chan[c.chan].state.useEnv) { + if (chan[c.chan].state.useEnv) { chWrite(c.chan,5,chan[c.chan].state.a|(chan[c.chan].state.d<<4)|0x80); chWrite(c.chan,6,chan[c.chan].state.r|(chan[c.chan].state.s<<5)); } else { @@ -329,6 +328,7 @@ int DivPlatformSNES::dispatch(DivCommand c) { break; } } + } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value)); chan[c.chan].freqChanged=true; @@ -413,7 +413,47 @@ int DivPlatformSNES::dispatch(DivCommand c) { chan[c.chan].audPos=c.value; chan[c.chan].setPos=true; break; - // TODO SNES-specific commands + case DIV_CMD_SNES_ECHO: + chan[c.chan].echo=c.value; + writeEcho=true; + break; + case DIV_CMD_SNES_ECHO_DELAY: { + echoDelay=c.value&15; + unsigned char esa=0xf8-(echoDelay<<3); + if (echoOn) { + rWrite(0x6d,esa); + rWrite(0x7d,echoDelay); + } + break; + } + case DIV_CMD_SNES_ECHO_ENABLE: + echoOn=c.value; + initEcho(); + break; + case DIV_CMD_SNES_ECHO_FEEDBACK: + echoFeedback=c.value; + if (echoOn) { + rWrite(0x0d,echoFeedback); + } + break; + case DIV_CMD_SNES_ECHO_FIR: + echoFIR[c.value&7]=c.value2; + if (echoOn) { + rWrite(0x0f+((c.value&7)<<4),echoFIR[c.value&7]); + } + break; + case DIV_CMD_SNES_ECHO_VOL_LEFT: + echoVolL=c.value; + if (echoOn) { + rWrite(0x2c,echoVolL); + } + break; + case DIV_CMD_SNES_ECHO_VOL_RIGHT: + echoVolR=c.value; + if (echoOn) { + rWrite(0x3c,echoVolR); + } + break; case DIV_CMD_GET_VOLMAX: return 127; break; @@ -469,6 +509,7 @@ void DivPlatformSNES::forceIns() { writeNoise=true; writePitchMod=true; writeEcho=true; + initEcho(); } void* DivPlatformSNES::getChanState(int ch) { @@ -497,7 +538,28 @@ int DivPlatformSNES::getRegisterPoolSize() { return 128; } +void DivPlatformSNES::initEcho() { + unsigned char esa=0xf8-(echoDelay<<3); + if (echoOn) { + rWrite(0x6d,esa); + rWrite(0x7d,echoDelay); + rWrite(0x0d,echoFeedback); + rWrite(0x2c,echoVolL); + rWrite(0x3c,echoVolR); + for (int i=0; i<8; i++) { + rWrite(0x0f+(i<<4),echoFIR[i]); + } + } else { + rWrite(0x6d,0); + rWrite(0x7d,0); + rWrite(0x2c,0); + rWrite(0x3c,0); + } + writeControl=true; +} + void DivPlatformSNES::reset() { + memcpy(sampleMem,copyOfSampleMem,65536); dsp.init(sampleMem); dsp.set_output(NULL,0); memset(regPool,0,128); @@ -521,6 +583,22 @@ void DivPlatformSNES::reset() { writeNoise=false; writePitchMod=false; writeEcho=false; + + echoDelay=0; + echoFeedback=0; + echoFIR[0]=127; + echoFIR[1]=0; + echoFIR[2]=0; + echoFIR[3]=0; + echoFIR[4]=0; + echoFIR[5]=0; + echoFIR[6]=0; + echoFIR[7]=0; + echoVolL=127; + echoVolR=127; + echoOn=false; + + initEcho(); } bool DivPlatformSNES::isStereo() { @@ -574,7 +652,7 @@ size_t DivPlatformSNES::getSampleMemUsage(int index) { } void DivPlatformSNES::renderSamples() { - memset(sampleMem,0,getSampleMemCapacity()); + memset(copyOfSampleMem,0,getSampleMemCapacity()); memset(sampleOff,0,256*sizeof(unsigned int)); // skip past sample table and wavetable buffer @@ -585,12 +663,12 @@ void DivPlatformSNES::renderSamples() { int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length); if (actualLength>0) { sampleOff[i]=memPos; - memcpy(&sampleMem[memPos],s->dataBRR,actualLength); + memcpy(©OfSampleMem[memPos],s->dataBRR,actualLength); memPos+=actualLength; } if (actualLengthrate=rate; + isMuted[i]=false; + } setFlags(flags); reset(); return 8; diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h index 4d05df83b..4a91f543e 100644 --- a/src/engine/platform/snes.h +++ b/src/engine/platform/snes.h @@ -77,11 +77,15 @@ class DivPlatformSNES: public DivDispatch { bool isMuted[8]; int globalVolL, globalVolR; unsigned char noiseFreq; + signed char echoVolL, echoVolR, echoFeedback; + signed char echoFIR[8]; + unsigned char echoDelay; size_t sampleTableBase; bool writeControl; bool writeNoise; bool writePitchMod; bool writeEcho; + bool echoOn; struct QueuedWrite { unsigned char addr; @@ -91,6 +95,7 @@ class DivPlatformSNES: public DivDispatch { std::queue writes; signed char sampleMem[65536]; + signed char copyOfSampleMem[65536]; size_t sampleMemLen; unsigned int sampleOff[256]; unsigned char regPool[0x80]; @@ -126,6 +131,7 @@ class DivPlatformSNES: public DivDispatch { private: void updateWave(int ch); void writeOutVol(int ch); + void initEcho(); }; #endif From 9cf9a9c14d6e8a3d03143db23d3bfe193691b696 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 26 Sep 2022 11:59:44 -0500 Subject: [PATCH 02/23] it happened fixes #691 --- src/engine/sysDef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 02f91a00d..9d2aa6633 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1185,7 +1185,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_SFX_BEEPER]=new DivSysDef( - "ZX Spectrum Beeper", NULL, 0x9f, 0, 6, false, true, 0, false, 1U< Date: Tue, 27 Sep 2022 03:44:16 -0500 Subject: [PATCH 03/23] update brrUtils --- src/engine/brrUtils.c | 330 +++++++++++++++++++++++++++++++++++------- 1 file changed, 281 insertions(+), 49 deletions(-) diff --git a/src/engine/brrUtils.c b/src/engine/brrUtils.c index e44635712..8c1a3cc9b 100644 --- a/src/engine/brrUtils.c +++ b/src/engine/brrUtils.c @@ -21,6 +21,39 @@ */ #include "brrUtils.h" +#include + +#define DO_ONE_DEC(r) \ + if (nextDec&8) nextDec|=0xfffffff0; \ +\ + if (r>=13) { /* invalid shift */ \ + nextDec=(nextDec<0)?0xfffff800:0; \ + } else { \ + nextDec<<=r; /* range */ \ + nextDec>>=1; \ + } \ +\ + switch (filter) { /* filter */ \ + case 0: \ + break; \ + case 1: \ + nextDec+=last1+((-last1)>>4); \ + break; \ + case 2: \ + nextDec+=last1*2+((-last1*3)>>5)-last2+(last2>>4); \ + break; \ + case 3: \ + nextDec+=last1*2+((-last1*13)>>6)-last2+((last2*3)>>4); \ + break; \ + } \ +\ + if (nextDec>32767) nextDec=32767; \ + if (nextDec<-32768) nextDec=-32768; \ + nextDec&=0x7fff; \ + if (nextDec&0x4000) nextDec|=0xffff8000; \ +\ + last2=last1; \ + last1=nextDec; \ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { if (len==0) return 0; @@ -28,72 +61,274 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { // encoding process: // 1. read next group of 16 samples // 2. is this the first block? - // - if yes, don't filter. output and then go to 1 + // - if yes, don't filter. output and then go to 1 // 3. is this the loop block? - // - if yes, don't filter. output and then go to 1 + // - if yes, don't filter. output and then go to 1 // 4. try encoding using 4 filters + // - perform linear prediction + // - calculate range + // - decode and apply correction to achieve low error // 5. which one of these yields the least amount of error? // 6. output the one which does // 7. is this the last block? - // - if yes, mark end and finish + // - if yes, mark end and finish // 8. go to 1 long total=0; - unsigned char next[9]; + unsigned char next0[8]; + unsigned char next1[8]; + unsigned char next2[8]; + unsigned char next3[8]; unsigned char filter=0; - unsigned char range=0; + unsigned char range0=0; + unsigned char range1=0; + unsigned char range2=0; + unsigned char range3=0; unsigned char o=0; + int pred1[16]; + int pred2[16]; + int pred3[16]; + short o1=0; + short o2=0; short o0=0; + int last1=0; + int last2=0; + int nextDec=0; + int maxError[4]; + int avgError[4]; + len&=~15; loopStart&=~15; for (long i=0; i>13); if (s<0) s=-s; - while (range<12 && s>((8<((8<=len)?((loopStart>=0)?3:1):0); - switch (filter) { - case 0: - for (int j=0; j<16; j++) { - short s=buf[j]-(buf[j]>>13); - o0=s>>range; - if (o0>7) o0=7; - if (o0<-8) o0=-8; - if (range>=12) if (o0<-7) o0=-7; - o=o0&15; - if (j&1) { - next[1+(j>>1)]|=o; - } else { - next[1+(j>>1)]=o<<4; - } - } - break; - case 1: - break; - case 2: - break; - case 3: - break; + for (int j=0; j<16; j++) { + short s=buf[j]-(buf[j]>>13); + o0=s>>range0; + if (range0) if (s&(1<<(range1>>1))) o0++; + if (o0>7) o0=7; + if (o0<-8) o0=-8; + if (range0>=12) if (o0<-7) o0=-7; + o=o0&15; + if (j&1) { + next0[j>>1]|=o; + } else { + next0[j>>1]=o<<4; + } } - out[0]=next[0]; - out[1]=next[1]; - out[2]=next[2]; - out[3]=next[3]; - out[4]=next[4]; - out[5]=next[5]; - out[6]=next[6]; - out[7]=next[7]; - out[8]=next[8]; + // encode with filter + if (i && i!=loopStart) { + // 1: x = o0 - o1 * 15/16 + // 2: x = o0 + o2 * 15/16 - o1 * 61/32 + // 3: x = o0 + o2 * 13/16 - o1 * 115/64 + range1=0; + range2=0; + range3=0; + for (int j=0; j<16; j++) { + int s=buf[j]-(buf[j]>>13); + + pred1[j]=s-(((int)o1*15)>>4); + if (pred1[j]<-32768) pred1[j]=-32768; + if (pred1[j]>32767) pred1[j]=32767; + + pred2[j]=s+(((int)o2*15)>>4)-(((int)o1*61)>>5); + if (pred2[j]<-32768) pred2[j]=-32768; + if (pred2[j]>32767) pred2[j]=32767; + + pred3[j]=s+(((int)o2*13)>>4)-(((int)o1*115)>>6); + if (pred3[j]<-32768) pred3[j]=-32768; + if (pred3[j]>32767) pred3[j]=32767; + + o2=o1; + o1=s; + } + for (int j=0; j<16; j++) { + short s=pred1[j]; + if (s<0) s=-s; + while (range1<10 && s>((8<((8<((8<>range1; + if (range1) if (s&(1<<(range1>>1))) o0++; + if (o0>7) o0=7; + if (o0<-8) o0=-8; + if (range1>=12) if (o0<-7) o0=-7; + o=o0&15; + if (j&1) { + next1[j>>1]|=o; + } else { + next1[j>>1]=o<<4; + } + + s=pred2[j]; + o0=s>>range2; + if (o0>7) o0=7; + if (o0<-8) o0=-8; + if (range2>=12) if (o0<-7) o0=-7; + o=o0&15; + if (j&1) { + next2[j>>1]|=o; + } else { + next2[j>>1]=o<<4; + } + + s=pred3[j]; + o0=s>>range3; + if (o0>7) o0=7; + if (o0<-8) o0=-8; + if (range3>=12) if (o0<-7) o0=-7; + o=o0&15; + if (j&1) { + next3[j>>1]|=o; + } else { + next3[j>>1]=o<<4; + } + } + } + + if (i && i!=loopStart) { + // find best filter + int prevLast1=last1; + int prevLast2=last2; + int error=0; + + maxError[0]=0; + maxError[1]=0; + maxError[2]=0; + maxError[3]=0; + avgError[0]=0; + avgError[1]=0; + avgError[2]=0; + avgError[3]=0; + + // test filter 0 + filter=0; + for (int j=0; j<16; j++) { + int s=buf[j]-(buf[j]>>13); + if (j&1) { + nextDec=next0[j>>1]&15; + } else { + nextDec=next0[j>>1]>>4; + } + DO_ONE_DEC(range0); + error=s-(nextDec<<1); + if (error<0) error=-error; + avgError[0]+=error; + if (error>maxError[0]) maxError[0]=error; + } + avgError[0]>>=4; + last1=prevLast1; + last2=prevLast2; + + // test filter 1 + filter=1; + for (int j=0; j<16; j++) { + int s=buf[j]-(buf[j]>>13); + if (j&1) { + nextDec=next1[j>>1]&15; + } else { + nextDec=next1[j>>1]>>4; + } + DO_ONE_DEC(range1); + error=s-(nextDec<<1); + if (error<0) error=-error; + avgError[1]+=error; + if (error>maxError[1]) maxError[1]=error; + //printf("%6d | %6d => %6d\n",s,nextDec<<1,error); + } + avgError[1]>>=4; + last1=prevLast1; + last2=prevLast2; + + // pick best filter + int candError=0x7fffffff; + for (int j=0; j<2; j++) { + if (avgError[j] %d\n",i>>4,avgError[0],avgError[1],filter); + } else { + // don't filter on the first or loop block + filter=0; + } + + switch (filter) { + case 0: + nextDec=next0[7]>>4; + DO_ONE_DEC(range0); + o2=nextDec<<1; + + nextDec=next0[7]&15; + DO_ONE_DEC(range0); + o1=nextDec<<1; + + out[0]=(range0<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0); + out[1]=next0[0]; + out[2]=next0[1]; + out[3]=next0[2]; + out[4]=next0[3]; + out[5]=next0[4]; + out[6]=next0[5]; + out[7]=next0[6]; + out[8]=next0[7]; + break; + case 1: + for (int j=0; j<8; j++) { + nextDec=next1[j]>>4; + DO_ONE_DEC(range1); + nextDec=next1[j]&15; + DO_ONE_DEC(range1); + } + out[0]=(range1<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0); + out[1]=next1[0]; + out[2]=next1[1]; + out[3]=next1[2]; + out[4]=next1[3]; + out[5]=next1[4]; + out[6]=next1[5]; + out[7]=next1[6]; + out[8]=next1[7]; + break; + case 2: + out[0]=(range2<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0); + out[1]=next2[0]; + out[2]=next2[1]; + out[3]=next2[2]; + out[4]=next2[3]; + out[5]=next2[4]; + out[6]=next2[5]; + out[7]=next2[6]; + out[8]=next2[7]; + break; + case 3: + out[0]=(range3<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0); + out[1]=next3[0]; + out[2]=next3[1]; + out[3]=next3[2]; + out[4]=next3[3]; + out[5]=next3[4]; + out[6]=next3[5]; + out[7]=next3[6]; + out[8]=next3[7]; + break; + } buf+=16; out+=9; total+=9; @@ -135,9 +370,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { *out=next<<1; \ out++; -// TODO: -// - what happens during overflow? -// - what happens when range values 12 to 15 are used? long brrDecode(unsigned char* buf, short* out, long len) { if (len==0) return 0; From 43ed6c78784714ec5bd0a761ab3b716550b66bb0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 27 Sep 2022 03:57:35 -0500 Subject: [PATCH 04/23] SNES: advanced arp macros and volume fix --- src/engine/platform/snes.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index 1a9dc9de7..320d06f2e 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -106,18 +106,9 @@ void DivPlatformSNES::tick(bool sysTick) { } if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val)); } chan[i].freqChanged=true; - } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); - chan[i].freqChanged=true; - } } if (chan[i].std.duty.had) { noiseFreq=chan[i].std.duty.val; @@ -359,7 +350,10 @@ int DivPlatformSNES::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - writeOutVol(c.chan); + if (!chan[c.chan].std.vol.has) { + chan[c.chan].outVol=c.value; + writeOutVol(c.chan); + } } break; case DIV_CMD_GET_VOLUME: From 9517b8ee14b58e8850890d27c174ba7d996f0b57 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 01:15:50 -0500 Subject: [PATCH 05/23] fc --- src/gui/gui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index edc89ac14..4c7850adf 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1396,9 +1396,9 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { if (!dirExists(workingDirSong)) workingDirSong=getHomeDir(); hasOpened=fileDialog->openLoad( "Open File", - {"compatible files", "*.fur *.dmf *.mod *.fc13 *.fc14 *.smod", + {"compatible files", "*.fur *.dmf *.mod *.fc13 *.fc14 *.smod *.fc", "all files", ".*"}, - "compatible files{.fur,.dmf,.mod,.fc13,.fc14,.smod},.*", + "compatible files{.fur,.dmf,.mod,.fc13,.fc14,.smod,.fc},.*", workingDirSong, dpiScale ); From 828bac32bd7e513049d946dbf68ef5d8f95a2a90 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 01:44:58 -0500 Subject: [PATCH 06/23] update brrUtils --- src/engine/brrUtils.c | 81 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/src/engine/brrUtils.c b/src/engine/brrUtils.c index 8c1a3cc9b..ef50c9dce 100644 --- a/src/engine/brrUtils.c +++ b/src/engine/brrUtils.c @@ -23,6 +23,8 @@ #include "brrUtils.h" #include +#define NEXT_SAMPLE buf[j]-(buf[j]>>3) + #define DO_ONE_DEC(r) \ if (nextDec&8) nextDec|=0xfffffff0; \ \ @@ -103,12 +105,12 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { range0=0; // encode with no filter for (int j=0; j<16; j++) { - short s=buf[j]-(buf[j]>>13); + short s=NEXT_SAMPLE; if (s<0) s=-s; while (range0<12 && s>((8<>13); + short s=NEXT_SAMPLE; o0=s>>range0; if (range0) if (s&(1<<(range1>>1))) o0++; if (o0>7) o0=7; @@ -131,7 +133,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { range2=0; range3=0; for (int j=0; j<16; j++) { - int s=buf[j]-(buf[j]>>13); + int s=NEXT_SAMPLE; pred1[j]=s-(((int)o1*15)>>4); if (pred1[j]<-32768) pred1[j]=-32768; @@ -167,7 +169,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { if (range1) if (s&(1<<(range1>>1))) o0++; if (o0>7) o0=7; if (o0<-8) o0=-8; - if (range1>=12) if (o0<-7) o0=-7; + if (range1>=10) if (o0<-7) o0=-7; o=o0&15; if (j&1) { next1[j>>1]|=o; @@ -177,9 +179,10 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { s=pred2[j]; o0=s>>range2; + if (range2) if (s&(1<<(range2>>1))) o0++; if (o0>7) o0=7; if (o0<-8) o0=-8; - if (range2>=12) if (o0<-7) o0=-7; + if (range2>=7) if (o0<-7) o0=-7; o=o0&15; if (j&1) { next2[j>>1]|=o; @@ -189,9 +192,10 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { s=pred3[j]; o0=s>>range3; + if (range3) if (s&(1<<(range3>>1))) o0++; if (o0>7) o0=7; if (o0<-8) o0=-8; - if (range3>=12) if (o0<-7) o0=-7; + if (range3>=7) if (o0<-7) o0=-7; o=o0&15; if (j&1) { next3[j>>1]|=o; @@ -219,7 +223,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { // test filter 0 filter=0; for (int j=0; j<16; j++) { - int s=buf[j]-(buf[j]>>13); + int s=NEXT_SAMPLE; if (j&1) { nextDec=next0[j>>1]&15; } else { @@ -238,7 +242,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { // test filter 1 filter=1; for (int j=0; j<16; j++) { - int s=buf[j]-(buf[j]>>13); + int s=NEXT_SAMPLE; if (j&1) { nextDec=next1[j>>1]&15; } else { @@ -255,9 +259,50 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { last1=prevLast1; last2=prevLast2; + // test filter 2 + filter=2; + for (int j=0; j<16; j++) { + int s=NEXT_SAMPLE; + if (j&1) { + nextDec=next2[j>>1]&15; + } else { + nextDec=next2[j>>1]>>4; + } + DO_ONE_DEC(range2); + error=s-(nextDec<<1); + if (error<0) error=-error; + avgError[2]+=error; + if (error>maxError[2]) maxError[2]=error; + //printf("%6d | %6d => %6d\n",s,nextDec<<1,error); + } + avgError[2]>>=4; + last1=prevLast1; + last2=prevLast2; + + // test filter 3 + filter=3; + for (int j=0; j<16; j++) { + int s=NEXT_SAMPLE; + if (j&1) { + nextDec=next3[j>>1]&15; + } else { + nextDec=next3[j>>1]>>4; + } + DO_ONE_DEC(range3); + error=s-(nextDec<<1); + if (error<0) error=-error; + avgError[3]+=error; + if (error>maxError[3]) maxError[3]=error; + //printf("%6d | %6d => %6d\n",s,nextDec<<1,error); + } + avgError[3]>>=4; + last1=prevLast1; + last2=prevLast2; + // pick best filter int candError=0x7fffffff; - for (int j=0; j<2; j++) { + //avgError[0]+=1000; + for (int j=0; j<4; j++) { if (avgError[j]=len)?((loopStart>=0)?3:1):0); out[1]=next1[0]; out[2]=next1[1]; @@ -307,6 +354,14 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { out[8]=next1[7]; break; case 2: + for (int j=0; j<8; j++) { + nextDec=next2[j]>>4; + DO_ONE_DEC(range2); + nextDec=next2[j]&15; + DO_ONE_DEC(range2); + } + o2=last2<<1; + o1=last1<<1; out[0]=(range2<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0); out[1]=next2[0]; out[2]=next2[1]; @@ -318,6 +373,14 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { out[8]=next2[7]; break; case 3: + for (int j=0; j<8; j++) { + nextDec=next3[j]>>4; + DO_ONE_DEC(range3); + nextDec=next3[j]&15; + DO_ONE_DEC(range3); + } + o2=last2<<1; + o1=last1<<1; out[0]=(range3<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0); out[1]=next3[0]; out[2]=next3[1]; From 8cc15b398d4eba817f2ad0302a213c0e58e795fa Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 04:16:07 -0500 Subject: [PATCH 07/23] what's going on here why is this not working --- src/engine/brrUtils.c | 86 +++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/src/engine/brrUtils.c b/src/engine/brrUtils.c index ef50c9dce..4718b46f7 100644 --- a/src/engine/brrUtils.c +++ b/src/engine/brrUtils.c @@ -92,6 +92,12 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { short o1=0; short o2=0; short o0=0; + short o1f1=0; + short o1f2=0; + short o1f3=0; + short o2f1=0; + short o2f2=0; + short o2f3=0; int last1=0; int last2=0; @@ -132,6 +138,13 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { range1=0; range2=0; range3=0; + o2f1=o2; + o2f2=o2; + o2f3=o2; + o1f1=o1; + o1f2=o1; + o1f3=o1; + // first pass for (int j=0; j<16; j++) { int s=NEXT_SAMPLE; @@ -150,26 +163,34 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { o2=o1; o1=s; } + // calculate range of values for (int j=0; j<16; j++) { short s=pred1[j]; if (s<0) s=-s; - while (range1<10 && s>((8<((8<((8<((8<((8<((8<>range1; - if (range1) if (s&(1<<(range1>>1))) o0++; + int s=NEXT_SAMPLE; + + pred1[j]=s-(((int)o1f1*15)>>4); + if (pred1[j]<-32768) pred1[j]=-32768; + if (pred1[j]>32767) pred1[j]=32767; + + o0=pred1[j]>>range1; + if (range1) if (pred1[j]&(1<<(range1>>1))) o0++; if (o0>7) o0=7; if (o0<-8) o0=-8; - if (range1>=10) if (o0<-7) o0=-7; o=o0&15; if (j&1) { next1[j>>1]|=o; @@ -177,12 +198,23 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { next1[j>>1]=o<<4; } - s=pred2[j]; - o0=s>>range2; - if (range2) if (s&(1<<(range2>>1))) o0++; + nextDec=o; + DO_ONE_DEC(range1); + o2f1=last2<<1; + o1f1=last1<<1; + } + last1=prevLast1; + last2=prevLast2; + for (int j=0; j<16; j++) { + int s=NEXT_SAMPLE; + pred2[j]=s+(((int)o2f2*15)>>4)-(((int)o1f2*61)>>5); + if (pred2[j]<-32768) pred2[j]=-32768; + if (pred2[j]>32767) pred2[j]=32767; + + o0=pred2[j]>>range2; + if (range2) if (pred2[j]&(1<<(range2>>1))) o0++; if (o0>7) o0=7; if (o0<-8) o0=-8; - if (range2>=7) if (o0<-7) o0=-7; o=o0&15; if (j&1) { next2[j>>1]|=o; @@ -190,19 +222,37 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { next2[j>>1]=o<<4; } - s=pred3[j]; - o0=s>>range3; - if (range3) if (s&(1<<(range3>>1))) o0++; + nextDec=o; + DO_ONE_DEC(range2); + o2f2=last2<<1; + o1f2=last1<<1; + } + last1=prevLast1; + last2=prevLast2; + for (int j=0; j<16; j++) { + int s=NEXT_SAMPLE; + pred3[j]=s+(((int)o2f3*13)>>4)-(((int)o1f3*115)>>6); + if (pred3[j]<-32768) pred3[j]=-32768; + if (pred3[j]>32767) pred3[j]=32767; + + o0=pred3[j]>>range3; + if (range3) if (pred3[j]&(1<<(range3>>1))) o0++; if (o0>7) o0=7; if (o0<-8) o0=-8; - if (range3>=7) if (o0<-7) o0=-7; o=o0&15; if (j&1) { next3[j>>1]|=o; } else { next3[j>>1]=o<<4; } + + nextDec=o; + DO_ONE_DEC(range3); + o2f3=last2<<1; + o1f3=last1<<1; } + last1=prevLast1; + last2=prevLast2; } if (i && i!=loopStart) { @@ -235,7 +285,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { avgError[0]+=error; if (error>maxError[0]) maxError[0]=error; } - avgError[0]>>=4; last1=prevLast1; last2=prevLast2; @@ -255,7 +304,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { if (error>maxError[1]) maxError[1]=error; //printf("%6d | %6d => %6d\n",s,nextDec<<1,error); } - avgError[1]>>=4; last1=prevLast1; last2=prevLast2; @@ -275,7 +323,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { if (error>maxError[2]) maxError[2]=error; //printf("%6d | %6d => %6d\n",s,nextDec<<1,error); } - avgError[2]>>=4; last1=prevLast1; last2=prevLast2; @@ -295,7 +342,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { if (error>maxError[3]) maxError[3]=error; //printf("%6d | %6d => %6d\n",s,nextDec<<1,error); } - avgError[3]>>=4; last1=prevLast1; last2=prevLast2; @@ -308,7 +354,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { filter=j; } } - //printf("block %ld: %8d %8d -> %d\n",i>>4,avgError[0],avgError[1],filter); + printf("block %ld: %8d %8d %8d %8d -> %d\n",i>>4,avgError[0],avgError[1],avgError[2],avgError[3],filter); } else { // don't filter on the first or loop block filter=0; From c6173311f78a1c19aa59c660e1e400044221d545 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 04:49:02 -0500 Subject: [PATCH 08/23] update brrUtils --- src/engine/brrUtils.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/engine/brrUtils.c b/src/engine/brrUtils.c index 4718b46f7..fb31e036c 100644 --- a/src/engine/brrUtils.c +++ b/src/engine/brrUtils.c @@ -95,7 +95,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { short o1f1=0; short o1f2=0; short o1f3=0; - short o2f1=0; + //short o2f1=0; short o2f2=0; short o2f3=0; @@ -138,7 +138,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { range1=0; range2=0; range3=0; - o2f1=o2; + //o2f1=o2; o2f2=o2; o2f3=o2; o1f1=o1; @@ -180,6 +180,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { // second pass int prevLast1=last1; int prevLast2=last2; + filter=1; for (int j=0; j<16; j++) { int s=NEXT_SAMPLE; @@ -200,11 +201,12 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { nextDec=o; DO_ONE_DEC(range1); - o2f1=last2<<1; + //o2f1=last2<<1; o1f1=last1<<1; } last1=prevLast1; last2=prevLast2; + filter=2; for (int j=0; j<16; j++) { int s=NEXT_SAMPLE; pred2[j]=s+(((int)o2f2*15)>>4)-(((int)o1f2*61)>>5); @@ -229,6 +231,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { } last1=prevLast1; last2=prevLast2; + filter=3; for (int j=0; j<16; j++) { int s=NEXT_SAMPLE; pred3[j]=s+(((int)o2f3*13)>>4)-(((int)o1f3*115)>>6); @@ -253,12 +256,8 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { } last1=prevLast1; last2=prevLast2; - } - if (i && i!=loopStart) { // find best filter - int prevLast1=last1; - int prevLast2=last2; int error=0; maxError[0]=0; @@ -347,7 +346,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { // pick best filter int candError=0x7fffffff; - //avgError[0]+=1000; for (int j=0; j<4; j++) { if (avgError[j]>4; - DO_ONE_DEC(range0); - o2=nextDec<<1; - - nextDec=next0[7]&15; - DO_ONE_DEC(range0); - o1=nextDec<<1; + for (int j=0; j<8; j++) { + nextDec=next0[j]>>4; + DO_ONE_DEC(range0); + nextDec=next0[j]&15; + DO_ONE_DEC(range0); + } + o2=last2<<1; + o1=last1<<1; out[0]=(range0<<4)|(filter<<2)|((i+16>=len)?((loopStart>=0)?3:1):0); out[1]=next0[0]; From 994f67b7e7b831947ee9736f68f4fff38a034561 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 04:55:18 -0500 Subject: [PATCH 09/23] update brrUtils once again --- src/engine/brrUtils.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/engine/brrUtils.c b/src/engine/brrUtils.c index fb31e036c..f5fce33b1 100644 --- a/src/engine/brrUtils.c +++ b/src/engine/brrUtils.c @@ -21,7 +21,6 @@ */ #include "brrUtils.h" -#include #define NEXT_SAMPLE buf[j]-(buf[j]>>3) @@ -301,7 +300,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { if (error<0) error=-error; avgError[1]+=error; if (error>maxError[1]) maxError[1]=error; - //printf("%6d | %6d => %6d\n",s,nextDec<<1,error); } last1=prevLast1; last2=prevLast2; @@ -320,7 +318,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { if (error<0) error=-error; avgError[2]+=error; if (error>maxError[2]) maxError[2]=error; - //printf("%6d | %6d => %6d\n",s,nextDec<<1,error); } last1=prevLast1; last2=prevLast2; @@ -339,7 +336,6 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { if (error<0) error=-error; avgError[3]+=error; if (error>maxError[3]) maxError[3]=error; - //printf("%6d | %6d => %6d\n",s,nextDec<<1,error); } last1=prevLast1; last2=prevLast2; @@ -352,7 +348,7 @@ long brrEncode(short* buf, unsigned char* out, long len, long loopStart) { filter=j; } } - printf("block %ld: %8d %8d %8d %8d -> %d\n",i>>4,avgError[0],avgError[1],avgError[2],avgError[3],filter); + //printf("block %ld: %8d %8d %8d %8d -> %d\n",i>>4,avgError[0],avgError[1],avgError[2],avgError[3],filter); } else { // don't filter on the first or loop block filter=0; From 7e07f616d57d0a2df3d4253f64fb3b811248a2bf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 16:42:46 -0500 Subject: [PATCH 10/23] SNES: fix samples not updating on change --- src/engine/platform/snes.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index 320d06f2e..6d448abef 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -668,6 +668,7 @@ void DivPlatformSNES::renderSamples() { } } sampleMemLen=memPos; + memcpy(sampleMem,copyOfSampleMem,65536); } void DivPlatformSNES::setFlags(unsigned int flags) { From 3329e98c51ceaaa5306a9f8439f800f7046ef490 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 17:05:48 -0500 Subject: [PATCH 11/23] new MSM5232 chip ID --- papers/format.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/papers/format.md b/papers/format.md index 1d4e7fc76..bb0085f55 100644 --- a/papers/format.md +++ b/papers/format.md @@ -248,7 +248,7 @@ size | description | - 0xb9: Namco WSG - 3 channels | - 0xba: Namco 15xx - 8 channels | - 0xbb: Namco CUS30 - 8 channels - | - 0xbc: reserved - 8 channels + | - 0xbc: MSM5232 - 8 channels | - 0xbd: YM2612 extra features extended - 11 channels | - 0xbe: YM2612 extra features - 7 channels | - 0xbf: T6W28 - 4 channels @@ -258,7 +258,6 @@ size | description | - 0xc3: OPN CSM - 10 channels | - 0xc4: PC-98 CSM - 20 channels | - 0xc5: YM2610B CSM - 20 channels - | - 0xc6: MSM5232 - 8 channels | - 0xde: YM2610B extended - 19 channels | - 0xe0: QSound - 19 channels | - 0xfd: Dummy System - 8 channels From 6f1a41de1e491361a06d1267f7d849fd7700d9f0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 18:28:01 -0500 Subject: [PATCH 12/23] SNES: implement more effects --- src/engine/platform/snes.cpp | 122 ++++++++++++++++++++++++++++------- src/engine/platform/snes.h | 1 + src/engine/sysDef.cpp | 28 ++++---- 3 files changed, 115 insertions(+), 36 deletions(-) diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index 6d448abef..0454ed357 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -296,29 +296,7 @@ int DivPlatformSNES::dispatch(DivCommand c) { } if (chan[c.chan].insChanged) { chan[c.chan].state=ins->snes; - if (chan[c.chan].state.useEnv) { - chWrite(c.chan,5,chan[c.chan].state.a|(chan[c.chan].state.d<<4)|0x80); - chWrite(c.chan,6,chan[c.chan].state.r|(chan[c.chan].state.s<<5)); - } else { - chWrite(c.chan,5,0); - switch (chan[c.chan].state.gainMode) { - case DivInstrumentSNES::GAIN_MODE_DIRECT: - chWrite(c.chan,7,chan[c.chan].state.gain&127); - break; - case DivInstrumentSNES::GAIN_MODE_DEC_LINEAR: - chWrite(c.chan,7,0x80|(chan[c.chan].state.gain&31)); - break; - case DivInstrumentSNES::GAIN_MODE_INC_LINEAR: - chWrite(c.chan,7,0xc0|(chan[c.chan].state.gain&31)); - break; - case DivInstrumentSNES::GAIN_MODE_DEC_LOG: - chWrite(c.chan,7,0xa0|(chan[c.chan].state.gain&31)); - break; - case DivInstrumentSNES::GAIN_MODE_INC_INVLOG: - chWrite(c.chan,7,0xe0|(chan[c.chan].state.gain&31)); - break; - } - } + writeEnv(c.chan); } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value)); @@ -368,6 +346,11 @@ int DivPlatformSNES::dispatch(DivCommand c) { chan[c.chan].pitch=c.value; chan[c.chan].freqChanged=true; break; + case DIV_CMD_WAVE: + if (!chan[c.chan].useWave) break; + chan[c.chan].wave=c.value; + chan[c.chan].ws.changeWave1(chan[c.chan].wave); + break; case DIV_CMD_NOTE_PORTA: { int destFreq=round(NOTE_FREQUENCY(c.value2)); bool return2=false; @@ -404,9 +387,76 @@ int DivPlatformSNES::dispatch(DivCommand c) { chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_POS: + // may have to remove this chan[c.chan].audPos=c.value; chan[c.chan].setPos=true; break; + case DIV_CMD_STD_NOISE_MODE: + chan[c.chan].noise=c.value; + writeNoise=true; + break; + case DIV_CMD_SNES_PITCH_MOD: + chan[c.chan].pitchMod=c.value; + writePitchMod=true; + break; + case DIV_CMD_SNES_INVERT: + chan[c.chan].invertL=(c.value>>4); + chan[c.chan].invertR=c.chan&15; + writeOutVol(c.chan); + break; + case DIV_CMD_SNES_GAIN_MODE: + if (c.value) { + chan[c.chan].state.useEnv=false; + switch (c.value) { + case 1: + chan[c.chan].state.gainMode=DivInstrumentSNES::GAIN_MODE_DIRECT; + break; + case 2: + chan[c.chan].state.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LINEAR; + break; + case 3: + chan[c.chan].state.gainMode=DivInstrumentSNES::GAIN_MODE_DEC_LOG; + break; + case 4: + chan[c.chan].state.gainMode=DivInstrumentSNES::GAIN_MODE_INC_LINEAR; + break; + case 5: + chan[c.chan].state.gainMode=DivInstrumentSNES::GAIN_MODE_INC_INVLOG; + break; + } + } else { + chan[c.chan].state.useEnv=true; + } + writeEnv(c.chan); + break; + case DIV_CMD_SNES_GAIN: + if (chan[c.chan].state.gainMode==DivInstrumentSNES::GAIN_MODE_DIRECT) { + chan[c.chan].state.gain=c.value&0x7f; + } else { + chan[c.chan].state.gain=c.value&0x1f; + } + if (!chan[c.chan].state.useEnv) writeEnv(c.chan); + break; + case DIV_CMD_STD_NOISE_FREQ: + noiseFreq=c.value&0x1f; + writeControl=true; + break; + case DIV_CMD_FM_AR: + chan[c.chan].state.a=c.value&15; + if (chan[c.chan].state.useEnv) writeEnv(c.chan); + break; + case DIV_CMD_FM_DR: + chan[c.chan].state.d=c.value&7; + if (chan[c.chan].state.useEnv) writeEnv(c.chan); + break; + case DIV_CMD_FM_SL: + chan[c.chan].state.s=c.value&7; + if (chan[c.chan].state.useEnv) writeEnv(c.chan); + break; + case DIV_CMD_FM_RR: + chan[c.chan].state.r=c.value&0x1f; + if (chan[c.chan].state.useEnv) writeEnv(c.chan); + break; case DIV_CMD_SNES_ECHO: chan[c.chan].echo=c.value; writeEcho=true; @@ -484,6 +534,32 @@ void DivPlatformSNES::writeOutVol(int ch) { chWrite(ch,1,outR); } +void DivPlatformSNES::writeEnv(int ch) { + if (chan[ch].state.useEnv) { + chWrite(ch,5,chan[ch].state.a|(chan[ch].state.d<<4)|0x80); + chWrite(ch,6,chan[ch].state.r|(chan[ch].state.s<<5)); + } else { + chWrite(ch,5,0); + switch (chan[ch].state.gainMode) { + case DivInstrumentSNES::GAIN_MODE_DIRECT: + chWrite(ch,7,chan[ch].state.gain&127); + break; + case DivInstrumentSNES::GAIN_MODE_DEC_LINEAR: + chWrite(ch,7,0x80|(chan[ch].state.gain&31)); + break; + case DivInstrumentSNES::GAIN_MODE_INC_LINEAR: + chWrite(ch,7,0xc0|(chan[ch].state.gain&31)); + break; + case DivInstrumentSNES::GAIN_MODE_DEC_LOG: + chWrite(ch,7,0xa0|(chan[ch].state.gain&31)); + break; + case DivInstrumentSNES::GAIN_MODE_INC_INVLOG: + chWrite(ch,7,0xe0|(chan[ch].state.gain&31)); + break; + } + } +} + void DivPlatformSNES::muteChannel(int ch, bool mute) { isMuted[ch]=mute; writeOutVol(ch); diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h index 4a91f543e..61ddb486b 100644 --- a/src/engine/platform/snes.h +++ b/src/engine/platform/snes.h @@ -131,6 +131,7 @@ class DivPlatformSNES: public DivDispatch { private: void updateWave(int ch); void writeOutVol(int ch); + void writeEnv(int ch); void initEcho(); }; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 9d2aa6633..9a10d26c0 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -867,23 +867,11 @@ void DivEngine::registerSystems() { {DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES, DIV_INS_SNES}, {}, { - {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, - {0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Toggle noise mode"}}, - {0x12, {DIV_CMD_SNES_ECHO, "12xx: Toggle echo on this channel"}}, - {0x13, {DIV_CMD_SNES_PITCH_MOD, "13xx: Toggle pitch modulation"}}, - {0x14, {DIV_CMD_SNES_INVERT, "14xy: Toggle invert (x: left; y: right)"}}, - {0x15, {DIV_CMD_SNES_GAIN_MODE, "15xx: Set gain mode"}}, - {0x16, {DIV_CMD_SNES_GAIN, "16xx: Set gain"}}, {0x18, {DIV_CMD_SNES_ECHO_ENABLE, "18xx: Enable echo buffer"}}, - {0x19, {DIV_CMD_SNES_ECHO_DELAY, "19xx: Set echo delay"}}, + {0x19, {DIV_CMD_SNES_ECHO_DELAY, "19xx: Set echo delay (0 to F)"}}, {0x1a, {DIV_CMD_SNES_ECHO_VOL_LEFT, "1Axx: Set left echo volume"}}, {0x1b, {DIV_CMD_SNES_ECHO_VOL_RIGHT, "1Bxx: Set right echo volume"}}, {0x1c, {DIV_CMD_SNES_ECHO_FEEDBACK, "1Cxx: Set echo feedback"}}, - {0x1d, {DIV_CMD_STD_NOISE_FREQ, "1Dxx: Set noise frequency"}}, - {0x20, {DIV_CMD_FM_AR, "20xx: Set attack"}}, - {0x21, {DIV_CMD_FM_DR, "21xx: Set decay"}}, - {0x22, {DIV_CMD_FM_SL, "22xx: Set sustain"}}, - {0x23, {DIV_CMD_FM_RR, "23xx: Set release"}}, {0x30, {DIV_CMD_SNES_ECHO_FIR, "30xx: Set echo filter coefficient 0",constVal<0>,effectVal}}, {0x31, {DIV_CMD_SNES_ECHO_FIR, "31xx: Set echo filter coefficient 1",constVal<1>,effectVal}}, {0x32, {DIV_CMD_SNES_ECHO_FIR, "32xx: Set echo filter coefficient 2",constVal<2>,effectVal}}, @@ -892,6 +880,20 @@ void DivEngine::registerSystems() { {0x35, {DIV_CMD_SNES_ECHO_FIR, "35xx: Set echo filter coefficient 5",constVal<5>,effectVal}}, {0x36, {DIV_CMD_SNES_ECHO_FIR, "36xx: Set echo filter coefficient 6",constVal<6>,effectVal}}, {0x37, {DIV_CMD_SNES_ECHO_FIR, "37xx: Set echo filter coefficient 7",constVal<7>,effectVal}}, + }, + { + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + {0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Toggle noise mode"}}, + {0x12, {DIV_CMD_SNES_ECHO, "12xx: Toggle echo on this channel"}}, + {0x13, {DIV_CMD_SNES_PITCH_MOD, "13xx: Toggle pitch modulation"}}, + {0x14, {DIV_CMD_SNES_INVERT, "14xy: Toggle invert (x: left; y: right)"}}, + {0x15, {DIV_CMD_SNES_GAIN_MODE, "15xx: Set envelope mode (0: ADSR, 1: gain/direct, 2: dec, 3: exp, 4: inc, 5: bent)"}}, + {0x16, {DIV_CMD_SNES_GAIN, "16xx: Set gain (00 to 7F if direct; 00 to 1F otherwise)"}}, + {0x1d, {DIV_CMD_STD_NOISE_FREQ, "1Dxx: Set noise frequency (00 to 1F)"}}, + {0x20, {DIV_CMD_FM_AR, "20xx: Set attack (0 to F)"}}, + {0x21, {DIV_CMD_FM_DR, "21xx: Set decay (0 to 7)"}}, + {0x22, {DIV_CMD_FM_SL, "22xx: Set sustain (0 to 7)"}}, + {0x23, {DIV_CMD_FM_RR, "23xx: Set release (00 to 1F)"}}, } ); From 6028523eafb5d4e9ae4e5e84029221095bf3a136 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 19:08:22 -0500 Subject: [PATCH 13/23] dev118 - SNES true sustain --- papers/format.md | 3 +++ src/engine/engine.h | 4 ++-- src/engine/instrument.cpp | 13 +++++++------ src/engine/instrument.h | 3 ++- src/engine/platform/snes.cpp | 30 +++++++++++++++++++++++++----- src/gui/insEdit.cpp | 1 + 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/papers/format.md b/papers/format.md index bb0085f55..6d463a893 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 118: Furnace dev118 +- 117: Furnace dev117 - 116: Furnace 0.6pre1.5 - 115: Furnace dev115 - 114: Furnace dev114 @@ -905,6 +907,7 @@ size | description 1 | attack 1 | decay 1 | sustain + | - bit 3: sustain mode (>=118) 1 | release --- | **macro speeds/delays** (>=111) 1 | volume macro speed diff --git a/src/engine/engine.h b/src/engine/engine.h index 2219b6e2c..19d86905a 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev117" -#define DIV_ENGINE_VERSION 117 +#define DIV_VERSION "dev118" +#define DIV_ENGINE_VERSION 118 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index e944fdbf3..a78bb8ffe 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -559,13 +559,12 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(es5506.envelope.k2Slow); // SNES - // @tildearrow please update this w->writeC(snes.useEnv); - w->writeC(0); - w->writeC(0); + w->writeC(snes.gainMode); + w->writeC(snes.gain); w->writeC(snes.a); w->writeC(snes.d); - w->writeC(snes.s); + w->writeC((snes.s&7)|(snes.sus?8:0)); w->writeC(snes.r); // macro speed/delay @@ -1259,11 +1258,13 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { // SNES if (version>=109) { snes.useEnv=reader.readC(); - reader.readC(); - reader.readC(); + snes.gainMode=(DivInstrumentSNES::GainMode)reader.readC(); + snes.gain=reader.readC(); snes.a=reader.readC(); snes.d=reader.readC(); snes.s=reader.readC(); + snes.sus=snes.s&8; + snes.s&=7; snes.r=reader.readC(); } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 01323d90f..a8283430e 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -527,12 +527,13 @@ struct DivInstrumentSNES { GAIN_MODE_INC_LINEAR=6, GAIN_MODE_INC_INVLOG=7 }; - bool useEnv; + bool useEnv, sus; GainMode gainMode; unsigned char gain; unsigned char a, d, s, r; DivInstrumentSNES(): useEnv(true), + sus(false), gainMode(GAIN_MODE_DIRECT), gain(127), a(15), diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index 0454ed357..5bd28b194 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -208,7 +208,9 @@ void DivPlatformSNES::tick(bool sysTick) { chan[i].keyOn=false; } if (chan[i].keyOff) { - koff|=(1<snes; + } + chan[c.chan].active=true; + if (chan[c.chan].insChanged || chan[c.chan].state.sus) { writeEnv(c.chan); } if (c.value!=DIV_NOTE_NULL) { @@ -303,19 +308,30 @@ int DivPlatformSNES::dispatch(DivCommand c) { chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; } - chan[c.chan].active=true; chan[c.chan].keyOn=true; chan[c.chan].macroInit(ins); chan[c.chan].insChanged=false; break; } case DIV_CMD_NOTE_OFF: - chan[c.chan].sample=-1; chan[c.chan].active=false; chan[c.chan].keyOff=true; - chan[c.chan].macroInit(NULL); + chan[c.chan].keyOn=false; + if (chan[c.chan].state.sus) { + writeEnv(c.chan); + } else { + chan[c.chan].macroInit(NULL); + } break; case DIV_CMD_NOTE_OFF_ENV: + chan[c.chan].active=false; + chan[c.chan].keyOff=true; + chan[c.chan].keyOn=false; + if (chan[c.chan].state.sus) { + writeEnv(c.chan); + } + chan[c.chan].std.release(); + break; case DIV_CMD_ENV_RELEASE: chan[c.chan].std.release(); break; @@ -537,7 +553,11 @@ void DivPlatformSNES::writeOutVol(int ch) { void DivPlatformSNES::writeEnv(int ch) { if (chan[ch].state.useEnv) { chWrite(ch,5,chan[ch].state.a|(chan[ch].state.d<<4)|0x80); - chWrite(ch,6,chan[ch].state.r|(chan[ch].state.s<<5)); + if (chan[ch].state.sus && chan[ch].active) { + chWrite(ch,6,chan[ch].state.s<<5); + } else { + chWrite(ch,6,chan[ch].state.r|(chan[ch].state.s<<5)); + } } else { chWrite(ch,5,0); switch (chan[ch].state.gainMode) { diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 15434a802..2ab022ddc 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4066,6 +4066,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTable(); } + ImGui::Checkbox("Make sustain effective",&ins->snes.sus); } else { if (ImGui::BeginTable("SNESGainParams",3,ImGuiTableFlags_NoHostExtendX)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); From 7770ca89659cd33d830485203d529e45519112a2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 19:33:16 -0500 Subject: [PATCH 14/23] SNES: more fixes (especially GUI ones) --- src/engine/platform/snes.cpp | 4 ++-- src/gui/debugWindow.cpp | 5 +++-- src/gui/gui.h | 2 +- src/gui/insEdit.cpp | 25 +++++++++++++++---------- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index 5bd28b194..e99db88a6 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -284,9 +284,9 @@ int DivPlatformSNES::dispatch(DivCommand c) { if (chan[c.chan].insChanged) { if (chan[c.chan].wave<0) { chan[c.chan].wave=0; - chan[c.chan].ws.setWidth(chan[c.chan].wtLen); - chan[c.chan].ws.changeWave1(chan[c.chan].wave); } + chan[c.chan].ws.setWidth(chan[c.chan].wtLen); + chan[c.chan].ws.changeWave1(chan[c.chan].wave); } chan[c.chan].ws.init(ins,chan[c.chan].wtLen,15,chan[c.chan].insChanged); } else { diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 2c507bb47..a8f750087 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -382,9 +382,9 @@ void FurnaceGUI::drawDebug() { } if (ImGui::TreeNode("ADSR Test Area")) { static int tl, ar, dr, d2r, sl, rr, sus, egt, algOrGlobalSus, instType; - static float maxArDr, maxTl; + static float maxArDr, maxTl, maxRr; ImGui::Text("This window was done out of frustration"); - drawFMEnv(tl,ar,dr,d2r,rr,sl,sus,egt,algOrGlobalSus,maxTl,maxArDr,ImVec2(200.0f*dpiScale,100.0f*dpiScale),instType); + drawFMEnv(tl,ar,dr,d2r,rr,sl,sus,egt,algOrGlobalSus,maxTl,maxArDr,maxRr,ImVec2(200.0f*dpiScale,100.0f*dpiScale),instType); ImGui::InputInt("tl",&tl); ImGui::InputInt("ar",&ar); @@ -398,6 +398,7 @@ void FurnaceGUI::drawDebug() { ImGui::InputInt("instType",&instType); ImGui::InputFloat("maxArDr",&maxArDr); ImGui::InputFloat("maxTl",&maxTl); + ImGui::InputFloat("maxRr",&maxRr); ImGui::TreePop(); } if (ImGui::TreeNode("User Interface")) { diff --git a/src/gui/gui.h b/src/gui/gui.h index 76a25efd4..c4b1005da 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1617,7 +1617,7 @@ class FurnaceGUI { void drawSSGEnv(unsigned char type, const ImVec2& size); void drawWaveform(unsigned char type, bool opz, const ImVec2& size); void drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size); - void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, const ImVec2& size, unsigned short instType); + void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, float maxRr, const ImVec2& size, unsigned short instType); void drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size); void drawSysConf(int chan, DivSystem type, unsigned int& flags, bool modifyOnChange); void kvsConfig(DivInstrument* ins); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 2ab022ddc..a8fbf48dc 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1070,7 +1070,7 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons } } -void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, const ImVec2& size, unsigned short instType) { +void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, float maxRr, const ImVec2& size, unsigned short instType) { ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); @@ -1096,7 +1096,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, float arPos=float(maxArDr-ar)/maxArDr; //peak of AR, start of DR float drPos=arPos+((sl/15.0)*(float(maxArDr-dr)/maxArDr)); //end of DR, start of D2R float d2rPos=drPos+(((15.0-sl)/15.0)*(float(31.0-d2r)/31.0)); //End of D2R - float rrPos=(float(15-rr)/15.0); //end of RR + float rrPos=(float(maxRr-rr)/float(maxRr)); //end of RR //shrink all the x positions horizontally arPos/=2.0; @@ -1125,7 +1125,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, //addAALine(dl,pos3,posSLineVEnd,colorS); //draw vert. line through sustain level addAALine(dl,pos1,pos2,color); //A addAALine(dl,pos2,posDecayRate0Pt,color); //Line from A to end of graph - } else if (d2r==0.0 || (instType==DIV_INS_OPL && sus==1.0) || (instType==DIV_INS_OPLL && egt!=0.0)) { //envelope stays at the sustain level forever + } else if (d2r==0.0 || ((instType==DIV_INS_OPL || instType==DIV_INS_SNES) && sus==1.0) || (instType==DIV_INS_OPLL && egt!=0.0)) { //envelope stays at the sustain level forever dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); //draw release as shaded triangle behind everything addAALine(dl,pos3,posSLineHEnd,colorR); //draw horiz line through sustain level addAALine(dl,pos3,posSLineVEnd,colorR); //draw vert. line through sustain level @@ -2393,7 +2393,7 @@ void FurnaceGUI::drawInsEdit() { } ImGui::TableNextColumn(); - drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight),ins->type); + drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight),ins->type); if (settings.separateFMColors) { popAccentColors(); @@ -2810,7 +2810,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_OPZ) { envHeight-=ImGui::GetFrameHeightWithSpacing()*2.0f; } - drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,envHeight),ins->type); + drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,envHeight),ins->type); if (ins->type==DIV_INS_OPZ) { ImGui::Separator(); @@ -3003,7 +3003,7 @@ void FurnaceGUI::drawInsEdit() { } //52.0 controls vert scaling; default 96 - drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type); + drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type); //P(CWSliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) { ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \ @@ -3650,7 +3650,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN)); ImGui::TableNextColumn(); - drawFMEnv(0,16-ins->c64.a,16-ins->c64.d,15-ins->c64.r,15-ins->c64.r,15-ins->c64.s,0,0,0,15,16,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); + drawFMEnv(0,16-ins->c64.a,16-ins->c64.d,15-ins->c64.r,15-ins->c64.r,15-ins->c64.s,0,0,0,15,16,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); ImGui::EndTable(); } @@ -3764,11 +3764,16 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Use wavetable (Amiga/SNES only)",&ins->amiga.useWave)); if (ins->amiga.useWave) { int len=ins->amiga.waveLen+1; + int origLen=len; if (ImGui::InputInt("Width",&len,2,16)) { if (ins->type==DIV_INS_SNES) { if (len<16) len=16; if (len>256) len=256; - ins->amiga.waveLen=(len&(~15))-1; + if (len>origLen) { + ins->amiga.waveLen=((len+15)&(~15))-1; + } else { + ins->amiga.waveLen=(len&(~15))-1; + } } else { if (len<2) len=2; if (len>256) len=256; @@ -4006,7 +4011,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); P(CWVSliderScalar("##Rate Correction",sliderSize,ImGuiDataType_U8,&ins->multipcm.rc,&_ZERO,&_FIFTEEN)); ImGui::TableNextColumn(); - drawFMEnv(0,ins->multipcm.ar,ins->multipcm.d1r,ins->multipcm.d2r,ins->multipcm.rr,ins->multipcm.dl,0,0,0,127,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); + drawFMEnv(0,ins->multipcm.ar,ins->multipcm.d1r,ins->multipcm.d2r,ins->multipcm.rr,ins->multipcm.dl,0,0,0,127,15,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); ImGui::EndTable(); } if (ImGui::BeginTable("MultiPCMLFOParams",3,ImGuiTableFlags_SizingStretchSame)) { @@ -4062,7 +4067,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->snes.r,&_ZERO,&_THIRTY_ONE)); ImGui::TableNextColumn(); - drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.r,ins->snes.r,(14-ins->snes.s*2),(ins->snes.r==0),0,0,7,16,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); + drawFMEnv(0,ins->snes.a+1,1+ins->snes.d*2,ins->snes.r,ins->snes.r,(14-ins->snes.s*2),(ins->snes.r==0 || ins->snes.sus),0,0,7,16,31,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); ImGui::EndTable(); } From 7990dc196527f18512085261555165aed306d04b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 28 Sep 2022 23:21:24 -0500 Subject: [PATCH 15/23] OPN: fix AY issue --- src/engine/platform/ym2203.cpp | 2 ++ src/engine/platform/ym2203ext.cpp | 1 + src/engine/platform/ym2608.cpp | 2 ++ src/engine/platform/ym2608ext.cpp | 1 + src/engine/platform/ym2610.cpp | 4 +++- src/engine/platform/ym2610b.cpp | 2 ++ src/engine/platform/ym2610bext.cpp | 1 + src/engine/platform/ym2610ext.cpp | 1 + 8 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 13fc014d8..6a0864377 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -203,6 +203,7 @@ void DivPlatformYM2203::tick(bool sysTick) { ay->tick(sysTick); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); @@ -807,6 +808,7 @@ void DivPlatformYM2203::forceIns() { ay->forceIns(); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index f3b279c97..fc6294870 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -448,6 +448,7 @@ void DivPlatformYM2203Ext::forceIns() { ay->forceIns(); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index b247be449..87fc79144 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -654,6 +654,7 @@ void DivPlatformYM2608::tick(bool sysTick) { ay->tick(sysTick); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); @@ -1199,6 +1200,7 @@ void DivPlatformYM2608::forceIns() { ay->forceIns(); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 66a4d252c..0b73b42c9 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -483,6 +483,7 @@ void DivPlatformYM2608Ext::forceIns() { ay->forceIns(); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 794fc7d95..89e354a98 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -593,13 +593,14 @@ void DivPlatformYM2610::tick(bool sysTick) { ay->tick(sysTick); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); } int DivPlatformYM2610::dispatch(DivCommand c) { - if (c.chan>=psgChanOffs && c.chan<7) { + if (c.chan>=psgChanOffs && c.chandispatch(c); } @@ -1169,6 +1170,7 @@ void DivPlatformYM2610::forceIns() { ay->forceIns(); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 941cee22e..3ee916a2f 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -656,6 +656,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { ay->tick(sysTick); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); @@ -1232,6 +1233,7 @@ void DivPlatformYM2610B::forceIns() { ay->forceIns(); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 5c8c2c635..201bb598d 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -474,6 +474,7 @@ void DivPlatformYM2610BExt::forceIns() { ay->forceIns(); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index 22c9ebf90..ac82bb81e 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -474,6 +474,7 @@ void DivPlatformYM2610Ext::forceIns() { ay->forceIns(); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { + if (i.addr>15) continue; immWrite(i.addr&15,i.val); } ay->getRegisterWrites().clear(); From 9f2cb1450fcba1bddfc0a2fede93d6acdc6da222 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 29 Sep 2022 00:10:34 -0500 Subject: [PATCH 16/23] YM2151: fix LFO --- src/engine/platform/arcade.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 477430994..aaf64e074 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -218,6 +218,10 @@ void DivPlatformArcade::tick(bool sysTick) { immWrite(0x18,chan[i].std.ex3.val); } + if (chan[i].std.ex1.had || chan[i].std.ex2.had || chan[i].std.ex3.had) { + immWrite(0x01,0x00); // LFO On + } + if (chan[i].std.alg.had) { chan[i].state.alg=chan[i].std.alg.val; if (isMuted[i]) { From 6ed50d717c0895f53badbe0accbff95b6cb201d7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 29 Sep 2022 00:27:40 -0500 Subject: [PATCH 17/23] fix song stop screwing everything up --- src/engine/engine.cpp | 3 +++ src/engine/engine.h | 2 ++ src/engine/playback.cpp | 24 +++++++++++++++--------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 46f7ad03a..f368788ac 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -401,6 +401,7 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) { SafeWriter* DivEngine::saveCommand(bool binary) { stop(); repeatPattern=false; + shallStop=false; setOrder(0); BUSY_BEGIN_SOFT; // determine loop point @@ -1873,6 +1874,7 @@ void DivEngine::play() { sPreview.wave=-1; sPreview.pos=0; sPreview.dir=false; + shallStop=false; if (stepPlay==0) { freelance=false; playSub(false); @@ -2031,6 +2033,7 @@ void DivEngine::reset() { speed1=curSubSong->speed1; speed2=curSubSong->speed2; firstTick=false; + shallStop=false; nextSpeed=speed1; divider=60; if (curSubSong->customTempo) { diff --git a/src/engine/engine.h b/src/engine/engine.h index 19d86905a..0cc05eefb 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -327,6 +327,7 @@ class DivEngine { bool lowQuality; bool playing; bool freelance; + bool shallStop; bool speedAB; bool endOfSong; bool consoleMode; @@ -998,6 +999,7 @@ class DivEngine { lowQuality(false), playing(false), freelance(false), + shallStop(false), speedAB(false), endOfSong(false), consoleMode(false), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index fedfc94eb..b00e09ddd 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -844,15 +844,7 @@ void DivEngine::processRow(int i, bool afterDelay) { break; case 0xff: // stop song - freelance=false; - playing=false; - extValuePresent=false; - stepPlay=0; - remainingLoops=-1; - sPreview.sample=-1; - sPreview.wave=-1; - sPreview.pos=0; - sPreview.dir=false; + shallStop=true; break; } } @@ -1285,6 +1277,20 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { firstTick=false; + if (shallStop) { + freelance=false; + playing=false; + extValuePresent=false; + stepPlay=0; + remainingLoops=-1; + sPreview.sample=-1; + sPreview.wave=-1; + sPreview.pos=0; + sPreview.dir=false; + ret=true; + return ret; + } + // system tick for (int i=0; itick(subticks==tickMult); From 86fe6206be191a7bb13db7c966b57cf94479b558 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 29 Sep 2022 00:27:58 -0500 Subject: [PATCH 18/23] another tiny fix --- src/engine/playback.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index b00e09ddd..2e2bb14fb 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1288,6 +1288,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { sPreview.pos=0; sPreview.dir=false; ret=true; + shallStop=false; return ret; } From c45816b8f2bc7a0eb232c706767338237fc1ac03 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 29 Sep 2022 00:38:18 -0500 Subject: [PATCH 19/23] DAC: fix wavetable mode --- src/engine/platform/pcmdac.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index f7db0ef4c..ae3362ecd 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -47,7 +47,7 @@ void DivPlatformPCMDAC::acquire(short* bufL, short* bufR, size_t start, size_t l chan.audPos%=chan.audLen; chan.audDir=false; } - output=(chan.ws.output[chan.audPos]^0x80)<<8; + output=(chan.ws.output[chan.audPos]-0x80)<<8; } else { DivSample* s=parent->getSample(chan.sample); if (s->samples>0) { @@ -195,7 +195,7 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_AMIGA); if (ins->amiga.useWave) { chan.useWave=true; - chan.audLen=ins->amiga.waveLen; + chan.audLen=ins->amiga.waveLen+1; if (chan.insChanged) { if (chan.wave<0) { chan.wave=0; From 24a72165c9197c79fb3ec59105f5d69b64e50684 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 29 Sep 2022 01:24:26 -0500 Subject: [PATCH 20/23] move config handler to a new class paves the way for chip flags rewrite --- CMakeLists.txt | 1 + src/engine/config.cpp | 123 ++++----------------------- src/engine/config.h | 51 ++++++++++++ src/engine/configEngine.cpp | 162 ++++++++++++++++++++++++++++++++++++ src/engine/engine.h | 3 +- 5 files changed, 233 insertions(+), 107 deletions(-) create mode 100644 src/engine/config.h create mode 100644 src/engine/configEngine.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2aae13d9d..03ad112ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -448,6 +448,7 @@ src/engine/brrUtils.c src/engine/safeReader.cpp src/engine/safeWriter.cpp src/engine/config.cpp +src/engine/configEngine.cpp src/engine/dispatchContainer.cpp src/engine/engine.cpp src/engine/fileOps.cpp diff --git a/src/engine/config.cpp b/src/engine/config.cpp index 38cb2b042..f98c82a4a 100644 --- a/src/engine/config.cpp +++ b/src/engine/config.cpp @@ -17,101 +17,13 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "engine.h" +#include "config.h" #include "../ta-log.h" #include "../fileutils.h" #include -#ifdef _WIN32 -#include "winStuff.h" -#define CONFIG_FILE "\\furnace.cfg" -#else -#ifdef __HAIKU__ -#include -#include -#endif -#include -#include -#include -#define CONFIG_FILE "/furnace.cfg" -#endif - -#ifdef IS_MOBILE -#ifdef HAVE_SDL2 -#include -#else -#error "Furnace mobile requires SDL2!" -#endif -#endif - -void DivEngine::initConfDir() { -#ifdef _WIN32 - // maybe move this function in here instead? - configPath=getWinConfigPath(); -#elif defined(IS_MOBILE) - configPath=SDL_GetPrefPath("tildearrow","furnace"); -#else -#ifdef __HAIKU__ - char userSettingsDir[PATH_MAX]; - status_t findUserDir = find_directory(B_USER_SETTINGS_DIRECTORY,0,true,userSettingsDir,PATH_MAX); - if (findUserDir==B_OK) { - configPath=userSettingsDir; - } else { - logW("unable to find/create user settings directory (%s)!",strerror(findUserDir)); - configPath="."; - return; - } -#else - // TODO this should check XDG_CONFIG_HOME first - char* home=getenv("HOME"); - if (home==NULL) { - int uid=getuid(); - struct passwd* entry=getpwuid(uid); - if (entry==NULL) { - logW("unable to determine home directory (%s)!",strerror(errno)); - configPath="."; - return; - } else { - configPath=entry->pw_dir; - } - } else { - configPath=home; - } -#ifdef __APPLE__ - configPath+="/Library/Application Support"; -#else - // FIXME this doesn't honour XDG_CONFIG_HOME *at all* - configPath+="/.config"; -#endif // __APPLE__ -#endif // __HAIKU__ -#ifdef __APPLE__ - configPath+="/Furnace"; -#else - configPath+="/furnace"; -#endif // __APPLE__ - struct stat st; - std::string pathSep="/"; - configPath+=pathSep; - size_t sepPos=configPath.find(pathSep,1); - while (sepPos!=std::string::npos) { - std::string subpath=configPath.substr(0,sepPos++); - if (stat(subpath.c_str(),&st)!=0) { - logI("creating config path element %s ...",subpath.c_str()); - if (mkdir(subpath.c_str(),0755)!=0) { - logW("could not create config path element %s! (%s)",subpath.c_str(),strerror(errno)); - configPath="."; - return; - } - } - sepPos=configPath.find(pathSep,sepPos); - } - configPath.resize(configPath.length()-pathSep.length()); -#endif // _WIN32 -} - -bool DivEngine::saveConf() { - configFile=configPath+String(CONFIG_FILE); - FILE* f=ps_fopen(configFile.c_str(),"wb"); +bool DivConfig::save(const char* path) { + FILE* f=ps_fopen(path,"wb"); if (f==NULL) { logW("could not write config file! %s",strerror(errno)); return false; @@ -128,13 +40,12 @@ bool DivEngine::saveConf() { return true; } -bool DivEngine::loadConf() { +bool DivConfig::loadFromFile(const char* path, bool createOnFail) { char line[4096]; - configFile=configPath+String(CONFIG_FILE); - FILE* f=ps_fopen(configFile.c_str(),"rb"); + FILE* f=ps_fopen(path,"rb"); if (f==NULL) { logI("creating default config."); - return saveConf(); + return save(path); } logI("loading config."); while (!feof(f)) { @@ -164,7 +75,7 @@ bool DivEngine::loadConf() { return true; } -bool DivEngine::getConfBool(String key, bool fallback) { +bool DivConfig::getConfBool(String key, bool fallback) { try { String val=conf.at(key); if (val=="true") { @@ -177,7 +88,7 @@ bool DivEngine::getConfBool(String key, bool fallback) { return fallback; } -int DivEngine::getConfInt(String key, int fallback) { +int DivConfig::getConfInt(String key, int fallback) { try { String val=conf.at(key); int ret=std::stoi(val); @@ -188,7 +99,7 @@ int DivEngine::getConfInt(String key, int fallback) { return fallback; } -float DivEngine::getConfFloat(String key, float fallback) { +float DivConfig::getConfFloat(String key, float fallback) { try { String val=conf.at(key); float ret=std::stof(val); @@ -199,7 +110,7 @@ float DivEngine::getConfFloat(String key, float fallback) { return fallback; } -double DivEngine::getConfDouble(String key, double fallback) { +double DivConfig::getConfDouble(String key, double fallback) { try { String val=conf.at(key); double ret=std::stod(val); @@ -210,7 +121,7 @@ double DivEngine::getConfDouble(String key, double fallback) { return fallback; } -String DivEngine::getConfString(String key, String fallback) { +String DivConfig::getConfString(String key, String fallback) { try { String val=conf.at(key); return val; @@ -219,7 +130,7 @@ String DivEngine::getConfString(String key, String fallback) { return fallback; } -void DivEngine::setConf(String key, bool value) { +void DivConfig::setConf(String key, bool value) { if (value) { conf[key]="true"; } else { @@ -227,22 +138,22 @@ void DivEngine::setConf(String key, bool value) { } } -void DivEngine::setConf(String key, int value) { +void DivConfig::setConf(String key, int value) { conf[key]=fmt::sprintf("%d",value); } -void DivEngine::setConf(String key, float value) { +void DivConfig::setConf(String key, float value) { conf[key]=fmt::sprintf("%f",value); } -void DivEngine::setConf(String key, double value) { +void DivConfig::setConf(String key, double value) { conf[key]=fmt::sprintf("%f",value); } -void DivEngine::setConf(String key, const char* value) { +void DivConfig::setConf(String key, const char* value) { conf[key]=String(value); } -void DivEngine::setConf(String key, String value) { +void DivConfig::setConf(String key, String value) { conf[key]=value; } diff --git a/src/engine/config.h b/src/engine/config.h new file mode 100644 index 000000000..c33494a99 --- /dev/null +++ b/src/engine/config.h @@ -0,0 +1,51 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 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 _DIVCONFIG_H +#define _DIVCONFIG_H + +#include "../ta-utils.h" +#include + +class DivConfig { + std::map conf; + public: + // config loading/saving + bool loadFromMemory(const char* buf); + bool loadFromFile(const char* path, bool createOnFail=true); + String toString(); + bool save(const char* path); + + // get a config value + bool getConfBool(String key, bool fallback); + int getConfInt(String key, int fallback); + float getConfFloat(String key, float fallback); + double getConfDouble(String key, double fallback); + String getConfString(String key, String fallback); + + // set a config value + void setConf(String key, bool value); + void setConf(String key, int value); + void setConf(String key, float value); + void setConf(String key, double value); + void setConf(String key, const char* value); + void setConf(String key, String value); +}; + +#endif \ No newline at end of file diff --git a/src/engine/configEngine.cpp b/src/engine/configEngine.cpp new file mode 100644 index 000000000..df93cc959 --- /dev/null +++ b/src/engine/configEngine.cpp @@ -0,0 +1,162 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2022 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. + */ + +#include "engine.h" +#include "../ta-log.h" + +#ifdef _WIN32 +#include "winStuff.h" +#define CONFIG_FILE "\\furnace.cfg" +#else +#ifdef __HAIKU__ +#include +#include +#endif +#include +#include +#include +#define CONFIG_FILE "/furnace.cfg" +#endif + +#ifdef IS_MOBILE +#ifdef HAVE_SDL2 +#include +#else +#error "Furnace mobile requires SDL2!" +#endif +#endif + +void DivEngine::initConfDir() { +#ifdef _WIN32 + // maybe move this function in here instead? + configPath=getWinConfigPath(); +#elif defined(IS_MOBILE) + configPath=SDL_GetPrefPath("tildearrow","furnace"); +#else +#ifdef __HAIKU__ + char userSettingsDir[PATH_MAX]; + status_t findUserDir = find_directory(B_USER_SETTINGS_DIRECTORY,0,true,userSettingsDir,PATH_MAX); + if (findUserDir==B_OK) { + configPath=userSettingsDir; + } else { + logW("unable to find/create user settings directory (%s)!",strerror(findUserDir)); + configPath="."; + return; + } +#else + // TODO this should check XDG_CONFIG_HOME first + char* home=getenv("HOME"); + if (home==NULL) { + int uid=getuid(); + struct passwd* entry=getpwuid(uid); + if (entry==NULL) { + logW("unable to determine home directory (%s)!",strerror(errno)); + configPath="."; + return; + } else { + configPath=entry->pw_dir; + } + } else { + configPath=home; + } +#ifdef __APPLE__ + configPath+="/Library/Application Support"; +#else + // FIXME this doesn't honour XDG_CONFIG_HOME *at all* + configPath+="/.config"; +#endif // __APPLE__ +#endif // __HAIKU__ +#ifdef __APPLE__ + configPath+="/Furnace"; +#else + configPath+="/furnace"; +#endif // __APPLE__ + struct stat st; + std::string pathSep="/"; + configPath+=pathSep; + size_t sepPos=configPath.find(pathSep,1); + while (sepPos!=std::string::npos) { + std::string subpath=configPath.substr(0,sepPos++); + if (stat(subpath.c_str(),&st)!=0) { + logI("creating config path element %s ...",subpath.c_str()); + if (mkdir(subpath.c_str(),0755)!=0) { + logW("could not create config path element %s! (%s)",subpath.c_str(),strerror(errno)); + configPath="."; + return; + } + } + sepPos=configPath.find(pathSep,sepPos); + } + configPath.resize(configPath.length()-pathSep.length()); +#endif // _WIN32 +} + +bool DivEngine::saveConf() { + configFile=configPath+String(CONFIG_FILE); + return conf.save(configFile.c_str()); +} + +bool DivEngine::loadConf() { + configFile=configPath+String(CONFIG_FILE); + return conf.loadFromFile(configFile.c_str()); +} + +bool DivEngine::getConfBool(String key, bool fallback) { + return conf.getConfBool(key,fallback); +} + +int DivEngine::getConfInt(String key, int fallback) { + return conf.getConfInt(key,fallback); +} + +float DivEngine::getConfFloat(String key, float fallback) { + return conf.getConfFloat(key,fallback); +} + +double DivEngine::getConfDouble(String key, double fallback) { + return conf.getConfDouble(key,fallback); +} + +String DivEngine::getConfString(String key, String fallback) { + return conf.getConfString(key,fallback); +} + +void DivEngine::setConf(String key, bool value) { + conf.setConf(key,value); +} + +void DivEngine::setConf(String key, int value) { + conf.setConf(key,value); +} + +void DivEngine::setConf(String key, float value) { + conf.setConf(key,value); +} + +void DivEngine::setConf(String key, double value) { + conf.setConf(key,value); +} + +void DivEngine::setConf(String key, const char* value) { + conf.setConf(key,value); +} + +void DivEngine::setConf(String key, String value) { + conf.setConf(key,value); +} \ No newline at end of file diff --git a/src/engine/engine.h b/src/engine/engine.h index 0cc05eefb..895a89ea5 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -19,6 +19,7 @@ #ifndef _ENGINE_H #define _ENGINE_H +#include "config.h" #include "instrument.h" #include "song.h" #include "dispatch.h" @@ -366,7 +367,7 @@ class DivEngine { DivAudioEngines audioEngine; DivAudioExportModes exportMode; double exportFadeOut; - std::map conf; + DivConfig conf; std::deque pendingNotes; // bitfield unsigned char walked[8192]; From 82eed26094b4b037dcbdbd82c164f99f7a534037 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 29 Sep 2022 03:19:48 -0500 Subject: [PATCH 21/23] chip flags rewrite, part 1 --- papers/format.md | 403 +++++++++++++++++++++++++++++++++++++++++- src/engine/config.cpp | 70 +++++--- src/engine/config.h | 1 + 3 files changed, 453 insertions(+), 21 deletions(-) diff --git a/papers/format.md b/papers/format.md index 6d463a893..a58193be0 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 119: Furnace dev119 (still not released) - 118: Furnace dev118 - 117: Furnace dev117 - 116: Furnace 0.6pre1.5 @@ -271,7 +272,9 @@ size | description | - signed char, 64=1.0, 127=~2.0 32 | sound chip panning | - signed char, -128=left, 127=right - 128 | sound chip parameters + 128 | sound chip flag pointers (>=119) or sound chip flags + | - before 118, these were 32-bit flags. + | - for conversion details, see the "converting from old flags" section. STR | song name STR | song author 4f | A-4 tuning @@ -410,6 +413,23 @@ size | description | - same as above ``` +# chip flags + +``` +size | description +-----|------------------------------------ + 4 | "FLAG" block ID + 4 | size of this block + STR | data +``` + +flags are stored in text (`key=value`) format. for example: + +``` +clock=4000000 +stereo=true +``` + # instrument notes: @@ -1156,3 +1176,384 @@ size | description ``` wavetable data follows. + +# converting from old flags + +prior to format version 119, chip flags were stored as a 32-bit integer. +this section will help you understand the old flag format. + +chips which aren't on this list don't have any flags. + +## 0x02: Genesis (COMPOUND) and 0x42: Genesis extended (COMPOUND) + +- bit 31: ladderEffect (bool) +- bit 0-30: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 8MHz + - 3: Firecore (`COLOR_NTSC*12/7`) + - 4: System 32 (`COLOR_NTSC*9/4`) + - only 0 and 1 apply to the SN part as well. + +## 0x03: SMS (SN76489) + +- flags AND 0xff03: clockSel (int) + - 0x0000: NTSC (becomes 0) + - 0x0001: PAL (becomes 1) + - 0x0002: 4MHz (becomes 2) + - 0x0003: half NTSC (becomes 3) + - 0x0100: 3MHz (becomes 4) + - 0x0101: 2MHz (becomes 5) + - 0x0102: eighth NTSC (becomes 6) +- flags AND 0xcc: chipType (int) + - 0x00: Sega PSG (becomes 0) + - 0x04: TI SN76489 (becomes 1) + - 0x08: SN with Atari-like short noise (becomes 2) + - 0x0c: Game Gear (becomes 3) + - 0x40: TI SN76489A (becomes 4) + - 0x44: TI SN76496 (becomes 5) + - 0x48: NCR 8496 (becomes 6) + - 0x4c: Tandy PSSJ 3-voice sound (becomes 7) + - 0x80: TI SN94624 (becomes 8) + - 0x84: TI SN76494 (becomes 9) +- bit 4: noPhaseReset (bool) + +## 0x04: Game Boy + +- bits 0-1: chipType (int) + - 0: DMG (rev B) + - 1: CGB (rev C) + - 2: CGB (rev E) + - 3: AGB +- bit 3: noAntiClick (bool) + +## 0x05: PC Engine + +- bit 1: clockSel (int) + - 0: NTSC + - 1: pseudo-PAL +- bit 2: chipType (int) + - 0: HuC6280 + - 1: HuC6280A +- bit 3: noAntiClick (bool) + +## 0x06: NES, 0x88: VRC6, 0x8a: FDS and 0x8b: MMC5 + +- flags: clockSel (int) + - 0: NTSC (2A03) + - 1: PAL (2A07) + - 2: Dendy + +## 0x07: C64 (8580) and 0x47: C64 (6581) + +- bit 0-3: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: SSI 2001 + +## 0x08: Arcade (YM2151+SegaPCM; COMPOUND) + +- bit 0-7: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 4MHz + - this clock only applies to the YM2151. + +## 0x09: Neo Geo CD (YM2610), 0xa5: Neo Geo (YM2610), 0xa6: Neo Geo extended (YM2610), 0x49: Neo Geo CD extended, 0x9e: YM2610B and 0xde: YM2610B extended + +- bit 0-7: clockSel (int) + - 0: 8MHz + - 1: 8.06MHz (Neo Geo AES) + +## 0x80: AY-3-8910 + +- bit 0-3: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: ZX Spectrum 48K (1.75MHz) + - 3: 2MHz + - 4: 1.5MHz + - 5: 1MHz + - 6: Sunsoft 5B + - 7: PAL NES + - 8: Sunsoft 5B on PAL NES + - 9: 1.10MHz + - 10: 2^21MHz + - 11: double NTSC + - 12: 3.6MHz + - 13: 1.25MHz + - 14: 1.536MHz +- bit 4-5: chipType (int) + - 0: AY-3-8910 + - 1: YM2149(F) + - 2: Sunsoft 5B + - 3: AY-3-8914 +- bit 6: stereo (bool) +- bit 8-15: stereoSep (int) + +## 0x81: Amiga + +- bit 0: clockSel (int) + - 0: NTSC + - 1: PAL +- bit 1: chipType (int) + - 0: Amiga 500 + - 1: Amiga 1200 +- bit 2: bypassLimits (bool) +- bit 8-14: stereoSep (int) + +## 0x82: YM2151 alone + +- bit 0-7: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 4MHz + +## 0x83: YM2612 alone, 0xa0: YM2612 extended, 0xbd: YM2612 extra features extended and 0xbe: YM2612 extra features + +- bit 31: ladderEffect (bool) +- bit 0-30: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 8MHz + - 3: Firecore (`COLOR_NTSC*12/7`) + - 4: System 32 (`COLOR_NTSC*9/4`) + +## 0x84: TIA + +- bit 0: clockSel (int) + - 0: NTSC + - 1: PAL +- bit 1-2: mixingType (int) + - 0: mono + - 1: mono (no distortion) + - 2: stereo + +## 0x85: VIC-20 + +- bit 0: clockSel (int) + - 0: NTSC + - 1: PAL + +## 0x87: SNES + +- bit 0-6: volScaleL (int) +- bit 8-14: volScaleR (int) + +## 0x89: OPLL (YM2413) and 0xa7: OPLL drums (YM2413) + +- bit 0-3: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 4MHz + - 3: half NTSC +- bit 4-31: patchSet (int) + - 0: YM2413 + - 1: YMF281 + - 2: YM2423 + - 3: VRC7 + +## 0x8c: Namco 163 + +- bit 0-3: clockSel (int) + - 0: NTSC (2A03) + - 1: PAL (2A07) + - 2: Dendy +- bit 4-6: channels (int) +- bit 7: multiplex (bool) + +## 0x8d: OPN (YM2203) and 0xb6: OPN extended + +- bit 0-4: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 4MHz + - 3: 3MHz + - 4: 3.99MHz + - 5: 1.5MHz +- bit 5-6: prescale (int) + - 0: /6 + - 1: /3 + - 2: /2 + +## 0x8e: PC-98 (YM2608) and 0xb7: PC-98 extended + +- bit 0-4: clockSel (int) + - 0: 8MHz + - 1: 7.98MHz +- bit 5-6: prescale (int) + - 0: /6 + - 1: /3 + - 2: /2 + +## 0x8f: OPL (YM3526), 0xa2: OPL drums (YM3526), 0x90: OPL2 (YM3812), 0xa3: OPL2 drums (YM3812), 0xb2: Yamaha Y8950 and 0xb3: Yamaha Y8950 drums + +- bit 0-7: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 4MHz + - 3: 3MHz + - 4: 3.99MHz + - 5: 3.5MHz + +## 0x91: OPL3 (YMF262) and 0xa4: OPL3 drums (YMF262) + +- bit 0-7: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 14MHz + - 3: 16MHz + - 4: 15MHz + +## 0x93: Intel 8253 (beeper) + +- bit 0-1: speakerType (int) + - 0: unfiltered + - 1: cone + - 2: piezo + - 3: system + +## 0x95: RF5C68 + +- bit 0-3: clockSel (int) + - 0: 8MHz + - 1: 10MHz + - 2: 12.5MHz +- bit 4-31: chipType (int) + - 0: RF5C68 + - 1: RF5C164 + +## 0x97: Philips SAA1099 + +- flags: clockSel (int) + - 0: 8MHz + - 1: NTSC + - 2: PAL + +## 0x98: OPZ (YM2414) + +- flags: clockSel (int) + - 0: NTSC + - 1: pseudo-PAL + - 2: 4MHz + +## 0x9a: AY8930 + +- bit 0-3: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: ZX Spectrum 48K (1.75MHz) + - 3: 2MHz + - 4: 1.5MHz + - 5: 1MHz + - 6: Sunsoft 5B + - 7: PAL NES + - 8: Sunsoft 5B on PAL NES + - 9: 1.10MHz + - 10: 2^21MHz + - 11: double NTSC + - 12: 3.6MHz +- bit 6: stereo (bool) +- bit 8-15: stereoSep (int) + +## 0x9d: VRC7 + +- bit 0-3: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 4MHz + - 3: half NTSC + +## 0x9f: ZX Spectrum (beeper) + +- bit 0-1: clockSel (int) + - 0: NTSC + - 1: PAL + +## 0xa1: Konami SCC and 0xb4: Konami SCC+ + +- bit 0-6: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 1.5MHz + - 3: 2MHz + +## 0xaa: MSM6295 + +- bit 0-6: clockSel (int) + - 0: 1MHz + - 1: 1.056MHz + - 2: 4MHz + - 3: 4.224MHz + - 4: NTSC + - 5: half NTSC + - 6: 2/7 NTSC + - 7: quarter NTSC + - 8: 2MHz + - 9: 2.112MHz + - 10: 875KHz + - 11: 937.5KHz + - 12: 1.5MHz + - 13: 3MHz + - 14: 1/3 NTSC +- bit 7: rateSel (bool) + +## 0xab: MSM6258 + +- flags: clockSel (int) + - 0: 4MHz + - 1: 4.096MHz + - 2: 8MHz + - 3: 8.192MHz + +## 0xae: OPL4 (YMF278B) and 0xaf: OPL4 drums (YMF278B) + +- bit 0-7: clockSel (int) + - 0: NTSC + - 1: PAL + - 2: 33.8688MHz + +## 0xb0: Seta/Allumer X1-010 + +- bit 0-3: clockSel (int) + - 0: 16MHz + - 1: 16.67MHz +- bit 4: stereo (bool) + +## 0xb5: tildearrow Sound Unit + +- bit 0: clockSel (int) + - 0: NTSC + - 1: PAL +- bit 2: echo (bool) +- bit 3: swapEcho (bool) +- bit 4: sampleMemSize (int) + - 0: 8K + - 1: 64K +- bit 5: pdm (bool) +- bit 8-13: echoDelay (int) +- bit 16-19: echoFeedback (int) +- bit 20-23: echoResolution (int) +- bit 24-31: echoVol (int) + +## 0xb8: YMZ280B + +- bit 0-7: clockSel (int) + - 0: 16.9344MHz + - 1: NTSC + - 2: PAL + - 3: 16MHz + - 4: 16.67MHz + - 5: 14MHz + +## 0xc0: PCM DAC + +- bit 0-15: rate (int) + - add +1 to this value +- bit 16-19: outDepth (int) +- bit 20: stereo (bool) + +## 0xe0: QSound + +- bit 0-11: echoDelay (int) +- bit 12-19: echoFeedback (int) \ No newline at end of file diff --git a/src/engine/config.cpp b/src/engine/config.cpp index f98c82a4a..6270bdfad 100644 --- a/src/engine/config.cpp +++ b/src/engine/config.cpp @@ -40,41 +40,71 @@ bool DivConfig::save(const char* path) { return true; } +String DivConfig::toString() { + String ret; + for (auto& i: conf) { + ret+=fmt::sprintf("%s=%s\n",i.first,i.second); + } + return ret; +} + +void DivConfig::parseLine(const char* line) { + String key=""; + String value=""; + bool keyOrValue=false; + for (const char* i=line; *i; i++) { + if (*i=='\n') continue; + if (keyOrValue) { + value+=*i; + } else { + if (*i=='=') { + keyOrValue=true; + } else { + key+=*i; + } + } + } + if (keyOrValue) { + conf[key]=value; + } +} + bool DivConfig::loadFromFile(const char* path, bool createOnFail) { char line[4096]; FILE* f=ps_fopen(path,"rb"); if (f==NULL) { - logI("creating default config."); - return save(path); + if (createOnFail) { + logI("creating default config."); + return save(path); + } else { + return false; + } } logI("loading config."); while (!feof(f)) { - String key=""; - String value=""; - bool keyOrValue=false; if (fgets(line,4095,f)==NULL) { break; } - for (char* i=line; *i; i++) { - if (*i=='\n') continue; - if (keyOrValue) { - value+=*i; - } else { - if (*i=='=') { - keyOrValue=true; - } else { - key+=*i; - } - } - } - if (keyOrValue) { - conf[key]=value; - } + parseLine(line); } fclose(f); return true; } +bool DivConfig::loadFromMemory(const char* buf) { + String line; + const char* readPos=buf; + while (*readPos) { + line+=*readPos; + readPos++; + if ((*readPos)=='\n' || (*readPos)==0) { + parseLine(line.c_str()); + line=""; + } + } + return true; +} + bool DivConfig::getConfBool(String key, bool fallback) { try { String val=conf.at(key); diff --git a/src/engine/config.h b/src/engine/config.h index c33494a99..0d3fdc41b 100644 --- a/src/engine/config.h +++ b/src/engine/config.h @@ -25,6 +25,7 @@ class DivConfig { std::map conf; + void parseLine(const char* line); public: // config loading/saving bool loadFromMemory(const char* buf); From 0acca7458dd0b15f1da5fb400a1fa3a99af123af Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 29 Sep 2022 03:29:24 -0500 Subject: [PATCH 22/23] chip flags rewrite, part 2 move systemFlags to legacy status --- src/engine/engine.cpp | 20 ++-- src/engine/fileOps.cpp | 12 +-- src/engine/song.h | 203 ++--------------------------------------- src/engine/sysDef.cpp | 18 ++-- src/engine/vgmOps.cpp | 10 +- src/gui/gui.cpp | 2 +- src/gui/insEdit.cpp | 2 +- src/gui/settings.cpp | 2 +- src/gui/sysManager.cpp | 2 +- 9 files changed, 40 insertions(+), 231 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index f368788ac..ce7f2a2ab 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1122,7 +1122,7 @@ void DivEngine::initSongWithDesc(const int* description) { song.system[index]=(DivSystem)description[i]; song.systemVol[index]=description[i+1]; song.systemPan[index]=description[i+2]; - song.systemFlags[index]=description[i+3]; + song.systemFlagsOld[index]=description[i+3]; index++; chanCount+=getChannelCount(song.system[index]); if (chanCount>=DIV_MAX_CHANS) break; @@ -1345,7 +1345,7 @@ void DivEngine::changeSystem(int index, DivSystem which, bool preserveOrder) { } song.system[index]=which; - song.systemFlags[index]=0; + song.systemFlagsOld[index]=0; recalcChans(); saveLock.unlock(); BUSY_END; @@ -1371,7 +1371,7 @@ bool DivEngine::addSystem(DivSystem which) { song.system[song.systemLen]=which; song.systemVol[song.systemLen]=64; song.systemPan[song.systemLen]=0; - song.systemFlags[song.systemLen++]=0; + song.systemFlagsOld[song.systemLen++]=0; recalcChans(); saveLock.unlock(); BUSY_END; @@ -1415,7 +1415,7 @@ bool DivEngine::removeSystem(int index, bool preserveOrder) { song.system[i]=song.system[i+1]; song.systemVol[i]=song.systemVol[i+1]; song.systemPan[i]=song.systemPan[i+1]; - song.systemFlags[i]=song.systemFlags[i+1]; + song.systemFlagsOld[i]=song.systemFlagsOld[i+1]; } recalcChans(); saveLock.unlock(); @@ -1541,9 +1541,9 @@ bool DivEngine::swapSystem(int src, int dest, bool preserveOrder) { song.systemPan[dest]^=song.systemPan[src]; song.systemPan[src]^=song.systemPan[dest]; - song.systemFlags[src]^=song.systemFlags[dest]; - song.systemFlags[dest]^=song.systemFlags[src]; - song.systemFlags[src]^=song.systemFlags[dest]; + song.systemFlagsOld[src]^=song.systemFlagsOld[dest]; + song.systemFlagsOld[dest]^=song.systemFlagsOld[src]; + song.systemFlagsOld[src]^=song.systemFlagsOld[dest]; recalcChans(); saveLock.unlock(); @@ -3470,9 +3470,9 @@ void DivEngine::setOrder(unsigned char order) { void DivEngine::setSysFlags(int system, unsigned int flags, bool restart) { BUSY_BEGIN_SOFT; saveLock.lock(); - song.systemFlags[system]=flags; + song.systemFlagsOld[system]=flags; saveLock.unlock(); - disCont[system].dispatch->setFlags(song.systemFlags[system]); + disCont[system].dispatch->setFlags(song.systemFlagsOld[system]); disCont[system].setRates(got.rate); if (restart && isPlaying()) { playSub(false); @@ -3630,7 +3630,7 @@ void DivEngine::rescanAudioDevices() { void DivEngine::initDispatch() { BUSY_BEGIN; for (int i=0; i1 || bypassLimits)?2:0); // PAL + ds.systemFlagsOld[i]=1|(80<<8)|(bypassLimits?4:0)|((ds.systemLen>1 || bypassLimits)?2:0); // PAL } for(int i=0; ichanShow[i]=true; @@ -2579,7 +2579,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ds.system[0]=DIV_SYSTEM_AMIGA; ds.systemVol[0]=64; ds.systemPan[0]=0; - ds.systemFlags[0]=1|(80<<8); // PAL + ds.systemFlagsOld[0]=1|(80<<8); // PAL ds.systemName="Amiga"; seqLen=reader.readI_BE(); @@ -3219,11 +3219,11 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) { } if (expansions&16) { ds.system[systemID]=DIV_SYSTEM_N163; - ds.systemFlags[systemID++]=n163Chans; + ds.systemFlagsOld[systemID++]=n163Chans; } if (expansions&32) { ds.system[systemID]=DIV_SYSTEM_AY8910; - ds.systemFlags[systemID++]=38; // Sunsoft 5B + ds.systemFlagsOld[systemID++]=38; // Sunsoft 5B } ds.systemLen=systemID; @@ -3734,7 +3734,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { } for (int i=0; i<32; i++) { - w->writeI(song.systemFlags[i]); + w->writeI(song.systemFlagsOld[i]); } // song name diff --git a/src/engine/song.h b/src/engine/song.h index b708ac0fb..975cc6e86 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -25,6 +25,7 @@ #define DIV_MAX_CHANS 128 #include "../ta-utils.h" +#include "config.h" #include "orders.h" #include "instrument.h" #include "pattern.h" @@ -232,202 +233,10 @@ struct DivSong { unsigned char systemLen; signed char systemVol[32]; signed char systemPan[32]; - // interpretation of these flags varies depending on system. - // - most systems: - // - bit 0: PAL - // - NES: - // - bit 0-1: system type - // - 0: NTSC - // - 1: PAL - // - 2: Dendy - // - SMS/SN76489: - // - bit 0-1, 8-15: clock rate - // - 0000: 3.58MHz (NTSC) - // - 0001: 3.55MHz (PAL) - // - 0002: 4MHz (Other) - // - 0003: 1.79MHz (half NTSC) - // - 0100: 3MHz - // - 0101: 2MHz - // - 0102: 447KHz (NTSC / 8) - // - bit 2-3, 6-7: chip type - // - 00: Sega VDP (16-bit noise) - // - 04: real SN76489 (15-bit noise) - // - 08: real SN76489 with Atari-like short noise buzz (15-bit noise) - // - 0c: Game Gear (16-bit noise, stereo) - // - 40: real SN76489A (17-bit noise) - // - 44: real SN76496 (17-bit noise) - // - 48: NCR 8496 (16-bit noise) - // - 4c: Tandy PSSJ-3 (16-bit noise) - // - 80: real SN94624 (15-bit noise) - // - 84: real SN76494 (17-bit noise) - // - bit 4: disable noise phase reset - // - YM2612/YM3438: - // - bit 0-30: clock rate - // - 0: Genesis NTSC (7.67MHz) - // - 1: Genesis PAL (7.61MHz) - // - 2: FM Towns (8MHz) - // - 3: AtGames Genesis (6.13MHz) - // - 4: Sega System 32 (8.06MHz) - // - bit 31: DAC distortion - // - 0: disable - // - 1: enable - // - YM2151: - // - bit 0-7: clock rate - // - 0: 3.58MHz (NTSC) - // - 1: 3.55MHz (PAL) - // - 2: 4MHz - // - YM2610(B): - // - bit 0-7: clock rate - // - 0: 8MHz (Neo Geo MVS) - // - 1: 8.06MHz (Neo Geo AES) - // - AY-3-8910/AY8930: - // - bit 0-3: clock rate - // - 0: 1.79MHz (MSX NTSC) - // - 1: 1.77MHz (ZX Spectrum, MSX PAL, etc.) - // - 2: 1.75MHz (ZX Spectrum) - // - 3: 2MHz (Atari ST) - // - 4: 1.5MHz (Vectrex) - // - 5: 1MHz (Amstrad CPC) - // - 6: 0.89MHz (Sunsoft 5B) - // - 7: 1.67MHz - // - 8: 0.83MHz (Sunsoft 5B on PAL) - // - 9: 1.10MHz (Gamate/VIC-20 PAL) - // - 10: 2.097152MHz (Game Boy) - // - 11: 3.58MHz (Darky) - // - 12: 3.6MHz (Darky) - // - 13: 1.25MHz - // - 14: 1.536MHz - // - bit 4-5: chip type (ignored on AY8930) - // - 0: AY-3-8910 or similar - // - 1: YM2149 - // - 2: Sunsoft 5B - // - 3: AY-3-8914 - // - bit 6: stereo (ignored on Sunsoft 5B) - // - 0: mono - // - 1: stereo ABC - // - bit 7: clock divider pin (YM2149, AY8930) - // - 0: high (disable divider) - // - 1: low (internally divided to half) - // - SAA1099: - // - bit 0-1: clock rate - // - 0: 8MHz (SAM CoupĂ©) - // - 1: 7.15MHz (Game Blaster, NTSC) - // - 2: 7.09MHz (PAL) - // - Amiga: - // - bit 0: clock rate - // - 0: 7.15MHz (NTSC) - // - 1: 7.09MHz (PAL) - // - bit 1: model - // - 0: Amiga 500 - // - 1: Amiga 1200 - // - bit 8-14: stereo separation - // - 0 is 0% while 127 is 100% - // - PC Speaker: - // - bit 0-1: speaker type - // - 0: unfiltered - // - 1: cone - // - 2: piezo - // - 3: real (TODO) - // - QSound: - // - bit 12-20: echo feedback - // - Valid values are 0-255 - // - bit 0-11: echo delay length - // - Valid values are 0-2725 - // - 0 is max length, 2725 is min length - // - OPLL: - // - bit 0-3: clock rate - // - 0: NTSC (3.58MHz) - // - 1: PAL (3.55MHz) - // - 2: Other (4MHz) - // - 3: half NTSC (1.79MHz) - // - bit 4-7: patch set - // - 0: YM2413 - // - 1: YMF281 - // - 2: YM2423 - // - 3: VRC7 - // - 4: custom (TODO) - // - X1-010: - // - bit 0-3: clock rate - // - 0: 16MHz (Seta 1) - // - 1: 16.67MHz (Seta 2) - // - bit 4: stereo - // - 0: mono - // - 1: stereo - // - YM2203: - // - bit 0-4: clock rate - // - 0: 3.58MHz (NTSC) - // - 1: 3.55MHz (PAL) - // - 2: 4MHz - // - 3: 3MHz - // - 4: 3.9936MHz (PC-88, PC-98) - // - 5: 1.5MHz - // - bit 5-6: output rate - // - 0: FM: clock / 72, SSG: clock / 16 - // - 1: FM: clock / 36, SSG: clock / 8 - // - 2: FM: clock / 24, SSG: clock / 4 - // - YM2608: - // - bit 0-4: clock rate - // - 0: 8MHz - // - 1: 7.987MHz (PC-88, PC-98) - // - bit 5-6: output rate - // - 0: FM: clock / 144, SSG: clock / 32 - // - 1: FM: clock / 72, SSG: clock / 16 - // - 2: FM: clock / 48, SSG: clock / 8 - // - YM3526, YM3812, Y8950: - // - bit 0-7: clock rate - // - 0: 3.58MHz (NTSC) - // - 1: 3.55MHz (PAL) - // - 2: 4MHz - // - 3: 3MHz - // - 4: 3.9936MHz (PC-88, PC-98) - // - 5: 3.5MHz - // - YMF262: - // - bit 0-7: clock rate - // - 0: 14.32MHz (NTSC) - // - 1: 14.19MHz (PAL) - // - 2: 14MHz - // - 3: 16MHz - // - 4: 15MHz - // - YMF289B: (TODO) - // - bit 0-7: clock rate - // - 0: 33.8688MHz - // - 1: 28.64MHz (NTSC) - // - 2: 28.38MHz (PAL) - // - MSM6295: - // - bit 0-6: clock rate - // - 0: 1MHz - // - 1: 1.056MHz - // - 2: 4MHz - // - 3: 4.224MHz - // - 4: 3.58MHz (NTSC) - // - 5: 1.79MHz (Half NTSC) - // - 6: 1.023MHz - // - 7: 0.895MHz (Quarter NTSC) - // - 8: 2MHz - // - 9: 2.112MHz - // - 10: 0.875MHz - // - 11: 0.9375MHz - // - 12: 1.5MHz - // - 13: 3MHz - // - 14: 1.193MHz - // - bit 7: Output rate - // - 0: clock / 132 - // - 1: clock / 165 - // - SCC/+: - // - bit 0-6: clock rate - // - 0: 1.79MHz (MSX NTSC) - // - 1: 1.77MHz (PAL) - // - 2: 1.5MHz - // - 3: 2MHz - // - YMZ280B: - // - bit 0-7: clock rate - // - 0: 16.9344MHz - // - 1: 14.32MHz (NTSC) - // - 2: 14.19MHz (PAL) - // - 3: 16MHz - // - 4: 16.67MHz - // - 5: 14MHz - unsigned int systemFlags[32]; + // this one will be removed soon... + unsigned int systemFlagsOld[32]; + // ...and replaced with... this! + DivConfig systemFlags[32]; // song information String name, author, systemName; @@ -623,7 +432,7 @@ struct DivSong { system[i]=DIV_SYSTEM_NULL; systemVol[i]=64; systemPan[i]=0; - systemFlags[i]=0; + systemFlagsOld[i]=0; } subsong.push_back(new DivSubSong); system[0]=DIV_SYSTEM_YM2612; diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 9a10d26c0..27c347145 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -61,7 +61,7 @@ String DivEngine::getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAccepta return "help! what's going on!"; case 1: if (ds.system[0]==DIV_SYSTEM_AY8910) { - switch (ds.systemFlags[0]&0x3f) { + switch (ds.systemFlagsOld[0]&0x3f) { case 0: // AY-3-8910, 1.79MHz case 1: // AY-3-8910, 1.77MHz case 2: // AY-3-8910, 1.75MHz @@ -88,35 +88,35 @@ String DivEngine::getSongSystemLegacyName(DivSong& ds, bool isMultiSystemAccepta return "Intellivision (PAL)"; default: - if ((ds.systemFlags[0]&0x30)==0x00) { + if ((ds.systemFlagsOld[0]&0x30)==0x00) { return "AY-3-8910"; - } else if ((ds.systemFlags[0]&0x30)==0x10) { + } else if ((ds.systemFlagsOld[0]&0x30)==0x10) { return "Yamaha YM2149"; - } else if ((ds.systemFlags[0]&0x30)==0x20) { + } else if ((ds.systemFlagsOld[0]&0x30)==0x20) { return "Overclocked Sunsoft 5B"; - } else if ((ds.systemFlags[0]&0x30)==0x30) { + } else if ((ds.systemFlagsOld[0]&0x30)==0x30) { return "Intellivision"; } } } else if (ds.system[0]==DIV_SYSTEM_SMS) { - switch (ds.systemFlags[0]&0x0f) { + switch (ds.systemFlagsOld[0]&0x0f) { case 0: case 1: return "Sega Master System"; case 6: return "BBC Micro"; } } else if (ds.system[0]==DIV_SYSTEM_YM2612) { - switch (ds.systemFlags[0]&3) { + switch (ds.systemFlagsOld[0]&3) { case 2: return "FM Towns"; } } else if (ds.system[0]==DIV_SYSTEM_YM2151) { - switch (ds.systemFlags[0]&3) { + switch (ds.systemFlagsOld[0]&3) { case 2: return "Sharp X68000"; } } else if (ds.system[0]==DIV_SYSTEM_SAA1099) { - switch (ds.systemFlags[0]&3) { + switch (ds.systemFlagsOld[0]&3) { case 0: return "SAM CoupĂ©"; } diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index c0dc88955..dd5e1f37a 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -939,7 +939,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p if (!hasSN) { hasSN=disCont[i].dispatch->chipClock; willExport[i]=true; - switch ((song.systemFlags[i]>>2)&3) { + switch ((song.systemFlagsOld[i]>>2)&3) { case 1: // real SN snNoiseConfig=3; snNoiseSize=15; @@ -1054,7 +1054,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p ayConfig=0x03; hasClockDivider=true; } else { - switch ((song.systemFlags[i]>>4)&3) { + switch ((song.systemFlagsOld[i]>>4)&3) { default: case 0: // AY8910 ayConfig=0x00; @@ -1073,10 +1073,10 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p break; } } - if (hasClockDivider && ((song.systemFlags[i]>>7)&1)) { + if (hasClockDivider && ((song.systemFlagsOld[i]>>7)&1)) { ayFlags|=0x10; } - if (hasStereo && ((song.systemFlags[i]>>6)&1)) { + if (hasStereo && ((song.systemFlagsOld[i]>>6)&1)) { ayFlags|=0x80; } willExport[i]=true; @@ -1304,7 +1304,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p // chips even though the only difference is the output resolution // these system types are currently handled by reusing isSecond flag // also this system is not dual-able - if ((song.systemFlags[i]>>4)==1) { + if ((song.systemFlagsOld[i]>>4)==1) { if (!hasRFC1) { hasRFC1=disCont[i].dispatch->chipClock; isSecond[i]=true; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4c7850adf..9ce08ab58 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3438,7 +3438,7 @@ bool FurnaceGUI::loop() { if (ImGui::BeginMenu("configure chip...")) { for (int i=0; isong.systemLen; i++) { if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSP%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { - drawSysConf(i,e->song.system[i],e->song.systemFlags[i],true); + drawSysConf(i,e->song.system[i],e->song.systemFlagsOld[i],true); ImGui::TreePop(); } } diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index a8fbf48dc..de770768e 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1904,7 +1904,7 @@ void FurnaceGUI::drawInsEdit() { if (e->song.system[i]==DIV_SYSTEM_VRC7) { isPresent[3]=true; } else if (e->song.system[i]==DIV_SYSTEM_OPLL || e->song.system[i]==DIV_SYSTEM_OPLL_DRUMS) { - isPresent[(e->song.systemFlags[i]>>4)&3]=true; + isPresent[(e->song.systemFlagsOld[i]>>4)&3]=true; } } if (!isPresent[0] && !isPresent[1] && !isPresent[2] && !isPresent[3]) { diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 805072f16..b55a064c5 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -273,7 +273,7 @@ void FurnaceGUI::drawSettings() { settings.initialSys.push_back(e->song.system[i]); settings.initialSys.push_back(e->song.systemVol[i]); settings.initialSys.push_back(e->song.systemPan[i]); - settings.initialSys.push_back(e->song.systemFlags[i]); + settings.initialSys.push_back(e->song.systemFlagsOld[i]); } settings.initialSysName=e->song.systemName; } diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index 386d26583..5d7a59c73 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -70,7 +70,7 @@ void FurnaceGUI::drawSysManager() { } ImGui::TableNextColumn(); if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSM%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { - drawSysConf(i,e->song.system[i],e->song.systemFlags[i],true); + drawSysConf(i,e->song.system[i],e->song.systemFlagsOld[i],true); ImGui::TreePop(); } ImGui::TableNextColumn(); From 3b28549885af4740d128d6a9658a530197babbd8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 29 Sep 2022 04:39:31 -0500 Subject: [PATCH 23/23] SNES: pre-dev118 gain hotfix --- src/engine/instrument.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index a78bb8ffe..020edb965 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -1258,8 +1258,14 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { // SNES if (version>=109) { snes.useEnv=reader.readC(); - snes.gainMode=(DivInstrumentSNES::GainMode)reader.readC(); - snes.gain=reader.readC(); + if (version<118) { + // why why why + reader.readC(); + reader.readC(); + } else { + snes.gainMode=(DivInstrumentSNES::GainMode)reader.readC(); + snes.gain=reader.readC(); + } snes.a=reader.readC(); snes.d=reader.readC(); snes.s=reader.readC();