mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 10:48:53 +01:00
audio: Add AudioContext.Update (#177)
This commit is contained in:
parent
77b62615b2
commit
71312ba26f
@ -35,6 +35,7 @@ var (
|
||||
)
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
audioContext.Update()
|
||||
if !audioLoaded {
|
||||
select {
|
||||
case <-audioLoadingDone:
|
||||
|
@ -131,6 +131,7 @@ func addNote() error {
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
audioContext.Update()
|
||||
defer func() {
|
||||
frames++
|
||||
}()
|
||||
|
@ -201,6 +201,7 @@ func init() {
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
audioContext.Update()
|
||||
updateInput()
|
||||
for i, key := range keys {
|
||||
if keyStates[key] != 1 {
|
||||
|
@ -79,6 +79,7 @@ func (s *stream) Seek(offset int64, whence int) (int64, error) {
|
||||
var player *audio.Player
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
audioContext.Update()
|
||||
if player == nil {
|
||||
var err error
|
||||
player, err = audioContext.NewPlayer(&stream{})
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
// TODO: In JavaScript, mixing should be done by WebAudio for performance.
|
||||
type mixedPlayersStream struct {
|
||||
context *Context
|
||||
writtenBytes int
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
@ -37,9 +38,19 @@ func (s *mixedPlayersStream) Read(b []byte) (int, error) {
|
||||
s.context.Lock()
|
||||
defer s.context.Unlock()
|
||||
|
||||
// TODO: 60 (FPS) is a magic number
|
||||
bytesPerFrame := s.context.sampleRate * 4 / 60
|
||||
x := s.context.frames*bytesPerFrame + len(b)
|
||||
if x <= s.writtenBytes {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
l := len(b) / 4 * 4
|
||||
if len(s.context.players) == 0 {
|
||||
return 0, nil
|
||||
l := min(len(b), x-s.writtenBytes)
|
||||
copy(b, make([]byte, l))
|
||||
s.writtenBytes += l
|
||||
return l, nil
|
||||
}
|
||||
closed := []*Player{}
|
||||
ll := l
|
||||
@ -76,6 +87,7 @@ func (s *mixedPlayersStream) Read(b []byte) (int, error) {
|
||||
for _, p := range closed {
|
||||
delete(s.context.players, p)
|
||||
}
|
||||
s.writtenBytes += ll
|
||||
return ll, nil
|
||||
}
|
||||
|
||||
@ -86,6 +98,7 @@ type Context struct {
|
||||
stream *mixedPlayersStream
|
||||
players map[*Player]struct{}
|
||||
innerPlayer *player
|
||||
frames int
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@ -95,7 +108,9 @@ func NewContext(sampleRate int) *Context {
|
||||
sampleRate: sampleRate,
|
||||
players: map[*Player]struct{}{},
|
||||
}
|
||||
c.stream = &mixedPlayersStream{c}
|
||||
c.stream = &mixedPlayersStream{
|
||||
context: c,
|
||||
}
|
||||
p, err := startPlaying(c.stream, c.sampleRate)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("audio: NewContext error: %v", err))
|
||||
@ -104,6 +119,18 @@ func NewContext(sampleRate int) *Context {
|
||||
return c
|
||||
}
|
||||
|
||||
// Update proceeds the inner (logical) time of the context by 1/60 second.
|
||||
// This is expected to be called in the game's updating function (sync mode)
|
||||
// or an independent goroutine with timers (unsync mode).
|
||||
// In sync mode, the game logical time syncs the audio logical time and
|
||||
// you will find audio stops when the game stops e.g. when the window is deactivated.
|
||||
// In unsync mode, the audio never stops even when the game stops.
|
||||
func (c *Context) Update() {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.frames++
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
context *Context
|
||||
src io.ReadSeeker
|
||||
|
@ -79,11 +79,6 @@ func (p *player) proceed() error {
|
||||
const bytesPerSample = channelNum * 16 / 8
|
||||
bufferSize := p.sampleRate * bytesPerSample / 60
|
||||
c := int64(p.context.Get("currentTime").Float() * float64(p.sampleRate))
|
||||
// Buffer size is relatively big and it is needed to check that c.positionInSample doesn't
|
||||
// proceed too far away (#180).
|
||||
if c+int64(bufferSize) < p.positionInSamples {
|
||||
return nil
|
||||
}
|
||||
if p.positionInSamples < c {
|
||||
p.positionInSamples = c
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ type VorbisStream struct {
|
||||
buf *bytes.Reader
|
||||
}
|
||||
|
||||
// TODO: Rename to DecodeVorbis or Decode?
|
||||
|
||||
func (c *Context) NewVorbisStream(src io.Reader) (*VorbisStream, error) {
|
||||
decoded, channels, sampleRate, err := vorbis.Decode(src)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user