flacgo/meta/streaminfo.go
2022-07-26 16:14:37 +02:00

117 lines
2.9 KiB
Go

package meta
import (
"crypto/md5"
"errors"
"fmt"
"io"
"git.gammaspectra.live/S.O.N.G/flacgo/internal/bits"
)
// StreamInfo contains the basic properties of a FLAC audio stream, such as its
// sample rate and channel count. It is the only mandatory metadata block and
// must be present as the first metadata block of a FLAC stream.
//
// ref: https://www.xiph.org/flac/format.html#metadata_block_streaminfo
type StreamInfo struct {
// Minimum block size (in samples) used in the stream; between 16 and 65535
// samples.
BlockSizeMin uint16
// Maximum block size (in samples) used in the stream; between 16 and 65535
// samples.
BlockSizeMax uint16
// Minimum frame size in bytes; a 0 value implies unknown.
FrameSizeMin uint32
// Maximum frame size in bytes; a 0 value implies unknown.
FrameSizeMax uint32
// Sample rate in Hz; between 1 and 655350 Hz.
SampleRate uint32
// Number of channels; between 1 and 8 channels.
NChannels uint8
// Sample size in bits-per-sample; between 4 and 32 bits.
BitsPerSample uint8
// Total number of inter-channel samples in the stream. One second of 44.1
// KHz audio will have 44100 samples regardless of the number of channels. A
// 0 value implies unknown.
NSamples uint64
// MD5 checksum of the unencoded audio data.
MD5sum [md5.Size]uint8
}
// parseStreamInfo reads and parses the body of a StreamInfo metadata block.
func (block *Block) parseStreamInfo() error {
// 16 bits: BlockSizeMin.
br := bits.NewReader(block.lr)
x, err := br.Read(16)
if err != nil {
return unexpected(err)
}
if x < 16 {
return fmt.Errorf("meta.Block.parseStreamInfo: invalid minimum block size (%d); expected >= 16", x)
}
si := new(StreamInfo)
block.Body = si
si.BlockSizeMin = uint16(x)
// 16 bits: BlockSizeMax.
x, err = br.Read(16)
if err != nil {
return unexpected(err)
}
if x < 16 {
return fmt.Errorf("meta.Block.parseStreamInfo: invalid maximum block size (%d); expected >= 16", x)
}
si.BlockSizeMax = uint16(x)
// 24 bits: FrameSizeMin.
x, err = br.Read(24)
if err != nil {
return unexpected(err)
}
si.FrameSizeMin = uint32(x)
// 24 bits: FrameSizeMax.
x, err = br.Read(24)
if err != nil {
return unexpected(err)
}
si.FrameSizeMax = uint32(x)
// 20 bits: SampleRate.
x, err = br.Read(20)
if err != nil {
return unexpected(err)
}
if x == 0 {
return errors.New("meta.Block.parseStreamInfo: invalid sample rate (0)")
}
si.SampleRate = uint32(x)
// 3 bits: NChannels.
x, err = br.Read(3)
if err != nil {
return unexpected(err)
}
// x contains: (number of channels) - 1
si.NChannels = uint8(x + 1)
// 5 bits: BitsPerSample.
x, err = br.Read(5)
if err != nil {
return unexpected(err)
}
// x contains: (bits-per-sample) - 1
si.BitsPerSample = uint8(x + 1)
// 36 bits: NSamples.
si.NSamples, err = br.Read(36)
if err != nil {
return unexpected(err)
}
// 16 bytes: MD5sum.
_, err = io.ReadFull(block.lr, si.MD5sum[:])
return unexpected(err)
}