#include #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); } }