Compare commits
4 commits
00f1daf718
...
e1a48c4800
Author | SHA1 | Date | |
---|---|---|---|
DataHoarder | e1a48c4800 | ||
DataHoarder | 18f6041006 | ||
DataHoarder | 3c16c77da5 | ||
DataHoarder | 42f940f815 |
30
README.md
30
README.md
|
@ -2,7 +2,7 @@
|
|||
|
||||
[![Build Status](https://travis-ci.org/mewkiz/flac.svg?branch=master)](https://travis-ci.org/mewkiz/flac)
|
||||
[![Coverage Status](https://img.shields.io/coveralls/mewkiz/flac.svg)](https://coveralls.io/r/mewkiz/flac?branch=master)
|
||||
[![GoDoc](https://godoc.org/github.com/mewkiz/flac?status.svg)](https://godoc.org/github.com/mewkiz/flac)
|
||||
[![GoDoc](https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo?status.svg)](https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo)
|
||||
|
||||
This package provides access to [FLAC][1] (Free Lossless Audio Codec) streams.
|
||||
|
||||
|
@ -16,40 +16,40 @@ Documentation provided by GoDoc.
|
|||
- [frame][flac/frame]: implements access to FLAC audio frames.
|
||||
- [meta][flac/meta]: implements access to FLAC metadata blocks.
|
||||
|
||||
[flac]: http://godoc.org/github.com/mewkiz/flac
|
||||
[flac/frame]: http://godoc.org/github.com/mewkiz/flac/frame
|
||||
[flac/meta]: http://godoc.org/github.com/mewkiz/flac/meta
|
||||
[flac]: http://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo
|
||||
[flac/frame]: http://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/frame
|
||||
[flac/meta]: http://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/meta
|
||||
|
||||
## Changes
|
||||
|
||||
* Version 1.0.7 (2021-01-28)
|
||||
- Add seek API (see [#44](https://github.com/mewkiz/flac/pull/44) and [#46](https://github.com/mewkiz/flac/pull/46)). Thanks to [Craig Swank](https://github.com/cswank).
|
||||
- Add seek API (see [#44](https://git.gammaspectra.live/S.O.N.G/flacgo/pull/44) and [#46](https://git.gammaspectra.live/S.O.N.G/flacgo/pull/46)). Thanks to [Craig Swank](https://github.com/cswank).
|
||||
|
||||
* Version 1.0.6 (2019-12-20)
|
||||
- Add experimental Encoder API to encode audio samples and metadata blocks (see [#32](https://github.com/mewkiz/flac/pull/32)).
|
||||
- Add experimental Encoder API to encode audio samples and metadata blocks (see [#32](https://git.gammaspectra.live/S.O.N.G/flacgo/pull/32)).
|
||||
- Use go.mod.
|
||||
- Skip ID3v2 data prepended to flac files when parsing (see [36cc17e](https://github.com/mewkiz/flac/commit/36cc17efed51a9bae283d6a3a7a10997492945e7)).
|
||||
- Skip ID3v2 data prepended to flac files when parsing (see [36cc17e](https://git.gammaspectra.live/S.O.N.G/flacgo/commit/36cc17efed51a9bae283d6a3a7a10997492945e7)).
|
||||
- Remove dependency on encodebytes. Thanks to [Mikey Dickerson](https://github.com/mdickers47).
|
||||
- Add 16kHz test case. Thanks to [Chewxy](https://github.com/chewxy).
|
||||
- Fix lint issues (see [#25](https://github.com/mewkiz/flac/issues/25)).
|
||||
- Fix lint issues (see [#25](https://git.gammaspectra.live/S.O.N.G/flacgo/issues/25)).
|
||||
|
||||
* Version 1.0.5 (2016-05-06)
|
||||
- Simplify import paths. Drop use of gopkg.in, and rely on vendoring instead (see [azul3d/engine#1](https://github.com/azul3d/engine/issues/1)).
|
||||
- Add FLAC decoding benchmark (see [d675e0a](https://github.com/mewkiz/flac/blob/d675e0aaccf2e43055f56b9b3feeddfdeed402e2/frame/frame_test.go#L60))
|
||||
- Add FLAC decoding benchmark (see [d675e0a](https://git.gammaspectra.live/S.O.N.G/flacgo/blob/d675e0aaccf2e43055f56b9b3feeddfdeed402e2/frame/frame_test.go#L60))
|
||||
|
||||
* Version 1.0.4 (2016-02-11)
|
||||
- Add API examples to documentation (see [#11](https://github.com/mewkiz/flac/issues/11)).
|
||||
- Extend test cases (see [aadf80a](https://github.com/mewkiz/flac/commit/aadf80aa28c463a94b8d5c49757e5a0948613ce2)).
|
||||
- Add API examples to documentation (see [#11](https://git.gammaspectra.live/S.O.N.G/flacgo/issues/11)).
|
||||
- Extend test cases (see [aadf80a](https://git.gammaspectra.live/S.O.N.G/flacgo/commit/aadf80aa28c463a94b8d5c49757e5a0948613ce2)).
|
||||
|
||||
* Version 1.0.3 (2016-02-02)
|
||||
- Implement decoding of FLAC files with wasted bits-per-sample (see [#12](https://github.com/mewkiz/flac/issues/12)).
|
||||
- Stress test the library using [go-fuzz](https://github.com/dvyukov/go-fuzz) (see [#10](https://github.com/mewkiz/flac/pull/10)). Thanks to [Patrick Mézard](https://github.com/pmezard).
|
||||
- Implement decoding of FLAC files with wasted bits-per-sample (see [#12](https://git.gammaspectra.live/S.O.N.G/flacgo/issues/12)).
|
||||
- Stress test the library using [go-fuzz](https://github.com/dvyukov/go-fuzz) (see [#10](https://git.gammaspectra.live/S.O.N.G/flacgo/pull/10)). Thanks to [Patrick Mézard](https://github.com/pmezard).
|
||||
|
||||
* Version 1.0.2 (2015-06-05)
|
||||
- Fix decoding of blocking strategy (see [#9](https://github.com/mewkiz/flac/pull/9)). Thanks to [Sergey Didyk](https://github.com/sdidyk).
|
||||
- Fix decoding of blocking strategy (see [#9](https://git.gammaspectra.live/S.O.N.G/flacgo/pull/9)). Thanks to [Sergey Didyk](https://github.com/sdidyk).
|
||||
|
||||
* Version 1.0.1 (2015-02-25)
|
||||
- Fix two subframe decoding bugs (see [#7](https://github.com/mewkiz/flac/pull/7)). Thanks to [Jonathan MacMillan](https://github.com/perotinus).
|
||||
- Fix two subframe decoding bugs (see [#7](https://git.gammaspectra.live/S.O.N.G/flacgo/pull/7)). Thanks to [Jonathan MacMillan](https://github.com/perotinus).
|
||||
- Add frame decoding test cases.
|
||||
|
||||
* Version 1.0.0 (2014-09-30)
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo"
|
||||
"github.com/go-audio/audio"
|
||||
"github.com/go-audio/wav"
|
||||
"github.com/mewkiz/flac"
|
||||
"github.com/mewkiz/pkg/osutil"
|
||||
"github.com/mewkiz/pkg/pathutil"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -88,7 +88,7 @@ func flac2wav(path string, force bool) error {
|
|||
// as signed values (ref page 59-60 of [1]).
|
||||
//
|
||||
// [1]: http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/riffmci.pdf
|
||||
// ref: https://github.com/mewkiz/flac/issues/51#issuecomment-1046183409
|
||||
// ref: https://git.gammaspectra.live/S.O.N.G/flacgo/issues/51#issuecomment-1046183409
|
||||
const midpointValue = 0x80
|
||||
sample += midpointValue
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/mewkiz/flac"
|
||||
"github.com/mewkiz/flac/meta"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/meta"
|
||||
)
|
||||
|
||||
// flagBlockNum contains an optional comma-separated list of block numbers to
|
||||
|
@ -143,10 +143,11 @@ var typeName = map[meta.Type]string{
|
|||
// is_last.
|
||||
//
|
||||
// Example:
|
||||
// METADATA block #0
|
||||
// type: 0 (STREAMINFO)
|
||||
// is last: false
|
||||
// length: 34
|
||||
//
|
||||
// METADATA block #0
|
||||
// type: 0 (STREAMINFO)
|
||||
// is last: false
|
||||
// length: 34
|
||||
func listStreamInfoHeader(isLast bool) {
|
||||
fmt.Println("METADATA block #0")
|
||||
fmt.Println(" type: 0 (STREAMINFO)")
|
||||
|
@ -155,10 +156,11 @@ func listStreamInfoHeader(isLast bool) {
|
|||
}
|
||||
|
||||
// Example:
|
||||
// METADATA block #0
|
||||
// type: 0 (STREAMINFO)
|
||||
// is last: false
|
||||
// length: 34
|
||||
//
|
||||
// METADATA block #0
|
||||
// type: 0 (STREAMINFO)
|
||||
// is last: false
|
||||
// length: 34
|
||||
func listHeader(header *meta.Header, blockNum int) {
|
||||
name, ok := typeName[header.Type]
|
||||
if !ok {
|
||||
|
@ -171,15 +173,16 @@ func listHeader(header *meta.Header, blockNum int) {
|
|||
}
|
||||
|
||||
// Example:
|
||||
// minimum blocksize: 4608 samples
|
||||
// maximum blocksize: 4608 samples
|
||||
// minimum framesize: 0 bytes
|
||||
// maximum framesize: 19024 bytes
|
||||
// sample_rate: 44100 Hz
|
||||
// channels: 2
|
||||
// bits-per-sample: 16
|
||||
// total samples: 151007220
|
||||
// MD5 signature: 2e6238f5d9fe5c19f3ead628f750fd3d
|
||||
//
|
||||
// minimum blocksize: 4608 samples
|
||||
// maximum blocksize: 4608 samples
|
||||
// minimum framesize: 0 bytes
|
||||
// maximum framesize: 19024 bytes
|
||||
// sample_rate: 44100 Hz
|
||||
// channels: 2
|
||||
// bits-per-sample: 16
|
||||
// total samples: 151007220
|
||||
// MD5 signature: 2e6238f5d9fe5c19f3ead628f750fd3d
|
||||
func listStreamInfo(si *meta.StreamInfo) {
|
||||
fmt.Printf(" minimum blocksize: %d samples\n", si.BlockSizeMin)
|
||||
fmt.Printf(" maximum blocksize: %d samples\n", si.BlockSizeMax)
|
||||
|
@ -193,9 +196,10 @@ func listStreamInfo(si *meta.StreamInfo) {
|
|||
}
|
||||
|
||||
// Example:
|
||||
// application ID: 46696361
|
||||
// data contents:
|
||||
// Medieval CUE Splitter (www.medieval.it)
|
||||
//
|
||||
// application ID: 46696361
|
||||
// data contents:
|
||||
// Medieval CUE Splitter (www.medieval.it)
|
||||
func listApplication(app *meta.Application) {
|
||||
fmt.Printf(" application ID: %d\n", app.ID)
|
||||
fmt.Println(" data contents:")
|
||||
|
@ -205,10 +209,11 @@ func listApplication(app *meta.Application) {
|
|||
}
|
||||
|
||||
// Example:
|
||||
// seek points: 17
|
||||
// point 0: sample_number=0, stream_offset=0, frame_samples=4608
|
||||
// point 1: sample_number=2419200, stream_offset=3733871, frame_samples=4608
|
||||
// ...
|
||||
//
|
||||
// seek points: 17
|
||||
// point 0: sample_number=0, stream_offset=0, frame_samples=4608
|
||||
// point 1: sample_number=2419200, stream_offset=3733871, frame_samples=4608
|
||||
// ...
|
||||
func listSeekTable(st *meta.SeekTable) {
|
||||
fmt.Printf(" seek points: %d\n", len(st.Points))
|
||||
for pointNum, point := range st.Points {
|
||||
|
@ -221,11 +226,12 @@ func listSeekTable(st *meta.SeekTable) {
|
|||
}
|
||||
|
||||
// Example:
|
||||
// vendor string: reference libFLAC 1.2.1 20070917
|
||||
// comments: 10
|
||||
// comment[0]: ALBUM=「sugar sweet nightmare」 & 「化物語」劇伴音楽集 其の壹
|
||||
// comment[1]: ARTIST=神前暁
|
||||
// ...
|
||||
//
|
||||
// vendor string: reference libFLAC 1.2.1 20070917
|
||||
// comments: 10
|
||||
// comment[0]: ALBUM=「sugar sweet nightmare」 & 「化物語」劇伴音楽集 其の壹
|
||||
// comment[1]: ARTIST=神前暁
|
||||
// ...
|
||||
func listVorbisComment(vc *meta.VorbisComment) {
|
||||
fmt.Printf(" vendor string: %s\n", vc.Vendor)
|
||||
fmt.Printf(" comments: %d\n", len(vc.Tags))
|
||||
|
@ -235,34 +241,35 @@ func listVorbisComment(vc *meta.VorbisComment) {
|
|||
}
|
||||
|
||||
// Example:
|
||||
// media catalog number:
|
||||
// lead-in: 88200
|
||||
// is CD: true
|
||||
// number of tracks: 18
|
||||
// track[0]
|
||||
// offset: 0
|
||||
// number: 1
|
||||
// ISRC:
|
||||
// type: AUDIO
|
||||
// pre-emphasis: false
|
||||
// number of index points: 1
|
||||
// index[0]
|
||||
// offset: 0
|
||||
// number: 1
|
||||
// track[1]
|
||||
// offset: 2421384
|
||||
// number: 2
|
||||
// ISRC:
|
||||
// type: AUDIO
|
||||
// pre-emphasis: false
|
||||
// number of index points: 1
|
||||
// index[0]
|
||||
// offset: 0
|
||||
// number: 1
|
||||
// ...
|
||||
// track[17]
|
||||
// offset: 151007220
|
||||
// number: 170 (LEAD-OUT)
|
||||
//
|
||||
// media catalog number:
|
||||
// lead-in: 88200
|
||||
// is CD: true
|
||||
// number of tracks: 18
|
||||
// track[0]
|
||||
// offset: 0
|
||||
// number: 1
|
||||
// ISRC:
|
||||
// type: AUDIO
|
||||
// pre-emphasis: false
|
||||
// number of index points: 1
|
||||
// index[0]
|
||||
// offset: 0
|
||||
// number: 1
|
||||
// track[1]
|
||||
// offset: 2421384
|
||||
// number: 2
|
||||
// ISRC:
|
||||
// type: AUDIO
|
||||
// pre-emphasis: false
|
||||
// number of index points: 1
|
||||
// index[0]
|
||||
// offset: 0
|
||||
// number: 1
|
||||
// ...
|
||||
// track[17]
|
||||
// offset: 151007220
|
||||
// number: 170 (LEAD-OUT)
|
||||
func listCueSheet(cs *meta.CueSheet) {
|
||||
fmt.Printf(" media catalog number: %s\n", cs.MCN)
|
||||
fmt.Printf(" lead-in: %d\n", cs.NLeadInSamples)
|
||||
|
@ -294,17 +301,18 @@ func listCueSheet(cs *meta.CueSheet) {
|
|||
}
|
||||
|
||||
// Example:
|
||||
// type: 3 (Cover (front))
|
||||
// MIME type: image/jpeg
|
||||
// description:
|
||||
// width: 0
|
||||
// height: 0
|
||||
// depth: 0
|
||||
// colors: 0 (unindexed)
|
||||
// data length: 234569
|
||||
// data:
|
||||
// 00000000: FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 60 ......JFIF.....`
|
||||
// 00000010: 00 60 00 00 FF DB 00 43 00 01 01 01 01 01 01 01 .`.....C........
|
||||
//
|
||||
// type: 3 (Cover (front))
|
||||
// MIME type: image/jpeg
|
||||
// description:
|
||||
// width: 0
|
||||
// height: 0
|
||||
// depth: 0
|
||||
// colors: 0 (unindexed)
|
||||
// data length: 234569
|
||||
// data:
|
||||
// 00000000: FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 60 ......JFIF.....`
|
||||
// 00000010: 00 60 00 00 FF DB 00 43 00 01 01 01 01 01 01 01 .`.....C........
|
||||
func listPicture(pic *meta.Picture) {
|
||||
typeName := map[uint32]string{
|
||||
0: "Other",
|
||||
|
|
|
@ -6,11 +6,11 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/frame"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/meta"
|
||||
"github.com/go-audio/audio"
|
||||
"github.com/go-audio/wav"
|
||||
"github.com/mewkiz/flac"
|
||||
"github.com/mewkiz/flac/frame"
|
||||
"github.com/mewkiz/flac/meta"
|
||||
"github.com/mewkiz/pkg/osutil"
|
||||
"github.com/mewkiz/pkg/pathutil"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -88,7 +88,7 @@ func wav2flac(wavPath string, force bool) error {
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
// Number of samples per channel and block.
|
||||
const nsamplesPerChannel = 16
|
||||
const nsamplesPerChannel = 4096
|
||||
nsamplesPerBlock := nchannels * nsamplesPerChannel
|
||||
buf := &audio.IntBuffer{
|
||||
Format: &audio.Format{
|
||||
|
@ -116,6 +116,10 @@ func wav2flac(wavPath string, force bool) error {
|
|||
if n == 0 {
|
||||
break
|
||||
}
|
||||
if n < 16*nchannels {
|
||||
n = 16
|
||||
//break
|
||||
}
|
||||
for _, subframe := range subframes {
|
||||
subHdr := frame.SubHeader{
|
||||
// Specifies the prediction method used to encode the audio sample of the
|
||||
|
@ -130,7 +134,7 @@ func wav2flac(wavPath string, force bool) error {
|
|||
subframe.NSamples = n / nchannels
|
||||
subframe.Samples = subframe.Samples[:subframe.NSamples]
|
||||
}
|
||||
for i, sample := range buf.Data {
|
||||
for i, sample := range buf.Data[:n] {
|
||||
subframe := subframes[i%nchannels]
|
||||
subframe.Samples[i/nchannels] = int32(sample)
|
||||
}
|
||||
|
@ -160,7 +164,7 @@ func wav2flac(wavPath string, force bool) error {
|
|||
HasFixedBlockSize: false,
|
||||
// Block size in inter-channel samples, i.e. the number of audio samples
|
||||
// in each subframe.
|
||||
BlockSize: uint16(nsamplesPerChannel),
|
||||
BlockSize: uint16(subframes[0].NSamples),
|
||||
// Sample rate in Hz; a 0 value implies unknown, get sample rate from
|
||||
// StreamInfo.
|
||||
SampleRate: uint32(sampleRate),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//+build ignore
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package flac_test
|
||||
|
||||
|
@ -7,8 +8,8 @@ import (
|
|||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/mewkiz/flac"
|
||||
"github.com/mewkiz/flac/meta"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/meta"
|
||||
)
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
|
|
|
@ -5,8 +5,8 @@ import (
|
|||
"hash"
|
||||
"io"
|
||||
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/meta"
|
||||
"github.com/icza/bitio"
|
||||
"github.com/mewkiz/flac/meta"
|
||||
"github.com/mewkiz/pkg/errutil"
|
||||
)
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@ import (
|
|||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/frame"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/hashutil/crc16"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/hashutil/crc8"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/utf8"
|
||||
"github.com/icza/bitio"
|
||||
"github.com/mewkiz/flac/frame"
|
||||
"github.com/mewkiz/flac/internal/hashutil/crc16"
|
||||
"github.com/mewkiz/flac/internal/hashutil/crc8"
|
||||
"github.com/mewkiz/flac/internal/utf8"
|
||||
"github.com/mewkiz/pkg/errutil"
|
||||
)
|
||||
|
||||
|
@ -200,12 +200,33 @@ func encodeFrameHeaderBlockSize(bw *bitio.Writer, blockSize uint16) (nblockSizeS
|
|||
case 192:
|
||||
// 0001
|
||||
bits = 0x1
|
||||
case 576, 1152, 2304, 4608:
|
||||
// 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608
|
||||
bits = 0x2 + uint64(blockSize/576) - 1
|
||||
case 256, 512, 1024, 2048, 4096, 8192, 16384, 32768:
|
||||
// 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768
|
||||
bits = 0x8 + uint64(blockSize/256) - 1
|
||||
|
||||
// 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608
|
||||
case 576:
|
||||
bits = 0x2
|
||||
case 1152:
|
||||
bits = 0x3
|
||||
case 2304:
|
||||
bits = 0x4
|
||||
case 4608:
|
||||
bits = 0x5
|
||||
// 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768
|
||||
case 256:
|
||||
bits = 0x8
|
||||
case 512:
|
||||
bits = 0x9
|
||||
case 1024:
|
||||
bits = 0xa
|
||||
case 2048:
|
||||
bits = 0xb
|
||||
case 4096:
|
||||
bits = 0xc
|
||||
case 8192:
|
||||
bits = 0xd
|
||||
case 16384:
|
||||
bits = 0xe
|
||||
case 32768:
|
||||
bits = 0xf
|
||||
default:
|
||||
if blockSize <= 256 {
|
||||
// 0110 : get 8 bit (blocksize-1) from end of header
|
||||
|
|
|
@ -5,9 +5,9 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/ioutilx"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/meta"
|
||||
"github.com/icza/bitio"
|
||||
"github.com/mewkiz/flac/internal/ioutilx"
|
||||
"github.com/mewkiz/flac/meta"
|
||||
"github.com/mewkiz/pkg/errutil"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package flac
|
||||
|
||||
import (
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/frame"
|
||||
iobits "git.gammaspectra.live/S.O.N.G/flacgo/internal/bits"
|
||||
"github.com/icza/bitio"
|
||||
"github.com/mewkiz/flac/frame"
|
||||
iobits "github.com/mewkiz/flac/internal/bits"
|
||||
"github.com/mewkiz/pkg/errutil"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/mewkiz/flac"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo"
|
||||
)
|
||||
|
||||
func ExampleParseFile() {
|
||||
|
|
10
flac.go
10
flac.go
|
@ -18,9 +18,9 @@
|
|||
// Please refer to the documentation of the meta [2] and the frame [3] packages
|
||||
// for a brief introduction of their respective formats.
|
||||
//
|
||||
// [1]: https://www.xiph.org/flac/format.html#stream
|
||||
// [2]: https://godoc.org/github.com/mewkiz/flac/meta
|
||||
// [3]: https://godoc.org/github.com/mewkiz/flac/frame
|
||||
// [1]: https://www.xiph.org/flac/format.html#stream
|
||||
// [2]: https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/meta
|
||||
// [3]: https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/frame
|
||||
//
|
||||
// Note: the Encoder API is experimental until the 1.1.x release. As such, it's
|
||||
// API is expected to change.
|
||||
|
@ -34,8 +34,8 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/mewkiz/flac/frame"
|
||||
"github.com/mewkiz/flac/meta"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/frame"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/meta"
|
||||
)
|
||||
|
||||
// A Stream contains the metadata blocks and provides access to the audio frames
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/mewkiz/flac"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo"
|
||||
)
|
||||
|
||||
func TestSkipID3v2(t *testing.T) {
|
||||
|
|
|
@ -10,19 +10,20 @@
|
|||
// of the channels and the difference between the channels, or store the average
|
||||
// of the channels and their difference. An encoder decorrelates audio samples
|
||||
// as follows:
|
||||
// mid = (left + right)/2 // average of the channels
|
||||
// side = left - right // difference between the channels
|
||||
//
|
||||
// mid = (left + right)/2 // average of the channels
|
||||
// side = left - right // difference between the channels
|
||||
//
|
||||
// The blocks are encoded using a variety of prediction methods [4][5] and
|
||||
// stored in frames. Blocks and subblocks contains unencoded audio samples while
|
||||
// frames and subframes contain encoded audio samples. A FLAC stream contains
|
||||
// one or more audio frames.
|
||||
//
|
||||
// [1]: https://www.xiph.org/flac/format.html#architecture
|
||||
// [2]: https://www.xiph.org/flac/format.html#blocking
|
||||
// [3]: https://www.xiph.org/flac/format.html#interchannel
|
||||
// [4]: https://www.xiph.org/flac/format.html#prediction
|
||||
// [5]: https://godoc.org/github.com/mewkiz/flac/frame#Pred
|
||||
// [1]: https://www.xiph.org/flac/format.html#architecture
|
||||
// [2]: https://www.xiph.org/flac/format.html#blocking
|
||||
// [3]: https://www.xiph.org/flac/format.html#interchannel
|
||||
// [4]: https://www.xiph.org/flac/format.html#prediction
|
||||
// [5]: https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/frame#Pred
|
||||
package frame
|
||||
|
||||
import (
|
||||
|
@ -33,11 +34,11 @@ import (
|
|||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/mewkiz/flac/internal/bits"
|
||||
"github.com/mewkiz/flac/internal/hashutil"
|
||||
"github.com/mewkiz/flac/internal/hashutil/crc16"
|
||||
"github.com/mewkiz/flac/internal/hashutil/crc8"
|
||||
"github.com/mewkiz/flac/internal/utf8"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/bits"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/hashutil"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/hashutil/crc16"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/hashutil/crc8"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/utf8"
|
||||
)
|
||||
|
||||
// A Frame contains the header and subframes of an audio frame. It holds the
|
||||
|
@ -531,18 +532,20 @@ func (frame *Frame) parseSampleRate(br *bits.Reader, sampleRate uint64) error {
|
|||
type Channels uint8
|
||||
|
||||
// Channel assignments. The following abbreviations are used:
|
||||
// C: center (directly in front)
|
||||
// R: right (standard stereo)
|
||||
// Sr: side right (directly to the right)
|
||||
// Rs: right surround (back right)
|
||||
// Cs: center surround (rear center)
|
||||
// Ls: left surround (back left)
|
||||
// Sl: side left (directly to the left)
|
||||
// L: left (standard stereo)
|
||||
// Lfe: low-frequency effect (placed according to room acoustics)
|
||||
//
|
||||
// C: center (directly in front)
|
||||
// R: right (standard stereo)
|
||||
// Sr: side right (directly to the right)
|
||||
// Rs: right surround (back right)
|
||||
// Cs: center surround (rear center)
|
||||
// Ls: left surround (back left)
|
||||
// Sl: side left (directly to the left)
|
||||
// L: left (standard stereo)
|
||||
// Lfe: low-frequency effect (placed according to room acoustics)
|
||||
//
|
||||
// The first 6 channel constants follow the SMPTE/ITU-R channel order:
|
||||
// L R C Lfe Ls Rs
|
||||
//
|
||||
// L R C Lfe Ls Rs
|
||||
const (
|
||||
ChannelsMono Channels = iota // 1 channel: mono.
|
||||
ChannelsLR // 2 channels: left, right.
|
||||
|
@ -582,8 +585,9 @@ func (channels Channels) Count() int {
|
|||
// subframes.
|
||||
//
|
||||
// An encoder decorrelates audio samples as follows:
|
||||
// mid = (left + right)/2
|
||||
// side = left - right
|
||||
//
|
||||
// mid = (left + right)/2
|
||||
// side = left - right
|
||||
func (frame *Frame) correlate() {
|
||||
switch frame.Channels {
|
||||
case ChannelsLeftSide:
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/mewkiz/flac"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo"
|
||||
)
|
||||
|
||||
var golden = []struct {
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/mewkiz/flac/internal/bits"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/bits"
|
||||
)
|
||||
|
||||
// A Subframe contains the encoded audio samples from one channel of an audio
|
||||
|
@ -237,11 +237,11 @@ func (subframe *Subframe) decodeVerbatim(br *bits.Reader, bps uint) error {
|
|||
// fixedCoeffs maps from prediction order to the LPC coefficients used in fixed
|
||||
// encoding.
|
||||
//
|
||||
// x_0[n] = 0
|
||||
// x_1[n] = x[n-1]
|
||||
// x_2[n] = 2*x[n-1] - x[n-2]
|
||||
// x_3[n] = 3*x[n-1] - 3*x[n-2] + x[n-3]
|
||||
// x_4[n] = 4*x[n-1] - 6*x[n-2] + 4*x[n-3] - x[n-4]
|
||||
// x_0[n] = 0
|
||||
// x_1[n] = x[n-1]
|
||||
// x_2[n] = 2*x[n-1] - x[n-2]
|
||||
// x_3[n] = 3*x[n-1] - 3*x[n-2] + x[n-3]
|
||||
// x_4[n] = 4*x[n-1] - 6*x[n-2] + 4*x[n-3] - x[n-4]
|
||||
var fixedCoeffs = [...][]int32{
|
||||
// ref: Section 2.2 of http://www.hpl.hp.com/techreports/1999/HPL-1999-144.pdf
|
||||
1: {1},
|
||||
|
|
14
go.mod
14
go.mod
|
@ -1,11 +1,13 @@
|
|||
module github.com/mewkiz/flac
|
||||
module git.gammaspectra.live/S.O.N.G/flacgo
|
||||
|
||||
go 1.14
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/go-audio/audio v1.0.0
|
||||
github.com/go-audio/wav v1.0.0
|
||||
github.com/icza/bitio v1.0.0
|
||||
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/go-audio/wav v1.1.0
|
||||
github.com/icza/bitio v1.1.0
|
||||
github.com/mewkiz/pkg v0.0.0-20211102230744-16a6ce8f1b77
|
||||
github.com/pkg/errors v0.9.1
|
||||
)
|
||||
|
||||
require github.com/go-audio/riff v1.0.0 // indirect
|
||||
|
|
16
go.sum
16
go.sum
|
@ -3,16 +3,18 @@ github.com/go-audio/audio v1.0.0 h1:zS9vebldgbQqktK4H0lUqWrG8P0NxCJVqcj7ZpNnwd4=
|
|||
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
|
||||
github.com/go-audio/riff v1.0.0 h1:d8iCGbDvox9BfLagY94fBynxSPHO80LmZCaOsmKxokA=
|
||||
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
|
||||
github.com/go-audio/wav v1.0.0 h1:WdSGLhtyud6bof6XHL28xKeCQRzCV06pOFo3LZsFdyE=
|
||||
github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE=
|
||||
github.com/icza/bitio v1.0.0 h1:squ/m1SHyFeCA6+6Gyol1AxV9nmPPlJFT8c2vKdj3U8=
|
||||
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
|
||||
github.com/go-audio/wav v1.1.0 h1:jQgLtbqBzY7G+BM8fXF7AHUk1uHUviWS4X39d5rsL2g=
|
||||
github.com/go-audio/wav v1.1.0/go.mod h1:mpe9qfwbScEbkd8uybLuIpTgHyrISw/OTuvjUW2iGtE=
|
||||
github.com/icza/bitio v1.1.0 h1:ysX4vtldjdi3Ygai5m1cWy4oLkhWTAi+SyO6HC8L9T0=
|
||||
github.com/icza/bitio v1.1.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
|
||||
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k=
|
||||
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
|
||||
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2 h1:EyTNMdePWaoWsRSGQnXiSoQu0r6RS1eA557AwJhlzHU=
|
||||
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/jszwec/csvutil v1.5.1/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
|
||||
github.com/mewkiz/pkg v0.0.0-20211102230744-16a6ce8f1b77 h1:DDyKVkTkrFmd9lR84QW3EIfkkoHlurlpgW+DYuAUJn8=
|
||||
github.com/mewkiz/pkg v0.0.0-20211102230744-16a6ce8f1b77/go.mod h1:J/rDzvIiwiVpv72OEP8aJFxLXjGpUdviIIeqJPLIctA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// http://www.ross.net/crc/download/crc_v3.txt for information.
|
||||
package crc16
|
||||
|
||||
import "github.com/mewkiz/flac/internal/hashutil"
|
||||
import "git.gammaspectra.live/S.O.N.G/flacgo/internal/hashutil"
|
||||
|
||||
// Size of a CRC-16 checksum in bytes.
|
||||
const Size = 2
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
// http://www.ross.net/crc/download/crc_v3.txt for information.
|
||||
package crc8
|
||||
|
||||
import "github.com/mewkiz/flac/internal/hashutil"
|
||||
import "git.gammaspectra.live/S.O.N.G/flacgo/internal/hashutil"
|
||||
|
||||
// Size of a CRC-8 checksum in bytes.
|
||||
const Size = 1
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/mewkiz/flac/internal/ioutilx"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/ioutilx"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -40,24 +40,24 @@ const (
|
|||
// ref: http://permalink.gmane.org/gmane.comp.audio.compression.flac.devel/3033
|
||||
//
|
||||
// Algorithm description:
|
||||
// - read one byte B0 from the stream
|
||||
// - if B0 = 0xxxxxxx then the read value is B0 -> end
|
||||
// - if B0 = 10xxxxxx, the encoding is invalid
|
||||
// - if B0 = 11xxxxxx, set L to the number of leading binary 1s minus 1:
|
||||
// B0 = 110xxxxx -> L = 1
|
||||
// B0 = 1110xxxx -> L = 2
|
||||
// B0 = 11110xxx -> L = 3
|
||||
// B0 = 111110xx -> L = 4
|
||||
// B0 = 1111110x -> L = 5
|
||||
// B0 = 11111110 -> L = 6
|
||||
// - assign the bits following the encoding (the x bits in the examples) to
|
||||
// a variable R with a magnitude of at least 36 bits
|
||||
// - loop from 1 to L
|
||||
// - left shift R 6 bits
|
||||
// - read B from the stream
|
||||
// - if B does not match 10xxxxxx, the encoding is invalid
|
||||
// - set R = R or <the lower 6 bits from B>
|
||||
// - the read value is R
|
||||
// - read one byte B0 from the stream
|
||||
// - if B0 = 0xxxxxxx then the read value is B0 -> end
|
||||
// - if B0 = 10xxxxxx, the encoding is invalid
|
||||
// - if B0 = 11xxxxxx, set L to the number of leading binary 1s minus 1:
|
||||
// B0 = 110xxxxx -> L = 1
|
||||
// B0 = 1110xxxx -> L = 2
|
||||
// B0 = 11110xxx -> L = 3
|
||||
// B0 = 111110xx -> L = 4
|
||||
// B0 = 1111110x -> L = 5
|
||||
// B0 = 11111110 -> L = 6
|
||||
// - assign the bits following the encoding (the x bits in the examples) to
|
||||
// a variable R with a magnitude of at least 36 bits
|
||||
// - loop from 1 to L
|
||||
// - left shift R 6 bits
|
||||
// - read B from the stream
|
||||
// - if B does not match 10xxxxxx, the encoding is invalid
|
||||
// - set R = R or <the lower 6 bits from B>
|
||||
// - the read value is R
|
||||
func Decode(r io.Reader) (x uint64, err error) {
|
||||
c0, err := ioutilx.ReadByte(r)
|
||||
if err != nil {
|
||||
|
|
|
@ -3,7 +3,7 @@ package utf8
|
|||
import (
|
||||
"io"
|
||||
|
||||
"github.com/mewkiz/flac/internal/ioutilx"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/ioutilx"
|
||||
"github.com/mewkiz/pkg/errutil"
|
||||
)
|
||||
|
||||
|
|
33
meta/meta.go
33
meta/meta.go
|
@ -8,23 +8,24 @@
|
|||
//
|
||||
// At the time of this writing, the FLAC metadata format defines seven different
|
||||
// metadata block types, namely:
|
||||
// * StreamInfo [2]
|
||||
// * Padding [3]
|
||||
// * Application [4]
|
||||
// * SeekTable [5]
|
||||
// * VorbisComment [6]
|
||||
// * CueSheet [7]
|
||||
// * Picture [8]
|
||||
// - StreamInfo [2]
|
||||
// - Padding [3]
|
||||
// - Application [4]
|
||||
// - SeekTable [5]
|
||||
// - VorbisComment [6]
|
||||
// - CueSheet [7]
|
||||
// - Picture [8]
|
||||
//
|
||||
// Please refer to their respective documentation for further information.
|
||||
//
|
||||
// [1]: https://www.xiph.org/flac/format.html#format_overview
|
||||
// [2]: https://godoc.org/github.com/mewkiz/flac/meta#StreamInfo
|
||||
// [3]: https://www.xiph.org/flac/format.html#metadata_block_padding
|
||||
// [4]: https://godoc.org/github.com/mewkiz/flac/meta#Application
|
||||
// [5]: https://godoc.org/github.com/mewkiz/flac/meta#SeekTable
|
||||
// [6]: https://godoc.org/github.com/mewkiz/flac/meta#VorbisComment
|
||||
// [7]: https://godoc.org/github.com/mewkiz/flac/meta#CueSheet
|
||||
// [8]: https://godoc.org/github.com/mewkiz/flac/meta#Picture
|
||||
// [1]: https://www.xiph.org/flac/format.html#format_overview
|
||||
// [2]: https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/meta#StreamInfo
|
||||
// [3]: https://www.xiph.org/flac/format.html#metadata_block_padding
|
||||
// [4]: https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/meta#Application
|
||||
// [5]: https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/meta#SeekTable
|
||||
// [6]: https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/meta#VorbisComment
|
||||
// [7]: https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/meta#CueSheet
|
||||
// [8]: https://godoc.org/git.gammaspectra.live/S.O.N.G/flacgo/meta#Picture
|
||||
package meta
|
||||
|
||||
import (
|
||||
|
@ -32,7 +33,7 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/mewkiz/flac/internal/bits"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/bits"
|
||||
)
|
||||
|
||||
// A Block contains the header and body of a metadata block.
|
||||
|
|
|
@ -6,8 +6,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/mewkiz/flac"
|
||||
"github.com/mewkiz/flac/meta"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/meta"
|
||||
)
|
||||
|
||||
var golden = []struct {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/mewkiz/flac/internal/bits"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/internal/bits"
|
||||
)
|
||||
|
||||
// StreamInfo contains the basic properties of a FLAC audio stream, such as its
|
||||
|
|
Loading…
Reference in a new issue