diff options
Diffstat (limited to 'src/SPU.cpp')
-rw-r--r-- | src/SPU.cpp | 265 |
1 files changed, 248 insertions, 17 deletions
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); } } |