Skip to content

Commit

Permalink
Stereo sound.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Arisotura committed Dec 13, 2014
1 parent e25cd2e commit 93e3f49
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 37 deletions.
33 changes: 22 additions & 11 deletions source/audio.c
Expand Up @@ -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
Expand Down Expand Up @@ -105,23 +101,38 @@ 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;

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);
}

Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions source/cpu.inc
Expand Up @@ -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
Expand Down
38 changes: 18 additions & 20 deletions source/cpu.s
Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down
40 changes: 37 additions & 3 deletions source/main.c
Expand Up @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -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);
}


Expand Down Expand Up @@ -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++;
Expand Down
5 changes: 3 additions & 2 deletions source/ppu.c
Expand Up @@ -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;
}
}

Expand Down
3 changes: 3 additions & 0 deletions source/snes.c
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion source/snes.h
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions source/spc700.s
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 93e3f49

Please sign in to comment.