mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-13 12:32:05 +01:00
audio: remove const bytesPerSampleInt16
This is a preparation for float32 players. Updates #2160
This commit is contained in:
parent
073d022c2e
commit
844a4de872
@ -48,7 +48,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
channelCount = 2
|
channelCount = 2
|
||||||
bitDepthInBytesInt16 = 2
|
bitDepthInBytesInt16 = 2
|
||||||
bytesPerSampleInt16 = bitDepthInBytesInt16 * channelCount
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Context represents a current state of audio.
|
// A Context represents a current state of audio.
|
||||||
@ -324,7 +323,7 @@ type Player struct {
|
|||||||
// A Player doesn't close src even if src implements io.Closer.
|
// A Player doesn't close src even if src implements io.Closer.
|
||||||
// Closing the source is src owner's responsibility.
|
// Closing the source is src owner's responsibility.
|
||||||
func (c *Context) NewPlayer(src io.Reader) (*Player, error) {
|
func (c *Context) NewPlayer(src io.Reader) (*Player, error) {
|
||||||
pi, err := c.playerFactory.newPlayer(c, src)
|
pi, err := c.playerFactory.newPlayer(c, src, bitDepthInBytesInt16)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,10 @@ type InfiniteLoop struct {
|
|||||||
lstart int64
|
lstart int64
|
||||||
llength int64
|
llength int64
|
||||||
pos int64
|
pos int64
|
||||||
|
bitDepthInBytes int
|
||||||
|
bytesPerSample int
|
||||||
|
|
||||||
// extra is the remainder in the case when the read byte sizes are not multiple of bitDepthInBytesInt16.
|
// extra is the remainder in the case when the read byte sizes are not multiple of the bit depth.
|
||||||
extra []byte
|
extra []byte
|
||||||
|
|
||||||
// afterLoop is data after the loop.
|
// afterLoop is data after the loop.
|
||||||
@ -58,11 +60,18 @@ func NewInfiniteLoop(src io.ReadSeeker, length int64) *InfiniteLoop {
|
|||||||
// If src has data after the loop end, an InfiniteLoop uses part of the data to blend with the loop start
|
// If src has data after the loop end, an InfiniteLoop uses part of the data to blend with the loop start
|
||||||
// to make the loop joint smooth.
|
// to make the loop joint smooth.
|
||||||
func NewInfiniteLoopWithIntro(src io.ReadSeeker, introLength int64, loopLength int64) *InfiniteLoop {
|
func NewInfiniteLoopWithIntro(src io.ReadSeeker, introLength int64, loopLength int64) *InfiniteLoop {
|
||||||
|
return newInfiniteLoopWithIntro(src, introLength, loopLength, bitDepthInBytesInt16)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInfiniteLoopWithIntro(src io.ReadSeeker, introLength int64, loopLength int64, bitDepthInBytes int) *InfiniteLoop {
|
||||||
|
bytesPerSample := bitDepthInBytes * channelCount
|
||||||
return &InfiniteLoop{
|
return &InfiniteLoop{
|
||||||
src: src,
|
src: src,
|
||||||
lstart: introLength / bytesPerSampleInt16 * bytesPerSampleInt16,
|
lstart: introLength / int64(bytesPerSample) * int64(bytesPerSample),
|
||||||
llength: loopLength / bytesPerSampleInt16 * bytesPerSampleInt16,
|
llength: loopLength / int64(bytesPerSample) * int64(bytesPerSample),
|
||||||
pos: -1,
|
pos: -1,
|
||||||
|
bitDepthInBytes: bitDepthInBytes,
|
||||||
|
bytesPerSample: bytesPerSample,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,8 +101,8 @@ func (i *InfiniteLoop) blendRate(pos int64) float64 {
|
|||||||
if pos >= i.lstart+int64(len(i.afterLoop)) {
|
if pos >= i.lstart+int64(len(i.afterLoop)) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
p := (pos - i.lstart) / bytesPerSampleInt16
|
p := (pos - i.lstart) / int64(i.bytesPerSample)
|
||||||
l := len(i.afterLoop) / bytesPerSampleInt16
|
l := len(i.afterLoop) / i.bytesPerSample
|
||||||
return 1 - float64(p)/float64(l)
|
return 1 - float64(p)/float64(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +128,7 @@ func (i *InfiniteLoop) Read(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save the remainder part to extra. This will be used at the next Read.
|
// Save the remainder part to extra. This will be used at the next Read.
|
||||||
if rem := n % bitDepthInBytesInt16; rem != 0 {
|
if rem := n % i.bitDepthInBytes; rem != 0 {
|
||||||
i.extra = append(i.extra, b[n-rem:n]...)
|
i.extra = append(i.extra, b[n-rem:n]...)
|
||||||
b = b[:n-rem]
|
b = b[:n-rem]
|
||||||
n = n - rem
|
n = n - rem
|
||||||
@ -128,24 +137,27 @@ func (i *InfiniteLoop) Read(b []byte) (int, error) {
|
|||||||
// Blend afterLoop and the loop start to reduce noises (#1888).
|
// Blend afterLoop and the loop start to reduce noises (#1888).
|
||||||
// Ideally, afterLoop and the loop start should be identical, but they can have very slight differences.
|
// Ideally, afterLoop and the loop start should be identical, but they can have very slight differences.
|
||||||
if !i.noBlendForTesting && i.blending && i.pos >= i.lstart && i.pos-int64(n) < i.lstart+int64(len(i.afterLoop)) {
|
if !i.noBlendForTesting && i.blending && i.pos >= i.lstart && i.pos-int64(n) < i.lstart+int64(len(i.afterLoop)) {
|
||||||
if n%bitDepthInBytesInt16 != 0 {
|
if n%i.bitDepthInBytes != 0 {
|
||||||
panic(fmt.Sprintf("audio: n must be a multiple of bitDepthInBytesInt16 but not: %d", n))
|
panic(fmt.Sprintf("audio: n must be a multiple of bit depth %d [bytes] but not: %d", i.bitDepthInBytes, n))
|
||||||
}
|
}
|
||||||
for idx := 0; idx < n/bitDepthInBytesInt16; idx++ {
|
for idx := 0; idx < n/i.bitDepthInBytes; idx++ {
|
||||||
abspos := i.pos - int64(n) + int64(idx)*bitDepthInBytesInt16
|
abspos := i.pos - int64(n) + int64(idx)*int64(i.bitDepthInBytes)
|
||||||
rate := i.blendRate(abspos)
|
rate := i.blendRate(abspos)
|
||||||
if rate == 0 {
|
if rate == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// This assumes that bitDepthInBytesInt16 is 2.
|
|
||||||
relpos := abspos - i.lstart
|
relpos := abspos - i.lstart
|
||||||
|
switch i.bitDepthInBytes {
|
||||||
|
case 2:
|
||||||
afterLoop := int16(i.afterLoop[relpos]) | (int16(i.afterLoop[relpos+1]) << 8)
|
afterLoop := int16(i.afterLoop[relpos]) | (int16(i.afterLoop[relpos+1]) << 8)
|
||||||
orig := int16(b[2*idx]) | (int16(b[2*idx+1]) << 8)
|
orig := int16(b[2*idx]) | (int16(b[2*idx+1]) << 8)
|
||||||
|
|
||||||
newval := int16(float64(afterLoop)*rate + float64(orig)*(1-rate))
|
newval := int16(float64(afterLoop)*rate + float64(orig)*(1-rate))
|
||||||
b[2*idx] = byte(newval)
|
b[2*idx] = byte(newval)
|
||||||
b[2*idx+1] = byte(newval >> 8)
|
b[2*idx+1] = byte(newval >> 8)
|
||||||
|
default:
|
||||||
|
panic("not reached")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +168,7 @@ func (i *InfiniteLoop) Read(b []byte) (int, error) {
|
|||||||
// Read the afterLoop part if necessary.
|
// Read the afterLoop part if necessary.
|
||||||
if i.pos == i.length() && err == nil {
|
if i.pos == i.length() && err == nil {
|
||||||
if i.afterLoop == nil {
|
if i.afterLoop == nil {
|
||||||
buflen := int64(256 * bytesPerSampleInt16)
|
buflen := int64(256 * i.bytesPerSample)
|
||||||
if buflen > i.length() {
|
if buflen > i.length() {
|
||||||
buflen = i.length()
|
buflen = i.length()
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ type playerImpl struct {
|
|||||||
stream *timeStream
|
stream *timeStream
|
||||||
factory *playerFactory
|
factory *playerFactory
|
||||||
initBufferSize int
|
initBufferSize int
|
||||||
|
bytesPerSample int
|
||||||
|
|
||||||
// adjustedPosition is the player's more accurate position.
|
// adjustedPosition is the player's more accurate position.
|
||||||
// The underlying buffer might not be changed even if the player is playing.
|
// The underlying buffer might not be changed even if the player is playing.
|
||||||
@ -85,7 +86,7 @@ type playerImpl struct {
|
|||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *playerFactory) newPlayer(context *Context, src io.Reader) (*playerImpl, error) {
|
func (f *playerFactory) newPlayer(context *Context, src io.Reader, bitDepthInBytes int) (*playerImpl, error) {
|
||||||
f.m.Lock()
|
f.m.Lock()
|
||||||
defer f.m.Unlock()
|
defer f.m.Unlock()
|
||||||
|
|
||||||
@ -94,6 +95,7 @@ func (f *playerFactory) newPlayer(context *Context, src io.Reader) (*playerImpl,
|
|||||||
context: context,
|
context: context,
|
||||||
factory: f,
|
factory: f,
|
||||||
lastSamples: -1,
|
lastSamples: -1,
|
||||||
|
bytesPerSample: bitDepthInBytes * channelCount,
|
||||||
}
|
}
|
||||||
runtime.SetFinalizer(p, (*playerImpl).Close)
|
runtime.SetFinalizer(p, (*playerImpl).Close)
|
||||||
return p, nil
|
return p, nil
|
||||||
@ -163,7 +165,7 @@ func (p *playerImpl) ensurePlayer() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if p.stream == nil {
|
if p.stream == nil {
|
||||||
s, err := newTimeStream(p.src, p.factory.sampleRate)
|
s, err := newTimeStream(p.src, p.factory.sampleRate, p.bytesPerSample/channelCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -313,8 +315,8 @@ func (p *playerImpl) SetBufferSize(bufferSize time.Duration) {
|
|||||||
p.m.Lock()
|
p.m.Lock()
|
||||||
defer p.m.Unlock()
|
defer p.m.Unlock()
|
||||||
|
|
||||||
bufferSizeInBytes := int(bufferSize * bytesPerSampleInt16 * time.Duration(p.factory.sampleRate) / time.Second)
|
bufferSizeInBytes := int(bufferSize * time.Duration(p.bytesPerSample) * time.Duration(p.factory.sampleRate) / time.Second)
|
||||||
bufferSizeInBytes = bufferSizeInBytes / bytesPerSampleInt16 * bytesPerSampleInt16
|
bufferSizeInBytes = bufferSizeInBytes / p.bytesPerSample * p.bytesPerSample
|
||||||
if p.player == nil {
|
if p.player == nil {
|
||||||
p.initBufferSize = bufferSizeInBytes
|
p.initBufferSize = bufferSizeInBytes
|
||||||
return
|
return
|
||||||
@ -361,7 +363,7 @@ func (p *playerImpl) updatePosition() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
samples := (p.stream.position() - int64(p.player.BufferedSize())) / bytesPerSampleInt16
|
samples := (p.stream.position() - int64(p.player.BufferedSize())) / int64(p.bytesPerSample)
|
||||||
|
|
||||||
var adjustingTime time.Duration
|
var adjustingTime time.Duration
|
||||||
if p.lastSamples >= 0 && p.lastSamples == samples {
|
if p.lastSamples >= 0 && p.lastSamples == samples {
|
||||||
@ -384,16 +386,18 @@ type timeStream struct {
|
|||||||
r io.Reader
|
r io.Reader
|
||||||
sampleRate int
|
sampleRate int
|
||||||
pos int64
|
pos int64
|
||||||
|
bytesPerSample int
|
||||||
|
|
||||||
// m is a mutex for this stream.
|
// m is a mutex for this stream.
|
||||||
// All the exported functions are protected by this mutex as Read can be read from a different goroutine than Seek.
|
// All the exported functions are protected by this mutex as Read can be read from a different goroutine than Seek.
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTimeStream(r io.Reader, sampleRate int) (*timeStream, error) {
|
func newTimeStream(r io.Reader, sampleRate int, bitDepthInBytes int) (*timeStream, error) {
|
||||||
s := &timeStream{
|
s := &timeStream{
|
||||||
r: r,
|
r: r,
|
||||||
sampleRate: sampleRate,
|
sampleRate: sampleRate,
|
||||||
|
bytesPerSample: bitDepthInBytes * channelCount,
|
||||||
}
|
}
|
||||||
if seeker, ok := s.r.(io.Seeker); ok {
|
if seeker, ok := s.r.(io.Seeker); ok {
|
||||||
// Get the current position of the source.
|
// Get the current position of the source.
|
||||||
@ -437,11 +441,11 @@ func (s *timeStream) timeDurationToPos(offset time.Duration) int64 {
|
|||||||
s.m.Lock()
|
s.m.Lock()
|
||||||
defer s.m.Unlock()
|
defer s.m.Unlock()
|
||||||
|
|
||||||
o := int64(offset) * bytesPerSampleInt16 * int64(s.sampleRate) / int64(time.Second)
|
o := int64(offset) * int64(s.bytesPerSample) * int64(s.sampleRate) / int64(time.Second)
|
||||||
|
|
||||||
// Align the byte position with the samples.
|
// Align the byte position with the samples.
|
||||||
o -= o % bytesPerSampleInt16
|
o -= o % int64(s.bytesPerSample)
|
||||||
o += s.pos % bytesPerSampleInt16
|
o += s.pos % int64(s.bytesPerSample)
|
||||||
|
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
@ -457,5 +461,5 @@ func (s *timeStream) positionInTimeDuration() time.Duration {
|
|||||||
s.m.Lock()
|
s.m.Lock()
|
||||||
defer s.m.Unlock()
|
defer s.m.Unlock()
|
||||||
|
|
||||||
return time.Duration(s.pos) * time.Second / (time.Duration(s.sampleRate) * bytesPerSampleInt16)
|
return time.Duration(s.pos) * time.Second / (time.Duration(s.sampleRate * s.bytesPerSample))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user