From 347e6c44bbc65603870e59cdae445f32629cb7a9 Mon Sep 17 00:00:00 2001 From: arcum42 Date: Fri, 30 Jan 2009 22:14:52 +0000 Subject: [PATCH] ZeroSPU2: Refactor a few things, break up a few files, and fix a fencepost issue when clamping. git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@663 a6443dda-0b58-4228-96e9-037be469359c --- plugins/zerospu2/Makefile.am | 2 +- plugins/zerospu2/Win32.cpp | 329 ++++++--------------- plugins/zerospu2/ZeroSPU2_2008.vcproj | 12 + plugins/zerospu2/build.sh | 2 +- plugins/zerospu2/configure.ac | 12 +- plugins/zerospu2/dsound51.cpp | 248 ++++++++++++++++ plugins/zerospu2/misc.h | 147 ++++++++++ plugins/zerospu2/reg.h | 182 ++++++++++++ plugins/zerospu2/voices.cpp | 10 +- plugins/zerospu2/zerodma.cpp | 332 +++++++++------------- plugins/zerospu2/zerospu2.cpp | 394 +++++++++++--------------- plugins/zerospu2/zerospu2.h | 334 ++++++---------------- 12 files changed, 1061 insertions(+), 943 deletions(-) create mode 100644 plugins/zerospu2/dsound51.cpp create mode 100644 plugins/zerospu2/misc.h create mode 100644 plugins/zerospu2/reg.h diff --git a/plugins/zerospu2/Makefile.am b/plugins/zerospu2/Makefile.am index 1d06f22a90..891935a4ae 100644 --- a/plugins/zerospu2/Makefile.am +++ b/plugins/zerospu2/Makefile.am @@ -28,7 +28,7 @@ libZeroSPU2_LDFLAGS+=-Wl,-soname,@ZEROSPU2_SONAME@ libZeroSPU2_LDADD=$(libZeroSPU2_a_OBJECTS) SoundTouch/libSoundTouch.a libZeroSPU2_a_SOURCES = zerospu2.cpp voices.cpp zerodma.cpp -libZeroSPU2_a_SOURCES += zerospu2.h +libZeroSPU2_a_SOURCES += zerospu2.h reg.h misc.h libZeroSPU2_a_SOURCES += Linux/interface.c Linux/Linux.cpp Linux/Alsa.cpp Linux/OSS.cpp Linux/support.c SUBDIRS = SoundTouch diff --git a/plugins/zerospu2/Win32.cpp b/plugins/zerospu2/Win32.cpp index 9e24627c9d..5702778677 100644 --- a/plugins/zerospu2/Win32.cpp +++ b/plugins/zerospu2/Win32.cpp @@ -1,252 +1,86 @@ -#include +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 #include #include #include "zerospu2.h" #include "resource.h" -///////////////////////////////////// -// use DirectSound for the sound -#include - -#define SOUNDSIZE 76800//4*48*73 -HWND hWMain; - -LPDIRECTSOUND lpDS; -LPDIRECTSOUNDBUFFER lpDSBPRIMARY = NULL; -LPDIRECTSOUNDBUFFER lpDSBSECONDARY1 = NULL; -LPDIRECTSOUNDBUFFER lpDSBSECONDARY2 = NULL; -DSBUFFERDESC dsbd; -DSBUFFERDESC dsbdesc; -DSCAPS dscaps; -DSBCAPS dsbcaps; - -unsigned long LastWrite=0xffffffff; -unsigned long LastWriteS=0xffffffff; -unsigned long LastPlay=0; - -int SetupSound() -{ - HRESULT dsval;WAVEFORMATEX pcmwf; - - dsval = DirectSoundCreate(NULL,&lpDS,NULL); - if(dsval!=DS_OK) { - MessageBox(NULL,"DirectSoundCreate!","Error",MB_OK); - return -1; - } - - if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_PRIORITY)) { - if(DS_OK!=IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_NORMAL)) { - MessageBox(NULL,"SetCooperativeLevel!","Error",MB_OK); - return -1; - } - } - - memset(&dsbd,0,sizeof(DSBUFFERDESC)); - dsbd.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(dsbd); - dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; - dsbd.dwBufferBytes = 0; - dsbd.lpwfxFormat = NULL; - - dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbd,&lpDSBPRIMARY,NULL); - if(dsval!=DS_OK) { - MessageBox(NULL, "CreateSoundBuffer (Primary)", "Error",MB_OK); - return -1; - } - - memset(&pcmwf, 0, sizeof(WAVEFORMATEX)); - pcmwf.wFormatTag = WAVE_FORMAT_PCM; - - pcmwf.nChannels = 2; - pcmwf.nBlockAlign = 4; - - pcmwf.nSamplesPerSec = SAMPLE_RATE; - - pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; - pcmwf.wBitsPerSample = 16; - - dsval=IDirectSoundBuffer_SetFormat(lpDSBPRIMARY,&pcmwf); - if(dsval!=DS_OK) { - MessageBox(NULL, "SetFormat!", "Error",MB_OK); - return -1; - } - - dscaps.dwSize = sizeof(DSCAPS); - dsbcaps.dwSize = sizeof(DSBCAPS); - IDirectSound_GetCaps(lpDS,&dscaps); - IDirectSoundBuffer_GetCaps(lpDSBPRIMARY,&dsbcaps); - - memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); - dsbdesc.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(DSBUFFERDESC); - dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; - dsbdesc.dwBufferBytes = SOUNDSIZE; - dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; - - dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); - if(dsval!=DS_OK) { - dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; - dsval=IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); - if(dsval!=DS_OK) { - MessageBox(NULL,"CreateSoundBuffer (Secondary1)", "Error",MB_OK); - return -1; - } - } - - dsval=IDirectSoundBuffer_Play(lpDSBPRIMARY,0,0,DSBPLAY_LOOPING); - if(dsval!=DS_OK) { - MessageBox(NULL,"Play (Primary)","Error",MB_OK); - return -1; - } - - dsval=IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); - if(dsval!=DS_OK) { - MessageBox(NULL,"Play (Secondary1)","Error",MB_OK); - return -1; - } - - LastWrite=0x00000000;LastPlay=0; // init some play vars - return 0; -} - -void RemoveSound() -{ - int iRes; - - if(lpDSBSECONDARY1!=NULL) { - IDirectSoundBuffer_Stop(lpDSBSECONDARY1); - iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); - // FF says such a loop is bad... Demo says it's good... Pete doesn't care - while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBSECONDARY1); - lpDSBSECONDARY1=NULL; - } - - if(lpDSBPRIMARY!=NULL) { - IDirectSoundBuffer_Stop(lpDSBPRIMARY); - iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); - // FF says such a loop is bad... Demo says it's good... Pete doesn't care - while(iRes!=0) iRes=IDirectSoundBuffer_Release(lpDSBPRIMARY); - lpDSBPRIMARY=NULL; - } - - if(lpDS!=NULL) { - iRes=IDirectSound_Release(lpDS); - // FF says such a loop is bad... Demo says it's good... Pete doesn't care - while(iRes!=0) iRes=IDirectSound_Release(lpDS); - lpDS=NULL; - } - -} - -int SoundGetBytesBuffered() -{ - unsigned long cplay,cwrite; - - if(LastWrite==0xffffffff) return 0; - - IDirectSoundBuffer_GetCurrentPosition(lpDSBSECONDARY1,&cplay,&cwrite); - - if(cplay>SOUNDSIZE) return SOUNDSIZE; - - if(cplay>2; - - lpSS=(unsigned long *)pSound; - while(dw) { - *lpSD++=*lpSS++; - dw--; - } - - if(lpvPtr2) { - lpSD=(unsigned long *)lpvPtr2; - dw=dwBytes2>>2; - while(dw) { - *lpSD++=*lpSS++; - dw--; - } - } - - IDirectSoundBuffer_Unlock(lpDSBSECONDARY1,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); - LastWrite+=lBytes; - if(LastWrite>=SOUNDSIZE) LastWrite-=SOUNDSIZE; - LastPlay=cplay; -} - +extern HINSTANCE hInst; ///////// // GUI // ///////// HINSTANCE hInst; -void SysMessage(char *fmt, ...) { +void SysMessage(char *fmt, ...) +{ va_list list; char tmp[512]; va_start(list,fmt); vsprintf_s(tmp,fmt,list); va_end(list); + MessageBox(0, tmp, "SPU2NULL Msg", 0); } -BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { +BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ - switch(uMsg) { + switch(uMsg) + { case WM_INITDIALOG: LoadConfig(); - if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); - //if( conf.options & OPTION_FFXHACK) CheckDlgButton(hW, IDC_FFXHACK, TRUE); - if( conf.options & OPTION_REALTIME) CheckDlgButton(hW, IDC_REALTIME, TRUE); - if( conf.options & OPTION_TIMESTRETCH) CheckDlgButton(hW, IDC_TIMESTRETCH, TRUE); - if( conf.options & OPTION_MUTE) CheckDlgButton(hW, IDC_MUTESOUND, TRUE); - if( conf.options & OPTION_RECORDING) CheckDlgButton(hW, IDC_SNDRECORDING, TRUE); + if (conf.Log) CheckDlgButton(hW, IDC_LOGGING, TRUE); + if( conf.options & OPTION_REALTIME) + CheckDlgButton(hW, IDC_REALTIME, TRUE); + if( conf.options & OPTION_TIMESTRETCH) + CheckDlgButton(hW, IDC_TIMESTRETCH, TRUE); + if( conf.options & OPTION_MUTE) + CheckDlgButton(hW, IDC_MUTESOUND, TRUE); + if( conf.options & OPTION_RECORDING) + CheckDlgButton(hW, IDC_SNDRECORDING, TRUE); return TRUE; case WM_COMMAND: - switch(LOWORD(wParam)) { + switch(LOWORD(wParam)) + { case IDCANCEL: EndDialog(hW, TRUE); return TRUE; case IDOK: - conf.options = 0; + conf.options = 0; if (IsDlgButtonChecked(hW, IDC_LOGGING)) conf.Log = 1; - else conf.Log = 0; -// if( IsDlgButtonChecked(hW, IDC_FFXHACK) ) -// conf.options |= OPTION_FFXHACK; - if( IsDlgButtonChecked(hW, IDC_REALTIME) ) - conf.options |= OPTION_REALTIME; - if( IsDlgButtonChecked(hW, IDC_TIMESTRETCH) ) - conf.options |= OPTION_TIMESTRETCH; - if( IsDlgButtonChecked(hW, IDC_MUTESOUND) ) - conf.options |= OPTION_MUTE; - if( IsDlgButtonChecked(hW, IDC_SNDRECORDING) ) - conf.options |= OPTION_RECORDING; + else + conf.Log = 0; + + if (IsDlgButtonChecked(hW, IDC_REALTIME)) + conf.options |= OPTION_REALTIME; + if (IsDlgButtonChecked(hW, IDC_TIMESTRETCH)) + conf.options |= OPTION_TIMESTRETCH; + if (IsDlgButtonChecked(hW, IDC_MUTESOUND)) + conf.options |= OPTION_MUTE; + if (IsDlgButtonChecked(hW, IDC_SNDRECORDING)) + conf.options |= OPTION_RECORDING; + SaveConfig(); EndDialog(hW, FALSE); return TRUE; @@ -255,13 +89,16 @@ BOOL CALLBACK ConfigureDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) return FALSE; } -BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { - switch(uMsg) { +BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { case WM_INITDIALOG: return TRUE; case WM_COMMAND: - switch(LOWORD(wParam)) { + switch(LOWORD(wParam)) + { case IDOK: EndDialog(hW, FALSE); return TRUE; @@ -270,31 +107,26 @@ BOOL CALLBACK AboutDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam) { return FALSE; } -void CALLBACK SPU2configure() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_CONFIG), - GetActiveWindow(), - (DLGPROC)ConfigureDlgProc); +void CALLBACK SPU2configure() +{ + DialogBox(hInst, MAKEINTRESOURCE(IDD_CONFIG), GetActiveWindow(), (DLGPROC)ConfigureDlgProc); } -void CALLBACK SPU2about() { - DialogBox(hInst, - MAKEINTRESOURCE(IDD_ABOUT), - GetActiveWindow(), - (DLGPROC)AboutDlgProc); +void CALLBACK SPU2about() +{ + DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUT), GetActiveWindow(), (DLGPROC)AboutDlgProc); } -BOOL APIENTRY DllMain(HANDLE hModule, // DLL INIT - DWORD dwReason, - LPVOID lpReserved) { + // DLL INIT +BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) +{ hInst = (HINSTANCE)hModule; return TRUE; // very quick :) } -extern HINSTANCE hInst; void SaveConfig() { - Config *Conf1 = &conf; + Config *Conf1 = &conf; char *szTemp; char szIniFile[256], szValue[256]; @@ -306,18 +138,17 @@ void SaveConfig() strcat_s(szIniFile, "\\inis\\zerospu2.ini"); sprintf_s(szValue,"%u",Conf1->Log); - WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); - sprintf_s(szValue,"%u",Conf1->options); - WritePrivateProfileString("Interface", "Options",szValue,szIniFile); + WritePrivateProfileString("Interface", "Logging",szValue,szIniFile); + sprintf_s(szValue,"%u",Conf1->options); + WritePrivateProfileString("Interface", "Options",szValue,szIniFile); } void LoadConfig() { - FILE *fp; - Config *Conf1 = &conf; + FILE *fp; + Config *Conf1 = &conf; char *szTemp; char szIniFile[256], szValue[256]; - int err; GetModuleFileName(GetModuleHandle((LPCSTR)hInst), szIniFile, 256); szTemp = strrchr(szIniFile, '\\'); @@ -326,22 +157,24 @@ void LoadConfig() szTemp[0] = 0; strcat_s(szIniFile, "\\inis\\zerospu2.ini"); - fopen_s(&fp, "inis\\zerospu2.ini","rt");//check if zerospu2.ini really exists + fopen_s(&fp, "inis\\zerospu2.ini","rt");//check if zerospu2.ini really exists + if (!fp) { CreateDirectory("inis",NULL); - memset(&conf, 0, sizeof(conf)); - conf.Log = 0;//default value - conf.options = OPTION_TIMESTRETCH; + memset(&conf, 0, sizeof(conf)); + conf.Log = 0;//default value + conf.options = OPTION_TIMESTRETCH; SaveConfig();//save and return return ; } fclose(fp); + GetPrivateProfileString("Interface", "Logging", NULL, szValue, 20, szIniFile); Conf1->Log = strtoul(szValue, NULL, 10); - GetPrivateProfileString("Interface", "Options", NULL, szValue, 20, szIniFile); - Conf1->options = strtoul(szValue, NULL, 10); - return ; + GetPrivateProfileString("Interface", "Options", NULL, szValue, 20, szIniFile); + Conf1->options = strtoul(szValue, NULL, 10); + return; } diff --git a/plugins/zerospu2/ZeroSPU2_2008.vcproj b/plugins/zerospu2/ZeroSPU2_2008.vcproj index 2de7ce3b5d..fc9a19640a 100644 --- a/plugins/zerospu2/ZeroSPU2_2008.vcproj +++ b/plugins/zerospu2/ZeroSPU2_2008.vcproj @@ -192,6 +192,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -214,6 +218,14 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + + diff --git a/plugins/zerospu2/build.sh b/plugins/zerospu2/build.sh index 39a9ef1384..08f40d2922 100644 --- a/plugins/zerospu2/build.sh +++ b/plugins/zerospu2/build.sh @@ -12,7 +12,7 @@ then aclocal automake -a autoconf -./configure --prefix=${PCSX2PLUGINS} +./configure --enable-debug-build --prefix=${PCSX2PLUGINS} make clean make install diff --git a/plugins/zerospu2/configure.ac b/plugins/zerospu2/configure.ac index 6f071d48d3..235f23e5c7 100644 --- a/plugins/zerospu2/configure.ac +++ b/plugins/zerospu2/configure.ac @@ -35,14 +35,14 @@ AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [debug build]), if test "x$debug" == xyes then AC_DEFINE(_DEBUG,1,[_DEBUG]) - CFLAGS+="-g -fPIC " - CPPFLAGS+="-g -fPIC " - CXXFLAGS+="-g -fPIC " + 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 " - CPPFLAGS+="-O3 -fomit-frame-pointer -fPIC " - CXXFLAGS+="-O3 -fomit-frame-pointer -fPIC " + 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) diff --git a/plugins/zerospu2/dsound51.cpp b/plugins/zerospu2/dsound51.cpp new file mode 100644 index 0000000000..c852add397 --- /dev/null +++ b/plugins/zerospu2/dsound51.cpp @@ -0,0 +1,248 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 +#include +#include +#include "zerospu2.h" +///////////////////////////////////// +// use DirectSound for the sound +#include + +//4*48*73 +#define SOUNDSIZE 76800 +HWND hWMain; + +LPDIRECTSOUND lpDS; +LPDIRECTSOUNDBUFFER lpDSBPRIMARY = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY1 = NULL; +LPDIRECTSOUNDBUFFER lpDSBSECONDARY2 = NULL; +DSBUFFERDESC dsbd; +DSBUFFERDESC dsbdesc; +DSCAPS dscaps; +DSBCAPS dsbcaps; + +unsigned long LastWrite = 0xffffffff; +unsigned long LastWriteS = 0xffffffff; +unsigned long LastPlay = 0; + +int SetupSound() +{ + HRESULT dsval; + WAVEFORMATEX pcmwf; + + dsval = DirectSoundCreate(NULL,&lpDS,NULL); + if(dsval != DS_OK) + { + MessageBox(NULL,"DirectSoundCreate!","Error",MB_OK); + return -1; + } + + if(DS_OK != IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_PRIORITY)) + { + if(DS_OK != IDirectSound_SetCooperativeLevel(lpDS,hWMain, DSSCL_NORMAL)) + { + MessageBox(NULL,"SetCooperativeLevel!","Error",MB_OK); + return -1; + } + } + + memset(&dsbd,0,sizeof(DSBUFFERDESC)); + dsbd.dwSize = sizeof(DSBUFFERDESC); // NT4 hack! sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = NULL; + + dsval = IDirectSound_CreateSoundBuffer(lpDS,&dsbd,&lpDSBPRIMARY,NULL); + if(dsval != DS_OK) + { + MessageBox(NULL, "CreateSoundBuffer (Primary)", "Error",MB_OK); + return -1; + } + + memset(&pcmwf, 0, sizeof(WAVEFORMATEX)); + pcmwf.wFormatTag = WAVE_FORMAT_PCM; + + pcmwf.nChannels = 2; + pcmwf.nBlockAlign = 4; + + pcmwf.nSamplesPerSec = SAMPLE_RATE; + + pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; + pcmwf.wBitsPerSample = 16; + + dsval = IDirectSoundBuffer_SetFormat(lpDSBPRIMARY,&pcmwf); + if(dsval != DS_OK) + { + MessageBox(NULL, "SetFormat!", "Error",MB_OK); + return -1; + } + + dscaps.dwSize = sizeof(DSCAPS); + dsbcaps.dwSize = sizeof(DSBCAPS); + IDirectSound_GetCaps(lpDS,&dscaps); + IDirectSoundBuffer_GetCaps(lpDSBPRIMARY,&dsbcaps); + + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); + // NT4 hack! sizeof(DSBUFFERDESC); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_LOCHARDWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsbdesc.dwBufferBytes = SOUNDSIZE; + dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; + + dsval = IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval != DS_OK) + { + dsbdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsval = IDirectSound_CreateSoundBuffer(lpDS,&dsbdesc,&lpDSBSECONDARY1,NULL); + if(dsval != DS_OK) + { + MessageBox(NULL,"CreateSoundBuffer (Secondary1)", "Error",MB_OK); + return -1; + } + } + + dsval = IDirectSoundBuffer_Play(lpDSBPRIMARY,0,0,DSBPLAY_LOOPING); + if(dsval != DS_OK) + { + MessageBox(NULL,"Play (Primary)","Error",MB_OK); + return -1; + } + + dsval = IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); + if(dsval != DS_OK) + { + MessageBox(NULL,"Play (Secondary1)","Error",MB_OK); + return -1; + } + + // init some play vars + LastWrite = 0x00000000; + LastPlay = 0; + + return 0; +} + +void RemoveSound() +{ + int iRes; + + if (lpDSBSECONDARY1 != NULL) + { + IDirectSoundBuffer_Stop(lpDSBSECONDARY1); + iRes = IDirectSoundBuffer_Release(lpDSBSECONDARY1); + + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes = IDirectSoundBuffer_Release(lpDSBSECONDARY1); + + lpDSBSECONDARY1 = NULL; + } + + if (lpDSBPRIMARY != NULL) + { + IDirectSoundBuffer_Stop(lpDSBPRIMARY); + iRes = IDirectSoundBuffer_Release(lpDSBPRIMARY); + + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes = IDirectSoundBuffer_Release(lpDSBPRIMARY); + + lpDSBPRIMARY = NULL; + } + + if (lpDS!=NULL) + { + iRes = IDirectSound_Release(lpDS); + + // FF says such a loop is bad... Demo says it's good... Pete doesn't care + while(iRes!=0) iRes = IDirectSound_Release(lpDS); + + lpDS = NULL; + } + +} + +int SoundGetBytesBuffered() +{ + unsigned long cplay,cwrite; + + if (LastWrite == 0xffffffff) return 0; + + IDirectSoundBuffer_GetCurrentPosition(lpDSBSECONDARY1,&cplay,&cwrite); + + if(cplay > SOUNDSIZE) return SOUNDSIZE; + if(cplay < LastWrite) return LastWrite - cplay; + + return (SOUNDSIZE - cplay) + LastWrite; +} + +void SoundFeedVoiceData(unsigned char* pSound,long lBytes) +{ + LPVOID lpvPtr1, lpvPtr2; + unsigned long dwBytes1,dwBytes2; + unsigned long *lpSS, *lpSD; + unsigned long dw,cplay,cwrite; + HRESULT hr; + unsigned long status; + + IDirectSoundBuffer_GetStatus(lpDSBSECONDARY1,&status); + if (status & DSBSTATUS_BUFFERLOST) + { + if (IDirectSoundBuffer_Restore(lpDSBSECONDARY1) != DS_OK) return; + IDirectSoundBuffer_Play(lpDSBSECONDARY1,0,0,DSBPLAY_LOOPING); + } + + IDirectSoundBuffer_GetCurrentPosition(lpDSBSECONDARY1,&cplay,&cwrite); + + if(LastWrite == 0xffffffff) LastWrite=cwrite; + + hr = IDirectSoundBuffer_Lock(lpDSBSECONDARY1,LastWrite,lBytes, + &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); + + if (hr != DS_OK) + { + LastWrite=0xffffffff; + return; + } + + lpSS = (unsigned long *)pSound; + lpSD = (unsigned long *)lpvPtr1; + dw = dwBytes1 >> 2; + + while(dw) + { + *lpSD++=*lpSS++; + dw--; + } + + if (lpvPtr2) + { + lpSD = (unsigned long *)lpvPtr2; + dw = dwBytes2 >> 2; + + while(dw) + { + *lpSD++ = *lpSS++; + dw--; + } + } + + IDirectSoundBuffer_Unlock(lpDSBSECONDARY1,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); + LastWrite += lBytes; + if(LastWrite >= SOUNDSIZE) LastWrite -= SOUNDSIZE; + LastPlay = cplay; +} \ No newline at end of file diff --git a/plugins/zerospu2/misc.h b/plugins/zerospu2/misc.h new file mode 100644 index 0000000000..17c3426b45 --- /dev/null +++ b/plugins/zerospu2/misc.h @@ -0,0 +1,147 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 + */ + + #ifdef __LINUX__ +#include +#include +#include // ftime(), struct timeb + +#define Sleep(ms) usleep(1000*ms) + +inline unsigned long timeGetTime() +{ +#ifdef _WIN32 + _timeb t; + _ftime(&t); +#else + timeb t; + ftime(&t); +#endif + + return (unsigned long)(t.time*1000+t.millitm); +} + +#include + +#else +#include +#include + +#include // ftime(), struct timeb +#endif + +inline u64 GetMicroTime() +{ +#ifdef _WIN32 + extern LARGE_INTEGER g_counterfreq; + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + return count.QuadPart * 1000000 / g_counterfreq.QuadPart; +#else + timeval t; + gettimeofday(&t, NULL); + return t.tv_sec*1000000+t.tv_usec; +#endif +} + +#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) + +#include + +// declare linux equivalents +static __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) +{ + assert( align < 0x10000 ); + char* p = (char*)malloc(size+align); + int off = 2+align - ((int)(uptr)(p+2) % align); + + p += off; + *(u16*)(p-2) = off; + + return p; +} + +static __forceinline void pcsx2_aligned_free(void* pmem) +{ + if( pmem != NULL ) { + char* p = (char*)pmem; + free(p - (int)*(u16*)(p-2)); + } +} + +#define _aligned_malloc pcsx2_aligned_malloc +#define _aligned_free pcsx2_aligned_free +#endif + +// Atomic Operations +#if defined (_WIN32) + +#ifndef __x86_64__ +extern "C" LONG __cdecl _InterlockedExchangeAdd(LPLONG volatile Addend, LONG Value); +#endif + +#pragma intrinsic (_InterlockedExchangeAdd) +#define InterlockedExchangeAdd _InterlockedExchangeAdd + +#else + +//typedef void* PVOID; + +static __forceinline long InterlockedExchange(volatile long* Target, long Value) +{ + long result; + /* + * The XCHG instruction always locks the bus with or without the + * LOCKED prefix. This makes it significantly slower than CMPXCHG on + * uni-processor machines. The Windows InterlockedExchange function + * is nearly 3 times faster than the XCHG instruction, so this routine + * is not yet very useful for speeding up pthreads. + */ + + __asm__ __volatile__ ( + "xchgl %2,%1" + :"=r" (result) + :"m" (*Target), "0" (Value)); + + return result; +} + +static __forceinline long InterlockedExchangeAdd(volatile long* Addend, long Value) +{ + __asm__ __volatile__( + ".intel_syntax\n" + "lock xadd [%0], %%eax\n" + ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory"); +} + +static __forceinline long InterlockedCompareExchange(volatile long *dest, long value, long comp) +{ + long result; + + __asm__ __volatile__ ( + "lock\n\t" + "cmpxchgl %2,%1" /* if (EAX == [location]) */ + /* [location] = value */ + /* else */ + /* EAX = [location] */ + :"=a" (result) + :"m" (*dest), "r" (value), "a" (comp)); + + return result; +} +#endif diff --git a/plugins/zerospu2/reg.h b/plugins/zerospu2/reg.h new file mode 100644 index 0000000000..27f5931fc7 --- /dev/null +++ b/plugins/zerospu2/reg.h @@ -0,0 +1,182 @@ +/* ZeroSPU2 + * Copyright (C) 2006-2007 zerofrog + * + * 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 __REG_H__ +#define __REG_H__ + +//////////////////// +// SPU2 Registers // +//////////////////// +enum +{ +// Volume Registers - currently not implemented in ZeroSPU2, like most volume registers. + REG_VP_VOLL = 0x0000, // Voice Volume Left + REG_VP_VOLR = 0x0002, // Voice Volume Right + REG_VP_PITCH = 0x0004, // Pitch + REG_VP_ADSR1 = 0x0006, // Envelope 1 (Attack-Decay-Sustain-Release) + REG_VP_ADSR2 = 0x0008, // Envelope 2 (Attack-Decay-Sustain-Release) + REG_VP_ENVX = 0x000A, // Current Envelope + REG_VP_VOLXL = 0x000C, // Current Voice Volume Left + REG_VP_VOLXR = 0x000E, // Current Voice Volume Right +// end unimplemented section + + REG_C0_FMOD1 = 0x0180, // Pitch Modulation Spec. + REG_C0_FMOD2 = 0x0182, + REG_S_NON = 0x0184, // Alloc Noise Generator - unimplemented + REG_C0_VMIXL1 = 0x0188, // Voice Output Mix Left (Dry) + REG_C0_VMIXL2 = 0x018A, + REG_S_VMIXEL = 0x018C, // Voice Output Mix Left (Wet) - unimplemented + REG_C0_VMIXR1 = 0x0190, // Voice Output Mix Right (Dry) + REG_C0_VMIXR2 = 0x0192, + REG_S_VMIXER = 0x0194, // Voice Output Mix Right (Wet) - unimplemented + + REG_C0_MMIX = 0x0198, // Output Spec. After Voice Mix + REG_C0_CTRL = 0x019A, // Core X Attrib + REG_C0_IRQA_HI = 0x019C, // Interrupt Address Spec. - Hi + REG_C0_IRQA_LO = 0x019E, // Interrupt Address Spec. - Lo + + REG_C0_SPUON1 = 0x01A0, // Key On 0/1 + REG_C0_SPUON2 = 0x01A2, + REG_C0_SPUOFF1 = 0x01A4, // Key Off 0/1 + REG_C0_SPUOFF2 = 0x01A6, + + REG_C0_SPUADDR_HI = 0x01A8, // Transfer starting address - hi + REG_C0_SPUADDR_LO = 0x01AA, // Transfer starting address - lo + REG_C0_SPUDATA = 0x01AC, // Transfer data + REG_C0_DMACTRL = 0x01AE, // unimplemented + REG_C0_ADMAS = 0x01B0, // AutoDMA Status + + // Section Unimplemented + // Actually, some are implemented but weren't using the constants. + REG_VA_SSA = 0x01C0, // Waveform data starting address + REG_VA_LSAX = 0x01C4, // Loop point address + REG_VA_NAX = 0x01C8, // Waveform data that should be read next + REG_A_ESA = 0x02E0, //Address: Top address of working area for effects processing + R_FB_SRC_A = 0x02E4, // Feedback Source A + R_FB_SRC_B = 0x02E8, // Feedback Source B +R_IIR_DEST_A0 = 0x02EC, +R_IIR_DEST_A1 = 0x02F0, +R_ACC_SRC_A0 = 0x02F4, +R_ACC_SRC_A1 = 0x02F8, +R_ACC_SRC_B0 = 0x02FC, +R_ACC_SRC_B1 = 0x0300, +R_IIR_SRC_A0 = 0x0304, +R_IIR_SRC_A1 = 0x0308, +R_IIR_DEST_B0 = 0x030C, +R_IIR_DEST_B1 = 0x0310, +R_ACC_SRC_C0 = 0x0314, +R_ACC_SRC_C1 = 0x0318, +R_ACC_SRC_D0 = 0x031C, +R_ACC_SRC_D1 = 0x0320, +R_IIR_SRC_B1 = 0x0324, +R_IIR_SRC_B0 = 0x0328, +R_MIX_DEST_A0 = 0x032C, +R_MIX_DEST_A1 = 0x0330, +R_MIX_DEST_B0 = 0x0334, +R_MIX_DEST_B1 = 0x0338, + REG_A_EEA = 0x033C, // Address: End address of working area for effects processing (upper part of address only!) + // end unimplemented section + + REG_C0_END1 = 0x0340, // End Point passed flag + REG_C0_END2 = 0x0342, + REG_C0_SPUSTAT = 0x0344, // Status register? + + // core 1 has the same registers with 0x400 added, and ends at 0x746. + REG_C1_FMOD1 = 0x0580, + REG_C1_FMOD2 = 0x0582, + REG_C1_VMIXL1 = 0x0588, + REG_C1_VMIXL2 = 0x058A, + REG_C1_VMIXR1 = 0x0590, + REG_C1_VMIXR2 = 0x0592, + REG_C1_MMIX = 0x0598, + REG_C1_CTRL = 0x059A, + REG_C1_IRQA_HI = 0x059C, + REG_C1_IRQA_LO = 0x059E, + REG_C1_SPUON1 = 0x05A0, + REG_C1_SPUON2 = 0x05A2, + REG_C1_SPUOFF1 = 0x05A4, + REG_C1_SPUOFF2 = 0x05A6, + REG_C1_SPUADDR_HI = 0x05A8, + REG_C1_SPUADDR_LO = 0x05AA, + REG_C1_SPUDATA = 0x05AC, + REG_C1_DMACTRL = 0x05AE, // unimplemented + REG_C1_ADMAS = 0x05B0, + REG_C1_END1 = 0x0740, + REG_C1_END2 = 0x0742, + REG_C1_SPUSTAT = 0x0744, + + // Interesting to note that *most* of the volume controls aren't implemented in Zerospu2. + REG_P_MVOLL = 0x0760, // Master Volume Left - unimplemented + REG_P_MVOLR = 0x0762, // Master Volume Right - unimplemented + REG_P_EVOLL = 0x0764, // Effect Volume Left - unimplemented + REG_P_EVOLR = 0x0766, // Effect Volume Right - unimplemented + REG_P_AVOLL = 0x0768, // Core External Input Volume Left (Only Core 1) - unimplemented + REG_P_AVOLR = 0x076A, // Core External Input Volume Right (Only Core 1) - unimplemented + REG_C0_BVOLL = 0x076C, // Sound Data Volume Left + REG_C0_BVOLR = 0x076E, // Sound Data Volume Right + REG_P_MVOLXL = 0x0770, // Current Master Volume Left - unimplemented + REG_P_MVOLXR = 0x0772, // Current Master Volume Right - unimplemented + + // Another unimplemented section + R_IIR_ALPHA = 0x0774, // IIR alpha (% used) + R_ACC_COEF_A = 0x0776, + R_ACC_COEF_B = 0x0778, + R_ACC_COEF_C = 0x077A, + R_ACC_COEF_D = 0x077C, + R_IIR_COEF = 0x077E, + R_FB_ALPHA = 0x0780, // feedback alpha (% used) + R_FB_X = 0x0782, // feedback + R_IN_COEF_L = 0x0784, + R_IN_COEF_R = 0x0786, + // end unimplemented section + + REG_C1_BVOLL = 0x0794, + REG_C1_BVOLR = 0x0796, + + SPDIF_OUT = 0x07C0, // SPDIF Out: OFF/'PCM'/Bitstream/Bypass - unimplemented + REG_IRQINFO = 0x07C2, + SPDIF_MODE = 0x07C6, // unimplemented + SPDIF_MEDIA = 0x07C8, // SPDIF Media: 'CD'/DVD - unimplemented + SPDIF_COPY_PROT = 0x07CC // SPDIF Copy Protection - unimplemented + // NOTE: SPDIF_COPY is defined in Linux kernel headers as 0x0004. +}; + +// These SPDIF defines aren't used yet - swiped from spu2ghz, like a number of the registers I added in. +// -- arcum42 +#define SPDIF_OUT_OFF 0x0000 //no spdif output +#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output +#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing + +#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data +#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output) + +#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD +#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD + +#define SPDIF_MEDIA_CDVD 0x0200 +#define SPDIF_MEDIA_400 0x0000 + +#define SPDIF_COPY_NORMAL 0x0000 // spdif stream is not protected +#define SPDIF_COPY_PROHIBIT 0x8000 // spdif stream can't be copied + +#define SPU_AUTODMA_ONESHOT 0 //spu2 +#define SPU_AUTODMA_LOOP 1 //spu2 +#define SPU_AUTODMA_START_ADDR (1 << 1) //spu2 + +#endif \ No newline at end of file diff --git a/plugins/zerospu2/voices.cpp b/plugins/zerospu2/voices.cpp index 6d2c16192c..2805b1f70b 100644 --- a/plugins/zerospu2/voices.cpp +++ b/plugins/zerospu2/voices.cpp @@ -201,10 +201,7 @@ int VOICE_PROCESSED::iGetNoiseVal() // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val fa=iOldNoise + ((fa - iOldNoise) / ((0x001f - (GetCtrl()->noiseFreq)) + 1)); - if (fa > 32767L) - fa = 32767L; - if (fa < -32767L) - fa = -32767L; + clamp16(fa); iOldNoise=fa; SB[29] = fa; // -> store noise val in "current sample" slot @@ -221,10 +218,7 @@ void VOICE_PROCESSED::StoreInterpolationVal(int fa) fa=0; // muted? else // else adjust { - if (fa >32767L) - fa = 32767L; - if (fa < -32767L) - fa = -32767L; + clamp16(fa); } SB[28] = 0; diff --git a/plugins/zerospu2/zerodma.cpp b/plugins/zerospu2/zerodma.cpp index d7f75d44c3..d35451ade2 100644 --- a/plugins/zerospu2/zerodma.cpp +++ b/plugins/zerospu2/zerodma.cpp @@ -24,68 +24,59 @@ #include "SoundTouch/SoundTouch.h" #include "SoundTouch/WavFile.h" -void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size) +void CALLBACK SPU2readDMAMem(u16 *pMem, int size, int core) { - u32 spuaddr = C0_SPUADDR(); - int i; - - SPU2_LOG("SPU2 readDMA4Mem size %x, addr: %x\n", size, pMem); - - for (i=0;i0x0fffff) spuaddr=0; // wrap at 2Mb + if (spuaddr > 0x0fffff) spuaddr=0; // wrap at 2Mb } - spuaddr+=19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) - C0_SPUADDR_SET(spuaddr); + spuaddr += 19; //Transfer Local To Host TSAH/L + Data Size + 20 (already +1'd) + C_SPUADDR_SET(spuaddr, core); - // 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); + // DMA complete + spu2Ru16(REG_C0_SPUSTAT + offset) &= ~0x80; + SPUStartCycle[core] = SPUCycles; + SPUTargetCycle[core] = size; + interrupt |= (1 << (1 + core)); +} + +void CALLBACK SPU2readDMA4Mem(u16 *pMem, int size) +{ + return SPU2readDMAMem(pMem, size, 0); } void CALLBACK 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;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); + return SPU2readDMAMem(pMem, size, 1); } // WRITE @@ -96,49 +87,65 @@ void CALLBACK SPU2readDMA7Mem(u16* pMem, int size) // 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() + +int ADMASWrite(int core) { u32 spuaddr; - ADMA *Adma = &Adma4; + ADMA *Adma; + int dma, offset; + + if (core == 0) + { + Adma = &Adma4; + dma = 4; + offset = 0; + } + else + { + Adma = &Adma7; + dma = 7; + offset = 0x0400; + } + if (interrupt & 0x2) { - printf("4 returning for interrupt\n"); + printf("%d returning for interrupt\n", dma); return 0; } if (Adma->AmountLeft <= 0) { - printf("4 amount left is 0\n"); + printf("%d amount left is 0\n", dma); return 1; } assert( Adma->AmountLeft >= 512 ); - spuaddr = C0_SPUADDR(); + spuaddr = C_SPUADDR(core); // SPU2 Deinterleaves the Left and Right Channels - memcpy((short*)(spu2mem + spuaddr + 0x2000),(short*)Adma->MemAddr,512); + memcpy((s16*)(spu2mem + spuaddr + 0x2000 + offset),(s16*)Adma->MemAddr,512); Adma->MemAddr += 256; - memcpy((short*)(spu2mem + spuaddr + 0x2200),(short*)Adma->MemAddr,512); + memcpy((s16*)(spu2mem + spuaddr + 0x2200 + offset),(s16*)Adma->MemAddr,512); Adma->MemAddr += 256; - if ((spu2Ru16(REG_C0_CTRL)&0x40) && ((spuaddr + 0x2400) <= C0_IRQA() && (spuaddr + 0x2400 + 256) >= C0_IRQA())) + if ((spu2Ru16(REG_C0_CTRL + offset) & 0x40) && ((spuaddr + 0x2400) <= C_IRQA(core) && (spuaddr + 0x2400 + 256) >= C_IRQA(core))) { - IRQINFO |= 4; - printf("ADMA 4 Mem access:interrupt\n"); + IRQINFO |= (4 * (core + 1)); + printf("ADMA %d Mem access:interrupt\n", dma); irqCallbackSPU2(); } - if ((spu2Ru16(REG_C0_CTRL)&0x40) && ((spuaddr + 0x2600) <= C0_IRQA() && (spuaddr + 0x2600 + 256) >= C0_IRQA())) + if ((spu2Ru16(REG_C0_CTRL + offset) & 0x40) && ((spuaddr + 0x2600) <= C_IRQA(core) && (spuaddr + 0x2600 + 256) >= C_IRQA(core))) { - IRQINFO |= 4; - printf("ADMA 4 Mem access:interrupt\n"); + IRQINFO |= (4 * (core + 1)); + printf("ADMA %d Mem access:interrupt\n", dma); irqCallbackSPU2(); } spuaddr = (spuaddr + 256) & 511; - C0_SPUADDR_SET(spuaddr); + C_SPUADDR_SET(spuaddr, core); - Adma->AmountLeft-=512; + Adma->AmountLeft -= 512; if (Adma->AmountLeft > 0) return 0; @@ -146,134 +153,43 @@ int ADMAS4Write() return 1; } -int ADMAS7Write() +void CALLBACK SPU2writeDMAMem(u16* pMem, int size, int core) { u32 spuaddr; - ADMA *Adma = &Adma7; + ADMA *Adma; + int dma, offset; - if (interrupt & 0x4) + if (core == 0) { - printf("7 returning for interrupt\n"); - return 0; + Adma = &Adma4; + dma = 4; + offset = 0; } - if (Adma->AmountLeft <= 0) + else { - printf("7 amount left is 0\n"); - return 1; + Adma = &Adma7; + dma = 7; + offset = 0x0400; } - assert( Adma->AmountLeft >= 512 ); - spuaddr = C1_SPUADDR(); - - // SPU2 Deinterleaves the Left and Right Channels - memcpy((short*)(spu2mem + spuaddr + 0x2400),(short*)Adma->MemAddr,512); - Adma->MemAddr += 256; - - memcpy((short*)(spu2mem + spuaddr + 0x2600),(short*)Adma->MemAddr,512); - Adma->MemAddr += 256; - - if ((spu2Ru16(REG_C1_CTRL)&0x40) && ((spuaddr + 0x2400) <= C1_IRQA() && (spuaddr + 0x2400 + 256) >= C1_IRQA())) - { - IRQINFO |= 8; - printf("ADMA 7 Mem access:interrupt\n"); - irqCallbackSPU2(); - } - - if ((spu2Ru16(REG_C1_CTRL)&0x40) && ((spuaddr + 0x2600) <= C1_IRQA() && (spuaddr + 0x2600 + 256) >= C1_IRQA())) - { - IRQINFO |= 8; - printf("ADMA 7 Mem access:interrupt\n"); - irqCallbackSPU2(); - } - - spuaddr = (spuaddr + 256) & 511; - C1_SPUADDR_SET(spuaddr); - - Adma->AmountLeft-=512; - - assert( Adma->AmountLeft >= 0 ); + SPU2_LOG("SPU2 writeDMA%dMem size %x, addr: %x(spu2:%x), ctrl: %x, adma: %x\n", \ + dma, size, pMem, C_SPUADDR(core), spu2Ru16(REG_C0_CTRL + offset), spu2Ru16(REG_C0_ADMAS + offset)); - if (Adma->AmountLeft > 0) - return 0; - else - return 1; -} - -void CALLBACK SPU2writeDMA4Mem(u16* pMem, int size) -{ - u32 spuaddr; - ADMA *Adma = &Adma4; - - SPU2_LOG("SPU2 writeDMA4Mem size %x, addr: %x(spu2:%x), ctrl: %x, adma: %x\n", size, pMem, C0_SPUADDR(), spu2Ru16(REG_C0_CTRL), spu2Ru16(REG_C0_ADMAS)); - - if ((spu2Ru16(REG_C0_ADMAS) & 0x1) && (spu2Ru16(REG_C0_CTRL) & 0x30) == 0 && size) - { - // if still active, don't destroy adma4 - if ( !Adma->Enabled ) - Adma->Index = 0; - - Adma->MemAddr = pMem; - Adma->AmountLeft = size; - SPUTargetCycle[0] = size; - spu2Ru16(REG_C0_SPUSTAT)&=~0x80; - if (!Adma->Enabled || Adma->Index > 384) - { - C0_SPUADDR_SET(0); - if (ADMAS4Write()) - { - SPUStartCycle[0] = SPUCycles; - interrupt |= (1<<1); - } - } - Adma->Enabled = 1; - 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) && (spuaddr < C0_IRQA() && C0_IRQA() <= spuaddr+0x20)) - { - IRQINFO |= 4; - SPU2_LOG("SPU2writeDMA4Mem:interrupt\n"); - irqCallbackSPU2(); - } - - if (spuaddr>0xFFFFE) - spuaddr = 0x2800; - C0_SPUADDR_SET(spuaddr); - - MemAddr[0] += size<<1; - spu2Ru16(REG_C0_SPUSTAT)&=~0x80; - SPUStartCycle[0] = SPUCycles; - SPUTargetCycle[0] = size; - interrupt |= (1<<1); -} - -void CALLBACK SPU2writeDMA7Mem(u16* pMem, int size) -{ - u32 spuaddr; - ADMA *Adma = &Adma7; - - SPU2_LOG("SPU2 writeDMA7Mem size %x, addr: %x(spu2:%x), ctrl: %x, adma: %x\n", size, pMem, C1_SPUADDR(), spu2Ru16(REG_C1_CTRL), spu2Ru16(REG_C1_ADMAS)); - - if ((spu2Ru16(REG_C1_ADMAS) & 0x2) && (spu2Ru16(REG_C1_CTRL) & 0x30) == 0 && size) + if ((spu2Ru16(REG_C0_ADMAS + offset) & 0x1 * (core + 1)) && ((spu2Ru16(REG_C0_CTRL + offset) & 0x30) == 0) && size) { if (!Adma->Enabled ) Adma->Index = 0; Adma->MemAddr = pMem; Adma->AmountLeft = size; - SPUTargetCycle[1] = size; - spu2Ru16(REG_C1_SPUSTAT)&=~0x80; - if (!Adma->Enabled || Adma->Index > 384) + SPUTargetCycle[core] = size; + spu2Ru16(REG_C0_SPUSTAT + offset) &= ~0x80; + if (!Adma->Enabled || (Adma->Index > 384)) { - C1_SPUADDR_SET(0); - if (ADMAS7Write()) + C_SPUADDR_SET(0, core); + if (ADMASWrite(core)) { - SPUStartCycle[1] = SPUCycles; - interrupt |= (1<<2); + SPUStartCycle[core] = SPUCycles; + interrupt |= (1 << (1 + core)); } } Adma->Enabled = 1; @@ -282,42 +198,68 @@ void CALLBACK SPU2writeDMA7Mem(u16* pMem, int size) } #ifdef _DEBUG - if (conf.Log && conf.options & OPTION_RECORDING) + if ((conf.Log && conf.options & OPTION_RECORDING) && (core == 1)) LogPacketSound(pMem, 0x8000); #endif - spuaddr = C1_SPUADDR(); - memcpy((unsigned char*)(spu2mem + spuaddr),(unsigned char*)pMem,size<<1); + spuaddr = C_SPUADDR(core); + memcpy((u8*)(spu2mem + spuaddr),(u8*)pMem,size << 1); spuaddr += size; - C1_SPUADDR_SET(spuaddr); + C_SPUADDR_SET(spuaddr, core); - if ((spu2Ru16(REG_C1_CTRL)&0x40) && (spuaddr < C1_IRQA() && C1_IRQA() <= spuaddr+0x20)) + if ((spu2Ru16(REG_C0_CTRL + offset)&0x40) && (spuaddr < C_IRQA(core) && (C_IRQA(core) <= (spuaddr+0x20)))) { - IRQINFO |= 8; - SPU2_LOG("SPU2writeDMA7Mem:interrupt\n"); + IRQINFO |= 4 * (core + 1); + SPU2_LOG("SPU2writeDMA%dMem:interrupt\n", dma); irqCallbackSPU2(); } - if (spuaddr>0xFFFFE) spuaddr = 0x2800; - C1_SPUADDR_SET(spuaddr); + if (spuaddr > 0xFFFFE) spuaddr = 0x2800; + C_SPUADDR_SET(spuaddr, core); - MemAddr[1] += size<<1; - spu2Ru16(REG_C1_SPUSTAT)&=~0x80; - SPUStartCycle[1] = SPUCycles; - SPUTargetCycle[1] = size; - interrupt |= (1<<2); + MemAddr[core] += size << 1; + spu2Ru16(REG_C0_SPUSTAT + offset) &= ~0x80; + SPUStartCycle[core] = SPUCycles; + SPUTargetCycle[core] = size; + interrupt |= (1 << (core + 1)); +} + +void CALLBACK SPU2writeDMA4Mem(u16* pMem, int size) +{ + SPU2writeDMAMem(pMem, size, 0); +} + +void CALLBACK SPU2writeDMA7Mem(u16* pMem, int size) +{ + SPU2writeDMAMem(pMem, size, 1); +} + +void CALLBACK SPU2interruptDMA(int core) +{ + int dma, offset; + + if (core == 0) + { + dma = 4; + offset = 0; + } + else + { + dma = 7; + offset = 0x0400; + } + + SPU2_LOG("SPU2 interruptDMA%d\n", dma); + spu2Rs16(REG_C0_CTRL + offset) &= ~0x30; + spu2Ru16(REG_C0_SPUSTAT + offset) |= 0x80; } void CALLBACK SPU2interruptDMA4() { - SPU2_LOG("SPU2 interruptDMA4\n"); - spu2Rs16(REG_C0_CTRL)&=~0x30; - spu2Ru16(REG_C0_SPUSTAT)|=0x80; + SPU2interruptDMA(0); } void CALLBACK SPU2interruptDMA7() { - SPU2_LOG("SPU2 interruptDMA7\n"); - spu2Rs16(REG_C1_CTRL)&=~0x30; - spu2Ru16(REG_C1_SPUSTAT)|=0x80; + SPU2interruptDMA(1); } \ No newline at end of file diff --git a/plugins/zerospu2/zerospu2.cpp b/plugins/zerospu2/zerospu2.cpp index d174738a54..12320eed18 100644 --- a/plugins/zerospu2/zerospu2.cpp +++ b/plugins/zerospu2/zerospu2.cpp @@ -65,18 +65,6 @@ pthread_t s_threadSPU2; void* SPU2ThreadProc(void*); #endif -struct AUDIOBUFFER -{ - u8* pbuf; - u32 len; - - // 1 if new channels started in this packet - // Variable used to smooth out sound by concentrating on new voices - u32 timestamp; // in microseconds, only used for time stretching - u32 avgtime; - int newchannels; -}; - static AUDIOBUFFER s_pAudioBuffers[NSPACKETS]; static int s_nCurBuffer = 0, s_nQueuedBuffers = 0; static s16* s_pCurOutput = NULL; @@ -98,8 +86,7 @@ int SPUTargetCycle[2]; int g_logsound=0; -int ADMAS4Write(); -int ADMAS7Write(); +int ADMASWrite(int c); void InitADSR(); @@ -220,7 +207,8 @@ s32 CALLBACK SPU2init() memset(spu2mem, 0, 0x200000); if ((spu2mem == NULL) || (spu2regs == NULL)) { - SysMessage("Error allocating Memory\n"); return -1; + SysMessage("Error allocating Memory\n"); + return -1; } memset(dwEndChannel2, 0, sizeof(dwEndChannel2)); @@ -360,11 +348,6 @@ void CALLBACK SPU2shutdown() if (spu2Log) fclose(spu2Log); } -// simulate SPU2 for 1ms -void SPU2Worker(); - -#define CYCLES_PER_MS (36864000/1000) - void CALLBACK SPU2async(u32 cycle) { SPUCycles += cycle; @@ -402,9 +385,9 @@ void CALLBACK SPU2async(u32 cycle) void InitADSR() // INIT ADSR { - unsigned long r,rs,rd; + u32 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) + memset(RateTable,0,sizeof(u32)*160); // build the rate table according to Neill's rules (see at bottom of file) r=3;rs=1;rd=0; @@ -529,12 +512,69 @@ int MixADSR(VOICE_PROCESSED* pvoice) // MIX ADSR return 0; } +void MixChannels(int core) +{ + // mix all channels + int c_offset = 0x0400 * core; + int dma; + ADMA *Adma; + + if (core == 0) + { + Adma = &Adma4; + dma = 4; + } + else + { + Adma = &Adma7; + dma = 7; + } + + if ((spu2Ru16(REG_C0_MMIX + c_offset) & 0xF0) && (spu2Ru16(REG_C0_ADMAS + c_offset) & (0x1 + core))) + { + for (int ns=0;nsIndex]*(int)spu2Ru16(REG_C0_BVOLL + c_offset))>>16; + if ((spu2Ru16(REG_C0_MMIX + c_offset) & 0x40)) + s_buffers[ns][1] += (((short*)spu2mem)[0x2200 + c_offset +Adma->Index]*(int)spu2Ru16(REG_C0_BVOLR + c_offset))>>16; + + Adma->Index +=1; + MemAddr[core] += 4; + + if (Adma->Index == 128 || Adma->Index == 384) + { + if (ADMASWrite(core)) + { + if (interrupt & (0x2 * (core + 1))) + { + interrupt &= ~(0x2 * (core + 1)); + printf("Stopping double interrupt DMA7\n"); + } + if (core == 0) + irqCallbackDMA4(); + else + irqCallbackDMA7(); + + } + if (core == 1) Adma->Enabled = 2; + } + + if (Adma->Index == 512) + { + if ( Adma->Enabled == 2 ) Adma->Enabled = 0; + Adma->Index = 0; + } + } + } +} + // simulate SPU2 for 1ms void SPU2Worker() { int s_1,s_2,fa; u8* start; - unsigned int nSample; + u32 nSample; int ch,predict_nr,shift_factor,flags,d,s; // assume s_buffers are zeroed out @@ -585,29 +625,29 @@ void SPU2Worker() s_1=pChannel->s_1; s_2=pChannel->s_2; - predict_nr=(int)start[0]; + predict_nr=(s32)start[0]; shift_factor=predict_nr&0xf; predict_nr >>= 4; - flags=(int)start[1]; + flags=(s32)start[1]; start += 2; for (nSample=0;nSample<28; ++start) { d = (int)*start; - s = ((d&0xf)<<12); - if (s&0x8000) s|=0xffff0000; + s = ((d & 0xf)<<12); + if (s & 0x8000) s |= 0xffff0000; fa = (s >> shift_factor); - fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + fa += ((s_1 * f[predict_nr][0]) >> 6) + ((s_2 * f[predict_nr][1]) >> 6); s_2 = s_1; s_1 = fa; s = ((d & 0xf0) << 8); pChannel->SB[nSample++]=fa; - if (s&0x8000) s|=0xffff0000; + if (s & 0x8000) s|=0xffff0000; fa = (s>>shift_factor); - fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1]) >> 6); s_2 = s_1; s_1 = fa; @@ -617,11 +657,11 @@ void SPU2Worker() // irq occurs no matter what core access the address for (int core = 0; core < 2; ++core) { - if (((SPU_CONTROL_*)(spu2regs+0x400*core+REG_C0_CTRL))->irq) // some callback and irq active? + if (((SPU_CONTROL_*)(spu2regs + 0x400 * core + REG_C0_CTRL))->irq) // some callback and irq active? { // if irq address reached or irq on looping addr, when stop/loop flag is set u8* pirq = (u8*)pSpuIrq[core]; - if ((pirq > start-16 && pirq <= start) || ((flags&1) && (pirq > pChannel->pLoop-16 && pirq <= pChannel->pLoop))) + if ((pirq > (start - 16) && pirq <= start) || ((flags & 1) && (pirq > (pChannel->pLoop - 16) && pirq <= pChannel->pLoop))) { IRQINFO |= 4<iGetInterpolationVal(); // get sample val - int sval = (MixADSR(pChannel)*fa)/1023; // mix adsr + int sval = (MixADSR(pChannel) * fa) / 1023; // mix adsr - if (pChannel->bFMod==2) // fmod freq channel + if (pChannel->bFMod == 2) // fmod freq channel { - iFMod[ns]=sval; // -> store 1T sample data, use that to do fmod on next channel + iFMod[ns] = sval; // -> store 1T sample data, use that to do fmod on next channel } else { if (pChannel->bVolumeL) - s_buffers[ns][0]+=(sval*pChannel->leftvol)>>14; + s_buffers[ns][0]+=(sval * pChannel->leftvol)>>14; if (pChannel->bVolumeR) - s_buffers[ns][1]+=(sval*pChannel->rightvol)>>14; + s_buffers[ns][1]+=(sval * pChannel->rightvol)>>14; } // go to the next packet @@ -690,107 +730,18 @@ ENDX: } // mix all channels - if ((spu2Ru16(REG_C0_MMIX) & 0xF0) && (spu2Ru16(REG_C0_ADMAS) & 0x1) /*&& !(spu2Ru16(REG_C0_CTRL) & 0x30)*/) - { - ADMA *Adma = &Adma4; - - for (int ns=0;nsIndex]*(int)spu2Ru16(REG_C0_BVOLL))>>16; - if ((spu2Ru16(REG_C0_MMIX) & 0x40)) - s_buffers[ns][1] += (((short*)spu2mem)[0x2200+Adma->Index]*(int)spu2Ru16(REG_C0_BVOLR))>>16; - - Adma->Index +=1; - // just add after every sample, it is better than adding 1024 all at once (games like Genji don't like it) - MemAddr[0] += 4; - - if ((Adma->Index == 128) || (Adma->Index == 384)) - { - if (ADMAS4Write()) - { - if (interrupt & 0x2) - { - interrupt &= ~0x2; - printf("Stopping double interrupt DMA4\n"); - } - irqCallbackDMA4(); - - } - } - - if (Adma->Index == 512) - { - if ( Adma->Enabled == 2 ) - { - Adma->Enabled = 0; - } - Adma->Index = 0; - } - } - } - - // Let's do the same bloody mixing code again, only for C1. - // fixme - There is way too much duplication of code between C0 & C1, and Adma4 & Adma7. - // arcum42 - if ((spu2Ru16(REG_C1_MMIX) & 0xF0) && (spu2Ru16(REG_C1_ADMAS) & 0x2)) - { - ADMA *Adma = &Adma7; - - for (int ns=0;nsIndex]*(int)spu2Ru16(REG_C1_BVOLL))>>16; - if ((spu2Ru16(REG_C1_MMIX) & 0x40)) - s_buffers[ns][1] += (((short*)spu2mem)[0x2600+Adma->Index]*(int)spu2Ru16(REG_C1_BVOLR))>>16; - - Adma->Index +=1; - MemAddr[1] += 4; - - if (Adma->Index == 128 || Adma->Index == 384) - { - if (ADMAS7Write()) - { - if (interrupt & 0x4) - { - interrupt &= ~0x4; - printf("Stopping double interrupt DMA7\n"); - } - irqCallbackDMA7(); - - } - Adma->Enabled = 2; - } - - if (Adma->Index == 512) - { - if ( Adma->Enabled == 2 ) Adma->Enabled = 0; - Adma->Index = 0; - } - } - } - + MixChannels(0); + MixChannels(1); + if ( g_bPlaySound ) { assert( s_pCurOutput != NULL); - for (int ns=0;ns 32767 ) - s_pCurOutput[0] = 32767; - else - s_pCurOutput[0] = (s16)s_buffers[ns][0]; - - if ( s_buffers[ns][1] < -32767 ) - s_pCurOutput[1] = -32767; - else if ( s_buffers[ns][1] > 32767 ) - s_pCurOutput[1] = 32767; - else - s_pCurOutput[1] = (s16)s_buffers[ns][1]; + clampandwrite16(s_pCurOutput[0],s_buffers[ns][0]); + clampandwrite16(s_pCurOutput[1],s_buffers[ns][1]); s_pCurOutput += 2; s_buffers[ns][0] = 0; @@ -803,7 +754,7 @@ ENDX: if ( conf.options & OPTION_RECORDING ) { - static int lastrectime=0; + static int lastrectime = 0; if (timeGetTime() - lastrectime > 5000) { printf("ZeroSPU2: recording\n"); @@ -870,8 +821,8 @@ void ResampleLinear(s16* pStereoSamples, int oldsamples, s16* pNewSamples, int n old *= 2; int newsampL = pStereoSamples[old] * (newsamples - rem) + pStereoSamples[old+2] * rem; int newsampR = pStereoSamples[old+1] * (newsamples - rem) + pStereoSamples[old+3] * rem; - pNewSamples[2*i] = newsampL / newsamples; - pNewSamples[2*i+1] = newsampR / newsamples; + pNewSamples[2 * i] = newsampL / newsamples; + pNewSamples[2 * i + 1] = newsampR / newsamples; } } @@ -917,7 +868,7 @@ void* SPU2ThreadProc(void* lpParam) } - int ps2delay = timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp; + //int ps2delay = timeGetTime() - s_pAudioBuffers[nReadBuf].timestamp; int NewSamples = s_pAudioBuffers[nReadBuf].avgtime; if ( (conf.options & OPTION_TIMESTRETCH) ) @@ -942,11 +893,11 @@ void* SPU2ThreadProc(void* lpParam) NewSamples *= NSSIZE; NewSamples /= 1000; - NewSamples = min(NewSamples, NSFRAMES*NSSIZE*3); + NewSamples = min(NewSamples, NSFRAMES * NSSIZE * 3); - int oldsamples = s_pAudioBuffers[nReadBuf].len/4; + int oldsamples = s_pAudioBuffers[nReadBuf].len / 4; - if ((nReadBuf&3)==0) // wow, this if statement makes the whole difference + if ((nReadBuf & 3) == 0) // wow, this if statement makes the whole difference pSoundTouch->setTempoChange(100.0f*(float)oldsamples/(float)NewSamples - 100.0f); pSoundTouch->putSamples((s16*)s_pAudioBuffers[nReadBuf].pbuf, oldsamples); @@ -956,8 +907,8 @@ void* SPU2ThreadProc(void* lpParam) do { - nOutSamples = pSoundTouch->receiveSamples(s_ThreadBuffer, NSSIZE*NSFRAMES*5); - if ( nOutSamples > 0 ) SoundFeedVoiceData((u8*)s_ThreadBuffer, nOutSamples*4); + nOutSamples = pSoundTouch->receiveSamples(s_ThreadBuffer, NSSIZE * NSFRAMES * 5); + if ( nOutSamples > 0 ) SoundFeedVoiceData((u8*)s_ThreadBuffer, nOutSamples * 4); } while (nOutSamples != 0); @@ -1026,16 +977,16 @@ void VolumeOn(int start,int end,unsigned short val,int iRight) // VOLUME ON PSX if (val&1) { // -> reverb on/off if (iRight) - voices[ch].bVolumeR=1; + voices[ch].bVolumeR = true; else - voices[ch].bVolumeL=1; + voices[ch].bVolumeL = true; } else { if (iRight) - voices[ch].bVolumeR=0; + voices[ch].bVolumeR = false; else - voices[ch].bVolumeL=0; + voices[ch].bVolumeL = false; } } } @@ -1045,38 +996,42 @@ void CALLBACK 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); + assert(C0_SPUADDR() < 0x100000); + assert(C1_SPUADDR() < 0x100000); spu2Ru16(mem) = value; - u32 r = mem&0xffff; + u32 r = mem & 0xffff; // channel info - if ((r>=0x0000 && r<0x0180) || (r>=0x0400 && r<0x0580)) // some channel info? + if ((r<0x0180) || (r>=0x0400 && r<0x0580)) // u32s are always >= 0. { int ch=0; - if (r>=0x400) ch=((r-0x400)>>4)+24; - else ch=(r>>4); + if (r >= 0x400) + ch = ((r - 0x400) >> 4) + 24; + else + ch = (r >> 4); VOICE_PROCESSED* pvoice = &voices[ch]; - switch(r&0x0f) + switch(r & 0x0f) { case 0: case 2: - pvoice->SetVolume(mem&0x2); + pvoice->SetVolume(mem & 0x2); break; case 4: { int NP; - if (value>0x3fff) NP=0x3fff; // get pitch val - else NP=value; + if (value> 0x3fff) + NP=0x3fff; // get pitch val + else + NP=value; pvoice->pvoice->pitch = NP; NP = (SAMPLE_RATE * NP) / 4096L; // calc frequency - if (NP<1) NP=1; // some security - pvoice->iActFreq=NP; // store frequency + if (NP<1) NP = 1; // some security + pvoice->iActFreq = NP; // store frequency break; } case 6: @@ -1116,16 +1071,16 @@ void CALLBACK SPU2write(u32 mem, u16 value) switch(rx) { - case 0x1C0: - pvoice->iStartAddr=(((unsigned long)value&0x3f)<<16)|(pvoice->iStartAddr&0xFFFF); + case REG_VA_SSA: + pvoice->iStartAddr=(((u32)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); + case REG_VA_LSAX: + pvoice->iLoopAddr =(((u32)value&0x3f)<<16)|(pvoice->iLoopAddr&0xFFFF); pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; break; @@ -1134,9 +1089,9 @@ void CALLBACK SPU2write(u32 mem, u16 value) pvoice->pLoop=(u8*)(spu2mem+pvoice->iLoopAddr); pvoice->bIgnoreLoop=pvoice->iLoopAddr>0; break; - case 0x1C8: + case REG_VA_NAX: // unused... check if it gets written as well - pvoice->iNextAddr=(((unsigned long)value&0x3f)<<16)|(pvoice->iNextAddr&0xFFFF); + pvoice->iNextAddr=(((u32)value&0x3f)<<16)|(pvoice->iNextAddr&0xFFFF); break; case 0x1CA: // unused... check if it gets written as well @@ -1148,7 +1103,7 @@ void CALLBACK SPU2write(u32 mem, u16 value) } // process non-channel data - switch(mem&0xffff) + switch(mem & 0xffff) { case REG_C0_SPUDATA: spuaddr = C0_SPUADDR(); @@ -1244,36 +1199,39 @@ void CALLBACK SPU2write(u32 mem, u16 value) case REG_C1_VMIXR2: VolumeOn(40,48,value,1); break; } - assert( C0_SPUADDR < 0x100000); - assert( C1_SPUADDR < 0x100000); + assert( C0_SPUADDR() < 0x100000); + assert( C1_SPUADDR() < 0x100000); } u16 CALLBACK SPU2read(u32 mem) { u32 spuaddr; - u16 ret; - u32 r = mem&0xffff; + u16 ret = 0; + u32 r = mem & 0xffff; // register - if ((r>=0x0000 && r<0x0180)||(r>=0x0400 && r<0x0580)) // some channel info? + // channel info + // if the register is any of the regs before core 0, or is somewhere between core 0 and 1... + if ((r < 0x0180) || (r >= 0x0400 && r < 0x0580)) // u32s are always >= 0. { - int ch=0; + int ch = 0; - if (r>=0x400) - ch=((r-0x400)>>4)+24; + if (r >= 0x400) + ch=((r - 0x400) >> 4) + 24; else - ch=(r>>4); + ch = (r >> 4); VOICE_PROCESSED* pvoice = &voices[ch]; - if ((r&0x0f) == 10) return (unsigned short)(pvoice->ADSRX.EnvelopeVol>>16); + if ((r&0x0f) == 10) return (u16)(pvoice->ADSRX.EnvelopeVol >> 16); } - if ((r>=0x01c0 && r<0x02E0)||(r>=0x05c0 && r<0x06E0)) // some channel info? + + if ((r>=REG_VA_SSA && r=0x05c0 && r<0x06E0)) // some channel info? { int ch=0; - unsigned long rx=r; + unsigned long rx = r; - if (rx>=0x400) + if (rx >=0x400) { ch=24; rx-=0x400; @@ -1286,19 +1244,19 @@ u16 CALLBACK SPU2read(u32 mem) // Note - can we generalize this? switch(rx) { - case 0x1C0: + case REG_VA_SSA: ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>17)&0x3F); break; case 0x1C2: ret = ((((uptr)pvoice->pStart-(uptr)spu2mem)>>1)&0xFFFF); break; - case 0x1C4: + case REG_VA_LSAX: ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>17)&0x3F); break; case 0x1C6: ret = ((((uptr)pvoice->pLoop-(uptr)spu2mem)>>1)&0xFFFF); break; - case 0x1C8: + case REG_VA_NAX: ret = ((((uptr)pvoice->pCurr-(uptr)spu2mem)>>17)&0x3F); break; case 0x1CA: @@ -1310,28 +1268,26 @@ u16 CALLBACK SPU2read(u32 mem) return ret; } - switch(mem&0xffff) + switch(mem & 0xffff) { case REG_C0_SPUDATA: spuaddr = C0_SPUADDR(); ret =spu2mem[spuaddr]; spuaddr++; - if (spuaddr>0xfffff) - spuaddr=0; + 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; + if (spuaddr > 0xfffff) spuaddr=0; C1_SPUADDR_SET(spuaddr); break; case REG_C0_END1: ret = (dwEndChannel2[0]&0xffff); break; - case REG_C0_END2: ret = (dwEndChannel2[0]>>16); break; case REG_C1_END1: ret = (dwEndChannel2[1]&0xffff); break; + case REG_C0_END2: ret = (dwEndChannel2[0]>>16); break; case REG_C1_END2: ret = (dwEndChannel2[1]>>16); break; case REG_IRQINFO: @@ -1349,12 +1305,12 @@ u16 CALLBACK SPU2read(u32 mem) void CALLBACK SPU2WriteMemAddr(int core, u32 value) { - MemAddr[core] = g_pDMABaseAddr+value; + MemAddr[core] = g_pDMABaseAddr + value; } u32 CALLBACK SPU2ReadMemAddr(int core) { - return MemAddr[core]-g_pDMABaseAddr; + return MemAddr[core] - g_pDMABaseAddr; } void CALLBACK SPU2setDMABaseAddr(uptr baseaddr) @@ -1374,53 +1330,47 @@ s32 CALLBACK SPU2test() return 0; } +#define SetPacket(s) \ +{ \ + if (s & 0x8000) s|=0xffff0000; \ + fa = (s >> shift_factor); \ + fa += ((s_1 * f[predict_nr][0]) >> 6) + ((s_2 * f[predict_nr][1]) >> 6); \ + s_2 = s_1; \ + s_1 = fa; \ + buf[nSample++] = fa; \ +} + // size is in bytes void LogPacketSound(void* packet, int memsize) { u16 buf[28]; u8* pstart = (u8*)packet; - int s_1 = 0; - int s_2=0; + int s_1 = 0, s_2=0; for (int i = 0; i < memsize; i += 16) { int predict_nr=(int)pstart[0]; int shift_factor=predict_nr&0xf; predict_nr >>= 4; - int flags=(int)pstart[1]; pstart += 2; for (int nSample=0;nSample<28; ++pstart) { int d=(int)*pstart; - int s=((d&0xf)<<12); - if (s&0x8000) s|=0xffff0000; - int fa; + int s, fa; + + s =((d & 0xf) << 12); + SetPacket(s); - fa = (s >> shift_factor); - fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); - s_2 = s_1; - s_1 = fa; s=((d & 0xf0) << 8); - - buf[nSample++]=fa; - - if (s&0x8000) s|=0xffff0000; - fa = (s>>shift_factor); - fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); - s_2 = s_1; - s_1 = fa; - - buf[nSample++]=fa; + SetPacket(s); } LogRawSound(buf, 2, buf, 2, 28); } } -#define RECORD_FILENAME "zerospu2.wav" - void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples) { if (g_pWavRecord == NULL ) @@ -1430,7 +1380,7 @@ void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int u8* right = (u8*)pright; static vector tempbuf; - tempbuf.resize(2*numsamples); + tempbuf.resize(2 * numsamples); for (int i = 0; i < numsamples; ++i) { @@ -1459,28 +1409,6 @@ int CALLBACK SPU2setupRecording(int start, void* pData) return 1; } -struct SPU2freezeData -{ - u32 version; - u8 spu2regs[0x10000]; - u8 spu2mem[0x200000]; - u16 interrupt; - int nSpuIrq[2]; - u32 dwNewChannel2[2], dwEndChannel2[2]; - u32 dwNoiseVal; - int iFMod[NSSIZE]; - u32 MemAddr[2]; - ADMA adma[2]; - u32 Adma4MemAddr, Adma7MemAddr; - - int SPUCycles, SPUWorkerCycles; - int SPUStartCycle[2]; - int SPUTargetCycle[2]; - - int voicesize; - VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; -}; - s32 CALLBACK SPU2freeze(int mode, freezeData *data) { SPU2freezeData *spud; diff --git a/plugins/zerospu2/zerospu2.h b/plugins/zerospu2/zerospu2.h index 3ff7c1d416..1e82c0c2c7 100644 --- a/plugins/zerospu2/zerospu2.h +++ b/plugins/zerospu2/zerospu2.h @@ -30,49 +30,8 @@ extern "C" { #include "PS2Edefs.h" } -#ifdef __LINUX__ -#include -#include -#include // ftime(), struct timeb - -#define Sleep(ms) usleep(1000*ms) - -inline unsigned long timeGetTime() -{ -#ifdef _WIN32 - _timeb t; - _ftime(&t); -#else - timeb t; - ftime(&t); -#endif - - return (unsigned long)(t.time*1000+t.millitm); -} - -#include - -#else -#include -#include - -#include // ftime(), struct timeb -#endif - - -inline u64 GetMicroTime() -{ -#ifdef _WIN32 - extern LARGE_INTEGER g_counterfreq; - LARGE_INTEGER count; - QueryPerformanceCounter(&count); - return count.QuadPart * 1000000 / g_counterfreq.QuadPart; -#else - timeval t; - gettimeofday(&t, NULL); - return t.tv_sec*1000000+t.tv_usec; -#endif -} +#include "reg.h" +#include "misc.h" #include #include @@ -102,6 +61,8 @@ extern FILE *spu2Log; #define SUSTAIN_MS 441L #define RELEASE_MS 437L +#define CYCLES_PER_MS (36864000/1000) + #define AUDIO_BUFFER 2048 #define NSSIZE 48 // ~ 1 ms of data @@ -109,6 +70,8 @@ extern FILE *spu2Log; #define NSPACKETS 24 #define SAMPLE_RATE 48000L +#define RECORD_FILENAME "zerospu2.wav" + extern s8 *spu2regs; extern u16* spu2mem; extern int iFMod[NSSIZE]; @@ -141,6 +104,9 @@ void SysMessage(char *fmt, ...); void LogRawSound(void* pleft, int leftstride, void* pright, int rightstride, int numsamples); void LogPacketSound(void* packet, int memsize); +// simulate SPU2 for 1ms +void SPU2Worker(); + // hardware sound functions int SetupSound(); // if successful, returns 0 void RemoveSound(); @@ -148,216 +114,24 @@ int SoundGetBytesBuffered(); // returns 0 is successful, else nonzero void SoundFeedVoiceData(unsigned char* pSound,long lBytes); -#if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC) - -#include - -// declare linux equivalents -static __forceinline void* pcsx2_aligned_malloc(size_t size, size_t align) -{ - assert( align < 0x10000 ); - char* p = (char*)malloc(size+align); - int off = 2+align - ((int)(uptr)(p+2) % align); - - p += off; - *(u16*)(p-2) = off; - - return p; +#define clamp16(dest) \ +{ \ + if ( dest < -32768L ) \ + dest = -32768L; \ + else if ( dest > 32767L ) \ + dest = 32767L; \ } -static __forceinline void pcsx2_aligned_free(void* pmem) -{ - if( pmem != NULL ) { - char* p = (char*)pmem; - free(p - (int)*(u16*)(p-2)); - } +#define clampandwrite16(dest,value) \ +{ \ + if ( value < -32768 ) \ + dest = -32768; \ + else if ( value > 32767 ) \ + dest = 32767; \ + else \ + dest = (s16)value; \ } -#define _aligned_malloc pcsx2_aligned_malloc -#define _aligned_free pcsx2_aligned_free -#endif - -// Atomic Operations -#if defined (_WIN32) - -#ifndef __x86_64__ -extern "C" LONG __cdecl _InterlockedExchangeAdd(LPLONG volatile Addend, LONG Value); -#endif - -#pragma intrinsic (_InterlockedExchangeAdd) -#define InterlockedExchangeAdd _InterlockedExchangeAdd - -#else - -typedef void* PVOID; - -static __forceinline long InterlockedExchangeAdd(long volatile* Addend, long Value) -{ - __asm__ __volatile__(".intel_syntax\n" - "lock xadd [%0], %%eax\n" - ".att_syntax\n" : : "r"(Addend), "a"(Value) : "memory" ); -} - -#endif - -//////////////////// -// SPU2 Registers // -//////////////////// -enum -{ -// Volume Registers - currently not implemented in ZeroSPU2, like most volume registers. - REG_VP_VOLL = 0x0000, // Voice Volume Left - REG_VP_VOLR = 0x0002, // Voice Volume Right - REG_VP_PITCH = 0x0004, // Pitch - REG_VP_ADSR1 = 0x0006, // Envelope 1 (Attack-Decay-Sustain-Release) - REG_VP_ADSR2 = 0x0008, // Envelope 2 (Attack-Decay-Sustain-Release) - REG_VP_ENVX = 0x000A, // Current Envelope - REG_VP_VOLXL = 0x000C, // Current Voice Volume Left - REG_VP_VOLXR = 0x000E, // Current Voice Volume Right -// end unimplemented section - - REG_C0_FMOD1 = 0x0180, // Pitch Modulation Spec. - REG_C0_FMOD2 = 0x0182, - REG_S_NON = 0x0184, // Alloc Noise Generator - unimplemented - REG_C0_VMIXL1 = 0x0188, // Voice Output Mix Left (Dry) - REG_C0_VMIXL2 = 0x018A, - REG_S_VMIXEL = 0x018C, // Voice Output Mix Left (Wet) - unimplemented - REG_C0_VMIXR1 = 0x0190, // Voice Output Mix Right (Dry) - REG_C0_VMIXR2 = 0x0192, - REG_S_VMIXER = 0x0194, // Voice Output Mix Right (Wet) - unimplemented - - REG_C0_MMIX = 0x0198, // Output Spec. After Voice Mix - REG_C0_CTRL = 0x019A, // Core X Attrib - REG_C0_IRQA_HI = 0x019C, // Interrupt Address Spec. - Hi - REG_C0_IRQA_LO = 0x019E, // Interrupt Address Spec. - Lo - - REG_C0_SPUON1 = 0x01A0, // Key On 0/1 - REG_C0_SPUON2 = 0x01A2, - REG_C0_SPUOFF1 = 0x01A4, // Key Off 0/1 - REG_C0_SPUOFF2 = 0x01A6, - - REG_C0_SPUADDR_HI = 0x01A8, // Transfer starting address - hi - REG_C0_SPUADDR_LO = 0x01AA, // Transfer starting address - lo - REG_C0_SPUDATA = 0x01AC, // Transfer data - REG_C0_DMACTRL = 0x01AE, // unimplemented - REG_C0_ADMAS = 0x01B0, // AutoDMA Status - - // Section Unimplemented - REG_VA_SSA = 0x01C0, // Waveform data starting address - REG_VA_LSAX = 0x01C4, // Loop point address - REG_VA_NAX = 0x01C8, // Waveform data that should be read next - REG_A_ESA = 0x02E0, //Address: Top address of working area for effects processing - R_FB_SRC_A = 0x02E4, // Feedback Source A - R_FB_SRC_B = 0x02E8, // Feedback Source B -R_IIR_DEST_A0 = 0x02EC, -R_IIR_DEST_A1 = 0x02F0, -R_ACC_SRC_A0 = 0x02F4, -R_ACC_SRC_A1 = 0x02F8, -R_ACC_SRC_B0 = 0x02FC, -R_ACC_SRC_B1 = 0x0300, -R_IIR_SRC_A0 = 0x0304, -R_IIR_SRC_A1 = 0x0308, -R_IIR_DEST_B0 = 0x030C, -R_IIR_DEST_B1 = 0x0310, -R_ACC_SRC_C0 = 0x0314, -R_ACC_SRC_C1 = 0x0318, -R_ACC_SRC_D0 = 0x031C, -R_ACC_SRC_D1 = 0x0320, -R_IIR_SRC_B1 = 0x0324, -R_IIR_SRC_B0 = 0x0328, -R_MIX_DEST_A0 = 0x032C, -R_MIX_DEST_A1 = 0x0330, -R_MIX_DEST_B0 = 0x0334, -R_MIX_DEST_B1 = 0x0338, - REG_A_EEA = 0x033C, // Address: End address of working area for effects processing (upper part of address only!) - // end unimplemented section - - REG_C0_END1 = 0x0340, // End Point passed flag - REG_C0_END2 = 0x0342, - REG_C0_SPUSTAT = 0x0344, // Status register? - - // core 1 has the same registers with 0x400 added, and ends at 0x746. - REG_C1_FMOD1 = 0x0580, - REG_C1_FMOD2 = 0x0582, - REG_C1_VMIXL1 = 0x0588, - REG_C1_VMIXL2 = 0x058A, - REG_C1_VMIXR1 = 0x0590, - REG_C1_VMIXR2 = 0x0592, - REG_C1_MMIX = 0x0598, - REG_C1_CTRL = 0x059A, - REG_C1_IRQA_HI = 0x059C, - REG_C1_IRQA_LO = 0x059E, - REG_C1_SPUON1 = 0x05A0, - REG_C1_SPUON2 = 0x05A2, - REG_C1_SPUOFF1 = 0x05A4, - REG_C1_SPUOFF2 = 0x05A6, - REG_C1_SPUADDR_HI = 0x05A8, - REG_C1_SPUADDR_LO = 0x05AA, - REG_C1_SPUDATA = 0x05AC, - REG_C1_DMACTRL = 0x05AE, // unimplemented - REG_C1_ADMAS = 0x05B0, - REG_C1_END1 = 0x0740, - REG_C1_END2 = 0x0742, - REG_C1_SPUSTAT = 0x0744, - - // Interesting to note that *most* of the volume controls aren't implemented in Zerospu2. - REG_P_MVOLL = 0x0760, // Master Volume Left - unimplemented - REG_P_MVOLR = 0x0762, // Master Volume Right - unimplemented - REG_P_EVOLL = 0x0764, // Effect Volume Left - unimplemented - REG_P_EVOLR = 0x0766, // Effect Volume Right - unimplemented - REG_P_AVOLL = 0x0768, // Core External Input Volume Left (Only Core 1) - unimplemented - REG_P_AVOLR = 0x076A, // Core External Input Volume Right (Only Core 1) - unimplemented - REG_C0_BVOLL = 0x076C, // Sound Data Volume Left - REG_C0_BVOLR = 0x076E, // Sound Data Volume Right - REG_P_MVOLXL = 0x0770, // Current Master Volume Left - unimplemented - REG_P_MVOLXR = 0x0772, // Current Master Volume Right - unimplemented - - // Another unimplemented section - R_IIR_ALPHA = 0x0774, // IIR alpha (% used) - R_ACC_COEF_A = 0x0776, - R_ACC_COEF_B = 0x0778, - R_ACC_COEF_C = 0x077A, - R_ACC_COEF_D = 0x077C, - R_IIR_COEF = 0x077E, - R_FB_ALPHA = 0x0780, // feedback alpha (% used) - R_FB_X = 0x0782, // feedback - R_IN_COEF_L = 0x0784, - R_IN_COEF_R = 0x0786, - // end unimplemented section - - REG_C1_BVOLL = 0x0794, - REG_C1_BVOLR = 0x0796, - - SPDIF_OUT = 0x07C0, // SPDIF Out: OFF/'PCM'/Bitstream/Bypass - unimplemented - REG_IRQINFO = 0x07C2, - SPDIF_MODE = 0x07C6, // unimplemented - SPDIF_MEDIA = 0x07C8, // SPDIF Media: 'CD'/DVD - unimplemented - SPDIF_COPY_PROT = 0x07CC // SPDIF Copy Protection - unimplemented - // NOTE: SPDIF_COPY is defined in Linux kernel headers as 0x0004. -}; - -// These SPDIF defines aren't used yet - swiped from spu2ghz, like a number of the registers I added in. -// -- arcum42 -#define SPDIF_OUT_OFF 0x0000 //no spdif output -#define SPDIF_OUT_PCM 0x0020 //encode spdif from spu2 pcm output -#define SPDIF_OUT_BYPASS 0x0100 //bypass spu2 processing - -#define SPDIF_MODE_BYPASS_BITSTREAM 0x0002 //bypass mode for digital bitstream data -#define SPDIF_MODE_BYPASS_PCM 0x0000 //bypass mode for pcm data (using analog output) - -#define SPDIF_MODE_MEDIA_CD 0x0800 //source media is a CD -#define SPDIF_MODE_MEDIA_DVD 0x0000 //source media is a DVD - -#define SPDIF_MEDIA_CDVD 0x0200 -#define SPDIF_MEDIA_400 0x0000 - -#define SPDIF_COPY_NORMAL 0x0000 // spdif stream is not protected -#define SPDIF_COPY_PROHIBIT 0x8000 // spdif stream can't be copied - -#define SPU_AUTODMA_ONESHOT 0 //spu2 -#define SPU_AUTODMA_LOOP 1 //spu2 -#define SPU_AUTODMA_START_ADDR (1 << 1) //spu2 - #define spu2Rs16(mem) (*(s16*)&spu2regs[(mem) & 0xffff]) #define spu2Ru16(mem) (*(u16*)&spu2regs[(mem) & 0xffff]) @@ -384,6 +158,14 @@ static __forceinline u32 C1_IRQA() return SPU2_GET32BIT(REG_C1_IRQA_LO, REG_C1_IRQA_HI); } +static __forceinline u32 C_IRQA(int c) +{ + if (c == 0) + return C0_IRQA(); + else + return C1_IRQA(); +} + static __forceinline u32 C0_SPUADDR() { return SPU2_GET32BIT(REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI); @@ -394,6 +176,14 @@ static __forceinline u32 C1_SPUADDR() return SPU2_GET32BIT(REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI); } +static __forceinline u32 C_SPUADDR(int c) +{ + if (c == 0) + return C0_SPUADDR(); + else + return C1_SPUADDR(); +} + static __forceinline void C0_SPUADDR_SET(u32 value) { SPU2_SET32BIT(value, REG_C0_SPUADDR_LO, REG_C0_SPUADDR_HI); @@ -404,6 +194,14 @@ static __forceinline void C1_SPUADDR_SET(u32 value) SPU2_SET32BIT(value, REG_C1_SPUADDR_LO, REG_C1_SPUADDR_HI); } +static __forceinline void C_SPUADDR_SET(u32 value, int c) +{ + if (c == 0) + C0_SPUADDR_SET(value); + else + C1_SPUADDR_SET(value); +} + #define SPU_NUMBER_VOICES 48 struct SPU_CONTROL_ @@ -543,16 +341,50 @@ struct VOICE_PROCESSED _SPU_VOICE* pvoice; }; +struct AUDIOBUFFER +{ + u8* pbuf; + u32 len; + + // 1 if new channels started in this packet + // Variable used to smooth out sound by concentrating on new voices + u32 timestamp; // in microseconds, only used for time stretching + u32 avgtime; + int newchannels; +}; + struct ADMA { unsigned short * MemAddr; int Index; int AmountLeft; - int Enabled; // used to make sure that ADMA doesn't get interrupted with a writeDMA call + int Enabled; + // used to make sure that ADMA doesn't get interrupted with a writeDMA call }; - extern ADMA Adma4; extern ADMA Adma7; +struct SPU2freezeData +{ + u32 version; + u8 spu2regs[0x10000]; + u8 spu2mem[0x200000]; + u16 interrupt; + int nSpuIrq[2]; + u32 dwNewChannel2[2], dwEndChannel2[2]; + u32 dwNoiseVal; + int iFMod[NSSIZE]; + u32 MemAddr[2]; + ADMA adma[2]; + u32 Adma4MemAddr, Adma7MemAddr; + + int SPUCycles, SPUWorkerCycles; + int SPUStartCycle[2]; + int SPUTargetCycle[2]; + + int voicesize; + VOICE_PROCESSED voices[SPU_NUMBER_VOICES+1]; +}; + #endif /* __SPU2_H__ */