mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 13:07:26 +01:00
loop: Better syncing with audio
This commit is contained in:
parent
0de9828e20
commit
fe3f0b2f1f
@ -33,14 +33,11 @@ type runContext struct {
|
|||||||
currentFPS float64
|
currentFPS float64
|
||||||
runningSlowly bool
|
runningSlowly bool
|
||||||
frames int64
|
frames int64
|
||||||
|
framesForFPS int64
|
||||||
lastUpdated int64
|
lastUpdated int64
|
||||||
lastFPSUpdated int64
|
lastFPSUpdated int64
|
||||||
m sync.RWMutex
|
|
||||||
|
|
||||||
lastAudioFrame int64
|
lastAudioFrame int64
|
||||||
lastAudioFrameTime int64
|
m sync.RWMutex
|
||||||
deltaTime int64
|
|
||||||
targetDeltaTime int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentRunContext *runContext
|
var currentRunContext *runContext
|
||||||
@ -112,7 +109,7 @@ func Run(g GraphicsContext, width, height int, scale float64, title string, fps
|
|||||||
currentRunContext.startRunning()
|
currentRunContext.startRunning()
|
||||||
defer currentRunContext.endRunning()
|
defer currentRunContext.endRunning()
|
||||||
|
|
||||||
n := currentRunContext.adjustedNowWithAudio()
|
n := now()
|
||||||
currentRunContext.lastUpdated = n
|
currentRunContext.lastUpdated = n
|
||||||
currentRunContext.lastFPSUpdated = n
|
currentRunContext.lastFPSUpdated = n
|
||||||
|
|
||||||
@ -126,74 +123,69 @@ func Run(g GraphicsContext, width, height int, scale float64, title string, fps
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *runContext) adjustedNowWithAudio() int64 {
|
func (c *runContext) updateCount(now int64) int {
|
||||||
n := now()
|
count := 0
|
||||||
if audio.CurrentContext() == nil {
|
sync := false
|
||||||
return n
|
|
||||||
|
t := now - c.lastUpdated
|
||||||
|
if t < 0 {
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
if c.lastAudioFrameTime == 0 {
|
|
||||||
c.lastAudioFrameTime = n
|
if audio.CurrentContext() != nil && c.lastAudioFrame != audio.CurrentContext().Frame() {
|
||||||
|
sync = true
|
||||||
|
f := audio.CurrentContext().Frame()
|
||||||
|
if c.frames < f {
|
||||||
|
count = int(f - c.frames)
|
||||||
}
|
}
|
||||||
if f := audio.CurrentContext().Frame(); c.lastAudioFrame != f {
|
|
||||||
c.targetDeltaTime += (f-c.lastAudioFrame)*int64(time.Second)/audio.FPS - (n - c.lastAudioFrameTime)
|
|
||||||
c.lastAudioFrame = f
|
c.lastAudioFrame = f
|
||||||
c.lastAudioFrameTime = n
|
} else {
|
||||||
|
count = int(t * int64(c.fps) / int64(time.Second))
|
||||||
}
|
}
|
||||||
switch {
|
|
||||||
case c.deltaTime > c.targetDeltaTime:
|
// Stabilize FPS.
|
||||||
c.deltaTime -= int64(time.Millisecond)
|
if count == 0 && (int64(time.Second)/int64(c.fps)/2) < t {
|
||||||
if c.deltaTime < c.targetDeltaTime {
|
count = 1
|
||||||
c.deltaTime = c.targetDeltaTime
|
|
||||||
}
|
}
|
||||||
case c.deltaTime < c.targetDeltaTime:
|
if count == 2 && (int64(time.Second)/int64(c.fps)*3/2) > t {
|
||||||
c.deltaTime += int64(time.Millisecond)
|
count = 1
|
||||||
if c.deltaTime > c.targetDeltaTime {
|
|
||||||
c.deltaTime = c.targetDeltaTime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if count > 3 {
|
||||||
|
count = 3
|
||||||
}
|
}
|
||||||
return n + c.deltaTime
|
|
||||||
|
if sync {
|
||||||
|
c.lastUpdated = now
|
||||||
|
} else {
|
||||||
|
c.lastUpdated += int64(count) * int64(time.Second) / int64(c.fps)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.frames += int64(count)
|
||||||
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *runContext) render(g GraphicsContext) error {
|
func (c *runContext) render(g GraphicsContext) error {
|
||||||
fps := c.fps
|
n := now()
|
||||||
clockN := now()
|
|
||||||
n := c.adjustedNowWithAudio()
|
|
||||||
defer func() {
|
|
||||||
// Calc the current FPS.
|
|
||||||
if time.Second > time.Duration(clockN-c.lastFPSUpdated) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentFPS := float64(c.frames) * float64(time.Second) / float64(clockN-c.lastFPSUpdated)
|
|
||||||
c.updateFPS(currentFPS)
|
|
||||||
c.lastFPSUpdated = clockN
|
|
||||||
c.frames = 0
|
|
||||||
}()
|
|
||||||
|
|
||||||
// If lastUpdated is too old, we assume that screen is not shown.
|
|
||||||
if 10*int64(time.Second)/int64(fps) < n-c.lastUpdated {
|
|
||||||
c.lastUpdated = n
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if audio.CurrentContext() != nil {
|
if audio.CurrentContext() != nil {
|
||||||
audio.CurrentContext().Ping()
|
audio.CurrentContext().Ping()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that generally t is a little different from 1/60[sec].
|
count := c.updateCount(n)
|
||||||
t := n - c.lastUpdated
|
if err := g.UpdateAndDraw(count); err != nil {
|
||||||
if t < 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
tt := int(t * int64(fps) / int64(time.Second))
|
|
||||||
|
|
||||||
// As t is not accurate 1/60[sec], errors are accumulated.
|
|
||||||
// To make the FPS stable, set tt 1 if t is a little less than 1/60[sec].
|
|
||||||
if tt == 0 && (int64(time.Second)/int64(fps)-int64(5*time.Millisecond)) < t {
|
|
||||||
tt = 1
|
|
||||||
}
|
|
||||||
if err := g.UpdateAndDraw(tt); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.lastUpdated += int64(tt) * int64(time.Second) / int64(fps)
|
c.framesForFPS++
|
||||||
c.frames++
|
|
||||||
|
// Calc the current FPS.
|
||||||
|
if time.Second > time.Duration(n-c.lastFPSUpdated) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
currentFPS := float64(c.framesForFPS) * float64(time.Second) / float64(n-c.lastFPSUpdated)
|
||||||
|
c.updateFPS(currentFPS)
|
||||||
|
c.lastFPSUpdated = n
|
||||||
|
c.framesForFPS = 0
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user