ebiten/audio/internal/convert/float32.go

98 lines
2.3 KiB
Go

// Copyright 2024 The Ebitengine 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"
"math"
)
func NewFloat32BytesReaderFromInt16BytesReader(r io.Reader) io.Reader {
return &float32BytesReader{r: r}
}
type float32BytesReader struct {
r io.Reader
eof bool
i16Buf []byte
}
func (r *float32BytesReader) Read(buf []byte) (int, error) {
if r.eof && len(r.i16Buf) == 0 {
return 0, io.EOF
}
if i16LenToFill := len(buf) / 4 * 2; len(r.i16Buf) < i16LenToFill && !r.eof {
origLen := len(r.i16Buf)
if cap(r.i16Buf) < i16LenToFill {
r.i16Buf = append(r.i16Buf, make([]byte, i16LenToFill-origLen)...)
}
// Read int16 bytes.
n, err := r.r.Read(r.i16Buf[origLen:i16LenToFill])
if err != nil && err != io.EOF {
return 0, err
}
if err == io.EOF {
r.eof = true
}
r.i16Buf = r.i16Buf[:origLen+n]
}
// Convert int16 bytes to float32 bytes and fill buf.
samplesToFill := min(len(r.i16Buf)/2, len(buf)/4)
for i := 0; i < samplesToFill; i++ {
vi16l := r.i16Buf[2*i]
vi16h := r.i16Buf[2*i+1]
v := float32(int16(vi16l)|int16(vi16h)<<8) / (1 << 15)
vf32 := math.Float32bits(v)
buf[4*i] = byte(vf32)
buf[4*i+1] = byte(vf32 >> 8)
buf[4*i+2] = byte(vf32 >> 16)
buf[4*i+3] = byte(vf32 >> 24)
}
// Copy the remaining part for the next read.
copy(r.i16Buf, r.i16Buf[samplesToFill*2:])
r.i16Buf = r.i16Buf[:len(r.i16Buf)-samplesToFill*2]
n := samplesToFill * 4
if r.eof {
return n, io.EOF
}
return n, nil
}
func (r *float32BytesReader) Seek(offset int64, whence int) (int64, error) {
s, ok := r.r.(io.Seeker)
if !ok {
panic("float32: the source must be io.Seeker when seeking but not")
}
r.i16Buf = r.i16Buf[:0]
r.eof = false
n, err := s.Seek(offset/4*2, whence)
if err != nil {
return 0, err
}
return n / 2 * 4, nil
}
func min(a, b int) int {
if a < b {
return a
}
return b
}