audio/internal/convert: Add Float32Reader and NewReaderFromFloat32Reader

This commit is contained in:
Hajime Hoshi 2019-01-15 11:14:55 +09:00
parent 13f6549cb6
commit f16f6cf4b9
3 changed files with 201 additions and 12 deletions

View File

@ -0,0 +1,78 @@
// Copyright 2019 The Ebiten Authors
//
// 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.
package convert
import (
"io"
)
type Float32Reader interface {
Read([]float32) (int, error)
}
func NewReaderFromFloat32Reader(r Float32Reader) io.Reader {
return &f32Reader{r: r}
}
type f32Reader struct {
r Float32Reader
eof bool
buf *byte
}
func (f *f32Reader) Read(buf []byte) (int, error) {
if f.eof {
return 0, io.EOF
}
if len(buf) == 0 {
return 0, nil
}
if f.buf != nil {
buf[0] = *f.buf
f.buf = nil
return 1, nil
}
bf := make([]float32, len(buf)/2)
if len(buf) == 1 {
bf = make([]float32, 1)
}
n, err := f.r.Read(bf)
if err != nil && err != io.EOF {
return 0, err
}
if err == io.EOF {
f.eof = true
}
b := buf
if len(buf) == 1 && n > 0 {
b = make([]byte, 2)
}
for i := 0; i < n; i++ {
f := bf[i]
s := int16(f * (1<<15 - 1))
b[2*i] = uint8(s)
b[2*i+1] = uint8(s >> 8)
}
if len(buf) == 1 && len(b) == 2 {
buf[0] = b[0]
f.buf = &b[1]
return 1, err
}
return n * 2, err
}

View File

@ -0,0 +1,111 @@
// Copyright 2019 The Ebiten Authors
//
// 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.
package convert_test
import (
"bytes"
"io"
"math"
"testing"
. "github.com/hajimehoshi/ebiten/audio/internal/convert"
)
type f32reader struct {
data []float32
pos int
}
func (f *f32reader) Read(buf []float32) (int, error) {
if f.pos == len(f.data) {
return 0, io.EOF
}
n := copy(buf, f.data[f.pos:])
f.pos += n
return n, nil
}
func newFloat32Reader(data []float32) Float32Reader {
return &f32reader{data: data}
}
func TestFloat32Reader(t *testing.T) {
in1 := make([]float32, 256)
for i := range in1 {
in1[i] = float32(math.Sin(float64(i)))
}
in2 := make([]float32, 65536)
for i := range in2 {
in2[i] = float32(math.Cos(float64(i)))
}
cases := []struct {
In []float32
N int
}{
{
In: in1,
N: 1,
},
{
In: in1,
N: 2,
},
{
In: in1,
N: 3,
},
{
In: in1,
N: 1024,
},
{
In: in2,
N: 1,
},
{
In: in2,
N: 4096,
},
}
for i, c := range cases {
r := NewReaderFromFloat32Reader(newFloat32Reader(c.In))
got := []byte{}
for {
buf := make([]byte, c.N)
n, err := r.Read(buf)
if err != nil {
if n == 0 && err == io.EOF {
break
}
t.Fatal(err)
}
got = append(got, buf[:n]...)
}
want := make([]byte, len(c.In)*2)
for i, f := range c.In {
s := int16(f * (1<<15 - 1))
want[2*i] = byte(s)
want[2*i+1] = byte(s >> 8)
}
if !bytes.Equal(got, want) {
t.Errorf("case: %d, got: %v, want: %v", i, got, want)
}
}
}

View File

@ -75,9 +75,14 @@ type decoded struct {
posInBytes int
source io.Closer
decoder decoder
decoderr io.Reader
}
func (d *decoded) Read(b []byte) (int, error) {
if d.decoderr == nil {
d.decoderr = convert.NewReaderFromFloat32Reader(d.decoder)
}
l := d.totalBytes - d.posInBytes
if l > len(b) {
l = len(b)
@ -86,28 +91,21 @@ func (d *decoded) Read(b []byte) (int, error) {
return 0, io.EOF
}
bf := make([]float32, l/2)
retry:
n, err := d.decoder.Read(bf)
n, err := d.decoderr.Read(b[:l])
if err != nil && err != io.EOF {
return 0, err
}
if n == 0 && len(bf) > 0 && err != io.EOF {
if n == 0 && l > 0 && err != io.EOF {
// 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))
b[2*i] = uint8(s)
b[2*i+1] = uint8(s >> 8)
}
d.posInBytes += 2 * n
d.posInBytes += n
if d.posInBytes == d.totalBytes || err == io.EOF {
return 2 * n, io.EOF
return n, io.EOF
}
return 2 * n, nil
return n, nil
}
func (d *decoded) Seek(offset int64, whence int) (int64, error) {
@ -124,6 +122,7 @@ func (d *decoded) Seek(offset int64, whence int) (int64, error) {
next = next / 2 * 2
d.posInBytes = int(next)
d.decoder.SetPosition(next / int64(d.decoder.Channels()) / 2)
d.decoderr = nil
return next, nil
}
@ -133,6 +132,7 @@ func (d *decoded) Close() error {
return err
}
d.decoder = nil
d.decoderr = nil
return nil
}