✨ Expand the metadata of flac, now you can read the STREAMINFO block
This commit is contained in:
parent
3d75831295
commit
779ee174a8
43
flac.go
43
flac.go
@ -14,7 +14,7 @@ type blockType byte
|
||||
|
||||
// FLAC block types.
|
||||
const (
|
||||
// Stream Info Block 0
|
||||
StreamInfoBlock blockType = 0
|
||||
// Padding Block 1
|
||||
// Application Block 2
|
||||
// Seektable Block 3
|
||||
@ -34,8 +34,8 @@ func ReadFLACTags(r io.ReadSeeker) (Metadata, error) {
|
||||
return nil, errors.New("expected 'fLaC'")
|
||||
}
|
||||
|
||||
m := &metadataFLAC{
|
||||
newMetadataVorbis(),
|
||||
m := &MetadataFLAC{
|
||||
metadataVorbis: newMetadataVorbis(),
|
||||
}
|
||||
|
||||
for {
|
||||
@ -51,18 +51,24 @@ func ReadFLACTags(r io.ReadSeeker) (Metadata, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
type metadataFLAC struct {
|
||||
type MetadataFLAC struct {
|
||||
*metadataVorbis
|
||||
|
||||
MiniBlockSize uint16
|
||||
MaxBlockSize uint16
|
||||
SampleRate uint32
|
||||
TotalSamples uint64
|
||||
Duration float64
|
||||
}
|
||||
|
||||
func (m *metadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err error) {
|
||||
func (m *MetadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err error) {
|
||||
blockHeader, err := readBytes(r, 1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if getBit(blockHeader[0], 7) {
|
||||
blockHeader[0] ^= (1 << 7)
|
||||
blockHeader[0] ^= 1 << 7
|
||||
last = true
|
||||
}
|
||||
|
||||
@ -72,6 +78,8 @@ func (m *metadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err er
|
||||
}
|
||||
|
||||
switch blockType(blockHeader[0]) {
|
||||
case StreamInfoBlock:
|
||||
err = m.readStreamInfo(r, blockLen)
|
||||
case vorbisCommentBlock:
|
||||
err = m.readVorbisComment(r)
|
||||
|
||||
@ -84,6 +92,27 @@ func (m *metadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err er
|
||||
return
|
||||
}
|
||||
|
||||
func (m *metadataFLAC) FileType() FileType {
|
||||
func (m *MetadataFLAC) readStreamInfo(r io.ReadSeeker, len int) error {
|
||||
data := make([]byte, len)
|
||||
|
||||
if _, err := r.Read(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.MiniBlockSize = uint16(data[0])<<8 | uint16(data[1])
|
||||
m.MaxBlockSize = uint16(data[2])<<8 | uint16(data[3])
|
||||
|
||||
m.SampleRate = (uint32(data[10])<<16 | uint32(data[11])<<8 | uint32(data[12])) >> 4
|
||||
|
||||
m.TotalSamples = uint64(data[13])<<32 | uint64(data[14])<<24 | uint64(data[15])<<16 | uint64(data[16])<<8 | uint64(data[17])
|
||||
|
||||
m.TotalSamples ^= m.TotalSamples >> 36 << 36
|
||||
|
||||
m.Duration = float64(m.TotalSamples) / float64(m.SampleRate)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MetadataFLAC) FileType() FileType {
|
||||
return FLAC
|
||||
}
|
||||
|
65
flac_test.go
Normal file
65
flac_test.go
Normal file
@ -0,0 +1,65 @@
|
||||
package tag
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type expect struct {
|
||||
file string
|
||||
sampleRate uint32
|
||||
totalSamples uint64
|
||||
duration float64
|
||||
}
|
||||
|
||||
func TestReadFLACTags(t *testing.T) {
|
||||
testFiles := []expect{
|
||||
{"./testdata/without_tags/sample.flac", 11025, 37478, 3.399365},
|
||||
{"./testdata/with_tags/sample.flac", 11025, 37478, 3.399365},
|
||||
}
|
||||
|
||||
for _, testFile := range testFiles {
|
||||
file, err := os.Open(testFile.file)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
metadata, err := ReadFLACTags(file)
|
||||
|
||||
t.Run("ReadFLACTags", func(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("ReadFLACTags(%s) returned error: %v", testFile.file, err)
|
||||
}
|
||||
if metadata == nil {
|
||||
t.Errorf("ReadFLACTags(%s) returned nil metadata", testFile.file)
|
||||
}
|
||||
})
|
||||
|
||||
flacMetadata, ok := metadata.(*MetadataFLAC)
|
||||
|
||||
t.Run("MetadataFLAC", func(t *testing.T) {
|
||||
if !ok {
|
||||
t.Errorf("ReadFLACTags(%s) returned wrong metadata type", testFile.file)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("SampleRate", func(t *testing.T) {
|
||||
if flacMetadata.SampleRate != testFile.sampleRate {
|
||||
t.Errorf("ReadFLACTags(%s) returned wrong SampleRate: %d", testFile.file, flacMetadata.SampleRate)
|
||||
}
|
||||
})
|
||||
t.Run("TotalSamples", func(t *testing.T) {
|
||||
if flacMetadata.TotalSamples != testFile.totalSamples {
|
||||
t.Errorf("ReadFLACTags(%s) returned wrong TotalSamples: %d", testFile.file, flacMetadata.TotalSamples)
|
||||
}
|
||||
})
|
||||
t.Run("Duration", func(t *testing.T) {
|
||||
if fmt.Sprintf("%.4f", flacMetadata.Duration) != fmt.Sprintf("%.4f", testFile.duration) {
|
||||
t.Errorf("ReadFLACTags(%s) returned wrong Duration: %f", testFile.file, flacMetadata.Duration)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user