mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 19:58:54 +01:00
f0ef1ecad0
This change adds these APIs * (*audio.Context).NewPlayerF32 * (*audio.Context).NewPlayerF32FromBytes * audio.NewInfiniteLoopF32 * audio.NewInfiniteLoopWithIntroF32 * audio.ResampleF32 * mp3.DecodeF32 * vorbis.DecodeF32 * wav.DecodeF32 Closes #2160
103 lines
2.5 KiB
Go
103 lines
2.5 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 (
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
)
|
|
|
|
func NewFloat32BytesReaderFromInt16BytesReader(r io.Reader) io.Reader {
|
|
return &float32BytesReader{r: r}
|
|
}
|
|
|
|
func NewFloat32BytesReadSeekerFromInt16BytesReadSeeker(r io.ReadSeeker) io.ReadSeeker {
|
|
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 {
|
|
return 0, fmt.Errorf("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
|
|
}
|