cloud-game/nes/apu.go
2019-03-31 23:54:02 +08:00

862 lines
18 KiB
Go

package nes
import "encoding/gob"
const frameCounterRate = CPUFrequency / 240.0
var lengthTable = []byte{
10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14,
12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30,
}
var dutyTable = [][]byte{
{0, 1, 0, 0, 0, 0, 0, 0},
{0, 1, 1, 0, 0, 0, 0, 0},
{0, 1, 1, 1, 1, 0, 0, 0},
{1, 0, 0, 1, 1, 1, 1, 1},
}
var triangleTable = []byte{
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
var noiseTable = []uint16{
4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068,
}
var dmcTable = []byte{
214, 190, 170, 160, 143, 127, 113, 107, 95, 80, 71, 64, 53, 42, 36, 27,
}
var pulseTable [31]float32
var tndTable [203]float32
func init() {
for i := 0; i < 31; i++ {
pulseTable[i] = 95.52 / (8128.0/float32(i) + 100)
}
for i := 0; i < 203; i++ {
tndTable[i] = 163.67 / (24329.0/float32(i) + 100)
}
}
// APU
type APU struct {
console *Console
channel chan float32
sampleRate float64
pulse1 Pulse
pulse2 Pulse
triangle Triangle
noise Noise
dmc DMC
cycle uint64
framePeriod byte
frameValue byte
frameIRQ bool
filterChain FilterChain
}
func NewAPU(console *Console) *APU {
apu := APU{}
apu.console = console
apu.noise.shiftRegister = 1
apu.pulse1.channel = 1
apu.pulse2.channel = 2
apu.dmc.cpu = console.CPU
return &apu
}
func (apu *APU) Save(encoder *gob.Encoder) error {
encoder.Encode(apu.cycle)
encoder.Encode(apu.framePeriod)
encoder.Encode(apu.frameValue)
encoder.Encode(apu.frameIRQ)
apu.pulse1.Save(encoder)
apu.pulse2.Save(encoder)
apu.triangle.Save(encoder)
apu.noise.Save(encoder)
apu.dmc.Save(encoder)
return nil
}
func (apu *APU) Load(decoder *gob.Decoder) error {
decoder.Decode(&apu.cycle)
decoder.Decode(&apu.framePeriod)
decoder.Decode(&apu.frameValue)
decoder.Decode(&apu.frameIRQ)
apu.pulse1.Load(decoder)
apu.pulse2.Load(decoder)
apu.triangle.Load(decoder)
apu.noise.Load(decoder)
apu.dmc.Load(decoder)
return nil
}
func (apu *APU) Step() {
cycle1 := apu.cycle
apu.cycle++
cycle2 := apu.cycle
apu.stepTimer()
f1 := int(float64(cycle1) / frameCounterRate)
f2 := int(float64(cycle2) / frameCounterRate)
if f1 != f2 {
apu.stepFrameCounter()
}
s1 := int(float64(cycle1) / apu.sampleRate)
s2 := int(float64(cycle2) / apu.sampleRate)
if s1 != s2 {
apu.sendSample()
}
}
func (apu *APU) sendSample() {
output := apu.filterChain.Step(apu.output())
select {
case apu.channel <- output:
default:
}
}
func (apu *APU) output() float32 {
p1 := apu.pulse1.output()
p2 := apu.pulse2.output()
t := apu.triangle.output()
n := apu.noise.output()
d := apu.dmc.output()
pulseOut := pulseTable[p1+p2]
tndOut := tndTable[3*t+2*n+d]
return pulseOut + tndOut
}
// mode 0: mode 1: function
// --------- ----------- -----------------------------
// - - - f - - - - - IRQ (if bit 6 is clear)
// - l - l l - l - - Length counter and sweep
// e e e e e e e e - Envelope and linear counter
func (apu *APU) stepFrameCounter() {
switch apu.framePeriod {
case 4:
apu.frameValue = (apu.frameValue + 1) % 4
switch apu.frameValue {
case 0, 2:
apu.stepEnvelope()
case 1:
apu.stepEnvelope()
apu.stepSweep()
apu.stepLength()
case 3:
apu.stepEnvelope()
apu.stepSweep()
apu.stepLength()
apu.fireIRQ()
}
case 5:
apu.frameValue = (apu.frameValue + 1) % 5
switch apu.frameValue {
case 0, 2:
apu.stepEnvelope()
case 1, 3:
apu.stepEnvelope()
apu.stepSweep()
apu.stepLength()
}
}
}
func (apu *APU) stepTimer() {
if apu.cycle%2 == 0 {
apu.pulse1.stepTimer()
apu.pulse2.stepTimer()
apu.noise.stepTimer()
apu.dmc.stepTimer()
}
apu.triangle.stepTimer()
}
func (apu *APU) stepEnvelope() {
apu.pulse1.stepEnvelope()
apu.pulse2.stepEnvelope()
apu.triangle.stepCounter()
apu.noise.stepEnvelope()
}
func (apu *APU) stepSweep() {
apu.pulse1.stepSweep()
apu.pulse2.stepSweep()
}
func (apu *APU) stepLength() {
apu.pulse1.stepLength()
apu.pulse2.stepLength()
apu.triangle.stepLength()
apu.noise.stepLength()
}
func (apu *APU) fireIRQ() {
if apu.frameIRQ {
apu.console.CPU.triggerIRQ()
}
}
func (apu *APU) readRegister(address uint16) byte {
switch address {
case 0x4015:
return apu.readStatus()
// default:
// log.Fatalf("unhandled apu register read at address: 0x%04X", address)
}
return 0
}
func (apu *APU) writeRegister(address uint16, value byte) {
switch address {
case 0x4000:
apu.pulse1.writeControl(value)
case 0x4001:
apu.pulse1.writeSweep(value)
case 0x4002:
apu.pulse1.writeTimerLow(value)
case 0x4003:
apu.pulse1.writeTimerHigh(value)
case 0x4004:
apu.pulse2.writeControl(value)
case 0x4005:
apu.pulse2.writeSweep(value)
case 0x4006:
apu.pulse2.writeTimerLow(value)
case 0x4007:
apu.pulse2.writeTimerHigh(value)
case 0x4008:
apu.triangle.writeControl(value)
case 0x4009:
case 0x4010:
apu.dmc.writeControl(value)
case 0x4011:
apu.dmc.writeValue(value)
case 0x4012:
apu.dmc.writeAddress(value)
case 0x4013:
apu.dmc.writeLength(value)
case 0x400A:
apu.triangle.writeTimerLow(value)
case 0x400B:
apu.triangle.writeTimerHigh(value)
case 0x400C:
apu.noise.writeControl(value)
case 0x400D:
case 0x400E:
apu.noise.writePeriod(value)
case 0x400F:
apu.noise.writeLength(value)
case 0x4015:
apu.writeControl(value)
case 0x4017:
apu.writeFrameCounter(value)
// default:
// log.Fatalf("unhandled apu register write at address: 0x%04X", address)
}
}
func (apu *APU) readStatus() byte {
var result byte
if apu.pulse1.lengthValue > 0 {
result |= 1
}
if apu.pulse2.lengthValue > 0 {
result |= 2
}
if apu.triangle.lengthValue > 0 {
result |= 4
}
if apu.noise.lengthValue > 0 {
result |= 8
}
if apu.dmc.currentLength > 0 {
result |= 16
}
return result
}
func (apu *APU) writeControl(value byte) {
apu.pulse1.enabled = value&1 == 1
apu.pulse2.enabled = value&2 == 2
apu.triangle.enabled = value&4 == 4
apu.noise.enabled = value&8 == 8
apu.dmc.enabled = value&16 == 16
if !apu.pulse1.enabled {
apu.pulse1.lengthValue = 0
}
if !apu.pulse2.enabled {
apu.pulse2.lengthValue = 0
}
if !apu.triangle.enabled {
apu.triangle.lengthValue = 0
}
if !apu.noise.enabled {
apu.noise.lengthValue = 0
}
if !apu.dmc.enabled {
apu.dmc.currentLength = 0
} else {
if apu.dmc.currentLength == 0 {
apu.dmc.restart()
}
}
}
func (apu *APU) writeFrameCounter(value byte) {
apu.framePeriod = 4 + (value>>7)&1
apu.frameIRQ = (value>>6)&1 == 0
// apu.frameValue = 0
if apu.framePeriod == 5 {
apu.stepEnvelope()
apu.stepSweep()
apu.stepLength()
}
}
// Pulse
type Pulse struct {
enabled bool
channel byte
lengthEnabled bool
lengthValue byte
timerPeriod uint16
timerValue uint16
dutyMode byte
dutyValue byte
sweepReload bool
sweepEnabled bool
sweepNegate bool
sweepShift byte
sweepPeriod byte
sweepValue byte
envelopeEnabled bool
envelopeLoop bool
envelopeStart bool
envelopePeriod byte
envelopeValue byte
envelopeVolume byte
constantVolume byte
}
func (p *Pulse) Save(encoder *gob.Encoder) error {
encoder.Encode(p.enabled)
encoder.Encode(p.channel)
encoder.Encode(p.lengthEnabled)
encoder.Encode(p.lengthValue)
encoder.Encode(p.timerPeriod)
encoder.Encode(p.timerValue)
encoder.Encode(p.dutyMode)
encoder.Encode(p.dutyValue)
encoder.Encode(p.sweepReload)
encoder.Encode(p.sweepEnabled)
encoder.Encode(p.sweepNegate)
encoder.Encode(p.sweepShift)
encoder.Encode(p.sweepPeriod)
encoder.Encode(p.sweepValue)
encoder.Encode(p.envelopeEnabled)
encoder.Encode(p.envelopeLoop)
encoder.Encode(p.envelopeStart)
encoder.Encode(p.envelopePeriod)
encoder.Encode(p.envelopeValue)
encoder.Encode(p.envelopeVolume)
encoder.Encode(p.constantVolume)
return nil
}
func (p *Pulse) Load(decoder *gob.Decoder) error {
decoder.Decode(&p.enabled)
decoder.Decode(&p.channel)
decoder.Decode(&p.lengthEnabled)
decoder.Decode(&p.lengthValue)
decoder.Decode(&p.timerPeriod)
decoder.Decode(&p.timerValue)
decoder.Decode(&p.dutyMode)
decoder.Decode(&p.dutyValue)
decoder.Decode(&p.sweepReload)
decoder.Decode(&p.sweepEnabled)
decoder.Decode(&p.sweepNegate)
decoder.Decode(&p.sweepShift)
decoder.Decode(&p.sweepPeriod)
decoder.Decode(&p.sweepValue)
decoder.Decode(&p.envelopeEnabled)
decoder.Decode(&p.envelopeLoop)
decoder.Decode(&p.envelopeStart)
decoder.Decode(&p.envelopePeriod)
decoder.Decode(&p.envelopeValue)
decoder.Decode(&p.envelopeVolume)
decoder.Decode(&p.constantVolume)
return nil
}
func (p *Pulse) writeControl(value byte) {
p.dutyMode = (value >> 6) & 3
p.lengthEnabled = (value>>5)&1 == 0
p.envelopeLoop = (value>>5)&1 == 1
p.envelopeEnabled = (value>>4)&1 == 0
p.envelopePeriod = value & 15
p.constantVolume = value & 15
p.envelopeStart = true
}
func (p *Pulse) writeSweep(value byte) {
p.sweepEnabled = (value>>7)&1 == 1
p.sweepPeriod = (value>>4)&7 + 1
p.sweepNegate = (value>>3)&1 == 1
p.sweepShift = value & 7
p.sweepReload = true
}
func (p *Pulse) writeTimerLow(value byte) {
p.timerPeriod = (p.timerPeriod & 0xFF00) | uint16(value)
}
func (p *Pulse) writeTimerHigh(value byte) {
p.lengthValue = lengthTable[value>>3]
p.timerPeriod = (p.timerPeriod & 0x00FF) | (uint16(value&7) << 8)
p.envelopeStart = true
p.dutyValue = 0
}
func (p *Pulse) stepTimer() {
if p.timerValue == 0 {
p.timerValue = p.timerPeriod
p.dutyValue = (p.dutyValue + 1) % 8
} else {
p.timerValue--
}
}
func (p *Pulse) stepEnvelope() {
if p.envelopeStart {
p.envelopeVolume = 15
p.envelopeValue = p.envelopePeriod
p.envelopeStart = false
} else if p.envelopeValue > 0 {
p.envelopeValue--
} else {
if p.envelopeVolume > 0 {
p.envelopeVolume--
} else if p.envelopeLoop {
p.envelopeVolume = 15
}
p.envelopeValue = p.envelopePeriod
}
}
func (p *Pulse) stepSweep() {
if p.sweepReload {
if p.sweepEnabled && p.sweepValue == 0 {
p.sweep()
}
p.sweepValue = p.sweepPeriod
p.sweepReload = false
} else if p.sweepValue > 0 {
p.sweepValue--
} else {
if p.sweepEnabled {
p.sweep()
}
p.sweepValue = p.sweepPeriod
}
}
func (p *Pulse) stepLength() {
if p.lengthEnabled && p.lengthValue > 0 {
p.lengthValue--
}
}
func (p *Pulse) sweep() {
delta := p.timerPeriod >> p.sweepShift
if p.sweepNegate {
p.timerPeriod -= delta
if p.channel == 1 {
p.timerPeriod--
}
} else {
p.timerPeriod += delta
}
}
func (p *Pulse) output() byte {
if !p.enabled {
return 0
}
if p.lengthValue == 0 {
return 0
}
if dutyTable[p.dutyMode][p.dutyValue] == 0 {
return 0
}
if p.timerPeriod < 8 || p.timerPeriod > 0x7FF {
return 0
}
// if !p.sweepNegate && p.timerPeriod+(p.timerPeriod>>p.sweepShift) > 0x7FF {
// return 0
// }
if p.envelopeEnabled {
return p.envelopeVolume
} else {
return p.constantVolume
}
}
// Triangle
type Triangle struct {
enabled bool
lengthEnabled bool
lengthValue byte
timerPeriod uint16
timerValue uint16
dutyValue byte
counterPeriod byte
counterValue byte
counterReload bool
}
func (t *Triangle) Save(encoder *gob.Encoder) error {
encoder.Encode(t.enabled)
encoder.Encode(t.lengthEnabled)
encoder.Encode(t.lengthValue)
encoder.Encode(t.timerPeriod)
encoder.Encode(t.timerValue)
encoder.Encode(t.dutyValue)
encoder.Encode(t.counterPeriod)
encoder.Encode(t.counterValue)
encoder.Encode(t.counterReload)
return nil
}
func (t *Triangle) Load(decoder *gob.Decoder) error {
decoder.Decode(&t.enabled)
decoder.Decode(&t.lengthEnabled)
decoder.Decode(&t.lengthValue)
decoder.Decode(&t.timerPeriod)
decoder.Decode(&t.timerValue)
decoder.Decode(&t.dutyValue)
decoder.Decode(&t.counterPeriod)
decoder.Decode(&t.counterValue)
decoder.Decode(&t.counterReload)
return nil
}
func (t *Triangle) writeControl(value byte) {
t.lengthEnabled = (value>>7)&1 == 0
t.counterPeriod = value & 0x7F
}
func (t *Triangle) writeTimerLow(value byte) {
t.timerPeriod = (t.timerPeriod & 0xFF00) | uint16(value)
}
func (t *Triangle) writeTimerHigh(value byte) {
t.lengthValue = lengthTable[value>>3]
t.timerPeriod = (t.timerPeriod & 0x00FF) | (uint16(value&7) << 8)
t.timerValue = t.timerPeriod
t.counterReload = true
}
func (t *Triangle) stepTimer() {
if t.timerValue == 0 {
t.timerValue = t.timerPeriod
if t.lengthValue > 0 && t.counterValue > 0 {
t.dutyValue = (t.dutyValue + 1) % 32
}
} else {
t.timerValue--
}
}
func (t *Triangle) stepLength() {
if t.lengthEnabled && t.lengthValue > 0 {
t.lengthValue--
}
}
func (t *Triangle) stepCounter() {
if t.counterReload {
t.counterValue = t.counterPeriod
} else if t.counterValue > 0 {
t.counterValue--
}
if t.lengthEnabled {
t.counterReload = false
}
}
func (t *Triangle) output() byte {
if !t.enabled {
return 0
}
if t.lengthValue == 0 {
return 0
}
if t.counterValue == 0 {
return 0
}
return triangleTable[t.dutyValue]
}
// Noise
type Noise struct {
enabled bool
mode bool
shiftRegister uint16
lengthEnabled bool
lengthValue byte
timerPeriod uint16
timerValue uint16
envelopeEnabled bool
envelopeLoop bool
envelopeStart bool
envelopePeriod byte
envelopeValue byte
envelopeVolume byte
constantVolume byte
}
func (n *Noise) Save(encoder *gob.Encoder) error {
encoder.Encode(n.enabled)
encoder.Encode(n.mode)
encoder.Encode(n.shiftRegister)
encoder.Encode(n.lengthEnabled)
encoder.Encode(n.lengthValue)
encoder.Encode(n.timerPeriod)
encoder.Encode(n.timerValue)
encoder.Encode(n.envelopeEnabled)
encoder.Encode(n.envelopeLoop)
encoder.Encode(n.envelopeStart)
encoder.Encode(n.envelopePeriod)
encoder.Encode(n.envelopeValue)
encoder.Encode(n.envelopeVolume)
encoder.Encode(n.constantVolume)
return nil
}
func (n *Noise) Load(decoder *gob.Decoder) error {
decoder.Decode(&n.enabled)
decoder.Decode(&n.mode)
decoder.Decode(&n.shiftRegister)
decoder.Decode(&n.lengthEnabled)
decoder.Decode(&n.lengthValue)
decoder.Decode(&n.timerPeriod)
decoder.Decode(&n.timerValue)
decoder.Decode(&n.envelopeEnabled)
decoder.Decode(&n.envelopeLoop)
decoder.Decode(&n.envelopeStart)
decoder.Decode(&n.envelopePeriod)
decoder.Decode(&n.envelopeValue)
decoder.Decode(&n.envelopeVolume)
decoder.Decode(&n.constantVolume)
return nil
}
func (n *Noise) writeControl(value byte) {
n.lengthEnabled = (value>>5)&1 == 0
n.envelopeLoop = (value>>5)&1 == 1
n.envelopeEnabled = (value>>4)&1 == 0
n.envelopePeriod = value & 15
n.constantVolume = value & 15
n.envelopeStart = true
}
func (n *Noise) writePeriod(value byte) {
n.mode = value&0x80 == 0x80
n.timerPeriod = noiseTable[value&0x0F]
}
func (n *Noise) writeLength(value byte) {
n.lengthValue = lengthTable[value>>3]
n.envelopeStart = true
}
func (n *Noise) stepTimer() {
if n.timerValue == 0 {
n.timerValue = n.timerPeriod
var shift byte
if n.mode {
shift = 6
} else {
shift = 1
}
b1 := n.shiftRegister & 1
b2 := (n.shiftRegister >> shift) & 1
n.shiftRegister >>= 1
n.shiftRegister |= (b1 ^ b2) << 14
} else {
n.timerValue--
}
}
func (n *Noise) stepEnvelope() {
if n.envelopeStart {
n.envelopeVolume = 15
n.envelopeValue = n.envelopePeriod
n.envelopeStart = false
} else if n.envelopeValue > 0 {
n.envelopeValue--
} else {
if n.envelopeVolume > 0 {
n.envelopeVolume--
} else if n.envelopeLoop {
n.envelopeVolume = 15
}
n.envelopeValue = n.envelopePeriod
}
}
func (n *Noise) stepLength() {
if n.lengthEnabled && n.lengthValue > 0 {
n.lengthValue--
}
}
func (n *Noise) output() byte {
if !n.enabled {
return 0
}
if n.lengthValue == 0 {
return 0
}
if n.shiftRegister&1 == 1 {
return 0
}
if n.envelopeEnabled {
return n.envelopeVolume
} else {
return n.constantVolume
}
}
// DMC
type DMC struct {
cpu *CPU
enabled bool
value byte
sampleAddress uint16
sampleLength uint16
currentAddress uint16
currentLength uint16
shiftRegister byte
bitCount byte
tickPeriod byte
tickValue byte
loop bool
irq bool
}
func (d *DMC) Save(encoder *gob.Encoder) error {
encoder.Encode(d.enabled)
encoder.Encode(d.value)
encoder.Encode(d.sampleAddress)
encoder.Encode(d.sampleLength)
encoder.Encode(d.currentAddress)
encoder.Encode(d.currentLength)
encoder.Encode(d.shiftRegister)
encoder.Encode(d.bitCount)
encoder.Encode(d.tickPeriod)
encoder.Encode(d.tickValue)
encoder.Encode(d.loop)
encoder.Encode(d.irq)
return nil
}
func (d *DMC) Load(decoder *gob.Decoder) error {
decoder.Decode(&d.enabled)
decoder.Decode(&d.value)
decoder.Decode(&d.sampleAddress)
decoder.Decode(&d.sampleLength)
decoder.Decode(&d.currentAddress)
decoder.Decode(&d.currentLength)
decoder.Decode(&d.shiftRegister)
decoder.Decode(&d.bitCount)
decoder.Decode(&d.tickPeriod)
decoder.Decode(&d.tickValue)
decoder.Decode(&d.loop)
decoder.Decode(&d.irq)
return nil
}
func (d *DMC) writeControl(value byte) {
d.irq = value&0x80 == 0x80
d.loop = value&0x40 == 0x40
d.tickPeriod = dmcTable[value&0x0F]
}
func (d *DMC) writeValue(value byte) {
d.value = value & 0x7F
}
func (d *DMC) writeAddress(value byte) {
// Sample address = %11AAAAAA.AA000000
d.sampleAddress = 0xC000 | (uint16(value) << 6)
}
func (d *DMC) writeLength(value byte) {
// Sample length = %0000LLLL.LLLL0001
d.sampleLength = (uint16(value) << 4) | 1
}
func (d *DMC) restart() {
d.currentAddress = d.sampleAddress
d.currentLength = d.sampleLength
}
func (d *DMC) stepTimer() {
if !d.enabled {
return
}
d.stepReader()
if d.tickValue == 0 {
d.tickValue = d.tickPeriod
d.stepShifter()
} else {
d.tickValue--
}
}
func (d *DMC) stepReader() {
if d.currentLength > 0 && d.bitCount == 0 {
d.cpu.stall += 4
d.shiftRegister = d.cpu.Read(d.currentAddress)
d.bitCount = 8
d.currentAddress++
if d.currentAddress == 0 {
d.currentAddress = 0x8000
}
d.currentLength--
if d.currentLength == 0 && d.loop {
d.restart()
}
}
}
func (d *DMC) stepShifter() {
if d.bitCount == 0 {
return
}
if d.shiftRegister&1 == 1 {
if d.value <= 125 {
d.value += 2
}
} else {
if d.value >= 2 {
d.value -= 2
}
}
d.shiftRegister >>= 1
d.bitCount--
}
func (d *DMC) output() byte {
return d.value
}