]> Chaos Git - corbenik/ctrulib.git/commitdiff
CSND: IMA-ADPCM playback support, really fix looping
authorfincs <fincs.alt1@gmail.com>
Sat, 3 Jan 2015 18:27:27 +0000 (19:27 +0100)
committerfincs <fincs.alt1@gmail.com>
Tue, 20 Jan 2015 16:55:24 +0000 (17:55 +0100)
libctru/include/3ds/services/csnd.h
libctru/source/services/csnd.c

index 4c20f6f13e8a715df1f7aa936580b3b8cddecc77..e0e24069283a95a083eb0ec29a4cd0a3fe0ee19e 100644 (file)
@@ -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);
index 8d97a6bd958de228d03aadf7e07697d1177bb9e7..e19a6176e40be2ca045efeb75fd332b3cb83c8f0 100644 (file)
@@ -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;