Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
akatsuki105 committed Apr 12, 2021
1 parent ed0f085 commit 56f9f88
Show file tree
Hide file tree
Showing 2 changed files with 262 additions and 2 deletions.
260 changes: 258 additions & 2 deletions pkg/gba/apu.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
package gba

import (
"math"
"mettaur/pkg/ram"
"mettaur/pkg/util"
)

var waveSamples byte
var wavePosition byte

const (
SND_FREQUENCY = 32768
SAMPLE_TIME float64 = 1.0 / 32768
CPU_FREQ_HZ = 16777216
SND_FREQUENCY = 32768
SND_SAMPLES = 512
BUFF_SAMPLES = ((SND_SAMPLES) * 16 * 2)
BUFF_SAMPLES_MSK = ((BUFF_SAMPLES) - 1)
SAMPLE_TIME float64 = 1.0 / 32768
)

const (
Expand Down Expand Up @@ -155,3 +163,251 @@ func (g *GBA) disableSoundChan(ch int) {
cntx = cntx & ^(1 << ch)
g._setRAM8(ram.SOUNDCNT_X, cntx)
}

func (g *GBA) waveSample() int8 {
cntx, wave := g._getRAM(ram.SOUNDCNT_X), uint16(g._getRAM(ram.SOUND3CNT_L))
if !(util.Bit(cntx, 2) && util.Bit(wave, 7)) {
return 0
}

// Actual frequency in Hertz
freqHz := g._getRAM(ram.SOUND3CNT_X) & 2047
frequency := 2097152 / (2048 - float64(freqHz))

cnth := uint16(g._getRAM(ram.SOUND3CNT_H))

// Full length of the generated wave (if enabled) in seconds
soundLen := cnth & 0xff
length := (256 - float64(soundLen)) / 256.

// Numbers of samples that a single "cycle" (all entries on Wave RAM) takes at output sample rate
cycleSamples := SND_FREQUENCY / frequency

// Length reached check (if so, just disable the channel and return silence)
if util.Bit(cntx, 14) {
g.apu[2].lengthTime += SAMPLE_TIME
if g.apu[2].lengthTime >= length {
g.disableSoundChan(2)
return 0
}
}

g.apu[2].samples++
if g.apu[2].samples >= cycleSamples {
g.apu[2].samples -= cycleSamples

waveSamples--
if waveSamples > 0 {
wavePosition = (wavePosition + 1) & 0b0011_1111
} else {
g.waveReset()
}
}

waveAddr := (uint32(wavePosition)>>1)&0x1f + ram.WAVE_RAM
samp := int8(byte(g._getRAM(waveAddr))&0xf) - 8
if wavePosition&1 == 0 {
samp = int8((byte(g._getRAM(waveAddr))>>4)&0xf) - 8
}

volume := (cnth >> 13) & 0x7
switch volume {
case 0:
samp = 0
case 1:
samp >>= 0
case 2:
samp >>= 1
case 3:
samp >>= 2
default:
samp = (samp >> 2) * 3
}

if samp >= 0 {
return samp * PSG_MAX / 7
}
return samp * PSG_MIN / (-8)
}

func (g *GBA) noiseSample() int8 {
cntx := g._getRAM(ram.SOUNDCNT_X)
if !util.Bit(cntx, 3) {
return 0
}

cnth := g._getRAM(ram.SOUND4CNT_H)

// Actual frequency in Hertz
freqDiv, freqRsh := float64(cnth&0x7), float64((cnth>>4)&0xf)
if freqDiv == 0 {
freqDiv = 2
}
frequency := (524288 * freqDiv) / math.Pow(2, freqRsh+1)

cntl := g._getRAM(ram.SOUND4CNT_L)
// Full length of the generated wave (if enabled) in seconds
soundLen := cntl & 0x3f
length := (64 - float64(soundLen)) / 256

// Length reached check (if so, just disable the channel and return silence)
if util.Bit(cnth, 14) {
g.apu[3].lengthTime += SAMPLE_TIME
if g.apu[3].lengthTime >= length {
g.disableSoundChan(3)
return 0
}
}

// Envelope volume change interval in seconds
envStep := (cntl >> 8) & 0x7
envelopeInterval := float64(envStep) / 64

// Envelope volume
envelope := (cntl >> 12) & 0xf
if envStep != 0 {
g.apu[3].envTime += SAMPLE_TIME
if g.apu[3].envTime >= envelopeInterval {
g.apu[3].envTime -= envelopeInterval

if util.Bit(cntl, 11) {
if envelope < 0xf {
envelope++
}
} else {
if envelope > 0x0 {
envelope--
}
}

newCntl := (cntl & ^uint32(0xf000)) | (envelope << 12)
g._setRAM32(ram.SOUND4CNT_L, newCntl)
}
}

// Numbers of samples that a single cycle (pseudo-random noise value) takes at output sample rate
cycleSamples := SND_FREQUENCY / frequency

carry := byte(g.apu[3].lfsr & 0b1)
g.apu[3].samples++
if g.apu[3].samples >= cycleSamples {
g.apu[3].samples -= cycleSamples
g.apu[3].lfsr >>= 1

high := uint16(byte(g.apu[3].lfsr&1) ^ carry)
if util.Bit(cnth, 3) {
g.apu[3].lfsr |= (high << 6)
} else {
g.apu[3].lfsr |= (high << 14)
}
}

if carry != 0 {
return int8((float64(envelope) / 15) * PSG_MAX)
}
return int8((float64(envelope) / 15) * PSG_MIN)
}

func (g *GBA) waveReset() {
wave := uint16(g._getRAM(ram.SOUND3CNT_L))
if util.Bit(wave, 5) {
// 64 samples (at 4 bits each, uses both banks so initial position is always 0)
wavePosition, waveSamples = 0, 64
return
}
// 32 samples (at 4 bits each, bank selectable through Wave Control register)
wavePosition, waveSamples = byte((wave>>1)&0x20), 32
}

var (
sndCurPlay uint32 = 0
sndCurWrite uint32 = 0x200
)

// This prevents the cursor from overflowing. Call after some time (like per frame, or per second...)
func (g *GBA) soundBufferWrap() {
left, right := sndCurPlay/BUFF_SAMPLES, sndCurWrite/BUFF_SAMPLES
if left == right {
sndCurPlay &= BUFF_SAMPLES_MSK
sndCurWrite &= BUFF_SAMPLES_MSK
}
}

var sndBuffer [BUFF_SAMPLES]int16

func (g *GBA) soundMix() {
for i := 0; i < 4; i++ {
// TODO
}

// Avoid desync between the Play cursor and the Write cursor
sndCurPlay += uint32(int32(sndCurWrite-sndCurPlay)>>8) & ^uint32(1)
}

var (
fifoALen, fifoBLen byte
fifoA, fifoB [0x20]int8
)

func (g *GBA) fifoACopy() {
// FIFO A full
if fifoALen+4 > 0x20 {
return
}

for i := uint32(0); i < 4; i++ {
fifoA[fifoALen] = int8(g._getRAM(ram.FIFO_A + i))
i++
}
}
func (g *GBA) fifoBCopy() {
// FIFO B full
if fifoBLen+4 > 0x20 {
return
}

for i := uint32(0); i < 4; i++ {
fifoB[fifoBLen] = int8(g._getRAM(ram.FIFO_B + i))
i++
}
}

var (
fifoASamp, fifoBSamp int8
)

func (g *GBA) fifoALoad() {
if fifoALen == 0 {
return
}

fifoASamp = fifoA[0]
fifoALen--

for i := byte(0); i < fifoALen; i++ {
fifoA[i] = fifoA[i+1]
}
}

func (g *GBA) fifoBLoad() {
if fifoBLen == 0 {
return
}

fifoBSamp = fifoB[0]
fifoBLen--

for i := byte(0); i < fifoBLen; i++ {
fifoB[i] = fifoB[i+1]
}
}

var (
sndCycles = 0
psgVolLut = [8]int32{0x000, 0x024, 0x049, 0x06d, 0x092, 0x0b6, 0x0db, 0x100}
psgRshLut = [4]int32{0xa, 0x9, 0x8, 0x7}
)

func (g *GBA) clip(val int32) int16 {
return 0
}
4 changes: 4 additions & 0 deletions pkg/gba/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ func (g *GBA) getRAM8(addr uint32, s bool) byte {

func (g *GBA) setRAM32(addr, value uint32, s bool) {
g.timer(g.waitBus(addr, 32, s))
g._setRAM32(addr, value)
}

func (g *GBA) _setRAM32(addr, value uint32) {
b0, b1, b2, b3 := value&0xff, (value>>8)&0xff, (value>>16)&0xff, (value>>24)&0xff
g._setRAM8(addr, byte(b0))
g._setRAM8(addr+1, byte(b1))
Expand Down

0 comments on commit 56f9f88

Please sign in to comment.