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
This commit is contained in:
arcum42 2009-01-30 22:14:52 +00:00 committed by Gregory Hainaut
parent 1ace722861
commit 347e6c44bb
12 changed files with 1061 additions and 943 deletions

View File

@ -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

View File

@ -1,252 +1,86 @@
#include <stdio.h>
/* 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 <stdio.h>
#include <windows.h>
#include <windowsx.h>
#include "zerospu2.h"
#include "resource.h"
/////////////////////////////////////
// use DirectSound for the sound
#include <dsound.h>
#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<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;}
lpSD=(unsigned long *)lpvPtr1;
dw=dwBytes1>>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;
}

View File

@ -192,6 +192,10 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\dsound51.cpp"
>
</File>
<File
RelativePath=".\voices.cpp"
>
@ -214,6 +218,14 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\misc.h"
>
</File>
<File
RelativePath=".\reg.h"
>
</File>
<File
RelativePath=".\resource.h"
>

View File

@ -12,7 +12,7 @@ then
aclocal
automake -a
autoconf
./configure --prefix=${PCSX2PLUGINS}
./configure --enable-debug-build --prefix=${PCSX2PLUGINS}
make clean
make install

View File

@ -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)

View File

@ -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 <stdio.h>
#include <windows.h>
#include <windowsx.h>
#include "zerospu2.h"
/////////////////////////////////////
// use DirectSound for the sound
#include <dsound.h>
//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;
}

147
plugins/zerospu2/misc.h Normal file
View File

@ -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 <unistd.h>
#include <gtk/gtk.h>
#include <sys/timeb.h> // 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 <sys/time.h>
#else
#include <windows.h>
#include <windowsx.h>
#include <sys/timeb.h> // 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 <assert.h>
// 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

182
plugins/zerospu2/reg.h Normal file
View File

@ -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

View File

@ -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;

View File

@ -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;i<size;i++)
u32 spuaddr;
int i, dma, offset;
if ( core == 0)
{
*pMem++ = *(u16*)(spu2mem+spuaddr);
if ((spu2Rs16(REG_C0_CTRL) & 0x40) && C0_IRQA() == spuaddr)
dma = 4;
offset = 0;
}
else
{
dma = 7;
offset = 0x0400;
}
spuaddr = C_SPUADDR(core);
SPU2_LOG("SPU2 readDMA%dMem size %x, addr: %x\n", dma, size, pMem);
for (i=0; i < size; i++)
{
*pMem++ = *(u16*)(spu2mem + spuaddr);
if ((spu2Rs16(REG_C0_CTRL + offset) & 0x40) && (C_IRQA(core) == spuaddr))
{
C0_SPUADDR_SET(spuaddr);
IRQINFO |= 4;
SPU2_LOG("SPU2readDMA4Mem:interrupt\n");
C_SPUADDR_SET(spuaddr, core);
IRQINFO |= (4 * (core + 1));
SPU2_LOG("SPU2readDMA%dMem:interrupt\n", dma);
irqCallbackSPU2();
}
spuaddr++; // inc spu addr
if (spuaddr>0x0fffff) 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;i<size;i++)
{
*pMem++ = *(u16*)(spu2mem+spuaddr);
if ((spu2Rs16(REG_C1_CTRL)&0x40) && (C1_IRQA() == spuaddr))
{
C1_SPUADDR_SET(spuaddr);
IRQINFO |= 8;
SPU2_LOG("SPU2readDMA7Mem:interrupt\n");
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);
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);
}

View File

@ -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;ns<NSSIZE;ns++)
{
if ((spu2Ru16(REG_C0_MMIX + c_offset) & 0x80))
s_buffers[ns][0] += (((short*)spu2mem)[0x2000 + c_offset +Adma->Index]*(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<<core;
SPU2_LOG("SPU2Worker:interrupt\n");
@ -666,19 +706,19 @@ void SPU2Worker()
else
fa=pChannel->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;ns<NSSIZE;ns++)
{
if ((spu2Ru16(REG_C0_MMIX) & 0x80))
s_buffers[ns][0] += (((short*)spu2mem)[0x2000+Adma->Index]*(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;ns<NSSIZE;ns++)
{
if ((spu2Ru16(REG_C1_MMIX) & 0x80))
s_buffers[ns][0] += (((short*)spu2mem)[0x2400+Adma->Index]*(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<NSSIZE;ns++)
for (int ns=0; ns<NSSIZE; ns++)
{
// clamp and write
if ( s_buffers[ns][0] < -32767 )
s_pCurOutput[0] = -32767;
else if ( s_buffers[ns][0] > 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<REG_A_ESA) || (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<s16> 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;

View File

@ -30,49 +30,8 @@ extern "C" {
#include "PS2Edefs.h"
}
#ifdef __LINUX__
#include <unistd.h>
#include <gtk/gtk.h>
#include <sys/timeb.h> // 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 <sys/time.h>
#else
#include <windows.h>
#include <windowsx.h>
#include <sys/timeb.h> // 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 <string>
#include <vector>
@ -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 <assert.h>
// 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__ */