From 456672168ebb8d0d399af6889b5f1069d1e72ba0 Mon Sep 17 00:00:00 2001 From: arcum42 Date: Sat, 2 May 2009 03:41:03 +0000 Subject: [PATCH] And there goes SPU2null. This one deserves a lot more work, though. A real gui and backporting all the changes I made to ZeroSPU2, for starters. (And again, Windows may or may not compile for it. Looking at the Visual C++ file, I'm pretty sure it already wasn't compiling. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1109 96395faa-99c1-11dd-bbfe-3dabce05a288 --- plugins/SPU2null/{Src => }/Changelog.txt | 0 plugins/SPU2null/Linux/Config.cpp | 86 ++ plugins/SPU2null/Makefile.am | 27 + plugins/SPU2null/SPU2.cpp | 1287 +++++++++++++++++ plugins/SPU2null/SPU2.h | 293 ++++ plugins/SPU2null/Src/Makefile | 25 - plugins/SPU2null/Src/SPU2.cpp | 1213 ---------------- plugins/SPU2null/Src/SPU2.h | 280 ---- plugins/SPU2null/{Src => Windows}/Config.cpp | 0 .../{Src => Windows}/ProjectRootDir.vsprops | 0 .../SPU2null/{Src => Windows}/SPU2null.def | 0 plugins/SPU2null/{Src => Windows}/SPU2null.rc | 0 .../{Src => Windows}/SPU2null_2008.vcproj | 12 +- plugins/SPU2null/{Src => Windows}/Win32.cpp | 0 plugins/SPU2null/{Src => Windows}/resource.h | 0 plugins/SPU2null/build.sh | 31 +- plugins/SPU2null/configure.ac | 80 + plugins/SPU2null/install-sh | 1 + plugins/SPU2null/missing | 1 + 19 files changed, 1806 insertions(+), 1530 deletions(-) rename plugins/SPU2null/{Src => }/Changelog.txt (100%) create mode 100644 plugins/SPU2null/Linux/Config.cpp create mode 100644 plugins/SPU2null/Makefile.am create mode 100644 plugins/SPU2null/SPU2.cpp create mode 100644 plugins/SPU2null/SPU2.h delete mode 100644 plugins/SPU2null/Src/Makefile delete mode 100644 plugins/SPU2null/Src/SPU2.cpp delete mode 100644 plugins/SPU2null/Src/SPU2.h rename plugins/SPU2null/{Src => Windows}/Config.cpp (100%) rename plugins/SPU2null/{Src => Windows}/ProjectRootDir.vsprops (100%) rename plugins/SPU2null/{Src => Windows}/SPU2null.def (100%) rename plugins/SPU2null/{Src => Windows}/SPU2null.rc (100%) rename plugins/SPU2null/{Src => Windows}/SPU2null_2008.vcproj (89%) rename plugins/SPU2null/{Src => Windows}/Win32.cpp (100%) rename plugins/SPU2null/{Src => Windows}/resource.h (100%) create mode 100644 plugins/SPU2null/configure.ac create mode 120000 plugins/SPU2null/install-sh create mode 120000 plugins/SPU2null/missing diff --git a/plugins/SPU2null/Src/Changelog.txt b/plugins/SPU2null/Changelog.txt similarity index 100% rename from plugins/SPU2null/Src/Changelog.txt rename to plugins/SPU2null/Changelog.txt diff --git a/plugins/SPU2null/Linux/Config.cpp b/plugins/SPU2null/Linux/Config.cpp new file mode 100644 index 0000000000..a42fc933a1 --- /dev/null +++ b/plugins/SPU2null/Linux/Config.cpp @@ -0,0 +1,86 @@ +/* SPU2null + * Copyright (C) 2002-2005 SPU2null Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "SPU2.h" + +#include +#include + +GtkWidget *MsgDlg; + +void OnMsg_Ok() +{ + gtk_widget_destroy(MsgDlg); + gtk_main_quit(); +} + +void SysMessage(char *fmt, ...) +{ + GtkWidget *Ok, *Txt; + GtkWidget *Box, *Box1; + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + MsgDlg = gtk_window_new(GTK_WINDOW_POPUP); + gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg"); + gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); + + Box = gtk_vbox_new(5, 0); + gtk_container_add(GTK_CONTAINER(MsgDlg), Box); + gtk_widget_show(Box); + + Txt = gtk_label_new(msg); + + gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); + gtk_widget_show(Txt); + + Box1 = gtk_hbutton_box_new(); + gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); + gtk_widget_show(Box1); + + Ok = gtk_button_new_with_label("Ok"); + gtk_signal_connect(GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); + gtk_container_add(GTK_CONTAINER(Box1), Ok); + GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); + gtk_widget_show(Ok); + + gtk_widget_show(MsgDlg); + + gtk_main(); +} + +EXPORT_C_(void) SPU2configure() +{ + SysMessage("Nothing to Configure"); +} + +EXPORT_C_(void) SPU2about() +{ + SysMessage("%s %d.%d", libraryName, version, build); +} + +void LoadConfig() +{ +} diff --git a/plugins/SPU2null/Makefile.am b/plugins/SPU2null/Makefile.am new file mode 100644 index 0000000000..394dba22a3 --- /dev/null +++ b/plugins/SPU2null/Makefile.am @@ -0,0 +1,27 @@ +# Create a shared library libSPU2null +AUTOMAKE_OPTIONS = foreign +noinst_LIBRARIES = libSPU2null.a +INCLUDES = -I@srcdir@/../../common/include -I@srcdir@/../../3rdparty -I@srcdir@/Linux + +libSPU2null_a_CXXFLAGS = $(shell pkg-config --cflags gtk+-2.0) +libSPU2null_a_CFLAGS = $(shell pkg-config --cflags gtk+-2.0) + +# Create a shared object by faking an exe (thanks to ODE makefiles) +traplibdir=$(prefix) + +if DEBUGBUILD +preext=d +endif + +EXEEXT=$(preext)@so_ext@ + +traplib_PROGRAMS=libSPU2null +libSPU2null_SOURCES= +libSPU2null_DEPENDENCIES = libSPU2null.a +libSPU2null_LDFLAGS= @SHARED_LDFLAGS@ +libSPU2null_LDFLAGS+=-Wl,-soname,@libSPU2null_SONAME@ +libSPU2null_LDADD=$(libSPU2null_a_OBJECTS) + +libSPU2null_a_SOURCES = SPU2.cpp SPU2.h Linux/Config.cpp + +#SUBDIRS = Linux \ No newline at end of file diff --git a/plugins/SPU2null/SPU2.cpp b/plugins/SPU2null/SPU2.cpp new file mode 100644 index 0000000000..e8a8e23697 --- /dev/null +++ b/plugins/SPU2null/SPU2.cpp @@ -0,0 +1,1287 @@ +/* SPU2null + * Copyright (C) 2002-2005 SPU2null Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "SPU2.h" + +#include +#include + +const unsigned char version = PS2E_SPU2_VERSION; +const unsigned char revision = 0; +const unsigned char build = 7; // increase that with each version +const unsigned int minor = 1; // increase that with each version + +// ADSR constants +#define ATTACK_MS 494L +#define DECAYHALF_MS 286L +#define DECAY_MS 572L +#define SUSTAIN_MS 441L +#define RELEASE_MS 437L + +#ifdef _DEBUG +char *libraryName = "SPU2null (Debug)"; +#else +char *libraryName = "SPU2null "; +#endif + +FILE *spu2Log; +Config conf; + +ADMA Adma4; +ADMA Adma7; + +u32 MemAddr[2]; +u32 g_nSpuInit = 0; +unsigned short interrupt = 0; +s8 *spu2regs = NULL; +u16* spu2mem = NULL; +u16* pSpuIrq[2] = {NULL}; +u32 dwEndChannel2[2] = {0}; // keeps track of what channels have ended +unsigned long dwNoiseVal = 1; // global noise generator + +int SPUCycles = 0, SPUWorkerCycles = 0; +int SPUStartCycle[2]; +int SPUTargetCycle[2]; + +int ADMAS4Write(); +int ADMAS7Write(); + +void InitADSR(); + +void (*irqCallbackSPU2)(); // func of main emu, called on spu irq +void (*irqCallbackDMA4)() = 0; // func of main emu, called on spu irq +void (*irqCallbackDMA7)() = 0; // func of main emu, called on spu irq + +const int f[5][2] = { + { 0, 0 }, + { 60, 0 }, + { 115, -52 }, + { 98, -55 }, + { 122, -60 } +}; + +u32 RateTable[160]; + +// channels and voices +VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; // +1 for modulation + +EXPORT_C_(u32) PS2EgetLibType() +{ + return PS2E_LT_SPU2; +} + +EXPORT_C_(char*) PS2EgetLibName() +{ + return libraryName; +} + +EXPORT_C_(u32) PS2EgetLibVersion2(u32 type) +{ + return (version << 16) | (revision << 8) | build | (minor << 24); +} + +void __Log(char *fmt, ...) +{ + va_list list; + + if (!conf.Log || spu2Log == NULL) return; + + va_start(list, fmt); + vfprintf(spu2Log, fmt, list); + va_end(list); +} + +EXPORT_C_(s32) SPU2init() +{ +#ifdef SPU2_LOG + spu2Log = fopen("logs/spu2.txt", "w"); + if (spu2Log) setvbuf(spu2Log, NULL, _IONBF, 0); + SPU2_LOG("Spu2 null version %d,%d\n", revision, build); + SPU2_LOG("SPU2init\n"); +#endif + spu2regs = (s8*)malloc(0x10000); + if (spu2regs == NULL) + { + SysMessage("Error allocating Memory\n"); + return -1; + } + memset(spu2regs, 0, 0x10000); + + spu2mem = (u16*)malloc(0x200000); // 2Mb + if (spu2mem == NULL) + { + SysMessage("Error allocating Memory\n"); + return -1; + } + memset(spu2mem, 0, 0x200000); + memset(dwEndChannel2, 0, sizeof(dwEndChannel2)); + + InitADSR(); + + memset(voices, 0, sizeof(voices)); + // last 24 channels have higher mem offset + for (int i = 0; i < 24; ++i) + voices[i+24].memoffset = 0x400; + + // init each channel + for (u32 i = 0; i < ArraySize(voices); ++i) + { + + voices[i].pLoop = voices[i].pStart = voices[i].pCurr = (u8*)spu2mem; + + voices[i].pvoice = (_SPU_VOICE*)((u8*)spu2regs + voices[i].memoffset) + (i % 24); + voices[i].ADSRX.SustainLevel = 1024; // -> init sustain + } + + return 0; +} + +EXPORT_C_(s32) SPU2open(void *pDsp) +{ + LoadConfig(); + SPUCycles = SPUWorkerCycles = 0; + interrupt = 0; + SPUStartCycle[0] = SPUStartCycle[1] = 0; + SPUTargetCycle[0] = SPUTargetCycle[1] = 0; + g_nSpuInit = 1; + return 0; +} + +EXPORT_C_(void) SPU2close() +{ + g_nSpuInit = 0; +} + +EXPORT_C_(void) SPU2shutdown() +{ + free(spu2regs); + spu2regs = NULL; + free(spu2mem); + spu2mem = NULL; +#ifdef SPU2_LOG + if (spu2Log) fclose(spu2Log); +#endif +} + +// simulate SPU2 for 1ms +void SPU2Worker(); + +#define CYCLES_PER_MS (36864000/1000) + +EXPORT_C_(void) SPU2async(u32 cycle) +{ + SPUCycles += cycle; + if (interrupt & (1 << 2)) + { + if (SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]) + { + interrupt &= ~(1 << 2); + irqCallbackDMA7(); + } + + } + + if (interrupt & (1 << 1)) + { + if (SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]) + { + interrupt &= ~(1 << 1); + irqCallbackDMA4(); + } + } + + if (g_nSpuInit) + { + + while (SPUCycles - SPUWorkerCycles > 0 && CYCLES_PER_MS < SPUCycles - SPUWorkerCycles) + { + SPU2Worker(); + SPUWorkerCycles += CYCLES_PER_MS; + } + } +} + +void InitADSR() // INIT ADSR +{ + unsigned long r, rs, rd; + int i; + memset(RateTable, 0, sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file) + + r = 3; + rs = 1; + rd = 0; + + for (i = 32;i < 160;i++) // we start at pos 32 with the real values... everything before is 0 + { + if (r < 0x3FFFFFFF) + { + r += rs; + rd++; + if (rd == 5) + { + rd = 1; + rs *= 2; + } + } + if (r > 0x3FFFFFFF) r = 0x3FFFFFFF; + + RateTable[i] = r; + } +} + +int MixADSR(VOICE_PROCESSED* pvoice) // MIX ADSR +{ + if (pvoice->bStop) // should be stopped: + { + if (pvoice->bIgnoreLoop == 0) + { + pvoice->ADSRX.EnvelopeVol = 0; + pvoice->bOn = false; + pvoice->pStart = (u8*)(spu2mem + pvoice->iStartAddr); + pvoice->pLoop = (u8*)(spu2mem + pvoice->iStartAddr); + pvoice->pCurr = (u8*)(spu2mem + pvoice->iStartAddr); + pvoice->bStop = true; + pvoice->bIgnoreLoop = false; + return 0; + } + if (pvoice->ADSRX.ReleaseModeExp)// do release + { + switch ((pvoice->ADSRX.EnvelopeVol >> 28)&0x7) + { + case 0: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; + break; + case 1: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; + break; + case 2: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; + break; + case 3: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; + break; + case 4: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; + break; + case 5: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; + break; + case 6: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; + break; + case 7: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; + break; + } + } + else + { + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x0C + 32]; + } + + if (pvoice->ADSRX.EnvelopeVol < 0) + { + pvoice->ADSRX.EnvelopeVol = 0; + pvoice->bOn = false; + pvoice->pStart = (u8*)(spu2mem + pvoice->iStartAddr); + pvoice->pLoop = (u8*)(spu2mem + pvoice->iStartAddr); + pvoice->pCurr = (u8*)(spu2mem + pvoice->iStartAddr); + pvoice->bStop = true; + pvoice->bIgnoreLoop = false; + //pvoice->bReverb=0; + //pvoice->bNoise=0; + } + + pvoice->ADSRX.lVolume = pvoice->ADSRX.EnvelopeVol >> 21; + pvoice->ADSRX.lVolume = pvoice->ADSRX.EnvelopeVol >> 21; + return pvoice->ADSRX.lVolume; + } + else // not stopped yet? + { + if (pvoice->ADSRX.State == 0) // -> attack + { + if (pvoice->ADSRX.AttackModeExp) + { + if (pvoice->ADSRX.EnvelopeVol < 0x60000000) + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x10 + 32]; + else + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x18 + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x10 + 32]; + } + + if (pvoice->ADSRX.EnvelopeVol < 0) + { + pvoice->ADSRX.EnvelopeVol = 0x7FFFFFFF; + pvoice->ADSRX.State = 1; + } + + pvoice->ADSRX.lVolume = pvoice->ADSRX.EnvelopeVol >> 21; + return pvoice->ADSRX.lVolume; + } + //--------------------------------------------------// + if (pvoice->ADSRX.State == 1) // -> decay + { + switch ((pvoice->ADSRX.EnvelopeVol >> 28)&0x7) + { + case 0: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+0 + 32]; + break; + case 1: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+4 + 32]; + break; + case 2: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+6 + 32]; + break; + case 3: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+8 + 32]; + break; + case 4: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+9 + 32]; + break; + case 5: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+10+ 32]; + break; + case 6: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+11+ 32]; + break; + case 7: + pvoice->ADSRX.EnvelopeVol -= RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+12+ 32]; + break; + } + + if (pvoice->ADSRX.EnvelopeVol < 0) pvoice->ADSRX.EnvelopeVol = 0; + if (((pvoice->ADSRX.EnvelopeVol >> 27)&0xF) <= pvoice->ADSRX.SustainLevel) + { + pvoice->ADSRX.State = 2; + } + + pvoice->ADSRX.lVolume = pvoice->ADSRX.EnvelopeVol >> 21; + return pvoice->ADSRX.lVolume; + } + //--------------------------------------------------// + if (pvoice->ADSRX.State == 2) // -> sustain + { + if (pvoice->ADSRX.SustainIncrease) + { + if (pvoice->ADSRX.SustainModeExp) + { + if (pvoice->ADSRX.EnvelopeVol < 0x60000000) + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x10 + 32]; + else + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x18 + 32]; + } + else + { + pvoice->ADSRX.EnvelopeVol += RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x10 + 32]; + } + + if (pvoice->ADSRX.EnvelopeVol < 0) + { + pvoice->ADSRX.EnvelopeVol = 0x7FFFFFFF; + } + } + else + { + if (pvoice->ADSRX.SustainModeExp) + { + switch ((pvoice->ADSRX.EnvelopeVol >> 28)&0x7) + { + case 0: + pvoice->ADSRX.EnvelopeVol -= RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +0 + 32]; + break; + case 1: + pvoice->ADSRX.EnvelopeVol -= RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +4 + 32]; + break; + case 2: + pvoice->ADSRX.EnvelopeVol -= RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +6 + 32]; + break; + case 3: + pvoice->ADSRX.EnvelopeVol -= RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +8 + 32]; + break; + case 4: + pvoice->ADSRX.EnvelopeVol -= RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +9 + 32]; + break; + case 5: + pvoice->ADSRX.EnvelopeVol -= RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +10+ 32]; + break; + case 6: + pvoice->ADSRX.EnvelopeVol -= RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +11+ 32]; + break; + case 7: + pvoice->ADSRX.EnvelopeVol -= RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +12+ 32]; + break; + } + } + else + { + pvoice->ADSRX.EnvelopeVol -= RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x0F + 32]; + } + + if (pvoice->ADSRX.EnvelopeVol < 0) + { + pvoice->ADSRX.EnvelopeVol = 0; + } + } + pvoice->ADSRX.lVolume = pvoice->ADSRX.EnvelopeVol >> 21; + return pvoice->ADSRX.lVolume; + } + } + return 0; +} + +// simulate SPU2 for 1ms +void SPU2Worker() +{ + u8* start; + int ch, flags; + + VOICE_PROCESSED* pChannel = voices; + for (ch = 0;ch < SPU_NUMBER_VOICES;ch++, pChannel++) // loop em all... we will collect 1 ms of sound of each playing channel + { + if (pChannel->bNew) + { + pChannel->StartSound(); // start new sound + dwEndChannel2[ch/24] &= ~(1 << (ch % 24)); // clear end channel bit + } + + if (!pChannel->bOn) + { + // fill buffer with empty data + continue; + } + + if (pChannel->iActFreq != pChannel->iUsedFreq) // new psx frequency? + pChannel->VoiceChangeFrequency(); + + // loop until 1 ms of data is reached + int ns = 0; + while (ns < NSSIZE) + { + while (pChannel->spos >= 0x10000) + { + if (pChannel->iSBPos == 28) // 28 reached? + { + start = pChannel->pCurr; // set up the current pos + + // special "stop" sign + if (start == (u8*) - 1) //!pChannel->bOn + { + pChannel->bOn = false; // -> turn everything off + pChannel->ADSRX.lVolume = 0; + pChannel->ADSRX.EnvelopeVol = 0; + goto ENDX; // -> and done for this channel + } + + pChannel->iSBPos = 0; + + // decode the 16 byte packet + + flags = (int)start[1]; + start += 16; + + // some callback and irq active? + if (pChannel->GetCtrl()->irq) + { + // if irq address reached or irq on looping addr, when stop/loop flag is set + u8* pirq = (u8*)pSpuIrq[ch>=24]; + if ((pirq > start - 16 && pirq <= start) + || ((flags&1) && (pirq > pChannel->pLoop - 16 && pirq <= pChannel->pLoop))) + { + IRQINFO |= 4 << (int)(ch >= 24); + irqCallbackSPU2(); + } + } + + // flag handler + if ((flags&4) && (!pChannel->bIgnoreLoop)) + pChannel->pLoop = start - 16; // loop adress + + if (flags&1) // 1: stop/loop + { + // We play this block out first... + dwEndChannel2[ch/24] |= (1 << (ch % 24)); + //if(!(flags&2)) // 1+2: do loop... otherwise: stop + if (flags != 3 || pChannel->pLoop == NULL) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example) + { // and checking if pLoop is set avoids crashes, yeah + start = (u8*) - 1; + pChannel->bStop = true; + pChannel->bIgnoreLoop = false; + } + else + { + start = pChannel->pLoop; + } + } + + pChannel->pCurr = start; // store values for next cycle + } + + pChannel->iSBPos++; // get sample data + pChannel->spos -= 0x10000; + } + + MixADSR(pChannel); + + // go to the next packet + ns++; + pChannel->spos += pChannel->sinc; + } +ENDX: + ; + } + + // mix all channels + if ((spu2Ru16(REG_C0_MMIX) & 0xC0) && (spu2Ru16(REG_C0_ADMAS) & 0x1) && !(spu2Ru16(REG_C0_CTRL) & 0x30)) + { + for (int ns = 0;ns < NSSIZE;ns++) + { + Adma4.Index += 1; + + if (Adma4.Index == 128 || Adma4.Index == 384) + { + if (ADMAS4Write()) + { + spu2Ru16(REG_C0_SPUSTAT) &= ~0x80; + irqCallbackDMA4(); + } + else MemAddr[0] += 1024; + } + + if (Adma4.Index == 512) + { + Adma4.Index = 0; + } + } + } + + + if ((spu2Ru16(REG_C1_MMIX) & 0xC0) && (spu2Ru16(REG_C1_ADMAS) & 0x2) && !(spu2Ru16(REG_C1_CTRL) & 0x30)) + { + for (int ns = 0;ns < NSSIZE;ns++) + { + Adma7.Index += 1; + + if (Adma7.Index == 128 || Adma7.Index == 384) + { + if (ADMAS7Write()) + { + spu2Ru16(REG_C1_SPUSTAT) &= ~0x80; + irqCallbackDMA7(); + } + else MemAddr[1] += 1024; + } + + if (Adma7.Index == 512) Adma7.Index = 0; + } + } +} + +EXPORT_C_(void) SPU2readDMA4Mem(u16 *pMem, int size) +{ + u32 spuaddr = C0_SPUADDR; + int i; + + SPU2_LOG("SPU2 readDMA4Mem size %x, addr: %x\n", size, pMem); + + for (i = 0;i < size;i++) + { + *pMem++ = *(u16*)(spu2mem + spuaddr); + if ((spu2Rs16(REG_C0_CTRL)&0x40) && C0_IRQA == spuaddr) + { + spu2Ru16(SPDIF_OUT) |= 0x4; + C0_SPUADDR_SET(spuaddr); + IRQINFO |= 4; + irqCallbackSPU2(); + } + + spuaddr++; // inc spu addr + if (spuaddr > 0x0fffff) // wrap at 2Mb + spuaddr = 0; // wrap + } + + spuaddr += 19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + C0_SPUADDR_SET(spuaddr); + + // got from J.F. and Kanodin... is it needed? + spu2Ru16(REG_C0_SPUSTAT) &= ~0x80; // DMA complete + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = size; + interrupt |= (1 << 1); +} + +EXPORT_C_(void) SPU2readDMA7Mem(u16* pMem, int size) +{ + u32 spuaddr = C1_SPUADDR; + int i; + + SPU2_LOG("SPU2 readDMA7Mem size %x, addr: %x\n", size, pMem); + + for (i = 0;i < size;i++) + { + *pMem++ = *(u16*)(spu2mem + spuaddr); + if ((spu2Rs16(REG_C1_CTRL)&0x40) && C1_IRQA == spuaddr) + { + spu2Ru16(SPDIF_OUT) |= 0x8; + C1_SPUADDR_SET(spuaddr); + IRQINFO |= 8; + irqCallbackSPU2(); + } + spuaddr++; // inc spu addr + if (spuaddr > 0x0fffff) // wrap at 2Mb + spuaddr = 0; // wrap + } + + spuaddr += 19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + C1_SPUADDR_SET(spuaddr); + + // got from J.F. and Kanodin... is it needed? + spu2Ru16(REG_C1_SPUSTAT) &= ~0x80; // DMA complete + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = size; + interrupt |= (1 << 2); +} + +// WRITE + +// AutoDMA's are used to transfer to the DIRECT INPUT area of the spu2 memory +// Left and Right channels are always interleaved together in the transfer so +// the AutoDMA's deinterleaves them and transfers them. An interrupt is +// generated when half of the buffer (256 short-words for left and 256 +// short-words for right ) has been transferred. Another interrupt occurs at +// the end of the transfer. +int ADMAS4Write() +{ + u32 spuaddr; + if (interrupt & 0x2) return 0; + if (Adma4.AmountLeft <= 0) return 1; + + spuaddr = C0_SPUADDR; + // SPU2 Deinterleaves the Left and Right Channels + memcpy((short*)(spu2mem + spuaddr + 0x2000), (short*)Adma4.MemAddr, 512); + Adma4.MemAddr += 256; + memcpy((short*)(spu2mem + spuaddr + 0x2200), (short*)Adma4.MemAddr, 512); + Adma4.MemAddr += 256; + spuaddr = (spuaddr + 256) & 511; + C0_SPUADDR_SET(spuaddr); + + Adma4.AmountLeft -= 512; + if (Adma4.AmountLeft == 0) + { + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = 1;//512*48000; + spu2Ru16(REG_C0_SPUSTAT) &= ~0x80; + interrupt |= (1 << 1); + } + return 0; +} + +int ADMAS7Write() +{ + u32 spuaddr; + if (interrupt & 0x4) return 0; + if (Adma7.AmountLeft <= 0) return 1; + + spuaddr = C1_SPUADDR; + // SPU2 Deinterleaves the Left and Right Channels + memcpy((short*)(spu2mem + spuaddr + 0x2400), (short*)Adma7.MemAddr, 512); + Adma7.MemAddr += 256; + memcpy((short*)(spu2mem + spuaddr + 0x2600), (short*)Adma7.MemAddr, 512); + Adma7.MemAddr += 256; + spuaddr = (spuaddr + 256) & 511; + C1_SPUADDR_SET(spuaddr); + + Adma7.AmountLeft -= 512; + if (Adma7.AmountLeft == 0) + { + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = 1;//512*48000; + spu2Ru16(REG_C1_SPUSTAT) &= ~0x80; + interrupt |= (1 << 2); + } + return 0; +} + +EXPORT_C_(void) SPU2writeDMA4Mem(u16* pMem, int size) +{ + u32 spuaddr; + + SPU2_LOG("SPU2 writeDMA4Mem size %x, addr: %x\n", size, pMem); + + if ((spu2Ru16(REG_C0_ADMAS) & 0x1) && (spu2Ru16(REG_C0_CTRL) & 0x30) == 0 && size) + { + //fwrite(pMem,iSize<<1,1,LogFile); + memset(&Adma4, 0, sizeof(ADMA)); + C0_SPUADDR_SET(0); + Adma4.MemAddr = pMem; + Adma4.AmountLeft = size; + ADMAS4Write(); + return; + } + + spuaddr = C0_SPUADDR; + memcpy((unsigned char*)(spu2mem + spuaddr), (unsigned char*)pMem, size << 1); + spuaddr += size; + C0_SPUADDR_SET(spuaddr); + + if ((spu2Ru16(REG_C0_CTRL)&0x40) && C0_IRQA == spuaddr) + { + spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 4; + irqCallbackSPU2(); + } + if (spuaddr > 0xFFFFE) + spuaddr = 0x2800; + C0_SPUADDR_SET(spuaddr); + + MemAddr[0] += size << 1; + spu2Ru16(REG_C0_SPUSTAT) &= ~0x80; + SPUStartCycle[0] = SPUCycles; + SPUTargetCycle[0] = 1;//iSize; + interrupt |= (1 << 1); +} + +EXPORT_C_(void) SPU2writeDMA7Mem(u16* pMem, int size) +{ + u32 spuaddr; + + SPU2_LOG("SPU2 writeDMA7Mem size %x, addr: %x\n", size, pMem); + + if ((spu2Ru16(REG_C1_ADMAS) & 0x2) && (spu2Ru16(REG_C1_CTRL) & 0x30) == 0 && size) + { + //fwrite(pMem,iSize<<1,1,LogFile); + memset(&Adma7, 0, sizeof(ADMA)); + C1_SPUADDR_SET(0); + Adma7.MemAddr = pMem; + Adma7.AmountLeft = size; + ADMAS7Write(); + return; + } + + spuaddr = C1_SPUADDR; + memcpy((unsigned char*)(spu2mem + spuaddr), (unsigned char*)pMem, size << 1); + spuaddr += size; + C1_SPUADDR_SET(spuaddr); + + if ((spu2Ru16(REG_C1_CTRL)&0x40) && C1_IRQA == spuaddr) + { + spu2Ru16(SPDIF_OUT) |= 0x8; + IRQINFO |= 8; + irqCallbackSPU2(); + } + if (spuaddr > 0xFFFFE) + spuaddr = 0x2800; + C1_SPUADDR_SET(spuaddr); + + MemAddr[1] += size << 1; + spu2Ru16(REG_C1_SPUSTAT) &= ~0x80; + SPUStartCycle[1] = SPUCycles; + SPUTargetCycle[1] = 1;//iSize; + interrupt |= (1 << 2); +} + +EXPORT_C_(void) SPU2interruptDMA4() +{ + SPU2_LOG("SPU2 interruptDMA4\n"); + + spu2Rs16(REG_C0_CTRL) &= ~0x30; + spu2Ru16(REG_C0_SPUSTAT) |= 0x80; +} + +EXPORT_C_(void) SPU2interruptDMA7() +{ + SPU2_LOG("SPU2 interruptDMA7\n"); + +// spu2Rs16(REG_C1_CTRL)&= ~0x30; +// //spu2Rs16(REG__5B0) = 0; +// spu2Rs16(SPU2_STATX_DREQ)|= 0x80; + spu2Rs16(REG_C1_CTRL) &= ~0x30; + spu2Ru16(REG_C1_SPUSTAT) |= 0x80; +} + +// turn channels on +void SoundOn(int start, int end, unsigned short val) // SOUND ON PSX COMAND +{ + for (int ch = start;ch < end;ch++, val >>= 1) // loop channels + { + if ((val&1) && voices[ch].pStart) // mmm... start has to be set before key on !?! + { + voices[ch].bNew = true; + voices[ch].bIgnoreLoop = false; + } + } +} + +// turn channels off +void SoundOff(int start, int end, unsigned short val) // SOUND OFF PSX COMMAND +{ + for (int ch = start;ch < end;ch++, val >>= 1) // loop channels + { + if (val&1) // && s_chan[i].bOn) mmm... + voices[ch].bStop = true; + } +} + +void FModOn(int start, int end, unsigned short val) // FMOD ON PSX COMMAND +{ + int ch; + + for (ch = start;ch < end;ch++, val >>= 1) // loop channels + { + if (val&1) // -> fmod on/off + { + if (ch > 0) + { + } + } + else + { + // turn fmod off + } + } +} + +EXPORT_C_(void) SPU2write(u32 mem, u16 value) +{ + u32 spuaddr; + + SPU2_LOG("SPU2 write mem %x value %x\n", mem, value); + + assert(C0_SPUADDR < 0x100000); + assert(C1_SPUADDR < 0x100000); + + spu2Ru16(mem) = value; + u32 r = mem & 0xffff; + + // channel info + if ((r >= 0x0000 && r < 0x0180) || (r >= 0x0400 && r < 0x0580)) // some channel info? + { + int ch = 0; + if (r >= 0x400) ch = ((r - 0x400) >> 4) + 24; + else ch = (r >> 4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch (r&0x0f) + { + case 0: + case 2: + pvoice->SetVolume(mem&0x2); + break; + case 4: + { + int NP; + if (value > 0x3fff) NP = 0x3fff; // get pitch val + else NP = value; + + pvoice->pvoice->pitch = NP; + + NP = (44100L * NP) / 4096L; // calc frequency + if (NP < 1) NP = 1; // some security + pvoice->iActFreq = NP; // store frequency + break; + } + case 6: + { + pvoice->ADSRX.AttackModeExp = (value & 0x8000) ? 1 : 0; + pvoice->ADSRX.AttackRate = ((value >> 8) & 0x007f); + pvoice->ADSRX.DecayRate = (((value >> 4) & 0x000f)); + pvoice->ADSRX.SustainLevel = (value & 0x000f); + break; + } + case 8: + pvoice->ADSRX.SustainModeExp = (value & 0x8000) ? 1 : 0; + pvoice->ADSRX.SustainIncrease = (value & 0x4000) ? 0 : 1; + pvoice->ADSRX.SustainRate = ((value >> 6) & 0x007f); + pvoice->ADSRX.ReleaseModeExp = (value & 0x0020) ? 1 : 0; + pvoice->ADSRX.ReleaseRate = ((value & 0x001f)); + break; + } + + return; + } + + // more channel info + if ((r >= 0x01c0 && r <= 0x02E0) || (r >= 0x05c0 && r <= 0x06E0)) + { + int ch = 0; + unsigned long rx = r; + if (rx >= 0x400) + { + ch = 24; + rx -= 0x400; + } + + ch += ((rx - 0x1c0) / 12); + rx -= (ch % 24) * 12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch (rx) + { + case 0x1C0: + pvoice->iStartAddr = (((unsigned long)value & 0x3f) << 16) | (pvoice->iStartAddr & 0xFFFF); + pvoice->pStart = (u8*)(spu2mem + pvoice->iStartAddr); + break; + case 0x1C2: + pvoice->iStartAddr = (pvoice->iStartAddr & 0x3f0000) | (value & 0xFFFF); + pvoice->pStart = (u8*)(spu2mem + pvoice->iStartAddr); + break; + case 0x1C4: + pvoice->iLoopAddr = (((unsigned long)value & 0x3f) << 16) | (pvoice->iLoopAddr & 0xFFFF); + pvoice->pLoop = (u8*)(spu2mem + pvoice->iLoopAddr); + pvoice->bIgnoreLoop = pvoice->iLoopAddr > 0; + break; + case 0x1C6: + pvoice->iLoopAddr = (pvoice->iLoopAddr & 0x3f0000) | (value & 0xFFFF); + pvoice->pLoop = (u8*)(spu2mem + pvoice->iLoopAddr); + pvoice->bIgnoreLoop = pvoice->iLoopAddr > 0; + break; + case 0x1C8: + // unused... check if it gets written as well + pvoice->iNextAddr = (((unsigned long)value & 0x3f) << 16) | (pvoice->iNextAddr & 0xFFFF); + break; + case 0x1CA: + // unused... check if it gets written as well + pvoice->iNextAddr = (pvoice->iNextAddr & 0x3f0000) | (value & 0xFFFF); + break; + } + + return; + } + + // process non-channel data + switch (mem&0xffff) + { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR; + spu2mem[spuaddr] = value; + spuaddr++; + if ((spu2Ru16(REG_C0_CTRL)&0x40) && C0_IRQA == spuaddr) + { + spu2Ru16(SPDIF_OUT) |= 0x4; + IRQINFO |= 4; + irqCallbackSPU2(); + } + if (spuaddr > 0xFFFFE) + spuaddr = 0x2800; + C0_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C0_SPUSTAT) &= ~0x80; + spu2Ru16(REG_C0_CTRL) &= ~0x30; + break; + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR; + spu2mem[spuaddr] = value; + spuaddr++; + if ((spu2Ru16(REG_C1_CTRL)&0x40) && C1_IRQA == spuaddr) + { + spu2Ru16(SPDIF_OUT) |= 0x8; + IRQINFO |= 8; + irqCallbackSPU2(); + } + if (spuaddr > 0xFFFFE) + spuaddr = 0x2800; + C1_SPUADDR_SET(spuaddr); + spu2Ru16(REG_C1_SPUSTAT) &= ~0x80; + spu2Ru16(REG_C1_CTRL) &= ~0x30; + break; + case REG_C0_IRQA_HI: + case REG_C0_IRQA_LO: + pSpuIrq[0] = spu2mem + (C0_IRQA << 1); + break; + case REG_C1_IRQA_HI: + case REG_C1_IRQA_LO: + pSpuIrq[1] = spu2mem + (C1_IRQA << 1); + break; + + case REG_C0_SPUADDR_HI: + case REG_C1_SPUADDR_HI: + spu2Ru16(mem) = value & 0xf; + break; + + case REG_C0_SPUON1: + SoundOn(0, 16, value); + break; + case REG_C0_SPUON2: + SoundOn(16, 24, value); + break; + case REG_C1_SPUON1: + SoundOn(24, 40, value); + break; + case REG_C1_SPUON2: + SoundOn(40, 48, value); + break; + case REG_C0_SPUOFF1: + SoundOff(0, 16, value); + break; + case REG_C0_SPUOFF2: + SoundOff(16, 24, value); + break; + case REG_C1_SPUOFF1: + SoundOff(24, 40, value); + break; + case REG_C1_SPUOFF2: + SoundOff(40, 48, value); + break; + + // According to manual all bits are cleared by writing an arbitary value + case REG_C0_END1: + dwEndChannel2[0] = 0; + break; + case REG_C0_END2: + dwEndChannel2[0] = 0; + break; + case REG_C1_END1: + dwEndChannel2[1] = 0; + break; + case REG_C1_END2: + dwEndChannel2[1] = 0; + break; + case REG_C0_FMOD1: + FModOn(0, 16, value); + break; + case REG_C0_FMOD2: + FModOn(16, 24, value); + break; + case REG_C1_FMOD1: + FModOn(24, 40, value); + break; + case REG_C1_FMOD2: + FModOn(40, 48, value); + break; + } + + assert(C0_SPUADDR < 0x100000); + assert(C1_SPUADDR < 0x100000); +} + +EXPORT_C_(u16) SPU2read(u32 mem) +{ + u32 spuaddr; + u16 ret; + u32 r = mem & 0xffff; + + if ((r >= 0x0000 && r <= 0x0180) || (r >= 0x0400 && r <= 0x0580)) // some channel info? + { + int ch = 0; + if (r >= 0x400) ch = ((r - 0x400) >> 4) + 24; + else ch = (r >> 4); + + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch (r&0x0f) + { + case 10: + return (unsigned short)(pvoice->ADSRX.EnvelopeVol >> 16); + } + } + + if ((r > 0x01c0 && r <= 0x02E0) || (r > 0x05c0 && r <= 0x06E0)) // some channel info? + { + int ch = 0; + unsigned long rx = r; + if (rx >= 0x400) + { + ch = 24; + rx -= 0x400; + } + + ch += ((rx - 0x1c0) / 12); + rx -= (ch % 24) * 12; + VOICE_PROCESSED* pvoice = &voices[ch]; + + switch (rx) + { + case 0x1C0: + return (u16)(((pvoice->pStart - (u8*)spu2mem) >> 17)&0x3F); + case 0x1C2: + return (u16)(((pvoice->pStart - (u8*)spu2mem) >> 1)&0xFFFF); + case 0x1C4: + return (u16)(((pvoice->pLoop - (u8*)spu2mem) >> 17)&0x3F); + case 0x1C6: + return (u16)(((pvoice->pLoop - (u8*)spu2mem) >> 1)&0xFFFF); + case 0x1C8: + return (u16)(((pvoice->pCurr - (u8*)spu2mem) >> 17)&0x3F); + case 0x1CA: + return (u16)(((pvoice->pCurr - (u8*)spu2mem) >> 1)&0xFFFF); + } + } + + switch (mem&0xffff) + { + case REG_C0_SPUDATA: + spuaddr = C0_SPUADDR; + ret = spu2mem[spuaddr]; + spuaddr++; + if (spuaddr > 0xfffff) + spuaddr = 0; + C0_SPUADDR_SET(spuaddr); + break; + case REG_C1_SPUDATA: + spuaddr = C1_SPUADDR; + ret = spu2mem[spuaddr]; + spuaddr++; + if (spuaddr > 0xfffff) + spuaddr = 0; + C1_SPUADDR_SET(spuaddr); + break; + + case REG_C0_END1: + return (dwEndChannel2[0]&0xffff); + case REG_C0_END2: + return (dwEndChannel2[0] >> 16); + case REG_C1_END1: + return (dwEndChannel2[1]&0xffff); + case REG_C1_END2: + return (dwEndChannel2[1] >> 16); + + case REG_IRQINFO: + ret = IRQINFO; + IRQINFO = 0; + break; + default: + ret = spu2Ru16(mem); + } + + SPU2_LOG("SPU2 read mem %x: %x\n", mem, ret); + + return ret; +} + +EXPORT_C_(void) SPU2WriteMemAddr(int core, u32 value) +{ + MemAddr[core] = value; +} + +EXPORT_C_(u32) SPU2ReadMemAddr(int core) +{ + return MemAddr[core]; +} + +EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)(), void (*DMA4callback)(), void (*DMA7callback)()) +{ + irqCallbackSPU2 = SPU2callback; + irqCallbackDMA4 = DMA4callback; + irqCallbackDMA7 = DMA7callback; +} + +// VOICE_PROCESSED definitions +SPU_CONTROL_* VOICE_PROCESSED::GetCtrl() +{ + return ((SPU_CONTROL_*)(spu2regs + memoffset + REG_C0_CTRL)); +} + +void VOICE_PROCESSED::SetVolume(int iProcessRight) +{ + u16 vol = iProcessRight ? pvoice->right.word : pvoice->left.word; + + if (vol&0x8000) // sweep not working + { + short sInc = 1; // -> sweep up? + if (vol&0x2000) sInc = -1; // -> or down? + if (vol&0x1000) vol ^= 0xffff; // -> mmm... phase inverted? have to investigate this + vol = ((vol & 0x7f) + 1) / 2; // -> sweep: 0..127 -> 0..64 + vol += vol / (2 * sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol *= 128; + } + else // no sweep: + { + if (vol&0x4000) // -> mmm... phase inverted? have to investigate this + vol = 0x3fff - (vol & 0x3fff); + } + + vol &= 0x3fff; + // set volume + //if( iProcessRight ) right = vol; + //else left = vol; +} + +void VOICE_PROCESSED::StartSound() +{ + ADSRX.lVolume = 1; // and init some adsr vars + ADSRX.State = 0; + ADSRX.EnvelopeVol = 0; + + if (bReverb && GetCtrl()->reverb) + { + // setup the reverb effects + } + + pCurr = pStart; // set sample start + iSBPos = 28; + + bNew = false; // init channel flags + bStop = false; + bOn = true; + spos = 0x10000L; +} + +void VOICE_PROCESSED::VoiceChangeFrequency() +{ + iUsedFreq = iActFreq; // -> take it and calc steps + sinc = (u32)pvoice->pitch << 4; + if (!sinc) + sinc = 1; +} + +void VOICE_PROCESSED::Stop() +{ +} + +// GUI Routines +EXPORT_C_(s32) SPU2test() +{ + return 0; +} + +typedef struct +{ + u32 version; + u8 spu2regs[0x10000]; +} SPU2freezeData; + +EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data) +{ + SPU2freezeData *spud; + + if (mode == FREEZE_LOAD) + { + spud = (SPU2freezeData*)data->data; + if (spud->version == 0x11223344) + { + memcpy(spu2regs, spud->spu2regs, 0x10000); + } + else printf("SPU2null wrong format\n"); + } + else + if (mode == FREEZE_SAVE) + { + spud = (SPU2freezeData*)data->data; + spud->version = 0x11223344; + memcpy(spud->spu2regs, spu2regs, 0x10000); + } + else + if (mode == FREEZE_SIZE) + { + data->size = sizeof(SPU2freezeData); + } + + return 0; +} + diff --git a/plugins/SPU2null/SPU2.h b/plugins/SPU2null/SPU2.h new file mode 100644 index 0000000000..842ff27b85 --- /dev/null +++ b/plugins/SPU2null/SPU2.h @@ -0,0 +1,293 @@ +/* SPU2null + * Copyright (C) 2002-2005 SPU2null Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SPU2_H__ +#define __SPU2_H__ + +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include + +extern "C" +{ +#define SPU2defs +#include "PS2Edefs.h" +} + +#ifdef __LINUX__ +#include +#else +#include +#include +#endif + +#ifdef _MSC_VER +#define EXPORT_C_(type) extern "C" __declspec(dllexport) type CALLBACK +#else +#define EXPORT_C_(type) extern "C" type +#endif + +extern FILE *spu2Log; +#define SPU2_LOG __Log //debug mode + +extern const unsigned char version; +extern const unsigned char revision; +extern const unsigned char build; +extern const unsigned int minor; +extern char *libraryName; + +typedef struct +{ + int Log; +} Config; + +extern Config conf; + +void __Log(char *fmt, ...); +void SaveConfig(); +void LoadConfig(); +void SysMessage(char *fmt, ...); + +//////////////////// +// SPU2 Registers // +//////////////////// +#define REG_VP_VOLL 0x0000 +#define REG_VP_VOLR 0x0002 +#define REG_VP_PITCH 0x0004 +#define REG_VP_ADSR1 0x0006 +#define REG_VP_ADSR2 0x0008 +#define REG_VP_ENVX 0x000A +#define REG_VP_VOLXL 0x000C +#define REG_VP_VOLXR 0x000E +#define REG_C0_FMOD1 0x0180 +#define REG_C0_FMOD2 0x0182 +#define REG_C1_FMOD1 0x0580 +#define REG_C1_FMOD2 0x0582 +#define REG_S_NON 0x0184 +#define REG_S_VMIXL 0x0188 +#define REG_S_VMIXEL 0x018C +#define REG_S_VMIXR 0x0190 +#define REG_S_VMIXER 0x0194 +#define REG_C0_MMIX 0x0198 +#define REG_C1_MMIX 0x0598 +#define REG_C0_CTRL 0x019A +#define REG_C0_IRQA_HI 0x019C +#define REG_C0_IRQA_LO 0x019D +#define REG_C1_IRQA_HI 0x059C +#define REG_C1_IRQA_LO 0x059D +#define REG_C0_SPUON1 0x1A0 +#define REG_C0_SPUON2 0x1A2 +#define REG_C1_SPUON1 0x5A0 +#define REG_C1_SPUON2 0x5A2 +#define REG_C0_SPUOFF1 0x1A4 +#define REG_C0_SPUOFF2 0x1A6 +#define REG_C1_SPUOFF1 0x5A4 +#define REG_C1_SPUOFF2 0x5A6 +#define REG_C0_SPUADDR_HI 0x01A8 +#define REG_C0_SPUADDR_LO 0x01AA +#define REG_C1_SPUADDR_HI 0x05A8 +#define REG_C1_SPUADDR_LO 0x05AA +#define REG_C0_SPUDATA 0x01AC +#define REG_C1_SPUDATA 0x05AC +#define REG_C0_DMACTRL 0x01AE +#define REG_C1_DMACTRL 0x05AE +#define REG_C0_ADMAS 0x01B0 +#define REG_VA_SSA 0x01C0 +#define REG_VA_LSAX 0x01C4 +#define REG_VA_NAX 0x01C8 +#define REG_A_ESA 0x02E0 +#define REG_A_EEA 0x033C +#define REG_C0_END1 0x0340 +#define REG_C0_END2 0x0342 +#define REG_C1_END1 0x0740 +#define REG_C1_END2 0x0742 +#define REG_C0_SPUSTAT 0x0344 //not sure! +#define REG_C1_CTRL 0x059A +#define REG_C1_ADMAS 0x05B0 +#define REG_C1_SPUSTAT 0x0744 //not sure! +#define REG_P_MVOLL 0x0760 +#define REG_P_MVOLR 0x0762 +#define REG_P_EVOLL 0x0764 +#define REG_P_EVOLR 0x0766 +#define REG_P_AVOLL 0x0768 +#define REG_P_AVOLR 0x076A +#define REG_P_BVOLL 0x076C +#define REG_P_BVOLR 0x076E +#define REG_P_MVOLXL 0x0770 +#define REG_P_MVOLXR 0x0772 +#define SPDIF_OUT 0x07C0 +#define REG_IRQINFO 0x07C2 +#define SPDIF_MODE 0x07C6 +#define SPDIF_MEDIA 0x07C8 + +#define spu2Rs16(mem) (*(s16*)&spu2regs[(mem) & 0xffff]) +#define spu2Ru16(mem) (*(u16*)&spu2regs[(mem) & 0xffff]) +//#define spu2Rs32(mem) (*(s32*)&spu2regs[(mem) & 0xffff]) +//#define spu2Ru32(mem) (*(u32*)&spu2regs[(mem) & 0xffff]) + +#define IRQINFO spu2Ru16(REG_IRQINFO) + +#define SPU2_GET32BIT(lo,hi) (((u32)(spu2Ru16(hi)&0x3f)<<16)|(u32)spu2Ru16(lo)) +#define SPU2_SET32BIT(value, lo, hi) { \ + spu2Ru16(hi) = ((value)>>16)&0x3f; \ + spu2Ru16(lo) = (value)&0xffff; \ + } \ + +#define C0_IRQA SPU2_GET32BIT(REG_C0_IRQA_LO, REG_C0_IRQA_HI) +#define C1_IRQA SPU2_GET32BIT(REG_C1_IRQA_LO, REG_C1_IRQA_HI) + +#define C0_SPUADDR SPU2_GET32BIT(REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI) +#define C1_SPUADDR SPU2_GET32BIT(REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI) + +#define C0_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C0_IRQA_LO, REG_C0_IRQA_HI) +#define C1_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C1_IRQA_LO, REG_C1_IRQA_HI) + +#define SPU_NUMBER_VOICES 48 + +struct SPU_CONTROL_ +{ + u16 spuon : 1; + u16 spuUnmute : 1; + u16 noiseFreq : 6; + u16 reverb : 1; + u16 irq : 1; + u16 dma : 2; // 1 - no dma, 2 - write, 3 - read + u16 extr : 1; // external reverb + u16 cdreverb : 1; + u16 extAudio : 1; + u16 extCd : 1; +}; + +// the layout of each voice in wSpuRegs +struct _SPU_VOICE +{ + union + { + struct { + u16 Vol : 14; + u16 Inverted : 1; + u16 Sweep0 : 1; + } vol; + struct { + u16 Vol : 7; + u16 res1 : 5; + u16 Inverted : 1; + u16 Decrease : 1; // if 0, increase + u16 ExpSlope : 1; // if 0, linear slope + u16 Sweep1 : 1; // always one + } sweep; + u16 word; +} left, right; + + u16 pitch : 14; // 1000 - no pitch, 2000 - pitch + 1, etc + u16 res0 : 2; + + u16 SustainLvl : 4; + u16 DecayRate : 4; + u16 AttackRate : 7; + u16 AttackExp : 1; // if 0, linear + + u16 ReleaseRate : 5; + u16 ReleaseExp : 1; // if 0, linear + u16 SustainRate : 7; + u16 res1 : 1; + u16 SustainDec : 1; // if 0, inc + u16 SustainExp : 1; // if 0, linear + + u16 AdsrVol; + u16 Address; // add / 8 + u16 RepeatAddr; // gets reset when sample starts +}; + +// ADSR INFOS PER CHANNEL +struct ADSRInfoEx +{ + int State; + int AttackModeExp; + int AttackRate; + int DecayRate; + int SustainLevel; + int SustainModeExp; + int SustainIncrease; + int SustainRate; + int ReleaseModeExp; + int ReleaseRate; + int EnvelopeVol; + long lVolume; +}; + +#define NSSIZE 48 // ~ 1 ms of data +#define NSFRAMES 16 // gather at least NSFRAMES of NSSIZE before submitting +#define NSPACKETS 4 +#define SPU_VOICE_STATE_SIZE (sizeof(VOICE_PROCESSED)-4*sizeof(void*)) + +struct VOICE_PROCESSED +{ + VOICE_PROCESSED() + { + memset(this, 0, sizeof(VOICE_PROCESSED)); + } + ~VOICE_PROCESSED() + { + } + + void SetVolume(int right); + void StartSound(); + void VoiceChangeFrequency(); + void FModChangeFrequency(int ns); + void Stop(); + + SPU_CONTROL_* GetCtrl(); + + // start save state + + int iSBPos; // mixing stuff + int spos; + int sinc; + + int iActFreq; // current psx pitch + int iUsedFreq; // current pc pitch + + int iStartAddr, iLoopAddr, iNextAddr; + + ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) + bool bIgnoreLoop, bNew, bNoise, bReverb, bOn, bStop, bVolChanged; + int memoffset; // if first core, 0, if second, 0x400 + + // end save state + + /////////////////// + // Sound Buffers // + /////////////////// + u8* pStart; // start and end addresses + u8* pLoop, *pCurr; + + _SPU_VOICE* pvoice; +}; + +struct ADMA +{ + unsigned short * MemAddr; + long IntPointer; + int Index; + int AmountLeft; + int Enabled; +}; + +#endif /* __SPU2_H__ */ diff --git a/plugins/SPU2null/Src/Makefile b/plugins/SPU2null/Src/Makefile deleted file mode 100644 index 89c2b357ae..0000000000 --- a/plugins/SPU2null/Src/Makefile +++ /dev/null @@ -1,25 +0,0 @@ - -CC = gcc - -PLUGIN = libSPU2null.so -CFLAGS+= -fPIC -Wall -O2 -fomit-frame-pointer -D__LINUX__ -I../../../common/include -OBJS = SPU2.o -DEPS:= $(OBJS:.o=.d) -LIBS = $(shell pkg-config --libs gtk+-2.0) -CFLAGS+= $(shell pkg-config --cflags gtk+-2.0) - -all: plugin -install: all - -plugin: ${OBJS} - rm -f ${PLUGIN} - gcc -shared -Wl,-soname,${PLUGIN} ${CFLAGS} ${OBJS} -o ${PLUGIN} ${LIBS} - strip --strip-unneeded --strip-debug ${PLUGIN} - -clean: - rm -f ${OBJS} ${DEPS} - -%.o: %.cpp - ${CC} ${CFLAGS} -c -o $@ $< -MD -MF $(patsubst %.o,%.d,$@) - -#-include ${DEPS} diff --git a/plugins/SPU2null/Src/SPU2.cpp b/plugins/SPU2null/Src/SPU2.cpp deleted file mode 100644 index da50e2bcce..0000000000 --- a/plugins/SPU2null/Src/SPU2.cpp +++ /dev/null @@ -1,1213 +0,0 @@ -/* SPU2null - * Copyright (C) 2002-2005 SPU2null Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "SPU2.h" - -#include -#include - -const unsigned char version = PS2E_SPU2_VERSION; -const unsigned char revision = 0; -const unsigned char build = 7; // increase that with each version -const unsigned int minor = 1; // increase that with each version - -// ADSR constants -#define ATTACK_MS 494L -#define DECAYHALF_MS 286L -#define DECAY_MS 572L -#define SUSTAIN_MS 441L -#define RELEASE_MS 437L - -#ifdef _DEBUG -static char *libraryName = "SPU2null (Debug)"; -#else -static char *libraryName = "SPU2null "; -#endif - -FILE *spu2Log; -Config conf; - -ADMA Adma4; -ADMA Adma7; - -u32 MemAddr[2]; -u32 g_nSpuInit = 0; -unsigned short interrupt = 0; -s8 *spu2regs = NULL; -u16* spu2mem = NULL; -u16* pSpuIrq[2] = {NULL}; -u32 dwEndChannel2[2] = {0}; // keeps track of what channels have ended -unsigned long dwNoiseVal=1; // global noise generator - -int SPUCycles = 0, SPUWorkerCycles = 0; -int SPUStartCycle[2]; -int SPUTargetCycle[2]; - -int ADMAS4Write(); -int ADMAS7Write(); - -void InitADSR(); - -void (*irqCallbackSPU2)(); // func of main emu, called on spu irq -void (*irqCallbackDMA4)()=0; // func of main emu, called on spu irq -void (*irqCallbackDMA7)()=0; // func of main emu, called on spu irq - -const int f[5][2] = { { 0, 0 }, - { 60, 0 }, - { 115, -52 }, - { 98, -55 }, - { 122, -60 } }; - -u32 RateTable[160]; - -// channels and voices -VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; // +1 for modulation - -u32 CALLBACK PS2EgetLibType() { - return PS2E_LT_SPU2; -} - -char* CALLBACK PS2EgetLibName() { - return libraryName; -} - -u32 CALLBACK PS2EgetLibVersion2(u32 type) { - return (version<<16)|(revision<<8)|build|(minor<<24); -} - -void __Log(char *fmt, ...) { - va_list list; - - if (!conf.Log || spu2Log == NULL) return; - - va_start(list, fmt); - vfprintf(spu2Log, fmt, list); - va_end(list); -} - -s32 CALLBACK SPU2init() { -#ifdef SPU2_LOG - spu2Log = fopen("logs/spu2.txt", "w"); - if (spu2Log) setvbuf(spu2Log, NULL, _IONBF, 0); - SPU2_LOG("Spu2 null version %d,%d\n",revision,build); - SPU2_LOG("SPU2init\n"); -#endif - spu2regs = (s8*)malloc(0x10000); - if (spu2regs == NULL) { - SysMessage("Error allocating Memory\n"); return -1; - } - memset(spu2regs, 0, 0x10000); - - spu2mem = (u16*)malloc(0x200000); // 2Mb - if (spu2mem == NULL) { - SysMessage("Error allocating Memory\n"); return -1; - } - memset(spu2mem, 0, 0x200000); - memset(dwEndChannel2, 0, sizeof(dwEndChannel2)); - - InitADSR(); - - memset(voices, 0, sizeof(voices)); - // last 24 channels have higher mem offset - for(int i = 0; i < 24; ++i) - voices[i+24].memoffset = 0x400; - - // init each channel - for(u32 i = 0; i < ArraySize(voices); ++i) { - - voices[i].pLoop = voices[i].pStart = voices[i].pCurr = (u8*)spu2mem; - - voices[i].pvoice = (_SPU_VOICE*)((u8*)spu2regs+voices[i].memoffset)+(i%24); - voices[i].ADSRX.SustainLevel = 1024; // -> init sustain - } - - return 0; -} - -s32 CALLBACK SPU2open(void *pDsp) { - LoadConfig(); - SPUCycles = SPUWorkerCycles = 0; - interrupt = 0; - SPUStartCycle[0] = SPUStartCycle[1] = 0; - SPUTargetCycle[0] = SPUTargetCycle[1] = 0; - g_nSpuInit = 1; - return 0; -} - -void CALLBACK SPU2close() { - g_nSpuInit = 0; -} - -void CALLBACK SPU2shutdown() { - free(spu2regs); spu2regs = NULL; - free(spu2mem); spu2mem = NULL; -#ifdef SPU2_LOG - if (spu2Log) fclose(spu2Log); -#endif -} - -// simulate SPU2 for 1ms -void SPU2Worker(); - -#define CYCLES_PER_MS (36864000/1000) - -void CALLBACK SPU2async(u32 cycle) -{ - SPUCycles += cycle; - if(interrupt & (1<<2)){ - if(SPUCycles - SPUStartCycle[1] >= SPUTargetCycle[1]){ - interrupt &= ~(1<<2); - irqCallbackDMA7(); - } - - } - - if(interrupt & (1<<1)){ - if(SPUCycles - SPUStartCycle[0] >= SPUTargetCycle[0]){ - interrupt &= ~(1<<1); - irqCallbackDMA4(); - } - } - - if( g_nSpuInit ) { - - while( SPUCycles-SPUWorkerCycles > 0 && CYCLES_PER_MS < SPUCycles-SPUWorkerCycles ) { - SPU2Worker(); - SPUWorkerCycles += CYCLES_PER_MS; - } - } -} - -void InitADSR() // INIT ADSR -{ - unsigned long r,rs,rd; - int i; - memset(RateTable,0,sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file) - - r=3;rs=1;rd=0; - - for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 - { - if(r<0x3FFFFFFF) - { - r+=rs; - rd++;if(rd==5) {rd=1;rs*=2;} - } - if(r>0x3FFFFFFF) r=0x3FFFFFFF; - - RateTable[i]=r; - } -} - -int MixADSR(VOICE_PROCESSED* pvoice) // MIX ADSR -{ - if(pvoice->bStop) // should be stopped: - { - if(pvoice->bIgnoreLoop==0){ - pvoice->ADSRX.EnvelopeVol=0; - pvoice->bOn=false; - pvoice->pStart= (u8*)(spu2mem+pvoice->iStartAddr); - pvoice->pLoop= (u8*)(spu2mem+pvoice->iStartAddr); - pvoice->pCurr= (u8*)(spu2mem+pvoice->iStartAddr); - pvoice->bStop=true; - pvoice->bIgnoreLoop=false; - return 0; - } - if(pvoice->ADSRX.ReleaseModeExp)// do release - { - switch((pvoice->ADSRX.EnvelopeVol>>28)&0x7) - { - case 0: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; break; - case 1: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; break; - case 2: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; break; - case 3: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; break; - case 4: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; break; - case 5: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; break; - case 6: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; break; - case 7: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; break; - } - } - else - { - pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.ReleaseRate^0x1F))-0x0C + 32]; - } - - if(pvoice->ADSRX.EnvelopeVol<0) - { - pvoice->ADSRX.EnvelopeVol=0; - pvoice->bOn=false; - pvoice->pStart= (u8*)(spu2mem+pvoice->iStartAddr); - pvoice->pLoop= (u8*)(spu2mem+pvoice->iStartAddr); - pvoice->pCurr= (u8*)(spu2mem+pvoice->iStartAddr); - pvoice->bStop=true; - pvoice->bIgnoreLoop=false; - //pvoice->bReverb=0; - //pvoice->bNoise=0; - } - - pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; - pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; - return pvoice->ADSRX.lVolume; - } - else // not stopped yet? - { - if(pvoice->ADSRX.State==0) // -> attack - { - if(pvoice->ADSRX.AttackModeExp) - { - if(pvoice->ADSRX.EnvelopeVol<0x60000000) - pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x10 + 32]; - else - pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x18 + 32]; - } - else - { - pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.AttackRate^0x7F)-0x10 + 32]; - } - - if(pvoice->ADSRX.EnvelopeVol<0) - { - pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; - pvoice->ADSRX.State=1; - } - - pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; - return pvoice->ADSRX.lVolume; - } - //--------------------------------------------------// - if(pvoice->ADSRX.State==1) // -> decay - { - switch((pvoice->ADSRX.EnvelopeVol>>28)&0x7) - { - case 0: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+0 + 32]; break; - case 1: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+4 + 32]; break; - case 2: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+6 + 32]; break; - case 3: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+8 + 32]; break; - case 4: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+9 + 32]; break; - case 5: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+10+ 32]; break; - case 6: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+11+ 32]; break; - case 7: pvoice->ADSRX.EnvelopeVol-=RateTable[(4*(pvoice->ADSRX.DecayRate^0x1F))-0x18+12+ 32]; break; - } - - if(pvoice->ADSRX.EnvelopeVol<0) pvoice->ADSRX.EnvelopeVol=0; - if(((pvoice->ADSRX.EnvelopeVol>>27)&0xF) <= pvoice->ADSRX.SustainLevel) - { - pvoice->ADSRX.State=2; - } - - pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; - return pvoice->ADSRX.lVolume; - } - //--------------------------------------------------// - if(pvoice->ADSRX.State==2) // -> sustain - { - if(pvoice->ADSRX.SustainIncrease) - { - if(pvoice->ADSRX.SustainModeExp) - { - if(pvoice->ADSRX.EnvelopeVol<0x60000000) - pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x10 + 32]; - else - pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x18 + 32]; - } - else - { - pvoice->ADSRX.EnvelopeVol+=RateTable[(pvoice->ADSRX.SustainRate^0x7F)-0x10 + 32]; - } - - if(pvoice->ADSRX.EnvelopeVol<0) - { - pvoice->ADSRX.EnvelopeVol=0x7FFFFFFF; - } - } - else - { - if(pvoice->ADSRX.SustainModeExp) - { - switch((pvoice->ADSRX.EnvelopeVol>>28)&0x7) - { - case 0: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +0 + 32];break; - case 1: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +4 + 32];break; - case 2: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +6 + 32];break; - case 3: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +8 + 32];break; - case 4: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +9 + 32];break; - case 5: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +10+ 32];break; - case 6: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +11+ 32];break; - case 7: pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x1B +12+ 32];break; - } - } - else - { - pvoice->ADSRX.EnvelopeVol-=RateTable[((pvoice->ADSRX.SustainRate^0x7F))-0x0F + 32]; - } - - if(pvoice->ADSRX.EnvelopeVol<0) - { - pvoice->ADSRX.EnvelopeVol=0; - } - } - pvoice->ADSRX.lVolume=pvoice->ADSRX.EnvelopeVol>>21; - return pvoice->ADSRX.lVolume; - } - } - return 0; -} - -// simulate SPU2 for 1ms -void SPU2Worker() -{ - u8* start; - int ch,flags; - - VOICE_PROCESSED* pChannel=voices; - for(ch=0;chbNew) { - pChannel->StartSound(); // start new sound - dwEndChannel2[ch/24]&=~(1<<(ch%24)); // clear end channel bit - } - - if(!pChannel->bOn) - { - // fill buffer with empty data - continue; - } - - if(pChannel->iActFreq!=pChannel->iUsedFreq) // new psx frequency? - pChannel->VoiceChangeFrequency(); - - // loop until 1 ms of data is reached - int ns = 0; - while(nsspos >= 0x10000 ) - { - if(pChannel->iSBPos==28) // 28 reached? - { - start=pChannel->pCurr; // set up the current pos - - // special "stop" sign - if( start == (u8*)-1 ) //!pChannel->bOn - { - pChannel->bOn=false; // -> turn everything off - pChannel->ADSRX.lVolume=0; - pChannel->ADSRX.EnvelopeVol=0; - goto ENDX; // -> and done for this channel - } - - pChannel->iSBPos=0; - - // decode the 16 byte packet - - flags=(int)start[1]; - start += 16; - - // some callback and irq active? - if(pChannel->GetCtrl()->irq) { - // if irq address reached or irq on looping addr, when stop/loop flag is set - u8* pirq = (u8*)pSpuIrq[ch>=24]; - if( (pirq > start-16 && pirq <= start) - || ((flags&1) && (pirq > pChannel->pLoop-16 && pirq <= pChannel->pLoop))) - { - IRQINFO |= 4<<(int)(ch>=24); - irqCallbackSPU2(); - } - } - - // flag handler - if((flags&4) && (!pChannel->bIgnoreLoop)) - pChannel->pLoop=start-16; // loop adress - - if(flags&1) // 1: stop/loop - { - // We play this block out first... - dwEndChannel2[ch/24]|=(1<<(ch%24)); - //if(!(flags&2)) // 1+2: do loop... otherwise: stop - if(flags!=3 || pChannel->pLoop==NULL) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example) - { // and checking if pLoop is set avoids crashes, yeah - start = (u8*)-1; - pChannel->bStop = true; - pChannel->bIgnoreLoop = false; - } - else - { - start = pChannel->pLoop; - } - } - - pChannel->pCurr=start; // store values for next cycle - } - - pChannel->iSBPos++; // get sample data - pChannel->spos -= 0x10000; - } - - MixADSR(pChannel); - - // go to the next packet - ns++; - pChannel->spos += pChannel->sinc; - } -ENDX: - ; - } - - // mix all channels - if( (spu2Ru16(REG_C0_MMIX) & 0xC0) && (spu2Ru16(REG_C0_ADMAS) & 0x1) && !(spu2Ru16(REG_C0_CTRL) & 0x30)) { - for(int ns=0;ns0x0fffff) // wrap at 2Mb - spuaddr=0; // wrap - } - - spuaddr+=19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) - C0_SPUADDR_SET(spuaddr); - - // got from J.F. and Kanodin... is it needed? - spu2Ru16(REG_C0_SPUSTAT) &=~0x80; // DMA complete - SPUStartCycle[0] = SPUCycles; - SPUTargetCycle[0] = size; - interrupt |= (1<<1); -} - -void CALLBACK SPU2readDMA7Mem(u16* pMem, int size) -{ - u32 spuaddr = C1_SPUADDR; - int i; - -#ifdef SPU2_LOG - SPU2_LOG("SPU2 readDMA7Mem size %x, addr: %x\n", size, pMem); -#endif - - for(i=0;i0x0fffff) // wrap at 2Mb - spuaddr=0; // wrap - } - - spuaddr+=19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) - C1_SPUADDR_SET(spuaddr); - - // got from J.F. and Kanodin... is it needed? - spu2Ru16(REG_C1_SPUSTAT)&=~0x80; // DMA complete - SPUStartCycle[1] = SPUCycles; - SPUTargetCycle[1] = size; - interrupt |= (1<<2); -} - -// WRITE - -// AutoDMA's are used to transfer to the DIRECT INPUT area of the spu2 memory -// Left and Right channels are always interleaved together in the transfer so -// the AutoDMA's deinterleaves them and transfers them. An interrupt is -// generated when half of the buffer (256 short-words for left and 256 -// short-words for right ) has been transferred. Another interrupt occurs at -// the end of the transfer. -int ADMAS4Write() -{ - u32 spuaddr; - if(interrupt & 0x2) return 0; - if(Adma4.AmountLeft <= 0) return 1; - - spuaddr = C0_SPUADDR; - // SPU2 Deinterleaves the Left and Right Channels - memcpy((short*)(spu2mem + spuaddr + 0x2000),(short*)Adma4.MemAddr,512); - Adma4.MemAddr += 256; - memcpy((short*)(spu2mem + spuaddr + 0x2200),(short*)Adma4.MemAddr,512); - Adma4.MemAddr += 256; - spuaddr = (spuaddr + 256) & 511; - C0_SPUADDR_SET(spuaddr); - - Adma4.AmountLeft-=512; - if(Adma4.AmountLeft == 0) - { - SPUStartCycle[0] = SPUCycles; - SPUTargetCycle[0] = 1;//512*48000; - spu2Ru16(REG_C0_SPUSTAT)&=~0x80; - interrupt |= (1<<1); - } - return 0; -} - -int ADMAS7Write() -{ - u32 spuaddr; - if(interrupt & 0x4) return 0; - if(Adma7.AmountLeft <= 0) return 1; - - spuaddr = C1_SPUADDR; - // SPU2 Deinterleaves the Left and Right Channels - memcpy((short*)(spu2mem + spuaddr + 0x2400),(short*)Adma7.MemAddr,512); - Adma7.MemAddr += 256; - memcpy((short*)(spu2mem + spuaddr + 0x2600),(short*)Adma7.MemAddr,512); - Adma7.MemAddr += 256; - spuaddr = (spuaddr + 256) & 511; - C1_SPUADDR_SET(spuaddr); - - Adma7.AmountLeft-=512; - if(Adma7.AmountLeft == 0) - { - SPUStartCycle[1] = SPUCycles; - SPUTargetCycle[1] = 1;//512*48000; - spu2Ru16(REG_C1_SPUSTAT)&=~0x80; - interrupt |= (1<<2); - } - return 0; -} - -void CALLBACK SPU2writeDMA4Mem(u16* pMem, int size) -{ - u32 spuaddr; - -#ifdef SPU2_LOG - SPU2_LOG("SPU2 writeDMA4Mem size %x, addr: %x\n", size, pMem); -#endif - if((spu2Ru16(REG_C0_ADMAS) & 0x1) && (spu2Ru16(REG_C0_CTRL) & 0x30) == 0 && size) - { - //fwrite(pMem,iSize<<1,1,LogFile); - memset(&Adma4,0,sizeof(ADMA)); - C0_SPUADDR_SET(0); - Adma4.MemAddr = pMem; - Adma4.AmountLeft = size; - ADMAS4Write(); - return; - } - - spuaddr = C0_SPUADDR; - memcpy((unsigned char*)(spu2mem + spuaddr),(unsigned char*)pMem,size<<1); - spuaddr += size; - C0_SPUADDR_SET(spuaddr); - - if( (spu2Ru16(REG_C0_CTRL)&0x40) && C0_IRQA == spuaddr){ - spu2Ru16(SPDIF_OUT) |= 0x4; - IRQINFO |= 4; - irqCallbackSPU2(); - } - if(spuaddr>0xFFFFE) - spuaddr = 0x2800; - C0_SPUADDR_SET(spuaddr); - - MemAddr[0] += size<<1; - spu2Ru16(REG_C0_SPUSTAT)&=~0x80; - SPUStartCycle[0] = SPUCycles; - SPUTargetCycle[0] = 1;//iSize; - interrupt |= (1<<1); -} - -void CALLBACK SPU2writeDMA7Mem(u16* pMem, int size) -{ - u32 spuaddr; - -#ifdef SPU2_LOG - SPU2_LOG("SPU2 writeDMA7Mem size %x, addr: %x\n", size, pMem); -#endif - if((spu2Ru16(REG_C1_ADMAS) & 0x2) && (spu2Ru16(REG_C1_CTRL) & 0x30) == 0 && size) - { - //fwrite(pMem,iSize<<1,1,LogFile); - memset(&Adma7,0,sizeof(ADMA)); - C1_SPUADDR_SET(0); - Adma7.MemAddr = pMem; - Adma7.AmountLeft = size; - ADMAS7Write(); - return; - } - - spuaddr = C1_SPUADDR; - memcpy((unsigned char*)(spu2mem + spuaddr),(unsigned char*)pMem,size<<1); - spuaddr += size; - C1_SPUADDR_SET(spuaddr); - - if( (spu2Ru16(REG_C1_CTRL)&0x40) && C1_IRQA == spuaddr){ - spu2Ru16(SPDIF_OUT) |= 0x8; - IRQINFO |= 8; - irqCallbackSPU2(); - } - if(spuaddr>0xFFFFE) - spuaddr = 0x2800; - C1_SPUADDR_SET(spuaddr); - - MemAddr[1] += size<<1; - spu2Ru16(REG_C1_SPUSTAT)&=~0x80; - SPUStartCycle[1] = SPUCycles; - SPUTargetCycle[1] = 1;//iSize; - interrupt |= (1<<2); -} - -void CALLBACK SPU2interruptDMA4() -{ -#ifdef SPU2_LOG - SPU2_LOG("SPU2 interruptDMA4\n"); -#endif -// spu2Rs16(REG_C0_CTRL)&= ~0x30; -// spu2Rs16(REG__1B0) = 0; -// spu2Rs16(SPU2_STATX_WRDY_M)|= 0x80; - spu2Rs16(REG_C0_CTRL)&=~0x30; - spu2Ru16(REG_C0_SPUSTAT)|=0x80; -} - -void CALLBACK SPU2interruptDMA7() -{ -#ifdef SPU2_LOG - SPU2_LOG("SPU2 interruptDMA7\n"); -#endif -// spu2Rs16(REG_C1_CTRL)&= ~0x30; -// //spu2Rs16(REG__5B0) = 0; -// spu2Rs16(SPU2_STATX_DREQ)|= 0x80; - spu2Rs16(REG_C1_CTRL)&=~0x30; - spu2Ru16(REG_C1_SPUSTAT)|=0x80; -} - -// turn channels on -void SoundOn(int start,int end,unsigned short val) // SOUND ON PSX COMAND -{ - for(int ch=start;ch>=1) // loop channels - { - if((val&1) && voices[ch].pStart) // mmm... start has to be set before key on !?! - { - voices[ch].bNew=true; - voices[ch].bIgnoreLoop = false; - } - } -} - -// turn channels off -void SoundOff(int start,int end,unsigned short val) // SOUND OFF PSX COMMAND -{ - for(int ch=start;ch>=1) // loop channels - { - if(val&1) // && s_chan[i].bOn) mmm... - voices[ch].bStop=true; - } -} - -void FModOn(int start,int end,unsigned short val) // FMOD ON PSX COMMAND -{ - int ch; - - for(ch=start;ch>=1) // loop channels - { - if(val&1) // -> fmod on/off - { - if(ch>0) { - } - } - else { - // turn fmod off - } - } -} - -void CALLBACK SPU2write(u32 mem, u16 value) -{ - u32 spuaddr; -#ifdef SPU2_LOG - SPU2_LOG("SPU2 write mem %x value %x\n", mem, value); -#endif - - assert( C0_SPUADDR < 0x100000); - assert( C1_SPUADDR < 0x100000); - - spu2Ru16(mem) = value; - u32 r = mem&0xffff; - - // channel info - if((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? - { - int ch=0; - if(r>=0x400) ch=((r-0x400)>>4)+24; - else ch=(r>>4); - - VOICE_PROCESSED* pvoice = &voices[ch]; - - switch(r&0x0f) - { - case 0: - case 2: - pvoice->SetVolume(mem&0x2); - break; - case 4: - { - int NP; - if(value>0x3fff) NP=0x3fff; // get pitch val - else NP=value; - - pvoice->pvoice->pitch = NP; - - NP=(44100L*NP)/4096L; // calc frequency - if(NP<1) NP=1; // some security - pvoice->iActFreq=NP; // store frequency - break; - } - case 6: - { - pvoice->ADSRX.AttackModeExp=(value&0x8000)?1:0; - pvoice->ADSRX.AttackRate = ((value>>8) & 0x007f); - pvoice->ADSRX.DecayRate = (((value>>4) & 0x000f)); - pvoice->ADSRX.SustainLevel = (value & 0x000f); - break; - } - case 8: - pvoice->ADSRX.SustainModeExp = (value&0x8000)?1:0; - pvoice->ADSRX.SustainIncrease= (value&0x4000)?0:1; - pvoice->ADSRX.SustainRate = ((value>>6) & 0x007f); - pvoice->ADSRX.ReleaseModeExp = (value&0x0020)?1:0; - pvoice->ADSRX.ReleaseRate = ((value & 0x001f)); - break; - } - - return; - } - - // more channel info - if((r>=0x01c0 && r<=0x02E0)||(r>=0x05c0 && r<=0x06E0)) - { - int ch=0; - unsigned long rx=r; - if(rx>=0x400) - { - ch=24; - rx-=0x400; - } - - ch+=((rx-0x1c0)/12); - rx-=(ch%24)*12; - VOICE_PROCESSED* pvoice = &voices[ch]; - - switch(rx) - { - case 0x1C0: - pvoice->iStartAddr=(((unsigned long)value&0x3f)<<16)|(pvoice->iStartAddr&0xFFFF); - pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); - break; - case 0x1C2: - pvoice->iStartAddr=(pvoice->iStartAddr & 0x3f0000) | (value & 0xFFFF); - pvoice->pStart=(u8*)(spu2mem+pvoice->iStartAddr); - break; - case 0x1C4: - pvoice->iLoopAddr =(((unsigned long)value&0x3f)<<16)|(pvoice->iLoopAddr&0xFFFF); - pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); - pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; - break; - case 0x1C6: - pvoice->iLoopAddr=(pvoice->iLoopAddr& 0x3f0000) | (value & 0xFFFF); - pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); - pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; - break; - case 0x1C8: - // unused... check if it gets written as well - pvoice->iNextAddr=(((unsigned long)value&0x3f)<<16)|(pvoice->iNextAddr&0xFFFF); - break; - case 0x1CA: - // unused... check if it gets written as well - pvoice->iNextAddr=(pvoice->iNextAddr & 0x3f0000) | (value & 0xFFFF); - break; - } - - return; - } - - // process non-channel data - switch(mem&0xffff) { - case REG_C0_SPUDATA: - spuaddr = C0_SPUADDR; - spu2mem[spuaddr] = value; - spuaddr++; - if( (spu2Ru16(REG_C0_CTRL)&0x40) && C0_IRQA == spuaddr){ - spu2Ru16(SPDIF_OUT) |= 0x4; - IRQINFO |= 4; - irqCallbackSPU2(); - } - if(spuaddr>0xFFFFE) - spuaddr = 0x2800; - C0_SPUADDR_SET(spuaddr); - spu2Ru16(REG_C0_SPUSTAT)&=~0x80; - spu2Ru16(REG_C0_CTRL)&=~0x30; - break; - case REG_C1_SPUDATA: - spuaddr = C1_SPUADDR; - spu2mem[spuaddr] = value; - spuaddr++; - if( (spu2Ru16(REG_C1_CTRL)&0x40) && C1_IRQA == spuaddr){ - spu2Ru16(SPDIF_OUT) |= 0x8; - IRQINFO |= 8; - irqCallbackSPU2(); - } - if(spuaddr>0xFFFFE) - spuaddr = 0x2800; - C1_SPUADDR_SET(spuaddr); - spu2Ru16(REG_C1_SPUSTAT)&=~0x80; - spu2Ru16(REG_C1_CTRL)&=~0x30; - break; - case REG_C0_IRQA_HI: - case REG_C0_IRQA_LO: - pSpuIrq[0]=spu2mem+(C0_IRQA<<1); - break; - case REG_C1_IRQA_HI: - case REG_C1_IRQA_LO: - pSpuIrq[1]=spu2mem+(C1_IRQA<<1); - break; - - case REG_C0_SPUADDR_HI: - case REG_C1_SPUADDR_HI: - spu2Ru16(mem) = value&0xf; - break; - - case REG_C0_SPUON1: SoundOn(0,16,value); break; - case REG_C0_SPUON2: SoundOn(16,24,value); break; - case REG_C1_SPUON1: SoundOn(24,40,value); break; - case REG_C1_SPUON2: SoundOn(40,48,value); break; - case REG_C0_SPUOFF1: SoundOff(0,16,value); break; - case REG_C0_SPUOFF2: SoundOff(16,24,value); break; - case REG_C1_SPUOFF1: SoundOff(24,40,value); break; - case REG_C1_SPUOFF2: SoundOff(40,48,value); break; - - // According to manual all bits are cleared by writing an arbitary value - case REG_C0_END1: dwEndChannel2[0] = 0; break; - case REG_C0_END2: dwEndChannel2[0] = 0; break; - case REG_C1_END1: dwEndChannel2[1] = 0; break; - case REG_C1_END2: dwEndChannel2[1] = 0; break; - case REG_C0_FMOD1: FModOn(0,16,value); break; - case REG_C0_FMOD2: FModOn(16,24,value); break; - case REG_C1_FMOD1: FModOn(24,40,value); break; - case REG_C1_FMOD2: FModOn(40,48,value); break; - } - - assert( C0_SPUADDR < 0x100000); - assert( C1_SPUADDR < 0x100000); -} - -u16 CALLBACK SPU2read(u32 mem) -{ - u32 spuaddr; - u16 ret; - u32 r = mem&0xffff; - - if((r>=0x0000 && r<=0x0180)||(r>=0x0400 && r<=0x0580)) // some channel info? - { - int ch=0; - if(r>=0x400) ch=((r-0x400)>>4)+24; - else ch=(r>>4); - - VOICE_PROCESSED* pvoice = &voices[ch]; - - switch(r&0x0f) { - case 10: return (unsigned short)(pvoice->ADSRX.EnvelopeVol>>16); - } - } - - if((r>0x01c0 && r<=0x02E0)||(r>0x05c0 && r<=0x06E0)) // some channel info? - { - int ch=0; - unsigned long rx=r; - if(rx>=0x400) - { - ch=24; - rx-=0x400; - } - - ch+=((rx-0x1c0)/12); - rx-=(ch%24)*12; - VOICE_PROCESSED* pvoice = &voices[ch]; - - switch(rx) { - case 0x1C0: return (u16)(((pvoice->pStart-(u8*)spu2mem)>>17)&0x3F); - case 0x1C2: return (u16)(((pvoice->pStart-(u8*)spu2mem)>>1)&0xFFFF); - case 0x1C4: return (u16)(((pvoice->pLoop-(u8*)spu2mem)>>17)&0x3F); - case 0x1C6: return (u16)(((pvoice->pLoop-(u8*)spu2mem)>>1)&0xFFFF); - case 0x1C8: return (u16)(((pvoice->pCurr-(u8*)spu2mem)>>17)&0x3F); - case 0x1CA: return (u16)(((pvoice->pCurr-(u8*)spu2mem)>>1)&0xFFFF); - } - } - - switch(mem&0xffff) { - case REG_C0_SPUDATA: - spuaddr = C0_SPUADDR; - ret =spu2mem[spuaddr]; - spuaddr++; - if(spuaddr>0xfffff) - spuaddr=0; - C0_SPUADDR_SET(spuaddr); - break; - case REG_C1_SPUDATA: - spuaddr = C1_SPUADDR; - ret = spu2mem[spuaddr]; - spuaddr++; - if(spuaddr>0xfffff) - spuaddr=0; - C1_SPUADDR_SET(spuaddr); - break; - - case REG_C0_END1: return (dwEndChannel2[0]&0xffff); - case REG_C0_END2: return (dwEndChannel2[0]>>16); - case REG_C1_END1: return (dwEndChannel2[1]&0xffff); - case REG_C1_END2: return (dwEndChannel2[1]>>16); - - case REG_IRQINFO: - ret = IRQINFO; - IRQINFO = 0; - break; - default: - ret = spu2Ru16(mem); - } -#ifdef SPU2_LOG - SPU2_LOG("SPU2 read mem %x: %x\n", mem, ret); -#endif - - return ret; -} - -void CALLBACK SPU2WriteMemAddr(int core, u32 value) -{ - MemAddr[core] = value; -} - -u32 CALLBACK SPU2ReadMemAddr(int core) -{ - return MemAddr[core]; -} - -void CALLBACK SPU2irqCallback(void (*SPU2callback)(),void (*DMA4callback)(),void (*DMA7callback)()) -{ - irqCallbackSPU2 = SPU2callback; - irqCallbackDMA4 = DMA4callback; - irqCallbackDMA7 = DMA7callback; -} - -// VOICE_PROCESSED definitions -SPU_CONTROL_* VOICE_PROCESSED::GetCtrl() -{ - return ((SPU_CONTROL_*)(spu2regs+memoffset+REG_C0_CTRL)); -} - -void VOICE_PROCESSED::SetVolume(int iProcessRight) -{ - u16 vol = iProcessRight ? pvoice->right.word : pvoice->left.word; - - if(vol&0x8000) // sweep not working - { - short sInc=1; // -> sweep up? - if(vol&0x2000) sInc=-1; // -> or down? - if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this - vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 - vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! - vol*=128; - } - else // no sweep: - { - if(vol&0x4000) // -> mmm... phase inverted? have to investigate this - vol=0x3fff-(vol&0x3fff); - } - - vol&=0x3fff; - // set volume - //if( iProcessRight ) right = vol; - //else left = vol; -} - -void VOICE_PROCESSED::StartSound() -{ - ADSRX.lVolume=1; // and init some adsr vars - ADSRX.State=0; - ADSRX.EnvelopeVol=0; - - if(bReverb && GetCtrl()->reverb ) - { - // setup the reverb effects - } - - pCurr=pStart; // set sample start - iSBPos=28; - - bNew=false; // init channel flags - bStop=false; - bOn=true; - spos=0x10000L; -} - -void VOICE_PROCESSED::VoiceChangeFrequency() -{ - iUsedFreq=iActFreq; // -> take it and calc steps - sinc=(u32)pvoice->pitch<<4; - if(!sinc) - sinc=1; -} - -void VOICE_PROCESSED::Stop() -{ -} - -// GUI Routines -s32 CALLBACK SPU2test() { - return 0; -} - -typedef struct { - u32 version; - u8 spu2regs[0x10000]; -} SPU2freezeData; - -s32 CALLBACK SPU2freeze(int mode, freezeData *data){ - SPU2freezeData *spud; - - if (mode == FREEZE_LOAD) { - spud = (SPU2freezeData*)data->data; - if( spud->version == 0x11223344 ) { - memcpy(spu2regs, spud->spu2regs, 0x10000); - } - else printf("SPU2null wrong format\n"); - } else - if (mode == FREEZE_SAVE) { - spud = (SPU2freezeData*)data->data; - spud->version = 0x11223344; - memcpy(spud->spu2regs, spu2regs, 0x10000); - } else - if (mode == FREEZE_SIZE) { - data->size = sizeof(SPU2freezeData); - } - - return 0; -} - -#ifndef _WIN32 - -GtkWidget *MsgDlg; - -void OnMsg_Ok() { - gtk_widget_destroy(MsgDlg); - gtk_main_quit(); -} - -void SysMessage(char *fmt, ...) { - GtkWidget *Ok,*Txt; - GtkWidget *Box,*Box1; - va_list list; - char msg[512]; - - va_start(list, fmt); - vsprintf(msg, fmt, list); - va_end(list); - - if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; - - MsgDlg = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_position(GTK_WINDOW(MsgDlg), GTK_WIN_POS_CENTER); - gtk_window_set_title(GTK_WINDOW(MsgDlg), "SPU2null Msg"); - gtk_container_set_border_width(GTK_CONTAINER(MsgDlg), 5); - - Box = gtk_vbox_new(5, 0); - gtk_container_add(GTK_CONTAINER(MsgDlg), Box); - gtk_widget_show(Box); - - Txt = gtk_label_new(msg); - - gtk_box_pack_start(GTK_BOX(Box), Txt, FALSE, FALSE, 5); - gtk_widget_show(Txt); - - Box1 = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(Box), Box1, FALSE, FALSE, 0); - gtk_widget_show(Box1); - - Ok = gtk_button_new_with_label("Ok"); - gtk_signal_connect (GTK_OBJECT(Ok), "clicked", GTK_SIGNAL_FUNC(OnMsg_Ok), NULL); - gtk_container_add(GTK_CONTAINER(Box1), Ok); - GTK_WIDGET_SET_FLAGS(Ok, GTK_CAN_DEFAULT); - gtk_widget_show(Ok); - - gtk_widget_show(MsgDlg); - - gtk_main(); -} - -void CALLBACK SPU2configure() { - SysMessage("Nothing to Configure"); -} - -void CALLBACK SPU2about() { - SysMessage("%s %d.%d", libraryName, version, build); -} - -void LoadConfig() -{ -} - -#endif diff --git a/plugins/SPU2null/Src/SPU2.h b/plugins/SPU2null/Src/SPU2.h deleted file mode 100644 index 9ea1180a2e..0000000000 --- a/plugins/SPU2null/Src/SPU2.h +++ /dev/null @@ -1,280 +0,0 @@ -/* SPU2null - * Copyright (C) 2002-2005 SPU2null Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __SPU2_H__ -#define __SPU2_H__ - -#define _CRT_SECURE_NO_DEPRECATE - -#include -#include - -extern "C" { -#define SPU2defs -#include "PS2Edefs.h" -} - -#ifdef __LINUX__ -#include -#else -#include -#include -#endif - -extern FILE *spu2Log; -#define SPU2_LOG __Log //debug mode - - -typedef struct { - int Log; -} Config; - -extern Config conf; - -void __Log(char *fmt, ...); -void SaveConfig(); -void LoadConfig(); -void SysMessage(char *fmt, ...); - -//////////////////// -// SPU2 Registers // -//////////////////// -#define REG_VP_VOLL 0x0000 -#define REG_VP_VOLR 0x0002 -#define REG_VP_PITCH 0x0004 -#define REG_VP_ADSR1 0x0006 -#define REG_VP_ADSR2 0x0008 -#define REG_VP_ENVX 0x000A -#define REG_VP_VOLXL 0x000C -#define REG_VP_VOLXR 0x000E -#define REG_C0_FMOD1 0x0180 -#define REG_C0_FMOD2 0x0182 -#define REG_C1_FMOD1 0x0580 -#define REG_C1_FMOD2 0x0582 -#define REG_S_NON 0x0184 -#define REG_S_VMIXL 0x0188 -#define REG_S_VMIXEL 0x018C -#define REG_S_VMIXR 0x0190 -#define REG_S_VMIXER 0x0194 -#define REG_C0_MMIX 0x0198 -#define REG_C1_MMIX 0x0598 -#define REG_C0_CTRL 0x019A -#define REG_C0_IRQA_HI 0x019C -#define REG_C0_IRQA_LO 0x019D -#define REG_C1_IRQA_HI 0x059C -#define REG_C1_IRQA_LO 0x059D -#define REG_C0_SPUON1 0x1A0 -#define REG_C0_SPUON2 0x1A2 -#define REG_C1_SPUON1 0x5A0 -#define REG_C1_SPUON2 0x5A2 -#define REG_C0_SPUOFF1 0x1A4 -#define REG_C0_SPUOFF2 0x1A6 -#define REG_C1_SPUOFF1 0x5A4 -#define REG_C1_SPUOFF2 0x5A6 -#define REG_C0_SPUADDR_HI 0x01A8 -#define REG_C0_SPUADDR_LO 0x01AA -#define REG_C1_SPUADDR_HI 0x05A8 -#define REG_C1_SPUADDR_LO 0x05AA -#define REG_C0_SPUDATA 0x01AC -#define REG_C1_SPUDATA 0x05AC -#define REG_C0_DMACTRL 0x01AE -#define REG_C1_DMACTRL 0x05AE -#define REG_C0_ADMAS 0x01B0 -#define REG_VA_SSA 0x01C0 -#define REG_VA_LSAX 0x01C4 -#define REG_VA_NAX 0x01C8 -#define REG_A_ESA 0x02E0 -#define REG_A_EEA 0x033C -#define REG_C0_END1 0x0340 -#define REG_C0_END2 0x0342 -#define REG_C1_END1 0x0740 -#define REG_C1_END2 0x0742 -#define REG_C0_SPUSTAT 0x0344 //not sure! -#define REG_C1_CTRL 0x059A -#define REG_C1_ADMAS 0x05B0 -#define REG_C1_SPUSTAT 0x0744 //not sure! -#define REG_P_MVOLL 0x0760 -#define REG_P_MVOLR 0x0762 -#define REG_P_EVOLL 0x0764 -#define REG_P_EVOLR 0x0766 -#define REG_P_AVOLL 0x0768 -#define REG_P_AVOLR 0x076A -#define REG_P_BVOLL 0x076C -#define REG_P_BVOLR 0x076E -#define REG_P_MVOLXL 0x0770 -#define REG_P_MVOLXR 0x0772 -#define SPDIF_OUT 0x07C0 -#define REG_IRQINFO 0x07C2 -#define SPDIF_MODE 0x07C6 -#define SPDIF_MEDIA 0x07C8 - -#define spu2Rs16(mem) (*(s16*)&spu2regs[(mem) & 0xffff]) -#define spu2Ru16(mem) (*(u16*)&spu2regs[(mem) & 0xffff]) -//#define spu2Rs32(mem) (*(s32*)&spu2regs[(mem) & 0xffff]) -//#define spu2Ru32(mem) (*(u32*)&spu2regs[(mem) & 0xffff]) - -#define IRQINFO spu2Ru16(REG_IRQINFO) - -#define SPU2_GET32BIT(lo,hi) (((u32)(spu2Ru16(hi)&0x3f)<<16)|(u32)spu2Ru16(lo)) -#define SPU2_SET32BIT(value, lo, hi) { \ - spu2Ru16(hi) = ((value)>>16)&0x3f; \ - spu2Ru16(lo) = (value)&0xffff; \ - } \ - -#define C0_IRQA SPU2_GET32BIT(REG_C0_IRQA_LO, REG_C0_IRQA_HI) -#define C1_IRQA SPU2_GET32BIT(REG_C1_IRQA_LO, REG_C1_IRQA_HI) - -#define C0_SPUADDR SPU2_GET32BIT(REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI) -#define C1_SPUADDR SPU2_GET32BIT(REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI) - -#define C0_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C0_IRQA_LO, REG_C0_IRQA_HI) -#define C1_SPUADDR_SET(value) SPU2_SET32BIT(value, REG_C1_IRQA_LO, REG_C1_IRQA_HI) - -#define SPU_NUMBER_VOICES 48 - -struct SPU_CONTROL_ -{ - u16 spuon : 1; - u16 spuUnmute : 1; - u16 noiseFreq : 6; - u16 reverb : 1; - u16 irq : 1; - u16 dma : 2; // 1 - no dma, 2 - write, 3 - read - u16 extr : 1; // external reverb - u16 cdreverb : 1; - u16 extAudio : 1; - u16 extCd : 1; -}; - -// the layout of each voice in wSpuRegs -struct _SPU_VOICE -{ - union - { - struct { - u16 Vol : 14; - u16 Inverted : 1; - u16 Sweep0 : 1; - } vol; - struct { - u16 Vol : 7; - u16 res1 : 5; - u16 Inverted : 1; - u16 Decrease : 1; // if 0, increase - u16 ExpSlope : 1; // if 0, linear slope - u16 Sweep1 : 1; // always one - } sweep; - u16 word; - } left, right; - - u16 pitch : 14; // 1000 - no pitch, 2000 - pitch + 1, etc - u16 res0 : 2; - - u16 SustainLvl : 4; - u16 DecayRate : 4; - u16 AttackRate : 7; - u16 AttackExp : 1; // if 0, linear - - u16 ReleaseRate : 5; - u16 ReleaseExp : 1; // if 0, linear - u16 SustainRate : 7; - u16 res1 : 1; - u16 SustainDec : 1; // if 0, inc - u16 SustainExp : 1; // if 0, linear - - u16 AdsrVol; - u16 Address; // add / 8 - u16 RepeatAddr; // gets reset when sample starts -}; - -// ADSR INFOS PER CHANNEL -struct ADSRInfoEx -{ - int State; - int AttackModeExp; - int AttackRate; - int DecayRate; - int SustainLevel; - int SustainModeExp; - int SustainIncrease; - int SustainRate; - int ReleaseModeExp; - int ReleaseRate; - int EnvelopeVol; - long lVolume; -}; - -#define NSSIZE 48 // ~ 1 ms of data -#define NSFRAMES 16 // gather at least NSFRAMES of NSSIZE before submitting -#define NSPACKETS 4 -#define SPU_VOICE_STATE_SIZE (sizeof(VOICE_PROCESSED)-4*sizeof(void*)) - -struct VOICE_PROCESSED -{ - VOICE_PROCESSED() - { - memset(this, 0, sizeof(VOICE_PROCESSED)); - } - ~VOICE_PROCESSED() - { - } - - void SetVolume(int right); - void StartSound(); - void VoiceChangeFrequency(); - void FModChangeFrequency(int ns); - void Stop(); - - SPU_CONTROL_* GetCtrl(); - - // start save state - - int iSBPos; // mixing stuff - int spos; - int sinc; - - int iActFreq; // current psx pitch - int iUsedFreq; // current pc pitch - - int iStartAddr, iLoopAddr, iNextAddr; - - ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) - bool bIgnoreLoop, bNew, bNoise, bReverb, bOn, bStop, bVolChanged; - int memoffset; // if first core, 0, if second, 0x400 - - // end save state - - /////////////////// - // Sound Buffers // - /////////////////// - u8* pStart; // start and end addresses - u8* pLoop, *pCurr; - - _SPU_VOICE* pvoice; -}; - -struct ADMA -{ - unsigned short * MemAddr; - long IntPointer; - int Index; - int AmountLeft; - int Enabled; -}; - -#endif /* __SPU2_H__ */ diff --git a/plugins/SPU2null/Src/Config.cpp b/plugins/SPU2null/Windows/Config.cpp similarity index 100% rename from plugins/SPU2null/Src/Config.cpp rename to plugins/SPU2null/Windows/Config.cpp diff --git a/plugins/SPU2null/Src/ProjectRootDir.vsprops b/plugins/SPU2null/Windows/ProjectRootDir.vsprops similarity index 100% rename from plugins/SPU2null/Src/ProjectRootDir.vsprops rename to plugins/SPU2null/Windows/ProjectRootDir.vsprops diff --git a/plugins/SPU2null/Src/SPU2null.def b/plugins/SPU2null/Windows/SPU2null.def similarity index 100% rename from plugins/SPU2null/Src/SPU2null.def rename to plugins/SPU2null/Windows/SPU2null.def diff --git a/plugins/SPU2null/Src/SPU2null.rc b/plugins/SPU2null/Windows/SPU2null.rc similarity index 100% rename from plugins/SPU2null/Src/SPU2null.rc rename to plugins/SPU2null/Windows/SPU2null.rc diff --git a/plugins/SPU2null/Src/SPU2null_2008.vcproj b/plugins/SPU2null/Windows/SPU2null_2008.vcproj similarity index 89% rename from plugins/SPU2null/Src/SPU2null_2008.vcproj rename to plugins/SPU2null/Windows/SPU2null_2008.vcproj index 1a8b6daea3..4df91f6d8e 100644 --- a/plugins/SPU2null/Src/SPU2null_2008.vcproj +++ b/plugins/SPU2null/Windows/SPU2null_2008.vcproj @@ -92,7 +92,7 @@ /> @@ -187,7 +187,7 @@ > diff --git a/plugins/SPU2null/Src/Win32.cpp b/plugins/SPU2null/Windows/Win32.cpp similarity index 100% rename from plugins/SPU2null/Src/Win32.cpp rename to plugins/SPU2null/Windows/Win32.cpp diff --git a/plugins/SPU2null/Src/resource.h b/plugins/SPU2null/Windows/resource.h similarity index 100% rename from plugins/SPU2null/Src/resource.h rename to plugins/SPU2null/Windows/resource.h diff --git a/plugins/SPU2null/build.sh b/plugins/SPU2null/build.sh index 5d04adfb50..da1381a4c4 100644 --- a/plugins/SPU2null/build.sh +++ b/plugins/SPU2null/build.sh @@ -1,13 +1,32 @@ #!/bin/sh +echo --------------- +echo Building SPU2null +echo --------------- + curdir=`pwd` -echo ----------------- -echo Building SPU2null -echo ----------------- -cd ${curdir}/Src +if test "${SPU2nullOPTIONS+set}" != set ; then +export SPU2nullOPTIONS="" +fi + +if [ $# -gt 0 ] && [ $1 = "all" ] +then + +aclocal +automake -a +autoconf + +./configure ${SPU2nullOPTIONS} --prefix=${PCSX2PLUGINS} make clean -make $@ +make install -cp libSPU2null.so ${PCSX2PLUGINS} +else +make $@ +fi + +if [ $? -ne 0 ] +then +exit 1 +fi diff --git a/plugins/SPU2null/configure.ac b/plugins/SPU2null/configure.ac new file mode 100644 index 0000000000..59ffe18988 --- /dev/null +++ b/plugins/SPU2null/configure.ac @@ -0,0 +1,80 @@ +AC_INIT(SPU2null, 0.5,arcum42@gmail.com) + +AM_INIT_AUTOMAKE(SPU2null,0.8) + +AC_PROG_CC([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CXX([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) +AC_PROG_CPP([gcc g++ cl KCC CC cxx cc++ xlC aCC c++]) + +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl necessary for compiling assembly +AM_PROG_AS + +AC_SUBST(SPU2null_CURRENT, 0) +AC_SUBST(SPU2null_REVISION, 8) +AC_SUBST(SPU2null_AGE, 0) +AC_SUBST(SPU2null_RELEASE,[$SPU2null_CURRENT].[$SPU2null_REVISION].[$SPU2null_AGE]) +AC_SUBST(SPU2null_SONAME,libSPU2null.so.[$SPU2null_CURRENT].[$SPU2null_REVISION].[$SPU2null_AGE]) + +CFLAGS= +CPPFLAGS= +CXXFLAGS= + +dnl Check for debug build +AC_MSG_CHECKING(debug build) +AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [debug build]), +debug=$enableval,debug=no) +if test "x$debug" == xyes +then + AC_DEFINE(_DEBUG,1,[_DEBUG]) + CFLAGS+="-g -fPIC -Wall -Wno-unused-value " + CPPFLAGS+="-g -fPIC -Wall -Wno-unused-value " + CXXFLAGS+="-g -fPIC -Wall -Wno-unused-value " +else + AC_DEFINE(NDEBUG,1,[NDEBUG]) + CFLAGS+="-O3 -fomit-frame-pointer -fPIC -Wall -Wno-unused-value " + CPPFLAGS+="-O3 -fomit-frame-pointer -fPIC -Wall -Wno-unused-value " + CXXFLAGS+="-O3 -fomit-frame-pointer -fPIC -Wall -Wno-unused-value " +fi +AM_CONDITIONAL(DEBUGBUILD, test x$debug = xyes) +AC_MSG_RESULT($debug) + +AC_DEFINE(__LINUX__,1,[__LINUX__]) + +dnl Check for dev build +AC_MSG_CHECKING(for development build...) +AC_ARG_ENABLE(devbuild, AC_HELP_STRING([--enable-devbuild], [Special Build for developers that simplifies testing and adds extra checks]), + devbuild=$enableval,devbuild=no) +if test "x$devbuild" == xyes +then + AC_DEFINE(SPU2null_DEVBUILD,1,[SPU2null_DEVBUILD]) +fi +AC_MSG_RESULT($devbuild) +AM_CONDITIONAL(RELEASE_TO_PUBLIC, test x$devbuild = xno) + +AC_CHECK_FUNCS([ _aligned_malloc _aligned_free ], AC_DEFINE(HAVE_ALIGNED_MALLOC)) + +dnl gtk +AC_MSG_CHECKING(gtk2+) +AC_CHECK_PROG(GTK_CONFIG, pkg-config, pkg-config) +LIBS+=$(pkg-config --libs gtk+-2.0) + +dnl bindir = pcsx2exe + +dnl assuming linux environment +so_ext=".so.$SPU2null_RELEASE" +SHARED_LDFLAGS="-shared" +AC_SUBST(so_ext) +AC_SUBST(SHARED_LDFLAGS) + +AC_CHECK_LIB(stdc++,main,[LIBS="$LIBS -lstdc++"]) + +AC_OUTPUT([ + Makefile + ]) + +echo "Configuration:" +echo " Debug build? $debug" +echo " Dev build? $devbuild" \ No newline at end of file diff --git a/plugins/SPU2null/install-sh b/plugins/SPU2null/install-sh new file mode 120000 index 0000000000..8272958b56 --- /dev/null +++ b/plugins/SPU2null/install-sh @@ -0,0 +1 @@ +/usr/share/automake-1.10/install-sh \ No newline at end of file diff --git a/plugins/SPU2null/missing b/plugins/SPU2null/missing new file mode 120000 index 0000000000..1f0fe88e65 --- /dev/null +++ b/plugins/SPU2null/missing @@ -0,0 +1 @@ +/usr/share/automake-1.10/missing \ No newline at end of file