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