auto APU::Master::run() -> void { if(enable == false) { center = 0; left = 0; right = 0; center_bias = left_bias = right_bias = 0; return; } int sample = 0; sample += apu.square1.output; sample += apu.square2.output; sample += apu.wave.output; sample += apu.noise.output; center = (sample * 512) - 16384; sample = 0; if(channel1_left_enable) sample += apu.square1.output; if(channel2_left_enable) sample += apu.square2.output; if(channel3_left_enable) sample += apu.wave.output; if(channel4_left_enable) sample += apu.noise.output; sample = (sample * 512) - 16384; sample = (sample * (left_volume + 1)) / 8; left = sample; sample = 0; if(channel1_right_enable) sample += apu.square1.output; if(channel2_right_enable) sample += apu.square2.output; if(channel3_right_enable) sample += apu.wave.output; if(channel4_right_enable) sample += apu.noise.output; sample = (sample * 512) - 16384; sample = (sample * (right_volume + 1)) / 8; right = sample; //reduce audio volume center >>= 1; left >>= 1; right >>= 1; } auto APU::Master::read(uint16 addr) -> uint8 { if(addr == 0xff24) { //NR50 return left_in_enable << 7 | left_volume << 4 | right_in_enable << 3 | right_volume; } if(addr == 0xff25) { //NR51 return channel4_left_enable << 7 | channel3_left_enable << 6 | channel2_left_enable << 5 | channel1_left_enable << 4 | channel4_right_enable << 3 | channel3_right_enable << 2 | channel2_right_enable << 1 | channel1_right_enable << 0; } if(addr == 0xff26) { //NR52 return enable << 7 | 0x70 | apu.noise.enable << 3 | apu.wave.enable << 2 | apu.square2.enable << 1 | apu.square1.enable << 0; } return 0xff; } auto APU::Master::write(uint16 addr, uint8 data) -> void { if(addr == 0xff24) { //NR50 left_in_enable = data & 0x80; left_volume = (data >> 4) & 7; right_in_enable = data & 0x08; right_volume = (data >> 0) & 7; } if(addr == 0xff25) { //NR51 channel4_left_enable = data & 0x80; channel3_left_enable = data & 0x40; channel2_left_enable = data & 0x20; channel1_left_enable = data & 0x10; channel4_right_enable = data & 0x08; channel3_right_enable = data & 0x04; channel2_right_enable = data & 0x02; channel1_right_enable = data & 0x01; } if(addr == 0xff26) { //NR52 enable = data & 0x80; if(!enable) { apu.square1.power(); apu.square2.power(); apu.wave.power(); apu.noise.power(); power(); } } } auto APU::Master::power() -> void { left_in_enable = 0; left_volume = 0; right_in_enable = 0; right_volume = 0; channel4_left_enable = 0; channel3_left_enable = 0; channel2_left_enable = 0; channel1_left_enable = 0; channel4_right_enable = 0; channel3_right_enable = 0; channel2_right_enable = 0; channel1_right_enable = 0; enable = 0; center = 0; left = 0; right = 0; center_bias = 0; left_bias = 0; right_bias = 0; } auto APU::Master::serialize(serializer& s) -> void { s.integer(left_in_enable); s.integer(left_volume); s.integer(right_in_enable); s.integer(right_volume); s.integer(channel4_left_enable); s.integer(channel3_left_enable); s.integer(channel2_left_enable); s.integer(channel1_left_enable); s.integer(channel4_right_enable); s.integer(channel3_right_enable); s.integer(channel2_right_enable); s.integer(channel1_right_enable); s.integer(enable); s.integer(center); s.integer(left); s.integer(right); s.integer(center_bias); s.integer(left_bias); s.integer(right_bias); }