package flac /* #cgo CFLAGS: -I"${SRCDIR}/../../../cgo" -march=native -Ofast -std=c99 #include "audio.h" */ import "C" import ( "bytes" "git.gammaspectra.live/S.O.N.G/Kirika/audio" "git.gammaspectra.live/S.O.N.G/Kirika/audio/format" libflac "github.com/cocoonlife/goflac" "io" ) type Format struct { } func NewFormat() Format { return Format{} } func (f Format) Open(r io.ReadSeekCloser, blockSize int) (*audio.Stream, error) { decoder, err := libflac.NewDecoderReader(r) if err != nil { return nil, err } newChannel := make(chan []float32) go func() { defer close(newChannel) defer decoder.Close() frameNumber := 0 for { currentFrame, err := decoder.ReadFrame() if err != nil { return } bitDepth := decoder.Depth if currentFrame.Depth != 0 { bitDepth = currentFrame.Depth } buf := make([]float32, len(currentFrame.Buffer)) C.audio_int32_to_float32((*C.int32_t)(¤tFrame.Buffer[0]), C.size_t(len(currentFrame.Buffer)), (*C.float)(&buf[0]), C.int(bitDepth)) newChannel <- buf frameNumber++ } }() return audio.NewStream(newChannel, decoder.Channels, float64(decoder.Rate), blockSize), nil } func (f Format) OpenAnalyzer(r io.ReadSeekCloser, blockSize int) (*audio.Stream, chan *format.AnalyzerPacket, error) { decoder, err := libflac.NewDecoderReader(r) if err != nil { return nil, nil, err } newChannel := make(chan []float32) analyzerChannel := make(chan *format.AnalyzerPacket) go func() { defer close(newChannel) defer close(analyzerChannel) defer decoder.Close() frameNumber := 0 for { currentFrame, err := decoder.ReadFrame() if err != nil { return } bitDepth := decoder.Depth channels := decoder.Channels if currentFrame.Depth != 0 { bitDepth = currentFrame.Depth } if currentFrame.Channels != 0 { channels = currentFrame.Channels } buf := make([]float32, len(currentFrame.Buffer)) C.audio_int32_to_float32((*C.int32_t)(¤tFrame.Buffer[0]), C.size_t(len(currentFrame.Buffer)), (*C.float)(&buf[0]), C.int(bitDepth)) newChannel <- buf analyzerChannel <- &format.AnalyzerPacket{ Samples: currentFrame.Buffer, Channels: channels, BitDepth: bitDepth, SampleRate: decoder.Rate, } frameNumber++ } }() return audio.NewStream(newChannel, decoder.Channels, float64(decoder.Rate), blockSize), analyzerChannel, nil } func (f Format) Encode(stream *audio.Stream, writer format.WriteSeekCloser) error { const bitsPerSample = 16 encoder, err := libflac.NewEncoderWriter(writer, stream.GetChannels(), bitsPerSample, int(stream.GetSampleRate())) if err != nil { return err } defer encoder.Close() for block := range stream.GetAsBlockChannel() { samples := make([]int32, len(block)) C.audio_float32_to_int32((*C.float)(&block[0]), C.size_t(len(block)), (*C.int32_t)(&samples[0]), C.int(bitsPerSample)) err = encoder.WriteFrame(libflac.Frame{ Rate: int(stream.GetSampleRate()), Channels: stream.GetChannels(), Depth: bitsPerSample, Buffer: samples, }) if err != nil { return err } } return nil } func (f Format) Identify(peek []byte, extension string) bool { return bytes.Compare(peek[:4], []byte{'f', 'L', 'a', 'C'}) == 0 || extension == "flac" }