bsnes/higan/gb/apu/master/master.cpp

147 lines
3.7 KiB
C++

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