From edda664ca8a76b860e1fa25bcee652f925ee5743 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 24 Jan 2015 14:50:41 +0900 Subject: [PATCH] audio: Refactoring --- exp/audio/audio.go | 3 ++ internal/audio/audio.go | 89 +++++++++++++++++++++++++++++---- internal/audio/audio_js.go | 91 ++-------------------------------- internal/audio/audio_openal.go | 25 ++++++++++ 4 files changed, 111 insertions(+), 97 deletions(-) create mode 100644 internal/audio/audio_openal.go diff --git a/exp/audio/audio.go b/exp/audio/audio.go index 5c4822e98..6cbd2f481 100644 --- a/exp/audio/audio.go +++ b/exp/audio/audio.go @@ -22,10 +22,13 @@ func SampleRate() int { return audio.SampleRate } +// TODO: better name func AppendToBuffer(channel int, l []float32, r []float32) bool { return audio.Append(channel, l, r) } +// TODO: Add funciton to append samples to the buffer without adjusting. + // TODO: better name func CurrentTime() int { return audio.CurrentBytes() diff --git a/internal/audio/audio.go b/internal/audio/audio.go index 2d6093e24..8dd88515c 100644 --- a/internal/audio/audio.go +++ b/internal/audio/audio.go @@ -12,30 +12,101 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build !js - package audio +const bufferSize = 1024 const SampleRate = 44100 +var nextInsertion = 0 +var currentBytes = 0 + +type channel struct { + l []float32 + r []float32 +} + +var channels = make([]*channel, 16) + +func init() { + for i, _ := range channels { + channels[i] = &channel{ + l: []float32{}, + r: []float32{}, + } + } +} + func Init() { - // TODO: Implement + initialize() } func Start() { - // TODO: Implement + start() } func Append(channel int, l []float32, r []float32) bool { - // TODO: Implement - return false + // TODO: Mutex (especially for OpenAL) + if len(l) != len(r) { + panic("len(l) must equal to len(r)") + } + ch := channelAt(channel) + if ch == nil { + return false + } + ch.l = append(ch.l, make([]float32, nextInsertion-len(ch.l))...) + ch.r = append(ch.r, make([]float32, nextInsertion-len(ch.r))...) + ch.l = append(ch.l, l...) + ch.r = append(ch.r, r...) + return true } func CurrentBytes() int { - // TODO: Implement - return 0 + return currentBytes + nextInsertion } func Update() { - // TODO: Implement + nextInsertion += SampleRate / 60 +} + +func channelAt(i int) *channel { + if i == -1 { + for _, ch := range channels { + if len(ch.l) <= nextInsertion { + return ch + } + } + return nil + } + ch := channels[i] + if len(ch.l) <= nextInsertion { + return ch + } + return nil +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func loadChannelBuffers() (l, r []float32) { + inputL := make([]float32, bufferSize) + inputR := make([]float32, bufferSize) + for _, ch := range channels { + if len(ch.l) == 0 { + continue + } + l := min(len(ch.l), bufferSize) + for i := 0; i < l; i++ { + inputL[i] += ch.l[i] + inputR[i] += ch.r[i] + } + // TODO: Use copyFromChannel? + usedLen := min(bufferSize, len(ch.l)) + ch.l = ch.l[usedLen:] + ch.r = ch.r[usedLen:] + } + return inputL, inputR } diff --git a/internal/audio/audio_js.go b/internal/audio/audio_js.go index c7c010b84..a0c2cf636 100644 --- a/internal/audio/audio_js.go +++ b/internal/audio/audio_js.go @@ -24,41 +24,7 @@ import ( var node js.Object var context js.Object -const bufferSize = 1024 -const SampleRate = 44100 - -var nextInsertion = 0 - -type channel struct { - l []float32 - r []float32 -} - -var channels = make([]*channel, 16) - -func init() { - for i, _ := range channels { - channels[i] = &channel{ - l: []float32{}, - r: []float32{}, - } - } -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} - -var currentBytes = 0 - -func CurrentBytes() int { - return currentBytes + nextInsertion -} - -func Init() { +func initialize() { context = js.Global.Get("AudioContext").New() // TODO: ScriptProcessorNode will be replaced with Audio WebWorker. // https://developer.mozilla.org/ja/docs/Web/API/ScriptProcessorNode @@ -70,22 +36,7 @@ func Init() { l := e.Get("outputBuffer").Call("getChannelData", 0) r := e.Get("outputBuffer").Call("getChannelData", 1) - inputL := make([]float32, bufferSize) - inputR := make([]float32, bufferSize) - for _, ch := range channels { - if len(ch.l) == 0 { - continue - } - l := min(len(ch.l), bufferSize) - for i := 0; i < l; i++ { - inputL[i] += ch.l[i] - inputR[i] += ch.r[i] - } - // TODO: Use copyFromChannel? - usedLen := min(bufferSize, len(ch.l)) - ch.l = ch.l[usedLen:] - ch.r = ch.r[usedLen:] - } + inputL, inputR := loadChannelBuffers() nextInsertion -= min(bufferSize, nextInsertion) for i := 0; i < bufferSize; i++ { // TODO: Use copyFromChannel? @@ -100,43 +51,7 @@ func Init() { }) } -func Update() { - nextInsertion += SampleRate / 60 -} - -func Start() { +func start() { // TODO: For iOS, node should be connected with a buffer node. node.Call("connect", context.Get("destination")) } - -func channelAt(i int) *channel { - if i == -1 { - for _, ch := range channels { - if len(ch.l) <= nextInsertion { - return ch - } - } - return nil - } - ch := channels[i] - if len(ch.l) <= nextInsertion { - return ch - } - return nil -} - -func Append(i int, l []float32, r []float32) bool { - // TODO: Mutex (especially for OpenAL) - if len(l) != len(r) { - panic("len(l) must equal to len(r)") - } - ch := channelAt(i) - if ch == nil { - return false - } - ch.l = append(ch.l, make([]float32, nextInsertion-len(ch.l))...) - ch.r = append(ch.r, make([]float32, nextInsertion-len(ch.r))...) - ch.l = append(ch.l, l...) - ch.r = append(ch.r, r...) - return true -} diff --git a/internal/audio/audio_openal.go b/internal/audio/audio_openal.go new file mode 100644 index 000000000..8aec7c7b2 --- /dev/null +++ b/internal/audio/audio_openal.go @@ -0,0 +1,25 @@ +// Copyright 2015 Hajime Hoshi +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !js + +package audio + +func initialize() { + // TODO: Implement +} + +func start() { + // TODO: Implement +}