summaryrefslogtreecommitdiff
path: root/arm7/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arm7/lib')
-rw-r--r--arm7/lib/include/PM.h9
-rw-r--r--arm7/lib/include/SND.h6
-rw-r--r--arm7/lib/include/SND_channel.h48
-rw-r--r--arm7/lib/include/SND_exChannel.h2
-rw-r--r--arm7/lib/include/registers.h30
-rw-r--r--arm7/lib/include/syscall.h2
-rw-r--r--arm7/lib/src/SND.c201
7 files changed, 265 insertions, 33 deletions
diff --git a/arm7/lib/include/PM.h b/arm7/lib/include/PM.h
new file mode 100644
index 00000000..df2185be
--- /dev/null
+++ b/arm7/lib/include/PM.h
@@ -0,0 +1,9 @@
+#ifndef GUARD_PM_H
+#define GUARD_PM_H
+
+#include "nitro/types.h"
+
+void PMi_SetControl(int ctrl);
+void PMi_ResetControl(int ctrl);
+
+#endif //GUARD_PM_H
diff --git a/arm7/lib/include/SND.h b/arm7/lib/include/SND.h
index c417ab0e..196377ed 100644
--- a/arm7/lib/include/SND.h
+++ b/arm7/lib/include/SND.h
@@ -4,6 +4,12 @@
#include "nitro/types.h"
void SND_Enable(void);
+void SND_Disable(void);
+void SND_Shutdown(void);
+void SND_BeginSleep(void);
+void SND_EndSleep(void);
+void SND_SetMasterPan(int pan);
+void SND_SetMasterVolume(int vol);
void SND_SetOutputSelector(int leftOutputFrom, int rightOutputFrom, int outputCh1ToMixer, int outputCh3ToMixer);
#endif //GUARD_SND_H
diff --git a/arm7/lib/include/SND_channel.h b/arm7/lib/include/SND_channel.h
index 8b74b579..9e015beb 100644
--- a/arm7/lib/include/SND_channel.h
+++ b/arm7/lib/include/SND_channel.h
@@ -8,40 +8,40 @@
void SNDi_SetSurroundDecay(int decay);
void SND_SetupChannelPcm(
- s32 chnIdx,
+ int chnIdx,
const void *data,
- s32 format,
- s32 loop,
- s32 loopStart,
- s32 loopLen,
- s32 volume,
- s32 volumeDiv,
- s32 timer,
- s32 pan
+ int format,
+ int loop,
+ int loopStart,
+ int loopLen,
+ int volume,
+ int volumeDiv,
+ int timer,
+ int pan
);
void SND_SetupChannelPsg(
- s32 chnIdx,
- s32 waveDuty,
- s32 volume,
- s32 volumeDiv,
- s32 timer,
- s32 pan
+ int chnIdx,
+ int waveDuty,
+ int volume,
+ int volumeDiv,
+ int timer,
+ int pan
);
void SND_SetupChannelNoise(
- s32 chnIdx,
- s32 volume,
- s32 volumeDiv,
- s32 timer,
- s32 pan
+ int chnIdx,
+ int volume,
+ int volumeDiv,
+ int timer,
+ int pan
);
-void SND_StopChannel(s32 chnIdx, s32 hold);
+void SND_StopChannel(int chnIdx, int hold);
-void SND_SetChannelVolume(s32 chnIdx, s32 volume, s32 volumeDiv);
-void SND_SetChannelPan(s32 chnIdx, s32 pan);
-void SND_SetChannelTimer(s32 chnIdx, s32 timer);
+void SND_SetChannelVolume(int chnIdx, int volume, int volumeDiv);
+void SND_SetChannelPan(int chnIdx, int pan);
+void SND_SetChannelTimer(int chnIdx, int timer);
u32 SND_GetChannelControl(int idx);
diff --git a/arm7/lib/include/SND_exChannel.h b/arm7/lib/include/SND_exChannel.h
index 038a1a49..66a1d78f 100644
--- a/arm7/lib/include/SND_exChannel.h
+++ b/arm7/lib/include/SND_exChannel.h
@@ -21,7 +21,7 @@ void SND_ReleaseExChannel(struct SNDExChannel *chn);
BOOL SND_IsExChannelActive(struct SNDExChannel *chn);
struct SNDExChannel *SND_AllocExChannel(u32 channelMask, int priority, u32 flags, SNDExChannelCallback callback, void *callbackUserData);
void SND_FreeExChannel(struct SNDExChannel *chn);
-BOOL SND_IsChannelActive(s32 idx);
+BOOL SND_IsChannelActive(int idx);
void SND_InvalidateWave(const void *start, const void *end);
// TODO internal functions, move these so exChannel
diff --git a/arm7/lib/include/registers.h b/arm7/lib/include/registers.h
index e9280957..f30d237a 100644
--- a/arm7/lib/include/registers.h
+++ b/arm7/lib/include/registers.h
@@ -5,14 +5,28 @@
#define reg_EXTKEYIN (*(REGType16v *)0x4000136)
-#define reg_SOUNDxCNT_STAT(x) (*((REGType8v *)0x4000403 + ((int)(x) * 0x10)))
-#define reg_SOUNDxCNT(x) (*((REGType32v *)0x4000400 + ((int)x) * 0x10))
-#define reg_SOUNDxSAD(x) (*((REGType32v *)0x4000404 + ((int)x) * 0x10))
-#define reg_SOUNDxTMR(x) (*((REGType16v *)0x4000408 + ((int)x) * 0x10))
-#define reg_SOUNDxPNT(x) (*((REGType16v *)0x400040A + ((int)x) * 0x10))
-#define reg_SOUNDxLEN(x) (*((REGType32v *)0x400040C + ((int)x) * 0x10))
-
-#define reg_SNDCAPxCNT(x) (*((REGType8v *)0x4000508 + ((int)(x))))
+#define reg_POWCNT2 (*(REGType16v *)0x4000304)
+
+
+#define reg_SOUNDCNT_VOL (*(REGType8v *)0x4000500)
+#define reg_SOUNDCNT_MIX (*(REGType8v *)0x4000501)
+
+#define reg_SOUNDxCNT_VOL(x) (*(REGType8v *)(0x4000400 + ((int)(x) * 0x10)))
+#define reg_SOUNDxCNT_VOLS(x) (*(REGType16v *)(0x4000400 + ((int)(x) * 0x10)))
+#define reg_SOUNDxCNT_PAN(x) (*(REGType8v *)(0x4000402 + ((int)(x) * 0x10)))
+#define reg_SOUNDxCNT_STAT(x) (*(REGType8v *)(0x4000403 + ((int)(x) * 0x10)))
+#define reg_SOUNDxCNT(x) (*(REGType32v *)(0x4000400 + ((int)x) * 0x10))
+#define reg_SOUNDoffCNT(off) (*(REGType32v *)(0x4000400 + (int)(off)))
+#define reg_SOUNDxSAD(x) (*(REGType32v *)(0x4000404 + ((int)x) * 0x10))
+#define reg_SOUNDoffSAD(off) (*(REGType32v *)(0x4000404 + (int)(off)))
+#define reg_SOUNDxTMR(x) (*(REGType16v *)(0x4000408 + ((int)x) * 0x10))
+#define reg_SOUNDoffTMR(off) (*(REGType16v *)(0x4000408 + (int)(off)))
+#define reg_SOUNDxPNT(x) (*(REGType16v *)(0x400040A + ((int)x) * 0x10))
+#define reg_SOUNDoffPNT(off) (*(REGType16v *)(0x400040A + (int)(off)))
+#define reg_SOUNDxLEN(x) (*(REGType32v *)(0x400040C + ((int)x) * 0x10))
+#define reg_SOUNDoffLEN(off) (*(REGType32v *)(0x400040C + (int)(off)))
+
+#define reg_SNDCAPxCNT(x) (*(REGType8v *)(0x4000508 + ((int)(x))))
#define EXTKEYIN_X (1<<0)
#define EXTKEYIN_Y (1<<1)
diff --git a/arm7/lib/include/syscall.h b/arm7/lib/include/syscall.h
index 1ac6fe49..579fd790 100644
--- a/arm7/lib/include/syscall.h
+++ b/arm7/lib/include/syscall.h
@@ -4,5 +4,7 @@
void SVC_WaitByLoop(u32 ct);
u8 SVC_GetVolumeTable(int idx);
u16 SVC_GetPitchTable(int idx);
+void SVC_SoundBiasSet(int step);
+void SVC_SoundBiasReset(int step);
#endif //POKEDIAMOND_ARM7_SYSCALL_H
diff --git a/arm7/lib/src/SND.c b/arm7/lib/src/SND.c
new file mode 100644
index 00000000..6c17fa69
--- /dev/null
+++ b/arm7/lib/src/SND.c
@@ -0,0 +1,201 @@
+#include "SND.h"
+
+#include "registers.h"
+#include "syscall.h"
+
+#include "OS_system.h"
+#include "PM.h"
+#include "SND_exChannel.h"
+#include "SND_work.h"
+#include "SND_channel.h"
+
+static int sMasterPan = -1;
+
+static u8 sOrgVolume[SND_CHANNEL_COUNT];
+static u8 sOrgPan[SND_CHANNEL_COUNT];
+static int sSurroundDecay;
+
+static int CalcSurroundDecay(int vol, int pan);
+
+void SND_SetupChannelPcm(int chnIdx, const void *data, int format, int loop, int loopStart, int loopLength, int volume, int volumeDiv, int timer, int pan) {
+ int off = chnIdx * 0x10;
+
+ sOrgPan[chnIdx] = (u8)pan;
+ if (sMasterPan >= 0)
+ pan = sMasterPan;
+
+ sOrgVolume[chnIdx] = (u8)volume;
+ if (sSurroundDecay > 0 && (1 << chnIdx) & 0xFFF5) {
+ volume = CalcSurroundDecay(volume, pan);
+ }
+
+ reg_SOUNDoffCNT(off) = (u32)((format << 29) | (loop << 27) | (pan << 16) | (volumeDiv << 8) | (volume));
+ reg_SOUNDoffTMR(off) = (u16)(0x10000 - timer);
+ reg_SOUNDoffPNT(off) = (u16)loopStart;
+ reg_SOUNDoffLEN(off) = (u32)loopLength;
+ reg_SOUNDoffSAD(off) = (u32)data;
+}
+
+void SND_SetupChannelPsg(int chnIdx, int duty, int volume, int volumeDiv, int timer, int pan) {
+ int off = chnIdx * 0x10;
+
+ sOrgPan[chnIdx] = (u8)pan;
+ if (sMasterPan >= 0)
+ pan = sMasterPan;
+
+ sOrgVolume[chnIdx] = (u8)volume;
+ if (sSurroundDecay > 0 && (1 << chnIdx) & 0xFFF5) {
+ volume = CalcSurroundDecay(volume, pan);
+ }
+
+ reg_SOUNDoffCNT(off) = (u32)(0x60000000 | (duty << 24) | (pan << 16) | (volumeDiv << 8) | volume);
+ reg_SOUNDoffTMR(off) = (u16)(0x10000 - timer);
+}
+
+void SND_SetupChannelNoise(int chnIdx, int volume, int volumeDiv, int timer, int pan) {
+ int off = chnIdx * 0x10;
+
+ sOrgPan[chnIdx] = (u8)pan;
+ if (sMasterPan >= 0)
+ pan = sMasterPan;
+
+ sOrgVolume[chnIdx] = (u8)volume;
+ if (sSurroundDecay > 0 && (1 << chnIdx) & 0xFFF5) {
+ volume = CalcSurroundDecay(volume, pan);
+ }
+
+ reg_SOUNDoffCNT(off) = (u32)(0x60000000 | (pan << 16) | (volumeDiv << 8) | volume);
+ reg_SOUNDoffTMR(off) = (u16)(0x10000 - timer);
+}
+
+void SND_StopChannel(int idx, int hold) {
+ vu32 *reg = &reg_SOUNDxCNT(idx);
+
+ u32 v = *reg;
+
+ // disable channel
+ v &= ~0x80000000;
+
+ // set hold flag
+ if (hold & 1)
+ v |= 0x8000;
+
+ *reg = v;
+}
+
+void SND_SetChannelVolume(int chnIdx, int vol, int volDiv) {
+ sOrgVolume[chnIdx] = (u8)vol;
+
+ if (sSurroundDecay > 0 && (1 << chnIdx) & 0xFFF5) {
+ int pan = reg_SOUNDxCNT_PAN(chnIdx);
+ vol = CalcSurroundDecay(vol, pan);
+ }
+
+ reg_SOUNDxCNT_VOLS(chnIdx) = (u16)((volDiv << 8) | vol);
+}
+
+void SND_SetChannelTimer(int chnIdx, int timer) {
+ reg_SOUNDxTMR(chnIdx) = (u16)(0x10000 - timer);
+}
+
+void SND_SetChannelPan(int chnIdx, int pan) {
+ sOrgPan[chnIdx] = (u8)pan;
+
+ if (sMasterPan >= 0) {
+ pan = sMasterPan;
+ }
+
+ reg_SOUNDxCNT_PAN(chnIdx) = (u8)pan;
+
+ if (sSurroundDecay > 0 && (1 << chnIdx) & 0xFFF5) {
+ reg_SOUNDxCNT_VOL(chnIdx) = (u8)CalcSurroundDecay(sOrgVolume[chnIdx], pan);
+ }
+}
+
+BOOL SND_IsChannelActive(int chnIdx) {
+ return (reg_SOUNDxCNT_STAT(chnIdx) & 0x80) != 0;
+}
+
+void SND_SetMasterPan(int pan) {
+ sMasterPan = pan;
+
+ if (pan >= 0) {
+ for (int i = 0; i < SND_CHANNEL_COUNT; i++) {
+ reg_SOUNDxCNT_PAN(i) = (u8)pan;
+ }
+ } else {
+ for (int i = 0; i < SND_CHANNEL_COUNT; i++) {
+ reg_SOUNDxCNT_PAN(i) = sOrgPan[i];
+ }
+ }
+}
+
+u32 SND_GetChannelControl(int chnIdx) {
+ return reg_SOUNDxCNT(chnIdx);
+}
+
+void SNDi_SetSurroundDecay(int decay) {
+ sSurroundDecay = decay;
+
+ for (int i = 0; i < SND_CHANNEL_COUNT; i++) {
+ // do not process channel 1+3 (capture playback channels)
+ if ((1 << i) & 0xFFF5) {
+ int pan = reg_SOUNDxCNT_PAN(i);
+ reg_SOUNDxCNT_VOL(i) = (u8)CalcSurroundDecay(sOrgVolume[i], pan);
+ }
+ }
+}
+
+static int CalcSurroundDecay(int vol, int pan) {
+ if (pan < 24) {
+ return vol * (sSurroundDecay * (pan + 40) + ((0x7FFF - sSurroundDecay) << 6)) >> 21;
+ } else if (pan <= 104) {
+ return vol;
+ } else {
+ return vol * (-sSurroundDecay * (pan - 40) + ((sSurroundDecay + 0x7FFF) << 6)) >> 21;
+ }
+}
+
+void SND_Enable(void) {
+ reg_SOUNDCNT_MIX |= 0x80;
+}
+
+void SND_Disable(void) {
+ reg_SOUNDCNT_MIX &= ~0x80;
+}
+
+void SND_Shutdown(void) {
+ SND_Disable();
+
+ for (int i = 0; i < SND_CHANNEL_COUNT; i++) {
+ SND_StopChannel(i, 1);
+ }
+
+ reg_SNDCAPxCNT(0) = 0;
+ reg_SNDCAPxCNT(1) = 0;
+}
+
+void SND_BeginSleep(void) {
+ SND_Disable();
+ SVC_SoundBiasReset(0x80);
+ OS_SpinWait(0x40000);
+ PMi_ResetControl(1);
+ reg_POWCNT2 &= ~1;
+}
+
+void SND_EndSleep(void) {
+ reg_POWCNT2 |= 1; // enable speakers
+ PMi_SetControl(1);
+ SVC_SoundBiasSet(0x100);
+ OS_SpinWait(0x7AB80); // what does this wait for and how long does it wait?
+ SND_Enable();
+}
+
+void SND_SetMasterVolume(int vol) {
+ reg_SOUNDCNT_VOL = (u8)vol;
+}
+
+void SND_SetOutputSelector(int leftOutputFrom, int rightOutputFrom, int outputCh1ToMixer, int outputCh3ToMixer) {
+ int masterEnable = (reg_SOUNDCNT_MIX & 0x80) ? 1 : 0;
+ reg_SOUNDCNT_MIX = (u8)((masterEnable << 7) | (outputCh3ToMixer << 5) | (outputCh1ToMixer << 4) | (rightOutputFrom << 2) | (leftOutputFrom));
+}