Kirika/audio/format/mp3/mp3_nocgo.go
2022-05-20 17:23:50 +02:00

66 lines
1.4 KiB
Go

//go:build !disable_format_mp3 && !cgo
package mp3
import (
"bytes"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
mp3Lib "github.com/hajimehoshi/go-mp3"
"io"
"unsafe"
)
const BlockSize = 1024 * 128
type Format struct {
}
func NewFormat() Format {
return Format{}
}
func (f Format) Name() string {
return "mp3"
}
func (f Format) Description() string {
return "hajimehoshi/go-mp3"
}
func (f Format) Open(r io.ReadSeekCloser) (audio.Source, error) {
decoder, err := mp3Lib.NewDecoder(r)
if err != nil {
return audio.Source{}, err
}
newChannel := make(chan []float32)
go func() {
defer close(newChannel)
samples := make([]int16, BlockSize*2)
const SizeofInt16 = int(unsafe.Sizeof(int16(0)))
byteSlice := unsafe.Slice((*byte)(unsafe.Pointer(&samples[0])), len(samples)*SizeofInt16)
for {
n, err := decoder.Read(byteSlice)
if err != nil {
return
}
n /= SizeofInt16
//convert 16-bit to f32 samples
newChannel <- cgo.Int16ToFloat32(samples[:n], 16)
}
}()
return audio.Source{
Channels: 2,
SampleRate: decoder.SampleRate(),
Blocks: newChannel,
}, nil
}
func (f Format) Identify(peek []byte, extension string) bool {
//match ID3 / sync header
return peek[0] == 0xff && (peek[1]>>5) == 0b111 || (bytes.Compare(peek[:3], []byte{'I', 'D', '3'}) == 0 && extension != "flac") || extension == "mp3"
}