From 76c4e576086c59a96020676bb4eb497111349f2a Mon Sep 17 00:00:00 2001 From: StapleButter Date: Thu, 6 Apr 2017 22:38:46 +0200 Subject: [PATCH] preliminary audio. only supports PSG (and handles all channels as such). drops out every once in a while. --- src/SPU.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/SPU.h | 20 +++++++++++- 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/src/SPU.cpp b/src/SPU.cpp index 440d39d9..17de45d3 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -71,12 +71,11 @@ void Reset() Channel::Channel(u32 num) { - // + Num = num; } Channel::~Channel() { - // } void Channel::Reset() @@ -88,28 +87,108 @@ void Channel::Reset() Length = 0; } +void Channel::Start() +{ + Timer = TimerReload; + Pos = 0; + + // hax + NextSample_PSG(); +} + +void Channel::NextSample_PSG() +{ + s16 psgtable[8][8] = + { + {-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF}, + {-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF}, + {-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF}, + {-0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF}, + {-0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF}, + {-0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF}, + {-0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF}, + { 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF} + }; + + CurSample = psgtable[(Cnt >> 24) & 0x7][Pos & 0x7]; +} + +void Channel::Run(s32* buf, u32 samples) +{ + for (u32 s = 0; s < samples; s++) + buf[s] = 0; + + if (!(Cnt & (1<<31))) return; + if (Num < 8) return; + if (!(Cnt & 0x7F)) return; + + for (u32 s = 0; s < samples; s++) + { + Timer += 512; // 1 sample = 512 cycles at 16MHz + // will probably shit itself for very high-pitched sounds + while (Timer >> 16) + { + Timer = TimerReload + (Timer - 0x10000); + Pos++; + NextSample_PSG(); + } + + buf[s] = (s32)CurSample; + } +} + void Mix(u32 samples) { + s32 channelbuf[32]; + s32 finalbuf[32]; + + for (u32 s = 0; s < samples; s++) + finalbuf[s] = 0; + + for (int i = 0; i < 16; i++) + //int i = 8; + { + Channel* chan = Channels[i]; + chan->Run(channelbuf, samples); + + for (u32 s = 0; s < samples; s++) + { + finalbuf[s] += channelbuf[s]; + } + } + // + for (u32 s = 0; s < samples; s++) + { + s16 val = (s16)(finalbuf[s] >> 4); + // TODO panning! also volume and all + + OutputBuffer[OutputWriteOffset] = val; + OutputBuffer[OutputWriteOffset + 1] = val; + OutputWriteOffset += 2; + OutputWriteOffset &= ((2*OutputBufferSize)-1); + } + + NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*16, Mix, 16); } void ReadOutput(s16* data, int samples) -{ +{u32 zarp = 0; for (int i = 0; i < samples; i++) { *data++ = OutputBuffer[OutputReadOffset]; *data++ = OutputBuffer[OutputReadOffset + 1]; if (OutputReadOffset != OutputWriteOffset) - { + {zarp += 2; OutputReadOffset += 2; OutputReadOffset &= ((2*OutputBufferSize)-1); } - } + }printf("read %d samples, took %d\n", samples, zarp); } diff --git a/src/SPU.h b/src/SPU.h index 5b762bd3..65548647 100644 --- a/src/SPU.h +++ b/src/SPU.h @@ -44,21 +44,39 @@ public: ~Channel(); void Reset(); + u32 Num; + u32 Cnt; u32 SrcAddr; u16 TimerReload; u32 LoopPos; u32 Length; + u32 Timer; + u32 Pos; + s16 CurSample; + void SetCnt(u32 val) { + if ((val & (1<<31)) && !(Cnt & (1<<31))) + { + Start(); + } + Cnt = val & 0xFF7F837F; + //if(Num==8)printf("chan %d volume: %d\n", Num, val&0x7F); } void SetSrcAddr(u32 val) { SrcAddr = val & 0x07FFFFFF; } - void SetTimerReload(u32 val) { TimerReload = val & 0xFFFF; } + void SetTimerReload(u32 val) { TimerReload = val & 0xFFFF;if(Num==8) printf("chan8 timer %04X\n", TimerReload);} void SetLoopPos(u32 val) { LoopPos = (val & 0xFFFF) << 2; } void SetLength(u32 val) { Length = (val & 0x001FFFFF) << 2; } + + void Start(); + + void NextSample_PSG(); + + void Run(s32* buf, u32 samples); }; }