2021-09-17 16:46:13 +03:00
package flac
// TODO: 24 bit picture length truncate warning
2021-10-13 22:40:20 +03:00
// TODO: Cuesheet
2021-09-17 16:46:13 +03:00
import (
"github.com/wader/fq/format"
"github.com/wader/fq/format/registry"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/ranges"
)
var flacPicture [ ] * decode . Format
var vorbisCommentFormat [ ] * decode . Format
func init ( ) {
registry . MustRegister ( & decode . Format {
Name : format . FLAC_METADATABLOCKS ,
Description : "FLAC metadatablocks" ,
DecodeFn : metadatablocskDecode ,
RootV : decode . Array { } ,
RootName : "metadatablocks" ,
Dependencies : [ ] decode . Dependency {
{ Names : [ ] string { format . FLAC_PICTURE } , Formats : & flacPicture } ,
{ Names : [ ] string { format . VORBIS_COMMENT } , Formats : & vorbisCommentFormat } ,
} ,
} )
}
const (
MetadataBlockStreaminfo = 0
MetadataBlockPadding = 1
MetadataBlockApplication = 2
MetadataBlockSeektable = 3
MetadataBlockVorbisComment = 4
MetadataBlockCuesheet = 5
MetadataBlockPicture = 6
)
var metadataBlockNames = map [ uint ] string {
MetadataBlockStreaminfo : "Streaminfo" ,
MetadataBlockPadding : "Padding" ,
MetadataBlockApplication : "Application" ,
MetadataBlockSeektable : "Seektable" ,
MetadataBlockVorbisComment : "Vorbis comment" ,
MetadataBlockCuesheet : "Cuesheet" ,
MetadataBlockPicture : "Picture" ,
}
func metadatablocskDecode ( d * decode . D , in interface { } ) interface { } {
mb := format . FlacMetadatablocksOut { }
isLastBlock := false
for ! isLastBlock {
d . FieldStructFn ( "metadatablock" , func ( d * decode . D ) {
isLastBlock = d . FieldBool ( "last_block" )
typ := d . FieldUFn ( "type" , func ( ) ( uint64 , decode . DisplayFormat , string ) {
t := d . U7 ( )
name := "Unknown"
if s , ok := metadataBlockNames [ uint ( t ) ] ; ok {
name = s
}
return t , decode . NumberDecimal , name
} )
length := d . FieldU24 ( "length" )
switch typ {
case MetadataBlockStreaminfo :
d . FieldU16 ( "minimum_block_size" )
d . FieldU16 ( "maximum_block_size" )
d . FieldU24 ( "minimum_frame_size" )
d . FieldU24 ( "maximum_frame_size" )
sampleRate := d . FieldU ( "sample_rate" , 20 )
// <3> (number of channels)-1. FLAC supports from 1 to 8 channels
d . FieldUFn ( "channels" , func ( ) ( uint64 , decode . DisplayFormat , string ) { return d . U3 ( ) + 1 , decode . NumberDecimal , "" } )
// <5> (bits per sample)-1. FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample.
bitPerSample := d . FieldUFn ( "bits_per_sample" , func ( ) ( uint64 , decode . DisplayFormat , string ) {
return d . U5 ( ) + 1 , decode . NumberDecimal , ""
} )
totalSamplesInStream := d . FieldU ( "total_samples_in_stream" , 36 )
md5Range := ranges . Range { Start : d . Pos ( ) , Len : 16 * 8 }
d . FieldBitBufLen ( "md5" , 16 * 8 )
mb . StreamInfo = format . FlacMetadatablockStreamInfo {
SampleRate : sampleRate ,
BitPerSample : bitPerSample ,
TotalSamplesInStream : totalSamplesInStream ,
MD5Range : md5Range ,
}
mb . HasStreamInfo = true
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 . FieldArrayFn ( "seekpoints" , func ( d * decode . D ) {
for i := uint64 ( 0 ) ; i < seektableCount ; i ++ {
d . FieldStructFn ( "seekpoint" , func ( d * decode . D ) {
d . FieldUFn ( "sample_number" , func ( ) ( uint64 , decode . DisplayFormat , string ) {
n := d . U64 ( )
d := ""
if n == 0xffffffffffffffff {
d = "Placeholder"
}
return n , decode . NumberDecimal , d
} )
d . FieldU64 ( "offset" )
d . FieldU16 ( "number_of_samples" )
} )
}
} )
2021-10-24 00:06:03 +03:00
case MetadataBlockApplication :
d . FieldUTF8 ( "id" , 4 )
d . FieldBitBufLen ( "data" , int64 ( ( length - 4 ) * 8 ) )
2021-09-17 16:46:13 +03:00
default :
2021-10-24 00:06:03 +03:00
d . FieldBitBufLen ( "data" , int64 ( length * 8 ) )
2021-09-17 16:46:13 +03:00
}
} )
}
return mb
}