flacgo/encode_meta.go

377 lines
11 KiB
Go
Raw Normal View History

flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
package flac
import (
"encoding/binary"
"fmt"
"io"
2022-07-16 22:07:10 +00:00
"git.gammaspectra.live/S.O.N.G/flacgo/internal/ioutilx"
"git.gammaspectra.live/S.O.N.G/flacgo/meta"
flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
"github.com/icza/bitio"
"github.com/mewkiz/pkg/errutil"
)
// --- [ Metadata block ] ------------------------------------------------------
// encodeBlock encodes the metadata block, writing to bw.
func encodeBlock(bw *bitio.Writer, body interface{}, last bool) error {
flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
switch body := body.(type) {
case *meta.StreamInfo:
return encodeStreamInfo(bw, body, last)
case *meta.Application:
return encodeApplication(bw, body, last)
case *meta.SeekTable:
return encodeSeekTable(bw, body, last)
case *meta.VorbisComment:
return encodeVorbisComment(bw, body, last)
case *meta.CueSheet:
return encodeCueSheet(bw, body, last)
case *meta.Picture:
return encodePicture(bw, body, last)
default:
panic(fmt.Errorf("support for metadata block body type %T not yet implemented", body))
}
}
// --- [ Metadata block header ] -----------------------------------------------
// encodeBlockHeader encodes the metadata block header, writing to bw.
func encodeBlockHeader(bw *bitio.Writer, hdr *meta.Header) error {
flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
// 1 bit: IsLast.
if err := bw.WriteBool(hdr.IsLast); err != nil {
return errutil.Err(err)
}
// 7 bits: Type.
if err := bw.WriteBits(uint64(hdr.Type), 7); err != nil {
return errutil.Err(err)
}
// 24 bits: Length.
if err := bw.WriteBits(uint64(hdr.Length), 24); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ StreamInfo ] ----------------------------------------------------------
// encodeStreamInfo encodes the StreamInfo metadata block, writing to bw.
func encodeStreamInfo(bw *bitio.Writer, info *meta.StreamInfo, last bool) error {
flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
// Store metadata block header.
const nbits = 16 + 16 + 24 + 24 + 20 + 3 + 5 + 36 + 8*16
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeStreamInfo,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// 16 bits: BlockSizeMin.
if err := bw.WriteBits(uint64(info.BlockSizeMin), 16); err != nil {
return errutil.Err(err)
}
// 16 bits: BlockSizeMax.
if err := bw.WriteBits(uint64(info.BlockSizeMax), 16); err != nil {
return errutil.Err(err)
}
// 24 bits: FrameSizeMin.
if err := bw.WriteBits(uint64(info.FrameSizeMin), 24); err != nil {
return errutil.Err(err)
}
// 24 bits: FrameSizeMax.
if err := bw.WriteBits(uint64(info.FrameSizeMax), 24); err != nil {
return errutil.Err(err)
}
// 20 bits: SampleRate.
if err := bw.WriteBits(uint64(info.SampleRate), 20); err != nil {
return errutil.Err(err)
}
// 3 bits: NChannels; stored as (number of channels) - 1.
if err := bw.WriteBits(uint64(info.NChannels-1), 3); err != nil {
return errutil.Err(err)
}
// 5 bits: BitsPerSample; stored as (bits-per-sample) - 1.
if err := bw.WriteBits(uint64(info.BitsPerSample-1), 5); err != nil {
return errutil.Err(err)
}
// 36 bits: NSamples.
if err := bw.WriteBits(info.NSamples, 36); err != nil {
return errutil.Err(err)
}
// 16 bytes: MD5sum.
if _, err := bw.Write(info.MD5sum[:]); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ Application ] ---------------------------------------------------------
// encodeApplication encodes the Application metadata block, writing to bw.
func encodeApplication(bw *bitio.Writer, app *meta.Application, last bool) error {
flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
// Store metadata block header.
nbits := int64(32 + 8*len(app.Data))
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeApplication,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// 32 bits: ID.
if err := bw.WriteBits(uint64(app.ID), 32); err != nil {
return errutil.Err(err)
}
// TODO: check if the Application block may contain only an ID.
if _, err := bw.Write(app.Data); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ SeekTable ] -----------------------------------------------------------
// encodeSeekTable encodes the SeekTable metadata block, writing to bw.
func encodeSeekTable(bw *bitio.Writer, table *meta.SeekTable, last bool) error {
flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
// Store metadata block header.
nbits := int64((64 + 64 + 16) * len(table.Points))
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeSeekTable,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
for _, point := range table.Points {
if err := binary.Write(bw, binary.BigEndian, point); err != nil {
return errutil.Err(err)
}
}
return nil
}
// --- [ VorbisComment ] -------------------------------------------------------
// encodeVorbisComment encodes the VorbisComment metadata block, writing to bw.
func encodeVorbisComment(bw *bitio.Writer, comment *meta.VorbisComment, last bool) error {
flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
// Store metadata block header.
nbits := int64(32 + 8*len(comment.Vendor) + 32)
for _, tag := range comment.Tags {
nbits += int64(32 + 8*(len(tag[0])+1+len(tag[1])))
}
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeVorbisComment,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// 32 bits: vendor length.
// TODO: verify that little-endian encoding is used; otherwise, switch to
// using bw.WriteBits.
if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Vendor))); err != nil {
return errutil.Err(err)
}
// (vendor length) bits: Vendor.
if _, err := bw.Write([]byte(comment.Vendor)); err != nil {
return errutil.Err(err)
}
// Store tags.
// 32 bits: number of tags.
if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Tags))); err != nil {
return errutil.Err(err)
}
for _, tag := range comment.Tags {
// Store tag, which has the following format:
// NAME=VALUE
buf := []byte(fmt.Sprintf("%s=%s", tag[0], tag[1]))
// 32 bits: vector length
if err := binary.Write(bw, binary.LittleEndian, uint32(len(buf))); err != nil {
return errutil.Err(err)
}
// (vector length): vector.
if _, err := bw.Write(buf); err != nil {
return errutil.Err(err)
}
}
return nil
}
// --- [ CueSheet ] ------------------------------------------------------------
// encodeCueSheet encodes the CueSheet metadata block, writing to bw.
func encodeCueSheet(bw *bitio.Writer, cs *meta.CueSheet, last bool) error {
flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
// Store metadata block header.
nbits := int64(8*128 + 64 + 1 + 7 + 8*258 + 8)
for _, track := range cs.Tracks {
nbits += 64 + 8 + 8*12 + 1 + 1 + 6 + 8*13 + 8
for range track.Indicies {
nbits += 64 + 8 + 8*3
}
}
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeCueSheet,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// Store cue sheet.
// 128 bytes: MCN.
var mcn [128]byte
copy(mcn[:], cs.MCN)
if _, err := bw.Write(mcn[:]); err != nil {
return errutil.Err(err)
}
// 64 bits: NLeadInSamples.
if err := bw.WriteBits(cs.NLeadInSamples, 64); err != nil {
return errutil.Err(err)
}
// 1 bit: IsCompactDisc.
if err := bw.WriteBool(cs.IsCompactDisc); err != nil {
return errutil.Err(err)
}
// 7 bits and 258 bytes: reserved.
if err := bw.WriteBits(0, 7); err != nil {
return errutil.Err(err)
}
if _, err := io.CopyN(bw, ioutilx.Zero, 258); err != nil {
return errutil.Err(err)
}
// Store cue sheet tracks.
// 8 bits: (number of tracks)
if err := bw.WriteBits(uint64(len(cs.Tracks)), 8); err != nil {
return errutil.Err(err)
}
for _, track := range cs.Tracks {
// 64 bits: Offset.
if err := bw.WriteBits(track.Offset, 64); err != nil {
return errutil.Err(err)
}
// 8 bits: Num.
if err := bw.WriteBits(uint64(track.Num), 8); err != nil {
return errutil.Err(err)
}
// 12 bytes: ISRC.
var isrc [12]byte
copy(isrc[:], track.ISRC)
if _, err := bw.Write(isrc[:]); err != nil {
return errutil.Err(err)
}
// 1 bit: IsAudio.
if err := bw.WriteBool(!track.IsAudio); err != nil {
return errutil.Err(err)
}
// 1 bit: HasPreEmphasis.
// mask = 01000000
if err := bw.WriteBool(track.HasPreEmphasis); err != nil {
return errutil.Err(err)
}
// 6 bits and 13 bytes: reserved.
// mask = 00111111
if err := bw.WriteBits(0, 6); err != nil {
return errutil.Err(err)
}
if _, err := io.CopyN(bw, ioutilx.Zero, 13); err != nil {
return errutil.Err(err)
}
// Store indicies.
// 8 bits: (number of indicies)
if err := bw.WriteBits(uint64(len(track.Indicies)), 8); err != nil {
return errutil.Err(err)
}
for _, index := range track.Indicies {
// 64 bits: Offset.
if err := bw.WriteBits(index.Offset, 64); err != nil {
return errutil.Err(err)
}
// 8 bits: Num.
if err := bw.WriteBits(uint64(index.Num), 8); err != nil {
return errutil.Err(err)
}
// 3 bytes: reserved.
if _, err := io.CopyN(bw, ioutilx.Zero, 3); err != nil {
return errutil.Err(err)
}
}
}
return nil
}
// --- [ Picture ] -------------------------------------------------------------
// encodePicture encodes the Picture metadata block, writing to bw.
func encodePicture(bw *bitio.Writer, pic *meta.Picture, last bool) error {
flac: add Encoder API to encode audio samples and metadata blocks (#32) * flac: encode frame header * flac: calculate CRC-8 when encoding frame headers * flac: fix encoding of frame header * flac: add preliminary subframe encoder * flac: fix UTF-8 encoding of frame number * frame: add sanity check for sample count in decodeLPC Updates #31. * flac: update flac encoding API, depricate flac.Encode Encode has been removed in favour of using NewEncoder. The Encode function was temporarily added to support re-encoding FLAC streams to update the metadata, but it had no support for encoding audio samples. The added flac.Encoder has support for encoding both metadata and audio samples. It also does not require that you first decode a FLAC file to later re-encode it by calling Encode (as was the previous behaviour). * flac: add MD5 running hash of unencoded audio samples to StreamInfo * flac: remove unused encodePadding Reported by golangci * flac: fix golangci lint issues frame/utf8.go:57:6: `decodeUTF8Int` is unused (deadcode) func decodeUTF8Int(r io.Reader) (n uint64, err error) { ^ internal/utf8/encode.go:32:16: unnecessary conversion (unconvert) bits = uint64(t2 | (x>>6)&mask2) ^ internal/utf8/encode.go:37:16: unnecessary conversion (unconvert) bits = uint64(t3 | (x>>(6*2))&mask3) ^ internal/utf8/encode.go:42:16: unnecessary conversion (unconvert) bits = uint64(t4 | (x>>(6*3))&mask4) ^ * flac: fix golangci lint issues encode_frame.go:89:1: cyclomatic complexity 52 of func `(*Encoder).encodeFrameHeader` is high (> 30) (gocyclo) func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { ^ internal/utf8/encode.go:66:17: unnecessary conversion (unconvert) bits := uint64(tx | (x>>uint(6*i))&maskx) ^ encode_subframe.go:105:46: unnecessary conversion (unconvert) if err := bw.WriteBits(uint64(sample), byte(hdr.BitsPerSample)); err != nil { ^ * flac: clarify that frame.Header.Num is calculated by the encoder * flac: minor re-phrasing
2018-08-18 18:18:12 +00:00
// Store metadata block header.
nbits := int64(32 + 32 + 8*len(pic.MIME) + 32 + 8*len(pic.Desc) + 32 + 32 + 32 + 32 + 32 + 8*len(pic.Data))
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeCueSheet,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// 32 bits: Type.
if err := bw.WriteBits(uint64(pic.Type), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: (MIME type length).
if err := bw.WriteBits(uint64(len(pic.MIME)), 32); err != nil {
return errutil.Err(err)
}
// (MIME type length) bytes: MIME.
if _, err := bw.Write([]byte(pic.MIME)); err != nil {
return errutil.Err(err)
}
// 32 bits: (description length).
if err := bw.WriteBits(uint64(len(pic.Desc)), 32); err != nil {
return errutil.Err(err)
}
// (description length) bytes: Desc.
if _, err := bw.Write([]byte(pic.Desc)); err != nil {
return errutil.Err(err)
}
// 32 bits: Width.
if err := bw.WriteBits(uint64(pic.Width), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: Height.
if err := bw.WriteBits(uint64(pic.Height), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: Depth.
if err := bw.WriteBits(uint64(pic.Depth), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: NPalColors.
if err := bw.WriteBits(uint64(pic.NPalColors), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: (data length).
if err := bw.WriteBits(uint64(len(pic.Data)), 32); err != nil {
return errutil.Err(err)
}
// (data length) bytes: Data.
if _, err := bw.Write(pic.Data); err != nil {
return errutil.Err(err)
}
return nil
}