aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/NDS.cpp47
-rw-r--r--src/NDS.h28
-rw-r--r--src/SPU.cpp265
-rw-r--r--src/SPU.h35
-rw-r--r--src/wx/main.cpp39
-rw-r--r--src/wx/main.h6
6 files changed, 335 insertions, 85 deletions
diff --git a/src/NDS.cpp b/src/NDS.cpp
index d8f346e..623f025 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -25,6 +25,7 @@
#include "DMA.h"
#include "FIFO.h"
#include "GPU.h"
+#include "SPU.h"
#include "SPI.h"
#include "RTC.h"
#include "Wifi.h"
@@ -37,11 +38,6 @@ namespace NDS
// * stick all the variables in a big structure?
// would make it easier to deal with savestates
-/*SchedEvent SchedBuffer[SCHED_BUF_LEN];
-SchedEvent* SchedQueue;
-
-bool NeedReschedule;*/
-
ARM* ARM9;
ARM* ARM7;
@@ -108,8 +104,6 @@ u32 SqrtRes;
u32 KeyInput;
-u16 _soundbias; // temp
-
bool Running;
@@ -132,6 +126,7 @@ bool Init()
if (!NDSCart::Init()) return false;
if (!GPU::Init()) return false;
+ if (!SPU::Init()) return false;
if (!SPI::Init()) return false;
if (!RTC::Init()) return false;
@@ -151,6 +146,7 @@ void DeInit()
NDSCart::DeInit();
GPU::DeInit();
+ SPU::DeInit();
SPI::DeInit();
RTC::DeInit();
}
@@ -300,14 +296,6 @@ void Reset()
for (i = 0; i < 8; i++) DMAs[i]->Reset();
memset(DMA9Fill, 0, 4*4);
- NDSCart::Reset();
- GPU::Reset();
- SPI::Reset();
- RTC::Reset();
- Wifi::Reset();
-
- // memset(SchedBuffer, 0, sizeof(SchedEvent)*SCHED_BUF_LEN);
- // SchedQueue = NULL;
memset(SchedList, 0, sizeof(SchedList));
SchedListMask = 0;
@@ -319,7 +307,12 @@ void Reset()
KeyInput = 0x007F03FF;
- _soundbias = 0;
+ NDSCart::Reset();
+ GPU::Reset();
+ SPU::Reset();
+ SPI::Reset();
+ RTC::Reset();
+ Wifi::Reset();
}
void LoadROM(const char* path, bool direct)
@@ -1629,7 +1622,6 @@ void ARM9IOWrite16(u32 addr, u16 val)
{
SetIRQ(1, IRQ_IPCSync);
}
- //CompensateARM7();
return;
case 0x04000184:
@@ -1901,8 +1893,7 @@ u8 ARM7IORead8(u32 addr)
if (addr >= 0x04000400 && addr < 0x04000520)
{
- // sound I/O
- return 0;
+ return SPU::Read8(addr);
}
printf("unknown ARM7 IO read8 %08X\n", addr);
@@ -1972,14 +1963,11 @@ u16 ARM7IORead16(u32 addr)
case 0x04000300: return PostFlag7;
case 0x04000304: return PowerControl7;
case 0x04000308: return ARM7BIOSProt;
-
- case 0x04000504: return _soundbias;
}
if (addr >= 0x04000400 && addr < 0x04000520)
{
- // sound I/O
- return 0;
+ return SPU::Read16(addr);
}
printf("unknown ARM7 IO read16 %08X %08X\n", addr, ARM9->R[15]);
@@ -2057,8 +2045,7 @@ u32 ARM7IORead32(u32 addr)
if (addr >= 0x04000400 && addr < 0x04000520)
{
- // sound I/O
- return 0;
+ return SPU::Read32(addr);
}
printf("unknown ARM7 IO read32 %08X\n", addr);
@@ -2116,7 +2103,7 @@ void ARM7IOWrite8(u32 addr, u8 val)
if (addr >= 0x04000400 && addr < 0x04000520)
{
- // sound I/O
+ SPU::Write8(addr, val);
return;
}
@@ -2228,15 +2215,11 @@ void ARM7IOWrite16(u32 addr, u16 val)
if (ARM7BIOSProt == 0)
ARM7BIOSProt = val;
return;
-
- case 0x04000504: // removeme
- _soundbias = val & 0x3FF;
- return;
}
if (addr >= 0x04000400 && addr < 0x04000520)
{
- // sound I/O
+ SPU::Write16(addr, val);
return;
}
@@ -2326,7 +2309,7 @@ void ARM7IOWrite32(u32 addr, u32 val)
if (addr >= 0x04000400 && addr < 0x04000520)
{
- // sound I/O
+ SPU::Write32(addr, val);
return;
}
diff --git a/src/NDS.h b/src/NDS.h
index 4fec117..583e12c 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -24,30 +24,11 @@
namespace NDS
{
-/*#define SCHED_BUF_LEN 64
-
-typedef struct _SchedEvent
-{
- u32 Delay;
- void (*Func)(u32);
- u32 Param;
- struct _SchedEvent* PrevEvent;
- struct _SchedEvent* NextEvent;
-
-} SchedEvent;*/
-
enum
{
Event_LCD = 0,
- /*Event_Timer9_0,
- Event_Timer9_1,
- Event_Timer9_2,
- Event_Timer9_3,
- Event_Timer7_0,
- Event_Timer7_1,
- Event_Timer7_2,
- Event_Timer7_3,*/
+ Event_SPU,
Event_MAX
};
@@ -95,7 +76,6 @@ typedef struct
u16 Cnt;
u32 Counter;
u32 CycleShift;
- //SchedEvent* Event;
} Timer;
@@ -127,15 +107,9 @@ void ReleaseKey(u32 key);
void TouchScreen(u16 x, u16 y);
void ReleaseScreen();
-/*SchedEvent* ScheduleEvent(s32 Delay, void (*Func)(u32), u32 Param);
-void CancelEvent(SchedEvent* event);
-void RunEvents(s32 cycles);*/
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
void CancelEvent(u32 id);
-// DO NOT CALL FROM ARM7!!
-void CompensateARM7();
-
void debug(u32 p);
void Halt();
diff --git a/src/SPU.cpp b/src/SPU.cpp
index c7a769e..440d39d 100644
--- a/src/SPU.cpp
+++ b/src/SPU.cpp
@@ -25,38 +25,269 @@
namespace SPU
{
-//SDL_AudioDeviceID device;
-//
+const u32 OutputBufferSize = 2*1024;
+s16 OutputBuffer[2 * OutputBufferSize];
+u32 OutputReadOffset;
+u32 OutputWriteOffset;
+
+
+u16 Cnt;
+u8 MasterVolume;
+u16 Bias;
+
+Channel* Channels[16];
bool Init()
{
- /*SDL_AudioSpec whatIwant, whatIget;
-
- memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
- whatIwant.freq = 32824; // 32823.6328125
- whatIwant.format = AUDIO_S16LSB;
- whatIwant.channels = 2;
- whatIwant.samples = 2048;
- whatIwant.callback = zorp;
- device = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, 0);
- if (!device)
- {
- printf("Audio init failed: %s\n", SDL_GetError());
- return false;
- }*/
+ for (int i = 0; i < 16; i++)
+ Channels[i] = new Channel(i);
return true;
}
void DeInit()
{
- //if (device) SDL_CloseAudioDevice(device);
+ for (int i = 0; i < 16; i++)
+ delete Channels[i];
}
void Reset()
{
+ memset(OutputBuffer, 0, 2*OutputBufferSize*2);
+ OutputReadOffset = 0;
+ OutputWriteOffset = 0;
+
+ Cnt = 0;
+ MasterVolume = 0;
+ Bias = 0;
+
+ for (int i = 0; i < 16; i++)
+ Channels[i]->Reset();
+
+ NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*16, Mix, 16);
+}
+
+
+Channel::Channel(u32 num)
+{
+ //
+}
+
+Channel::~Channel()
+{
+ //
+}
+
+void Channel::Reset()
+{
+ SetCnt(0);
+ SrcAddr = 0;
+ TimerReload = 0;
+ LoopPos = 0;
+ Length = 0;
+}
+
+
+void Mix(u32 samples)
+{
//
+
+ NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*16, Mix, 16);
+}
+
+
+void ReadOutput(s16* data, int samples)
+{
+ for (int i = 0; i < samples; i++)
+ {
+ *data++ = OutputBuffer[OutputReadOffset];
+ *data++ = OutputBuffer[OutputReadOffset + 1];
+
+ if (OutputReadOffset != OutputWriteOffset)
+ {
+ OutputReadOffset += 2;
+ OutputReadOffset &= ((2*OutputBufferSize)-1);
+ }
+ }
+}
+
+
+u8 Read8(u32 addr)
+{
+ if (addr < 0x04000500)
+ {
+ Channel* chan = Channels[(addr >> 4) & 0xF];
+
+ switch (addr & 0xF)
+ {
+ case 0x0: return chan->Cnt & 0xFF;
+ case 0x1: return (chan->Cnt >> 8) & 0xFF;
+ case 0x2: return (chan->Cnt >> 16) & 0xFF;
+ case 0x3: return chan->Cnt >> 24;
+ }
+ }
+ else
+ {
+ switch (addr)
+ {
+ case 0x04000500: return Cnt & 0x7F;
+ case 0x04000501: return Cnt >> 8;
+ }
+ }
+
+ printf("unknown SPU read8 %08X\n", addr);
+ return 0;
+}
+
+u16 Read16(u32 addr)
+{
+ if (addr < 0x04000500)
+ {
+ Channel* chan = Channels[(addr >> 4) & 0xF];
+
+ switch (addr & 0xF)
+ {
+ case 0x0: return chan->Cnt & 0xFFFF;
+ case 0x2: return chan->Cnt >> 16;
+ }
+ }
+ else
+ {
+ switch (addr)
+ {
+ case 0x04000500: return Cnt;
+ case 0x04000504: return Bias;
+ }
+ }
+
+ printf("unknown SPU read16 %08X\n", addr);
+ return 0;
+}
+
+u32 Read32(u32 addr)
+{
+ if (addr < 0x04000500)
+ {
+ Channel* chan = Channels[(addr >> 4) & 0xF];
+
+ switch (addr & 0xF)
+ {
+ case 0x0: return chan->Cnt;
+ }
+ }
+ else
+ {
+ switch (addr)
+ {
+ case 0x04000500: return Cnt;
+ case 0x04000504: return Bias;
+ }
+ }
+
+ printf("unknown SPU read32 %08X\n", addr);
+ return 0;
+}
+
+void Write8(u32 addr, u8 val)
+{
+ if (addr < 0x04000500)
+ {
+ Channel* chan = Channels[(addr >> 4) & 0xF];
+
+ switch (addr & 0xF)
+ {
+ case 0x0: chan->SetCnt((chan->Cnt & 0xFFFFFF00) | val); return;
+ case 0x1: chan->SetCnt((chan->Cnt & 0xFFFF00FF) | (val << 8)); return;
+ case 0x2: chan->SetCnt((chan->Cnt & 0xFF00FFFF) | (val << 16)); return;
+ case 0x3: chan->SetCnt((chan->Cnt & 0x00FFFFFF) | (val << 24)); return;
+ }
+ }
+ else
+ {
+ switch (addr)
+ {
+ case 0x04000500:
+ Cnt = (Cnt & 0xBF00) | (val & 0x7F);
+ MasterVolume = Cnt & 0x7F;
+ if (MasterVolume == 127) MasterVolume++;
+ return;
+ case 0x04000501:
+ Cnt = (Cnt & 0x007F) | ((val & 0xBF) << 8);
+ return;
+ }
+ }
+
+ printf("unknown SPU write8 %08X %02X\n", addr, val);
+}
+
+void Write16(u32 addr, u16 val)
+{
+ if (addr < 0x04000500)
+ {
+ Channel* chan = Channels[(addr >> 4) & 0xF];
+
+ switch (addr & 0xF)
+ {
+ case 0x0: chan->SetCnt((chan->Cnt & 0xFFFF0000) | val); return;
+ case 0x2: chan->SetCnt((chan->Cnt & 0x0000FFFF) | (val << 16)); return;
+ case 0x8: chan->SetTimerReload(val); return;
+ case 0xA: chan->SetLoopPos(val); return;
+ }
+ }
+ else
+ {
+ switch (addr)
+ {
+ case 0x04000500:
+ Cnt = val & 0xBF7F;
+ MasterVolume = Cnt & 0x7F;
+ if (MasterVolume == 127) MasterVolume++;
+ return;
+
+ case 0x04000504:
+ Bias = val & 0x3FF;
+ return;
+ }
+ }
+
+ printf("unknown SPU write16 %08X %04X\n", addr, val);
+}
+
+void Write32(u32 addr, u32 val)
+{
+ if (addr < 0x04000500)
+ {
+ Channel* chan = Channels[(addr >> 4) & 0xF];
+
+ switch (addr & 0xF)
+ {
+ case 0x0: chan->SetCnt(val); return;
+ case 0x4: chan->SetSrcAddr(val); return;
+ case 0x8:
+ chan->SetTimerReload(val & 0xFFFF);
+ chan->SetLoopPos(val >> 16);
+ return;
+ case 0xC: chan->SetLength(val); return;
+ }
+ }
+ else
+ {
+ switch (addr)
+ {
+ case 0x04000500:
+ Cnt = val & 0xBF7F;
+ MasterVolume = Cnt & 0x7F;
+ if (MasterVolume == 127) MasterVolume++;
+ return;
+
+ case 0x04000504:
+ Bias = val & 0x3FF;
+ return;
+ }
+ }
+
+ printf("unknown SPU write32 %08X %08X\n", addr, val);
}
}
diff --git a/src/SPU.h b/src/SPU.h
index a66b98d..5b762bd 100644
--- a/src/SPU.h
+++ b/src/SPU.h
@@ -26,6 +26,41 @@ bool Init();
void DeInit();
void Reset();
+void Mix(u32 samples);
+
+void ReadOutput(s16* data, int samples);
+
+u8 Read8(u32 addr);
+u16 Read16(u32 addr);
+u32 Read32(u32 addr);
+void Write8(u32 addr, u8 val);
+void Write16(u32 addr, u16 val);
+void Write32(u32 addr, u32 val);
+
+class Channel
+{
+public:
+ Channel(u32 num);
+ ~Channel();
+ void Reset();
+
+ u32 Cnt;
+ u32 SrcAddr;
+ u16 TimerReload;
+ u32 LoopPos;
+ u32 Length;
+
+ void SetCnt(u32 val)
+ {
+ Cnt = val & 0xFF7F837F;
+ }
+
+ void SetSrcAddr(u32 val) { SrcAddr = val & 0x07FFFFFF; }
+ void SetTimerReload(u32 val) { TimerReload = val & 0xFFFF; }
+ void SetLoopPos(u32 val) { LoopPos = (val & 0xFFFF) << 2; }
+ void SetLength(u32 val) { Length = (val & 0x001FFFFF) << 2; }
+};
+
}
#endif // SPU_H
diff --git a/src/wx/main.cpp b/src/wx/main.cpp
index 85568a4..f3d8ef8 100644
--- a/src/wx/main.cpp
+++ b/src/wx/main.cpp
@@ -22,6 +22,7 @@
#include "../Config.h"
#include "../NDS.h"
#include "../GPU.h"
+#include "../SPU.h"
#include "InputConfig.h"
#include "EmuConfig.h"
@@ -86,7 +87,7 @@ bool wxApp_melonDS::OnInit()
printf("melonDS " MELONDS_VERSION "\n" MELONDS_URL "\n");
Config::Load();
-
+
emuthread = new EmuThread();
if (emuthread->Run() != wxTHREAD_NO_ERROR)
{
@@ -97,7 +98,7 @@ bool wxApp_melonDS::OnInit()
MainFrame* melon = new MainFrame();
melon->Show(true);
-
+
melon->emuthread = emuthread;
emuthread->parent = melon;
@@ -108,7 +109,7 @@ int wxApp_melonDS::OnExit()
{
emuthread->Wait();
delete emuthread;
-
+
return wxApp::OnExit();
}
@@ -169,7 +170,7 @@ void MainFrame::OnClose(wxCloseEvent& event)
{
emuthread->EmuPause();
emuthread->EmuExit();
-
+
NDS::DeInit();
if (joy)
@@ -313,6 +314,11 @@ EmuThread::~EmuThread()
{
}
+static void AudioCallback(void* data, Uint8* stream, int len)
+{
+ SPU::ReadOutput((s16*)stream, len>>2);
+}
+
wxThread::ExitCode EmuThread::Entry()
{
emustatus = 3;
@@ -344,6 +350,23 @@ wxThread::ExitCode EmuThread::Entry()
botdst.x = 0; botdst.y = 192;
botdst.w = 256; botdst.h = 192;
+ SDL_AudioSpec whatIwant, whatIget;
+ memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
+ whatIwant.freq = 32824; // 32823.6328125
+ whatIwant.format = AUDIO_S16LSB;
+ whatIwant.channels = 2;
+ whatIwant.samples = 1024;
+ whatIwant.callback = AudioCallback;
+ audio = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, 0);
+ if (!audio)
+ {
+ printf("Audio init failed: %s\n", SDL_GetError());
+ }
+ else
+ {
+ SDL_PauseAudioDevice(audio, 0);
+ }
+
Touching = false;
axismask = 0;
@@ -430,9 +453,11 @@ wxThread::ExitCode EmuThread::Entry()
emupaused = true;
}
}
-
+
emupaused = true;
+ if (audio) SDL_CloseAudioDevice(audio);
+
SDL_DestroyTexture(sdltex);
SDL_DestroyRenderer(sdlrend);
SDL_DestroyWindow(sdlwin);
@@ -462,7 +487,7 @@ void EmuThread::ProcessEvents()
{
int w = evt.window.data1;
int h = evt.window.data2;
-
+
// SDL_SetWindowMinimumSize() doesn't seem to work on Linux. oh well
if ((w < 256) || (h < 384))
{
@@ -514,7 +539,7 @@ void EmuThread::ProcessEvents()
{
Touching = true;
NDS::PressKey(16+6);
-
+
int mx, my;
SDL_GetGlobalMouseState(&mx, &my);
txoffset = mx - evt.button.x;
diff --git a/src/wx/main.h b/src/wx/main.h
index 851a061..0219ff7 100644
--- a/src/wx/main.h
+++ b/src/wx/main.h
@@ -46,7 +46,7 @@ class wxApp_melonDS : public wxApp
public:
virtual bool OnInit();
virtual int OnExit();
-
+
EmuThread* emuthread;
};
@@ -91,7 +91,7 @@ public:
bool EmuIsRunning() { return (emustatus == 1) || (emustatus == 2); }
bool EmuIsPaused() { return (emustatus == 2) && emupaused; }
-
+
MainFrame* parent;
protected:
@@ -105,6 +105,8 @@ protected:
SDL_Rect topsrc, topdst;
SDL_Rect botsrc, botdst;
+ SDL_AudioDeviceID audio;
+
bool Touching;
int txoffset, tyoffset;