NES: envelope and length counter effects

This commit is contained in:
tildearrow 2022-10-25 00:43:03 -05:00
parent 07f247af12
commit 9a1447e392
6 changed files with 100 additions and 8 deletions

View file

@ -205,6 +205,10 @@ enum DivDispatchCmds {
DIV_CMD_SNES_ECHO_FEEDBACK,
DIV_CMD_SNES_ECHO_FIR,
DIV_CMD_NES_ENV_MODE,
DIV_CMD_NES_LENGTH,
DIV_CMD_NES_COUNT_MODE,
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
DIV_CMD_MAX

View file

@ -214,7 +214,7 @@ void DivPlatformNES::tick(bool sysTick) {
rWrite(0x4000+i*4,(chan[i].outVol==0)?0:255);
chan[i].freqChanged=true;
} else {
rWrite(0x4000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
rWrite(0x4000+i*4,(chan[i].envMode<<4)|chan[i].outVol|((chan[i].duty&3)<<6));
}
}
if (chan[i].std.arp.had) {
@ -239,7 +239,7 @@ void DivPlatformNES::tick(bool sysTick) {
}
}
if (i!=2) {
rWrite(0x4000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
rWrite(0x4000+i*4,(chan[i].envMode<<4)|chan[i].outVol|((chan[i].duty&3)<<6));
}
if (i==3) { // noise
chan[i].freqChanged=true;
@ -289,11 +289,11 @@ void DivPlatformNES::tick(bool sysTick) {
}
if (i==3) { // noise
rWrite(0x4002+i*4,(chan[i].duty<<7)|chan[i].freq);
rWrite(0x4003+i*4,0xf0);
rWrite(0x4003+i*4,(chan[i].len<<3));
} else {
rWrite(0x4002+i*4,chan[i].freq&0xff);
if ((chan[i].prevFreq>>8)!=(chan[i].freq>>8) || i==2) {
rWrite(0x4003+i*4,0xf8|(chan[i].freq>>8));
rWrite(0x4003+i*4,(chan[i].len<<3)|(chan[i].freq>>8));
}
if (chan[i].freq!=65535 && chan[i].freq!=0) {
chan[i].prevFreq=chan[i].freq;
@ -419,7 +419,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
if (c.chan==2) {
rWrite(0x4000+c.chan*4,0xff);
} else if (!parent->song.brokenOutVol2) {
rWrite(0x4000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
rWrite(0x4000+c.chan*4,(chan[c.chan].envMode<<4)|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
}
break;
case DIV_CMD_NOTE_OFF:
@ -451,7 +451,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
if (c.chan==2) {
rWrite(0x4000+c.chan*4,0xff);
} else {
rWrite(0x4000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
rWrite(0x4000+c.chan*4,(chan[c.chan].envMode<<4)|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
}
}
}
@ -491,7 +491,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
if (c.chan==3) { // noise
chan[c.chan].freqChanged=true;
} else if (c.chan<2) {
rWrite(0x4000+c.chan*4,0x30|(chan[c.chan].active?chan[c.chan].outVol:0)|((chan[c.chan].duty&3)<<6));
rWrite(0x4000+c.chan*4,(chan[c.chan].active?((chan[c.chan].envMode<<4)|chan[c.chan].outVol):0x30)|((chan[c.chan].duty&3)<<6));
}
break;
case DIV_CMD_NES_SWEEP:
@ -507,6 +507,24 @@ int DivPlatformNES::dispatch(DivCommand c) {
}
rWrite(0x4001+(c.chan*4),chan[c.chan].sweep);
break;
case DIV_CMD_NES_ENV_MODE:
chan[c.chan].envMode=c.value&3;
if (c.chan==3) { // noise
chan[c.chan].freqChanged=true;
} else if (c.chan<2) {
rWrite(0x4000+c.chan*4,(chan[c.chan].active?((chan[c.chan].envMode<<4)|chan[c.chan].outVol):0x30)|((chan[c.chan].duty&3)<<6));
}
break;
case DIV_CMD_NES_LENGTH:
if (c.chan>=4) break;
chan[c.chan].len=c.value&0x1f;
chan[c.chan].freqChanged=true;
chan[c.chan].prevFreq=-1;
break;
case DIV_CMD_NES_COUNT_MODE:
countMode=c.value;
rWrite(0x4017,countMode?0x80:0);
break;
case DIV_CMD_NES_DMC:
rWrite(0x4011,c.value&0x7f);
break;
@ -572,6 +590,7 @@ void DivPlatformNES::forceIns() {
}
rWrite(0x4001,chan[0].sweep);
rWrite(0x4005,chan[1].sweep);
rWrite(0x4017,countMode?0x80:0);
}
void* DivPlatformNES::getChanState(int ch) {
@ -615,6 +634,7 @@ void DivPlatformNES::reset() {
dpcmBank=0;
dpcmMode=false;
goingToLoop=false;
countMode=false;
if (useNP) {
nes1_NP->Reset();

View file

@ -28,7 +28,7 @@
class DivPlatformNES: public DivDispatch {
struct Channel {
int freq, baseFreq, pitch, pitch2, prevFreq, note, ins;
unsigned char duty, sweep;
unsigned char duty, sweep, envMode, len;
bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac;
signed char vol, outVol, wave;
DivMacroInt std;
@ -46,6 +46,8 @@ class DivPlatformNES: public DivDispatch {
ins(-1),
duty(0),
sweep(8),
envMode(3),
len(0x1f),
active(false),
insChanged(true),
freqChanged(false),
@ -74,6 +76,7 @@ class DivPlatformNES: public DivDispatch {
bool dacAntiClickOn;
bool useNP;
bool goingToLoop;
bool countMode;
struct NESAPU* nes;
xgm::NES_APU* nes1_NP;
xgm::NES_DMC* nes2_NP;

View file

@ -206,6 +206,10 @@ const char* cmdName[]={
"SNES_ECHO_FEEDBACK",
"SNES_ECHO_FIR",
"DIV_CMD_NES_ENV_MODE",
"DIV_CMD_NES_LENGTH",
"DIV_CMD_NES_COUNT_MODE",
"ALWAYS_SET_VOLUME"
};

View file

@ -693,6 +693,9 @@ void DivEngine::registerSystems() {
{0x12, {DIV_CMD_STD_NOISE_MODE, "12xx: Set duty cycle/noise mode (pulse: 0 to 3; noise: 0 or 1)"}},
{0x13, {DIV_CMD_NES_SWEEP, "13xy: Sweep up (x: time; y: shift)",constVal<0>,effectVal}},
{0x14, {DIV_CMD_NES_SWEEP, "14xy: Sweep down (x: time; y: shift)",constVal<1>,effectVal}},
{0x15, {DIV_CMD_NES_ENV_MODE, "15xx: Set envelope mode (0: envelope, 1: length, 2: looping, 3: constant)"}},
{0x16, {DIV_CMD_NES_LENGTH, "16xx: Set length counter (refer to manual for a list of values)"}},
{0x17, {DIV_CMD_NES_COUNT_MODE, "17xx: Set frame counter mode (0: 4-step, 1: 5-step)"}},
{0x18, {DIV_CMD_SAMPLE_MODE, "18xx: Select PCM/DPCM mode (0: PCM; 1: DPCM)"}}
}
);