Skip to content

Commit

Permalink
Merge pull request #10 from ichirin2501/use-ebitengine
Browse files Browse the repository at this point in the history
Use portaudio
  • Loading branch information
ichirin2501 authored Jan 13, 2024
2 parents 9c20d70 + c499149 commit b1b3953
Show file tree
Hide file tree
Showing 13 changed files with 830 additions and 221 deletions.
2 changes: 1 addition & 1 deletion Dockerfile.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ FROM golang:1.20-buster

RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
gcc libgl1-mesa-dev xorg-dev libasound2-dev
gcc libgl1-mesa-dev xorg-dev portaudio19-dev

WORKDIR /work
COPY . .
Expand Down
147 changes: 78 additions & 69 deletions cmd/rgnes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/driver/desktop"
"github.com/hajimehoshi/oto"
"github.com/gordonklaus/portaudio"
"github.com/ichirin2501/rgnes/nes"
)

Expand Down Expand Up @@ -56,28 +56,65 @@ func (r *renderer) Refresh() {
r.currImg.Refresh()
}

type player struct {
p *oto.Player
buf []byte
// ref: https://github.com/fogleman/nes/blob/3880f3400500b1ff2e89af4e12e90be46c73ae07/ui/audio.go#L5
type Player struct {
stream *portaudio.Stream
sampleRate float64
outputChannels int
channel chan float32
}

func newPlayer() (*player, error) {
c, err := oto.NewContext(44100, 1, 1, 1)
func newPlayer() (*Player, error) {
host, err := portaudio.DefaultHostApi()
if err != nil {
return nil, err
}
p := c.NewPlayer()
return &player{
p: p,
buf: make([]byte, 1),
}, nil
}
parameters := portaudio.HighLatencyParameters(nil, host.DefaultOutputDevice)

p := Player{
sampleRate: parameters.SampleRate,
outputChannels: parameters.Output.Channels,
// If this channel size is too large (e.g. 44100), the BGM will be delayed. Make the size not too big
channel: make(chan float32, 3000),
}

func (p *player) Sample(v float32) {
p.buf[0] = byte(v * 0xFF)
if _, err := p.p.Write(p.buf); err != nil {
fmt.Println("why: ", err)
cbFunc := func(out []float32) {
var output float32
for i := range out {
if i%p.outputChannels == 0 {
select {
case sample := <-p.channel:
output = sample
default:
output = 0
}
}
out[i] = output
}
}
stream, err := portaudio.OpenStream(parameters, cbFunc)
if err != nil {
return nil, err
}

p.stream = stream
return &p, nil
}

func (p *Player) Start() error {
return p.stream.Start()
}

func (p *Player) Stop() error {
return p.stream.Close()
}

func (p *Player) Sample(v float32) {
p.channel <- v
}

func (p *Player) SampleRate() float64 {
return p.sampleRate
}

func realMain() error {
Expand All @@ -94,8 +131,9 @@ func realMain() error {

canvasImg1 := canvas.NewImageFromImage(img1)
canvasImg2 := canvas.NewImageFromImage(img2)
canvasImg1.SetMinSize(fyne.NewSize(256, 240))
canvasImg2.SetMinSize(fyne.NewSize(256, 240))
canvasImg1.SetMinSize(fyne.NewSize(256*2, 240*2))
canvasImg2.SetMinSize(fyne.NewSize(256*2, 240*2))

canvasImg1.ScaleMode = canvas.ImageScalePixels
canvasImg2.ScaleMode = canvas.ImageScalePixels

Expand All @@ -115,61 +153,32 @@ func realMain() error {
return err
}

player, err := newPlayer()
portaudio.Initialize()
defer portaudio.Terminate()
player, nil := newPlayer()
if err != nil {
return err
}
if err := player.Start(); err != nil {
return err
}
defer player.Stop()

trace := &nes.Trace{}
irp := &nes.Interrupter{}

m := mapper.MirroingType()
ppu := nes.NewPPU(renderer, mapper, m, irp)
joypad := nes.NewJoypad()
apu := nes.NewAPU(irp, player)
cpuBus := nes.NewBus(ppu, apu, mapper, joypad)

cpu := nes.NewCPU(cpuBus, irp, nes.WithTracer(trace))
apu.PowerUp()
cpu.PowerUp()
n := nes.New(mapper, renderer, player)
n.PowerUp()

if deskCanvas, ok := win.Canvas().(desktop.Canvas); ok {
deskCanvas.SetOnKeyDown(func(k *fyne.KeyEvent) {
updateKey(win, cpu, joypad, k.Name, true)
updateKey(win, n, k.Name, true)
})
deskCanvas.SetOnKeyUp(func(k *fyne.KeyEvent) {
updateKey(win, cpu, joypad, k.Name, false)
updateKey(win, n, k.Name, false)
})
}

go func() {
for {
trace.Reset()

// ここでppuの状態を記録しておく
trace.SetPPUX(uint16(ppu.Cycle))
trace.SetPPUY(uint16(ppu.Scanline))
// v := ppu.FetchV()
// mp0 := mapper.Read(0)
// ppuBuf := ppu.FetchBuffer()
//beforeScanline := ppu.Scanline
cpu.Step()

// fmt.Printf("%s apuSteps:%d\tapuFrameMode:%d\tapuFrameSeqStep:%d\tapuPulse1LC:%d\tframeIRQFlag:%v\tnewfval:%v\twriteDelayFC:%v\n", trace.NESTestString(),
// apu.FetchFrameStep(),
// apu.FetchFrameMode(),
// apu.FetchFrameSeqStep(),
// apu.FetchPulse1LC(),
// apu.FetchFrameIRQFlag(),
// apu.FetchNewFrameCounterVal(),
// apu.FetchWriteDelayFC(),
// )
//fmt.Printf("%s ppu.v:0x%04X ppu.buf:0x%02X mapper[0]:0x%02X\n", trace.NESTestString(), v, ppuBuf, mp0)
//fmt.Printf("0x6000 = 0x%02X\n", cpuBus.ReadForTest(0x6000))

// if cpu.FetchCycles()*3 != ppu.Clock {
// panic("eeeeeeeeeeeeeeeeee")
// }
n.Step()
}
}()

Expand All @@ -178,27 +187,27 @@ func realMain() error {
return nil
}

func updateKey(win fyne.Window, cpu *nes.CPU, j *nes.Joypad, k fyne.KeyName, pressed bool) {
func updateKey(win fyne.Window, n *nes.NES, k fyne.KeyName, pressed bool) {
switch k {
case fyne.KeyEscape:
win.Close()
case fyne.KeyR:
cpu.Reset()
n.Reset()
case fyne.KeySpace:
j.SetButtonStatus(nes.ButtonSelect, pressed)
n.SetButtonStatus(nes.ButtonSelect, pressed)
case fyne.KeyReturn:
j.SetButtonStatus(nes.ButtonStart, pressed)
n.SetButtonStatus(nes.ButtonStart, pressed)
case fyne.KeyUp:
j.SetButtonStatus(nes.ButtonUP, pressed)
n.SetButtonStatus(nes.ButtonUP, pressed)
case fyne.KeyDown:
j.SetButtonStatus(nes.ButtonDown, pressed)
n.SetButtonStatus(nes.ButtonDown, pressed)
case fyne.KeyLeft:
j.SetButtonStatus(nes.ButtonLeft, pressed)
n.SetButtonStatus(nes.ButtonLeft, pressed)
case fyne.KeyRight:
j.SetButtonStatus(nes.ButtonRight, pressed)
n.SetButtonStatus(nes.ButtonRight, pressed)
case fyne.KeyZ:
j.SetButtonStatus(nes.ButtonA, pressed)
n.SetButtonStatus(nes.ButtonA, pressed)
case fyne.KeyX:
j.SetButtonStatus(nes.ButtonB, pressed)
n.SetButtonStatus(nes.ButtonB, pressed)
}
}
48 changes: 29 additions & 19 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,38 @@ module github.com/ichirin2501/rgnes
go 1.20

require (
fyne.io/fyne/v2 v2.1.4
github.com/hajimehoshi/oto v1.0.1
github.com/stretchr/testify v1.6.1
fyne.io/fyne/v2 v2.4.3
github.com/gordonklaus/portaudio v0.0.0-20230709114228-aafa478834f5
github.com/stretchr/testify v1.8.4
)

require (
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be // indirect
github.com/godbus/dbus/v5 v5.0.4 // indirect
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect
github.com/fredbi/uri v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fyne-io/gl-js v0.0.0-20220119005834-d2da28d9ccfe // indirect
github.com/fyne-io/glfw-js v0.0.0-20220120001248-ee7290d23504 // indirect
github.com/fyne-io/image v0.0.0-20220602074514-4956b0afb3d2 // indirect
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b // indirect
github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8 // indirect
github.com/go-text/typesetting v0.0.0-20230905121921-abdbcca6e0eb // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect
github.com/yuin/goldmark v1.3.8 // indirect
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 // indirect
golang.org/x/image v0.0.0-20200430140353-33d19683fad8 // indirect
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6 // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
golang.org/x/text v0.3.3 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
github.com/tevino/abool v1.2.0 // indirect
github.com/yuin/goldmark v1.5.5 // indirect
golang.org/x/image v0.12.0 // indirect
golang.org/x/mobile v0.0.0-20230922142353-e2f452493d57 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 // indirect
)
Loading

0 comments on commit b1b3953

Please sign in to comment.