diff --git a/apu.cpp b/apu.cpp index cb9d804..9061a8c 100644 --- a/apu.cpp +++ b/apu.cpp @@ -1,91 +1,162 @@ -/******************************************************************************* +/********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. - - (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and - Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2001 - 2004 John Weidman (jweidman@slip.net) + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net), - funkyass (funkyass@spam.shaw.ca), - Joel Yliluoma (http://iki.fi/bisqwit/) - Kris Bleakley (codeviolation@hotmail.com), - Matthew Kendora, - Nach (n-a-c-h@users.sourceforge.net), - Peter Bortas (peter@bortas.org) and - zones (kasumitokoduck@yahoo.com) + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2007 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones C4 x86 assembler and some C emulation code - (c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com), - _Demo_ (_demo_@zsnes.com), and Nach + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) C4 C++ code - (c) Copyright 2003 Brad Jorsch + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach DSP-1 emulator code - (c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson, - John Weidman, neviksti (neviksti@hotmail.com), - Kris Bleakley, Andreas Naive + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) DSP-2 emulator code - (c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and - Lord Nightmare (lord_nightmare@users.sourceforge.net + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden OBC1 emulator code - (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and - Kris Bleakley - Ported from x86 assembler to C by sanmaiwashi + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code - (c) Copyright 2002 Matthew Kendora with research by - zsKnight, John Weidman, and Dark Force + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force S-DD1 C emulator code - (c) Copyright 2003 Brad Jorsch with research by - Andreas Naive and John Weidman - + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + S-RTC C emulator code - (c) Copyright 2001 John Weidman - + (c) Copyright 2001-2006 byuu, + John Weidman + ST010 C++ emulator code - (c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + 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 _Demo_, + pagefault, + zsKnight, - Super FX C emulator code - (c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' 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) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2007 zones + - 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. - + + Permission to use, copy, modify and/or 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. - + arising from the use of this software or it's derivatives. + 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. - + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + 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. -*******************************************************************************/ +**********************************************************************************/ #include "port.h" @@ -95,6 +166,7 @@ #include "soundux.h" //#include "cpuexec.h" +extern int32 env_counter_table[32]; extern int NoiseFreq [32]; #ifdef ME_SOUND @@ -174,9 +246,12 @@ void S9xResetAPU () apu_init_after_load=0; //apu_can_execute=0; + + if(Settings.APUEnabled) + APUPack.APU.Flags &= ~HALTED_FLAG; - - memset((IAPUuncached.RAM),0, 0x10000); + //memset((IAPUuncached.RAM),0, 0x10000); + ZeroMemory(IAPUuncached.RAM, 0x100); memset((IAPUuncached.RAM)+0x20, 0xFF, 0x20); memset((IAPUuncached.RAM)+0x60, 0xFF, 0x20); memset((IAPUuncached.RAM)+0xA0, 0xFF, 0x20); @@ -187,13 +262,10 @@ void S9xResetAPU () memcpy((IAPUuncached.RAM)+(i<<8), (IAPUuncached.RAM), 0x100); } -// memcpy ((IAPUuncached.ShadowRAM), (IAPUuncached.RAM), 0x10000); - -// ZeroMemory ((IAPUuncached.CachedSamples), 0x40000); ZeroMemory ((APUPack.APU.OutPorts), 4); ZeroMemory ((void*)Uncache_APU_OutPorts, 4); - memcpy (&(IAPUuncached.RAM) [0xffc0], APUROM, sizeof (APUROM)); - memcpy ((APUuncached.ExtraRAM), APUROM, sizeof (APUROM)); + memmove (&(IAPUuncached.RAM) [0xffc0], APUROM, sizeof (APUROM)); + memmove ((APUuncached.ExtraRAM), &(IAPUuncached.RAM)[0xffc0], sizeof (APUROM)); (IAPUuncached.DirectPage) = (IAPUuncached.RAM); (IAPUuncached.PC) = (IAPUuncached.RAM) + (IAPUuncached.RAM) [0xfffe] + ((IAPUuncached.RAM) [0xffff] << 8); APUPack.APU.Cycles = 0; @@ -214,8 +286,8 @@ void S9xResetAPU () (APURegistersUncached.YA).W = 0; (APURegistersUncached.X) = 0; - (APURegistersUncached.S) = 0xff; - (APURegistersUncached.P) = 0; + (APURegistersUncached.S) = 0xef; + (APURegistersUncached.P) = 0x02; S9xAPUUnpackStatusUncached (); (APURegistersUncached.PC) = 0; (IAPU_APUExecuting) = Settings.APUEnabled; @@ -273,9 +345,7 @@ void S9xSetAPUDSP (uint8 byte) static uint8 KeyOnPrev; //WAIT4MIXING() uint8 reg = (IAPU.RAM) [0xf2]; - int i; - - + switch (reg) { case APU_FLG: @@ -299,12 +369,7 @@ void S9xSetAPUDSP (uint8 byte) 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); - } + SoundData.noise_rate = env_counter_table[byte & 0x1f]; } break; case APU_NON: @@ -478,10 +543,6 @@ void S9xSetAPUDSP (uint8 byte) case APU_SRCN + 0x50: case APU_SRCN + 0x60: case APU_SRCN + 0x70: - if (byte != APUPack.APU.DSP[reg]) - { - S9xSetSoundSample (reg >> 4, byte); - } break; case APU_ADSR1 + 0x00: @@ -610,93 +671,37 @@ void S9xSetAPUDSP (uint8 byte) // //////////////////////////////////////////////////////////////////////////////////////// // 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 - }; - 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 - }; void S9xFixEnvelope (int channel, uint8 gain, uint8 adsr1, uint8 adsr2) { - if (adsr1 & 0x80) { - - // 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) ) - attack = 0; - - S9xSetSoundADSR (channel, attack, - DecayRate [(adsr1 >> 4) & 7], - SustainRate [adsr2 & 0x1f], - (adsr2 >> 5) & 7, 8); - } + S9xSetSoundADSR (channel, adsr1 & 0xf, (adsr1 >> 4) & 7, + adsr2 & 0x1f, (adsr2 >> 5) & 7); } else - { - // Gain mode + { if ((gain & 0x80) == 0) { if (S9xSetSoundMode (channel, MODE_GAIN)) - { - S9xSetEnvelopeRate (channel, 0, 0, gain & 0x7f); - S9xSetEnvelopeHeight (channel, gain & 0x7f); - } + S9xSetEnvelopeHeight (channel, (gain & 0x7f) << ENV_SHIFT); } else { - if (gain & 0x40) { - // Increase mode if (S9xSetSoundMode (channel, (gain & 0x20) ? -MODE_INCREASE_BENT_LINE : - MODE_INCREASE_LINEAR)) - { - S9xSetEnvelopeRate (channel, IncreaseRate [gain & 0x1f], - 1, 127); - } + MODE_INCREASE_BENT_LINE : MODE_INCREASE_LINEAR)) + S9xSetEnvelopeRate (channel, env_counter_table[gain & 0x1f], ENV_MAX); } 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); + if (S9xSetSoundMode (channel, (gain & 0x20) ? + MODE_DECREASE_EXPONENTIAL : MODE_DECREASE_LINEAR)) + S9xSetEnvelopeRate (channel, env_counter_table[gain & 0x1f], 0); } } - } + } } //////////////////////////////////////////////////////////////////////////////////////// @@ -807,11 +812,17 @@ uint8 S9xGetAPUDSP () case APU_OUTX + 0x50: case APU_OUTX + 0x60: case APU_OUTX + 0x70: - if (SoundData.channels [reg >> 4].state == SOUND_SILENT) + if(Settings.FakeMuteFix) + { + // hack that is off by default: fixes Terranigma desync return (0); - return ((SoundData.channels [reg >> 4].sample >> 8) | - (SoundData.channels [reg >> 4].sample & 0xff)); - + } + else + { + if (SoundData.channels [reg >> 4].state == SOUND_SILENT) + return (0); + return (int8) (SoundData.channels [reg >> 4].out_sample >> 8); + } case APU_ENVX + 0x00: case APU_ENVX + 0x10: case APU_ENVX + 0x20: @@ -911,8 +922,8 @@ bool8 S9xInitAPU () #else (IAPUuncached.RAM) = (uint8 *) malloc (0x10000); - (IAPUuncached.ShadowRAM) = (uint8 *) malloc (0x10000); - (IAPUuncached.CachedSamples) = (uint8 *) malloc (0x40000); + //(IAPUuncached.ShadowRAM) = (uint8 *) malloc (0x10000); + //(IAPUuncached.CachedSamples) = (uint8 *) malloc (0x40000); #endif // PSP if (!(IAPUuncached.RAM) /*|| !(IAPUuncached.ShadowRAM) || !(IAPUuncached.CachedSamples)*/){ diff --git a/apu.h b/apu.h index c5d5d89..a37d27d 100644 --- a/apu.h +++ b/apu.h @@ -1,91 +1,162 @@ -/******************************************************************************* +/********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. - - (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and - Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2001 - 2004 John Weidman (jweidman@slip.net) + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net), - funkyass (funkyass@spam.shaw.ca), - Joel Yliluoma (http://iki.fi/bisqwit/) - Kris Bleakley (codeviolation@hotmail.com), - Matthew Kendora, - Nach (n-a-c-h@users.sourceforge.net), - Peter Bortas (peter@bortas.org) and - zones (kasumitokoduck@yahoo.com) + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2007 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones C4 x86 assembler and some C emulation code - (c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com), - _Demo_ (_demo_@zsnes.com), and Nach + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) C4 C++ code - (c) Copyright 2003 Brad Jorsch + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach DSP-1 emulator code - (c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson, - John Weidman, neviksti (neviksti@hotmail.com), - Kris Bleakley, Andreas Naive + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) DSP-2 emulator code - (c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and - Lord Nightmare (lord_nightmare@users.sourceforge.net + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden OBC1 emulator code - (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and - Kris Bleakley - Ported from x86 assembler to C by sanmaiwashi + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code - (c) Copyright 2002 Matthew Kendora with research by - zsKnight, John Weidman, and Dark Force + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force S-DD1 C emulator code - (c) Copyright 2003 Brad Jorsch with research by - Andreas Naive and John Weidman - + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + S-RTC C emulator code - (c) Copyright 2001 John Weidman - + (c) Copyright 2001-2006 byuu, + John Weidman + ST010 C++ emulator code - (c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + 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 _Demo_, + pagefault, + zsKnight, - Super FX C emulator code - (c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' 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) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2007 zones + - 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. - + + Permission to use, copy, modify and/or 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. - + arising from the use of this software or it's derivatives. + 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. - + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + 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. -*******************************************************************************/ +**********************************************************************************/ #ifndef _apu_h_ #define _apu_h_ diff --git a/apumem.h b/apumem.h index 1f33078..54bdf9a 100644 --- a/apumem.h +++ b/apumem.h @@ -1,91 +1,162 @@ -/******************************************************************************* +/********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. - - (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and - Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2001 - 2004 John Weidman (jweidman@slip.net) + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net), - funkyass (funkyass@spam.shaw.ca), - Joel Yliluoma (http://iki.fi/bisqwit/) - Kris Bleakley (codeviolation@hotmail.com), - Matthew Kendora, - Nach (n-a-c-h@users.sourceforge.net), - Peter Bortas (peter@bortas.org) and - zones (kasumitokoduck@yahoo.com) + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2007 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones C4 x86 assembler and some C emulation code - (c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com), - _Demo_ (_demo_@zsnes.com), and Nach + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) C4 C++ code - (c) Copyright 2003 Brad Jorsch + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach DSP-1 emulator code - (c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson, - John Weidman, neviksti (neviksti@hotmail.com), - Kris Bleakley, Andreas Naive + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) DSP-2 emulator code - (c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and - Lord Nightmare (lord_nightmare@users.sourceforge.net + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden OBC1 emulator code - (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and - Kris Bleakley - Ported from x86 assembler to C by sanmaiwashi + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code - (c) Copyright 2002 Matthew Kendora with research by - zsKnight, John Weidman, and Dark Force + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force S-DD1 C emulator code - (c) Copyright 2003 Brad Jorsch with research by - Andreas Naive and John Weidman - + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + S-RTC C emulator code - (c) Copyright 2001 John Weidman - + (c) Copyright 2001-2006 byuu, + John Weidman + ST010 C++ emulator code - (c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + 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 _Demo_, + pagefault, + zsKnight, - Super FX C emulator code - (c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' 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) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2007 zones + - 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. - + + Permission to use, copy, modify and/or 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. - + arising from the use of this software or it's derivatives. + 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. - + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + 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. -*******************************************************************************/ +**********************************************************************************/ #ifndef _apumemory_h_ #define _apumemory_h_ @@ -95,137 +166,143 @@ START_EXTERN_C //extern uint8 APUROM[64]; END_EXTERN_C -INLINE uint8 S9xAPUGetByteZ (uint8 Address) +static INLINE uint8 apu_get_reg (uint8 Address) { - if (Address >= 0xf0 && ((IAPU.DirectPage)) == ((IAPU.RAM))) - { - if (Address >= 0xf4 && Address <= 0xf7) + switch (Address) { -#ifdef SPC700_SHUTDOWN - ((IAPU.WaitAddress2)) = ((IAPU.WaitAddress1)); - ((IAPU.WaitAddress1)) = ((IAPU.PC)); -#endif - return (((IAPU.RAM)) [Address]); + case 0xf0: // -w TEST + return 0; + + case 0xf1: // -w CONTROL + return 0; + + case 0xf2: // rw DSPADDR + return (IAPU.RAM[Address]); + + case 0xf3: // rw DSPDATA + return (S9xGetAPUDSP()); + + case 0xf4: // r- CPUI0 + case 0xf5: // r- CPUI1 + case 0xf6: // r- CPUI2 + case 0xf7: // r- CPUI3 + #ifdef SPC700_SHUTDOWN + IAPU.WaitAddress2 = IAPU.WaitAddress1; + IAPU.WaitAddress1 = IAPU.PC; + #endif + return (IAPU.RAM[Address]); + + case 0xf8: // rw - Normal RAM + case 0xf9: // rw - Normal RAM + return (IAPU.RAM[Address]); + + case 0xfa: // -w T0TARGET + case 0xfb: // -w T1TARGET + case 0xfc: // -w T2TARGET + return 0; + + case 0xfd: // r- T0OUT + case 0xfe: // r- T1OUT + case 0xff: // r- T2OUT + #ifdef SPC700_SHUTDOWN + IAPU.WaitAddress2 = IAPU.WaitAddress1; + IAPU.WaitAddress1 = IAPU.PC; + #endif + uint8 t = IAPU.RAM[Address] & 0xF; + IAPU.RAM[Address] = 0; + return (t); } - if (Address >= 0xfd) + + return 0; +} + +static INLINE void apu_set_reg (uint8 byte, uint8 Address) +{ + switch (Address) { -#ifdef SPC700_SHUTDOWN - ((IAPU.WaitAddress2)) = ((IAPU.WaitAddress1)); - ((IAPU.WaitAddress1)) = ((IAPU.PC)); -#endif - uint8 t = ((IAPU.RAM)) [Address]; - ((IAPU.RAM)) [Address] = 0; - return (t); + case 0xf0: // -w TEST + //printf("Write %02X to APU 0xF0!\n", byte); + return; + + case 0xf1: // -w CONTROL + S9xSetAPUControl(byte); + return; + + case 0xf2: // rw DSPADDR + IAPU.RAM[Address] = byte; + return; + + case 0xf3: // rw DSPDATA + S9xSetAPUDSP(byte); + return; + + case 0xf4: // -w CPUO0 + case 0xf5: // -w CPUO1 + case 0xf6: // -w CPUO2 + case 0xf7: // -w CPUO3 + APUPack.APU.OutPorts[Address - 0xf4] = byte; + return; + + case 0xf8: // rw - Normal RAM + case 0xf9: // rw - Normal RAM + IAPU.RAM[Address] = byte; + return; + + case 0xfa: // -w T0TARGET + case 0xfb: // -w T1TARGET + case 0xfc: // -w T2TARGET + IAPU.RAM[Address] = byte; + if (byte == 0) + APUPack.APU.TimerTarget[Address - 0xfa] = 0x100; + else + APUPack.APU.TimerTarget[Address - 0xfa] = byte; + return; + + case 0xfd: // r- T0OUT + case 0xfe: // r- T1OUT + case 0xff: // r- T2OUT + return; } - else - if (Address == 0xf3) - return (S9xGetAPUDSP ()); +} - return (((IAPU.RAM)) [Address]); - } - else - return (((IAPU.DirectPage)) [Address]); +INLINE uint8 S9xAPUGetByteZ (uint8 Address) +{ + if (Address >= 0xf0 && IAPU.DirectPage == IAPU.RAM) + return (apu_get_reg(Address)); + else + return (IAPU.DirectPage[Address]); } INLINE void S9xAPUSetByteZ (uint8 byte, uint8 Address) { - if (Address >= 0xf0 && ((IAPU.DirectPage)) == ((IAPU.RAM))) - { - if (Address == 0xf3) - S9xSetAPUDSP (byte); - else - if (Address >= 0xf4 && Address <= 0xf7) - ((APUPack.APU.OutPorts)) [Address - 0xf4] = byte; - else - if (Address == 0xf1) - S9xSetAPUControl (byte); - else - if (Address < 0xfd) - { - ((IAPU.RAM)) [Address] = byte; - if (Address >= 0xfa) - { - if (byte == 0) - ((APUPack.APU.TimerTarget)) [Address - 0xfa] = 0x100; - else - ((APUPack.APU.TimerTarget)) [Address - 0xfa] = byte; - } - } - } + if (Address >= 0xf0 && IAPU.DirectPage == IAPU.RAM) + apu_set_reg(byte, Address); else - ((IAPU.DirectPage)) [Address] = byte; + IAPU.DirectPage[Address] = byte; } INLINE uint8 S9xAPUGetByte (uint32 Address) { Address &= 0xffff; - if (Address <= 0xff && Address >= 0xf0) - { - if (Address >= 0xf4 && Address <= 0xf7) - { -#ifdef SPC700_SHUTDOWN - ((IAPU.WaitAddress2)) = ((IAPU.WaitAddress1)); - ((IAPU.WaitAddress1)) = ((IAPU.PC)); -#endif - return (((IAPU.RAM)) [Address]); - } - else - if (Address == 0xf3) - return (S9xGetAPUDSP ()); - if (Address >= 0xfd) - { -#ifdef SPC700_SHUTDOWN - ((IAPU.WaitAddress2)) = ((IAPU.WaitAddress1)); - ((IAPU.WaitAddress1)) = ((IAPU.PC)); -#endif - uint8 t = ((IAPU.RAM)) [Address]; - ((IAPU.RAM)) [Address] = 0; - return (t); - } - return (((IAPU.RAM)) [Address]); - } + return (apu_get_reg(Address & 0xff)); else - return (((IAPU.RAM)) [Address]); + return (IAPU.RAM[Address]); } INLINE void S9xAPUSetByte (uint8 byte, uint32 Address) { Address &= 0xffff; - if (Address <= 0xff && Address >= 0xf0) - { - if (Address == 0xf3) - S9xSetAPUDSP (byte); - else - if (Address >= 0xf4 && Address <= 0xf7) - ((APUPack.APU.OutPorts)) [Address - 0xf4] = byte; + apu_set_reg(byte, Address & 0xff); else - if (Address == 0xf1) - S9xSetAPUControl (byte); - else - if (Address < 0xfd) - { - ((IAPU.RAM)) [Address] = byte; - if (Address >= 0xfa) - { - if (byte == 0) - ((APUPack.APU.TimerTarget)) [Address - 0xfa] = 0x100; - else - ((APUPack.APU.TimerTarget)) [Address - 0xfa] = byte; - } - } - } - else - { if (Address < 0xffc0) - ((IAPU.RAM)) [Address] = byte; + IAPU.RAM[Address] = byte; else { - ((APUPack.APU.ExtraRAM)) [Address - 0xffc0] = byte; - if (!((APUPack.APU.ShowROM))) - ((IAPU.RAM)) [Address] = byte; + APUPack.APU.ExtraRAM[Address - 0xffc0] = byte; + if (!APUPack.APU.ShowROM) + IAPU.RAM[Address] = byte; } - } } #endif diff --git a/ppu.cpp b/ppu.cpp index aad7a1a..c86c6a0 100644 --- a/ppu.cpp +++ b/ppu.cpp @@ -2267,7 +2267,7 @@ if (g_debuginfo) return (0); } - int ind = 0;//Settings.SwapJoypads ? 1 : 0; + int ind = Settings.SwapJoypads ? 1 : 0; byte = IPPU.Joypads[ind] >> (PPUPack.PPU.Joypad1ButtonReadPos ^ 15); PPUPack.PPU.Joypad1ButtonReadPos++; #ifdef __debug_io_gb__ @@ -2309,7 +2309,7 @@ if (g_debuginfo) return (0x00); } - int ind = 0;//Settings.SwapJoypads ? 0 : 1; + int ind = Settings.SwapJoypads ? 0 : 1; if (IPPU.Controller == SNES_MULTIPLAYER5) { @@ -3130,7 +3130,7 @@ void S9xUpdateJoypads () *((uint16*)(ROM_GLOBAL +0x421e)) = (uint16) IPPU.Joypads [4]; } #else - int ind = 0;//Settings.SwapJoypads ? 1 : 0; + int ind = Settings.SwapJoypads ? 1 : 0; ROM_GLOBAL [0x4218] = (uint8) IPPU.Joypads [ind]; ROM_GLOBAL [0x4219] = (uint8) (IPPU.Joypads [ind] >> 8); diff --git a/psp/menu.c b/psp/menu.c index 35f3a08..3d7b5f8 100644 --- a/psp/menu.c +++ b/psp/menu.c @@ -3409,8 +3409,7 @@ static int menu_credits(char *mode) { mh_printLimit(menu_panel_pos+5,15,479,272,"Code : YoyoFR & Laxer3a",CODE_COL); mh_printLimit(menu_panel_pos+5,25,479,272,"Mod : 173210, Ruka & 33(76)",CODE_COL); - if (menu_panel_pos+5+40<479-40) pgDrawFrame(menu_panel_pos+5+40,40,479-40,40,CODE2_COL); - if (menu_panel_pos+5+40<479-40) pgDrawFrame(menu_panel_pos+5+40,41,479-40,41,CODE3_COL); + mh_printLimit(menu_panel_pos+5,35,479,272," esmjanus",CODE_COL); mh_printLimit(menu_panel_pos+5,50,479,272,"Splines based on PSPSDK samples",GFX_COL); mh_printLimit(menu_panel_pos+5,60,479,272,"Logo, some bgs : Pochi",GFX_COL); diff --git a/psp/psp.cpp b/psp/psp.cpp index 1b4f2b6..a0dcb75 100644 --- a/psp/psp.cpp +++ b/psp/psp.cpp @@ -101,7 +101,6 @@ #include "display.h" #include "gfx.h" #include "soundux.h" -//#define SOUNDDUX_151 #include "spc700.h" #include "psp/counter.h" //#include "spc7110.h" @@ -2772,9 +2771,7 @@ static void low_level_init(){ sceKernelDcacheWritebackInvalidateAll(); (stSoundStatus.sound_fd) = -1; -#ifndef SOUNDDUX_151 - S9xAllocSound(); -#endif + S9xInitAPU(); SetGeCallback(); @@ -2800,9 +2797,6 @@ static void low_level_deinit(){ //snd_beep2_current=0; S9xDeinitAPU(); -#ifndef SOUNDDUX_151 - S9xFreeSound(); -#endif //OSK if (os9x_osk) danzeff_free(); diff --git a/snaporig.cpp b/snaporig.cpp index 114134a..9252cbc 100644 --- a/snaporig.cpp +++ b/snaporig.cpp @@ -409,7 +409,7 @@ static int ReadOrigSnapshot (STREAM snap) (IAPU_APUExecuting) = FALSE; S9xSetSoundMute (TRUE); } - S9xFixSoundAfterSnapshotLoad (); + S9xFixSoundAfterSnapshotLoad (1); ICPU.ShiftedPB = Registers.PB << 16; ICPU.ShiftedDB = Registers.DB << 16; S9xSetPCBase (ICPU.ShiftedPB + Registers.PC); diff --git a/snapshot.cpp b/snapshot.cpp index 393f0db..52489f0 100644 --- a/snapshot.cpp +++ b/snapshot.cpp @@ -867,7 +867,7 @@ static int Unfreeze (STREAM stream) #endif #ifdef ME_SOUND - S9xFixSoundAfterSnapshotLoad (); + S9xFixSoundAfterSnapshotLoad (1); #else //S9xFixSoundAfterSnapshotLoad (); #endif @@ -1657,7 +1657,7 @@ READ_STREAM(&temp, 4, fs); S9xFixColourBrightness (); IPPU.RenderThisFrame = FALSE; - S9xFixSoundAfterSnapshotLoad (); + S9xFixSoundAfterSnapshotLoad (1); ICPU.ShiftedPB = Registers.PB << 16; ICPU.ShiftedDB = Registers.DB << 16; S9xSetPCBase (ICPU.ShiftedPB + Registers.PCw); diff --git a/snes9x.h b/snes9x.h index c62404f..23f018a 100644 --- a/snes9x.h +++ b/snes9x.h @@ -344,7 +344,9 @@ struct SSettings{ bool8 InterpolatedSound; bool8 ThreadSound; bool8 Mute; - + + bool8 FakeMuteFix; + bool8 NextAPUEnabled; uint8 AltSampleDecode; bool8 FixFrequency; diff --git a/soundux.cpp b/soundux.cpp index 0ef7c26..6972f14 100644 --- a/soundux.cpp +++ b/soundux.cpp @@ -1,99 +1,299 @@ -/******************************************************************************* +/********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. - - (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and - Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2001 - 2004 John Weidman (jweidman@slip.net) + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net), - funkyass (funkyass@spam.shaw.ca), - Joel Yliluoma (http://iki.fi/bisqwit/) - Kris Bleakley (codeviolation@hotmail.com), - Matthew Kendora, - Nach (n-a-c-h@users.sourceforge.net), - Peter Bortas (peter@bortas.org) and - zones (kasumitokoduck@yahoo.com) + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2007 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones C4 x86 assembler and some C emulation code - (c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com), - _Demo_ (_demo_@zsnes.com), and Nach + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) C4 C++ code - (c) Copyright 2003 Brad Jorsch + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach DSP-1 emulator code - (c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson, - John Weidman, neviksti (neviksti@hotmail.com), - Kris Bleakley, Andreas Naive + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) DSP-2 emulator code - (c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and - Lord Nightmare (lord_nightmare@users.sourceforge.net + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden OBC1 emulator code - (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and - Kris Bleakley - Ported from x86 assembler to C by sanmaiwashi + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code - (c) Copyright 2002 Matthew Kendora with research by - zsKnight, John Weidman, and Dark Force + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force S-DD1 C emulator code - (c) Copyright 2003 Brad Jorsch with research by - Andreas Naive and John Weidman - + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + S-RTC C emulator code - (c) Copyright 2001 John Weidman - + (c) Copyright 2001-2006 byuu, + John Weidman + ST010 C++ emulator code - (c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + 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 _Demo_, + pagefault, + zsKnight, - Super FX C emulator code - (c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' 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) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2007 zones + - 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. - + + Permission to use, copy, modify and/or 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. - + arising from the use of this software or it's derivatives. + 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. - + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + 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. -*******************************************************************************/ +**********************************************************************************/ #include "psp.h" -//#include -//#include -//#include -//#include -//#include +#include "snes9x.h" +#include "soundux.h" +#include "apu.h" +#include "memmap.h" + +// gaussian table by libopenspc and SNEeSe +static const int32 gauss[512] = +{ + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, + 0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002, + 0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, + 0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005, + 0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008, + 0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A, + 0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E, + 0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011, + 0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016, + 0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B, + 0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021, + 0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028, + 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030, + 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038, + 0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042, + 0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D, + 0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059, + 0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066, + 0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075, + 0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084, + 0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096, + 0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8, + 0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC, + 0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2, + 0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9, + 0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101, + 0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B, + 0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137, + 0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153, + 0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172, + 0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191, + 0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2, + 0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5, + 0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8, + 0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C, + 0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241, + 0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267, + 0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E, + 0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5, + 0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC, + 0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304, + 0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B, + 0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353, + 0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379, + 0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F, + 0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5, + 0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9, + 0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C, + 0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E, + 0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E, + 0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C, + 0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488, + 0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2, + 0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA, + 0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0, + 0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3, + 0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3, + 0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500, + 0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B, + 0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512, + 0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517, + 0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519 +}; + +#define G1(n) gauss[256 + (n)] +#define G2(n) gauss[512 + (n)] +#define G3(n) gauss[255 + (n)] +#define G4(n) gauss[ -1 + (n)] + +// envelope/noise table by libopenspc and SNEeSe +int32 env_counter_table[32] = +{ + 0x0000, 0x000F, 0x0014, 0x0018, 0x001E, 0x0028, 0x0030, 0x003C, + 0x0050, 0x0060, 0x0078, 0x00A0, 0x00C0, 0x00F0, 0x0140, 0x0180, + 0x01E0, 0x0280, 0x0300, 0x03C0, 0x0500, 0x0600, 0x0780, 0x0A00, + 0x0C00, 0x0F00, 0x1400, 0x1800, 0x1E00, 0x2800, 0x3C00, 0x7800 +}; + +static int32 env_counter_max; +static const int32 env_counter_max_master = 0x7800; + +static int rand_seed = 1; + +int32 Loop[16]; +int32 Echo[24000]; +int32 FilterTaps[8]; +int32 MixBuffer[SOUND_BUFFER_SIZE]; +int32 EchoBuffer[SOUND_BUFFER_SIZE]; +int32 DummyEchoBuffer[SOUND_BUFFER_SIZE]; +uint32 FIRIndex = 0; + +// For backward compatibility ------------------------------ +static uint32 OldAttackRate[16] = +{ + 4100, 2600, 1500, 1000, 640, 380, 260, 160, + 96, 64, 40, 24, 16, 10, 6, 1 +}; + +static uint32 OldDecayRate[8] = +{ + 1200, 740, 440, 290, 180, 110, 74, 37 +}; + +static uint32 OldSustainRate[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 +}; + +static int OldNoiseFreq[32] = +{ + 0, 16, 21, 25, 31, 42, 50, 63, + 84, 100, 125, 167, 200, 250, 333, 400, + 500, 667, 800, 1000, 1300, 1600, 2000, 2700, + 3200, 4000, 5300, 6400, 8000, 10700, 16000, 32000 +}; +// --------------------------------------------------------- +#define FIXED_POINT 0x10000UL +#define FIXED_POINT_SHIFT 16 + +#undef ABS +#define ABS(a) ((a) < 0 ? -(a) : (a)) #define CLIP16(v) \ if ((v) < -32768) \ @@ -102,21 +302,6 @@ if ((v) > 32767) \ (v) = 32767 -#define CLIP17(v) \ - if ((v) < -65536) \ - (v) = -65536; \ - else \ - if ((v) > 65535) \ -(v) = 65535 - -#define CLIP16_latch(v,l) \ - if ((v) < -32768) \ -{ (v) = -32768; (l)++; }\ - else \ - if ((v) > 32767) \ -{ (v) = 32767; (l)++; } - - #define CLIP8(v) \ if ((v) < -128) \ (v) = -128; \ @@ -124,25 +309,9 @@ if ((v) > 127) \ (v) = 127 -#include "psp.h" -#include "snes9x.h" -#include "soundux.h" -#include "apu.h" -#include "memmap.h" -//#include "cpuexec.h" - -/*extern int Echo[24000]; -extern int DummyEchoBuffer[SOUND_BUFFER_SIZE]; -extern int MixBuffer[SOUND_BUFFER_SIZE]; -extern int EchoBuffer[SOUND_BUFFER_SIZE]; -extern int FilterTaps [8]; -//extern unsigned long Z; -extern int Loop [16];*/ #ifdef ME_SOUND SoundStatus __attribute__((aligned(64))) stSoundStatus_value; SoundStatus * __attribute__((aligned(64))) stSoundStatus_p=(SoundStatus*)UNCACHE_PTR(&stSoundStatus_value); -//SSoundData __attribute__((aligned(64))) SoundData_value; -//SSoundData * __attribute__((aligned(64))) SoundData_p=(SSoundData*)UNCACHE_PTR(&SoundData_value); SSoundData __attribute__((aligned(64))) SoundData; #else SoundStatus __attribute__((aligned(64))) stSoundStatus; @@ -150,39 +319,16 @@ SSoundData __attribute__((aligned(64))) SoundData; #endif struct SAPUPACK __attribute__((aligned(64))) APUPack; -//struct SAPU __attribute__((aligned(64))) APU; -//struct SIAPU __attribute__((aligned(64))) IAPU; -//struct SAPURegisters __attribute__((aligned(64))) APURegisters; -// struct SAPU APUuncached; #ifdef ME_SOUND -//SSoundData __attribute__((aligned(64))) SoundData; -//SSoundData __attribute__((aligned(64))) SoundData; - -//#undef IAPUuncached -//SIAPU IAPUuncached; -//SIAPU * const Uncache_Uncache_IAPU_p=(SIAPU *)UNCACHE_PTR(&IAPUuncached); SIAPU * const Uncache_Uncache_IAPU_p=(SIAPU *)UNCACHE_PTR(&IAPU); -//#define IAPUuncached (*Uncache_Uncache_IAPU_p) - -//SAPU APU4Uncache; -//SAPU * const Uncache_Uncache_APU_p=(SAPU *)UNCACHE_PTR(&APU4Uncache); -//#undef APUuncached SAPU * const Uncache_Uncache_APU_p=(SAPU *)UNCACHE_PTR(&APUPack.APU); -//#define APUuncached (*Uncache_Uncache_APU_p) - SAPURegisters* const Uncache_APURegisters_p=(SAPURegisters*)UNCACHE_PTR(&APURegisters); -//struct SAPURegisters APURegistersUncached; -//struct SAPURegisters APURegisters4Uncached; -//SAPURegisters* const Uncache_APURegisters_p=(SAPURegisters*)UNCACHE_PTR(&APURegisters4Uncached); - #else struct SIAPU IAPUuncached; struct SAPURegisters APURegistersUncached; #endif - - SAPUEVENTS __attribute__((aligned(64))) stAPUEvents; #ifdef ME_SOUND volatile int *apu_cycles_left_p,*apu_glob_cycles_p; @@ -193,185 +339,150 @@ volatile int *apu_init_after_load_=(int*)UNCACHE_PTR(&stAPUEvents.apu_init_after #define apu_init_after_load (*apu_init_after_load_) volatile int *apu_can_execute_p,*apu_ram_write_cpt1_p,*apu_ram_write_cpt2_p; #endif -//int __attribute__((aligned(64))) Echo[24000]; -int *DummyEchoBuffer; -int EchoBuffer[SOUND_BUFFER_SIZE]; -int Echo[24000]; -int MixBuffer[SOUND_BUFFER_SIZE]; -int wave[SOUND_BUFFER_SIZE]; -/*int __attribute__((aligned(64))) DummyEchoBuffer[SOUND_BUFFER_SIZE]; -int __attribute__((aligned(64))) MixBuffer[SOUND_BUFFER_SIZE]; -int __attribute__((aligned(64))) EchoBuffer[SOUND_BUFFER_SIZE]; -int __attribute__((aligned(64))) wave[SOUND_BUFFER_SIZE];*/ - -int FilterTaps [8]; -unsigned long Z = 0; -int Loop [16]; - -long FilterValues[4][2] = -{ - {0, 0}, - {240, 0}, - {488, -240}, - {460, -208} -}; - -int NoiseFreq [32] = { - 0, 16, 21, 25, 31, 42, 50, 63, 84, 100, 125, 167, 200, 250, 333, - 400, 500, 667, 800, 1000, 1300, 1600, 2000, 2700, 3200, 4000, - 5300, 6400, 8000, 10700, 16000, 32000 -}; - -//char dummy_yo1[1024*1024*1]; +void S9xAPUSetEndOfSample (int i, Channel *); +void S9xAPUSetEndX (int); +void S9xSetEnvRate (Channel *, int32, int32); +void MixStereo (int); +void MixMono (int); -#undef ABS -#define ABS(a) ((a) < 0 ? -(a) : (a)) +static void S9xSetSoundFrequency (int, int); +static void S9xConvertSoundOldValues (); +static void DecodeBlock (Channel *); +static void AltDecodeBlock (Channel *); +static void AltDecodeBlock2 (Channel *); +STATIC inline uint8 *S9xGetSampleAddress (int); -#define FIXED_POINT 0x10000UL -#define FIXED_POINT_REMAINDER 0xffffUL -#define FIXED_POINT_SHIFT 16 +EXTERN_C void DecodeBlockAsm (int8 *, int16 *, int32 *, int32 *); +EXTERN_C void DecodeBlockAsm2 (int8 *, int16 *, int32 *, int32 *); -#define VOL_DIV8 0x8000 -//#define VOL_DIV16 0x0080 -#define VOL16_SHIFT 6//7 +static bool8 DoFakeMute = FALSE; -#define ENVX_SHIFT 24 - -//extern "C" void DecodeBlockAsm (int8 *, int16 *, int32 *, int32 *); -//extern "C" void DecodeBlockAsm2 (int8 *, int16 *, int32 *, int32 *); - -// F is channel's current frequency and M is the 16-bit modulation waveform -// from the previous channel multiplied by the current envelope volume level. -#define PITCH_MOD(F,M) ((F) * ((((unsigned long) (M)) + 0x800000) >> 16) >> 7) -//#define PITCH_MOD(F,M) ((F) * ((((M) & 0x7fffff) >> 14) + 1) >> 8) - -#define LAST_SAMPLE 0xffffff -#define JUST_PLAYED_LAST_SAMPLE(c) ((c)->sample_pointer >= LAST_SAMPLE) - -static inline uint8 *S9xGetSampleAddress (int sample_number) { - uint32 addr = (((((APUPack.APU.DSP))[APU_DIR] << 8) + (sample_number << 2)) & 0xffff); - return (((IAPU.RAM)) + addr); +STATIC inline uint8 *S9xGetSampleAddress (int sample_number) { + uint32 addr = (((APUPack.APU.DSP[APU_DIR] << 8) + (sample_number << 2)) & 0xffff); + return (IAPU.RAM + addr); } void S9xAPUSetEndOfSample (int i, Channel *ch) { ch->state = SOUND_SILENT; - ch->mode = MODE_NONE; - APUPack.APU.DSP[APU_ENDX] |= 1 << i; - APUPack.APU.DSP[APU_KON] &= ~(1 << i); - APUPack.APU.DSP[APU_KOFF] &= ~(1 << i); - ((APUPack.APU.KeyedChannels)) &= ~(1 << i); + ch->mode = MODE_NONE; + ch->out_sample = 0; + ch->xenvx = 0; + + if(!DoFakeMute) { + APUPack.APU.DSP[APU_ENDX] |= 1 << i; + APUPack.APU.DSP[APU_KON] &= ~(1 << i); + APUPack.APU.DSP[APU_KOFF] &= ~(1 << i); + ((APUPack.APU.KeyedChannels)) &= ~(1 << i); + } } - -void S9xAPUSetEndX (int ch) { - APUPack.APU.DSP[APU_ENDX] |= 1 << ch; +void S9xAPUSetEndX (int i) { + if(!DoFakeMute) { + APUPack.APU.DSP[APU_ENDX] |= 1 << i; + } } -static int steps [] = { - // 0, 64, 1238, 1238, 256, 1, 64, 109, 64, 1238 - 0, 64, 619, 619, 128, 1, 64, 55, 64, 619 - }; -void S9xSetEnvRate (Channel *ch, unsigned long rate, int direction, int target) { - - - ch->envx_target = target; - - if (rate == ~0UL) { - ch->direction = 0; - rate = 0; - } else ch->direction = direction; - - - - - if (rate == 0 || stSoundStatus.playback_rate == 0) ch->erate = 0; - else ch->erate = (unsigned long) (((int64) FIXED_POINT * 1000 * steps [ch->state]) / (rate * stSoundStatus.playback_rate)); - - +void S9xSetEnvRate (Channel *ch, int32 rate_count, int32 xtarget) +{ + ch->xenvx_target = xtarget; + ch->xenv_rate = rate_count; } - -void S9xSetEnvelopeRate (int channel, unsigned long rate, int direction, int target) { - S9xSetEnvRate (&SoundData.channels [channel], rate, direction, target); +void S9xSetEnvelopeRate (int channel, int32 rate_count, int32 xtarget) +{ + S9xSetEnvRate (&SoundData.channels[channel], rate_count, xtarget); } - -void S9xSetSoundVolume (int channel, short volume_left, short volume_right) { +void S9xSetSoundVolume (int channel, short volume_left, short volume_right) +{ Channel *ch = &SoundData.channels[channel]; - ch->volume_left = volume_left; - ch->volume_right = volume_right; - ch-> left_vol_level = ((ch->envx * volume_left) >> 7); - ch->right_vol_level = ((ch->envx * volume_right) >> 7); + if (stSoundStatus.stereo_switch + 1) + { + volume_left = ((stSoundStatus.stereo_switch & ( 1 << channel)) ? volume_left : 0); + volume_right = ((stSoundStatus.stereo_switch & (256 << channel)) ? volume_right : 0); + } + + if (!stSoundStatus.stereo) + volume_left = (ABS(volume_right) + ABS(volume_left)) >> 1; + + ch->volume_left = volume_left; + ch->volume_right = volume_right; } -void S9xSetMasterVolume (short volume_left, short volume_right) { - if ((Settings.DisableMasterVolume) || SNESGameFixes.EchoOnlyOutput) { - SoundData.master_volume_left = 127; +void S9xSetMasterVolume (short volume_left, short volume_right) +{ + if (Settings.DisableMasterVolume) + { + SoundData.master_volume_left = 127; SoundData.master_volume_right = 127; - SoundData.master_volume [0] = SoundData.master_volume [1] = 127; - } else { - - SoundData.master_volume_left = volume_left; + SoundData.master_volume[0] = SoundData.master_volume[1] = 127; + } + else + { + if (!stSoundStatus.stereo) + volume_left = (ABS(volume_right) + ABS(volume_left)) >> 1; + + SoundData.master_volume_left = volume_left; SoundData.master_volume_right = volume_right; - SoundData.master_volume [0] = volume_left; - SoundData.master_volume [1] = volume_right; + SoundData.master_volume[Settings.ReverseStereo] = volume_left; + SoundData.master_volume[1 ^ Settings.ReverseStereo] = volume_right; } } -void S9xSetEchoVolume (short volume_left, short volume_right) { - - SoundData.echo_volume_left = volume_left; - SoundData.echo_volume_right = volume_right; - SoundData.echo_volume [0] = volume_left; - SoundData.echo_volume [1] = volume_right; +void S9xSetEchoVolume (short volume_left, short volume_right) +{ + if (!stSoundStatus.stereo) + volume_left = (ABS(volume_right) + ABS(volume_left)) >> 1; + + SoundData.echo_volume_left = volume_left; + SoundData.echo_volume_right = volume_right; + SoundData.echo_volume[Settings.ReverseStereo] = volume_left; + SoundData.echo_volume[1 ^ Settings.ReverseStereo] = volume_right; } -void S9xSetEchoEnable (uint8 byte) { +void S9xSetEchoEnable (uint8 byte) +{ +#if 0 SoundData.echo_channel_enable = byte; - if (!SoundData.echo_write_enabled || (Settings.DisableSoundEcho)) - byte = 0; - if (byte && !SoundData.echo_enable) { - memset (&Echo, 0, sizeof (Echo)); + if (!SoundData.echo_write_enabled || Settings.DisableSoundEcho) + byte = 0; + if (byte && !SoundData.echo_enable) + { memset (Loop, 0, sizeof (Loop)); - } - - SoundData.echo_enable = byte; - for (int i = 0; i < 8; i++) { - if (byte & (1 << i)) SoundData.channels [i].echo_buf_ptr = EchoBuffer; - else SoundData.channels [i].echo_buf_ptr = DummyEchoBuffer; + memset (Echo, 0, sizeof (Echo)); + } +#endif + SoundData.echo_enable = byte; + for (int i = 0; i < NUM_CHANNELS; i++) + { + if (byte & (1 << i)) + SoundData.channels[i].echo_buf_ptr = EchoBuffer; + else + SoundData.channels[i].echo_buf_ptr = DummyEchoBuffer; } } -void S9xSetEchoFeedback (int feedback) { - CLIP8(feedback); - SoundData.echo_feedback = feedback; +void S9xSetEchoFeedback (int feedback) +{ + SoundData.echo_feedback = feedback; } -void S9xSetEchoDelay (int delay) { - - - SoundData.echo_buffer_size = (512 * delay * (stSoundStatus.playback_rate)) / 32000; - - SoundData.echo_buffer_size <<= 1; - - - if (SoundData.echo_buffer_size>=24000) { - S9xMessage(-1,0,"setechodelay too big!"); - SoundData.echo_buffer_size=24000; - } - - if (SoundData.echo_buffer_size) SoundData.echo_ptr %= SoundData.echo_buffer_size; - else SoundData.echo_ptr = 0; - S9xSetEchoEnable (APUPack.APU.DSP[APU_EON]); - - +void S9xSetEchoDelay (unsigned int delay) +{ + SoundData.echo_buffer_size = (delay << 10) * stSoundStatus.playback_rate / 32000; + if (!stSoundStatus.stereo) + SoundData.echo_buffer_size >>= 1; + if (SoundData.echo_buffer_size) + SoundData.echo_ptr %= SoundData.echo_buffer_size; + else + SoundData.echo_ptr = 0; } -void S9xSetEchoWriteEnable (uint8 byte) { +void S9xSetEchoWriteEnable (uint8 byte) +{ SoundData.echo_write_enabled = byte; - S9xSetEchoDelay (APUPack.APU.DSP[APU_EDL] & 15); } void S9xSetFrequencyModulationEnable (uint8 byte) { @@ -384,141 +495,240 @@ void S9xSetSoundKeyOff (int channel) { if (ch->state != SOUND_SILENT) { ch->state = SOUND_RELEASE; ch->mode = MODE_RELEASE; - S9xSetEnvRate (ch, 8, -1, 0); + S9xSetEnvRate (ch, env_counter_max, 0); } } -void S9xFixSoundAfterSnapshotLoad () { - SoundData.echo_write_enabled = !(APUPack.APU.DSP[APU_FLG] & 0x20); - SoundData.echo_channel_enable = APUPack.APU.DSP[APU_EON]; - S9xSetEchoDelay (APUPack.APU.DSP[APU_EDL] & 0xf); - S9xSetEchoFeedback ((signed char) APUPack.APU.DSP[APU_EFB]); - - S9xSetFilterCoefficient (0, (signed char) APUPack.APU.DSP[APU_C0]); - S9xSetFilterCoefficient (1, (signed char) APUPack.APU.DSP[APU_C1]); - S9xSetFilterCoefficient (2, (signed char) APUPack.APU.DSP[APU_C2]); - S9xSetFilterCoefficient (3, (signed char) APUPack.APU.DSP[APU_C3]); - S9xSetFilterCoefficient (4, (signed char) APUPack.APU.DSP[APU_C4]); - S9xSetFilterCoefficient (5, (signed char) APUPack.APU.DSP[APU_C5]); - S9xSetFilterCoefficient (6, (signed char) APUPack.APU.DSP[APU_C6]); - S9xSetFilterCoefficient (7, (signed char) APUPack.APU.DSP[APU_C7]); - for (int i = 0; i < 8; i++) { - SoundData.channels[i].needs_decode = TRUE; - S9xSetSoundFrequency (i, SoundData.channels[i].hertz); - SoundData.channels [i].envxx = SoundData.channels [i].envx << ENVX_SHIFT; - SoundData.channels [i].next_sample = 0; - SoundData.channels [i].interpolate = 0; - SoundData.channels [i].previous [0] = (int32) SoundData.channels [i].previous16 [0]; - SoundData.channels [i].previous [1] = (int32) SoundData.channels [i].previous16 [1]; +void S9xPrepareSoundForSnapshotSave (bool8 restore) +{ + static uint32 temp_hertz[NUM_CHANNELS]; + + int i, j; + + if (!restore) + { + for (i = 0; i < NUM_CHANNELS; i++) + { + Channel *ch = &SoundData.channels[i]; + + ch->count = 0; + ch->envx = ch->xenvx >> 4; + ch->envx_target = ch->xenvx_target >> 4; + ch->direction = 0; + ch-> left_vol_level = (ch->xenvx * ch->volume_left ) >> 11; + ch->right_vol_level = (ch->xenvx * ch->volume_right) >> 11; + ch->release_rate = 8; + ch->sustain_level = ch->xsustain_level >> 8; + + if (env_counter_max < ch->xenv_count) + ch->env_error = 0; + else + ch->env_error = (uint32) + ((double) FIXED_POINT / env_counter_max * (env_counter_max - ch->xenv_count)); + + if (ch->xenv_rate < 0) + ch->erate = 0; + else + ch->erate = (uint32) + ((double) FIXED_POINT / env_counter_max * ch->xenv_rate); + + for (j = 0; j < 32; j++) + if (env_counter_table[j] == ch->xattack_rate) + break; + ch->attack_rate = OldAttackRate[(unsigned) (((j - 1) >> 1) & 0xF)]; + + for (j = 0; j < 32; j++) + if (env_counter_table[j] == ch->xdecay_rate) + break; + ch->decay_rate = OldDecayRate[(unsigned) (((j - 0x10) >> 1) & 0x7)]; + + for (j = 0; j < 32; j++) + if (env_counter_table[j] == ch->xsustain_rate) + break; + ch->sustain_rate = OldSustainRate[(unsigned) (j & 0x1F)]; + } + + for (j = 0; j < 32; j++) + if (env_counter_table[j] == SoundData.noise_rate) + break; + + for (i = 0; i < NUM_CHANNELS; i++) + { + Channel *ch = &SoundData.channels[i]; + + temp_hertz[i] = ch->hertz; + if (ch->type == SOUND_NOISE) + ch->hertz = OldNoiseFreq[(unsigned) (j & 0x1F)]; + } } - SoundData.master_volume [0] = SoundData.master_volume_left; - SoundData.master_volume [1] = SoundData.master_volume_right; - SoundData.echo_volume [0] = SoundData.echo_volume_left; - SoundData.echo_volume [1] = SoundData.echo_volume_right; - ((IAPU.Scanline)) = 0; - - -} + else + { + for (i = 0; i < NUM_CHANNELS; i++) + { + Channel *ch = &SoundData.channels[i]; -void S9xSetFilterCoefficient (int tap, int value) { - FilterTaps [tap & 7] = value; - SoundData.no_filter = (FilterTaps [0] == 127 || FilterTaps [0] == 0) && - FilterTaps [1] == 0 && - FilterTaps [2] == 0 && - FilterTaps [3] == 0 && - FilterTaps [4] == 0 && - FilterTaps [5] == 0 && - FilterTaps [6] == 0 && - FilterTaps [7] == 0; + ch->hertz = temp_hertz[i]; + } + } } -void S9xSetSoundADSR (int channel, int attack_rate, int decay_rate, int sustain_rate, int sustain_level, int release_rate) { - SoundData.channels[channel].attack_rate = attack_rate; - SoundData.channels[channel].decay_rate = decay_rate; - SoundData.channels[channel].sustain_rate = sustain_rate; - SoundData.channels[channel].release_rate = release_rate; - SoundData.channels[channel].sustain_level = sustain_level + 1; - - switch (SoundData.channels[channel].state) { - case SOUND_ATTACK: - S9xSetEnvelopeRate (channel, attack_rate, 1, 127); - break; - - case SOUND_DECAY: - S9xSetEnvelopeRate (channel, decay_rate, -1, - (MAX_ENVELOPE_HEIGHT * (sustain_level + 1)) >> 3); - break; - case SOUND_SUSTAIN: - S9xSetEnvelopeRate (channel, sustain_rate, -1, 0); - break; - } -} +static void S9xConvertSoundOldValues () +{ + int i, j; + int old_noise_freq = 0; + + for (i = 0; i < NUM_CHANNELS; i++) + { + Channel *ch = &SoundData.channels[i]; + + ch->xenvx = ch->envx << 4; + ch->xenvx_target = ch->envx_target << 4; + ch->out_sample = ((ch->sample * ch->xenvx) >> 11) & ~1; + ch->xsustain_level = ch->sustain_level << 8; + + ch->xenv_rate = (int32) ((double) ch->erate * env_counter_max / FIXED_POINT); + ch->xenv_count = env_counter_max - + (int32) ((double) ch->env_error * env_counter_max / FIXED_POINT); + + for (j = 0; j < 16; j++) + if (OldAttackRate[j] == ch->attack_rate) + break; + ch->xattack_rate = env_counter_table[(unsigned) (((j << 1) + 1) & 0x1F)]; + + for (j = 0; j < 8; j++) + if (OldDecayRate[j] == ch->decay_rate) + break; + ch->xdecay_rate = env_counter_table[(unsigned) (((j << 1) + 0x10) & 0x1F)]; + + for (j = 0; j < 32; j++) + if (OldSustainRate[j] == ch->sustain_rate) + break; + ch->xsustain_rate = env_counter_table[(unsigned) (j & 0x1F)]; + + if (ch->type == SOUND_NOISE) + { + old_noise_freq = ch->hertz; + ch->hertz = 32000; + } + } -void S9xSetEnvelopeHeight (int channel, int level) { - Channel *ch = &SoundData.channels[channel]; - - ch->envx = level; - ch->envxx = level << ENVX_SHIFT; - - - ch->left_vol_level = ((level * ch->volume_left) >> 7); - ch->right_vol_level = ((level * ch->volume_right) >> 7); - - if (ch->envx == 0 && ch->state != SOUND_SILENT && ch->state != SOUND_GAIN) S9xAPUSetEndOfSample (channel, ch); + if (old_noise_freq) + { + for (j = 0; j < 32; j++) + if (OldNoiseFreq[j] == old_noise_freq) + break; + SoundData.noise_rate = env_counter_table[(unsigned) (j & 0x1F)]; + } + else + SoundData.noise_rate = 0; } -int S9xGetEnvelopeHeight (int channel) { - if (((Settings.SoundEnvelopeHeightReading) || - SNESGameFixes.SoundEnvelopeHeightReading2) && - SoundData.channels[channel].state != SOUND_SILENT && - SoundData.channels[channel].state != SOUND_GAIN) return (SoundData.channels[channel].envx); - - - //siren fix from XPP - if (SNESGameFixes.SoundEnvelopeHeightReading2 && - SoundData.channels[channel].state != SOUND_SILENT) return (SoundData.channels[channel].envx); - - return (0); +void S9xFixSoundAfterSnapshotLoad (int version) +{ + S9xSetEchoEnable (APUPack.APU.DSP[APU_EON]); + S9xSetEchoWriteEnable (!(APUPack.APU.DSP[APU_FLG] & APU_ECHO_DISABLED)); + S9xSetEchoDelay (APUPack.APU.DSP[APU_EDL] & 0xF); + S9xSetEchoFeedback ((signed char) APUPack.APU.DSP[APU_EFB]); + + S9xSetFilterCoefficient (0, (signed char) APUPack.APU.DSP[APU_C0]); + S9xSetFilterCoefficient (1, (signed char) APUPack.APU.DSP[APU_C1]); + S9xSetFilterCoefficient (2, (signed char) APUPack.APU.DSP[APU_C2]); + S9xSetFilterCoefficient (3, (signed char) APUPack.APU.DSP[APU_C3]); + S9xSetFilterCoefficient (4, (signed char) APUPack.APU.DSP[APU_C4]); + S9xSetFilterCoefficient (5, (signed char) APUPack.APU.DSP[APU_C5]); + S9xSetFilterCoefficient (6, (signed char) APUPack.APU.DSP[APU_C6]); + S9xSetFilterCoefficient (7, (signed char) APUPack.APU.DSP[APU_C7]); + + if (version < 2) + S9xConvertSoundOldValues (); + + for (int i = 0; i < NUM_CHANNELS; i++) + { + S9xSetSoundFrequency (i, SoundData.channels[i].hertz); + SoundData.channels[i].needs_decode = TRUE; + SoundData.channels[i].nb_index = 0; + SoundData.channels[i].nb_sample[0] = 0; + SoundData.channels[i].nb_sample[1] = 0; + SoundData.channels[i].nb_sample[2] = 0; + SoundData.channels[i].nb_sample[3] = 0; + SoundData.channels[i].xsmp_count = 0; + SoundData.channels[i].previous[0] = (int32) SoundData.channels[i].previous16[0]; + SoundData.channels[i].previous[1] = (int32) SoundData.channels[i].previous16[1]; + } + + SoundData.noise_count = 0; + + SoundData.master_volume[Settings.ReverseStereo] = SoundData.master_volume_left; + SoundData.master_volume[1 ^ Settings.ReverseStereo] = SoundData.master_volume_right; + SoundData.echo_volume[Settings.ReverseStereo] = SoundData.echo_volume_left; + SoundData.echo_volume[1 ^ Settings.ReverseStereo] = SoundData.echo_volume_right; } -#if 1 -void S9xSetSoundSample (int, uint16) +void S9xSetFilterCoefficient (int tap, int value) { - + FilterTaps[tap & 7] = value; + SoundData.no_filter = + FilterTaps[0] == 127 && + FilterTaps[1] == 0 && + FilterTaps[2] == 0 && + FilterTaps[3] == 0 && + FilterTaps[4] == 0 && + FilterTaps[5] == 0 && + FilterTaps[6] == 0 && + FilterTaps[7] == 0; } -#else -void S9xSetSoundSample (int channel, uint16 sample_number) + +void S9xSetSoundADSR (int channel, int ar, int dr, int sr, int sl) { - register Channel *ch = &SoundData.channels[channel]; - - if (ch->state != SOUND_SILENT && - sample_number != ch->sample_number) - { - int keep = ch->state; - ch->state = SOUND_SILENT; - ch->sample_number = sample_number; - ch->loop = FALSE; - ch->needs_decode = TRUE; - ch->last_block = FALSE; - ch->previous [0] = ch->previous[1] = 0; - uint8 *dir = S9xGetSampleAddress (sample_number); - ch->block_pointer = READ_WORD (dir); - ch->sample_pointer = 0; - ch->state = keep; - } + Channel *ch = &SoundData.channels[channel]; + + ch->xattack_rate = env_counter_table[(ar << 1) + 1]; + ch->xdecay_rate = env_counter_table[(dr << 1) + 0x10]; + ch->xsustain_rate = env_counter_table[sr]; + ch->xsustain_level = (ENV_RANGE >> 3) * (sl + 1); + + switch (ch->state) + { + case SOUND_ATTACK: + S9xSetEnvRate (ch, ch->xattack_rate, ENV_MAX); + break; + + case SOUND_DECAY: + S9xSetEnvRate (ch, ch->xdecay_rate, ch->xsustain_level); + break; + + case SOUND_SUSTAIN: + S9xSetEnvRate (ch, ch->xsustain_rate, 0); + break; + } } -#endif -void S9xSetSoundFrequency (int channel, int hertz) { - - if ((stSoundStatus.playback_rate)) { - if (SoundData.channels[channel].type == SOUND_NOISE) hertz = NoiseFreq [APUPack.APU.DSP[APU_FLG] & 0x1f]; - SoundData.channels[channel].frequency = (int)(((int64) hertz * FIXED_POINT) / (stSoundStatus.playback_rate)); - //if ((Settings.FixFrequency)) SoundData.channels[channel].frequency = (unsigned long) ((float)SoundData.channels[channel].frequency * 0.980); - if ((Settings.FixFrequency)) SoundData.channels[channel].frequency = (unsigned long) (SoundData.channels[channel].frequency * 2007 >> 11 /*0.98*/); - } +void S9xSetEnvelopeHeight (int channel, int32 xlevel) +{ + Channel *ch = &SoundData.channels[channel]; + + ch->xenvx = ch->xenvx_target = xlevel; + ch->xenv_rate = 0; + if (xlevel == 0 && ch->state != SOUND_SILENT && ch->state != SOUND_GAIN) + S9xAPUSetEndOfSample (channel, ch); +} +uint8 S9xGetEnvelopeHeight (int channel) +{ + if (Settings.SoundEnvelopeHeightReading) + return ((SoundData.channels[channel].xenvx >> ENV_SHIFT) & 0x7F); + else + return (0); +} +static void S9xSetSoundFrequency (int channel, int hertz) +{ + if (stSoundStatus.playback_rate) + SoundData.channels[channel].frequency = (uint32) + ((int64) (hertz << (FIXED_POINT_SHIFT - 15)) * 32000 / stSoundStatus.playback_rate); + if (Settings.FixFrequency) + SoundData.channels[channel].frequency = (uint32) + (SoundData.channels[channel].frequency * stSoundStatus.pitch_mul); } void S9xSetSoundHertz (int channel, int hertz) { @@ -536,978 +746,1094 @@ bool8 S9xSetSoundMute (bool8 mute) { return (old); } -void AltDecodeBlock (Channel *ch) { - if (ch->block_pointer >= 0x10000 - 9) { +static void AltDecodeBlock (Channel *ch) +{ + if (ch->block_pointer > 0x10000 - 9) + { ch->last_block = TRUE; ch->loop = FALSE; ch->block = ch->decoded; memset ((void *) ch->decoded, 0, sizeof (int16) * 16); return; - } - signed char *compressed = (signed char *) &((IAPU.RAM)) [ch->block_pointer]; - - unsigned char filter = *compressed; - if ((ch->last_block = filter & 1)) ch->loop = (filter & 2) != 0; - -#if (defined (USE_X86_ASM) && (defined (__i386__) || defined (__i486__) ||\ - defined (__i586__) || defined (__WIN32__) || defined (__DJGPP)) || defined(__PSPyo__)) - int16 *raw = ch->block = ch->decoded; - - if ((Settings.AltSampleDecode) == 1) DecodeBlockAsm (compressed, raw, &ch->previous [0], &ch->previous [1]); - else DecodeBlockAsm2 (compressed, raw, &ch->previous [0], &ch->previous [1]); + } + + signed char *compressed = (signed char *) &IAPU.RAM[ch->block_pointer]; + + unsigned char filter = *compressed; + ch->last_block = filter & 1; + ch->loop = (filter & 2) != 0; + + signed short *raw = ch->block = ch->decoded; + +#if (defined (USE_X86_ASM) && (defined (__i386__) || defined (__i486__) || \ + defined (__i586__) || defined (__WIN32__) || defined (__DJGPP))) + if (Settings.AltSampleDecode == 1) + DecodeBlockAsm (compressed, raw, &ch->previous[0], &ch->previous[1]); + else + DecodeBlockAsm2 (compressed, raw, &ch->previous[0], &ch->previous[1]); #else int32 out; - unsigned char shift; - signed char sample1, sample2; - unsigned int i; - - compressed++; - signed short *raw = ch->block = ch->decoded; - - int32 prev0 = ch->previous [0]; - int32 prev1 = ch->previous [1]; - shift = filter >> 4; - - switch ((filter >> 2) & 3) { - case 0: - for (i = 8; i != 0; i--) { - sample1 = *compressed++; - sample2 = sample1 << 4; - sample2 >>= 4; - sample1 >>= 4; - *raw++ = ((int32) sample1 << shift); - *raw++ = ((int32) sample2 << shift); - } - prev1 = *(raw - 2); - prev0 = *(raw - 1); - break; - case 1: - for (i = 8; i != 0; i--) { - sample1 = *compressed++; - sample2 = sample1 << 4; - sample2 >>= 4; - sample1 >>= 4; - prev0 = (int16) prev0; - *raw++ = prev1 = ((int32) sample1 << shift) + prev0 - (prev0 >> 4); - prev1 = (int16) prev1; - *raw++ = prev0 = ((int32) sample2 << shift) + prev1 - (prev1 >> 4); - } - break; - case 2: - for (i = 8; i != 0; i--) { - sample1 = *compressed++; - sample2 = sample1 << 4; - sample2 >>= 4; - sample1 >>= 4; - - out = (sample1 << shift) - prev1 + (prev1 >> 4); - prev1 = (int16) prev0; - prev0 &= ~3; - *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) - - (prev0 >> 4); - - out = (sample2 << shift) - prev1 + (prev1 >> 4); - prev1 = (int16) prev0; - prev0 &= ~3; - *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) - - (prev0 >> 4); - } - break; - case 3: - for (i = 8; i != 0; i--) { - sample1 = *compressed++; - sample2 = sample1 << 4; - sample2 >>= 4; - sample1 >>= 4; - out = (sample1 << shift); - - out = out - prev1 + (prev1 >> 3) + (prev1 >> 4); - prev1 = (int16) prev0; - prev0 &= ~3; - *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) - - (prev0 >> 4) - (prev1 >> 6); - - out = (sample2 << shift); - out = out - prev1 + (prev1 >> 3) + (prev1 >> 4); - prev1 = (int16) prev0; - prev0 &= ~3; - *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) - - (prev0 >> 4) - (prev1 >> 6); - } - break; + unsigned char shift; + signed char sample1, sample2; + uint32 i; + + compressed++; + + int32 prev0 = ch->previous[0]; + int32 prev1 = ch->previous[1]; + shift = filter >> 4; + + switch ((filter >> 2) & 3) + { + case 0: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + *raw++ = ((int32) sample1 << shift); + *raw++ = ((int32) sample2 << shift); + } + prev1 = *(raw - 2); + prev0 = *(raw - 1); + break; + + case 1: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + prev0 = (int16) prev0; + *raw++ = prev1 = ((int32) sample1 << shift) + prev0 - (prev0 >> 4); + prev1 = (int16) prev1; + *raw++ = prev0 = ((int32) sample2 << shift) + prev1 - (prev1 >> 4); + } + break; + + case 2: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + + out = (sample1 << shift) - prev1 + (prev1 >> 4); + prev1 = (int16) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) - + (prev0 >> 4); + + out = (sample2 << shift) - prev1 + (prev1 >> 4); + prev1 = (int16) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) - + (prev0 >> 4); + } + break; + + case 3: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + out = (sample1 << shift); + + out = out - prev1 + (prev1 >> 3) + (prev1 >> 4); + prev1 = (int16) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) - + (prev0 >> 4) - (prev1 >> 6); + + out = (sample2 << shift); + out = out - prev1 + (prev1 >> 3) + (prev1 >> 4); + prev1 = (int16) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) - + (prev0 >> 4) - (prev1 >> 6); + } + break; } - ch->previous [0] = prev0; - ch->previous [1] = prev1; + + ch->previous[0] = prev0; + ch->previous[1] = prev1; #endif - - ch->block_pointer += 9; + ch->block_pointer += 9; } -void AltDecodeBlock2 (Channel *ch) { +static void AltDecodeBlock2 (Channel *ch) +{ int32 out; - unsigned char filter; - unsigned char shift; - signed char sample1, sample2; - unsigned char i; - - if (ch->block_pointer > 0x10000 - 9) { + unsigned char filter; + unsigned char shift; + signed char sample1, sample2; + uint32 i; + + if (ch->block_pointer > 0x10000 - 9) + { ch->last_block = TRUE; ch->loop = FALSE; ch->block = ch->decoded; memset ((void *) ch->decoded, 0, sizeof (int16) * 16); return; - } - - signed char *compressed = (signed char *) &((IAPU.RAM)) [ch->block_pointer]; - - filter = *compressed; - if ((ch->last_block = filter & 1)) ch->loop = (filter & 2) != 0; - - - compressed++; - signed short *raw = ch->block = ch->decoded; - - shift = filter >> 4; - int32 prev0 = ch->previous [0]; - int32 prev1 = ch->previous [1]; - - if(shift > 12) shift -= 4; - - switch ((filter >> 2) & 3) { - case 0: - for (i = 8; i != 0; i--) { - sample1 = *compressed++; - sample2 = sample1 << 4; - //Sample 2 = Bottom Nibble, Sign Extended. - sample2 >>= 4; - //Sample 1 = Top Nibble, shifted down and Sign Extended. - sample1 >>= 4; - - out = (int32)(sample1 << shift); - - prev1 = prev0; - prev0 = out; - CLIP16(out); - *raw++ = (int16)out; - - out = (int32)(sample2 << shift); - - prev1 = prev0; - prev0 = out; - CLIP16(out); - *raw++ = (int16)out; - } - break; - case 1: - for (i = 8; i != 0; i--) { - sample1 = *compressed++; - sample2 = sample1 << 4; - //Sample 2 = Bottom Nibble, Sign Extended. - sample2 >>= 4; - //Sample 1 = Top Nibble, shifted down and Sign Extended. - sample1 >>= 4; - out = (int32)(sample1 << shift); - out += (int32)((prev0 * 15)>>4); - - prev1 = prev0; - prev0 = out; - CLIP16(out); - *raw++ = (int16)out; - - out = (int32)(sample2 << shift); - out += (int32)((prev0 * 15)>>4); - - prev1 = prev0; - prev0 = out; - CLIP16(out); - *raw++ = (int16)out; - } - break; - case 2: - for (i = 8; i != 0; i--) { - sample1 = *compressed++; - sample2 = sample1 << 4; - //Sample 2 = Bottom Nibble, Sign Extended. - sample2 >>= 4; - //Sample 1 = Top Nibble, shifted down and Sign Extended. - sample1 >>= 4; - - out = ((sample1 << shift) * 256 + (prev0 & ~0x2) * 488 - prev1 * 240) >> 8; - - prev1 = prev0; - prev0 = (int16)out; - *raw++ = (int16)out; - - out = ((sample2 << shift) * 256 + (prev0 & ~0x2) * 488 - prev1 * 240) >> 8; - - prev1 = prev0; - prev0 = (int16)out; - *raw++ = (int16)out; - } - break; - - case 3: - for (i = 8; i != 0; i--) { - sample1 = *compressed++; - sample2 = sample1 << 4; - //Sample 2 = Bottom Nibble, Sign Extended. - sample2 >>= 4; - //Sample 1 = Top Nibble, shifted down and Sign Extended. - sample1 >>= 4; - out = (int32)(sample1 << shift); - out += (int32)(prev0 * 115/64 - prev1 * 13/16); - - prev1 = prev0; - prev0 = out; - - CLIP16(out); - *raw++ = (int16)out; - - out = (int32)(sample2 << shift); - out += (int32)(prev0 * 115/64 - prev1 * 13/16); - - prev1 = prev0; - prev0 = out; - - CLIP16(out); - *raw++ = (int16)out; - } - break; } - ch->previous [0] = prev0; - ch->previous [1] = prev1; - ch->block_pointer += 9; -} -void DecodeBlock (Channel *ch) { - int32 out; - unsigned char filter; - unsigned char shift; - signed char sample1, sample2; - unsigned char i; - bool invalid_header; - - if ((Settings.AltSampleDecode)) { - if ((Settings.AltSampleDecode) < 3) AltDecodeBlock (ch); - else AltDecodeBlock2 (ch); - return; - } - if (ch->block_pointer > 0x10000 - 9) { - ch->last_block = TRUE; - ch->loop = FALSE; - ch->block = ch->decoded; - return; - } - signed char *compressed = (signed char *) &((IAPU.RAM)) [ch->block_pointer]; - - filter = *compressed; - if ((ch->last_block = filter & 1)) ch->loop = (filter & 2) != 0; + signed char *compressed = (signed char *) &IAPU.RAM[ch->block_pointer]; + + filter = *compressed; + ch->last_block = filter & 1; + ch->loop = (filter & 2) != 0; + compressed++; signed short *raw = ch->block = ch->decoded; - - // Seperate out the header parts used for decoding shift = filter >> 4; - + int32 prev0 = ch->previous[0]; + int32 prev1 = ch->previous[1]; + + if(shift > 12) + shift -= 4; + + switch ((filter >> 2) & 3) + { + case 0: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + + out = (int32) (sample1 << shift); + + prev1 = prev0; + prev0 = out; + CLIP16(out); + *raw++ = (int16) out; + + out = (int32) (sample2 << shift); + + prev1 = prev0; + prev0 = out; + CLIP16(out); + *raw++ = (int16) out; + } + break; + + case 1: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + out = (int32) (sample1 << shift); + out += (int32) ((double) prev0 * 15/16); + + prev1 = prev0; + prev0 = out; + CLIP16(out); + *raw++ = (int16) out; + + out = (int32) (sample2 << shift); + out += (int32) ((double) prev0 * 15/16); + + prev1 = prev0; + prev0 = out; + CLIP16(out); + *raw++ = (int16) out; + } + break; + + case 2: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + + out = ((sample1 << shift) * 256 + (prev0 & ~0x2) * 488 - prev1 * 240) >> 8; + + prev1 = prev0; + prev0 = (int16) out; + *raw++ = (int16) out; + + out = ((sample2 << shift) * 256 + (prev0 & ~0x2) * 488 - prev1 * 240) >> 8; + + prev1 = prev0; + prev0 = (int16) out; + *raw++ = (int16) out; + } + break; + + case 3: + for (i = 8; i != 0; i--) + { + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + out = (int32) (sample1 << shift); + out += (int32) ((double) prev0 * 115/64 - (double) prev1 * 13/16); + + prev1 = prev0; + prev0 = out; + + CLIP16(out); + *raw++ = (int16) out; + + out = (int32) (sample2 << shift); + out += (int32) ((double) prev0 * 115/64 - (double) prev1 * 13/16); + + prev1 = prev0; + prev0 = out; + + CLIP16(out); + *raw++ = (int16) out; + } + break; + } + + ch->previous[0] = prev0; + ch->previous[1] = prev1; + + ch->block_pointer += 9; +} + +static void DecodeBlock (Channel *ch) +{ + int32 out; + unsigned char filter; + unsigned char shift; + signed char sample1, sample2; + bool invalid_header; + + if (Settings.AltSampleDecode) + { + if (Settings.AltSampleDecode < 3) + AltDecodeBlock (ch); + else + AltDecodeBlock2 (ch); + return; + } + + if (ch->block_pointer > 0x10000 - 9) + { + ch->last_block = TRUE; + ch->loop = FALSE; + ch->block = ch->decoded; + return; + } + + signed char *compressed = (signed char *) &IAPU.RAM[ch->block_pointer]; + + filter = *compressed; + ch->last_block = filter & 1; + ch->loop = (filter & 2) != 0; + + compressed++; + signed short *raw = ch->block = ch->decoded; + + // Seperate out the header parts used for decoding + + shift = filter >> 4; + // Header validity check: if range(shift) is over 12, ignore // all bits of the data for that block except for the sign bit of each invalid_header = !(shift < 0xD); - filter = filter&0x0c; + filter &= 0x0C; - int32 prev0 = ch->previous [0]; - int32 prev1 = ch->previous [1]; - - for (i = 8; i != 0; i--) { + int32 prev0 = ch->previous[0]; + int32 prev1 = ch->previous[1]; + + for (uint32 i = 8; i != 0; i--) + { sample1 = *compressed++; sample2 = sample1 << 4; //Sample 2 = Bottom Nibble, Sign Extended. sample2 >>= 4; //Sample 1 = Top Nibble, shifted down and Sign Extended. sample1 >>= 4; - if (invalid_header) { sample1>>=3; sample2>>=3; } - - for (int nybblesmp = 0; nybblesmp<2; nybblesmp++) { - out=(((nybblesmp) ? sample2 : sample1) << shift); - out >>= 1; - - switch(filter) { + + for (int nybblesmp = 0; nybblesmp < 2; nybblesmp++) + { + out = (nybblesmp ? sample2 : sample1); + if (!invalid_header) + out = (out << shift) >> 1; + else + out &= ~0x7FF; + + switch (filter) + { case 0x00: - // Method0 - [Smp] + // Method0 -[Smp] break; - + case 0x04: - // Method1 - [Delta]+[Smp-1](15/16) - out+=(prev0>>1)+((-prev0)>>5); + // Method1 -[Delta]+[Smp-1](15/16) + out += prev0 >> 1; + out += (-prev0) >> 5; break; - + case 0x08: - // Method2 - [Delta]+[Smp-1](61/32)-[Smp-2](15/16) - out+=(prev0)+((-(prev0 +(prev0>>1)))>>5)-(prev1>>1)+(prev1>>5); + // Method2 -[Delta]+[Smp-1](61/32)-[Smp-2](15/16) + out += prev0; + out += (-(prev0 + (prev0 >> 1))) >> 5; + out -= prev1 >> 1; + out += prev1 >> 5; + break; + + case 0x0C: + // Method3 -[Delta]+[Smp-1](115/64)-[Smp-2](13/16) + out += prev0; + out += (-(prev0 + (prev0 << 2) + (prev0 << 3))) >> 7; + out -= prev1 >> 1; + out += (prev1 + (prev1 >> 1)) >> 4; break; - - default: - // Method3 - [Delta]+[Smp-1](115/64)-[Smp-2](13/16) - out+=(prev0)+((-(prev0 + (prev0<<2) + (prev0<<3)))>>7)-(prev1>>1)+((prev1+(prev1>>1))>>4); - break; } + CLIP16(out); - //CLIP17(out); - *raw++ = (signed short)(out<<1); - // *raw++ = (signed short)(out); - prev1=(signed short)prev0; - prev0=(signed short)(out<<1); - // prev0=(signed short)(out); + + prev1 = (signed short) prev0; + prev0 = *raw++ = (signed short) (out << 1); } } - ch->previous [0] = prev0; - ch->previous [1] = prev1; - + + ch->previous[0] = prev0; + ch->previous[1] = prev1; + ch->block_pointer += 9; } +void MixStereo (int sample_count) +{ + DoFakeMute=Settings.FakeMuteFix; + + static int32 noise_cache[256]; + static int32 wave[SOUND_BUFFER_SIZE]; -void MixStereo (int sample_count) { - int pitch_mod = SoundData.pitch_mod & ~((APUPack.APU.DSP))[APU_NON]; - - for (uint32 J = 0; J < NUM_CHANNELS; J++) { - int32 VL, VR; + int pitch_mod = SoundData.pitch_mod & ~APUPack.APU.DSP[APU_NON]; + + int32 noise_index = 0; + int32 noise_count = 0; + + if (APUPack.APU.DSP[APU_NON]) + { + noise_count = SoundData.noise_count; + + for (uint32 I = 0; I < (uint32) sample_count; I += 2) + { + noise_count -= SoundData.noise_rate; + while (noise_count <= 0) + { + rand_seed = rand_seed * 48828125 + 1; + noise_cache[noise_index] = rand_seed; + noise_index = (noise_index + 1) & 0xFF; + noise_count += env_counter_max; + } + } + } + + for (uint32 J = 0; J < NUM_CHANNELS; J++) + { Channel *ch = &SoundData.channels[J]; - unsigned long freq0 = ch->frequency; - - if (ch->state == SOUND_SILENT || !((stSoundStatus.sound_switch) & (1 << J))) continue; - - freq0 = (unsigned long) (( freq0 * 2017)>>11 /*0.985*/);//uncommented by jonathan gevaryahu, as it is necessary for most cards in linux - - bool8 mod = pitch_mod & (1 << J); - - if (ch->needs_decode) { + uint32 freq = ch->frequency; + + bool8 last_block = FALSE; + + if (ch->type == SOUND_NOISE) + { + noise_index = 0; + noise_count = SoundData.noise_count; + } + + if (ch->state == SOUND_SILENT || last_block || !(stSoundStatus.sound_switch & (1 << J))) + continue; + + bool8 mod1 = pitch_mod & (1 << J); + bool8 mod2 = pitch_mod & (1 << (J + 1)); + + if (ch->needs_decode) + { DecodeBlock(ch); ch->needs_decode = FALSE; ch->sample = ch->block[0]; - ch->sample_pointer = freq0 >> FIXED_POINT_SHIFT; - if (ch->sample_pointer == 0) ch->sample_pointer = 1; - if (ch->sample_pointer > SOUND_DECODE_LENGTH) ch->sample_pointer = SOUND_DECODE_LENGTH - 1; - - ch->next_sample=ch->block[ch->sample_pointer]; - ch->interpolate = 0; - - if ((Settings.InterpolatedSound) && freq0 < FIXED_POINT && !mod) - ch->interpolate = ((ch->next_sample - ch->sample) * - (long) freq0) / (long) FIXED_POINT; + ch->sample_pointer = 0; } - - VL = ((ch->sample * ch-> left_vol_level) >> 7); - VR = ((ch->sample * ch->right_vol_level) >> 7); - - for (uint32 I = 0; I < (uint32) sample_count; I += 2) { - unsigned long freq = freq0; - - if (mod) freq = PITCH_MOD(freq, wave [I >> 1]); - - ch->env_error += ch->erate; - if (ch->env_error >= FIXED_POINT) { - uint32 step = ch->env_error >> FIXED_POINT_SHIFT; - - switch (ch->state) { - case SOUND_ATTACK: - ch->env_error &= FIXED_POINT_REMAINDER; - ch->envx += step << 1; - ch->envxx = ch->envx << ENVX_SHIFT; - - if (ch->envx >= 126) { - ch->envx = 127; - ch->envxx = 127 << ENVX_SHIFT; - ch->state = SOUND_DECAY; - if (ch->sustain_level != 8) { - S9xSetEnvRate (ch, ch->decay_rate, -1,(MAX_ENVELOPE_HEIGHT * ch->sustain_level)>> 3); - break; - } - ch->state = SOUND_SUSTAIN; - S9xSetEnvRate (ch, ch->sustain_rate, -1, 0); + + for (uint32 I = 0; I < (uint32) sample_count; I += 2) + { + switch (ch->state) + { + case SOUND_ATTACK: + if (ch->xenv_rate == env_counter_max_master) + ch->xenvx += (ENV_RANGE >> 1); // FIXME + else + { + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx += (ENV_RANGE >> 6); // 1/64 + ch->xenv_count += env_counter_max; } - break; - - case SOUND_DECAY: - while (ch->env_error >= FIXED_POINT) { - ch->envxx = (ch->envxx >> 8) * 255; - ch->env_error -= FIXED_POINT; + } + + if (ch->xenvx > ENV_MAX) + { + ch->xenvx = ENV_MAX; + + if (ch->xsustain_level != ENV_RANGE) + { + ch->state = SOUND_DECAY; + S9xSetEnvRate (ch, ch->xdecay_rate, ch->xsustain_level); } - ch->envx = ch->envxx >> ENVX_SHIFT; - if (ch->envx <= ch->envx_target) { - if (ch->envx <= 0) { - S9xAPUSetEndOfSample (J, ch); - goto stereo_exit; - } + else + { ch->state = SOUND_SUSTAIN; - S9xSetEnvRate (ch, ch->sustain_rate, -1, 0); - } - break; - - case SOUND_SUSTAIN: - while (ch->env_error >= FIXED_POINT) { - ch->envxx = (ch->envxx >> 8) * 255; - ch->env_error -= FIXED_POINT; - } - ch->envx = ch->envxx >> ENVX_SHIFT; - if (ch->envx <= 0) { - S9xAPUSetEndOfSample (J, ch); - goto stereo_exit; - } - break; - - case SOUND_RELEASE: - while (ch->env_error >= FIXED_POINT) { - ch->envxx -= ((MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) >> 8); - ch->env_error -= FIXED_POINT; - } - ch->envx = ch->envxx >> ENVX_SHIFT; - if (ch->envx <= 0) { - S9xAPUSetEndOfSample (J, ch); - goto stereo_exit; + S9xSetEnvRate (ch, ch->xsustain_rate, 0); } - break; - - case SOUND_INCREASE_LINEAR: - ch->env_error &= FIXED_POINT_REMAINDER; - ch->envx += step << 1; - ch->envxx = ch->envx << ENVX_SHIFT; - - if (ch->envx >= 126) { - ch->envx = 127; - ch->envxx = 127 << ENVX_SHIFT; - ch->state = SOUND_GAIN; - ch->mode = MODE_GAIN; - S9xSetEnvRate (ch, 0, -1, 0); - } - break; - - case SOUND_INCREASE_BENT_LINE: - if (ch->envx >= (MAX_ENVELOPE_HEIGHT * 3) >> 2) { - while (ch->env_error >= FIXED_POINT) { - ch->envxx += ((MAX_ENVELOPE_HEIGHT << ENVX_SHIFT) >> 8); - ch->env_error -= FIXED_POINT; - } - ch->envx = ch->envxx >> ENVX_SHIFT; - } else { - ch->env_error &= FIXED_POINT_REMAINDER; - ch->envx += step << 1; - ch->envxx = ch->envx << ENVX_SHIFT; - } - - if (ch->envx >= 126) { - ch->envx = 127; - ch->envxx = 127 << ENVX_SHIFT; - ch->state = SOUND_GAIN; - ch->mode = MODE_GAIN; - S9xSetEnvRate (ch, 0, -1, 0); - } - break; - - case SOUND_DECREASE_LINEAR: - ch->env_error &= FIXED_POINT_REMAINDER; - ch->envx -= step << 1; - ch->envxx = ch->envx << ENVX_SHIFT; - if (ch->envx <= 0) { + } + + break; + + case SOUND_DECAY: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= ((ch->xenvx - 1) >> 8) + 1; // 1 - 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= ch->xenvx_target) + { + if (ch->xenvx <= 0) + { S9xAPUSetEndOfSample (J, ch); goto stereo_exit; } - break; - - case SOUND_DECREASE_EXPONENTIAL: - while (ch->env_error >= FIXED_POINT) { - ch->envxx = (ch->envxx >> 8) * 255; - ch->env_error -= FIXED_POINT; - } - ch->envx = ch->envxx >> ENVX_SHIFT; - if (ch->envx <= 0) { - S9xAPUSetEndOfSample (J, ch); - goto stereo_exit; + else + { + ch->state = SOUND_SUSTAIN; + S9xSetEnvRate (ch, ch->xsustain_rate, 0); } - break; - - case SOUND_GAIN: - S9xSetEnvRate (ch, 0, -1, 0); - break; - } - ch-> left_vol_level = ((ch->envx * ch->volume_left) >> 7); - ch->right_vol_level = ((ch->envx * ch->volume_right) >> 7); - VL = ((ch->sample * ch-> left_vol_level) >> 7); - VR = ((ch->sample * ch->right_vol_level) >> 7); - } + } - ch->count += freq; - if (ch->count >= FIXED_POINT) { - VL = ch->count >> FIXED_POINT_SHIFT; - ch->sample_pointer += VL; - ch->count &= FIXED_POINT_REMAINDER; - - ch->sample = ch->next_sample; - if (ch->sample_pointer >= SOUND_DECODE_LENGTH) { - if (JUST_PLAYED_LAST_SAMPLE(ch)) { + break; + + case SOUND_SUSTAIN: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= ((ch->xenvx - 1) >> 8) + 1; // 1 - 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto stereo_exit; + } + + break; + + case SOUND_RELEASE: + ch->xenv_count -= env_counter_max; + while (ch->xenv_count <= 0) + { + ch->xenvx -= (ENV_RANGE >> 8); // 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto stereo_exit; + } + + break; + + case SOUND_INCREASE_LINEAR: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx += (ENV_RANGE >> 6); // 1/64 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx > ENV_MAX) + { + ch->xenvx = ENV_MAX; + ch->state = SOUND_GAIN; + ch->mode = MODE_GAIN; + S9xSetEnvRate (ch, 0, 0); + } + + break; + + case SOUND_INCREASE_BENT_LINE: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + if (ch->xenvx >= ((ENV_RANGE * 3) >> 2)) // 0x600 + ch->xenvx += (ENV_RANGE >> 8); // 1/256 + else + ch->xenvx += (ENV_RANGE >> 6); // 1/64 + + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx > ENV_MAX) + { + ch->xenvx = ENV_MAX; + ch->state = SOUND_GAIN; + ch->mode = MODE_GAIN; + S9xSetEnvRate (ch, 0, 0); + } + + break; + + case SOUND_DECREASE_LINEAR: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= (ENV_RANGE >> 6); // 1/64 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { + S9xAPUSetEndOfSample (J, ch); + goto stereo_exit; + } + + break; + + case SOUND_DECREASE_EXPONENTIAL: + ch->xenv_count -= ch->xenv_rate; + while (ch->xenv_count <= 0) + { + ch->xenvx -= ((ch->xenvx - 1) >> 8) + 1; // 1 - 1/256 + ch->xenv_count += env_counter_max; + } + + if (ch->xenvx <= 0) + { S9xAPUSetEndOfSample (J, ch); goto stereo_exit; } - do { - ch->sample_pointer -= SOUND_DECODE_LENGTH; - if (ch->last_block) { - if (!ch->loop) { - ch->sample_pointer = LAST_SAMPLE; - ch->next_sample = ch->sample; - break; - } else { - S9xAPUSetEndX (J); - ch->last_block = FALSE; - uint8 *dir = S9xGetSampleAddress (ch->sample_number); - ch->block_pointer = READ_WORD(dir + 2); + + break; + + case SOUND_GAIN: + S9xSetEnvRate (ch, 0, 0); + + break; + } + + ch->xsmp_count += mod1 ? (((int64) freq * (32768 + wave[I >> 1])) >> 15) : freq; + + while (ch->xsmp_count >= 0) + { + ch->xsmp_count -= FIXED_POINT; + ch->nb_sample[ch->nb_index] = ch->sample; + ch->nb_index = (ch->nb_index + 1) & 3; + + ch->sample_pointer++; + if (ch->sample_pointer == SOUND_DECODE_LENGTH) + { + ch->sample_pointer = 0; + + if (ch->last_block) + { + S9xAPUSetEndX (J); + if (!ch->loop) + { + ch->xenvx = 0; + last_block = TRUE; + //S9xAPUSetEndOfSample (J, ch); + while (ch->xsmp_count >= 0) + { + ch->xsmp_count -= FIXED_POINT; + ch->nb_sample[ch->nb_index] = 0; + ch->nb_index = (ch->nb_index + 1) & 3; } + + break; } - DecodeBlock (ch); - } while (ch->sample_pointer >= SOUND_DECODE_LENGTH); - if (!JUST_PLAYED_LAST_SAMPLE (ch)) ch->next_sample = ch->block [ch->sample_pointer]; - } else ch->next_sample = ch->block [ch->sample_pointer]; - - if (ch->type == SOUND_SAMPLE) { - if ((Settings.InterpolatedSound) && freq < FIXED_POINT && !mod) { - ch->interpolate = ((ch->next_sample - ch->sample) * (long) freq) / (long) FIXED_POINT; - ch->sample = (int16) (ch->sample + (((ch->next_sample - ch->sample) * (long) (ch->count)) / (long) FIXED_POINT)); - } else ch->interpolate = 0; - } else { - for (;VL > 0; VL--) if (((stSoundStatus.noise_gen) <<= 1) & 0x80000000L) (stSoundStatus.noise_gen) ^= 0x0040001L; - ch->sample = ((stSoundStatus.noise_gen) << 17) >> 17; - ch->interpolate = 0; + else + { + ch->last_block = FALSE; + uint8 *dir = S9xGetSampleAddress (ch->sample_number); + ch->block_pointer = READ_WORD(dir + 2); // loop pointer + } + } + + DecodeBlock (ch); + } + + ch->sample = ch->block[ch->sample_pointer]; + } + + int32 outx, d; + + if (ch->type == SOUND_SAMPLE) + { + if (Settings.InterpolatedSound) + { + // 4-point gaussian interpolation + d = ch->xsmp_count >> (FIXED_POINT_SHIFT - 8); + outx = ((G4(-d) * ch->nb_sample[ ch->nb_index ]) >> 11) & ~1; + outx += ((G3(-d) * ch->nb_sample[(ch->nb_index + 1) & 3]) >> 11) & ~1; + outx += ((G2( d) * ch->nb_sample[(ch->nb_index + 2) & 3]) >> 11) & ~1; + outx = ((outx & 0xFFFF) ^ 0x8000) - 0x8000; + outx += ((G1( d) * ch->nb_sample[(ch->nb_index + 3) & 3]) >> 11) & ~1; + CLIP16(outx); } - - VL = ((ch->sample * ch-> left_vol_level) >> 7); - VR = ((ch->sample * ch->right_vol_level) >> 7); - } else { - if (ch->interpolate) { - int32 s = (int32) ch->sample + ch->interpolate; - - CLIP16(s); - ch->sample = (int16) s; - VL = (ch->sample * ch-> left_vol_level) / 128; - VR = (ch->sample * ch->right_vol_level) / 128; + else + outx = ch->sample; + } + else // SAMPLE_NOISE + { + noise_count -= SoundData.noise_rate; + while (noise_count <= 0) + { + noise_count += env_counter_max; + noise_index = (noise_index + 1) & 0xFF; } + + outx = noise_cache[noise_index] >> 16; } - - if (pitch_mod & (1 << (J + 1))) wave [I >> 1] = ch->sample * ch->envx; - - MixBuffer [I ] += VL; - MixBuffer [I + 1] += VR; - ch->echo_buf_ptr [I ] += VL; - ch->echo_buf_ptr [I + 1] += VR; + + outx = ((outx * ch->xenvx) >> 11) & ~1; + ch->out_sample = outx; + + if (mod2) + wave[I >> 1] = outx; + + int32 VL, VR; + + VL = (outx * ch->volume_left ) >> 7; + VR = (outx * ch->volume_right) >> 7; + + MixBuffer[I ^ Settings.ReverseStereo ] += VL; + MixBuffer[I + (1 ^ Settings.ReverseStereo)] += VR; + ch->echo_buf_ptr[I ^ Settings.ReverseStereo ] += VL; + ch->echo_buf_ptr[I + (1 ^ Settings.ReverseStereo)] += VR; } -stereo_exit: ; - } + + stereo_exit: ; + } + DoFakeMute=FALSE; + + if (APUPack.APU.DSP[APU_NON]) + SoundData.noise_count = noise_count; } +void S9xMixSamples (uint8 *buffer, int sample_count) +{ + int I, J; + + if (!stSoundStatus.mute_sound) + { + memset (MixBuffer, 0, sample_count * sizeof (MixBuffer[0])); + if (!Settings.DisableSoundEcho) + memset (EchoBuffer, 0, sample_count * sizeof (EchoBuffer[0])); + + MixStereo (sample_count); + + } + + /* Mix and convert waveforms */ + + // 16-bit sound + if (stSoundStatus.mute_sound) + memset (buffer, 0, sample_count << 1); + else + { + if (!Settings.DisableSoundEcho) + { + // 16-bit stereo sound with echo enabled ... + if (SoundData.no_filter) + { + // ... but no filter defined. + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 15] = E; + E = (E * 127) >> 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + + I = (MixBuffer[J] * SoundData.master_volume[J & 1] + + E * SoundData.echo_volume[J & 1]) >> 7; + CLIP16(I); + ((int16 *) buffer) [J] = I; + } + } + else + { + // ... with filter defined. + for (J = 0; J < sample_count; J++) + { + int E = Echo[SoundData.echo_ptr]; + + Loop[FIRIndex & 15] = E; + E = E * FilterTaps[0]; + E += Loop[(FIRIndex - 2) & 15] * FilterTaps[1]; + E += Loop[(FIRIndex - 4) & 15] * FilterTaps[2]; + E += Loop[(FIRIndex - 6) & 15] * FilterTaps[3]; + E += Loop[(FIRIndex - 8) & 15] * FilterTaps[4]; + E += Loop[(FIRIndex - 10) & 15] * FilterTaps[5]; + E += Loop[(FIRIndex - 12) & 15] * FilterTaps[6]; + E += Loop[(FIRIndex - 14) & 15] * FilterTaps[7]; + E >>= 7; + FIRIndex++; + + if (SoundData.echo_write_enabled) + { + I = EchoBuffer[J] + ((E * SoundData.echo_feedback) >> 7); + CLIP16(I); + Echo[SoundData.echo_ptr] = I; + } + else // FIXME: Snes9x's echo buffer is not in APU_RAM + Echo[SoundData.echo_ptr] = 0; + + if (++SoundData.echo_ptr >= SoundData.echo_buffer_size) + SoundData.echo_ptr = 0; + I = (MixBuffer[J] * SoundData.master_volume[J & 1] + + E * SoundData.echo_volume[J & 1]) >> 7; + CLIP16(I); + ((int16 *) buffer) [J] = I; + } + } + } + else + { + // 16-bit mono or stereo sound, no echo + for (J = 0; J < sample_count; J++) + { + I = (MixBuffer[J] * SoundData.master_volume[J & 1]) >> 7; + CLIP16(I); + ((int16 *) buffer) [J] = I; + } + } + } +} void S9xResetSound (bool8 full) { - - memset(&Echo,0,24000*4); - memset(DummyEchoBuffer,0,SOUND_BUFFER_SIZE*4); - memset(&MixBuffer,0,SOUND_BUFFER_SIZE*4); - memset(EchoBuffer,0,SOUND_BUFFER_SIZE*4); - memset(&wave,0,SOUND_BUFFER_SIZE*4); - - for (int i = 0; i < 8; i++) - { + for (int i = 0; i < NUM_CHANNELS; i++) + { SoundData.channels[i].state = SOUND_SILENT; SoundData.channels[i].mode = MODE_NONE; SoundData.channels[i].type = SOUND_SAMPLE; SoundData.channels[i].volume_left = 0; SoundData.channels[i].volume_right = 0; SoundData.channels[i].hertz = 0; - SoundData.channels[i].count = 0; SoundData.channels[i].loop = FALSE; - SoundData.channels[i].envx_target = 0; - SoundData.channels[i].env_error = 0; - SoundData.channels[i].erate = 0; - SoundData.channels[i].envx = 0; - SoundData.channels[i].envxx = 0; - SoundData.channels[i].left_vol_level = 0; - SoundData.channels[i].right_vol_level = 0; - SoundData.channels[i].direction = 0; - SoundData.channels[i].attack_rate = 0; - SoundData.channels[i].decay_rate = 0; - SoundData.channels[i].sustain_rate = 0; - SoundData.channels[i].release_rate = 0; - SoundData.channels[i].sustain_level = 0; - SoundData.echo_ptr = 0; - SoundData.echo_feedback = 0; - SoundData.echo_buffer_size = 1; - } - FilterTaps [0] = 127; - FilterTaps [1] = 0; - FilterTaps [2] = 0; - FilterTaps [3] = 0; - FilterTaps [4] = 0; - FilterTaps [5] = 0; - FilterTaps [6] = 0; - FilterTaps [7] = 0; - (stSoundStatus.mute_sound) = TRUE; - (stSoundStatus.noise_gen) = 1; - (stSoundStatus.sound_switch) = 255; - (stSoundStatus.samples_mixed_so_far) = 0; - (stSoundStatus.play_position) = 0; - (stSoundStatus.err_counter) = 0; - - if (full) - { - SoundData.master_volume_left = 0; - SoundData.master_volume_right = 0; + SoundData.channels[i].xsmp_count = 0; + SoundData.channels[i].xenvx = 0; + SoundData.channels[i].xenvx_target = 0; + SoundData.channels[i].xenv_count = 0; + SoundData.channels[i].xenv_rate = 0; + SoundData.channels[i].xattack_rate = 0; + SoundData.channels[i].xdecay_rate = 0; + SoundData.channels[i].xsustain_rate = 0; + SoundData.channels[i].xsustain_level = 0; + if(full) + { + SoundData.channels[i].out_sample = 0; + SoundData.channels[i].block_pointer = 0; + SoundData.channels[i].sample_pointer = 0; + SoundData.channels[i].sample = 0; + SoundData.channels[i].sample_number = 0; + SoundData.channels[i].last_block = 0; + for(int j = 0 ; j < 2 ; j++) SoundData.channels[i].previous[j] = 0; + for(int j = 0 ; j < 2 ; j++) SoundData.channels[i].previous16[j] = 0; + for(int j = 0 ; j < 16 ; j++) SoundData.channels[i].decoded[j] = 0; + } + } + + FilterTaps [0] = 127; + FilterTaps [1] = 0; + FilterTaps [2] = 0; + FilterTaps [3] = 0; + FilterTaps [4] = 0; + FilterTaps [5] = 0; + FilterTaps [6] = 0; + FilterTaps [7] = 0; + + rand_seed = 1; + + stSoundStatus.mute_sound = TRUE; + stSoundStatus.noise_gen = 1; + stSoundStatus.sound_switch = 255; + stSoundStatus.stereo_switch = ~0; + stSoundStatus.samples_mixed_so_far = 0; + stSoundStatus.play_position = 0; + stSoundStatus.err_counter = 0; + + if (full) + { SoundData.echo_volume_left = 0; SoundData.echo_volume_right = 0; SoundData.echo_enable = 0; SoundData.echo_write_enabled = 0; - SoundData.echo_channel_enable = 0; SoundData.pitch_mod = 0; SoundData.dummy[0] = 0; SoundData.dummy[1] = 0; SoundData.dummy[2] = 0; - SoundData.master_volume[0] = 0; - SoundData.master_volume[1] = 0; SoundData.echo_volume[0] = 0; SoundData.echo_volume[1] = 0; - SoundData.noise_hertz = 0; - } - - SoundData.master_volume_left = 127; - SoundData.master_volume_right = 127; - SoundData.master_volume [0] = SoundData.master_volume [1] = 127; - - //if ((so->playback_rate)) (so->err_rate) = (uint32) (FIXED_POINT * SNES_SCANLINE_TIME / (1.0 / (so->playback_rate))); - //else (so->err_rate) = 0; + SoundData.noise_count = 0; + SoundData.noise_rate = 0; + memset (Loop, 0, sizeof (Loop)); + memset (Echo, 0, sizeof (Echo)); + } - SoundData.no_filter = TRUE; + // At least Super Bomberman 2 requires the defaule master volume is not zero. +#if 1 + SoundData.master_volume_left = 127; + SoundData.master_volume_right = 127; + SoundData.master_volume [0] = SoundData.master_volume [1] = 127; +#else + SoundData.master_volume_left = 0; + SoundData.master_volume_right = 0; + SoundData.master_volume [0] = SoundData.master_volume [1] = 0; +#endif + SoundData.no_filter = TRUE; + SoundData.echo_ptr = 0; + SoundData.echo_feedback = 0; + SoundData.echo_buffer_size = 1; + + if (stSoundStatus.playback_rate) + stSoundStatus.err_rate = (uint32) (FIXED_POINT * SNES_SCANLINE_TIME * stSoundStatus.playback_rate); + else + stSoundStatus.err_rate = 0; } void S9xSetPlaybackRate (uint32 playback_rate) { - - (stSoundStatus.playback_rate) = playback_rate; - //(so->err_rate) = (uint32) (SNES_SCANLINE_TIME * FIXED_POINT / (1.0 / (double) (so->playback_rate))); + if (playback_rate > 48000) + playback_rate = 48000; - S9xSetEchoDelay (APUPack.APU.DSP[APU_EDL] & 0xf); - for (int i = 0; i < 8; i++) - S9xSetSoundFrequency (i, SoundData.channels [i].hertz); + stSoundStatus.playback_rate = playback_rate; + stSoundStatus.err_rate = (uint32) (FIXED_POINT * SNES_SCANLINE_TIME * stSoundStatus.playback_rate); -} + memset (Loop, 0, sizeof (Loop)); + memset (Echo, 0, sizeof (Echo)); + S9xSetEchoDelay (APUPack.APU.DSP[APU_EDL] & 0xF); -void S9xAllocSound () { -// Echo=(int*)malloc(24000*4); - DummyEchoBuffer=(int*)malloc(SOUND_BUFFER_SIZE*4); -// MixBuffer=(int*)malloc(SOUND_BUFFER_SIZE*4); -// EchoBuffer=(int*)malloc(SOUND_BUFFER_SIZE*4); -// wave=(int*)malloc(SOUND_BUFFER_SIZE*4); -} + for (int i = 0; i < NUM_CHANNELS; i++) + S9xSetSoundFrequency (i, SoundData.channels[i].hertz); -void S9xFreeSound () { -// free(Echo); - free(DummyEchoBuffer); -// free(MixBuffer); -// free(EchoBuffer); -// free(wave); + env_counter_max = env_counter_max_master * playback_rate / 32000; + SoundData.noise_count = env_counter_max; } bool8 S9xInitSound (int mode, bool8 stereo, int buffer_size) { - - - (stSoundStatus.sound_fd) = -1; - (stSoundStatus.sound_switch) = 255; - - - (stSoundStatus.playback_rate) = 0; - - (stSoundStatus.buffer_size) = 0; - - - (stSoundStatus.encoded) = FALSE; - - S9xResetSound (TRUE); - - if (!(mode & 7)) { - return (1); - } - - S9xSetSoundMute (TRUE); - if (!S9xOpenSoundDevice (mode, stereo, buffer_size)) - { + stSoundStatus.sound_fd = -1; + stSoundStatus.sound_switch = 255; + stSoundStatus.stereo_switch = ~0; + + stSoundStatus.playback_rate = 0; + stSoundStatus.buffer_size = 0; + stSoundStatus.stereo = stereo; + stSoundStatus.sixteen_bit = Settings.SixteenBitSound; + stSoundStatus.encoded = FALSE; + stSoundStatus.pitch_mul = 0.985; // XXX: necessary for most cards in linux...? + + S9xResetSound (TRUE); + + if (!(mode & 7)) + return (1); + + S9xSetSoundMute (TRUE); + if (!S9xOpenSoundDevice (mode, stereo, buffer_size)) + { + #ifdef NOSOUND + S9xMessage (S9X_WARNING, S9X_SOUND_NOT_BUILT, + "No sound support compiled in"); + #else S9xMessage (S9X_ERROR, S9X_SOUND_DEVICE_OPEN_FAILED, - "Sound device open failed"); + "Sound device open failed"); + #endif return (0); - } - - - return (1); + } + + return (1); } bool8 S9xSetSoundMode (int channel, int mode) { - Channel *ch = &SoundData.channels[channel]; - - switch (mode) - { - case MODE_RELEASE: - if (ch->mode != MODE_NONE) - { - ch->mode = MODE_RELEASE; - return (TRUE); - } - break; - - case MODE_DECREASE_LINEAR: - case MODE_DECREASE_EXPONENTIAL: - case MODE_GAIN: - if (ch->mode != MODE_RELEASE) - { - ch->mode = mode; - if (ch->state != SOUND_SILENT) - ch->state = mode; - - return (TRUE); - } - break; - - case MODE_INCREASE_LINEAR: - case MODE_INCREASE_BENT_LINE: - if (ch->mode != MODE_RELEASE) - { - ch->mode = mode; - if (ch->state != SOUND_SILENT) - ch->state = mode; - - return (TRUE); - } - break; - - case MODE_ADSR: - if (ch->mode == MODE_NONE || ch->mode == MODE_ADSR) - { - ch->mode = mode; - return (TRUE); - } - } - - return (FALSE); + Channel *ch = &SoundData.channels[channel]; + + switch (mode) + { + case MODE_RELEASE: + if (ch->mode != MODE_NONE) + { + ch->mode = MODE_RELEASE; + return (TRUE); + } + break; + + case MODE_DECREASE_LINEAR: + case MODE_DECREASE_EXPONENTIAL: + case MODE_GAIN: + if (ch->mode != MODE_RELEASE) + { + ch->mode = mode; + if (ch->state != SOUND_SILENT) + ch->state = mode; + + return (TRUE); + } + break; + + case MODE_INCREASE_LINEAR: + case MODE_INCREASE_BENT_LINE: + if (ch->mode != MODE_RELEASE) + { + ch->mode = mode; + if (ch->state != SOUND_SILENT) + ch->state = mode; + + return (TRUE); + } + break; + + case MODE_ADSR: + if (ch->mode == MODE_NONE || ch->mode == MODE_ADSR) + { + ch->mode = mode; + return (TRUE); + } + } + + return (FALSE); } void S9xSetSoundControl (int sound_switch) { - (stSoundStatus.sound_switch) = sound_switch; + stSoundStatus.sound_switch = sound_switch; } void S9xPlaySample (int channel) { - Channel *ch = &SoundData.channels[channel]; - - ch->state = SOUND_SILENT; - ch->mode = MODE_NONE; - ch->envx = 0; - ch->envxx = 0; - - S9xFixEnvelope (channel, - APUPack.APU.DSP[APU_GAIN + (channel << 4)], + Channel *ch = &SoundData.channels[channel]; + + ch->state = SOUND_SILENT; + ch->mode = MODE_NONE; + ch->xenvx = 0; + + S9xFixEnvelope (channel, + APUPack.APU.DSP[APU_GAIN + (channel << 4)], APUPack.APU.DSP[APU_ADSR1 + (channel << 4)], APUPack.APU.DSP[APU_ADSR2 + (channel << 4)]); - - ch->sample_number = APUPack.APU.DSP[APU_SRCN + channel * 0x10]; - if (APUPack.APU.DSP[APU_NON] & (1 << channel)) + + ch->sample_number = APUPack.APU.DSP[APU_SRCN + channel * 0x10]; + if (APUPack.APU.DSP[APU_NON] & (1 << channel)) ch->type = SOUND_NOISE; - else + else ch->type = SOUND_SAMPLE; - - S9xSetSoundFrequency (channel, ch->hertz); - ch->loop = FALSE; - ch->needs_decode = TRUE; - ch->last_block = FALSE; - ch->previous [0] = ch->previous[1] = 0; - uint8 *dir = S9xGetSampleAddress (ch->sample_number); - ch->block_pointer = READ_WORD (dir); - ch->sample_pointer = 0; - ch->env_error = 0; - ch->next_sample = 0; - ch->interpolate = 0; - switch (ch->mode) - { - case MODE_ADSR: - if (ch->attack_rate == 0) - { - if (ch->decay_rate == 0 || ch->sustain_level == 8) + + S9xSetSoundFrequency (channel, ch->hertz); + ch->loop = FALSE; + ch->needs_decode = TRUE; + ch->last_block = FALSE; + ch->previous[0] = ch->previous[1] = 0; + uint8 *dir = S9xGetSampleAddress (ch->sample_number); + ch->block_pointer = READ_WORD (dir); + ch->sample_pointer = 0; + ch->xenv_count = env_counter_max; + ch->xsmp_count = 3 * FIXED_POINT; // since gaussian interpolation uses 4 points + ch->nb_sample[0] = 0; + ch->nb_sample[1] = 0; + ch->nb_sample[2] = 0; + ch->nb_sample[3] = 0; + ch->nb_index = 0; + + switch (ch->mode) + { + case MODE_ADSR: // FIXME: rapid attack + #if 0 + ch->state = SOUND_ATTACK; + ch->xenvx = 0; + S9xSetEnvRate (ch, ch->xattack_rate, ENV_MAX); + break; + #else + if (ch->xattack_rate == env_counter_max_master) { - ch->state = SOUND_SUSTAIN; - ch->envx = (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3; - S9xSetEnvRate (ch, ch->sustain_rate, -1, 0); + ch->xenvx = ENV_MAX; + if (ch->xsustain_level == ENV_RANGE) + { + ch->state = SOUND_SUSTAIN; + S9xSetEnvRate (ch, ch->xsustain_rate, 0); + } + else + { + ch->state = SOUND_DECAY; + S9xSetEnvRate (ch, ch->xdecay_rate, ch->xsustain_level); + } } else { - ch->state = SOUND_DECAY; - ch->envx = MAX_ENVELOPE_HEIGHT; - S9xSetEnvRate (ch, ch->decay_rate, -1, - (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3); + ch->state = SOUND_ATTACK; + ch->xenvx = 0; + S9xSetEnvRate (ch, ch->xattack_rate, ENV_MAX); } - //ch-> left_vol_level = (ch->envx * ch->volume_left) / 128; - //ch->right_vol_level = (ch->envx * ch->volume_right) / 128; - ch-> left_vol_level = ((ch->envx * ch->volume_left) >> 7); - ch->right_vol_level = ((ch->envx * ch->volume_right) >> 7); - } - else - { - ch->state = SOUND_ATTACK; - ch->envx = 0; - ch->left_vol_level = 0; - ch->right_vol_level = 0; - S9xSetEnvRate (ch, ch->attack_rate, 1, MAX_ENVELOPE_HEIGHT); - } - ch->envxx = ch->envx << ENVX_SHIFT; - break; - - case MODE_GAIN: - ch->state = SOUND_GAIN; - break; - - case MODE_INCREASE_LINEAR: - ch->state = SOUND_INCREASE_LINEAR; - break; - - case MODE_INCREASE_BENT_LINE: - ch->state = SOUND_INCREASE_BENT_LINE; - break; - - case MODE_DECREASE_LINEAR: - ch->state = SOUND_DECREASE_LINEAR; - break; - - case MODE_DECREASE_EXPONENTIAL: - ch->state = SOUND_DECREASE_EXPONENTIAL; - break; - - default: - break; - } - - S9xFixEnvelope (channel, - APUPack.APU.DSP[APU_GAIN + (channel << 4)], - APUPack.APU.DSP[APU_ADSR1 + (channel << 4)], - APUPack.APU.DSP[APU_ADSR2 + (channel << 4)]); -} - - -void S9xMixSamples (uint8 *buffer, int sample_count) -{ - int J; - int I; - - if (!(stSoundStatus.mute_sound)) - { - memset (&MixBuffer, 0, sample_count * 4); - - if (SoundData.echo_enable) memset (EchoBuffer, 0, sample_count * 4); - - MixStereo (sample_count); - - - } - /* Mix and convert waveforms */ - - { + break; + #endif - int byte_count = sample_count << 1; + case MODE_GAIN: + ch->state = SOUND_GAIN; + break; + case MODE_INCREASE_LINEAR: + ch->state = SOUND_INCREASE_LINEAR; + break; - - // 16-bit sound - if ((stSoundStatus.mute_sound)) - { - memset (buffer, 0, byte_count); - } - else - { - if (SoundData.echo_enable && SoundData.echo_buffer_size) - { - - { - - // 16-bit stereo sound with echo enabled ... - if (SoundData.no_filter) - { - // ... but no filter defined. - - for (J = 0; J < sample_count; J++) - { - int E = Echo [SoundData.echo_ptr]; - - Echo [SoundData.echo_ptr] = ((E * SoundData.echo_feedback) >> 7) + EchoBuffer [J]; - - if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size) SoundData.echo_ptr = 0; - - I = (MixBuffer [J] * SoundData.master_volume [J & 1] + E * SoundData.echo_volume [J & 1]) >> VOL16_SHIFT;/// VOL_DIV16; - - CLIP16(I); - ((signed short *) buffer)[J] = I; + case MODE_INCREASE_BENT_LINE: + ch->state = SOUND_INCREASE_BENT_LINE; + break; - } - - } - else - { - // ... with filter defined. - - - - for (J = 0; J < sample_count; J++) - { - int E = Echo [SoundData.echo_ptr]; - - Loop [(Z - 0) & 15] = E; - E = E * FilterTaps [0]; - E += Loop [(Z - 2) & 15] * FilterTaps [1]; - E += Loop [(Z - 4) & 15] * FilterTaps [2]; - E += Loop [(Z - 6) & 15] * FilterTaps [3]; - E += Loop [(Z - 8) & 15] * FilterTaps [4]; - E += Loop [(Z - 10) & 15] * FilterTaps [5]; - E += Loop [(Z - 12) & 15] * FilterTaps [6]; - E += Loop [(Z - 14) & 15] * FilterTaps [7]; - E /= 128; - Z++; - - //Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 + - // EchoBuffer [J]; - Echo [SoundData.echo_ptr] = ((E * SoundData.echo_feedback) >> 7) + - EchoBuffer [J]; - - if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size) - SoundData.echo_ptr = 0; - - I = (MixBuffer [J] * SoundData.master_volume [J & 1] + E * SoundData.echo_volume [J & 1]) >> VOL16_SHIFT;/// VOL_DIV16; - - CLIP16(I); - ((signed short *) buffer)[J] = I; + case MODE_DECREASE_LINEAR: + ch->state = SOUND_DECREASE_LINEAR; + break; - } - - } - } - } - else - { - // 16-bit mono or stereo sound, no echo - for (J = 0; J < sample_count; J++) - { - I = (MixBuffer [J] * SoundData.master_volume [J & 1]) >> VOL16_SHIFT;/// VOL_DIV16; - CLIP16(I); - ((signed short *) buffer)[J] = I; + case MODE_DECREASE_EXPONENTIAL: + ch->state = SOUND_DECREASE_EXPONENTIAL; + break; - } - - } - } - } + default: + break; + } - + S9xFixEnvelope (channel, + APUPack.APU.DSP[APU_GAIN + (channel << 4)], + APUPack.APU.DSP[APU_ADSR1 + (channel << 4)], + APUPack.APU.DSP[APU_ADSR2 + (channel << 4)]); } diff --git a/soundux.h b/soundux.h index 2ee32bd..c417013 100644 --- a/soundux.h +++ b/soundux.h @@ -1,134 +1,235 @@ -/******************************************************************************* +/********************************************************************************** Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. - - (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and - Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2001 - 2004 John Weidman (jweidman@slip.net) + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) - (c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net), - funkyass (funkyass@spam.shaw.ca), - Joel Yliluoma (http://iki.fi/bisqwit/) - Kris Bleakley (codeviolation@hotmail.com), - Matthew Kendora, - Nach (n-a-c-h@users.sourceforge.net), - Peter Bortas (peter@bortas.org) and - zones (kasumitokoduck@yahoo.com) + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2007 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones C4 x86 assembler and some C emulation code - (c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com), - _Demo_ (_demo_@zsnes.com), and Nach + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) C4 C++ code - (c) Copyright 2003 Brad Jorsch + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach DSP-1 emulator code - (c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson, - John Weidman, neviksti (neviksti@hotmail.com), - Kris Bleakley, Andreas Naive + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com) + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) DSP-2 emulator code - (c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and - Lord Nightmare (lord_nightmare@users.sourceforge.net + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden OBC1 emulator code - (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and - Kris Bleakley - Ported from x86 assembler to C by sanmaiwashi + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley, + Ported from x86 assembler to C by sanmaiwashi SPC7110 and RTC C++ emulator code - (c) Copyright 2002 Matthew Kendora with research by - zsKnight, John Weidman, and Dark Force + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force S-DD1 C emulator code - (c) Copyright 2003 Brad Jorsch with research by - Andreas Naive and John Weidman - + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + S-RTC C emulator code - (c) Copyright 2001 John Weidman - + (c) Copyright 2001-2006 byuu, + John Weidman + ST010 C++ emulator code - (c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + 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 _Demo_, + pagefault, + zsKnight, - Super FX C emulator code - (c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + Sound DSP emulator code is derived from SNEeSe and OpenSPC: + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' 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) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2007 zones + - 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. - + + Permission to use, copy, modify and/or 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. - + arising from the use of this software or it's derivatives. + 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. - + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + 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. -*******************************************************************************/ +**********************************************************************************/ + #ifndef _SOUND_H_ #define _SOUND_H_ -enum { SOUND_SAMPLE = 0, SOUND_NOISE, SOUND_EXTRA_NOISE, SOUND_MUTE }; -enum { SOUND_SILENT, SOUND_ATTACK, SOUND_DECAY, SOUND_SUSTAIN, - SOUND_RELEASE, SOUND_GAIN, SOUND_INCREASE_LINEAR, - SOUND_INCREASE_BENT_LINE, SOUND_DECREASE_LINEAR, - SOUND_DECREASE_EXPONENTIAL}; - -enum { MODE_NONE = SOUND_SILENT, MODE_ADSR, MODE_RELEASE = SOUND_RELEASE, - MODE_GAIN, MODE_INCREASE_LINEAR, MODE_INCREASE_BENT_LINE, - MODE_DECREASE_LINEAR, MODE_DECREASE_EXPONENTIAL}; - -#define MAX_ENVELOPE_HEIGHT 127 -#define ENVELOPE_SHIFT 7 -#define MAX_VOLUME 127 -#define VOLUME_SHIFT 7 -#define VOL_DIV 128 -#define SOUND_DECODE_LENGTH 16 - -#define NUM_CHANNELS 8 -#define SOUND_BUFFER_SIZE (1024 * 16) -#define MAX_BUFFER_SIZE SOUND_BUFFER_SIZE -#define SOUND_BUFFER_SIZE_MASK (SOUND_BUFFER_SIZE - 1) +enum +{ + SOUND_SAMPLE = 0, + SOUND_NOISE +}; -#define SOUND_BUFS 4 +enum +{ + SOUND_SILENT, + SOUND_ATTACK, + SOUND_DECAY, + SOUND_SUSTAIN, + SOUND_RELEASE, + SOUND_GAIN, + SOUND_INCREASE_LINEAR, + SOUND_INCREASE_BENT_LINE, + SOUND_DECREASE_LINEAR, + SOUND_DECREASE_EXPONENTIAL +}; + +enum +{ + MODE_NONE = SOUND_SILENT, + MODE_ADSR, + MODE_RELEASE = SOUND_RELEASE, + MODE_GAIN, + MODE_INCREASE_LINEAR, + MODE_INCREASE_BENT_LINE, + MODE_DECREASE_LINEAR, + MODE_DECREASE_EXPONENTIAL +}; + +#define NUM_CHANNELS 8 +#define SOUND_DECODE_LENGTH 16 +#define SOUND_BUFFER_SIZE (1024 * 16) +#define MAX_BUFFER_SIZE SOUND_BUFFER_SIZE +#define SOUND_BUFFER_SIZE_MASK (SOUND_BUFFER_SIZE - 1) + +#define ENV_RANGE 0x800 +#define ENV_MAX 0x7FF +#define ENV_SHIFT 4 + +#ifdef __sgi +#include +#endif /* __sgi */ typedef struct { - int sound_fd; - int sound_switch; -//#ifndef PSP - int playback_rate; -//#endif // PSP - int buffer_size; - int noise_gen; - bool8 mute_sound; - - bool8 encoded; - uint16 sp; - int32 samples_mixed_so_far; - int32 play_position; - uint32 err_counter; - uint32 err_rate; + int sound_fd; // ** port specific + int sound_switch; // channel on/off + int playback_rate; // 32000Hz is recommended + int buffer_size; // ** port specific + int noise_gen; // ** unused + bool8 mute_sound; // mute + int stereo; // stereo or mono + bool8 sixteen_bit; // 16bit or 8bit sample + bool8 encoded; // ** port specific +#ifdef __sun + int last_eof; // ** port specific +#endif +#ifdef __sgi + ALport al_port; // ** port specific +#endif /* __sgi */ + int32 samples_mixed_so_far; // ** port specific + int32 play_position; // ** port specific + uint32 err_counter; // ** port specific + uint32 err_rate; // ** port specific + + uint16 stereo_switch; // stereo channel on/off + double pitch_mul; // used with Settings.FixFrequency } SoundStatus; #ifdef ME_SOUND @@ -140,81 +241,81 @@ EXTERN_C SoundStatus stSoundStatus; #endif typedef struct { - int state; - int type; - short volume_left; - short volume_right; - uint32 hertz; - uint32 frequency; - uint32 count; - int envx; - - short left_vol_level; - short right_vol_level; - - short envx_target; - signed short sample; - - signed short decoded [16]; - signed short previous16 [2]; - - signed short *block; - uint16 sp; - - unsigned long int env_error; - - unsigned long erate; - int direction; - unsigned long attack_rate; - unsigned long decay_rate; - unsigned long sustain_rate; - unsigned long release_rate; - unsigned long sustain_level; - - uint16 sample_number; - bool8 last_block; - bool8 needs_decode; - - uint32 block_pointer; - uint32 sample_pointer; - int *echo_buf_ptr; - int mode; - int32 envxx; - - signed short next_sample; - uint16 sp2; - int32 interpolate; - int32 previous [2]; - // Just incase they are needed in the future, for snapshot compatibility. - uint32 dummy [8]; - bool8 loop; - uint8 sp3[3]; -// unsigned short last_valid_header; + int32 state; // ADSR/GAIN/RELEASE/SILENT + int32 type; // sample or noise + short volume_left; // VOL(L) + short volume_right; // VOL(R) + uint32 hertz; // ((P(H) << 8) + P(L)) * 8 + uint32 frequency; // normalized pitch + uint32 count; // ** unused + bool8 loop; // loop flag in BRR header + int32 envx; // ** unused + short left_vol_level; // ** unused + short right_vol_level; // ** unused + short envx_target; // ** unused + uint32 env_error; // ** unused + uint32 erate; // ** unused + int32 direction; // ** unused + uint32 attack_rate; // ** unused + uint32 decay_rate; // ** unused + uint32 sustain_rate; // ** unused + uint32 release_rate; // ** unused + uint32 sustain_level; // ** unused + signed short sample; // signed 16 bit sample + signed short decoded[16]; // decoded 16 samples + signed short previous16[2]; + signed short *block; + uint16 sample_number; // SRCN + bool8 last_block; // end flag in BRR header + bool8 needs_decode; // true when BRR block will be decoded + uint32 block_pointer; // currect block + uint32 sample_pointer; // pointer in a block + int32 *echo_buf_ptr; // EchoBuffer[] or DummyEchoBuffer[] + int32 mode; // ADSR/GAIN/RELEASE/SILENT + int32 envxx; // ** unused + signed short next_sample; // ** unused + int32 interpolate; // ** unused + int32 previous[2]; // last two nybbles for BRR decode + uint32 dummy[8]; // Just incase they are needed in the future, + // for snapshot compatibility. + + int32 nb_index; // index of cached samples + int16 nb_sample[4]; // cached samples for interpolation + int16 out_sample; // OUTX << 4 + int32 xenvx; // ENVX << 4 + int32 xenvx_target; // ENVX target << 4 + int32 xenv_count; // counter for envelope timing + int32 xenv_rate; // envelope timing from env_counter_table + int32 xsmp_count; // counter for pitch + int32 xattack_rate; // envelope timing from env_counter_table + int32 xdecay_rate; // envelope timing from env_counter_table + int32 xsustain_rate; // envelope timing from env_counter_table + int32 xsustain_level; // (128 / 8 * (SR + 1)) << 4 } Channel; typedef struct { - short master_volume_left; - short master_volume_right; - - short echo_volume_left; - short echo_volume_right; - - int echo_enable; - int echo_feedback; - int echo_ptr; - int echo_buffer_size; - int echo_write_enabled; - int echo_channel_enable; - int pitch_mod; - - // Just incase they are needed in the future, for snapshot compatibility. - uint32 dummy [3]; - int master_volume [2]; - int echo_volume [2]; - int noise_hertz; - Channel channels [NUM_CHANNELS]; - bool8 no_filter; + short master_volume_left; // MVOL(L) + short master_volume_right; // MVOL(R) + short echo_volume_left; // EVOL(L) + short echo_volume_right; // EVOL(R) + int32 echo_enable; // EON + int32 echo_feedback; // EFB + int32 echo_ptr; // index of Echo[] + int32 echo_buffer_size; // num of echo samples + int32 echo_write_enabled; // ECEN + int32 echo_channel_enable; // ** unused + int32 pitch_mod; // PMOD + uint32 dummy[3]; // Just incase they are needed in the future, + // for snapshot compatibility. + Channel channels[NUM_CHANNELS]; + bool8 no_filter; // true when simple echo + int32 master_volume[2]; + int32 echo_volume[2]; + int32 noise_hertz; // ** unused + + int32 noise_count; // counter for noise frequency + int32 noise_rate; // noise frequency from env_counter_table } SSoundData; #ifdef ME_SOUND @@ -226,46 +327,35 @@ EXTERN_C SSoundData SoundData; EXTERN_C SSoundData SoundData; #endif - +void S9xSetEnvelopeRate (int channel, int32 rate_count, int32 xtarget); void S9xSetSoundVolume (int channel, short volume_left, short volume_right); -void S9xSetSoundFrequency (int channel, int hertz); -void S9xSetSoundHertz (int channel, int hertz); -void S9xSetSoundType (int channel, int type_of_sound); -void S9xSetMasterVolume (short master_volume_left, short master_volume_right); -void S9xSetEchoVolume (short echo_volume_left, short echo_volume_right); -void S9xSetSoundControl (int sound_switch); -bool8 S9xSetSoundMute (bool8 mute); -void S9xSetEnvelopeHeight (int channel, int height); -void S9xSetSoundADSR (int channel, int attack, int decay, int sustain, - int sustain_level, int release); -void S9xSetSoundKeyOff (int channel); -void S9xSetSoundDecayMode (int channel); -void S9xSetSoundAttachMode (int channel); -void S9xSoundStartEnvelope (Channel *); -void S9xSetSoundSample (int channel, uint16 sample_number); -void S9xSetEchoFeedback (int echo_feedback); +void S9xSetMasterVolume (short volume_left, short volume_right); +void S9xSetEchoVolume (short volume_left, short volume_right); void S9xSetEchoEnable (uint8 byte); -void S9xSetEchoDelay (int byte); +void S9xSetEchoFeedback (int echo_feedback); +void S9xSetEchoDelay (unsigned int byte); void S9xSetEchoWriteEnable (uint8 byte); -void S9xSetFilterCoefficient (int tap, int value); void S9xSetFrequencyModulationEnable (uint8 byte); -void S9xSetEnvelopeRate (int channel, unsigned long rate, int direction, - int target); -bool8 S9xSetSoundMode (int channel, int mode); -int S9xGetEnvelopeHeight (int channel); +void S9xSetSoundKeyOff (int channel); +void S9xPrepareSoundForSnapshotSave (bool8 restore); +void S9xFixSoundAfterSnapshotLoad (int version); +void S9xSetFilterCoefficient (int tap, int value); +void S9xSetSoundADSR (int channel, int ar, int dr, int sr, int sl); +void S9xSetEnvelopeHeight (int channel, int32 xlevel); +uint8 S9xGetEnvelopeHeight (int channel); +void S9xSetSoundHertz (int channel, int hertz); +void S9xSetSoundType (int channel, int type_of_sound); +bool8 S9xSetSoundMute (bool8 mute); void S9xResetSound (bool8 full); -void S9xFixSoundAfterSnapshotLoad (); -void S9xPlaybackSoundSetting (int channel); +void S9xSetPlaybackRate (uint32 playback_rate); +bool8 S9xSetSoundMode (int channel, int mode); +void S9xSetSoundControl (int sound_switch); void S9xPlaySample (int channel); + void S9xFixEnvelope (int channel, uint8 gain, uint8 adsr1, uint8 adsr2); -void S9xStartSample (int channel); +bool8 S9xOpenSoundDevice (int mode, bool8 stereo, int buffer_size); EXTERN_C void S9xMixSamples (uint8 *buffer, int sample_count); -bool8 S9xOpenSoundDevice (int, bool8, int); -void S9xSetPlaybackRate (uint32 rate); +EXTERN_C void S9xMixSamplesO (uint8 *buffer, int sample_count, int byte_offset); -EXTERN_C void S9xFreeSound (); -EXTERN_C void S9xAllocSound (); -EXTERN_C bool8 S9xInitSound (int mode, bool8 stereo, int buffer_size); #endif -