package flac // TODO: 24 bit picture length truncate warning // TODO: Cuesheet import ( "fmt" "github.com/wader/fq/format" "github.com/wader/fq/pkg/decode" "github.com/wader/fq/pkg/interp" "github.com/wader/fq/pkg/scalar" ) var flacStreaminfoFormat decode.Group var flacPicture decode.Group var vorbisCommentFormat decode.Group func init() { interp.RegisterFormat(decode.Format{ Name: format.FLAC_METADATABLOCK, Description: "FLAC metadatablock", DecodeFn: metadatablockDecode, Dependencies: []decode.Dependency{ {Names: []string{format.FLAC_STREAMINFO}, Group: &flacStreaminfoFormat}, {Names: []string{format.FLAC_PICTURE}, Group: &flacPicture}, {Names: []string{format.VORBIS_COMMENT}, Group: &vorbisCommentFormat}, }, }) } const ( MetadataBlockStreaminfo = 0 MetadataBlockPadding = 1 MetadataBlockApplication = 2 MetadataBlockSeektable = 3 MetadataBlockVorbisComment = 4 MetadataBlockCuesheet = 5 MetadataBlockPicture = 6 ) var metadataBlockNames = scalar.UintMapSymStr{ MetadataBlockStreaminfo: "streaminfo", MetadataBlockPadding: "padding", MetadataBlockApplication: "application", MetadataBlockSeektable: "seektable", MetadataBlockVorbisComment: "vorbis_comment", MetadataBlockCuesheet: "cuesheet", MetadataBlockPicture: "picture", } func metadatablockDecode(d *decode.D) any { var hasStreamInfo bool var streamInfo format.FlacStreamInfo isLastBlock := d.FieldBool("last_block") typ := d.FieldU7("type", metadataBlockNames) length := d.FieldU24("length") switch typ { case MetadataBlockStreaminfo: flacStreaminfoOut, ok := d.Format(flacStreaminfoFormat, nil).(format.FlacStreaminfoOut) if !ok { panic(fmt.Sprintf("expected FlacStreaminfoOut, got %#+v", flacStreaminfoOut)) } hasStreamInfo = true streamInfo = flacStreaminfoOut.StreamInfo case MetadataBlockVorbisComment: d.FieldFormatLen("comment", int64(length*8), vorbisCommentFormat, nil) case MetadataBlockPicture: d.FieldFormatLen("picture", int64(length*8), flacPicture, nil) case MetadataBlockSeektable: seektableCount := length / 18 d.FieldArray("seekpoints", func(d *decode.D) { for i := uint64(0); i < seektableCount; i++ { d.FieldStruct("seekpoint", func(d *decode.D) { d.FieldU64("sample_number", scalar.UintMap{ 0xffff_ffff_ffff_ffff: {Description: "Placeholder"}, }) d.FieldU64("offset") d.FieldU16("number_of_samples") }) } }) case MetadataBlockApplication: d.FieldUTF8("id", 4) d.FieldRawLen("data", int64((length-4)*8)) default: d.FieldRawLen("data", int64(length*8)) } return format.FlacMetadatablockOut{ IsLastBlock: isLastBlock, HasStreamInfo: hasStreamInfo, StreamInfo: streamInfo, } }