SNES: invert/pitch mod/noise control

echo still work in progress
This commit is contained in:
tildearrow 2022-09-25 03:33:39 -05:00
parent b4c260dc2a
commit b4c020c11b
3 changed files with 124 additions and 45 deletions

View file

@ -93,24 +93,15 @@ void DivPlatformSNES::tick(bool sysTick) {
// so they have to be accumulated
unsigned char kon=0;
unsigned char koff=0;
bool writeControl=false;
bool writeNoise=false;
bool writePitchMod=false;
bool writeEcho=false;
for (int i=0; i<8; i++) {
//bool hadGain=chan[i].std.vol.had || chan[i].std.ex1.had || chan[i].std.ex2.had;
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=VOL_SCALE_LOG(chan[i].vol&127,MIN(127,chan[i].std.vol.val),127);
}
/*
if (chan[i].std.vol.had) {
chWrite(i,7,MIN(127,chan[i].std.vol.val*2));
} else if (!chan[i].state.useEnv && hadGain) {
if (chan[i].std.ex1.val==0) {
// direct gain
chWrite(i,7,chan[i].std.vol.val);
} else {
// inc/dec
chWrite(i,7,chan[i].std.ex2.val|((chan[i].std.ex1.val-1)<<5)|0x80);
}
}*/
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
if (chan[i].std.arp.mode) {
@ -126,6 +117,10 @@ void DivPlatformSNES::tick(bool sysTick) {
chan[i].freqChanged=true;
}
}
if (chan[i].std.duty.had) {
noiseFreq=chan[i].std.duty.val;
writeControl=true;
}
if (chan[i].useWave && chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave.val;
@ -149,7 +144,30 @@ void DivPlatformSNES::tick(bool sysTick) {
int val=chan[i].std.panR.val&0x7f;
chan[i].panR=(val<<1)|(val>>6);
}
if (chan[i].std.vol.had || chan[i].std.panL.had || chan[i].std.panR.had) {
bool hasInverted=false;
if (chan[i].std.ex1.had) {
if (chan[i].invertL!=(chan[i].std.ex1.val&16)) {
chan[i].invertL=chan[i].std.ex1.val&16;
hasInverted=true;
}
if (chan[i].invertR!=(chan[i].std.ex1.val&8)) {
chan[i].invertR=chan[i].std.ex1.val&8;
hasInverted=true;
}
if (chan[i].pitchMod!=(chan[i].std.ex1.val&4)) {
chan[i].pitchMod=chan[i].std.ex1.val&4;
writePitchMod=true;
}
if (chan[i].echo!=(chan[i].std.ex1.val&2)) {
chan[i].echo=chan[i].std.ex1.val&2;
writeEcho=true;
}
if (chan[i].noise!=(chan[i].std.ex1.val&1)) {
chan[i].noise=chan[i].std.ex1.val&1;
writeNoise=true;
}
}
if (chan[i].std.vol.had || chan[i].std.panL.had || chan[i].std.panR.had || hasInverted) {
writeOutVol(i);
}
if (chan[i].setPos) {
@ -173,29 +191,6 @@ void DivPlatformSNES::tick(bool sysTick) {
if (chan[i].keyOn) {
unsigned int start, end, loop;
unsigned short tabAddr=sampleTableAddr(i);
if (chan[i].state.useEnv) {
chWrite(i,5,chan[i].state.a|(chan[i].state.d<<4)|0x80);
chWrite(i,6,chan[i].state.r|(chan[i].state.s<<5));
} else {
chWrite(i,5,0);
switch (chan[i].state.gainMode) {
case DivInstrumentSNES::GAIN_MODE_DIRECT:
chWrite(i,7,chan[i].state.gain&127);
break;
case DivInstrumentSNES::GAIN_MODE_DEC_LINEAR:
chWrite(i,7,0x80|(chan[i].state.gain&31));
break;
case DivInstrumentSNES::GAIN_MODE_INC_LINEAR:
chWrite(i,7,0xc0|(chan[i].state.gain&31));
break;
case DivInstrumentSNES::GAIN_MODE_DEC_LOG:
chWrite(i,7,0xa0|(chan[i].state.gain&31));
break;
case DivInstrumentSNES::GAIN_MODE_INC_INVLOG:
chWrite(i,7,0xe0|(chan[i].state.gain&31));
break;
}
}
if (chan[i].useWave) {
start=waveTableAddr(i);
loop=start;
@ -228,6 +223,49 @@ void DivPlatformSNES::tick(bool sysTick) {
}
}
}
if (writeControl) {
unsigned char control=noiseFreq&0x1f;
rWrite(0x6c,control);
}
if (writeNoise) {
unsigned char noiseBits=(
(chan[0].noise?1:0)|
(chan[1].noise?2:0)|
(chan[2].noise?4:0)|
(chan[3].noise?8:0)|
(chan[4].noise?0x10:0)|
(chan[5].noise?0x20:0)|
(chan[6].noise?0x40:0)|
(chan[7].noise?0x80:0)
);
rWrite(0x3d,noiseBits);
}
if (writePitchMod) {
unsigned char pitchModBits=(
(chan[0].pitchMod?1:0)|
(chan[1].pitchMod?2:0)|
(chan[2].pitchMod?4:0)|
(chan[3].pitchMod?8:0)|
(chan[4].pitchMod?0x10:0)|
(chan[5].pitchMod?0x20:0)|
(chan[6].pitchMod?0x40:0)|
(chan[7].pitchMod?0x80:0)
);
rWrite(0x2d,pitchModBits);
}
if (writeEcho) {
unsigned char echoBits=(
(chan[0].echo?1:0)|
(chan[1].echo?2:0)|
(chan[2].echo?4:0)|
(chan[3].echo?8:0)|
(chan[4].echo?0x10:0)|
(chan[5].echo?0x20:0)|
(chan[6].echo?0x40:0)|
(chan[7].echo?0x80:0)
);
rWrite(0x4d,echoBits);
}
if (kon!=0) {
rWrite(0x4c,kon);
}
@ -260,6 +298,29 @@ 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;
}
}
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value));
chan[c.chan].freqChanged=true;
@ -375,6 +436,8 @@ void DivPlatformSNES::writeOutVol(int ch) {
if (!isMuted[ch]) {
outL=(globalVolL*((chan[ch].outVol*chan[ch].panL)/127))/127;
outR=(globalVolR*((chan[ch].outVol*chan[ch].panR)/127))/127;
if (chan[ch].invertL) outL=-outL;
if (chan[ch].invertR) outR=-outR;
}
chWrite(ch,0,outL);
chWrite(ch,1,outR);

View file

@ -33,7 +33,7 @@ class DivPlatformSNES: public DivDispatch {
int sample, wave, ins;
int note;
int panL, panR;
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, setPos;
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave, setPos, noise, echo, pitchMod, invertL, invertR;
int vol, outVol;
int wtLen;
DivInstrumentSNES state;
@ -63,6 +63,7 @@ class DivPlatformSNES: public DivDispatch {
inPorta(false),
useWave(false),
setPos(false),
noise(false),
vol(127),
outVol(127),
wtLen(16) {}
@ -71,6 +72,7 @@ class DivPlatformSNES: public DivDispatch {
DivDispatchOscBuffer* oscBuf[8];
bool isMuted[8];
signed char globalVolL, globalVolR;
unsigned char noiseFreq;
size_t sampleTableBase;
struct QueuedWrite {

View file

@ -227,6 +227,10 @@ const char* saaEnvBits[9]={
"mirror", "loop", "cut", "direction", "resolution", "fixed", "N/A","enabled", NULL
};
const char* snesModeBits[6]={
"noise", "echo", "pitch mod", "invert right", "invert left", NULL
};
const char* filtModeBits[5]={
"low", "band", "high", "ch3off", NULL
};
@ -4380,9 +4384,12 @@ void FurnaceGUI::drawInsEdit() {
dutyLabel="Noise";
dutyMax=ins->amiga.useSample?0:8;
}
if (ins->type==DIV_INS_SNES) {
dutyLabel="Noise Freq";
dutyMax=31;
}
if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS ||
ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM ||
ins->type==DIV_INS_SNES) {
ins->type==DIV_INS_VRC6_SAW || ins->type==DIV_INS_FDS || ins->type==DIV_INS_MULTIPCM) {
dutyMax=0;
}
if (ins->type==DIV_INS_VERA) {
@ -4504,9 +4511,9 @@ void FurnaceGUI::drawInsEdit() {
ex1Max=65535;
ex2Max=65535;
}
if (ins->type==DIV_INS_SNES && !ins->snes.useEnv) {
ex1Max=4;
ex2Max=31;
if (ins->type==DIV_INS_SNES) {
ex1Max=5;
ex2Max=5;
}
int panMin=0;
@ -4557,6 +4564,10 @@ void FurnaceGUI::drawInsEdit() {
panMax=127;
panSingleNoBit=true;
}
if (ins->type==DIV_INS_SNES) {
panMin=0;
panMax=127;
}
if (ins->type==DIV_INS_ES5506) {
panMax=65535;
}
@ -4649,7 +4660,7 @@ void FurnaceGUI::drawInsEdit() {
} else if (ins->type==DIV_INS_QSOUND) {
macroList.push_back(FurnaceGUIMacroDesc("Echo Feedback",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
} else if (ins->type==DIV_INS_SNES) {
macroList.push_back(FurnaceGUIMacroDesc("Gain Mode",&ins->std.ex1Macro,0,ex1Max,64,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,snesGainModes));
macroList.push_back(FurnaceGUIMacroDesc("Special",&ins->std.ex1Macro,0,ex1Max,96,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,snesModeBits));
} else {
macroList.push_back(FurnaceGUIMacroDesc("Duty",&ins->std.ex1Macro,0,ex1Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
}
@ -4668,7 +4679,7 @@ void FurnaceGUI::drawInsEdit() {
} else if (ins->type==DIV_INS_QSOUND) {
macroList.push_back(FurnaceGUIMacroDesc("Echo Length",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_OTHER]));
} else if (ins->type==DIV_INS_SNES) {
macroList.push_back(FurnaceGUIMacroDesc("Gain Rate",&ins->std.ex2Macro,0,ex2Max,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
macroList.push_back(FurnaceGUIMacroDesc("Gain Mode",&ins->std.ex2Macro,0,ex2Max,64,uiColors[GUI_COLOR_MACRO_VOLUME],false,NULL,NULL,false,snesGainModes));
} else {
macroList.push_back(FurnaceGUIMacroDesc("Envelope",&ins->std.ex2Macro,0,ex2Max,ex2Bit?64:160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,ex2Bit,ayEnvBits));
}
@ -4708,6 +4719,9 @@ void FurnaceGUI::drawInsEdit() {
macroList.push_back(FurnaceGUIMacroDesc("Envelope mode",&ins->std.ex8Macro,0,2,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506EnvelopeModes));
macroList.push_back(FurnaceGUIMacroDesc("Control",&ins->std.algMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,es5506ControlModes));
}
if (ins->type==DIV_INS_SNES) {
macroList.push_back(FurnaceGUIMacroDesc("Gain Rate",&ins->std.ex3Macro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
}
drawMacros(macroList);
ImGui::EndTabItem();