2015-04-14 16:09:58 +02:00
|
|
|
// Copyright 2015, David Howden
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package tag
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2015-06-28 04:40:49 +02:00
|
|
|
// blockType is a type which represents an enumeration of valid FLAC blocks
|
|
|
|
type blockType byte
|
2015-04-14 16:09:58 +02:00
|
|
|
|
2015-06-06 08:29:40 +02:00
|
|
|
// FLAC block types.
|
2015-04-14 16:09:58 +02:00
|
|
|
const (
|
2024-05-05 11:45:03 +02:00
|
|
|
StreamInfoBlock blockType = 0
|
2018-04-02 00:17:25 +02:00
|
|
|
// Padding Block 1
|
|
|
|
// Application Block 2
|
|
|
|
// Seektable Block 3
|
|
|
|
// Cue Sheet Block 5
|
|
|
|
vorbisCommentBlock blockType = 4
|
|
|
|
pictureBlock blockType = 6
|
2015-04-14 16:09:58 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// ReadFLACTags reads FLAC metadata from the io.ReadSeeker, returning the resulting
|
|
|
|
// metadata in a Metadata implementation, or non-nil error if there was a problem.
|
|
|
|
func ReadFLACTags(r io.ReadSeeker) (Metadata, error) {
|
|
|
|
flac, err := readString(r, 4)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if flac != "fLaC" {
|
|
|
|
return nil, errors.New("expected 'fLaC'")
|
|
|
|
}
|
|
|
|
|
2024-05-05 11:45:03 +02:00
|
|
|
m := &MetadataFLAC{
|
|
|
|
metadataVorbis: newMetadataVorbis(),
|
2015-04-14 16:09:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
last, err := m.readFLACMetadataBlock(r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if last {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return m, nil
|
|
|
|
}
|
|
|
|
|
2024-05-05 11:45:03 +02:00
|
|
|
type MetadataFLAC struct {
|
2015-05-24 02:44:45 +02:00
|
|
|
*metadataVorbis
|
2024-05-05 11:45:03 +02:00
|
|
|
|
|
|
|
MiniBlockSize uint16
|
|
|
|
MaxBlockSize uint16
|
|
|
|
SampleRate uint32
|
|
|
|
TotalSamples uint64
|
|
|
|
Duration float64
|
2015-04-14 16:09:58 +02:00
|
|
|
}
|
|
|
|
|
2024-05-05 11:45:03 +02:00
|
|
|
func (m *MetadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err error) {
|
2015-04-15 14:20:10 +02:00
|
|
|
blockHeader, err := readBytes(r, 1)
|
2015-04-14 16:09:58 +02:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if getBit(blockHeader[0], 7) {
|
2024-05-05 11:45:03 +02:00
|
|
|
blockHeader[0] ^= 1 << 7
|
2015-04-14 16:09:58 +02:00
|
|
|
last = true
|
|
|
|
}
|
|
|
|
|
2015-04-15 14:20:10 +02:00
|
|
|
blockLen, err := readInt(r, 3)
|
2015-04-14 16:09:58 +02:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-06-28 04:40:49 +02:00
|
|
|
switch blockType(blockHeader[0]) {
|
2024-05-05 11:45:03 +02:00
|
|
|
case StreamInfoBlock:
|
|
|
|
err = m.readStreamInfo(r, blockLen)
|
2015-06-28 04:40:49 +02:00
|
|
|
case vorbisCommentBlock:
|
2015-04-15 14:20:10 +02:00
|
|
|
err = m.readVorbisComment(r)
|
2015-04-14 16:09:58 +02:00
|
|
|
|
2015-06-28 04:40:49 +02:00
|
|
|
case pictureBlock:
|
2015-04-15 14:20:10 +02:00
|
|
|
err = m.readPictureBlock(r)
|
2015-04-14 16:09:58 +02:00
|
|
|
|
2015-04-15 14:20:10 +02:00
|
|
|
default:
|
2018-04-02 03:06:41 +02:00
|
|
|
_, err = r.Seek(int64(blockLen), io.SeekCurrent)
|
2015-04-15 14:20:10 +02:00
|
|
|
}
|
2015-04-14 16:09:58 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-05-05 11:45:03 +02:00
|
|
|
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 {
|
2015-04-14 16:09:58 +02:00
|
|
|
return FLAC
|
|
|
|
}
|