SNES: get some of echo working

This commit is contained in:
tildearrow 2022-09-26 04:07:51 -05:00
parent e5b37db55a
commit 08e23a68cd
2 changed files with 97 additions and 12 deletions

View file

@ -83,7 +83,7 @@ void DivPlatformSNES::acquire(short* bufL, short* bufR, size_t start, size_t len
bufL[h]=out[0]; bufL[h]=out[0];
bufR[h]=out[1]; bufR[h]=out[1];
for (int i=0; i<8; i++) { 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<-32768) next=-32768;
if (next>32767) next=32767; if (next>32767) next=32767;
next=(next*254)/MAX(1,globalVolL+globalVolR); next=(next*254)/MAX(1,globalVolL+globalVolR);
@ -228,7 +228,7 @@ void DivPlatformSNES::tick(bool sysTick) {
} }
} }
if (writeControl) { if (writeControl) {
unsigned char control=noiseFreq&0x1f; unsigned char control=(noiseFreq&0x1f)|(echoOn?0:0x20);
rWrite(0x6c,control); rWrite(0x6c,control);
writeControl=false; writeControl=false;
} }
@ -305,7 +305,6 @@ int DivPlatformSNES::dispatch(DivCommand c) {
} }
if (chan[c.chan].insChanged) { if (chan[c.chan].insChanged) {
chan[c.chan].state=ins->snes; 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,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)); chWrite(c.chan,6,chan[c.chan].state.r|(chan[c.chan].state.s<<5));
@ -329,6 +328,7 @@ int DivPlatformSNES::dispatch(DivCommand c) {
break; break;
} }
} }
}
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value)); chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value));
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
@ -413,7 +413,47 @@ int DivPlatformSNES::dispatch(DivCommand c) {
chan[c.chan].audPos=c.value; chan[c.chan].audPos=c.value;
chan[c.chan].setPos=true; chan[c.chan].setPos=true;
break; 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: case DIV_CMD_GET_VOLMAX:
return 127; return 127;
break; break;
@ -469,6 +509,7 @@ void DivPlatformSNES::forceIns() {
writeNoise=true; writeNoise=true;
writePitchMod=true; writePitchMod=true;
writeEcho=true; writeEcho=true;
initEcho();
} }
void* DivPlatformSNES::getChanState(int ch) { void* DivPlatformSNES::getChanState(int ch) {
@ -497,7 +538,28 @@ int DivPlatformSNES::getRegisterPoolSize() {
return 128; 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() { void DivPlatformSNES::reset() {
memcpy(sampleMem,copyOfSampleMem,65536);
dsp.init(sampleMem); dsp.init(sampleMem);
dsp.set_output(NULL,0); dsp.set_output(NULL,0);
memset(regPool,0,128); memset(regPool,0,128);
@ -521,6 +583,22 @@ void DivPlatformSNES::reset() {
writeNoise=false; writeNoise=false;
writePitchMod=false; writePitchMod=false;
writeEcho=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() { bool DivPlatformSNES::isStereo() {
@ -574,7 +652,7 @@ size_t DivPlatformSNES::getSampleMemUsage(int index) {
} }
void DivPlatformSNES::renderSamples() { void DivPlatformSNES::renderSamples() {
memset(sampleMem,0,getSampleMemCapacity()); memset(copyOfSampleMem,0,getSampleMemCapacity());
memset(sampleOff,0,256*sizeof(unsigned int)); memset(sampleOff,0,256*sizeof(unsigned int));
// skip past sample table and wavetable buffer // skip past sample table and wavetable buffer
@ -585,12 +663,12 @@ void DivPlatformSNES::renderSamples() {
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length); int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length);
if (actualLength>0) { if (actualLength>0) {
sampleOff[i]=memPos; sampleOff[i]=memPos;
memcpy(&sampleMem[memPos],s->dataBRR,actualLength); memcpy(&copyOfSampleMem[memPos],s->dataBRR,actualLength);
memPos+=actualLength; memPos+=actualLength;
} }
if (actualLength<length) { if (actualLength<length) {
// terminate the sample // terminate the sample
sampleMem[memPos-9]=1; copyOfSampleMem[memPos-9]=1;
logW("out of BRR memory for sample %d!",i); logW("out of BRR memory for sample %d!",i);
break; break;
} }
@ -607,13 +685,14 @@ int DivPlatformSNES::init(DivEngine* p, int channels, int sugRate, unsigned int
parent=p; parent=p;
dumpWrites=false; dumpWrites=false;
skipRegisterWrites=false; skipRegisterWrites=false;
for (int i=0; i<8; i++) {
oscBuf[i]=new DivDispatchOscBuffer;
isMuted[i]=false;
}
sampleMemLen=0; sampleMemLen=0;
chipClock=1024000; chipClock=1024000;
rate=chipClock/32; rate=chipClock/32;
for (int i=0; i<8; i++) {
oscBuf[i]=new DivDispatchOscBuffer;
oscBuf[i]->rate=rate;
isMuted[i]=false;
}
setFlags(flags); setFlags(flags);
reset(); reset();
return 8; return 8;

View file

@ -77,11 +77,15 @@ class DivPlatformSNES: public DivDispatch {
bool isMuted[8]; bool isMuted[8];
int globalVolL, globalVolR; int globalVolL, globalVolR;
unsigned char noiseFreq; unsigned char noiseFreq;
signed char echoVolL, echoVolR, echoFeedback;
signed char echoFIR[8];
unsigned char echoDelay;
size_t sampleTableBase; size_t sampleTableBase;
bool writeControl; bool writeControl;
bool writeNoise; bool writeNoise;
bool writePitchMod; bool writePitchMod;
bool writeEcho; bool writeEcho;
bool echoOn;
struct QueuedWrite { struct QueuedWrite {
unsigned char addr; unsigned char addr;
@ -91,6 +95,7 @@ class DivPlatformSNES: public DivDispatch {
std::queue<QueuedWrite> writes; std::queue<QueuedWrite> writes;
signed char sampleMem[65536]; signed char sampleMem[65536];
signed char copyOfSampleMem[65536];
size_t sampleMemLen; size_t sampleMemLen;
unsigned int sampleOff[256]; unsigned int sampleOff[256];
unsigned char regPool[0x80]; unsigned char regPool[0x80];
@ -126,6 +131,7 @@ class DivPlatformSNES: public DivDispatch {
private: private:
void updateWave(int ch); void updateWave(int ch);
void writeOutVol(int ch); void writeOutVol(int ch);
void initEcho();
}; };
#endif #endif