auto APU::Noise::dacEnable() const -> bool { return (envelopeVolume || envelopeDirection); } auto APU::Noise::getPeriod() const -> uint { static const uint table[] = {4, 8, 16, 24, 32, 40, 48, 56}; return table[divisor] << frequency; } auto APU::Noise::run() -> void { if(period && --period == 0) { period = getPeriod(); if(frequency < 14) { bool bit = (lfsr ^ (lfsr >> 1)) & 1; lfsr = (lfsr >> 1) ^ (bit << (narrow ? 6 : 14)); } } uint4 sample = lfsr & 1 ? 0 : (uint)volume; if(!enable) sample = 0; output = sample; } auto APU::Noise::clockLength() -> void { if(counter) { if(length && --length == 0) enable = false; } } auto APU::Noise::clockEnvelope() -> void { if(enable && envelopeFrequency && --envelopePeriod == 0) { envelopePeriod = envelopeFrequency ? (uint)envelopeFrequency : 8; if(envelopeDirection == 0 && volume > 0) volume--; if(envelopeDirection == 1 && volume < 15) volume++; } } auto APU::Noise::read(uint16 addr) -> uint8 { if(addr == 0xff1f) { //NR40 return 0xff; } if(addr == 0xff20) { //NR41 return 0xff; } if(addr == 0xff21) { //NR42 return envelopeVolume << 4 | envelopeDirection << 3 | envelopeFrequency; } if(addr == 0xff22) { //NR43 return frequency << 4 | narrow << 3 | divisor; } if(addr == 0xff23) { //NR44 return 0x80 | counter << 6 | 0x3f; } return 0xff; } auto APU::Noise::write(uint16 addr, uint8 data) -> void { if(addr == 0xff20) { //NR41 length = 64 - (data & 0x3f); } if(addr == 0xff21) { //NR42 envelopeVolume = data.bits(7,4); envelopeDirection = data.bit (3); envelopeFrequency = data.bits(2,0); if(!dacEnable()) enable = false; } if(addr == 0xff22) { //NR43 frequency = data.bits(7,4); narrow = data.bit (3); divisor = data.bits(2,0); period = getPeriod(); } if(addr == 0xff23) { //NR44 if((apu.phase & 1) && !counter && (data & 0x40)) { if(length && --length == 0) enable = false; } counter = data.bit(6); if(data.bit(7)) { enable = dacEnable(); lfsr = -1; envelopePeriod = envelopeFrequency ? (uint)envelopeFrequency : 8; volume = envelopeVolume; if(!length) { length = 64; if(apu.phase.bit(0) && counter) length--; } } } } auto APU::Noise::power(bool initializeLength) -> void { enable = 0; envelopeVolume = 0; envelopeDirection = 0; envelopeFrequency = 0; frequency = 0; narrow = 0; divisor = 0; counter = 0; output = 0; envelopePeriod = 0; volume = 0; period = 0; lfsr = 0; if(initializeLength) length = 64; } auto APU::Noise::serialize(serializer& s) -> void { s.integer(enable); s.integer(envelopeVolume); s.integer(envelopeDirection); s.integer(envelopeFrequency); s.integer(frequency); s.integer(narrow); s.integer(divisor); s.integer(counter); s.integer(output); s.integer(length); s.integer(envelopePeriod); s.integer(volume); s.integer(period); s.integer(lfsr); }