Skip to content

Commit

Permalink
spu: try to improve timing
Browse files Browse the repository at this point in the history
  • Loading branch information
notaz committed Sep 27, 2023
1 parent 1fb319e commit 6183ddf
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 41 deletions.
4 changes: 2 additions & 2 deletions frontend/plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ extern long CALLBACK SPUinit(void);
extern long CALLBACK SPUshutdown(void);
extern long CALLBACK SPUclose(void);
extern void CALLBACK SPUwriteRegister(unsigned long, unsigned short, unsigned int);
extern unsigned short CALLBACK SPUreadRegister(unsigned long);
extern unsigned short CALLBACK SPUreadRegister(unsigned long, unsigned int);
extern void CALLBACK SPUwriteDMAMem(unsigned short *, int, unsigned int);
extern void CALLBACK SPUreadDMAMem(unsigned short *, int, unsigned int);
extern void CALLBACK SPUplayADPCMchannel(void *, unsigned int, int);
Expand Down Expand Up @@ -309,7 +309,7 @@ pc_hook_func_ret(long, GPU_dmaChain, (uint32_t *a0, int32_t a1), (a0, a1), P
pc_hook_func (GPU_updateLace, (void), (), PCNT_GPU)

pc_hook_func (SPU_writeRegister, (unsigned long a0, unsigned short a1, uint32_t a2), (a0, a1, a2), PCNT_SPU)
pc_hook_func_ret(unsigned short,SPU_readRegister, (unsigned long a0), (a0), PCNT_SPU)
pc_hook_func_ret(unsigned short,SPU_readRegister, (unsigned long a0, , unsigned int a1), (a0, a1), PCNT_SPU)
pc_hook_func (SPU_writeDMAMem, (unsigned short *a0, int a1, uint32_t a2), (a0, a1, a2), PCNT_SPU)
pc_hook_func (SPU_readDMAMem, (unsigned short *a0, int a1, uint32_t a2), (a0, a1, a2), PCNT_SPU)
pc_hook_func (SPU_playADPCMchannel, (void *a0, unsigned int a1, int a2), (a0, a1, a2), PCNT_SPU)
Expand Down
24 changes: 18 additions & 6 deletions libpcsxcore/new_dynarec/pcsxmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,19 @@ make_dma_func(3)
make_dma_func(4)
make_dma_func(6)

static u32 io_spu_read16(u32 addr)
{
return SPU_readRegister(addr, psxRegs.cycle);
}

static u32 io_spu_read32(u32 addr)
{
u32 ret;
ret = SPU_readRegister(addr, psxRegs.cycle);
ret |= SPU_readRegister(addr + 2, psxRegs.cycle) << 16;
return ret;
}

static void io_spu_write16(u32 value)
{
// meh
Expand Down Expand Up @@ -387,6 +400,11 @@ void new_dyna_pcsx_mem_init(void)
map_item(&mem_iortab[IOMEM8(0x1802)], cdrRead2, 1);
map_item(&mem_iortab[IOMEM8(0x1803)], cdrRead3, 1);

for (i = 0x1c00; i < 0x2000; i += 2) {
map_item(&mem_iortab[IOMEM16(i)], io_spu_read16, 1);
map_item(&mem_iortab[IOMEM32(i)], io_spu_read32, 1);
}

// write(u32 data)
map_item(&mem_iowtab[IOMEM32(0x1040)], io_write_sio32, 1);
map_item(&mem_iowtab[IOMEM32(0x1070)], psxHwWriteIstat, 1);
Expand Down Expand Up @@ -456,14 +474,8 @@ void new_dyna_pcsx_mem_init(void)

void new_dyna_pcsx_mem_reset(void)
{
int i;

// plugins might change so update the pointers
map_item(&mem_iortab[IOMEM32(0x1810)], GPU_readData, 1);

for (i = 0x1c00; i < 0x2000; i += 2)
map_item(&mem_iortab[IOMEM16(i)], SPU_readRegister, 1);

map_item(&mem_iowtab[IOMEM32(0x1810)], GPU_writeData, 1);
}

Expand Down
2 changes: 1 addition & 1 deletion libpcsxcore/plugins.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ typedef long (CALLBACK* SPUinit)(void);
typedef long (CALLBACK* SPUshutdown)(void);
typedef long (CALLBACK* SPUclose)(void);
typedef void (CALLBACK* SPUwriteRegister)(unsigned long, unsigned short, unsigned int);
typedef unsigned short (CALLBACK* SPUreadRegister)(unsigned long);
typedef unsigned short (CALLBACK* SPUreadRegister)(unsigned long, unsigned int);
typedef void (CALLBACK* SPUwriteDMAMem)(unsigned short *, int, unsigned int);
typedef void (CALLBACK* SPUreadDMAMem)(unsigned short *, int, unsigned int);
typedef void (CALLBACK* SPUplayADPCMchannel)(xa_decode_t *, unsigned int, int);
Expand Down
6 changes: 3 additions & 3 deletions libpcsxcore/psxhw.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ u16 psxHwRead16(u32 add) {
// falthrough
default:
if (0x1f801c00 <= add && add < 0x1f802000)
return SPU_readRegister(add);
return SPU_readRegister(add, psxRegs.cycle);
hard = psxHu16(add);
#ifdef PSXHW_LOG
PSXHW_LOG("*Unkwnown 16bit read at address %x\n", add);
Expand Down Expand Up @@ -411,8 +411,8 @@ u32 psxHwRead32(u32 add) {
// falthrough
default:
if (0x1f801c00 <= add && add < 0x1f802000) {
hard = SPU_readRegister(add);
hard |= SPU_readRegister(add + 2) << 16;
hard = SPU_readRegister(add, psxRegs.cycle);
hard |= SPU_readRegister(add + 2, psxRegs.cycle) << 16;
return hard;
}
hard = psxHu32(add);
Expand Down
4 changes: 2 additions & 2 deletions plugins/dfsound/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize,
unsigned int addr = spu.spuAddr, irq_addr = regAreaGet(H_SPUirqAddr) << 3;
int i, irq;

do_samples_if_needed(cycles, 1);
do_samples_if_needed(cycles, 1, 2);
irq = addr <= irq_addr && irq_addr < addr + iSize*2;

for(i = 0; i < iSize; i++)
Expand All @@ -66,7 +66,7 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize,
unsigned int addr = spu.spuAddr, irq_addr = regAreaGet(H_SPUirqAddr) << 3;
int i, irq;

do_samples_if_needed(cycles, 1);
do_samples_if_needed(cycles, 1, 2);
spu.bMemDirty = 1;
irq = addr <= irq_addr && irq_addr < addr + iSize*2;

Expand Down
5 changes: 3 additions & 2 deletions plugins/dfsound/externals.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ typedef struct
unsigned int prevflags:3; // flags from previous block
unsigned int bIgnoreLoop:1; // Ignore loop
unsigned int bNewPitch:1; // pitch changed
unsigned int bStarting:1; // starting after keyon
union {
struct {
int iLeftVolume; // left volume
Expand Down Expand Up @@ -261,9 +262,9 @@ void do_samples(unsigned int cycles_to, int do_sync);
void schedule_next_irq(void);
void check_irq_io(unsigned int addr);

#define do_samples_if_needed(c, sync) \
#define do_samples_if_needed(c, sync, samples) \
do { \
if (sync || (int)((c) - spu.cycles_played) >= 16 * 768) \
if (sync || (int)((c) - spu.cycles_played) >= (samples) * 768) \
do_samples(c, sync); \
} while (0)

Expand Down
22 changes: 13 additions & 9 deletions plugins/dfsound/registers.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
if (val == 0 && (r & 0xff8) == 0xd88)
return;

do_samples_if_needed(cycles, 0);
do_samples_if_needed(cycles, 0, 16);

if(r>=0x0c00 && r<0x0d80) // some channel info?
{
Expand Down Expand Up @@ -213,10 +213,12 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
*/
//-------------------------------------------------//
case H_SPUon1:
do_samples_if_needed(cycles, 0, 2);
SoundOn(0,16,val);
break;
//-------------------------------------------------//
case H_SPUon2:
case H_SPUon2:
do_samples_if_needed(cycles, 0, 2);
SoundOn(16,24,val);
break;
//-------------------------------------------------//
Expand Down Expand Up @@ -309,7 +311,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
// READ REGISTER: called by main emu
////////////////////////////////////////////////////////////////////////

unsigned short CALLBACK SPUreadRegister(unsigned long reg)
unsigned short CALLBACK SPUreadRegister(unsigned long reg, unsigned int cycles)
{
const unsigned long r = reg & 0xffe;

Expand All @@ -319,12 +321,13 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg)
{
case 12: // get adsr vol
{
const int ch=(r>>4)-0xc0;
if(spu.dwNewChannel&(1<<ch)) return 1; // we are started, but not processed? return 1
if((spu.dwChannelsAudible&(1<<ch)) && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well
!spu.s_chan[ch].ADSRX.EnvelopeVol)
return 1;
return (unsigned short)(spu.s_chan[ch].ADSRX.EnvelopeVol>>16);
// this used to return 1 immediately after keyon to deal with
// some poor timing, but that causes Rayman 2 to lose track of
// it's channels on busy scenes and start looping some of them forever
const int ch = (r>>4) - 0xc0;
if (spu.s_chan[ch].bStarting)
do_samples_if_needed(cycles, 0, 2);
return (unsigned short)(spu.s_chan[ch].ADSRX.EnvelopeVol >> 16);
}

case 14: // get loop address
Expand Down Expand Up @@ -404,6 +407,7 @@ static void SoundOn(int start,int end,unsigned short val)
if((val&1) && regAreaGetCh(ch, 6)) // mmm... start has to be set before key on !?!
{
spu.s_chan[ch].bIgnoreLoop = 0;
spu.s_chan[ch].bStarting = 1;
spu.dwNewChannel|=(1<<ch);
}
}
Expand Down
47 changes: 31 additions & 16 deletions plugins/dfsound/spu.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,10 @@ static void StartSoundMain(int ch)
StartADSR(ch);
StartREVERB(ch);

s_chan->prevflags=2;
s_chan->iSBPos=27;
s_chan->spos=0;
s_chan->prevflags = 2;
s_chan->iSBPos = 27;
s_chan->spos = 0;
s_chan->bStarting = 1;

s_chan->pCurr = spu.spuMemC + ((regAreaGetCh(ch, 6) & ~1) << 3);

Expand Down Expand Up @@ -421,8 +422,11 @@ static int decode_block(void *unused, int ch, int *SB)
int ret = 0;

start = s_chan->pCurr; // set up the current pos
if (start == spu.spuMemC) // ?
if (start - spu.spuMemC < 0x1000) { // ?
//log_unhandled("ch%02d plays decode bufs @%05lx\n",
// ch, (long)(start - spu.spuMemC));
ret = 1;
}

if (s_chan->prevflags & 1) // 1: stop/loop
{
Expand All @@ -448,6 +452,7 @@ static int decode_block(void *unused, int ch, int *SB)

s_chan->pCurr = start; // store values for next cycle
s_chan->prevflags = flags;
s_chan->bStarting = 0;

return ret;
}
Expand Down Expand Up @@ -477,6 +482,7 @@ static int skip_block(int ch)

s_chan->pCurr = start;
s_chan->prevflags = flags;
s_chan->bStarting = 0;

return ret;
}
Expand Down Expand Up @@ -794,12 +800,14 @@ static void do_channels(int ns_to)
d = do_samples_default(decode_block, NULL, ch, ns_to,
SB, sinc, &s_chan->spos, &s_chan->iSBPos);

d = MixADSR(&s_chan->ADSRX, d);
if (d < ns_to) {
spu.dwChannelsAudible &= ~(1 << ch);
s_chan->ADSRX.State = ADSR_RELEASE;
s_chan->ADSRX.EnvelopeVol = 0;
memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
if (!s_chan->bStarting) {
d = MixADSR(&s_chan->ADSRX, d);
if (d < ns_to) {
spu.dwChannelsAudible &= ~(1 << ch);
s_chan->ADSRX.State = ADSR_RELEASE;
s_chan->ADSRX.EnvelopeVol = 0;
memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
}
}

if (ch == 1 || ch == 3)
Expand Down Expand Up @@ -965,12 +973,14 @@ static void queue_channel_work(int ns_to, unsigned int silentch)
d = do_samples_skip(ch, ns_to);
work->ch[ch].ns_to = d;

// note: d is not accurate on skip
d = SkipADSR(&s_chan->ADSRX, d);
if (d < ns_to) {
spu.dwChannelsAudible &= ~(1 << ch);
s_chan->ADSRX.State = ADSR_RELEASE;
s_chan->ADSRX.EnvelopeVol = 0;
if (!s_chan->bStarting) {
// note: d is not accurate on skip
d = SkipADSR(&s_chan->ADSRX, d);
if (d < ns_to) {
spu.dwChannelsAudible &= ~(1 << ch);
s_chan->ADSRX.State = ADSR_RELEASE;
s_chan->ADSRX.EnvelopeVol = 0;
}
}
s_chan->bNewPitch = 0;
}
Expand Down Expand Up @@ -1178,6 +1188,11 @@ void do_samples(unsigned int cycles_to, int do_direct)

spu.cycles_played += ns_to * 768;
spu.decode_pos = (spu.decode_pos + ns_to) & 0x1ff;
#if 0
static int ccount; static time_t ctime; ccount++;
if (time(NULL) != ctime)
{ printf("%d\n", ccount); ccount = 0; ctime = time(NULL); }
#endif
}

static void do_samples_finish(int *SSumLR, int ns_to,
Expand Down

0 comments on commit 6183ddf

Please sign in to comment.