bsnes/gba/apu/noise.cpp

94 lines
2.0 KiB
C++

unsigned APU::Noise::divider() const {
if(divisor == 0) return 4;
return divisor * 8;
}
void APU::Noise::run() {
if(period && --period == 0) {
period = divider() << frequency;
if(frequency < 14) {
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
lfsr = (lfsr >> 1) ^ (bit << (narrowlfsr ? 6 : 14));
}
}
output = volume;
if(enable == false || (lfsr & 1)) output = 0;
}
void APU::Noise::clocklength() {
if(enable && counter) {
if(++length == 0) enable = false;
}
}
void APU::Noise::clockenvelope() {
if(enable && envelope.frequency && --envelope.period == 0) {
envelope.period = envelope.frequency;
if(envelope.direction == 0 && volume > 0) volume--;
if(envelope.direction == 1 && volume < 15) volume++;
}
}
uint8 APU::Noise::read(unsigned addr) const {
switch(addr) {
case 1: return 0;
case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4);
case 3: return (divisor << 0) | (narrowlfsr << 3) | (frequency << 4);
case 4: return (counter << 6);
}
}
void APU::Noise::write(unsigned addr, uint8 byte) {
switch(addr) {
case 1: //NR41
length = byte >> 0;
break;
case 2: //NR42
envelope.frequency = byte >> 0;
envelope.direction = byte >> 3;
envelope.volume = byte >> 4;
if(envelope.dacenable() == false) enable = false;
break;
case 3: //NR43
divisor = byte >> 0;
narrowlfsr = byte >> 3;
frequency = byte >> 4;
period = divider() << frequency;
break;
case 4: //NR44
counter = byte >> 6;
initialize = byte >> 7;
if(initialize) {
enable = envelope.dacenable();
lfsr = ~0u;
envelope.period = envelope.frequency;
volume = envelope.volume;
}
break;
}
}
void APU::Noise::power() {
envelope.frequency = 0;
envelope.direction = 0;
envelope.volume = 0;
envelope.period = 0;
length = 0;
divisor = 0;
narrowlfsr = 0;
frequency = 0;
counter = 0;
initialize = 0;
enable = 0;
lfsr = 0;
output = 0;
period = 0;
volume = 0;
}