From 93e3f490527942916fca0563bc681d6d3cfdcd95 Mon Sep 17 00:00:00 2001 From: StapleButter Date: Sat, 13 Dec 2014 02:39:58 +0100 Subject: [PATCH] Stereo sound. Attempts at fixing SPC timing. It's still off, will need investigation. Sound still somewhat crackling. This is as good as we can get with CSND I guess. --- source/audio.c | 33 ++++++++++++++++++++++----------- source/cpu.inc | 1 + source/cpu.s | 38 ++++++++++++++++++-------------------- source/main.c | 40 +++++++++++++++++++++++++++++++++++++--- source/ppu.c | 5 +++-- source/snes.c | 3 +++ source/snes.h | 3 ++- source/spc700.s | 13 +++++++++++++ 8 files changed, 99 insertions(+), 37 deletions(-) diff --git a/source/audio.c b/source/audio.c index 3a72ea5..d855c73 100644 --- a/source/audio.c +++ b/source/audio.c @@ -57,10 +57,6 @@ void Audio_Init() if (!res) { Audio_Type = 1; - - // TODO: figure out how to do panning, if it's possible at all? - //CSND_playsound(8, 1, 1/*PCM16*/, 31994, (u32*)Audio_LeftBuffer, (u32*)Audio_LeftBuffer, MIXBUFSIZE*4, 2, 0); - //CSND_playsound(9, 1, 1/*PCM16*/, 31994, (u32*)Audio_RightBuffer, (u32*)Audio_RightBuffer, MIXBUFSIZE*4, 2, 0); } // TODO: DSP black magic @@ -105,7 +101,22 @@ void Audio_Mix() cursample &= ((MIXBUFSIZE << 1) - 1); } -void myCSND_playsound(u32 channel, u32 looping, u32 encoding, u32 samplerate, u32 *vaddr0, u32 *vaddr1, u32 totalbytesize, u32 unk0, u32 unk1) +// volume control +void myCSND_sharedmemtype0_cmd9(u32 channel, u16 leftvol, u16 rightvol) +{ + u32 cmdparams[0x18>>2]; + + memset(cmdparams, 0, 0x18); + + cmdparams[0] = channel & 0x1f; + cmdparams[1] = leftvol | (rightvol<<16); + + CSND_writesharedmem_cmdtype0(0x9, (u8*)&cmdparams); +} + +// tweaked CSND_playsound() version. Allows setting multiple channels and calling updatestate once. +// the last two parameters are also repurposed for volume control +void myCSND_playsound(u32 channel, u32 looping, u32 encoding, u32 samplerate, u32 *vaddr0, u32 *vaddr1, u32 totalbytesize, u32 leftvol, u32 rightvol) { u32 physaddr0 = 0; u32 physaddr1 = 0; @@ -113,15 +124,15 @@ void myCSND_playsound(u32 channel, u32 looping, u32 encoding, u32 samplerate, u3 physaddr0 = osConvertVirtToPhys((u32)vaddr0); physaddr1 = osConvertVirtToPhys((u32)vaddr1); - CSND_sharedmemtype0_cmde(channel, looping, encoding, samplerate, unk0, unk1, physaddr0, physaddr1, totalbytesize); + CSND_sharedmemtype0_cmde(channel, looping, encoding, samplerate, 2/*unk0*/, 1/*unk1*/, physaddr0, physaddr1, totalbytesize); CSND_sharedmemtype0_cmd8(channel, samplerate); if(looping) { - if(physaddr1>physaddr0)totalbytesize = (u32)physaddr1 - (u32)physaddr0; + if(physaddr1>physaddr0)totalbytesize -= (u32)physaddr1 - (u32)physaddr0; CSND_sharedmemtype0_cmd3(channel, physaddr1, totalbytesize); } CSND_sharedmemtype0_cmd8(channel, samplerate); - CSND_sharedmemtype0_cmd9(channel, 0xffff); + myCSND_sharedmemtype0_cmd9(channel, leftvol, rightvol); // volume CSND_setchannel_playbackstate(channel, 1); } @@ -136,10 +147,10 @@ void Audio_MixFinish() { int newbuffer = curbuffer^1; - myCSND_playsound(8+newbuffer, 1, 1/*PCM16*/, 32000, (u32*)&Audio_Buffer[0], (u32*)&Audio_Buffer[(MIXBUFSIZE*2)-1], MIXBUFSIZE*4, 2, 0); - myCSND_playsound(10+newbuffer, 1, 1/*PCM16*/, 32000, (u32*)&Audio_Buffer[MIXBUFSIZE*2], (u32*)&Audio_Buffer[(MIXBUFSIZE*4)-1], MIXBUFSIZE*4, 2, 0); + myCSND_playsound(8+newbuffer, 1, CSND_ENCODING_PCM16, 32000, (u32*)&Audio_Buffer[0], (u32*)&Audio_Buffer[(MIXBUFSIZE*2)-1], MIXBUFSIZE*4, 0xFFFF, 0); + myCSND_playsound(10+newbuffer, 1, CSND_ENCODING_PCM16, 32000, (u32*)&Audio_Buffer[MIXBUFSIZE*2], (u32*)&Audio_Buffer[(MIXBUFSIZE*4)-1], MIXBUFSIZE*4, 0, 0xFFFF); - CSND_setchannel_playbackstate(8+curbuffer, 0); + CSND_setchannel_playbackstate(8+curbuffer, 0); CSND_setchannel_playbackstate(10+curbuffer, 0); CSND_sharedmemtype0_cmdupdatestate(0); diff --git a/source/cpu.inc b/source/cpu.inc index 501223c..4a20c49 100644 --- a/source/cpu.inc +++ b/source/cpu.inc @@ -48,6 +48,7 @@ snesStatus .req r4 @ status data is before this pointer .equ IRQ_VMatch, -24 .equ SPC_LastCycle, -28 .equ SPC_CycleRatio, -32 +.equ SPC_CyclesPerLine, -36 .equ flagC, 0x01 .equ flagZ, 0x02 diff --git a/source/cpu.s b/source/cpu.s index 6b78169..8f1e1b4 100644 --- a/source/cpu.s +++ b/source/cpu.s @@ -676,8 +676,6 @@ CPU_MainLoop: lineloop1: strh r3, [snesStatus, #VCount] - mov r0, snesCycles, asr #16 - str r0, [snesStatus, #SPC_LastCycle] @ IRQ check ldrb r0, [snesStatus, #IRQCond] @@ -730,16 +728,17 @@ lineloop1: bl CPU_Run @ run the SPC700 - ldr r0, [snesStatus, #SPC_LastCycle] - rsb r0, r0, snesCycles, asr #16 + mov r0, snesCycles, asr #16 ldr r1, [snesStatus, #SPC_CycleRatio] - mul r0, r1, r0 + mul r2, r1, r0 + ldr r1, [snesStatus, #SPC_LastCycle] + sub r0, r2, r1 + ldr r1, [snesStatus, #SPC_CyclesPerLine] + sub r2, r2, r1 + str r2, [snesStatus, #SPC_LastCycle] movs r0, r0, asr #24 - ble _1_nospc - bl SPC_Run - mov r0, snesCycles, asr #16 - str r0, [snesStatus, #SPC_LastCycle] - _1_nospc: + movmis r0, #0 + blne SPC_Run ldr r0, =((1364<<16) + 340) sub snesCycles, snesCycles, r0 @@ -767,8 +766,6 @@ lineloop1: lineloop2: strh r3, [snesStatus, #VCount] - mov r0, snesCycles, asr #16 - str r0, [snesStatus, #SPC_LastCycle] @ IRQ check ldrb r0, [snesStatus, #IRQCond] @@ -806,16 +803,17 @@ lineloop2: bl CPU_Run @ run the SPC700 - ldr r0, [snesStatus, #SPC_LastCycle] - rsb r0, r0, snesCycles, asr #16 + mov r0, snesCycles, asr #16 ldr r1, [snesStatus, #SPC_CycleRatio] - mul r0, r1, r0 + mul r2, r1, r0 + ldr r1, [snesStatus, #SPC_LastCycle] + sub r0, r2, r1 + ldr r1, [snesStatus, #SPC_CyclesPerLine] + sub r2, r2, r1 + str r2, [snesStatus, #SPC_LastCycle] movs r0, r0, asr #24 - ble _2_nospc - bl SPC_Run - mov r0, snesCycles, asr #16 - str r0, [snesStatus, #SPC_LastCycle] - _2_nospc: + movmis r0, #0 + blne SPC_Run ldr r0, =(1364<<16) sub snesCycles, snesCycles, r0 diff --git a/source/main.c b/source/main.c index f06640f..040233e 100644 --- a/source/main.c +++ b/source/main.c @@ -98,7 +98,10 @@ int exitspc = 0; void SPCThread(u32 blarg) { int i; - + /*u64 lastmixtime = svcGetSystemTick(); + u32 mixtimes[2048]; + memset(mixtimes, 0, 2048*4); + int k = 0;*/ while (!exitspc) { svcWaitSynchronization(SPCSync, U64_MAX); @@ -113,6 +116,27 @@ void SPCThread(u32 blarg) } Audio_MixFinish(); + /*if (k < 2048) + { + u64 t = svcGetSystemTick(); + u32 diff = (u32)(t-lastmixtime); + lastmixtime = t; + mixtimes[k] = diff; + k++; + if (k >= 2048) + { + double avg = 0; + int m; + for (m = 0; m < 2048; m++) avg += (double)mixtimes[m]; + avg /= 2048.0f; + avg = (avg * 1000.0f) / 268123480.0f; + // avg = time in ms for 512 samples + double freq = (1000.0f * 512.0f) / avg; + bprintf("time: %f | freq: %f\n", avg, freq); + + k = 0; + } + }*/ } else Audio_Pause(); @@ -734,13 +758,14 @@ void reportshit(u32 pc, u32 a, u32 y) oldshiz = *(u32*)&SNES_SysRAM[0x300];*/ //bprintf("!! IRQ %04X %02X\n", SNES_Status->IRQ_CurHMatch, SNES_Status->IRQCond); //pause=1; - bprintf("TSX S=%04X X=%04X P=%04X %04X\n", pc>>16, a, y&0xFFFF, y>>16); + //bprintf("TSX S=%04X X=%04X P=%04X %04X\n", pc>>16, a, y&0xFFFF, y>>16); + bprintf("SPC: %d %d\n", pc, a); } int reported2=0; void reportshit2(u32 pc, u32 a, u32 y) { - bprintf("TSC S=%04X A=%04X P=%04X %04X\n", pc>>16, a, y&0xFFFF, y>>16); + //bprintf("TSC S=%04X A=%04X P=%04X %04X\n", pc>>16, a, y&0xFFFF, y>>16); } @@ -854,6 +879,15 @@ int main() CPU_MainLoop(); // runs the SNES for one frame. Handles PPU rendering. ContinueRendering(); + /*{ + extern u32 dbgcycles, nruns; + bprintf("SPC: %d / 17066 %08X\n", dbgcycles, SNES_Status->SPC_CycleRatio); + dbgcycles = 0; nruns=0; + }*/ + /*if (press & KEY_X) SNES_Status->SPC_CycleRatio+=0x1000; + if (press & KEY_Y) SNES_Status->SPC_CycleRatio-=0x1000; + SNES_Status->SPC_CyclesPerLine = SNES_Status->SPC_CycleRatio*1364;*/ + // SRAM autosave check // TODO: also save SRAM under certain circumstances (pausing, returning to home menu, etc) framecount++; diff --git a/source/ppu.c b/source/ppu.c index 36f5197..f0279c1 100644 --- a/source/ppu.c +++ b/source/ppu.c @@ -349,12 +349,13 @@ void PPU_LatchHVCounters() void SPC_Compensate() { - int torun = (SNES_Status->HCount - SNES_Status->SPC_LastCycle) * SNES_Status->SPC_CycleRatio; + int cyclenow = (SNES_Status->HCount * SNES_Status->SPC_CycleRatio); + int torun = cyclenow - SNES_Status->SPC_LastCycle; torun >>= 24; if (torun > 0) { SPC_Run(torun); - SNES_Status->SPC_LastCycle = SNES_Status->HCount; + SNES_Status->SPC_LastCycle = cyclenow; } } diff --git a/source/snes.c b/source/snes.c index 3a5e768..e3727fa 100644 --- a/source/snes.c +++ b/source/snes.c @@ -110,6 +110,9 @@ bool SNES_LoadROM(char* path) SNES_Status->ScreenHeight = 224; SNES_Status->SPC_CycleRatio = ROM_Region ? 0x000C51D9 : 0x000C39C6; + SNES_Status->SPC_CycleRatio += 0x1000; // hax -- TODO investigate why we need this to run at a somewhat proper rate + SNES_Status->SPC_CyclesPerLine = SNES_Status->SPC_CycleRatio * 1364; + //SNES_Status->SPC_CyclesPerLine = ROM_Region ? 0x41A41A42 : 0x4123D3B5; SNES_SRAMMask = sramsize ? ((1024 << sramsize) - 1) : 0; SNES_SRAMMask &= 0x000FFFFF; diff --git a/source/snes.h b/source/snes.h index 83c288c..abb428f 100644 --- a/source/snes.h +++ b/source/snes.h @@ -24,8 +24,9 @@ typedef struct { + s32 SPC_CyclesPerLine; // -36 | cycleratio * 1364 s32 SPC_CycleRatio; // -32 - s32 SPC_LastCycle; // -28 | CPU cycle count at last SPC run + s32 SPC_LastCycle; // -28 | SPC cycle count (<<24) at last SPC run u16 IRQ_VMatch; // -24 u16 IRQ_HMatch; // -22 diff --git a/source/spc700.s b/source/spc700.s index 5ce0232..6616490 100644 --- a/source/spc700.s +++ b/source/spc700.s @@ -34,6 +34,13 @@ SPC_Regs: .long 0,0,0,0,0,0,0,0 +.global dbgcycles +dbgcycles: + .long 0 +.global nruns +nruns: + .long 0 + .global SPC_TimerReload .global SPC_TimerVal .global SPC_TimerEnable @@ -416,6 +423,12 @@ noTimer1: addeq r1, r1, r2 str r1, [memory, #-12] noTimer2: + + @debug + @ldr r0, =dbgcycles + @ldr r1, [r0] + @add r1, r1, r3 + @str r1, [r0] ldr r0, [memory, #-4] @ elapsed cycles add r0, r0, r3