2012-04-06 04:29:50 +00:00
|
|
|
unsigned APU::Noise::divider() const {
|
2013-12-10 12:12:54 +00:00
|
|
|
if(divisor == 0) return 4;
|
|
|
|
return divisor * 8;
|
2012-04-06 04:29:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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 (length << 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) | (initialize << 7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|