minimp3/minimp3.go

133 lines
4.1 KiB
Go
Raw Permalink Normal View History

package minimp3
/*
#define MINIMP3_IMPLEMENTATION
2022-12-01 08:47:34 +00:00
#define MINIMP3_FLOAT_OUTPUT
#include "minimp3.h"
*/
import "C"
import (
"errors"
"io"
"unsafe"
)
const maxSamplesPerFrame = 1152 * 2
// Decoder decode the mp3 stream by minimp3
type Decoder struct {
source io.Reader
2022-12-01 08:47:34 +00:00
mp3 []byte
pcm []float32
mp3Length, pcmLength int
lastError error
decode C.mp3dec_t
info C.mp3dec_frame_info_t
}
// NewDecoder creates and returns a new mp3 decoder with the default internal buffer size.
func NewDecoder(source io.Reader) *Decoder {
d := &Decoder{
source: source,
mp3: make([]byte, 1024*16),
2022-12-01 08:47:34 +00:00
pcm: make([]float32, maxSamplesPerFrame),
}
C.mp3dec_init(&d.decode)
return d
}
2022-12-01 08:47:34 +00:00
// Read copies the decoded audio data from the internal buffer to p and returns the number of items copied.
// If the internal buffer is empty, then Read first tries to read mp3 data from the source and decode it.
// If len(p) == 0, then Read will return zero bytes, but if the internal buffer is empty, then before that it will still try to decode one frame and fill the internal buffer.
2022-12-01 08:47:34 +00:00
func (d *Decoder) Read(p []float32) (int, error) {
for d.pcmLength == 0 {
// If possible, fill the mp3 buffer completely
for d.mp3Length < len(d.mp3) && d.lastError == nil {
n, err := d.source.Read(d.mp3[d.mp3Length:])
d.mp3Length += n
d.lastError = err
}
samples := C.mp3dec_decode_frame(&d.decode,
(*C.uint8_t)(unsafe.Pointer(&d.mp3[0])), C.int(d.mp3Length),
(*C.mp3d_sample_t)(unsafe.Pointer(&d.pcm[0])), &d.info,
)
if d.info.frame_bytes == 0 {
return 0, d.lastError
}
d.mp3Length = copy(d.mp3, d.mp3[d.info.frame_bytes:d.mp3Length])
2022-12-01 08:47:34 +00:00
d.pcmLength = int(samples * d.info.channels * C.sizeof_float)
}
2022-12-01 08:47:34 +00:00
n := copy(p, d.pcm[:d.pcmLength/C.sizeof_float])
// If there is any data left in the pcm buffer, then move it to the beginning of the buffer
2022-12-01 08:47:34 +00:00
copy(d.pcm, d.pcm[n:d.pcmLength/C.sizeof_float])
d.pcmLength -= n * C.sizeof_float
return n, nil
}
// Seek sets a new position for reading audio data.
// At least one decoded frame is required to set a new position.
// If there are no decoded frames, then Seek will return an error.
// The mp3 data source must support the io.Seeker interface.
// If the source doesn't support io.Seeker, then Seek will panic.
func (d *Decoder) Seek(offset int64, whence int) (int64, error) {
seeker, ok := d.source.(io.Seeker)
if !ok {
panic("minimp3: d.source is not seeker")
}
mp3BytesPerMsec := int64(d.info.bitrate_kbps) / 8
2022-12-01 08:47:34 +00:00
pcmBytesPerMsec := int64(d.info.channels*C.sizeof_float*d.info.hz) / 1000
if mp3BytesPerMsec == 0 || pcmBytesPerMsec == 0 {
// There is no information about audio data. Probably not a single frame has been decoded yet
return 0, errors.New("no frame available")
}
var mp3Offset int64
if whence == io.SeekCurrent {
// If seeking is performed from the current position, then be aware of buffered audio data
offset -= int64(d.pcmLength)
mp3Offset = offset / pcmBytesPerMsec * mp3BytesPerMsec
mp3Offset -= int64(d.mp3Length)
} else {
// If seeking is performed from the beginning or the end, then the buffered data does not matter
mp3Offset = offset / pcmBytesPerMsec * mp3BytesPerMsec
}
// Internal buffers must always be cleared, regardless of the result of calling the Seek method
d.mp3Length = 0
d.pcmLength = 0
mp3Pos, err := seeker.Seek(mp3Offset, whence)
if err != nil {
return 0, err
}
pcmPos := mp3Pos / mp3BytesPerMsec * pcmBytesPerMsec
return pcmPos, nil
}
// SampleRate returns the sample rate of the last decoded frame.
// If no frames have been decoded yet, then it will return 0.
func (d *Decoder) SampleRate() int {
return int(d.info.hz)
}
// Channels returns the number of channels of the last decoded frame.
// If no frames have been decoded yet, then it will return 0.
func (d *Decoder) Channels() int {
return int(d.info.channels)
}
// Bitrate returns the mp3 bitrate of the last decoded frame.
// If no frames have been decoded yet, then it will return 0.
func (d *Decoder) Bitrate() int {
return int(d.info.bitrate_kbps)
}