]> Chaos Git - corbenik/ctrulib.git/commitdiff
CSND: many looping-related discoveries
authorfincs <fincs.alt1@gmail.com>
Fri, 2 Jan 2015 22:18:39 +0000 (23:18 +0100)
committerfincs <fincs.alt1@gmail.com>
Tue, 20 Jan 2015 16:54:35 +0000 (17:54 +0100)
libctru/include/3ds/services/csnd.h
libctru/source/services/csnd.c

index a28fc19da70934296ce18608e1125b4930cf56fb..9d34d139c281037f839f14a4036647fdfa495a18 100644 (file)
@@ -6,18 +6,30 @@
 
 #define CSND_TIMER(n) (0x3FEC3FC / ((u32)(n)))
 
-typedef enum{
-    CSND_LOOP_DISABLE,
-    CSND_LOOP_ENABLE,
-} CSND_LOOPING;
-
-typedef enum{
+typedef enum
+{
     CSND_ENCODING_PCM8,
     CSND_ENCODING_PCM16,
-    CSND_ENCODING_IMA_ADPCM,
+    CSND_ENCODING_ADPCM, // IMA-ADPCM
     CSND_ENCODING_PSG, // Similar to DS?
 } CSND_ENCODING;
 
+#define SOUND_CHANNEL(n) ((u32)(n) & 0x1F)
+#define SOUND_FORMAT(n) ((u32)(n) << 12)
+
+enum
+{
+       SOUND_LINEAR_INTERP = BIT(6),
+       SOUND_REPEAT = BIT(10),
+       SOUND_CONST_BLOCK_SIZE = BIT(11),
+       SOUND_ONE_SHOT = 0,
+       SOUND_FORMAT_8BIT = SOUND_FORMAT(CSND_ENCODING_PCM8),
+       SOUND_FORMAT_16BIT = SOUND_FORMAT(CSND_ENCODING_PCM16),
+       SOUND_FORMAT_ADPCM = SOUND_FORMAT(CSND_ENCODING_ADPCM),
+       SOUND_FORMAT_PSG = SOUND_FORMAT(CSND_ENCODING_PSG),
+       SOUND_ENABLE = BIT(14),
+};
+
 typedef union
 {
        u32 value[3];
@@ -47,14 +59,14 @@ Result csndExecChnCmds(bool waitDone);
 
 void CSND_ChnSetPlayStateR(u32 channel, u32 value);
 void CSND_ChnSetPlayState(u32 channel, u32 value);
-void CSND_ChnSetLoop(u32 channel, u32 physaddr, u32 size);
+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_ChnConfig(u32 channel, u32 looping, u32 encoding, u32 timer, u32 unk0, u32 unk1, u32 physaddr0, u32 physaddr1, u32 totalbytesize);
+void CSND_ChnConfig(u32 flags, u32 physaddr0, u32 physaddr1, u32 totalbytesize);
 
 Result CSND_UpdateChnInfo(bool waitDone);
 
-Result csndChnPlaySound(u32 channel, u32 looping, u32 encoding, u32 samplerate, u32 *vaddr0, u32 *vaddr1, u32 totalbytesize, u32 unk0, u32 unk1);
+Result csndChnPlaySound(int chn, u32 flags, u32 sampleRate, void* data0, void* data1, u32 size);
 
 CSND_ChnInfo* csndChnGetInfo(u32 channel); // Requires previous CSND_UpdateChnInfo()
 
index c8aacfdf488415ea8f096d934d5c387d7494a478..bea23fd0ffa9a29def1bfc1acaff553ceb88dd07 100644 (file)
@@ -223,7 +223,7 @@ void CSND_ChnSetPlayState(u32 channel, u32 value)
        csndWriteChnCmd(0x1, (u8*)&cmdparams);
 }
 
-void CSND_ChnSetLoop(u32 channel, u32 physaddr, u32 size)
+void CSND_ChnSetBlock(u32 channel, int block, u32 physaddr, u32 size)
 {
        u32 cmdparams[0x18>>2];
 
@@ -233,7 +233,7 @@ void CSND_ChnSetLoop(u32 channel, u32 physaddr, u32 size)
        cmdparams[1] = physaddr;
        cmdparams[2] = size;
 
-       csndWriteChnCmd(0x3, (u8*)&cmdparams);
+       csndWriteChnCmd(block ? 0x3 : 0xA, (u8*)&cmdparams);
 }
 
 void CSND_ChnSetVol(u32 channel, u16 left, u16 right)
@@ -260,23 +260,15 @@ void CSND_ChnSetTimer(u32 channel, u32 timer)
        csndWriteChnCmd(0x8, (u8*)&cmdparams);
 }
 
-void CSND_ChnConfig(u32 channel, u32 looping, u32 encoding, u32 timer, u32 unk0, u32 unk1, u32 physaddr0, u32 physaddr1, u32 totalbytesize)
+void CSND_ChnConfig(u32 flags, u32 physaddr0, u32 physaddr1, u32 totalbytesize)
 {
        u32 cmdparams[0x18>>2];
 
        memset(cmdparams, 0, 0x18);
 
-       cmdparams[0] = channel & 0x1f;
-       cmdparams[0] |= (unk0 & 0xf) << 6;
-       if (!looping) cmdparams[0] |= 2 << 10;
-       if (looping) cmdparams[0] |= 1 << 10;
-       cmdparams[0] |= (encoding & 3) << 12;
-       cmdparams[0] |= (unk1 & 3) << 14;
-
-       if (timer < 0x42) timer = 0x42;
-       if (timer > 0xffff) timer = 0xffff;
-       cmdparams[0] |= timer<<16;
-
+       cmdparams[0] = flags;
+       cmdparams[1] = 0; // Unknown
+       cmdparams[2] = 0; // Unknown
        cmdparams[3] = physaddr0;
        cmdparams[4] = physaddr1;
        cmdparams[5] = totalbytesize;
@@ -294,25 +286,35 @@ Result CSND_UpdateChnInfo(bool waitDone)
        return csndExecChnCmds(waitDone);
 }
 
-Result csndChnPlaySound(u32 channel, u32 looping, u32 encoding, u32 samplerate, u32 *vaddr0, u32 *vaddr1, u32 totalbytesize, u32 unk0, u32 unk1)
+Result csndChnPlaySound(int chn, u32 flags, u32 sampleRate, void* data0, void* data1, u32 size)
 {
-       if (!(csndChannels & BIT(channel)))
+       if (!(csndChannels & BIT(chn)))
                return 1;
 
-       u32 physaddr0 = 0;
-       u32 physaddr1 = 0;
+       u32 paddr0 = 0, paddr1 = 0;
+
+       if (((flags >> 12) & 3) != CSND_ENCODING_PSG)
+       {
+               if (data0) paddr0 = osConvertVirtToPhys((u32)data0);
+               if (data1) paddr1 = osConvertVirtToPhys((u32)data1);
+       }
 
-       physaddr0 = osConvertVirtToPhys((u32)vaddr0);
-       physaddr1 = osConvertVirtToPhys((u32)vaddr1);
+       u32 timer = CSND_TIMER(sampleRate);
+       if (timer < 0x0042) timer = 0x0042;
+       else if (timer > 0xFFFF) timer = 0xFFFF;
+       flags &= ~0xFFFF001F;
+       flags |= SOUND_ENABLE | SOUND_CHANNEL(chn) | (timer << 16);
 
-       CSND_ChnConfig(channel, looping, encoding, CSND_TIMER(samplerate), unk0, unk1, physaddr0, physaddr1, totalbytesize);
-       if(looping)
+       CSND_ChnConfig(flags, paddr0, paddr1, size);
+
+       if ((flags & SOUND_REPEAT) && !(flags & SOUND_CONST_BLOCK_SIZE) && paddr1 > paddr0)
        {
-               if(physaddr1>physaddr0)totalbytesize-= (u32)physaddr1 - (u32)physaddr0;
-               CSND_ChnSetLoop(channel, physaddr1, totalbytesize);
+               // Now that the first block is playing, configure the size of the subsequent blocks
+               size -= paddr1 - paddr0;
+               CSND_ChnSetBlock(chn, 1, paddr1, size);
        }
-       CSND_ChnSetVol(channel, 0xFFFF, 0xFFFF);
-       CSND_ChnSetPlayState(channel, 1);
+
+       CSND_ChnSetVol(chn, 0xFFFF, 0xFFFF);
 
        return csndExecChnCmds(true);
 }