mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 19:28:57 +01:00
audio: Move drivers to internal/driver
This commit is contained in:
parent
5c73357ef8
commit
2840bafd0a
@ -21,6 +21,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/exp/audio/internal/driver"
|
||||
)
|
||||
|
||||
type mixingStream struct {
|
||||
@ -44,7 +45,6 @@ func min(a, b int) int {
|
||||
const (
|
||||
channelNum = 2
|
||||
bytesPerSample = 2
|
||||
bitsPerSample = bytesPerSample * 8
|
||||
|
||||
// TODO: This assumes that channelNum is a power of 2.
|
||||
mask = ^(channelNum*bytesPerSample - 1)
|
||||
@ -197,15 +197,15 @@ func NewContext(sampleRate int) (*Context, error) {
|
||||
players: map[*Player]struct{}{},
|
||||
}
|
||||
// TODO: Rename this other than player
|
||||
p, err := newPlayer(c.stream, sampleRate)
|
||||
p, err := driver.NewPlayer(c.stream, sampleRate, channelNum, bytesPerSample)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
// TODO: Is it OK to close asap?
|
||||
defer p.close()
|
||||
defer p.Close()
|
||||
for {
|
||||
err := p.proceed()
|
||||
err := p.Proceed()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
@ -14,25 +14,26 @@
|
||||
|
||||
// +build js
|
||||
|
||||
package audio
|
||||
package driver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/gopherjs/gopherjs/js"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
type player struct {
|
||||
type Player struct {
|
||||
src io.Reader
|
||||
sampleRate int
|
||||
channelNum int
|
||||
bytesPerSample int
|
||||
positionInSamples int64
|
||||
context *js.Object
|
||||
bufferSource *js.Object
|
||||
}
|
||||
|
||||
func newPlayer(src io.Reader, sampleRate int) (*player, error) {
|
||||
func NewPlayer(src io.Reader, sampleRate, channelNum, bytesPerSample int) (*Player, error) {
|
||||
class := js.Global.Get("AudioContext")
|
||||
if class == js.Undefined {
|
||||
class = js.Global.Get("webkitAudioContext")
|
||||
@ -40,9 +41,11 @@ func newPlayer(src io.Reader, sampleRate int) (*player, error) {
|
||||
if class == js.Undefined {
|
||||
return nil, errors.New("audio: audio couldn't be initialized")
|
||||
}
|
||||
p := &player{
|
||||
p := &Player{
|
||||
src: src,
|
||||
sampleRate: sampleRate,
|
||||
channelNum: channelNum,
|
||||
bytesPerSample: bytesPerSample,
|
||||
bufferSource: nil,
|
||||
context: class.New(),
|
||||
}
|
||||
@ -67,8 +70,12 @@ func max64(a, b int64) int64 {
|
||||
return b
|
||||
}
|
||||
|
||||
func (p *player) proceed() error {
|
||||
bufferSize := p.sampleRate * bytesPerSample * channelNum / ebiten.FPS
|
||||
const (
|
||||
// 1024 seems not enough (some noise remains after the tab is deactivated).
|
||||
bufferSize = 2048
|
||||
)
|
||||
|
||||
func (p *Player) Proceed() error {
|
||||
c := int64(p.context.Get("currentTime").Float() * float64(p.sampleRate))
|
||||
if p.positionInSamples < c {
|
||||
p.positionInSamples = c
|
||||
@ -76,7 +83,7 @@ func (p *player) proceed() error {
|
||||
b := make([]byte, bufferSize)
|
||||
n, err := p.src.Read(b)
|
||||
if 0 < n {
|
||||
buf := p.context.Call("createBuffer", channelNum, n/bytesPerSample/channelNum, p.sampleRate)
|
||||
buf := p.context.Call("createBuffer", p.channelNum, n/p.bytesPerSample/p.channelNum, p.sampleRate)
|
||||
l := buf.Call("getChannelData", 0)
|
||||
r := buf.Call("getChannelData", 1)
|
||||
il, ir := toLR(b[:n])
|
||||
@ -96,7 +103,7 @@ func (p *player) proceed() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *player) close() error {
|
||||
func (p *Player) Close() error {
|
||||
if p.bufferSource == nil {
|
||||
return nil
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
|
||||
// +build !js,!windows
|
||||
|
||||
package audio
|
||||
package driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -28,7 +28,7 @@ const (
|
||||
maxBufferNum = 8
|
||||
)
|
||||
|
||||
type player struct {
|
||||
type Player struct {
|
||||
alSource al.Source
|
||||
alBuffers []al.Buffer
|
||||
source io.Reader
|
||||
@ -36,7 +36,7 @@ type player struct {
|
||||
isClosed bool
|
||||
}
|
||||
|
||||
func newPlayer(src io.Reader, sampleRate int) (*player, error) {
|
||||
func NewPlayer(src io.Reader, sampleRate, channelNum, bytesPerSample int) (*Player, error) {
|
||||
if e := al.OpenDevice(); e != nil {
|
||||
return nil, fmt.Errorf("audio: OpenAL initialization failed: %v", e)
|
||||
}
|
||||
@ -44,13 +44,13 @@ func newPlayer(src io.Reader, sampleRate int) (*player, error) {
|
||||
if err := al.Error(); err != 0 {
|
||||
return nil, fmt.Errorf("audio: al.GenSources error: %d", err)
|
||||
}
|
||||
p := &player{
|
||||
p := &Player{
|
||||
alSource: s[0],
|
||||
alBuffers: []al.Buffer{},
|
||||
source: src,
|
||||
sampleRate: sampleRate,
|
||||
}
|
||||
runtime.SetFinalizer(p, (*player).close)
|
||||
runtime.SetFinalizer(p, (*Player).Close)
|
||||
|
||||
bs := al.GenBuffers(maxBufferNum)
|
||||
emptyBytes := make([]byte, bufferSize)
|
||||
@ -72,7 +72,7 @@ var (
|
||||
tmpAlBuffers = make([]al.Buffer, maxBufferNum)
|
||||
)
|
||||
|
||||
func (p *player) proceed() error {
|
||||
func (p *Player) Proceed() error {
|
||||
if err := al.Error(); err != 0 {
|
||||
return fmt.Errorf("audio: before proceed: %d", err)
|
||||
}
|
||||
@ -113,7 +113,7 @@ func (p *player) proceed() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *player) close() error {
|
||||
func (p *Player) Close() error {
|
||||
if err := al.Error(); err != 0 {
|
||||
return fmt.Errorf("audio: error before closing: %d", err)
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package audio
|
||||
package driver
|
||||
|
||||
// #cgo LDFLAGS: -lwinmm
|
||||
//
|
||||
@ -75,7 +75,7 @@ func releaseSemaphore() {
|
||||
<-sem
|
||||
}
|
||||
|
||||
type player struct {
|
||||
type Player struct {
|
||||
src io.Reader
|
||||
out C.HWAVEOUT
|
||||
buffer []byte
|
||||
@ -84,21 +84,21 @@ type player struct {
|
||||
|
||||
const bufferSize = 1024
|
||||
|
||||
func newPlayer(src io.Reader, sampleRate int) (*player, error) {
|
||||
const numBlockAlign = channelNum * bitsPerSample / 8
|
||||
func NewPlayer(src io.Reader, sampleRate, channelNum, bytesPerSample int) (*Player, error) {
|
||||
const numBlockAlign = channelNum * bytesPerSample
|
||||
f := C.WAVEFORMATEX{
|
||||
wFormatTag: C.WAVE_FORMAT_PCM,
|
||||
nChannels: channelNum,
|
||||
nSamplesPerSec: C.DWORD(sampleRate),
|
||||
nAvgBytesPerSec: C.DWORD(sampleRate) * numBlockAlign,
|
||||
wBitsPerSample: bitsPerSample,
|
||||
wBitsPerSample: bytesPerSample * 8,
|
||||
nBlockAlign: numBlockAlign,
|
||||
}
|
||||
var w C.HWAVEOUT
|
||||
if err := C.waveOutOpen2(&w, &f); err != C.MMSYSERR_NOERROR {
|
||||
return nil, fmt.Errorf("audio: waveOutOpen error: %d", err)
|
||||
}
|
||||
p := &player{
|
||||
p := &Player{
|
||||
src: src,
|
||||
out: w,
|
||||
buffer: []byte{},
|
||||
@ -114,7 +114,7 @@ func newPlayer(src io.Reader, sampleRate int) (*player, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *player) proceed() error {
|
||||
func (p *Player) Proceed() error {
|
||||
if len(p.buffer) < bufferSize {
|
||||
b := make([]byte, bufferSize)
|
||||
n, err := p.src.Read(b)
|
||||
@ -130,7 +130,7 @@ func (p *player) proceed() error {
|
||||
headerToWrite := (*header)(nil)
|
||||
for _, h := range p.headers {
|
||||
// TODO: Need to check WHDR_DONE?
|
||||
if h.waveHdr.dwFlags & C.WHDR_INQUEUE == 0 {
|
||||
if h.waveHdr.dwFlags&C.WHDR_INQUEUE == 0 {
|
||||
headerToWrite = h
|
||||
break
|
||||
}
|
||||
@ -146,6 +146,6 @@ func (p *player) proceed() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *player) close() {
|
||||
func (p *Player) Close() {
|
||||
// TODO: Implement this
|
||||
}
|
Loading…
Reference in New Issue
Block a user