aboutsummaryrefslogtreecommitdiff
path: root/source/apu.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/apu.c')
-rw-r--r--source/apu.c1284
1 files changed, 640 insertions, 644 deletions
diff --git a/source/apu.c b/source/apu.c
index e117bd8..a63b42f 100644
--- a/source/apu.c
+++ b/source/apu.c
@@ -1,6 +1,6 @@
/*******************************************************************************
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
-
+
(c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and
Jerremy Koot (jkoot@snes9x.com)
@@ -43,46 +43,46 @@
S-DD1 C emulator code
(c) Copyright 2003 Brad Jorsch with research by
Andreas Naive and John Weidman
-
+
S-RTC C emulator code
(c) Copyright 2001 John Weidman
-
+
ST010 C++ emulator code
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
- Super FX x86 assembler emulator code
- (c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
+ Super FX x86 assembler emulator code
+ (c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
- Super FX C emulator code
+ Super FX C emulator code
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
SH assembler code partly based on x86 assembler code
- (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
+ (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
+
-
Specific ports contains the works of other authors. See headers in
individual files.
-
+
Snes9x homepage: http://www.snes9x.com
-
+
Permission to use, copy, modify and distribute Snes9x in both binary and
source form, for non-commercial purposes, is hereby granted without fee,
providing that this license information and copyright notice appear with
all copies and any derived work.
-
+
This software is provided 'as-is', without any express or implied
warranty. In no event shall the authors be held liable for any damages
arising from the use of this software.
-
+
Snes9x is freeware for PERSONAL USE only. Commercial users should
seek permission of the copyright holders first. Commercial use includes
charging money for Snes9x or software derived from Snes9x.
-
+
The copyright holders request that bug fixes and improvements to the code
should be forwarded to them so everyone can benefit from the modifications
in future versions.
-
+
Super NES and Super Nintendo Entertainment System are trademarks of
Nintendo Co., Limited and its subsidiary companies.
*******************************************************************************/
@@ -101,675 +101,671 @@
/* For note-triggered SPC dump support */
#include "snapshot.h"
-const char *S9xGetFilenameInc (const char *);
+const char* S9xGetFilenameInc(const char*);
-int spc_is_dumping=0;
+int spc_is_dumping = 0;
int spc_is_dumping_temp;
-uint8 spc_dump_dsp[0x100];
+uint8 spc_dump_dsp[0x100];
extern int NoiseFreq [32];
-bool8 S9xInitAPU ()
+bool8 S9xInitAPU()
{
- IAPU.RAM = (uint8 *) malloc (0x10000);
-
- if (!IAPU.RAM)
- {
- S9xDeinitAPU ();
- return (FALSE);
- }
-
- memset(IAPU.RAM, 0, 0x10000);
-
- return (TRUE);
+ IAPU.RAM = (uint8*) malloc(0x10000);
+
+ if (!IAPU.RAM)
+ {
+ S9xDeinitAPU();
+ return (FALSE);
+ }
+
+ memset(IAPU.RAM, 0, 0x10000);
+
+ return (TRUE);
}
-void S9xDeinitAPU ()
+void S9xDeinitAPU()
{
- if (IAPU.RAM)
- {
- free ((char *) IAPU.RAM);
- IAPU.RAM = NULL;
- }
+ if (IAPU.RAM)
+ {
+ free((char*) IAPU.RAM);
+ IAPU.RAM = NULL;
+ }
}
uint8 APUROM [64];
-void S9xResetAPU ()
+void S9xResetAPU()
{
- int i,j;
-
- Settings.APUEnabled = Settings.NextAPUEnabled;
-
- ZeroMemory(spc_dump_dsp, 0x100);
- ZeroMemory(IAPU.RAM, 0x100);
- memset(IAPU.RAM+0x20, 0xFF, 0x20);
- memset(IAPU.RAM+0x60, 0xFF, 0x20);
- memset(IAPU.RAM+0xA0, 0xFF, 0x20);
- memset(IAPU.RAM+0xE0, 0xFF, 0x20);
-
- for(i=1;i<256;i++)
- {
- memcpy(IAPU.RAM+(i<<8), IAPU.RAM, 0x100);
- }
-
- ZeroMemory (APU.OutPorts, 4);
- IAPU.DirectPage = IAPU.RAM;
- // memmove converted: Different mallocs [Neb]
- // DS2 DMA notes: The APU ROM is not 32-byte aligned [Neb]
- memcpy (&IAPU.RAM [0xffc0], APUROM, sizeof (APUROM));
- // memmove converted: Different mallocs [Neb]
- // DS2 DMA notes: The APU ROM is not 32-byte aligned [Neb]
- memcpy (APU.ExtraRAM, APUROM, sizeof (APUROM));
- IAPU.PC = IAPU.RAM + IAPU.RAM [0xfffe] + (IAPU.RAM [0xffff] << 8);
- APU.Cycles = 0;
- IAPU.Registers.YA.W = 0;
- IAPU.Registers.X = 0;
- IAPU.Registers.S = 0xff;
- IAPU.Registers.P = 0;
- S9xAPUUnpackStatus ();
- IAPU.Registers.PC = 0;
- IAPU.APUExecuting = Settings.APUEnabled;
+ int i, j;
+
+ Settings.APUEnabled = Settings.NextAPUEnabled;
+
+ ZeroMemory(spc_dump_dsp, 0x100);
+ ZeroMemory(IAPU.RAM, 0x100);
+ memset(IAPU.RAM + 0x20, 0xFF, 0x20);
+ memset(IAPU.RAM + 0x60, 0xFF, 0x20);
+ memset(IAPU.RAM + 0xA0, 0xFF, 0x20);
+ memset(IAPU.RAM + 0xE0, 0xFF, 0x20);
+
+ for (i = 1; i < 256; i++)
+ memcpy(IAPU.RAM + (i << 8), IAPU.RAM, 0x100);
+
+ ZeroMemory(APU.OutPorts, 4);
+ IAPU.DirectPage = IAPU.RAM;
+ // memmove converted: Different mallocs [Neb]
+ // DS2 DMA notes: The APU ROM is not 32-byte aligned [Neb]
+ memcpy(&IAPU.RAM [0xffc0], APUROM, sizeof(APUROM));
+ // memmove converted: Different mallocs [Neb]
+ // DS2 DMA notes: The APU ROM is not 32-byte aligned [Neb]
+ memcpy(APU.ExtraRAM, APUROM, sizeof(APUROM));
+ IAPU.PC = IAPU.RAM + IAPU.RAM [0xfffe] + (IAPU.RAM [0xffff] << 8);
+ APU.Cycles = 0;
+ IAPU.Registers.YA.W = 0;
+ IAPU.Registers.X = 0;
+ IAPU.Registers.S = 0xff;
+ IAPU.Registers.P = 0;
+ S9xAPUUnpackStatus();
+ IAPU.Registers.PC = 0;
+ IAPU.APUExecuting = Settings.APUEnabled;
#ifdef SPC700_SHUTDOWN
- IAPU.WaitAddress1 = NULL;
- IAPU.WaitAddress2 = NULL;
- IAPU.WaitCounter = 0;
+ IAPU.WaitAddress1 = NULL;
+ IAPU.WaitAddress2 = NULL;
+ IAPU.WaitCounter = 0;
#endif
- APU.ShowROM = TRUE;
- IAPU.RAM [0xf1] = 0x80;
-
- for (i = 0; i < 3; i++)
- {
- APU.TimerEnabled [i] = FALSE;
- APU.TimerValueWritten [i] = 0;
- APU.TimerTarget [i] = 0;
- APU.Timer [i] = 0;
- }
- for (j = 0; j < 0x80; j++)
- APU.DSP [j] = 0;
-
- IAPU.TwoCycles = IAPU.OneCycle * 2;
-
- for (i = 0; i < 256; i++)
- S9xAPUCycles [i] = S9xAPUCycleLengths [i] * IAPU.OneCycle;
-
- APU.DSP [APU_ENDX] = 0;
- APU.DSP [APU_KOFF] = 0;
- APU.DSP [APU_KON] = 0;
- APU.DSP [APU_FLG] = APU_MUTE | APU_ECHO_DISABLED;
- APU.KeyedChannels = 0;
-
- S9xResetSound (TRUE);
- S9xSetEchoEnable (0);
+ APU.ShowROM = TRUE;
+ IAPU.RAM [0xf1] = 0x80;
+
+ for (i = 0; i < 3; i++)
+ {
+ APU.TimerEnabled [i] = FALSE;
+ APU.TimerValueWritten [i] = 0;
+ APU.TimerTarget [i] = 0;
+ APU.Timer [i] = 0;
+ }
+ for (j = 0; j < 0x80; j++)
+ APU.DSP [j] = 0;
+
+ IAPU.TwoCycles = IAPU.OneCycle * 2;
+
+ for (i = 0; i < 256; i++)
+ S9xAPUCycles [i] = S9xAPUCycleLengths [i] * IAPU.OneCycle;
+
+ APU.DSP [APU_ENDX] = 0;
+ APU.DSP [APU_KOFF] = 0;
+ APU.DSP [APU_KON] = 0;
+ APU.DSP [APU_FLG] = APU_MUTE | APU_ECHO_DISABLED;
+ APU.KeyedChannels = 0;
+
+ S9xResetSound(TRUE);
+ S9xSetEchoEnable(0);
}
-void S9xSetAPUDSP (uint8 byte)
+void S9xSetAPUDSP(uint8 byte)
{
- uint8 reg = IAPU.RAM [0xf2];
- static uint8 KeyOn;
- static uint8 KeyOnPrev;
- int i;
-
- spc_dump_dsp[reg] = byte;
-
- switch (reg)
- {
- case APU_FLG:
- if (byte & APU_SOFT_RESET)
- {
- APU.DSP [reg] = APU_MUTE | APU_ECHO_DISABLED | (byte & 0x1f);
- APU.DSP [APU_ENDX] = 0;
- APU.DSP [APU_KOFF] = 0;
- APU.DSP [APU_KON] = 0;
- S9xSetEchoWriteEnable (FALSE);
+ uint8 reg = IAPU.RAM [0xf2];
+ static uint8 KeyOn;
+ static uint8 KeyOnPrev;
+ int i;
+
+ spc_dump_dsp[reg] = byte;
+
+ switch (reg)
+ {
+ case APU_FLG:
+ if (byte & APU_SOFT_RESET)
+ {
+ APU.DSP [reg] = APU_MUTE | APU_ECHO_DISABLED | (byte & 0x1f);
+ APU.DSP [APU_ENDX] = 0;
+ APU.DSP [APU_KOFF] = 0;
+ APU.DSP [APU_KON] = 0;
+ S9xSetEchoWriteEnable(FALSE);
// Kill sound
- S9xResetSound (FALSE);
- }
- else
- {
- S9xSetEchoWriteEnable (!(byte & APU_ECHO_DISABLED));
- if (byte & APU_MUTE)
- {
- S9xSetSoundMute (TRUE);
- }
- else
- S9xSetSoundMute (FALSE);
-
- SoundData.noise_hertz = NoiseFreq [byte & 0x1f];
- for (i = 0; i < 8; i++)
- {
- if (SoundData.channels [i].type == SOUND_NOISE)
- S9xSetSoundFrequency (i, SoundData.noise_hertz);
- }
- }
- break;
- case APU_NON:
- if (byte != APU.DSP [APU_NON])
- {
- int c;
- uint8 mask = 1;
- for (c = 0; c < 8; c++, mask <<= 1)
- {
- int type;
-
- if (byte & mask)
- type = SOUND_NOISE;
- else
- type = SOUND_SAMPLE;
-
- S9xSetSoundType (c, type);
- }
- }
- break;
- case APU_MVOL_LEFT:
- if (byte != APU.DSP [APU_MVOL_LEFT])
- {
- S9xSetMasterVolume ((signed char) byte,
- (signed char) APU.DSP [APU_MVOL_RIGHT]);
- }
- break;
- case APU_MVOL_RIGHT:
- if (byte != APU.DSP [APU_MVOL_RIGHT])
- {
- S9xSetMasterVolume ((signed char) APU.DSP [APU_MVOL_LEFT],
- (signed char) byte);
- }
- break;
- case APU_EVOL_LEFT:
- if (byte != APU.DSP [APU_EVOL_LEFT])
- {
- S9xSetEchoVolume ((signed char) byte,
- (signed char) APU.DSP [APU_EVOL_RIGHT]);
- }
- break;
- case APU_EVOL_RIGHT:
- if (byte != APU.DSP [APU_EVOL_RIGHT])
- {
- S9xSetEchoVolume ((signed char) APU.DSP [APU_EVOL_LEFT],
- (signed char) byte);
- }
- break;
- case APU_ENDX:
- byte = 0;
- break;
-
- case APU_KOFF:
- // if (byte)
- {
+ S9xResetSound(FALSE);
+ }
+ else
+ {
+ S9xSetEchoWriteEnable(!(byte & APU_ECHO_DISABLED));
+ if (byte & APU_MUTE)
+ S9xSetSoundMute(TRUE);
+ else
+ S9xSetSoundMute(FALSE);
+
+ SoundData.noise_hertz = NoiseFreq [byte & 0x1f];
+ for (i = 0; i < 8; i++)
+ {
+ if (SoundData.channels [i].type == SOUND_NOISE)
+ S9xSetSoundFrequency(i, SoundData.noise_hertz);
+ }
+ }
+ break;
+ case APU_NON:
+ if (byte != APU.DSP [APU_NON])
+ {
int c;
- uint8 mask = 1;
+ uint8 mask = 1;
for (c = 0; c < 8; c++, mask <<= 1)
- {
- if ((byte & mask) != 0)
- {
- if (APU.KeyedChannels & mask)
- {
- {
- KeyOnPrev&=~mask;
- APU.KeyedChannels &= ~mask;
- APU.DSP [APU_KON] &= ~mask;
- //APU.DSP [APU_KOFF] |= mask;
- S9xSetSoundKeyOff (c);
- }
- }
- }
- else if((KeyOnPrev&mask)!=0)
- {
- KeyOnPrev&=~mask;
- APU.KeyedChannels |= mask;
- //APU.DSP [APU_KON] |= mask;
- APU.DSP [APU_KOFF] &= ~mask;
- APU.DSP [APU_ENDX] &= ~mask;
- S9xPlaySample (c);
- }
- }
- }
- //KeyOnPrev=0;
- APU.DSP [APU_KOFF] = byte;
- return;
- case APU_KON:
- if (spc_is_dumping)
- {
- if (byte & ~spc_is_dumping_temp)
- {
- IAPU.Registers.PC = IAPU.PC - IAPU.RAM;
- S9xAPUPackStatus();
- S9xSPCDump (".spc");
- spc_is_dumping = 0;
- }
- }
- if (byte)
- {
+ {
+ int type;
+
+ if (byte & mask)
+ type = SOUND_NOISE;
+ else
+ type = SOUND_SAMPLE;
+
+ S9xSetSoundType(c, type);
+ }
+ }
+ break;
+ case APU_MVOL_LEFT:
+ if (byte != APU.DSP [APU_MVOL_LEFT])
+ {
+ S9xSetMasterVolume((signed char) byte,
+ (signed char) APU.DSP [APU_MVOL_RIGHT]);
+ }
+ break;
+ case APU_MVOL_RIGHT:
+ if (byte != APU.DSP [APU_MVOL_RIGHT])
+ {
+ S9xSetMasterVolume((signed char) APU.DSP [APU_MVOL_LEFT],
+ (signed char) byte);
+ }
+ break;
+ case APU_EVOL_LEFT:
+ if (byte != APU.DSP [APU_EVOL_LEFT])
+ {
+ S9xSetEchoVolume((signed char) byte,
+ (signed char) APU.DSP [APU_EVOL_RIGHT]);
+ }
+ break;
+ case APU_EVOL_RIGHT:
+ if (byte != APU.DSP [APU_EVOL_RIGHT])
+ {
+ S9xSetEchoVolume((signed char) APU.DSP [APU_EVOL_LEFT],
+ (signed char) byte);
+ }
+ break;
+ case APU_ENDX:
+ byte = 0;
+ break;
+
+ case APU_KOFF:
+ // if (byte)
+ {
+ int c;
+ uint8 mask = 1;
+ for (c = 0; c < 8; c++, mask <<= 1)
+ {
+ if ((byte & mask) != 0)
+ {
+ if (APU.KeyedChannels & mask)
+ {
+ {
+ KeyOnPrev &= ~mask;
+ APU.KeyedChannels &= ~mask;
+ APU.DSP [APU_KON] &= ~mask;
+ //APU.DSP [APU_KOFF] |= mask;
+ S9xSetSoundKeyOff(c);
+ }
+ }
+ }
+ else if ((KeyOnPrev & mask) != 0)
+ {
+ KeyOnPrev &= ~mask;
+ APU.KeyedChannels |= mask;
+ //APU.DSP [APU_KON] |= mask;
+ APU.DSP [APU_KOFF] &= ~mask;
+ APU.DSP [APU_ENDX] &= ~mask;
+ S9xPlaySample(c);
+ }
+ }
+ }
+ //KeyOnPrev=0;
+ APU.DSP [APU_KOFF] = byte;
+ return;
+ case APU_KON:
+ if (spc_is_dumping)
+ {
+ if (byte & ~spc_is_dumping_temp)
+ {
+ IAPU.Registers.PC = IAPU.PC - IAPU.RAM;
+ S9xAPUPackStatus();
+ S9xSPCDump(".spc");
+ spc_is_dumping = 0;
+ }
+ }
+ if (byte)
+ {
int c;
- uint8 mask = 1;
+ uint8 mask = 1;
for (c = 0; c < 8; c++, mask <<= 1)
- {
- if ((byte & mask) != 0)
- {
- // Pac-In-Time requires that channels can be key-on
- // regardeless of their current state.
- if((APU.DSP [APU_KOFF] & mask) ==0)
- {
- KeyOnPrev&=~mask;
- APU.KeyedChannels |= mask;
- //APU.DSP [APU_KON] |= mask;
- //APU.DSP [APU_KOFF] &= ~mask;
- APU.DSP [APU_ENDX] &= ~mask;
- S9xPlaySample (c);
- }
- else KeyOn|=mask;
- }
- }
- }
- spc_is_dumping_temp = byte;
- return;
-
- case APU_VOL_LEFT + 0x00:
- case APU_VOL_LEFT + 0x10:
- case APU_VOL_LEFT + 0x20:
- case APU_VOL_LEFT + 0x30:
- case APU_VOL_LEFT + 0x40:
- case APU_VOL_LEFT + 0x50:
- case APU_VOL_LEFT + 0x60:
- case APU_VOL_LEFT + 0x70:
- // At Shin Megami Tensei suggestion 6/11/00
- // if (byte != APU.DSP [reg])
- {
- S9xSetSoundVolume (reg >> 4, (signed char) byte,
- (signed char) APU.DSP [reg + 1]);
- }
- break;
- case APU_VOL_RIGHT + 0x00:
- case APU_VOL_RIGHT + 0x10:
- case APU_VOL_RIGHT + 0x20:
- case APU_VOL_RIGHT + 0x30:
- case APU_VOL_RIGHT + 0x40:
- case APU_VOL_RIGHT + 0x50:
- case APU_VOL_RIGHT + 0x60:
- case APU_VOL_RIGHT + 0x70:
- // At Shin Megami Tensei suggestion 6/11/00
- // if (byte != APU.DSP [reg])
- {
- S9xSetSoundVolume (reg >> 4, (signed char) APU.DSP [reg - 1],
- (signed char) byte);
- }
- break;
-
- case APU_P_LOW + 0x00:
- case APU_P_LOW + 0x10:
- case APU_P_LOW + 0x20:
- case APU_P_LOW + 0x30:
- case APU_P_LOW + 0x40:
- case APU_P_LOW + 0x50:
- case APU_P_LOW + 0x60:
- case APU_P_LOW + 0x70:
- S9xSetSoundHertz (reg >> 4, ((byte + (APU.DSP [reg + 1] << 8)) & FREQUENCY_MASK) * 8);
- break;
-
- case APU_P_HIGH + 0x00:
- case APU_P_HIGH + 0x10:
- case APU_P_HIGH + 0x20:
- case APU_P_HIGH + 0x30:
- case APU_P_HIGH + 0x40:
- case APU_P_HIGH + 0x50:
- case APU_P_HIGH + 0x60:
- case APU_P_HIGH + 0x70:
- S9xSetSoundHertz (reg >> 4,
- (((byte << 8) + APU.DSP [reg - 1]) & FREQUENCY_MASK) * 8);
- break;
-
- case APU_SRCN + 0x00:
- case APU_SRCN + 0x10:
- case APU_SRCN + 0x20:
- case APU_SRCN + 0x30:
- case APU_SRCN + 0x40:
- case APU_SRCN + 0x50:
- case APU_SRCN + 0x60:
- case APU_SRCN + 0x70:
- if (byte != APU.DSP [reg])
- {
- S9xSetSoundSample (reg >> 4, byte);
- }
- break;
-
- case APU_ADSR1 + 0x00:
- case APU_ADSR1 + 0x10:
- case APU_ADSR1 + 0x20:
- case APU_ADSR1 + 0x30:
- case APU_ADSR1 + 0x40:
- case APU_ADSR1 + 0x50:
- case APU_ADSR1 + 0x60:
- case APU_ADSR1 + 0x70:
- if (byte != APU.DSP [reg])
- {
- {
- S9xFixEnvelope (reg >> 4, APU.DSP [reg + 2], byte,
- APU.DSP [reg + 1]);
- }
- }
- break;
-
- case APU_ADSR2 + 0x00:
- case APU_ADSR2 + 0x10:
- case APU_ADSR2 + 0x20:
- case APU_ADSR2 + 0x30:
- case APU_ADSR2 + 0x40:
- case APU_ADSR2 + 0x50:
- case APU_ADSR2 + 0x60:
- case APU_ADSR2 + 0x70:
- if (byte != APU.DSP [reg])
- {
- {
- S9xFixEnvelope (reg >> 4, APU.DSP [reg + 1], APU.DSP [reg - 1],
- byte);
- }
- }
- break;
-
- case APU_GAIN + 0x00:
- case APU_GAIN + 0x10:
- case APU_GAIN + 0x20:
- case APU_GAIN + 0x30:
- case APU_GAIN + 0x40:
- case APU_GAIN + 0x50:
- case APU_GAIN + 0x60:
- case APU_GAIN + 0x70:
- if (byte != APU.DSP [reg])
- {
- {
- S9xFixEnvelope (reg >> 4, byte, APU.DSP [reg - 2],
- APU.DSP [reg - 1]);
- }
- }
- break;
-
- case APU_ENVX + 0x00:
- case APU_ENVX + 0x10:
- case APU_ENVX + 0x20:
- case APU_ENVX + 0x30:
- case APU_ENVX + 0x40:
- case APU_ENVX + 0x50:
- case APU_ENVX + 0x60:
- case APU_ENVX + 0x70:
- break;
-
- case APU_OUTX + 0x00:
- case APU_OUTX + 0x10:
- case APU_OUTX + 0x20:
- case APU_OUTX + 0x30:
- case APU_OUTX + 0x40:
- case APU_OUTX + 0x50:
- case APU_OUTX + 0x60:
- case APU_OUTX + 0x70:
- break;
-
- case APU_DIR:
- break;
-
- case APU_PMON:
- if (byte != APU.DSP [APU_PMON])
- {
- S9xSetFrequencyModulationEnable (byte);
- }
- break;
-
- case APU_EON:
- if (byte != APU.DSP [APU_EON])
- {
- S9xSetEchoEnable (byte);
- }
- break;
-
- case APU_EFB:
- S9xSetEchoFeedback ((signed char) byte);
- break;
-
- case APU_ESA:
- break;
-
- case APU_EDL:
- S9xSetEchoDelay (byte & 0xf);
- break;
-
- case APU_C0:
- case APU_C1:
- case APU_C2:
- case APU_C3:
- case APU_C4:
- case APU_C5:
- case APU_C6:
- case APU_C7:
- S9xSetFilterCoefficient (reg >> 4, (signed char) byte);
- break;
- default:
- // XXX
- //printf ("Write %02x to unknown APU register %02x\n", byte, reg);
- break;
- }
-
- KeyOnPrev|=KeyOn;
- KeyOn=0;
-
- if (reg < 0x80)
- APU.DSP [reg] = byte;
+ {
+ if ((byte & mask) != 0)
+ {
+ // Pac-In-Time requires that channels can be key-on
+ // regardeless of their current state.
+ if ((APU.DSP [APU_KOFF] & mask) == 0)
+ {
+ KeyOnPrev &= ~mask;
+ APU.KeyedChannels |= mask;
+ //APU.DSP [APU_KON] |= mask;
+ //APU.DSP [APU_KOFF] &= ~mask;
+ APU.DSP [APU_ENDX] &= ~mask;
+ S9xPlaySample(c);
+ }
+ else KeyOn |= mask;
+ }
+ }
+ }
+ spc_is_dumping_temp = byte;
+ return;
+
+ case APU_VOL_LEFT + 0x00:
+ case APU_VOL_LEFT + 0x10:
+ case APU_VOL_LEFT + 0x20:
+ case APU_VOL_LEFT + 0x30:
+ case APU_VOL_LEFT + 0x40:
+ case APU_VOL_LEFT + 0x50:
+ case APU_VOL_LEFT + 0x60:
+ case APU_VOL_LEFT + 0x70:
+ // At Shin Megami Tensei suggestion 6/11/00
+ // if (byte != APU.DSP [reg])
+ {
+ S9xSetSoundVolume(reg >> 4, (signed char) byte,
+ (signed char) APU.DSP [reg + 1]);
+ }
+ break;
+ case APU_VOL_RIGHT + 0x00:
+ case APU_VOL_RIGHT + 0x10:
+ case APU_VOL_RIGHT + 0x20:
+ case APU_VOL_RIGHT + 0x30:
+ case APU_VOL_RIGHT + 0x40:
+ case APU_VOL_RIGHT + 0x50:
+ case APU_VOL_RIGHT + 0x60:
+ case APU_VOL_RIGHT + 0x70:
+ // At Shin Megami Tensei suggestion 6/11/00
+ // if (byte != APU.DSP [reg])
+ {
+ S9xSetSoundVolume(reg >> 4, (signed char) APU.DSP [reg - 1],
+ (signed char) byte);
+ }
+ break;
+
+ case APU_P_LOW + 0x00:
+ case APU_P_LOW + 0x10:
+ case APU_P_LOW + 0x20:
+ case APU_P_LOW + 0x30:
+ case APU_P_LOW + 0x40:
+ case APU_P_LOW + 0x50:
+ case APU_P_LOW + 0x60:
+ case APU_P_LOW + 0x70:
+ S9xSetSoundHertz(reg >> 4,
+ ((byte + (APU.DSP [reg + 1] << 8)) & FREQUENCY_MASK) * 8);
+ break;
+
+ case APU_P_HIGH + 0x00:
+ case APU_P_HIGH + 0x10:
+ case APU_P_HIGH + 0x20:
+ case APU_P_HIGH + 0x30:
+ case APU_P_HIGH + 0x40:
+ case APU_P_HIGH + 0x50:
+ case APU_P_HIGH + 0x60:
+ case APU_P_HIGH + 0x70:
+ S9xSetSoundHertz(reg >> 4,
+ (((byte << 8) + APU.DSP [reg - 1]) & FREQUENCY_MASK) * 8);
+ break;
+
+ case APU_SRCN + 0x00:
+ case APU_SRCN + 0x10:
+ case APU_SRCN + 0x20:
+ case APU_SRCN + 0x30:
+ case APU_SRCN + 0x40:
+ case APU_SRCN + 0x50:
+ case APU_SRCN + 0x60:
+ case APU_SRCN + 0x70:
+ if (byte != APU.DSP [reg])
+ S9xSetSoundSample(reg >> 4, byte);
+ break;
+
+ case APU_ADSR1 + 0x00:
+ case APU_ADSR1 + 0x10:
+ case APU_ADSR1 + 0x20:
+ case APU_ADSR1 + 0x30:
+ case APU_ADSR1 + 0x40:
+ case APU_ADSR1 + 0x50:
+ case APU_ADSR1 + 0x60:
+ case APU_ADSR1 + 0x70:
+ if (byte != APU.DSP [reg])
+ {
+ {
+ S9xFixEnvelope(reg >> 4, APU.DSP [reg + 2], byte,
+ APU.DSP [reg + 1]);
+ }
+ }
+ break;
+
+ case APU_ADSR2 + 0x00:
+ case APU_ADSR2 + 0x10:
+ case APU_ADSR2 + 0x20:
+ case APU_ADSR2 + 0x30:
+ case APU_ADSR2 + 0x40:
+ case APU_ADSR2 + 0x50:
+ case APU_ADSR2 + 0x60:
+ case APU_ADSR2 + 0x70:
+ if (byte != APU.DSP [reg])
+ {
+ {
+ S9xFixEnvelope(reg >> 4, APU.DSP [reg + 1], APU.DSP [reg - 1],
+ byte);
+ }
+ }
+ break;
+
+ case APU_GAIN + 0x00:
+ case APU_GAIN + 0x10:
+ case APU_GAIN + 0x20:
+ case APU_GAIN + 0x30:
+ case APU_GAIN + 0x40:
+ case APU_GAIN + 0x50:
+ case APU_GAIN + 0x60:
+ case APU_GAIN + 0x70:
+ if (byte != APU.DSP [reg])
+ {
+ {
+ S9xFixEnvelope(reg >> 4, byte, APU.DSP [reg - 2],
+ APU.DSP [reg - 1]);
+ }
+ }
+ break;
+
+ case APU_ENVX + 0x00:
+ case APU_ENVX + 0x10:
+ case APU_ENVX + 0x20:
+ case APU_ENVX + 0x30:
+ case APU_ENVX + 0x40:
+ case APU_ENVX + 0x50:
+ case APU_ENVX + 0x60:
+ case APU_ENVX + 0x70:
+ break;
+
+ case APU_OUTX + 0x00:
+ case APU_OUTX + 0x10:
+ case APU_OUTX + 0x20:
+ case APU_OUTX + 0x30:
+ case APU_OUTX + 0x40:
+ case APU_OUTX + 0x50:
+ case APU_OUTX + 0x60:
+ case APU_OUTX + 0x70:
+ break;
+
+ case APU_DIR:
+ break;
+
+ case APU_PMON:
+ if (byte != APU.DSP [APU_PMON])
+ S9xSetFrequencyModulationEnable(byte);
+ break;
+
+ case APU_EON:
+ if (byte != APU.DSP [APU_EON])
+ S9xSetEchoEnable(byte);
+ break;
+
+ case APU_EFB:
+ S9xSetEchoFeedback((signed char) byte);
+ break;
+
+ case APU_ESA:
+ break;
+
+ case APU_EDL:
+ S9xSetEchoDelay(byte & 0xf);
+ break;
+
+ case APU_C0:
+ case APU_C1:
+ case APU_C2:
+ case APU_C3:
+ case APU_C4:
+ case APU_C5:
+ case APU_C6:
+ case APU_C7:
+ S9xSetFilterCoefficient(reg >> 4, (signed char) byte);
+ break;
+ default:
+ // XXX
+ //printf ("Write %02x to unknown APU register %02x\n", byte, reg);
+ break;
+ }
+
+ KeyOnPrev |= KeyOn;
+ KeyOn = 0;
+
+ if (reg < 0x80)
+ APU.DSP [reg] = byte;
}
-void S9xFixEnvelope (int channel, uint8 gain, uint8 adsr1, uint8 adsr2)
+void S9xFixEnvelope(int channel, uint8 gain, uint8 adsr1, uint8 adsr2)
{
- if (adsr1 & 0x80)
- {
- // ADSR mode
- static unsigned long AttackRate [16] = {
- 4100, 2600, 1500, 1000, 640, 380, 260, 160,
- 96, 64, 40, 24, 16, 10, 6, 1
- };
- static unsigned long DecayRate [8] = {
- 1200, 740, 440, 290, 180, 110, 74, 37
- };
- static unsigned long SustainRate [32] = {
- ~0, 38000, 28000, 24000, 19000, 14000, 12000, 9400,
- 7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500,
- 1200, 880, 740, 590, 440, 370, 290, 220,
- 180, 150, 110, 92, 74, 55, 37, 18
- };
- // XXX: can DSP be switched to ADSR mode directly from GAIN/INCREASE/
- // DECREASE mode? And if so, what stage of the sequence does it start
- // at?
- if (S9xSetSoundMode (channel, MODE_ADSR))
- {
- // Hack for ROMs that use a very short attack rate, key on a
- // channel, then switch to decay mode. e.g. Final Fantasy II.
-
- int attack = AttackRate [adsr1 & 0xf];
-
- if (attack == 1 && (!Settings.SoundSync
+ if (adsr1 & 0x80)
+ {
+ // ADSR mode
+ static unsigned long AttackRate [16] =
+ {
+ 4100, 2600, 1500, 1000, 640, 380, 260, 160,
+ 96, 64, 40, 24, 16, 10, 6, 1
+ };
+ static unsigned long DecayRate [8] =
+ {
+ 1200, 740, 440, 290, 180, 110, 74, 37
+ };
+ static unsigned long SustainRate [32] =
+ {
+ ~0, 38000, 28000, 24000, 19000, 14000, 12000, 9400,
+ 7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500,
+ 1200, 880, 740, 590, 440, 370, 290, 220,
+ 180, 150, 110, 92, 74, 55, 37, 18
+ };
+ // XXX: can DSP be switched to ADSR mode directly from GAIN/INCREASE/
+ // DECREASE mode? And if so, what stage of the sequence does it start
+ // at?
+ if (S9xSetSoundMode(channel, MODE_ADSR))
+ {
+ // Hack for ROMs that use a very short attack rate, key on a
+ // channel, then switch to decay mode. e.g. Final Fantasy II.
+
+ int attack = AttackRate [adsr1 & 0xf];
+
+ if (attack == 1 && (!Settings.SoundSync
#ifdef __WIN32__
- || Settings.SoundDriver != WIN_SNES9X_DIRECT_SOUND_DRIVER
+ || Settings.SoundDriver != WIN_SNES9X_DIRECT_SOUND_DRIVER
#endif
- ))
- attack = 0;
-
- S9xSetSoundADSR (channel, attack,
- DecayRate [(adsr1 >> 4) & 7],
- SustainRate [adsr2 & 0x1f],
- (adsr2 >> 5) & 7, 8);
- }
- }
- else
- {
- // Gain mode
- if ((gain & 0x80) == 0)
- {
- if (S9xSetSoundMode (channel, MODE_GAIN))
- {
- S9xSetEnvelopeRate (channel, 0, 0, gain & 0x7f);
- S9xSetEnvelopeHeight (channel, gain & 0x7f);
- }
- }
- else
- {
- static unsigned long IncreaseRate [32] = {
- ~0, 4100, 3100, 2600, 2000, 1500, 1300, 1000,
- 770, 640, 510, 380, 320, 260, 190, 160,
- 130, 96, 80, 64, 48, 40, 32, 24,
- 20, 16, 12, 10, 8, 6, 4, 2
- };
- static unsigned long DecreaseRateExp [32] = {
- ~0, 38000, 28000, 24000, 19000, 14000, 12000, 9400,
- 7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500,
- 1200, 880, 740, 590, 440, 370, 290, 220,
- 180, 150, 110, 92, 74, 55, 37, 18
- };
- if (gain & 0x40)
- {
- // Increase mode
- if (S9xSetSoundMode (channel, (gain & 0x20) ?
-MODE_INCREASE_BENT_LINE :
- MODE_INCREASE_LINEAR))
- {
- S9xSetEnvelopeRate (channel, IncreaseRate [gain & 0x1f],
- 1, 127);
- }
- }
- else
- {
- uint32 rate = (gain & 0x20) ? DecreaseRateExp [gain & 0x1f] / 2 :
- IncreaseRate [gain & 0x1f];
- int mode = (gain & 0x20) ? MODE_DECREASE_EXPONENTIAL
- : MODE_DECREASE_LINEAR;
-
- if (S9xSetSoundMode (channel, mode))
- S9xSetEnvelopeRate (channel, rate, -1, 0);
- }
- }
- }
+ ))
+ attack = 0;
+
+ S9xSetSoundADSR(channel, attack,
+ DecayRate [(adsr1 >> 4) & 7],
+ SustainRate [adsr2 & 0x1f],
+ (adsr2 >> 5) & 7, 8);
+ }
+ }
+ else
+ {
+ // Gain mode
+ if ((gain & 0x80) == 0)
+ {
+ if (S9xSetSoundMode(channel, MODE_GAIN))
+ {
+ S9xSetEnvelopeRate(channel, 0, 0, gain & 0x7f);
+ S9xSetEnvelopeHeight(channel, gain & 0x7f);
+ }
+ }
+ else
+ {
+ static unsigned long IncreaseRate [32] =
+ {
+ ~0, 4100, 3100, 2600, 2000, 1500, 1300, 1000,
+ 770, 640, 510, 380, 320, 260, 190, 160,
+ 130, 96, 80, 64, 48, 40, 32, 24,
+ 20, 16, 12, 10, 8, 6, 4, 2
+ };
+ static unsigned long DecreaseRateExp [32] =
+ {
+ ~0, 38000, 28000, 24000, 19000, 14000, 12000, 9400,
+ 7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500,
+ 1200, 880, 740, 590, 440, 370, 290, 220,
+ 180, 150, 110, 92, 74, 55, 37, 18
+ };
+ if (gain & 0x40)
+ {
+ // Increase mode
+ if (S9xSetSoundMode(channel, (gain & 0x20) ?
+ MODE_INCREASE_BENT_LINE :
+ MODE_INCREASE_LINEAR))
+ {
+ S9xSetEnvelopeRate(channel, IncreaseRate [gain & 0x1f],
+ 1, 127);
+ }
+ }
+ else
+ {
+ uint32 rate = (gain & 0x20) ? DecreaseRateExp [gain & 0x1f] / 2 :
+ IncreaseRate [gain & 0x1f];
+ int mode = (gain & 0x20) ? MODE_DECREASE_EXPONENTIAL
+ : MODE_DECREASE_LINEAR;
+
+ if (S9xSetSoundMode(channel, mode))
+ S9xSetEnvelopeRate(channel, rate, -1, 0);
+ }
+ }
+ }
}
-void S9xSetAPUControl (uint8 byte)
+void S9xSetAPUControl(uint8 byte)
{
- //if (byte & 0x40)
- //printf ("*** Special SPC700 timing enabled\n");
- if ((byte & 1) != 0 && !APU.TimerEnabled [0])
- {
- APU.Timer [0] = 0;
- IAPU.RAM [0xfd] = 0;
- if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0)
- APU.TimerTarget [0] = 0x100;
- }
- if ((byte & 2) != 0 && !APU.TimerEnabled [1])
- {
- APU.Timer [1] = 0;
- IAPU.RAM [0xfe] = 0;
- if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0)
- APU.TimerTarget [1] = 0x100;
- }
- if ((byte & 4) != 0 && !APU.TimerEnabled [2])
- {
- APU.Timer [2] = 0;
- IAPU.RAM [0xff] = 0;
- if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0)
- APU.TimerTarget [2] = 0x100;
- }
- APU.TimerEnabled [0] = byte & 1;
- APU.TimerEnabled [1] = (byte & 2) >> 1;
- APU.TimerEnabled [2] = (byte & 4) >> 2;
-
- if (byte & 0x10)
- IAPU.RAM [0xF4] = IAPU.RAM [0xF5] = 0;
-
- if (byte & 0x20)
- IAPU.RAM [0xF6] = IAPU.RAM [0xF7] = 0;
-
- if (byte & 0x80)
- {
- if (!APU.ShowROM)
- {
- // memmove converted: Different mallocs [Neb]
- // DS2 DMA notes: The APU ROM is not 32-byte aligned [Neb]
- memcpy (&IAPU.RAM [0xffc0], APUROM, sizeof (APUROM));
- APU.ShowROM = TRUE;
- }
- }
- else
- {
- if (APU.ShowROM)
- {
- APU.ShowROM = FALSE;
- // memmove converted: Different mallocs [Neb]
- // DS2 DMA notes: The APU ROM is not 32-byte aligned [Neb]
- memcpy (&IAPU.RAM [0xffc0], APU.ExtraRAM, sizeof (APUROM));
- }
- }
- IAPU.RAM [0xf1] = byte;
+ //if (byte & 0x40)
+ //printf ("*** Special SPC700 timing enabled\n");
+ if ((byte & 1) != 0 && !APU.TimerEnabled [0])
+ {
+ APU.Timer [0] = 0;
+ IAPU.RAM [0xfd] = 0;
+ if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0)
+ APU.TimerTarget [0] = 0x100;
+ }
+ if ((byte & 2) != 0 && !APU.TimerEnabled [1])
+ {
+ APU.Timer [1] = 0;
+ IAPU.RAM [0xfe] = 0;
+ if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0)
+ APU.TimerTarget [1] = 0x100;
+ }
+ if ((byte & 4) != 0 && !APU.TimerEnabled [2])
+ {
+ APU.Timer [2] = 0;
+ IAPU.RAM [0xff] = 0;
+ if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0)
+ APU.TimerTarget [2] = 0x100;
+ }
+ APU.TimerEnabled [0] = byte & 1;
+ APU.TimerEnabled [1] = (byte & 2) >> 1;
+ APU.TimerEnabled [2] = (byte & 4) >> 2;
+
+ if (byte & 0x10)
+ IAPU.RAM [0xF4] = IAPU.RAM [0xF5] = 0;
+
+ if (byte & 0x20)
+ IAPU.RAM [0xF6] = IAPU.RAM [0xF7] = 0;
+
+ if (byte & 0x80)
+ {
+ if (!APU.ShowROM)
+ {
+ // memmove converted: Different mallocs [Neb]
+ // DS2 DMA notes: The APU ROM is not 32-byte aligned [Neb]
+ memcpy(&IAPU.RAM [0xffc0], APUROM, sizeof(APUROM));
+ APU.ShowROM = TRUE;
+ }
+ }
+ else
+ {
+ if (APU.ShowROM)
+ {
+ APU.ShowROM = FALSE;
+ // memmove converted: Different mallocs [Neb]
+ // DS2 DMA notes: The APU ROM is not 32-byte aligned [Neb]
+ memcpy(&IAPU.RAM [0xffc0], APU.ExtraRAM, sizeof(APUROM));
+ }
+ }
+ IAPU.RAM [0xf1] = byte;
}
-void S9xSetAPUTimer (uint16 Address, uint8 byte)
+void S9xSetAPUTimer(uint16 Address, uint8 byte)
{
- IAPU.RAM [Address] = byte;
-
- switch (Address)
- {
- case 0xfa:
- if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0)
- APU.TimerTarget [0] = 0x100;
- APU.TimerValueWritten [0] = TRUE;
- break;
- case 0xfb:
- if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0)
- APU.TimerTarget [1] = 0x100;
- APU.TimerValueWritten [1] = TRUE;
- break;
- case 0xfc:
- if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0)
- APU.TimerTarget [2] = 0x100;
- APU.TimerValueWritten [2] = TRUE;
- break;
- }
+ IAPU.RAM [Address] = byte;
+
+ switch (Address)
+ {
+ case 0xfa:
+ if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0)
+ APU.TimerTarget [0] = 0x100;
+ APU.TimerValueWritten [0] = TRUE;
+ break;
+ case 0xfb:
+ if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0)
+ APU.TimerTarget [1] = 0x100;
+ APU.TimerValueWritten [1] = TRUE;
+ break;
+ case 0xfc:
+ if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0)
+ APU.TimerTarget [2] = 0x100;
+ APU.TimerValueWritten [2] = TRUE;
+ break;
+ }
}
-uint8 S9xGetAPUDSP ()
+uint8 S9xGetAPUDSP()
{
- uint8 reg = IAPU.RAM [0xf2] & 0x7f;
- uint8 byte = APU.DSP [reg];
-
- switch (reg)
- {
- case APU_KON:
- break;
- case APU_KOFF:
- break;
- case APU_OUTX + 0x00:
- case APU_OUTX + 0x10:
- case APU_OUTX + 0x20:
- case APU_OUTX + 0x30:
- case APU_OUTX + 0x40:
- case APU_OUTX + 0x50:
- case APU_OUTX + 0x60:
- case APU_OUTX + 0x70:
- if (SoundData.channels [reg >> 4].state == SOUND_SILENT)
- return (0);
- return ((SoundData.channels [reg >> 4].sample >> 8) |
- (SoundData.channels [reg >> 4].sample & 0xff));
-
- case APU_ENVX + 0x00:
- case APU_ENVX + 0x10:
- case APU_ENVX + 0x20:
- case APU_ENVX + 0x30:
- case APU_ENVX + 0x40:
- case APU_ENVX + 0x50:
- case APU_ENVX + 0x60:
- case APU_ENVX + 0x70:
- return ((uint8) S9xGetEnvelopeHeight (reg >> 4));
-
- case APU_ENDX:
- // To fix speech in Magical Drop 2 6/11/00
- // APU.DSP [APU_ENDX] = 0;
- break;
- default:
- break;
- }
- return (byte);
+ uint8 reg = IAPU.RAM [0xf2] & 0x7f;
+ uint8 byte = APU.DSP [reg];
+
+ switch (reg)
+ {
+ case APU_KON:
+ break;
+ case APU_KOFF:
+ break;
+ case APU_OUTX + 0x00:
+ case APU_OUTX + 0x10:
+ case APU_OUTX + 0x20:
+ case APU_OUTX + 0x30:
+ case APU_OUTX + 0x40:
+ case APU_OUTX + 0x50:
+ case APU_OUTX + 0x60:
+ case APU_OUTX + 0x70:
+ if (SoundData.channels [reg >> 4].state == SOUND_SILENT)
+ return (0);
+ return ((SoundData.channels [reg >> 4].sample >> 8) |
+ (SoundData.channels [reg >> 4].sample & 0xff));
+
+ case APU_ENVX + 0x00:
+ case APU_ENVX + 0x10:
+ case APU_ENVX + 0x20:
+ case APU_ENVX + 0x30:
+ case APU_ENVX + 0x40:
+ case APU_ENVX + 0x50:
+ case APU_ENVX + 0x60:
+ case APU_ENVX + 0x70:
+ return ((uint8) S9xGetEnvelopeHeight(reg >> 4));
+
+ case APU_ENDX:
+ // To fix speech in Magical Drop 2 6/11/00
+ // APU.DSP [APU_ENDX] = 0;
+ break;
+ default:
+ break;
+ }
+ return (byte);
}