mirror of https://github.com/bsnes-emu/bsnes.git
117 lines
3.5 KiB
C++
117 lines
3.5 KiB
C++
#include <gb/gb.hpp>
|
|
|
|
#define APU_CPP
|
|
namespace GameBoy {
|
|
|
|
#include "square1/square1.cpp"
|
|
#include "square2/square2.cpp"
|
|
#include "wave/wave.cpp"
|
|
#include "noise/noise.cpp"
|
|
#include "master/master.cpp"
|
|
#include "serialization.cpp"
|
|
APU apu;
|
|
|
|
void APU::Main() {
|
|
apu.main();
|
|
}
|
|
|
|
void APU::main() {
|
|
while(true) {
|
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
|
}
|
|
|
|
if(sequencer_base == 0) { //512hz
|
|
if(sequencer_step == 0 || sequencer_step == 2 || sequencer_step == 4 || sequencer_step == 6) { //256hz
|
|
square1.clock_length();
|
|
square2.clock_length();
|
|
wave.clock_length();
|
|
noise.clock_length();
|
|
}
|
|
if(sequencer_step == 2 || sequencer_step == 6) { //128hz
|
|
square1.clock_sweep();
|
|
}
|
|
if(sequencer_step == 7) { //64hz
|
|
square1.clock_envelope();
|
|
square2.clock_envelope();
|
|
noise.clock_envelope();
|
|
}
|
|
sequencer_step++;
|
|
}
|
|
sequencer_base++;
|
|
|
|
square1.run();
|
|
square2.run();
|
|
wave.run();
|
|
noise.run();
|
|
master.run();
|
|
|
|
hipass(master.center, master.center_bias);
|
|
hipass(master.left, master.left_bias);
|
|
hipass(master.right, master.right_bias);
|
|
|
|
interface->audioSample(master.left, master.right);
|
|
|
|
clock += cpu.frequency;
|
|
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(scheduler.active_thread = cpu.thread);
|
|
}
|
|
}
|
|
|
|
void APU::hipass(int16& sample, int64& bias) {
|
|
bias += ((((int64)sample << 16) - (bias >> 16)) * 57593) >> 16;
|
|
sample = sclamp<16>(sample - (bias >> 32));
|
|
}
|
|
|
|
void APU::power() {
|
|
create(Main, 2 * 1024 * 1024);
|
|
for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this;
|
|
|
|
for(auto& n : mmio_data) n = 0x00;
|
|
sequencer_base = 0;
|
|
sequencer_step = 0;
|
|
|
|
square1.power();
|
|
square2.power();
|
|
wave.power();
|
|
noise.power();
|
|
master.power();
|
|
}
|
|
|
|
uint8 APU::mmio_read(uint16 addr) {
|
|
static const uint8 table[48] = {
|
|
0x80, 0x3f, 0x00, 0xff, 0xbf, //square1
|
|
0xff, 0x3f, 0x00, 0xff, 0xbf, //square2
|
|
0x7f, 0xff, 0x9f, 0xff, 0xbf, //wave
|
|
0xff, 0xff, 0x00, 0x00, 0xbf, //noise
|
|
0x00, 0x00, 0x70, //master
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //unmapped
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //wave pattern
|
|
};
|
|
|
|
if(addr == 0xff26) {
|
|
uint8 data = master.enable << 7;
|
|
if(square1.enable) data |= 0x01;
|
|
if(square2.enable) data |= 0x02;
|
|
if( wave.enable) data |= 0x04;
|
|
if( noise.enable) data |= 0x08;
|
|
return data | table[addr - 0xff10];
|
|
}
|
|
|
|
if(addr >= 0xff10 && addr <= 0xff3f) return mmio_data[addr - 0xff10] | table[addr - 0xff10];
|
|
return 0xff;
|
|
}
|
|
|
|
void APU::mmio_write(uint16 addr, uint8 data) {
|
|
if(addr >= 0xff10 && addr <= 0xff3f) mmio_data[addr - 0xff10] = data;
|
|
|
|
if(addr >= 0xff10 && addr <= 0xff14) return square1.write (addr - 0xff10, data);
|
|
if(addr >= 0xff15 && addr <= 0xff19) return square2.write (addr - 0xff15, data);
|
|
if(addr >= 0xff1a && addr <= 0xff1e) return wave.write (addr - 0xff1a, data);
|
|
if(addr >= 0xff1f && addr <= 0xff23) return noise.write (addr - 0xff1f, data);
|
|
if(addr >= 0xff24 && addr <= 0xff26) return master.write (addr - 0xff24, data);
|
|
if(addr >= 0xff30 && addr <= 0xff3f) return wave.write_pattern(addr - 0xff30, data);
|
|
}
|
|
|
|
}
|