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

138 lines
3 KiB
Go

//go:build !disable_format_flac && (disable_codec_libflac || !cgo)
package flac
import (
"bytes"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/audio/format"
"git.gammaspectra.live/S.O.N.G/Kirika/cgo"
libflac "github.com/mewkiz/flac"
"io"
)
type Format struct {
}
func NewFormat() Format {
return Format{}
}
func (f Format) Name() string {
return "flac"
}
func (f Format) Description() string {
return "mewkiz/flac"
}
func (f Format) Open(r io.ReadSeekCloser) (audio.Source, error) {
decoder, err := libflac.New(r)
if err != nil {
return audio.Source{}, err
}
newChannel := make(chan []float32)
go func() {
defer close(newChannel)
defer decoder.Close()
frameNumber := 0
for {
currentFrame, err := decoder.ParseNext()
if err != nil {
return
}
bitDepth := int(decoder.Info.BitsPerSample)
channels := int(decoder.Info.NChannels)
if currentFrame.BitsPerSample != 0 {
bitDepth = int(currentFrame.BitsPerSample)
}
if len(currentFrame.Subframes) != 0 {
channels = len(currentFrame.Subframes)
}
buffer := make([]int32, len(currentFrame.Subframes[0].Samples)*channels)
for i := range buffer {
buffer[i] = currentFrame.Subframes[i%channels].Samples[i/channels]
}
newChannel <- cgo.Int32ToFloat32(buffer, bitDepth)
frameNumber++
}
}()
return audio.Source{
Channels: int(decoder.Info.NChannels),
SampleRate: int(decoder.Info.SampleRate),
Blocks: newChannel,
}, nil
}
func (f Format) OpenAnalyzer(r io.ReadSeekCloser) (audio.Source, format.AnalyzerChannel, error) {
decoder, err := libflac.New(r)
if err != nil {
return audio.Source{}, nil, err
}
newChannel := make(chan []float32)
analyzerChannel := make(format.AnalyzerChannel)
go func() {
defer close(newChannel)
defer close(analyzerChannel)
defer decoder.Close()
frameNumber := 0
for {
currentFrame, err := decoder.ParseNext()
if err != nil {
return
}
bitDepth := int(decoder.Info.BitsPerSample)
channels := int(decoder.Info.NChannels)
if currentFrame.BitsPerSample != 0 {
bitDepth = int(currentFrame.BitsPerSample)
}
if len(currentFrame.Subframes) != 0 {
channels = len(currentFrame.Subframes)
}
buffer := make([]int32, len(currentFrame.Subframes[0].Samples)*channels)
for i := range buffer {
buffer[i] = currentFrame.Subframes[i%channels].Samples[i/channels]
}
newChannel <- cgo.Int32ToFloat32(buffer, bitDepth)
analyzerChannel <- &format.AnalyzerPacket{
Samples: buffer,
Channels: channels,
BitDepth: bitDepth,
SampleRate: int(decoder.Info.SampleRate),
}
frameNumber++
}
}()
return audio.Source{
Channels: int(decoder.Info.NChannels),
SampleRate: int(decoder.Info.SampleRate),
Blocks: newChannel,
}, analyzerChannel, nil
}
func (f Format) Identify(peek []byte, extension string) bool {
return bytes.Compare(peek[:4], []byte{'f', 'L', 'a', 'C'}) == 0 || (bytes.Compare(peek[:3], []byte{'I', 'D', '3'}) == 0 && extension != "mp3") || extension == "flac"
}