📄 apu.cpp
字号:
/* * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. * * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and * Jerremy Koot (jkoot@snes9x.com) * * Super FX C emulator code * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and * Gary Henderson. * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. * * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). * * DOS port code contains the works of other authors. See headers in * individual files. * * Snes9x homepage: 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. */#ifdef __DJGPP#include <allegro.h>#undef TRUE#endif#include "snes9x.h"#include "spc700.h"#include "apu.h"#include "soundux.h"#include "cpuexec.h"extern int NoiseFreq [32];#ifdef DEBUGGERvoid S9xTraceSoundDSP (const char *s, int i1 = 0, int i2 = 0, int i3 = 0, int i4 = 0, int i5 = 0, int i6 = 0, int i7 = 0);#endifbool8 S9xInitAPU (){ IAPU.RAM = new uint8 [0x10000]; IAPU.ShadowRAM = new uint8 [0x10000]; IAPU.CachedSamples = new uint8 [0x40000]; if (!IAPU.RAM || !IAPU.ShadowRAM || !IAPU.CachedSamples) return (FALSE); return (TRUE);}void S9xDeinitAPU (){ delete IAPU.RAM; delete IAPU.ShadowRAM; delete IAPU.CachedSamples;}EXTERN_C uint8 APUROM [64];void S9xResetAPU (){ Settings.APUEnabled = Settings.NextAPUEnabled; memset (IAPU.RAM, 0xff, 0x10000); ZeroMemory (IAPU.ShadowRAM, 0x10000); ZeroMemory (IAPU.CachedSamples, 0x40000); ZeroMemory (APU.OutPorts, 4); IAPU.DirectPage = IAPU.RAM; memmove (&IAPU.RAM [0xffc0], APUROM, sizeof (APUROM)); memmove (APU.ExtraRAM, APUROM, sizeof (APUROM)); IAPU.PC = IAPU.RAM + IAPU.RAM [0xfffe] + (IAPU.RAM [0xffff] << 8); APU.Cycles = 0; APURegisters.YA.W = 0; APURegisters.X = 0; APURegisters.S = 0xff; APURegisters.P = 0; S9xAPUUnpackStatus (); APURegisters.PC = 0; IAPU.APUExecuting = Settings.APUEnabled;#ifdef SPC700_SHUTDOWN IAPU.WaitAddress1 = NULL; IAPU.WaitAddress2 = NULL; IAPU.WaitCounter = 0;#endif APU.ShowROM = TRUE; IAPU.RAM [0xf1] = 0x80; int i; for (i = 0; i < 3; i++) { APU.TimerEnabled [i] = FALSE; APU.TimerValueWritten [i] = 0; APU.TimerTarget [i] = 0; APU.Timer [i] = 0; } for (int 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){ uint8 reg = IAPU.RAM [0xf2]; int i; 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);#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] DSP reset\n", ICPU.Scanline);#endif // Kill sound S9xResetSound (FALSE); } else { S9xSetEchoWriteEnable (!(byte & APU_ECHO_DISABLED)); if (byte & APU_MUTE) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] Mute sound\n", ICPU.Scanline);#endif 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]) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] Noise:", ICPU.Scanline);#endif uint8 mask = 1; for (int c = 0; c < 8; c++, mask <<= 1) { int type; if (byte & mask) { type = SOUND_NOISE;#ifdef DEBUGGER if (Settings.TraceSoundDSP) { if (APU.DSP [reg] & mask) S9xTraceSoundDSP ("%d,", c); else S9xTraceSoundDSP ("%d(on),", c); }#endif } else { type = SOUND_SAMPLE;#ifdef DEBUGGER if (Settings.TraceSoundDSP) { if (APU.DSP [reg] & mask) S9xTraceSoundDSP ("%d(off),", c); }#endif } S9xSetSoundType (c, type); }#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("\n");#endif } break; case APU_MVOL_LEFT: if (byte != APU.DSP [APU_MVOL_LEFT]) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] Master volume left:%d\n", ICPU.Scanline, (signed char) byte);#endif S9xSetMasterVolume ((signed char) byte, (signed char) APU.DSP [APU_MVOL_RIGHT]); } break; case APU_MVOL_RIGHT: if (byte != APU.DSP [APU_MVOL_RIGHT]) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] Master volume right:%d\n", ICPU.Scanline, (signed char) byte);#endif S9xSetMasterVolume ((signed char) APU.DSP [APU_MVOL_LEFT], (signed char) byte); } break; case APU_EVOL_LEFT: if (byte != APU.DSP [APU_EVOL_LEFT]) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] Echo volume left:%d\n", ICPU.Scanline, (signed char) byte);#endif S9xSetEchoVolume ((signed char) byte, (signed char) APU.DSP [APU_EVOL_RIGHT]); } break; case APU_EVOL_RIGHT: if (byte != APU.DSP [APU_EVOL_RIGHT]) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] Echo volume right:%d\n", ICPU.Scanline, (signed char) byte);#endif S9xSetEchoVolume ((signed char) APU.DSP [APU_EVOL_LEFT], (signed char) byte); } break; case APU_ENDX:#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] Reset ENDX\n", ICPU.Scanline);#endif byte = 0; break; case APU_KOFF: if (byte) { uint8 mask = 1;#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] Key off:", ICPU.Scanline);#endif for (int c = 0; c < 8; c++, mask <<= 1) { if ((byte & mask) != 0) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("%d,", c);#endif if (APU.KeyedChannels & mask) { { APU.KeyedChannels &= ~mask; APU.DSP [APU_KON] &= ~mask; //APU.DSP [APU_KOFF] |= mask; S9xSetSoundKeyOff (c); } } } }#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("\n");#endif } APU.DSP [APU_KOFF] = byte; return; case APU_KON: if (byte) { uint8 mask = 1;#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] Key on:", ICPU.Scanline);#endif for (int c = 0; c < 8; c++, mask <<= 1) { if ((byte & mask) != 0) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("%d,", c);#endif // Pac-In-Time requires that channels can be key-on // regardeless of their current state. APU.KeyedChannels |= mask; APU.DSP [APU_KON] |= mask; APU.DSP [APU_KOFF] &= ~mask; APU.DSP [APU_ENDX] &= ~mask; S9xPlaySample (c); } }#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("\n");#endif } 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]) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] %d volume left: %d\n", ICPU.Scanline, reg>>4, (signed char) byte);#endif 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]) {#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] %d volume right: %d\n", ICPU.Scanline, reg >>4, (signed char) byte);#endif 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:#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] %d freq low: %d\n", ICPU.Scanline, reg>>4, byte);#endif 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:#ifdef DEBUGGER if (Settings.TraceSoundDSP) S9xTraceSoundDSP ("[%d] %d freq high: %d\n", ICPU.Scanline, reg>>4, byte);#endif S9xSetSoundHertz (reg >> 4,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -