mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
1ace722861
commit
347e6c44bb
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -12,7 +12,7 @@ then
|
|||
aclocal
|
||||
automake -a
|
||||
autoconf
|
||||
./configure --prefix=${PCSX2PLUGINS}
|
||||
./configure --enable-debug-build --prefix=${PCSX2PLUGINS}
|
||||
make clean
|
||||
make install
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in New Issue