bsnes/higan/ws/apu/apu.cpp

158 lines
3.7 KiB
C++

#include <ws/ws.hpp>
namespace WonderSwan {
APU apu;
#include "io.cpp"
#include "dma.cpp"
#include "channel1.cpp"
#include "channel2.cpp"
#include "channel3.cpp"
#include "channel4.cpp"
#include "channel5.cpp"
#include "serialization.cpp"
auto APU::Enter() -> void {
while(true) scheduler.synchronize(), apu.main();
}
auto APU::main() -> void {
dma.run();
channel1.run();
channel2.run();
channel3.run();
channel4.run();
channel5.run();
dacRun();
if(++s.sweepClock == 0) channel3.sweep();
step(1);
}
auto APU::sample(uint channel, uint5 index) -> uint4 {
uint8 data = iram.read((r.waveBase << 6) + (--channel << 4) + (index >> 1));
if(index.bit(0) == 0) return data.bits(0,3);
if(index.bit(0) == 1) return data.bits(4,7);
}
auto APU::dacRun() -> void {
int left = 0;
if(channel1.r.enable) left += channel1.o.left;
if(channel2.r.enable) left += channel2.o.left;
if(channel3.r.enable) left += channel3.o.left;
if(channel4.r.enable) left += channel4.o.left;
if(channel5.r.enable) left += channel5.o.left;
left = sclamp<16>(left << 5);
int right = 0;
if(channel1.r.enable) right += channel1.o.right;
if(channel2.r.enable) right += channel2.o.right;
if(channel3.r.enable) right += channel3.o.right;
if(channel4.r.enable) right += channel4.o.right;
if(channel5.r.enable) right += channel5.o.right;
right = sclamp<16>(right << 5);
if(!r.headphoneEnable) {
left = 0;
right = 0;
}
stream->sample(left / 32768.0, right / 32768.0);
}
auto APU::step(uint clocks) -> void {
clock += clocks;
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
}
auto APU::power() -> void {
create(APU::Enter, 3'072'000);
stream = Emulator::audio.createStream(2, 3'072'000.0);
bus.map(this, 0x004a, 0x004c);
bus.map(this, 0x004e, 0x0050);
bus.map(this, 0x0052);
bus.map(this, 0x006a, 0x006b);
bus.map(this, 0x0080, 0x0095);
s.sweepClock = 0;
r.waveBase = 0;
r.speakerEnable = 0;
r.speakerShift = 0;
r.headphoneEnable = 0;
dma.s.clock = 0;
dma.s.source = 0;
dma.s.length = 0;
dma.r.source = 0;
dma.r.length = 0;
dma.r.rate = 0;
dma.r.unknown = 0;
dma.r.loop = 0;
dma.r.target = 0;
dma.r.direction = 0;
dma.r.enable = 0;
channel1.o.left = 0;
channel1.o.right = 0;
channel1.s.period = 0;
channel1.s.sampleOffset = 0;
channel1.r.pitch = 0;
channel1.r.volumeLeft = 0;
channel1.r.volumeRight = 0;
channel1.r.enable = 0;
channel2.o.left = 0;
channel2.o.right = 0;
channel2.s.period = 0;
channel2.s.sampleOffset = 0;
channel2.r.pitch = 0;
channel2.r.volumeLeft = 0;
channel2.r.volumeRight = 0;
channel2.r.enable = 0;
channel2.r.voice = 0;
channel2.r.voiceEnableLeft = 0;
channel2.r.voiceEnableRight = 0;
channel3.o.left = 0;
channel3.o.right = 0;
channel3.s.period = 0;
channel3.s.sampleOffset = 0;
channel3.s.sweepCounter = 0;
channel3.r.pitch = 0;
channel3.r.volumeLeft = 0;
channel3.r.volumeRight = 0;
channel3.r.sweepValue = 0;
channel3.r.sweepTime = 0;
channel3.r.enable = 0;
channel3.r.sweep = 0;
channel4.o.left = 0;
channel4.o.right = 0;
channel4.s.period = 0;
channel4.s.sampleOffset = 0;
channel4.s.noiseOutput = 0;
channel4.s.noiseLFSR = 0;
channel4.r.pitch = 0;
channel4.r.volumeLeft = 0;
channel4.r.volumeRight = 0;
channel4.r.noiseMode = 0;
channel4.r.noiseReset = 0;
channel4.r.noiseUpdate = 0;
channel4.r.enable = 0;
channel4.r.noise = 0;
channel5.o.left = 0;
channel5.o.right = 0;
channel5.s.clock = 0;
channel5.s.data = 0;
channel5.r.volume = 0;
channel5.r.scale = 0;
channel5.r.speed = 0;
channel5.r.enable = 0;
channel5.r.unknown = 0;
channel5.r.leftEnable = 0;
channel5.r.rightEnable = 0;
}
}