audio: Refactoring

This commit is contained in:
Hajime Hoshi 2016-02-11 18:43:11 +09:00
parent 1e4f486174
commit 1fec0d8203
3 changed files with 38 additions and 32 deletions

View File

@ -19,8 +19,7 @@ import (
) )
type Player struct { type Player struct {
src io.ReadSeeker *player
sampleRate int
} }
// NewPlayer creates a new player with the given data to the given channel. // NewPlayer creates a new player with the given data to the given channel.
@ -32,12 +31,9 @@ type Player struct {
// //
// TODO: Pass sample rate and num of channels. // TODO: Pass sample rate and num of channels.
func NewPlayer(src io.ReadSeeker, sampleRate int) *Player { func NewPlayer(src io.ReadSeeker, sampleRate int) *Player {
return &Player{ return newPlayer(src, sampleRate)
src: src,
sampleRate: sampleRate,
}
} }
func (p *Player) Play() error { func (p *Player) Play() error {
return play(p.src, p.sampleRate) return p.play()
} }

View File

@ -17,7 +17,6 @@
package audio package audio
import ( import (
"errors"
"io" "io"
"io/ioutil" "io/ioutil"
@ -26,12 +25,27 @@ import (
var context *js.Object var context *js.Object
type audioProcessor struct { type player struct {
src io.ReadSeeker src io.ReadSeeker
sampleRate int sampleRate int
position float64 position float64
} }
func newPlayer(src io.ReadSeeker, sampleRate int) *Player {
if context == nil {
if !initialize() {
panic("audio couldn't be initialized")
}
}
p := &player{
src: src,
sampleRate: sampleRate,
position: context.Get("currentTime").Float(),
}
return &Player{p}
}
func toLR(data []byte) ([]int16, []int16) { func toLR(data []byte) ([]int16, []int16) {
l := make([]int16, len(data)/4) l := make([]int16, len(data)/4)
r := make([]int16, len(data)/4) r := make([]int16, len(data)/4)
@ -42,9 +56,9 @@ func toLR(data []byte) ([]int16, []int16) {
return l, r return l, r
} }
func (a *audioProcessor) play() error { func (p *player) play() error {
// TODO: Reading all data at once is temporary implemntation. Treat this as stream. // TODO: Reading all data at once is temporary implemntation. Treat this as stream.
buf, err := ioutil.ReadAll(a.src) buf, err := ioutil.ReadAll(p.src)
if err != nil { if err != nil {
return err return err
} }
@ -53,7 +67,7 @@ func (a *audioProcessor) play() error {
} }
const channelNum = 2 const channelNum = 2
const bytesPerSample = channelNum * 16 / 8 const bytesPerSample = channelNum * 16 / 8
b := context.Call("createBuffer", channelNum, len(buf)/bytesPerSample, a.sampleRate) b := context.Call("createBuffer", channelNum, len(buf)/bytesPerSample, p.sampleRate)
l := b.Call("getChannelData", 0) l := b.Call("getChannelData", 0)
r := b.Call("getChannelData", 1) r := b.Call("getChannelData", 1)
il, ir := toLR(buf) il, ir := toLR(buf)
@ -65,25 +79,11 @@ func (a *audioProcessor) play() error {
s := context.Call("createBufferSource") s := context.Call("createBufferSource")
s.Set("buffer", b) s.Set("buffer", b)
s.Call("connect", context.Get("destination")) s.Call("connect", context.Get("destination"))
s.Call("start", a.position) s.Call("start", p.position)
a.position += b.Get("duration").Float() p.position += b.Get("duration").Float()
return nil return nil
} }
func play(src io.ReadSeeker, sampleRate int) error {
if context == nil {
if !initialize() {
return errors.New("audio couldn't be initialized")
}
}
a := &audioProcessor{
src: src,
sampleRate: sampleRate,
position: context.Get("currentTime").Float(),
}
return a.play()
}
func initialize() bool { func initialize() bool {
// Do nothing in node.js. // Do nothing in node.js.
if js.Global.Get("require") != js.Undefined { if js.Global.Get("require") != js.Undefined {

View File

@ -30,13 +30,23 @@ func (r *readSeekCloser) Close() error {
return nil return nil
} }
func play(src io.ReadSeeker, sampleRate int) error { type player struct {
// TODO: audio.NewPlayer interprets WAV header, which we don't want. *audio.Player
// Use OpenAL or native API instead. }
func newPlayer(src io.ReadSeeker, sampleRate int) *Player {
p, err := audio.NewPlayer(&readSeekCloser{src}, audio.Stereo16, int64(sampleRate)) p, err := audio.NewPlayer(&readSeekCloser{src}, audio.Stereo16, int64(sampleRate))
if err != nil { if err != nil {
return err // TODO: Should we return errors for this method?
panic(err)
} }
pp := &player{p}
return &Player{pp}
}
func (p *player) play() error {
// TODO: audio.NewPlayer interprets WAV header, which we don't want.
// Use OpenAL or native API instead.
return p.Play() return p.Play()
} }