mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
audio/vorbis: Remove duplicated decoded data
There was duplicated decoded date in audio/vorbis package and Ogg decoder package. This change removes this duplication and reduces memory usage.
This commit is contained in:
parent
5cd66b6d6b
commit
13f6549cb6
@ -40,29 +40,54 @@ func init() {
|
|||||||
|
|
||||||
type Samples struct {
|
type Samples struct {
|
||||||
samples [][]float32
|
samples [][]float32
|
||||||
length int64
|
channels int
|
||||||
|
lengthInSamples int64
|
||||||
|
posInSamples int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Samples) Read(buf []float32) (int, error) {
|
func (s *Samples) Read(buf []float32) (int, error) {
|
||||||
if len(s.samples) == 0 {
|
if s.posInSamples == s.lengthInSamples {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
n := copy(buf, s.samples[0])
|
if len(buf) == 0 {
|
||||||
s.samples[0] = s.samples[0][n:]
|
return 0, nil
|
||||||
if len(s.samples[0]) == 0 {
|
|
||||||
s.samples = s.samples[1:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var p int64
|
||||||
|
idx := 0
|
||||||
|
for idx < len(s.samples) {
|
||||||
|
l := int64(len(s.samples[idx])) / int64(s.channels)
|
||||||
|
if p+l > s.posInSamples {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p += l
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
start := (s.posInSamples - p) * int64(s.channels)
|
||||||
|
if start == int64(len(s.samples[idx])) {
|
||||||
|
idx++
|
||||||
|
start = 0
|
||||||
|
}
|
||||||
|
if len(s.samples[idx]) == 0 {
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
|
n := copy(buf, s.samples[idx][start:])
|
||||||
|
s.posInSamples += int64(n) / int64(s.channels)
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Samples) Length() int64 {
|
func (s *Samples) Length() int64 {
|
||||||
return s.length
|
return s.lengthInSamples
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Samples) SetPosition(pos int64) error {
|
||||||
|
s.posInSamples = pos
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeVorbis(buf []byte) (*Samples, int, int, error) {
|
func DecodeVorbis(buf []byte) (*Samples, int, int, error) {
|
||||||
ch := make(chan error)
|
ch := make(chan error)
|
||||||
samples := &Samples{}
|
samples := &Samples{}
|
||||||
channels := 0
|
|
||||||
sampleRate := 0
|
sampleRate := 0
|
||||||
|
|
||||||
var f js.Callback
|
var f js.Callback
|
||||||
@ -82,21 +107,26 @@ func DecodeVorbis(buf []byte) (*Samples, int, int, error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if channels == 0 {
|
if samples.channels == 0 {
|
||||||
channels = r.Get("data").Length()
|
samples.channels = r.Get("data").Length()
|
||||||
|
|
||||||
}
|
}
|
||||||
if sampleRate == 0 {
|
if sampleRate == 0 {
|
||||||
sampleRate = r.Get("sampleRate").Int()
|
sampleRate = r.Get("sampleRate").Int()
|
||||||
}
|
}
|
||||||
|
|
||||||
flattened := flatten.Invoke(r.Get("data"))
|
flattened := flatten.Invoke(r.Get("data"))
|
||||||
|
if flattened.Length() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s := make([]float32, flattened.Length())
|
s := make([]float32, flattened.Length())
|
||||||
arr := js.TypedArrayOf(s)
|
arr := js.TypedArrayOf(s)
|
||||||
arr.Call("set", flattened)
|
arr.Call("set", flattened)
|
||||||
arr.Release()
|
arr.Release()
|
||||||
|
|
||||||
samples.samples = append(samples.samples, s)
|
samples.samples = append(samples.samples, s)
|
||||||
samples.length += int64(len(s)) / int64(channels)
|
samples.lengthInSamples += int64(len(s)) / int64(samples.channels)
|
||||||
})
|
})
|
||||||
|
|
||||||
arr := js.TypedArrayOf(buf)
|
arr := js.TypedArrayOf(buf)
|
||||||
@ -107,5 +137,5 @@ func DecodeVorbis(buf []byte) (*Samples, int, int, error) {
|
|||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return samples, channels, sampleRate, nil
|
return samples, samples.channels, sampleRate, nil
|
||||||
}
|
}
|
||||||
|
@ -63,13 +63,13 @@ func (s *Stream) Size() int64 {
|
|||||||
|
|
||||||
type decoder interface {
|
type decoder interface {
|
||||||
Read([]float32) (int, error)
|
Read([]float32) (int, error)
|
||||||
|
SetPosition(int64) error
|
||||||
Length() int64
|
Length() int64
|
||||||
Channels() int
|
Channels() int
|
||||||
SampleRate() int
|
SampleRate() int
|
||||||
}
|
}
|
||||||
|
|
||||||
type decoded struct {
|
type decoded struct {
|
||||||
data []float32
|
|
||||||
totalBytes int
|
totalBytes int
|
||||||
readBytes int
|
readBytes int
|
||||||
posInBytes int
|
posInBytes int
|
||||||
@ -77,36 +77,6 @@ type decoded struct {
|
|||||||
decoder decoder
|
decoder decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decoded) readUntil(posInBytes int) error {
|
|
||||||
if d.decoder == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer := make([]float32, 8192)
|
|
||||||
for d.readBytes < posInBytes {
|
|
||||||
n, err := d.decoder.Read(buffer)
|
|
||||||
if n > 0 {
|
|
||||||
// Actual read bytes might exceed the total bytes.
|
|
||||||
if d.readBytes+n*2 > d.totalBytes {
|
|
||||||
n = (d.totalBytes - d.readBytes) / 2
|
|
||||||
}
|
|
||||||
p := d.readBytes / 2
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
d.data[p+i] = buffer[i]
|
|
||||||
}
|
|
||||||
d.readBytes += n * 2
|
|
||||||
}
|
|
||||||
if err == io.EOF {
|
|
||||||
d.decoder = nil
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *decoded) Read(b []byte) (int, error) {
|
func (d *decoded) Read(b []byte) (int, error) {
|
||||||
l := d.totalBytes - d.posInBytes
|
l := d.totalBytes - d.posInBytes
|
||||||
if l > len(b) {
|
if l > len(b) {
|
||||||
@ -115,22 +85,29 @@ func (d *decoded) Read(b []byte) (int, error) {
|
|||||||
if l < 0 {
|
if l < 0 {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
// l must be even so that d.posInBytes is always even.
|
|
||||||
l = l / 2 * 2
|
bf := make([]float32, l/2)
|
||||||
if err := d.readUntil(d.posInBytes + l); err != nil {
|
retry:
|
||||||
|
n, err := d.decoder.Read(bf)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
for i := 0; i < l/2; i++ {
|
if n == 0 && len(bf) > 0 && err != io.EOF {
|
||||||
f := d.data[d.posInBytes/2+i]
|
// When l is too small, decoder's Read might return 0 for a while. Let's retry.
|
||||||
|
goto retry
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
f := bf[i]
|
||||||
s := int16(f * (1<<15 - 1))
|
s := int16(f * (1<<15 - 1))
|
||||||
b[2*i] = uint8(s)
|
b[2*i] = uint8(s)
|
||||||
b[2*i+1] = uint8(s >> 8)
|
b[2*i+1] = uint8(s >> 8)
|
||||||
}
|
}
|
||||||
d.posInBytes += l
|
d.posInBytes += 2 * n
|
||||||
if d.posInBytes == d.totalBytes {
|
if d.posInBytes == d.totalBytes || err == io.EOF {
|
||||||
return l, io.EOF
|
return 2 * n, io.EOF
|
||||||
}
|
}
|
||||||
return l, nil
|
return 2 * n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decoded) Seek(offset int64, whence int) (int64, error) {
|
func (d *decoded) Seek(offset int64, whence int) (int64, error) {
|
||||||
@ -146,9 +123,7 @@ func (d *decoded) Seek(offset int64, whence int) (int64, error) {
|
|||||||
// pos should be always even
|
// pos should be always even
|
||||||
next = next / 2 * 2
|
next = next / 2 * 2
|
||||||
d.posInBytes = int(next)
|
d.posInBytes = int(next)
|
||||||
if err := d.readUntil(d.posInBytes); err != nil {
|
d.decoder.SetPosition(next / int64(d.decoder.Channels()) / 2)
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return next, nil
|
return next, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,8 +147,6 @@ func decode(in audio.ReadSeekCloser) (*decoded, int, int, error) {
|
|||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
d := &decoded{
|
d := &decoded{
|
||||||
data: make([]float32, int(r.Length())*r.Channels()),
|
|
||||||
|
|
||||||
// TODO: r.Length() returns 0 when the format is unknown.
|
// TODO: r.Length() returns 0 when the format is unknown.
|
||||||
// Should we check that?
|
// Should we check that?
|
||||||
totalBytes: int(r.Length()) * r.Channels() * 2, // 2 means 16bit per sample.
|
totalBytes: int(r.Length()) * r.Channels() * 2, // 2 means 16bit per sample.
|
||||||
|
@ -46,6 +46,10 @@ func (d *decoderImpl) SampleRate() int {
|
|||||||
return d.sampleRate
|
return d.sampleRate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *decoderImpl) SetPosition(pos int64) error {
|
||||||
|
return d.samples.SetPosition(pos)
|
||||||
|
}
|
||||||
|
|
||||||
func newDecoder(in audio.ReadSeekCloser) (decoder, error) {
|
func newDecoder(in audio.ReadSeekCloser) (decoder, error) {
|
||||||
buf, err := ioutil.ReadAll(in)
|
buf, err := ioutil.ReadAll(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user