diff --git a/src/emulator-debug.c b/src/emulator-debug.c index e02e353..0fa3245 100644 --- a/src/emulator-debug.c +++ b/src/emulator-debug.c @@ -65,6 +65,8 @@ static int s_breakpoint_max_id; X(A, V, write_nrx2_initial_volume_abi, "(%#04x, %#02x) initial_volume=%u") \ X(A, V, write_nrx2_zombie_mode_abii, \ "(%#04x, %#02x) zombie mode: volume %u -> %u") \ + X(A, V, write_nrx2_zombie_mode_hack_abi, \ + "(%#04x, %#02x) zombie mode hack: step %u") \ X(A, D, write_nrx4_disable_channel_ab, "(%#04x, %#02x) disabling channel") \ X(A, D, write_nrx4_extra_length_clock_abi, \ "(%#04x, %#02x) extra length clock = %u") \ diff --git a/src/emulator.c b/src/emulator.c index ac3931a..d60819e 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -499,6 +499,7 @@ typedef struct { u8 volume; /* 0..15 */ u32 timer; /* 0..period */ Bool automatic; /* TRUE when MAX/MIN has not yet been reached. */ + u8 zombie_step; /* HACK: support zombie volume decrease */ } Envelope; /* Channel 1 and 2 */ @@ -2893,6 +2894,27 @@ static void write_nrx2_reg(Emulator* e, Channel* channel, Address addr, HOOK(write_nrx2_zombie_mode_abii, addr, value, channel->envelope.volume, new_volume); channel->envelope.volume = new_volume; + // Super ugly hack to support decreasing volume in zombie mode. + channel->envelope.zombie_step = value == 9; + if (value == 9) { + HOOK(write_nrx2_zombie_mode_hack_abi, addr, value, + channel->envelope.zombie_step); + } + } else if (UNLIKELY(channel->envelope.zombie_step > 0)) { + if (channel->envelope.zombie_step == 1 && value == 0x11) { + channel->envelope.zombie_step++; + HOOK(write_nrx2_zombie_mode_hack_abi, addr, value, + channel->envelope.zombie_step); + } else if (channel->envelope.zombie_step == 2 && value == 0x18) { + channel->envelope.zombie_step++; + u8 new_volume = (channel->envelope.volume + ENVELOPE_MAX_VOLUME - 1) & + ENVELOPE_MAX_VOLUME; + HOOK(write_nrx2_zombie_mode_abii, addr, value, channel->envelope.volume, + new_volume); + channel->envelope.volume = new_volume; + } else { + channel->envelope.zombie_step = 0; + } } } channel->envelope.direction = UNPACK(value, NRX2_ENVELOPE_DIRECTION);