From cbc1c645a6d739f2ef949eda9ee922e7e57176da Mon Sep 17 00:00:00 2001 From: fincs Date: Sat, 3 Jan 2015 19:27:27 +0100 Subject: [PATCH] CSND: IMA-ADPCM playback support, really fix looping --- libctru/include/3ds/services/csnd.h | 16 +++++++++--- libctru/source/services/csnd.c | 39 +++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/libctru/include/3ds/services/csnd.h b/libctru/include/3ds/services/csnd.h index 4c20f6f..e0e2406 100644 --- a/libctru/include/3ds/services/csnd.h +++ b/libctru/include/3ds/services/csnd.h @@ -14,15 +14,23 @@ typedef enum CSND_ENCODING_PSG, // Similar to DS? }; +enum +{ + CSND_LOOPMODE_MANUAL = 0, + CSND_LOOPMODE_NORMAL, + CSND_LOOPMODE_ONESHOT, + CSND_LOOPMODE_NORELOAD, +}; + #define SOUND_CHANNEL(n) ((u32)(n) & 0x1F) #define SOUND_FORMAT(n) ((u32)(n) << 12) +#define SOUND_LOOPMODE(n) ((u32)(n) << 10) enum { SOUND_LINEAR_INTERP = BIT(6), - SOUND_REPEAT = BIT(10), - SOUND_CONST_BLOCK_SIZE = BIT(11), - SOUND_ONE_SHOT = 0, + SOUND_REPEAT = SOUND_LOOPMODE(CSND_LOOPMODE_NORMAL), + SOUND_ONE_SHOT = SOUND_LOOPMODE(CSND_LOOPMODE_ONESHOT), SOUND_FORMAT_8BIT = SOUND_FORMAT(CSND_ENCODING_PCM8), SOUND_FORMAT_16BIT = SOUND_FORMAT(CSND_ENCODING_PCM16), SOUND_FORMAT_ADPCM = SOUND_FORMAT(CSND_ENCODING_ADPCM), @@ -76,6 +84,8 @@ void CSND_ChnSetBlock(u32 channel, int block, u32 physaddr, u32 size); void CSND_ChnSetVol(u32 channel, u16 left, u16 right); void CSND_ChnSetTimer(u32 channel, u32 timer); void CSND_ChnSetDuty(u32 channel, u32 duty); +void CSND_ChnSetAdpcmState(u32 channel, int block, int sample, int index); +void CSND_ChnSetAdpcmReload(u32 channel, bool reload); void CSND_ChnConfig(u32 flags, u32 physaddr0, u32 physaddr1, u32 totalbytesize); Result CSND_UpdateChnInfo(bool waitDone); diff --git a/libctru/source/services/csnd.c b/libctru/source/services/csnd.c index 8d97a6b..e19a617 100644 --- a/libctru/source/services/csnd.c +++ b/libctru/source/services/csnd.c @@ -272,6 +272,31 @@ void CSND_ChnSetDuty(u32 channel, u32 duty) csndWriteChnCmd(0x7, (u8*)&cmdparams); } +void CSND_ChnSetAdpcmState(u32 channel, int block, int sample, int index) +{ + u32 cmdparams[0x18>>2]; + + memset(cmdparams, 0, 0x18); + + cmdparams[0] = channel & 0x1f; + cmdparams[1] = sample & 0xFFFF; + cmdparams[2] = index & 0x7F; + + csndWriteChnCmd(block ? 0xC : 0xB, (u8*)&cmdparams); +} + +void CSND_ChnSetAdpcmReload(u32 channel, bool reload) +{ + u32 cmdparams[0x18>>2]; + + memset(cmdparams, 0, 0x18); + + cmdparams[0] = channel & 0x1f; + cmdparams[1] = reload ? 1 : 0; + + csndWriteChnCmd(0xD, (u8*)&cmdparams); +} + void CSND_ChnConfig(u32 flags, u32 physaddr0, u32 physaddr1, u32 totalbytesize) { u32 cmdparams[0x18>>2]; @@ -305,10 +330,20 @@ Result csndChnPlaySound(int chn, u32 flags, u32 sampleRate, void* data0, void* d u32 paddr0 = 0, paddr1 = 0; - if (((flags >> 12) & 3) != CSND_ENCODING_PSG) + int encoding = (flags >> 12) & 3; + int loopMode = (flags >> 10) & 3; + + if (encoding != CSND_ENCODING_PSG) { if (data0) paddr0 = osConvertVirtToPhys((u32)data0); if (data1) paddr1 = osConvertVirtToPhys((u32)data1); + + if (encoding == CSND_ENCODING_ADPCM) + { + int adpcmSample = ((s16*)data0)[-2]; + int adpcmIndex = ((u8*)data0)[-2]; + CSND_ChnSetAdpcmState(chn, 0, adpcmSample, adpcmIndex); + } } u32 timer = CSND_TIMER(sampleRate); @@ -319,7 +354,7 @@ Result csndChnPlaySound(int chn, u32 flags, u32 sampleRate, void* data0, void* d CSND_ChnConfig(flags, paddr0, paddr1, size); - if ((flags & SOUND_REPEAT) && !(flags & SOUND_CONST_BLOCK_SIZE) && paddr1 > paddr0) + if (loopMode == CSND_LOOPMODE_NORMAL && paddr1 > paddr0) { // Now that the first block is playing, configure the size of the subsequent blocks size -= paddr1 - paddr0;