Showing preview only (349K chars total). Download the full file or copy to clipboard to get everything.
Repository: mewkiz/flac
Branch: master
Commit: f26319f6afb6
Files: 52
Total size: 332.0 KB
Directory structure:
gitextract_oegtlq8n/
├── .github/
│ └── workflows/
│ └── go.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── analysis_fixed.go
├── enc_benchmark_test.go
├── enc_test.go
├── encode.go
├── encode_frame.go
├── encode_meta.go
├── encode_subframe.go
├── example_test.go
├── flac.go
├── flac_test.go
├── frame/
│ ├── frame.go
│ ├── frame_test.go
│ └── subframe.go
├── go.mod
├── go.sum
├── internal/
│ ├── bits/
│ │ ├── reader.go
│ │ ├── reader_test.go
│ │ ├── twocomp.go
│ │ ├── twocomp_test.go
│ │ ├── unary.go
│ │ ├── unary_test.go
│ │ ├── zigzag.go
│ │ └── zigzag_test.go
│ ├── bufseekio/
│ │ ├── readseeker.go
│ │ └── readseeker_test.go
│ ├── hashutil/
│ │ ├── crc16/
│ │ │ ├── crc16.go
│ │ │ └── crc16_test.go
│ │ ├── crc8/
│ │ │ ├── crc8.go
│ │ │ └── crc8_test.go
│ │ └── hashutil.go
│ ├── ioutilx/
│ │ ├── byte.go
│ │ └── zero.go
│ └── utf8/
│ ├── decode.go
│ └── encode.go
├── meta/
│ ├── application.go
│ ├── cuesheet.go
│ ├── meta.go
│ ├── meta_test.go
│ ├── padding.go
│ ├── picture.go
│ ├── reader.go
│ ├── seektable.go
│ ├── streaminfo.go
│ ├── testdata/
│ │ └── README.md
│ └── vorbiscomment.go
└── testdata/
├── README.md
└── convert_to_verbatim.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/go.yml
================================================
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: Go
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['stable']
name: Build with Go ${{ matrix.go-version }}
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Install goveralls
if: ${{ matrix.go-version == 'stable' && github.ref == 'refs/heads/master' }}
run: go install github.com/mattn/goveralls@latest
- name: Build
run: go build -v ./...
- name: Test
run: go test -v -covermode atomic -coverprofile=covprofile ./...
- name: Gofmt
# Run gofmt, print the output and exit with status code 1 if it isn't empty.
run: |
OUTPUT=$(gofmt -d ./)
echo "$OUTPUT"
test -z "$OUTPUT"
- name: Send coverage
if: ${{ matrix.go-version == 'stable' && github.ref == 'refs/heads/master' }}
env:
COVERALLS_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
run: goveralls -coverprofile=covprofile -service=github
================================================
FILE: .gitignore
================================================
*.flac
*.wav
_resources_
================================================
FILE: .gitmodules
================================================
[submodule "flac-test-files"]
path = testdata/flac-test-files
url = https://github.com/ietf-wg-cellar/flac-test-files
================================================
FILE: LICENSE
================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
================================================
FILE: README.md
================================================
# flac
[](https://github.com/mewkiz/flac/actions/workflows/go.yml)
[](https://coveralls.io/github/mewkiz/flac?branch=master)
[](https://pkg.go.dev/github.com/mewkiz/flac)
This package provides access to [FLAC][1] (Free Lossless Audio Codec) streams.
[1]: http://flac.sourceforge.net/format.html
## Documentation
Documentation provided by GoDoc.
- [flac]: provides access to FLAC (Free Lossless Audio Codec) streams.
- [frame][flac/frame]: implements access to FLAC audio frames.
- [meta][flac/meta]: implements access to FLAC metadata blocks.
[flac]: http://pkg.go.dev/github.com/mewkiz/flac
[flac/frame]: http://pkg.go.dev/github.com/mewkiz/flac/frame
[flac/meta]: http://pkg.go.dev/github.com/mewkiz/flac/meta
## Changes
* Version 1.0.14 (TBA)
- Make parsing more robust against corrupt/malicious FLAC files (see [#77](https://github.com/mewkiz/flac/pull/77)). Thanks to [Alex Svetkin](https://github.com/whisk).
* Version 1.0.13 (2025-07-11)
- Add support for Fixed prediction encoding of FLAC subframes (see [#76](https://github.com/mewkiz/flac/pull/76)). Thanks to [Michael Braha](https://github.com/braheezy).
* Version 1.0.12 (2024-08-11)
- Improve performance of `flac.NewSeek()` by using a buffered reader (see [#72](https://github.com/mewkiz/flac/pull/72)).
- Fix off-by-one error in `Seek` end of stream check (see [#73](https://github.com/mewkiz/flac/pull/73)).
* Version 1.0.11 (2024-08-04)
- Move example tools to dedicated [mewkiz/flac-tools](https://github.com/mewkiz/flac-tools) repository to reduce external dependencies (see [#62](https://github.com/mewkiz/flac/pull/62)).
- Fix seek to frame start (see [#71](https://github.com/mewkiz/flac/pull/71)). Thanks to [Mark Kremer](https://github.com/MarkKremer).
- Simplify internal handling of `io.Closer` element in `flac.Stream` and `flac.Encoder` types (see [#70](https://github.com/mewkiz/flac/pull/70)). Thanks to [Mario Salgado](https://github.com/zalgonoise).
* Version 1.0.10 (2023-11-11)
- Add support for LPC audio sample encoding (see [#66](https://github.com/mewkiz/flac/pull/66)). Thanks to [Mark Kremer](https://github.com/MarkKremer) for bug fixes and [Mattias Wadman](https://github.com/wader) for the invaluable [fq](https://github.com/wader/fq) tool used to investigate FLAC encoding issues.
- Replace Travis CI with GitHub actions for CI build status, test status and code coverage [#64](https://github.com/mewkiz/flac/pull/64)). Thanks to [Mark Kremer](https://github.com/MarkKremer).
* Version 1.0.9 (2023-10-24)
- Fix integer overflow during unfolding of rice residual (see [#61](https://github.com/mewkiz/flac/pull/61)). Thanks to [Mark Kremer](https://github.com/MarkKremer).
- Fix decoding of escaped partition audio samples (see [#60](https://github.com/mewkiz/flac/issues/60)). Thanks to [Mark Kremer](https://github.com/MarkKremer).
- Handle frame hashing of audio samples with bits-per-sample not evenly divisible by 8 (see [9d50c9e](https://github.com/mewkiz/flac/commit/9d50c9ee99ba322f487ed60442dc16f22b2affb8)).
* Version 1.0.8 (2023-04-09)
- Fix race condition when reading meta data (see [#56](https://github.com/mewkiz/flac/pull/56)). Thanks to [Zach Orosz](https://github.com/zachorosz).
- Fix encoding of 8-bps WAV audio samples (see [#52](https://github.com/mewkiz/flac/pull/52)). Thanks to [Martijn van Beurden](https://github.com/ktmf01).
- Fix `StreamInfo` block type error message (see [#49](https://github.com/mewkiz/flac/pull/49)).
* 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).
* 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)).
- Use go.mod.
- Skip ID3v2 data prepended to flac files when parsing (see [36cc17e](https://github.com/mewkiz/flac/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)).
* 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)).
* 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)).
* 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).
* 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).
* 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).
- Add frame decoding test cases.
* Version 1.0.0 (2014-09-30)
- Initial release.
- Implement decoding of FLAC files.
================================================
FILE: analysis_fixed.go
================================================
package flac
import (
"github.com/mewkiz/flac/frame"
iobits "github.com/mewkiz/flac/internal/bits"
)
// analyzeFixed selects the best fixed predictor (order 0-4) for the given
// subframe and fills the fields required by the existing writer so that a
// compressed SUBFRAME_FIXED is emitted instead of a verbatim subframe.
//
// The algorithm is a very small subset of libFLAC's encoder analysis:
// 1. For each order 0..4 compute residuals using the fixed coefficients
// defined in frame.FixedCoeffs.
// 2. For those residuals, choose the Rice parameter k (0..14) that minimizes
// the encoded bit-length assuming partition order 0.
// 3. Pick the order with the overall fewest bits.
//
// Note: ignoring partition orders >0 and Rice2 for now.
func analyzeFixed(sf *frame.Subframe, bps uint) {
bestBits := int(^uint(0) >> 1) // max int
bestOrder := 0
bestK := uint(0)
// Try predictor orders 0 through 4.
for order := 0; order <= 4 && order < len(sf.Samples); order++ {
residuals := computeFixedResiduals(sf.Samples, order)
k := chooseRice(residuals)
bits := costFixed(order, bps, residuals, k)
if bits < bestBits {
bestBits = bits
bestOrder = order
bestK = k
}
}
// Populate subframe fields so the existing encode* routines can do their
// job. Warm-up samples are already present in sf.Samples.
sf.Pred = frame.PredFixed
sf.Order = bestOrder
sf.ResidualCodingMethod = frame.ResidualCodingMethodRice1
sf.RiceSubframe = &frame.RiceSubframe{
PartOrder: 0,
Partitions: []frame.RicePartition{{Param: bestK}},
}
// Note: We do NOT mutate sf.Samples. The encoder expects original samples
// because it recomputes residuals internally. The metadata we filled in is
// enough for encodeFixedSamples to reproduce the exact same residuals.
}
// computeFixedResiduals returns the residual signal for a given fixed predictor
// order. The returned slice has length len(samples)-order.
func computeFixedResiduals(samples []int32, order int) []int32 {
n := len(samples)
res := make([]int32, 0, n-order)
switch order {
case 0:
// x_0[n] = 0
for i := 0; i < n; i++ {
res = append(res, samples[i])
}
case 1:
// x_1[n] = x[n-1]
for i := 1; i < n; i++ {
predicted := samples[i-1]
res = append(res, samples[i]-predicted)
}
case 2:
// x_2[n] = 2*x[n-1] - x[n-2]
for i := 2; i < n; i++ {
predicted := 2*samples[i-1] - samples[i-2]
res = append(res, samples[i]-predicted)
}
case 3:
// x_3[n] = 3*x[n-1] - 3*x[n-2] + x[n-3]
for i := 3; i < n; i++ {
predicted := 3*samples[i-1] - 3*samples[i-2] + samples[i-3]
res = append(res, samples[i]-predicted)
}
case 4:
// x_4[n] = 4*x[n-1] - 6*x[n-2] + 4*x[n-3] - x[n-4]
for i := 4; i < n; i++ {
predicted := 4*samples[i-1] - 6*samples[i-2] + 4*samples[i-3] - samples[i-4]
res = append(res, samples[i]-predicted)
}
}
return res
}
// chooseRice returns the Rice parameter k (0..14) that minimizes the encoded
// length of residuals when using Rice coding with paramSize=4 (Rice1).
func chooseRice(residuals []int32) uint {
bestK := uint(0)
bestBits := int(^uint(0) >> 1)
for k := uint(0); k < 15; k++ { // 15 is escape code, so evaluate 0..14
bits := 0
for _, r := range residuals {
folded := iobits.EncodeZigZag(r)
quo := folded >> k
bits += int(quo) + 1 + int(k) // unary + stop bit + k LSBs
}
if bits < bestBits {
bestBits = bits
bestK = k
}
}
return bestK
}
// costFixed returns the number of bits needed to code the subframe with the
// given parameters. 6 bits for the subframe header are included so orders with
// more warm-up samples are fairly compared.
func costFixed(order int, bps uint, residuals []int32, k uint) int {
warmUpBits := order * int(bps)
// residual bits for chosen k
residBits := 0
for _, r := range residuals {
folded := iobits.EncodeZigZag(r)
quo := folded >> k
residBits += int(quo) + 1 + int(k)
}
// Subframe header is 6 bits + 1 wasted flag bit (always 0 here)
return 6 + warmUpBits + residBits
}
// analyzeSubframe decides on the best prediction method (constant, verbatim, or
// fixed) for a subframe that is currently marked PredVerbatim. It will update
// the Subframe fields to use the chosen method. The heuristic is simple: it
// picks the encoding that yields the fewest estimated bits when assuming a
// single Rice partition.
func analyzeSubframe(sf *frame.Subframe, bps uint) {
// Only analyze when the caller has not chosen a prediction method yet.
if sf.Pred != frame.PredVerbatim {
return
}
samples := sf.Samples
n := len(samples)
if n == 0 {
return
}
// Guard against degenerate inputs. If there are fewer than two samples we
// simply keep verbatim encoding.
if n < 2 {
return
}
// --- Constant predictor cost.
allEqual := true
for i := 1; i < n; i++ {
if samples[i] != samples[0] {
allEqual = false
break
}
}
constBits := int(^uint(0) >> 1) // max int
if allEqual {
// 6-bit header + one sample.
constBits = 6 + int(bps)
}
// --- Verbatim predictor cost.
verbatimBits := 6 + n*int(bps) // 6-bit header + raw samples
// --- Fixed predictor: reuse existing helper to find best order/k.
analyzeFixed(sf, bps) // fills Order, RiceSubframe, etc.
// Cost of that choice
fixedResiduals := computeFixedResiduals(samples, sf.Order)
fixedBits := costFixed(sf.Order, bps, fixedResiduals, sf.RiceSubframe.Partitions[0].Param)
// Choose the smallest.
switch {
case constBits < verbatimBits && constBits < fixedBits:
// Use constant encoding.
sf.Pred = frame.PredConstant
// No other metadata needed.
case fixedBits < verbatimBits:
// Keep fixed settings filled in by analyzeFixed.
sf.Pred = frame.PredFixed
default:
// Stick with verbatim – restore defaults that analyzeFixed may have
// overwritten.
sf.Pred = frame.PredVerbatim
sf.Order = 0
sf.RiceSubframe = nil
}
}
================================================
FILE: enc_benchmark_test.go
================================================
package flac
import (
"bytes"
"math"
"testing"
"github.com/mewkiz/flac/frame"
"github.com/mewkiz/flac/meta"
)
// BenchmarkEncodeSyntheticAudio measures the performance of encoding synthetic
// audio data. It creates a simple sine wave pattern to avoid dependency on
// external files.
func BenchmarkEncodeSyntheticAudio(b *testing.B) {
// Create synthetic audio data (1 second of 44.1kHz stereo audio)
const (
sampleRate = 44100
nchannels = 2
bitsPerSample = 16
nsamples = sampleRate
)
// Create StreamInfo
info := &meta.StreamInfo{
BlockSizeMin: 4096,
BlockSizeMax: 4096,
FrameSizeMin: 0,
FrameSizeMax: 0,
SampleRate: sampleRate,
NChannels: nchannels,
BitsPerSample: bitsPerSample,
NSamples: nsamples,
}
// Generate synthetic audio data (sine wave)
samples := make([]int32, nsamples*nchannels)
freq := 440.0 // A4 note
for i := 0; i < nsamples; i++ {
// Generate a sine wave
sample := int32(math.Sin(2*math.Pi*freq*float64(i)/float64(sampleRate)) * 32767)
// Fill both channels with the same data
samples[i*2] = sample
samples[i*2+1] = sample
}
// Reset the timer before the actual benchmark
b.ResetTimer()
// Run the benchmark
for range b.N {
// Create a buffer to write the encoded data
buf := &bytes.Buffer{}
// Create encoder
enc, err := NewEncoder(buf, info)
if err != nil {
b.Fatal(err)
}
// Process samples in blocks
for offset := 0; offset < nsamples; offset += 4096 {
blockSize := 4096
if offset+blockSize > nsamples {
blockSize = nsamples - offset
}
// Create frame
f := &frame.Frame{
Header: frame.Header{
HasFixedBlockSize: true,
BlockSize: uint16(blockSize),
SampleRate: sampleRate,
Channels: frame.ChannelsLR,
BitsPerSample: bitsPerSample,
},
}
// Create subframes
f.Subframes = make([]*frame.Subframe, nchannels)
for channel := 0; channel < nchannels; channel++ {
// Extract samples for this channel
channelSamples := make([]int32, blockSize)
for i := 0; i < blockSize; i++ {
channelSamples[i] = samples[(offset+i)*nchannels+channel]
}
// Create verbatim subframe since we're just testing encoding speed
f.Subframes[channel] = &frame.Subframe{
SubHeader: frame.SubHeader{
Pred: frame.PredVerbatim,
},
Samples: channelSamples,
NSamples: blockSize,
}
}
// Encode frame
if err := enc.WriteFrame(f); err != nil {
b.Fatal(err)
}
}
// Close encoder
if err := enc.Close(); err != nil {
b.Fatal(err)
}
}
}
================================================
FILE: enc_test.go
================================================
package flac_test
import (
"bytes"
"errors"
"io"
"io/ioutil"
"os"
"slices"
"testing"
"github.com/mewkiz/flac"
"github.com/mewkiz/flac/meta"
)
var paths = []string{
// metadata test cases.
"meta/testdata/input-SCPAP.flac",
"meta/testdata/input-SCVA.flac",
"meta/testdata/input-SCVPAP.flac",
"meta/testdata/input-VA.flac",
"meta/testdata/input-SCVAUP.flac", // empty metadata block (of type 0x7e)
"meta/testdata/input-SVAUP.flac", // empty metadata block (of type 0x7e)
"meta/testdata/silence.flac",
// flac test cases.
"testdata/19875.flac", // prediction method 3 (FIR)
"testdata/44127.flac", // prediction method 3 (FIR)
"testdata/59996.flac",
"testdata/80574.flac", // prediction method 3 (FIR)
"testdata/172960.flac",
"testdata/189983.flac",
"testdata/191885.flac",
"testdata/212768.flac",
"testdata/220014.flac", // prediction method 2 (Fixed)
"testdata/243749.flac", // prediction method 2 (Fixed)
"testdata/256529.flac",
"testdata/257344.flac", // prediction method 3 (FIR)
"testdata/8297-275156-0011.flac", // prediction method 3 (FIR)
"testdata/love.flac", // wasted bits
// test cases for prediction analysis.
//
// Run `testdata/convert_to_verbatim.sh` to generate these test files.
"testdata/19875_verbatim.flac", // verbatim
"testdata/44127_verbatim.flac", // verbatim
"testdata/59996_verbatim.flac", // verbatim
"testdata/80574_verbatim.flac", // verbatim
"testdata/172960_verbatim.flac", // verbatim
"testdata/189983_verbatim.flac", // verbatim
"testdata/191885_verbatim.flac", // verbatim
"testdata/212768_verbatim.flac", // verbatim
"testdata/220014_verbatim.flac", // verbatim
"testdata/243749_verbatim.flac", // verbatim
"testdata/256529_verbatim.flac", // verbatim
"testdata/257344_verbatim.flac", // verbatim
// IETF test cases.
"testdata/flac-test-files/subset/01 - blocksize 4096.flac",
"testdata/flac-test-files/subset/02 - blocksize 4608.flac",
"testdata/flac-test-files/subset/03 - blocksize 16.flac",
"testdata/flac-test-files/subset/04 - blocksize 192.flac",
"testdata/flac-test-files/subset/05 - blocksize 254.flac",
"testdata/flac-test-files/subset/06 - blocksize 512.flac",
"testdata/flac-test-files/subset/07 - blocksize 725.flac",
"testdata/flac-test-files/subset/08 - blocksize 1000.flac",
"testdata/flac-test-files/subset/09 - blocksize 1937.flac",
"testdata/flac-test-files/subset/10 - blocksize 2304.flac",
"testdata/flac-test-files/subset/11 - partition order 8.flac",
"testdata/flac-test-files/subset/12 - qlp precision 15 bit.flac",
"testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac",
"testdata/flac-test-files/subset/14 - wasted bits.flac",
"testdata/flac-test-files/subset/15 - only verbatim subframes.flac",
"testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac",
"testdata/flac-test-files/subset/17 - all fixed orders.flac",
"testdata/flac-test-files/subset/18 - precision search.flac",
"testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac",
"testdata/flac-test-files/subset/20 - samplerate 39kHz.flac",
"testdata/flac-test-files/subset/21 - samplerate 22050Hz.flac",
"testdata/flac-test-files/subset/22 - 12 bit per sample.flac",
"testdata/flac-test-files/subset/23 - 8 bit per sample.flac",
"testdata/flac-test-files/subset/24 - variable blocksize file created with flake revision 264.flac",
"testdata/flac-test-files/subset/25 - variable blocksize file created with flake revision 264, modified to create smaller blocks.flac",
// NOTE: the only diff is that "26 - ...flac" uses `block_size: 0b111
// (end of header (16 bit))` to encode the block size at the end of the
// header, whereas mewkiz/flac encodes it directly `block_size: 4096
// (0b1100)`. Notably, the computed md5 hash of the decoded audio samples
// is identical (MD5: 3b2939b39ae7369b80451c77865e60c1). Thus, ignore the
// test case.
//"testdata/flac-test-files/subset/26 - variable blocksize file created with CUETools.Flake 2.1.6.flac",
// NOTE: the only diff is that "27 - ...flac" uses `block_size: 0b111
// (end of header (16 bit))` to encode the block size at the end of the
// header, whereas mewkiz/flac encodes it directly `block_size: 4608
// (0b101)`. Notably, the computed md5 hash of the decoded audio samples
// is identical (MD5: 9fb66177d2f735d4b1f501a5af1320a3). Thus, ignore the
// test case.
//"testdata/flac-test-files/subset/27 - old format variable blocksize file created with Flake 0.11.flac",
"testdata/flac-test-files/subset/28 - high resolution audio, default settings.flac",
"testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac",
"testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac",
"testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac",
"testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac",
"testdata/flac-test-files/subset/33 - samplerate 192kHz.flac",
// NOTE: the only diff is that "34 - ...flac" uses `0b1100 (end of header
// (8 bit*1000))` to encode the sample rate at the end of the header,
// whereas mewkiz/flac encodes it directly `192000 (0b11)`. Notably, the
// computed md5 hash of the decoded audio samples is identical
// (MD5: 942f56e503437dfd4c269c331774b2e3). Thus, ignore the test case.
//"testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac",
"testdata/flac-test-files/subset/35 - samplerate 134560Hz.flac",
"testdata/flac-test-files/subset/36 - samplerate 384kHz.flac",
"testdata/flac-test-files/subset/37 - 20 bit per sample.flac",
"testdata/flac-test-files/subset/38 - 3 channels (3.0).flac",
"testdata/flac-test-files/subset/39 - 4 channels (4.0).flac",
"testdata/flac-test-files/subset/40 - 5 channels (5.0).flac",
"testdata/flac-test-files/subset/41 - 6 channels (5.1).flac",
"testdata/flac-test-files/subset/42 - 7 channels (6.1).flac",
"testdata/flac-test-files/subset/43 - 8 channels (7.1).flac",
// NOTE: the only diff is that "44 - ...flac" uses `0b1100 (end of header
// (8 bit*1000))` to encode the sample rate at the end of the header,
// whereas mewkiz/flac encodes it directly `192000 (0b11)`. Notably, the
// computed md5 hash of the decoded audio samples is identical
// (MD5: cdf531d4d4b95233986bc499518a89db). Thus, ignore the test case.
//"testdata/flac-test-files/subset/44 - 8-channel surround, 192kHz, 24 bit, using only 32nd order predictors.flac",
"testdata/flac-test-files/subset/45 - no total number of samples set.flac",
"testdata/flac-test-files/subset/46 - no min-max framesize set.flac",
"testdata/flac-test-files/subset/47 - only STREAMINFO.flac",
"testdata/flac-test-files/subset/48 - Extremely large SEEKTABLE.flac",
"testdata/flac-test-files/subset/49 - Extremely large PADDING.flac",
"testdata/flac-test-files/subset/50 - Extremely large PICTURE.flac",
"testdata/flac-test-files/subset/51 - Extremely large VORBISCOMMENT.flac",
"testdata/flac-test-files/subset/52 - Extremely large APPLICATION.flac",
"testdata/flac-test-files/subset/53 - CUESHEET with very many indexes.flac",
"testdata/flac-test-files/subset/54 - 1000x repeating VORBISCOMMENT.flac",
"testdata/flac-test-files/subset/55 - file 48-53 combined.flac",
"testdata/flac-test-files/subset/56 - JPG PICTURE.flac",
"testdata/flac-test-files/subset/57 - PNG PICTURE.flac",
"testdata/flac-test-files/subset/58 - GIF PICTURE.flac",
"testdata/flac-test-files/subset/59 - AVIF PICTURE.flac",
"testdata/flac-test-files/subset/60 - mono audio.flac",
"testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac",
"testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac",
"testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac",
"testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac",
}
func TestEncodeRoundTrip(t *testing.T) {
for _, path := range paths {
t.Run(path, func(t *testing.T) {
if !exists(path) {
t.Skipf("path %q does not exist", path)
}
// Decode source file.
stream, err := flac.ParseFile(path)
if err != nil {
t.Fatalf("%q: unable to parse FLAC file; %v", path, err)
}
defer stream.Close()
// Open encoder for FLAC stream.
out := new(bytes.Buffer)
enc, err := flac.NewEncoder(out, stream.Info, stream.Blocks...)
if err != nil {
t.Fatalf("%q: unable to create encoder for FLAC stream; %v", path, err)
}
enc.EnablePredictionAnalysis(false) // disable prediction analysis to support round-trip decode/encode test.
// Encode audio samples.
for {
frame, err := stream.ParseNext()
if err != nil {
if err == io.EOF {
break
}
t.Fatalf("%q: unable to parse audio frame of FLAC stream; %v", path, err)
}
if err := enc.WriteFrame(frame); err != nil {
t.Fatalf("%q: unable to encode audio frame of FLAC stream; %v", path, err)
}
}
// Close encoder and flush pending writes.
if err := enc.Close(); err != nil {
t.Fatalf("%q: unable to close encoder for FLAC stream; %v", path, err)
}
// Compare source and destination FLAC streams.
want, err := ioutil.ReadFile(path)
if err != nil {
t.Fatalf("%q: unable to read file; %v", path, err)
}
got := out.Bytes()
if !bytes.Equal(got, want) {
t.Fatalf("%q: content mismatch; expected % X, got % X", path, want, got)
}
})
}
}
func TestEncodeComment(t *testing.T) {
// Decode FLAC file.
const path = "meta/testdata/input-VA.flac"
src, err := flac.ParseFile(path)
if err != nil {
t.Fatalf("unable to parse input FLAC file; %v", err)
}
defer src.Close()
// Add custom vorbis comment.
const want = "FLAC encoding test case"
for _, block := range src.Blocks {
if comment, ok := block.Body.(*meta.VorbisComment); ok {
comment.Vendor = want
}
}
// Open encoder for FLAC stream.
out := new(bytes.Buffer)
enc, err := flac.NewEncoder(out, src.Info, src.Blocks...)
if err != nil {
t.Fatalf("%q: unable to create encoder for FLAC stream; %v", path, err)
}
// Encode audio samples.
for {
frame, err := src.ParseNext()
if err != nil {
if err == io.EOF {
break
}
t.Fatalf("%q: unable to parse audio frame of FLAC stream; %v", path, err)
}
if err := enc.WriteFrame(frame); err != nil {
t.Fatalf("%q: unable to encode audio frame of FLAC stream; %v", path, err)
}
}
// Close encoder and flush pending writes.
if err := enc.Close(); err != nil {
t.Fatalf("%q: unable to close encoder for FLAC stream; %v", path, err)
}
// Parse encoded FLAC file.
stream, err := flac.Parse(out)
if err != nil {
t.Fatalf("unable to parse output FLAC file; %v", err)
}
defer stream.Close()
// Add custom vorbis comment.
for _, block := range stream.Blocks {
if comment, ok := block.Body.(*meta.VorbisComment); ok {
got := comment.Vendor
if got != want {
t.Errorf("Vorbis comment mismatch; expected %q, got %q", want, got)
continue
}
}
}
}
func TestEncodeAnalysisFixed(t *testing.T) {
for _, path := range paths {
t.Run(path, func(t *testing.T) {
if !exists(path) {
t.Skipf("path %q does not exist", path)
}
// Decode source file.
stream, err := flac.ParseFile(path)
if err != nil {
t.Fatalf("%q: unable to parse FLAC file; %v", path, err)
}
defer stream.Close()
// Open encoder for FLAC stream.
out := new(bytes.Buffer)
enc, err := flac.NewEncoder(out, stream.Info, stream.Blocks...)
if err != nil {
t.Fatalf("%q: unable to create encoder for FLAC stream; %v", path, err)
}
enc.EnablePredictionAnalysis(true) // enable prediction encoding
// Encode audio samples.
for {
frame, err := stream.ParseNext()
if err != nil {
if err == io.EOF {
break
}
t.Fatalf("%q: unable to parse audio frame of FLAC stream; %v", path, err)
}
if err := enc.WriteFrame(frame); err != nil {
t.Fatalf("%q: unable to encode audio frame of FLAC stream; %v", path, err)
}
}
// Close encoder and flush pending writes.
if err := enc.Close(); err != nil {
t.Fatalf("%q: unable to close encoder for FLAC stream; %v", path, err)
}
// Compare source and destination FLAC streams.
wantStream, err := flac.ParseFile(path)
if err != nil {
t.Fatalf("%q: unable to parse FLAC file; %v", path, err)
}
wantSamples, err := getSamples(wantStream)
if err != nil {
t.Fatalf("%q: unable to get audio samples of FLAC file; %v", path, err)
}
if err := wantStream.Close(); err != nil {
t.Fatalf("%q: unable to close FLAC stream; %v", path, err)
}
fi, err := os.Stat(path)
if err != nil {
t.Fatalf("%q: unable to stat FLAC file; %v", path, err)
}
wantSize := fi.Size()
gotBytes := out.Bytes()
gotSize := int64(len(gotBytes))
gotStream, err := flac.Parse(bytes.NewReader(gotBytes))
if err != nil {
t.Fatalf("%q: unable to parse encoded FLAC file; %v", path, err)
}
gotSamples, err := getSamples(gotStream)
if err != nil {
t.Fatalf("%q: unable to get audio samples of encoded FLAC file; %v", path, err)
}
if err := gotStream.Close(); err != nil {
t.Fatalf("%q: unable to close encoded FLAC stream; %v", path, err)
}
if !slices.Equal(wantSamples, gotSamples) {
t.Fatalf("%q: content mismatch; expected %#v, got %#v", path, wantSamples, gotSamples)
}
percent := 100 * float64(gotSize) / float64(wantSize)
if wantSize != gotSize {
t.Logf("%q: input size: %d, output size: %d. ratio: %.02f%%", path, wantSize, gotSize, percent)
}
})
}
}
// getSamples returns all audio samples in stream.
func getSamples(stream *flac.Stream) ([]int32, error) {
var out []int32
for {
frame, err := stream.ParseNext()
if err != nil {
if err == io.EOF {
break
}
return nil, errors.New("unable to parse audio frame of FLAC stream")
}
for _, subframe := range frame.Subframes {
out = append(out, subframe.Samples...)
}
}
return out, nil
}
// exists reports whether the given file or directory exists.
func exists(path string) bool {
_, err := os.Stat(path)
return err == nil
}
================================================
FILE: encode.go
================================================
package flac
import (
"crypto/md5"
"hash"
"io"
"github.com/icza/bitio"
"github.com/mewkiz/flac/meta"
"github.com/mewkiz/pkg/errutil"
)
// An Encoder represents a FLAC encoder.
type Encoder struct {
// FLAC stream of encoder.
*Stream
// Underlying io.Writer or io.WriteCloser to the output stream.
w io.Writer
// Minimum and maximum block size (in samples) of frames written by encoder.
blockSizeMin, blockSizeMax uint16
// Minimum and maximum frame size (in bytes) of frames written by encoder.
frameSizeMin, frameSizeMax uint32
// MD5 running hash of unencoded audio samples.
md5sum hash.Hash
// Total number of samples (per channel) written by encoder.
nsamples uint64
// Current frame number if block size is fixed, and the first sample number
// of the current frame otherwise.
curNum uint64
// AnalysisEnabled indicates whether analysis is enabled for the encoder.
AnalysisEnabled bool
}
// NewEncoder returns a new FLAC encoder for the given metadata StreamInfo block
// and optional metadata blocks.
//
// By default prediction analysis is enabled. For more information, see
// Encoder.EnablePredictionAnalysis.
func NewEncoder(w io.Writer, info *meta.StreamInfo, blocks ...*meta.Block) (*Encoder, error) {
// Store FLAC signature.
enc := &Encoder{
Stream: &Stream{
Info: info,
Blocks: blocks,
},
w: w,
md5sum: md5.New(),
AnalysisEnabled: true, // enable prediction analysis by default.
}
bw := bitio.NewWriter(w)
if _, err := bw.Write(flacSignature); err != nil {
return nil, errutil.Err(err)
}
// Encode metadata blocks.
// TODO: consider using bufio.NewWriter.
if err := encodeStreamInfo(bw, info, len(blocks) == 0); err != nil {
return nil, errutil.Err(err)
}
for i, block := range blocks {
if err := encodeBlock(bw, block, i == len(blocks)-1); err != nil {
return nil, errutil.Err(err)
}
}
// Flush pending writes of metadata blocks.
if _, err := bw.Align(); err != nil {
return nil, errutil.Err(err)
}
// Return encoder to be used for encoding audio samples.
return enc, nil
}
// Close closes the underlying io.Writer of the encoder and flushes any pending
// writes. If the io.Writer implements io.Seeker, the encoder will update the
// StreamInfo metadata block with the MD5 checksum of the unencoded audio
// samples, the number of samples, and the minimum and maximum frame size and
// block size.
func (enc *Encoder) Close() error {
// TODO: check if bit writer should be flushed before seeking on enc.w.
// Update StreamInfo metadata block.
if ws, ok := enc.w.(io.WriteSeeker); ok {
if _, err := ws.Seek(int64(len(flacSignature)), io.SeekStart); err != nil {
return errutil.Err(err)
}
// Update minimum and maximum block size (in samples) of FLAC stream.
enc.Info.BlockSizeMin = enc.blockSizeMin
enc.Info.BlockSizeMax = enc.blockSizeMax
// Update minimum and maximum frame size (in bytes) of FLAC stream.
enc.Info.FrameSizeMin = enc.frameSizeMin
enc.Info.FrameSizeMax = enc.frameSizeMax
// Update total number of samples (per channel) of FLAC stream.
enc.Info.NSamples = enc.nsamples
// Update MD5 checksum of the unencoded audio samples.
sum := enc.md5sum.Sum(nil)
for i := range sum {
enc.Info.MD5sum[i] = sum[i]
}
bw := bitio.NewWriter(ws)
// Write updated StreamInfo metadata block to output stream.
if err := encodeStreamInfo(bw, enc.Info, len(enc.Blocks) == 0); err != nil {
return errutil.Err(err)
}
if _, err := bw.Align(); err != nil {
return errutil.Err(err)
}
}
if closer, ok := enc.w.(io.Closer); ok {
return closer.Close()
}
return nil
}
// EnablePredictionAnalysis specifies whether to enable analysis for the
// encoder. When analysis is enabled, subframes that are currently marked as
// PredVerbatim will be analyzed to use the best prediction method
// (constant, fixed or verbatim) based on size.
func (enc *Encoder) EnablePredictionAnalysis(enable bool) {
enc.AnalysisEnabled = enable
}
================================================
FILE: encode_frame.go
================================================
package flac
import (
"encoding/binary"
"io"
"math"
"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"
)
// --- [ Frame ] ---------------------------------------------------------------
// WriteFrame encodes the given audio frame to the output stream. The Num field
// of the frame header is automatically calculated by the encoder.
func (enc *Encoder) WriteFrame(f *frame.Frame) error {
// Sanity checks.
nchannels := int(enc.Info.NChannels)
if nchannels != len(f.Subframes) {
return errutil.Newf("subframe and channel count mismatch; expected %d, got %d", nchannels, len(f.Subframes))
}
nsamplesPerChannel := f.Subframes[0].NSamples
for i, subframe := range f.Subframes {
if nsamplesPerChannel != len(subframe.Samples) {
return errutil.Newf("invalid number of samples in channel %d; expected %d, got %d", i, nsamplesPerChannel, len(subframe.Samples))
}
}
if nchannels != f.Channels.Count() {
return errutil.Newf("channel count mismatch; expected %d, got %d", nchannels, f.Channels.Count())
}
// Create a new CRC-16 hash writer which adds the data from all write
// operations to a running hash.
h := crc16.NewIBM()
hw := io.MultiWriter(h, enc.w)
// Encode frame header.
f.Num = enc.curNum
if f.HasFixedBlockSize {
enc.curNum++
} else {
enc.curNum += uint64(nsamplesPerChannel)
}
enc.nsamples += uint64(nsamplesPerChannel)
blockSize := uint16(nsamplesPerChannel)
if enc.blockSizeMin == 0 || blockSize < enc.blockSizeMin {
enc.blockSizeMin = blockSize
}
if enc.blockSizeMax == 0 || blockSize > enc.blockSizeMax {
enc.blockSizeMax = blockSize
}
// TODO: track number of bytes written to hw, to update values of
// frameSizeMin and frameSizeMax.
// Add unencoded audio samples to running MD5 hash.
f.Hash(enc.md5sum)
if err := enc.encodeFrameHeader(hw, f.Header); err != nil {
return errutil.Err(err)
}
// Inter-channel decorrelation of subframe samples.
f.Decorrelate()
defer f.Correlate() // NOTE: revert decorrelation of audio samples after encoding is done (to make encode non-destructive).
// Encode subframes.
bw := bitio.NewWriter(hw)
for channel, subframe := range f.Subframes {
// The side channel requires an extra bit per sample when using
// inter-channel decorrelation.
bps := uint(f.BitsPerSample)
switch f.Channels {
case frame.ChannelsSideRight:
// channel 0 is the side channel.
if channel == 0 {
bps++
}
case frame.ChannelsLeftSide, frame.ChannelsMidSide:
// channel 1 is the side channel.
if channel == 1 {
bps++
}
}
// optional prediction analysis
//
// (leave subframe as-is if AnalysisEnabled is false)
if enc.AnalysisEnabled {
switch subframe.Pred {
case frame.PredVerbatim:
analyzeSubframe(subframe, bps)
}
}
if err := encodeSubframe(bw, f.Header, subframe, bps); err != nil {
return errutil.Err(err)
}
}
// Zero-padding to byte alignment.
// Flush pending writes to subframe.
if _, err := bw.Align(); err != nil {
return errutil.Err(err)
}
// CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with 0) of
// everything before the crc, back to and including the frame header sync
// code.
crc := h.Sum16()
if err := binary.Write(enc.w, binary.BigEndian, crc); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ Frame header ] --------------------------------------------------------
// encodeFrameHeader encodes the given frame header, writing to w.
func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error {
// Create a new CRC-8 hash writer which adds the data from all write
// operations to a running hash.
h := crc8.NewATM()
hw := io.MultiWriter(h, w)
bw := bitio.NewWriter(hw)
// Closing the *bitio.Writer will not close the underlying writer
defer bw.Close()
// Sync code: 11111111111110
if err := bw.WriteBits(0x3FFE, 14); err != nil {
return errutil.Err(err)
}
// Reserved: 0
if err := bw.WriteBits(0x0, 1); err != nil {
return errutil.Err(err)
}
// Blocking strategy:
// 0 : fixed-blocksize stream; frame header encodes the frame number
// 1 : variable-blocksize stream; frame header encodes the sample number
if err := bw.WriteBool(!hdr.HasFixedBlockSize); err != nil {
return errutil.Err(err)
}
// Encode block size.
nblockSizeSuffixBits, err := encodeFrameHeaderBlockSize(bw, hdr.BlockSize)
if err != nil {
return errutil.Err(err)
}
// Encode sample rate.
sampleRateSuffixBits, nsampleRateSuffixBits, err := encodeFrameHeaderSampleRate(bw, hdr.SampleRate)
if err != nil {
return errutil.Err(err)
}
// Encode channels assignment.
if err := encodeFrameHeaderChannels(bw, hdr.Channels); err != nil {
return errutil.Err(err)
}
// Encode bits-per-sample.
if err := encodeFrameHeaderBitsPerSample(bw, hdr.BitsPerSample); err != nil {
return errutil.Err(err)
}
// Reserved: 0
if err := bw.WriteBits(0x0, 1); err != nil {
return errutil.Err(err)
}
// if (variable blocksize)
// <8-56>:"UTF-8" coded sample number (decoded number is 36 bits)
// else
// <8-48>:"UTF-8" coded frame number (decoded number is 31 bits)
if err := utf8.Encode(bw, hdr.Num); err != nil {
return errutil.Err(err)
}
// Write block size after the frame header (used for uncommon block sizes).
if nblockSizeSuffixBits > 0 {
// 0110 : get 8 bit (blocksize-1) from end of header
// 0111 : get 16 bit (blocksize-1) from end of header
if err := bw.WriteBits(uint64(hdr.BlockSize-1), nblockSizeSuffixBits); err != nil {
return errutil.Err(err)
}
}
// Write sample rate after the frame header (used for uncommon sample rates).
if nsampleRateSuffixBits > 0 {
if err := bw.WriteBits(sampleRateSuffixBits, nsampleRateSuffixBits); err != nil {
return errutil.Err(err)
}
}
// Flush pending writes to frame header.
if _, err := bw.Align(); err != nil {
return errutil.Err(err)
}
// CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) of
// everything before the crc, including the sync code.
crc := h.Sum8()
if err := binary.Write(w, binary.BigEndian, crc); err != nil {
return errutil.Err(err)
}
return nil
}
// ~~~ [ Block size ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// encodeFrameHeaderBlockSize encodes the block size of the frame header,
// writing to bw. It returns the number of bits used to store block size after
// the frame header.
func encodeFrameHeaderBlockSize(bw *bitio.Writer, blockSize uint16) (nblockSizeSuffixBits byte, err error) {
// Block size in inter-channel samples:
// 0000 : reserved
// 0001 : 192 samples
// 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608
// 0110 : get 8 bit (blocksize-1) from end of header
// 0111 : get 16 bit (blocksize-1) from end of header
// 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768
var bits uint64
switch blockSize {
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(math.Log2(float64(blockSize/576)))
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(math.Log2(float64(blockSize/256)))
default:
if blockSize <= 256 {
// 0110 : get 8 bit (blocksize-1) from end of header
bits = 0x6
nblockSizeSuffixBits = 8
} else {
// 0111 : get 16 bit (blocksize-1) from end of header
bits = 0x7
nblockSizeSuffixBits = 16
}
}
if err := bw.WriteBits(bits, 4); err != nil {
return 0, errutil.Err(err)
}
return nblockSizeSuffixBits, nil
}
// ~~~ [ Sample rate ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// encodeFrameHeaderSampleRate encodes the sample rate of the frame header,
// writing to bw. It returns the bits and the number of bits used to store
// sample rate after the frame header.
func encodeFrameHeaderSampleRate(bw *bitio.Writer, sampleRate uint32) (sampleRateSuffixBits uint64, nsampleRateSuffixBits byte, err error) {
// Sample rate:
// 0000 : get from STREAMINFO metadata block
// 0001 : 88.2kHz
// 0010 : 176.4kHz
// 0011 : 192kHz
// 0100 : 8kHz
// 0101 : 16kHz
// 0110 : 22.05kHz
// 0111 : 24kHz
// 1000 : 32kHz
// 1001 : 44.1kHz
// 1010 : 48kHz
// 1011 : 96kHz
// 1100 : get 8 bit sample rate (in kHz) from end of header
// 1101 : get 16 bit sample rate (in Hz) from end of header
// 1110 : get 16 bit sample rate (in tens of Hz) from end of header
// 1111 : invalid, to prevent sync-fooling string of 1s
var bits uint64
switch sampleRate {
case 0:
// 0000 : get from STREAMINFO metadata block
bits = 0
case 88200:
// 0001 : 88.2kHz
bits = 0x1
case 176400:
// 0010 : 176.4kHz
bits = 0x2
case 192000:
// 0011 : 192kHz
bits = 0x3
case 8000:
// 0100 : 8kHz
bits = 0x4
case 16000:
// 0101 : 16kHz
bits = 0x5
case 22050:
// 0110 : 22.05kHz
bits = 0x6
case 24000:
// 0111 : 24kHz
bits = 0x7
case 32000:
// 1000 : 32kHz
bits = 0x8
case 44100:
// 1001 : 44.1kHz
bits = 0x9
case 48000:
// 1010 : 48kHz
bits = 0xA
case 96000:
// 1011 : 96kHz
bits = 0xB
default:
switch {
case sampleRate <= 255000 && sampleRate%1000 == 0:
// 1100 : get 8 bit sample rate (in kHz) from end of header
bits = 0xC
sampleRateSuffixBits = uint64(sampleRate / 1000)
nsampleRateSuffixBits = 8
case sampleRate <= 65535:
// 1101 : get 16 bit sample rate (in Hz) from end of header
bits = 0xD
sampleRateSuffixBits = uint64(sampleRate)
nsampleRateSuffixBits = 16
case sampleRate <= 655350 && sampleRate%10 == 0:
// 1110 : get 16 bit sample rate (in tens of Hz) from end of header
bits = 0xE
sampleRateSuffixBits = uint64(sampleRate / 10)
nsampleRateSuffixBits = 16
default:
return 0, 0, errutil.Newf("unable to encode sample rate %v", sampleRate)
}
}
if err := bw.WriteBits(bits, 4); err != nil {
return 0, 0, errutil.Err(err)
}
return sampleRateSuffixBits, nsampleRateSuffixBits, nil
}
// ~~~ [ Channels assignment ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// encodeFrameHeaderChannels encodes the channels assignment of the frame
// header, writing to bw.
func encodeFrameHeaderChannels(bw *bitio.Writer, channels frame.Channels) error {
// Channel assignment.
// 0000-0111 : (number of independent channels)-1. Where defined, the channel order follows SMPTE/ITU-R recommendations. The assignments are as follows:
// 1 channel: mono
// 2 channels: left, right
// 3 channels: left, right, center
// 4 channels: front left, front right, back left, back right
// 5 channels: front left, front right, front center, back/surround left, back/surround right
// 6 channels: front left, front right, front center, LFE, back/surround left, back/surround right
// 7 channels: front left, front right, front center, LFE, back center, side left, side right
// 8 channels: front left, front right, front center, LFE, back left, back right, side left, side right
// 1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel
// 1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel
// 1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel
// 1011-1111 : reserved
var bits uint64
switch channels {
case frame.ChannelsMono, frame.ChannelsLR, frame.ChannelsLRC, frame.ChannelsLRLsRs, frame.ChannelsLRCLsRs, frame.ChannelsLRCLfeLsRs, frame.ChannelsLRCLfeCsSlSr, frame.ChannelsLRCLfeLsRsSlSr:
// 1 channel: mono.
// 2 channels: left, right.
// 3 channels: left, right, center.
// 4 channels: left, right, left surround, right surround.
// 5 channels: left, right, center, left surround, right surround.
// 6 channels: left, right, center, LFE, left surround, right surround.
// 7 channels: left, right, center, LFE, center surround, side left, side right.
// 8 channels: left, right, center, LFE, left surround, right surround, side left, side right.
bits = uint64(channels.Count() - 1)
case frame.ChannelsLeftSide:
// 2 channels: left, side; using inter-channel decorrelation.
// 1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel
bits = 0x8
case frame.ChannelsSideRight:
// 2 channels: side, right; using inter-channel decorrelation.
// 1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel
bits = 0x9
case frame.ChannelsMidSide:
// 2 channels: mid, side; using inter-channel decorrelation.
// 1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel
bits = 0xA
default:
return errutil.Newf("support for channel assignment %v not yet implemented", channels)
}
if err := bw.WriteBits(bits, 4); err != nil {
return errutil.Err(err)
}
return nil
}
// ~~~ [ Bits-per-sample ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// encodeFrameHeaderBitsPerSample encodes the bits-per-sample of the frame
// header, writing to bw.
func encodeFrameHeaderBitsPerSample(bw *bitio.Writer, bps uint8) error {
// Sample size in bits:
// 000 : get from STREAMINFO metadata block
// 001 : 8 bits per sample
// 010 : 12 bits per sample
// 011 : reserved
// 100 : 16 bits per sample
// 101 : 20 bits per sample
// 110 : 24 bits per sample
// 111 : reserved
var bits uint64
switch bps {
case 0:
// 000 : get from STREAMINFO metadata block
bits = 0x0
case 8:
// 001 : 8 bits per sample
bits = 0x1
case 12:
// 010 : 12 bits per sample
bits = 0x2
case 16:
// 100 : 16 bits per sample
bits = 0x4
case 20:
// 101 : 20 bits per sample
bits = 0x5
case 24:
// 110 : 24 bits per sample
bits = 0x6
default:
return errutil.Newf("support for sample size %v not yet implemented", bps)
}
if err := bw.WriteBits(bits, 3); err != nil {
return errutil.Err(err)
}
return nil
}
================================================
FILE: encode_meta.go
================================================
package flac
import (
"encoding/binary"
"fmt"
"io"
"github.com/icza/bitio"
"github.com/mewkiz/flac/internal/ioutilx"
"github.com/mewkiz/flac/meta"
"github.com/mewkiz/pkg/errutil"
)
// --- [ Metadata block ] ------------------------------------------------------
// encodeBlock encodes the metadata block, writing to bw.
func encodeBlock(bw *bitio.Writer, block *meta.Block, last bool) error {
if block.Type == meta.TypePadding {
return encodePadding(bw, block.Length, last)
}
if block.Length == 0 {
return encodeEmptyBlock(bw, block.Type, last)
}
switch body := block.Body.(type) {
case *meta.StreamInfo:
return encodeStreamInfo(bw, body, last)
case *meta.Application:
return encodeApplication(bw, body, last)
case *meta.SeekTable:
return encodeSeekTable(bw, body, last)
case *meta.VorbisComment:
return encodeVorbisComment(bw, body, last)
case *meta.CueSheet:
return encodeCueSheet(bw, body, last)
case *meta.Picture:
return encodePicture(bw, body, last)
default:
panic(fmt.Errorf("support for metadata block body type %T not yet implemented", body))
}
}
// --- [ Metadata block header ] -----------------------------------------------
// encodeEmptyBlock encodes the metadata block header of an empty metadata
// block with the specified type, writing to bw.
func encodeEmptyBlock(bw *bitio.Writer, typ meta.Type, last bool) error {
// Store metadata block header.
hdr := &meta.Header{
IsLast: last,
Type: typ,
Length: 0,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ Metadata block header ] -----------------------------------------------
// encodeBlockHeader encodes the metadata block header, writing to bw.
func encodeBlockHeader(bw *bitio.Writer, hdr *meta.Header) error {
// 1 bit: IsLast.
if err := bw.WriteBool(hdr.IsLast); err != nil {
return errutil.Err(err)
}
// 7 bits: Type.
if err := bw.WriteBits(uint64(hdr.Type), 7); err != nil {
return errutil.Err(err)
}
// 24 bits: Length.
if err := bw.WriteBits(uint64(hdr.Length), 24); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ StreamInfo ] ----------------------------------------------------------
// encodeStreamInfo encodes the StreamInfo metadata block, writing to bw.
func encodeStreamInfo(bw *bitio.Writer, info *meta.StreamInfo, last bool) error {
// Store metadata block header.
const nbits = 16 + 16 + 24 + 24 + 20 + 3 + 5 + 36 + 8*16
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeStreamInfo,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// 16 bits: BlockSizeMin.
if err := bw.WriteBits(uint64(info.BlockSizeMin), 16); err != nil {
return errutil.Err(err)
}
// 16 bits: BlockSizeMax.
if err := bw.WriteBits(uint64(info.BlockSizeMax), 16); err != nil {
return errutil.Err(err)
}
// 24 bits: FrameSizeMin.
if err := bw.WriteBits(uint64(info.FrameSizeMin), 24); err != nil {
return errutil.Err(err)
}
// 24 bits: FrameSizeMax.
if err := bw.WriteBits(uint64(info.FrameSizeMax), 24); err != nil {
return errutil.Err(err)
}
// 20 bits: SampleRate.
if err := bw.WriteBits(uint64(info.SampleRate), 20); err != nil {
return errutil.Err(err)
}
// 3 bits: NChannels; stored as (number of channels) - 1.
if err := bw.WriteBits(uint64(info.NChannels-1), 3); err != nil {
return errutil.Err(err)
}
// 5 bits: BitsPerSample; stored as (bits-per-sample) - 1.
if err := bw.WriteBits(uint64(info.BitsPerSample-1), 5); err != nil {
return errutil.Err(err)
}
// 36 bits: NSamples.
if err := bw.WriteBits(info.NSamples, 36); err != nil {
return errutil.Err(err)
}
// 16 bytes: MD5sum.
if _, err := bw.Write(info.MD5sum[:]); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ Padding ] ----------------------------------------------------------
// encodePadding encodes the Padding metadata block, writing to bw.
func encodePadding(bw *bitio.Writer, length int64, last bool) error {
// Store metadata block header.
hdr := &meta.Header{
IsLast: last,
Type: meta.TypePadding,
Length: length,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
if _, err := io.CopyN(bw, ioutilx.Zero, length); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ Application ] ---------------------------------------------------------
// encodeApplication encodes the Application metadata block, writing to bw.
func encodeApplication(bw *bitio.Writer, app *meta.Application, last bool) error {
// Store metadata block header.
nbits := int64(32 + 8*len(app.Data))
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeApplication,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// 32 bits: ID.
if err := bw.WriteBits(uint64(app.ID), 32); err != nil {
return errutil.Err(err)
}
// TODO: check if the Application block may contain only an ID.
if _, err := bw.Write(app.Data); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ SeekTable ] -----------------------------------------------------------
// encodeSeekTable encodes the SeekTable metadata block, writing to bw.
func encodeSeekTable(bw *bitio.Writer, table *meta.SeekTable, last bool) error {
// Store metadata block header.
nbits := int64((64 + 64 + 16) * len(table.Points))
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeSeekTable,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
for _, point := range table.Points {
if err := binary.Write(bw, binary.BigEndian, point); err != nil {
return errutil.Err(err)
}
}
return nil
}
// --- [ VorbisComment ] -------------------------------------------------------
// encodeVorbisComment encodes the VorbisComment metadata block, writing to bw.
func encodeVorbisComment(bw *bitio.Writer, comment *meta.VorbisComment, last bool) error {
// Store metadata block header.
nbits := int64(32 + 8*len(comment.Vendor) + 32)
for _, tag := range comment.Tags {
nbits += int64(32 + 8*(len(tag[0])+1+len(tag[1])))
}
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeVorbisComment,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// 32 bits: vendor length.
// TODO: verify that little-endian encoding is used; otherwise, switch to
// using bw.WriteBits.
if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Vendor))); err != nil {
return errutil.Err(err)
}
// (vendor length) bits: Vendor.
if _, err := bw.Write([]byte(comment.Vendor)); err != nil {
return errutil.Err(err)
}
// Store tags.
// 32 bits: number of tags.
if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Tags))); err != nil {
return errutil.Err(err)
}
for _, tag := range comment.Tags {
// Store tag, which has the following format:
// NAME=VALUE
buf := []byte(fmt.Sprintf("%s=%s", tag[0], tag[1]))
// 32 bits: vector length
if err := binary.Write(bw, binary.LittleEndian, uint32(len(buf))); err != nil {
return errutil.Err(err)
}
// (vector length): vector.
if _, err := bw.Write(buf); err != nil {
return errutil.Err(err)
}
}
return nil
}
// --- [ CueSheet ] ------------------------------------------------------------
// encodeCueSheet encodes the CueSheet metadata block, writing to bw.
func encodeCueSheet(bw *bitio.Writer, cs *meta.CueSheet, last bool) error {
// Store metadata block header.
nbits := int64(8*128 + 64 + 1 + 7 + 8*258 + 8)
for _, track := range cs.Tracks {
nbits += 64 + 8 + 8*12 + 1 + 1 + 6 + 8*13 + 8
for range track.Indicies {
nbits += 64 + 8 + 8*3
}
}
hdr := &meta.Header{
IsLast: last,
Type: meta.TypeCueSheet,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// Store cue sheet.
// 128 bytes: MCN.
var mcn [128]byte
copy(mcn[:], cs.MCN)
if _, err := bw.Write(mcn[:]); err != nil {
return errutil.Err(err)
}
// 64 bits: NLeadInSamples.
if err := bw.WriteBits(cs.NLeadInSamples, 64); err != nil {
return errutil.Err(err)
}
// 1 bit: IsCompactDisc.
if err := bw.WriteBool(cs.IsCompactDisc); err != nil {
return errutil.Err(err)
}
// 7 bits and 258 bytes: reserved.
if err := bw.WriteBits(0, 7); err != nil {
return errutil.Err(err)
}
if _, err := io.CopyN(bw, ioutilx.Zero, 258); err != nil {
return errutil.Err(err)
}
// Store cue sheet tracks.
// 8 bits: (number of tracks)
if err := bw.WriteBits(uint64(len(cs.Tracks)), 8); err != nil {
return errutil.Err(err)
}
for _, track := range cs.Tracks {
// 64 bits: Offset.
if err := bw.WriteBits(track.Offset, 64); err != nil {
return errutil.Err(err)
}
// 8 bits: Num.
if err := bw.WriteBits(uint64(track.Num), 8); err != nil {
return errutil.Err(err)
}
// 12 bytes: ISRC.
var isrc [12]byte
copy(isrc[:], track.ISRC)
if _, err := bw.Write(isrc[:]); err != nil {
return errutil.Err(err)
}
// 1 bit: IsAudio.
if err := bw.WriteBool(!track.IsAudio); err != nil {
return errutil.Err(err)
}
// 1 bit: HasPreEmphasis.
// mask = 01000000
if err := bw.WriteBool(track.HasPreEmphasis); err != nil {
return errutil.Err(err)
}
// 6 bits and 13 bytes: reserved.
// mask = 00111111
if err := bw.WriteBits(0, 6); err != nil {
return errutil.Err(err)
}
if _, err := io.CopyN(bw, ioutilx.Zero, 13); err != nil {
return errutil.Err(err)
}
// Store indicies.
// 8 bits: (number of indicies)
if err := bw.WriteBits(uint64(len(track.Indicies)), 8); err != nil {
return errutil.Err(err)
}
for _, index := range track.Indicies {
// 64 bits: Offset.
if err := bw.WriteBits(index.Offset, 64); err != nil {
return errutil.Err(err)
}
// 8 bits: Num.
if err := bw.WriteBits(uint64(index.Num), 8); err != nil {
return errutil.Err(err)
}
// 3 bytes: reserved.
if _, err := io.CopyN(bw, ioutilx.Zero, 3); err != nil {
return errutil.Err(err)
}
}
}
return nil
}
// --- [ Picture ] -------------------------------------------------------------
// encodePicture encodes the Picture metadata block, writing to bw.
func encodePicture(bw *bitio.Writer, pic *meta.Picture, last bool) error {
// Store metadata block header.
nbits := int64(32 + 32 + 8*len(pic.MIME) + 32 + 8*len(pic.Desc) + 32 + 32 + 32 + 32 + 32 + 8*len(pic.Data))
hdr := &meta.Header{
IsLast: last,
Type: meta.TypePicture,
Length: nbits / 8,
}
if err := encodeBlockHeader(bw, hdr); err != nil {
return errutil.Err(err)
}
// Store metadata block body.
// 32 bits: Type.
if err := bw.WriteBits(uint64(pic.Type), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: (MIME type length).
if err := bw.WriteBits(uint64(len(pic.MIME)), 32); err != nil {
return errutil.Err(err)
}
// (MIME type length) bytes: MIME.
if _, err := bw.Write([]byte(pic.MIME)); err != nil {
return errutil.Err(err)
}
// 32 bits: (description length).
if err := bw.WriteBits(uint64(len(pic.Desc)), 32); err != nil {
return errutil.Err(err)
}
// (description length) bytes: Desc.
if _, err := bw.Write([]byte(pic.Desc)); err != nil {
return errutil.Err(err)
}
// 32 bits: Width.
if err := bw.WriteBits(uint64(pic.Width), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: Height.
if err := bw.WriteBits(uint64(pic.Height), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: Depth.
if err := bw.WriteBits(uint64(pic.Depth), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: NPalColors.
if err := bw.WriteBits(uint64(pic.NPalColors), 32); err != nil {
return errutil.Err(err)
}
// 32 bits: (data length).
if err := bw.WriteBits(uint64(len(pic.Data)), 32); err != nil {
return errutil.Err(err)
}
// (data length) bytes: Data.
if _, err := bw.Write(pic.Data); err != nil {
return errutil.Err(err)
}
return nil
}
================================================
FILE: encode_subframe.go
================================================
package flac
import (
"fmt"
"github.com/icza/bitio"
"github.com/mewkiz/flac/frame"
iobits "github.com/mewkiz/flac/internal/bits"
"github.com/mewkiz/pkg/errutil"
)
// --- [ Subframe ] ------------------------------------------------------------
// encodeSubframe encodes the given subframe, writing to bw.
func encodeSubframe(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
// Encode subframe header.
if err := encodeSubframeHeader(bw, subframe.SubHeader); err != nil {
return errutil.Err(err)
}
// Adjust bps of subframe for wasted bits-per-sample.
bps -= subframe.Wasted
// Right shift to account for wasted bits-per-sample.
if subframe.Wasted > 0 {
for i, sample := range subframe.Samples {
subframe.Samples[i] = sample >> subframe.Wasted
}
// NOTE: use defer to restore original samples after encode.
defer func() {
for i, sample := range subframe.Samples {
subframe.Samples[i] = sample << subframe.Wasted
}
}()
}
// Encode audio samples.
switch subframe.Pred {
case frame.PredConstant:
if err := encodeConstantSamples(bw, hdr, subframe, bps); err != nil {
return errutil.Err(err)
}
case frame.PredVerbatim:
if err := encodeVerbatimSamples(bw, hdr, subframe, bps); err != nil {
return errutil.Err(err)
}
case frame.PredFixed:
if err := encodeFixedSamples(bw, hdr, subframe, bps); err != nil {
return errutil.Err(err)
}
case frame.PredFIR:
if err := encodeFIRSamples(bw, hdr, subframe, bps); err != nil {
return errutil.Err(err)
}
default:
return errutil.Newf("support for prediction method %v not yet implemented", subframe.Pred)
}
return nil
}
// --- [ Subframe header ] -----------------------------------------------------
// encodeSubframeHeader encodes the given subframe header, writing to bw.
func encodeSubframeHeader(bw *bitio.Writer, subHdr frame.SubHeader) error {
// Zero bit padding, to prevent sync-fooling string of 1s.
if err := bw.WriteBits(0x0, 1); err != nil {
return errutil.Err(err)
}
// Subframe type:
// 000000 : SUBFRAME_CONSTANT
// 000001 : SUBFRAME_VERBATIM
// 00001x : reserved
// 0001xx : reserved
// 001xxx : if(xxx <= 4) SUBFRAME_FIXED, xxx=order ; else reserved
// 01xxxx : reserved
// 1xxxxx : SUBFRAME_LPC, xxxxx=order-1
var bits uint64
switch subHdr.Pred {
case frame.PredConstant:
// 000000 : SUBFRAME_CONSTANT
bits = 0x00
case frame.PredVerbatim:
// 000001 : SUBFRAME_VERBATIM
bits = 0x01
case frame.PredFixed:
// 001xxx : if(xxx <= 4) SUBFRAME_FIXED, xxx=order ; else reserved
bits = 0x08 | uint64(subHdr.Order)
case frame.PredFIR:
// 1xxxxx : SUBFRAME_LPC, xxxxx=order-1
bits = 0x20 | uint64(subHdr.Order-1)
}
if err := bw.WriteBits(bits, 6); err != nil {
return errutil.Err(err)
}
// <1+k> 'Wasted bits-per-sample' flag:
//
// 0 : no wasted bits-per-sample in source subblock, k=0
// 1 : k wasted bits-per-sample in source subblock, k-1 follows, unary coded; e.g. k=3 => 001 follows, k=7 => 0000001 follows.
hasWastedBits := subHdr.Wasted > 0
if err := bw.WriteBool(hasWastedBits); err != nil {
return errutil.Err(err)
}
if hasWastedBits {
if err := iobits.WriteUnary(bw, uint64(subHdr.Wasted-1)); err != nil {
return errutil.Err(err)
}
}
return nil
}
// --- [ Constant samples ] ----------------------------------------------------
// encodeConstantSamples stores the given constant sample, writing to bw.
func encodeConstantSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
samples := subframe.Samples
sample := samples[0]
for _, s := range samples[1:] {
if sample != s {
return errutil.Newf("constant sample mismatch; expected %v, got %v", sample, s)
}
}
// Unencoded constant value of the subblock, n = frame's bits-per-sample.
if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ Verbatim samples ] ----------------------------------------------------
// encodeVerbatimSamples stores the given samples verbatim (uncompressed),
// writing to bw.
func encodeVerbatimSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
// Unencoded subblock; n = frame's bits-per-sample, i = frame's blocksize.
samples := subframe.Samples
if int(hdr.BlockSize) != len(samples) {
return errutil.Newf("block size and sample count mismatch; expected %d, got %d", hdr.BlockSize, len(samples))
}
for _, sample := range samples {
if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
return errutil.Err(err)
}
}
return nil
}
// --- [ Fixed samples ] -------------------------------------------------------
// encodeFixedSamples stores the given samples using linear prediction coding
// with a fixed set of predefined polynomial coefficients, writing to bw.
func encodeFixedSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
// Encode unencoded warm-up samples.
samples := subframe.Samples
for i := 0; i < subframe.Order; i++ {
sample := samples[i]
if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
return errutil.Err(err)
}
}
// Compute residuals (signal errors of the prediction) between audio
// samples and LPC predicted audio samples.
const shift = 0
residuals, err := getLPCResiduals(subframe, frame.FixedCoeffs[subframe.Order], shift)
if err != nil {
return errutil.Err(err)
}
// Encode subframe residuals.
if err := encodeResiduals(bw, subframe, residuals); err != nil {
return errutil.Err(err)
}
return nil
}
// --- [ FIR samples ] -------------------------------------------------------
// encodeFIRSamples stores the given samples using linear prediction coding
// with a custom set of predefined polynomial coefficients, writing to bw.
func encodeFIRSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error {
// Encode unencoded warm-up samples.
samples := subframe.Samples
for i := 0; i < subframe.Order; i++ {
sample := samples[i]
if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil {
return errutil.Err(err)
}
}
// 4 bits: (coefficients' precision in bits) - 1.
if err := bw.WriteBits(uint64(subframe.CoeffPrec-1), 4); err != nil {
return errutil.Err(err)
}
// 5 bits: predictor coefficient shift needed in bits.
if err := bw.WriteBits(uint64(subframe.CoeffShift), 5); err != nil {
return errutil.Err(err)
}
// Encode coefficients.
for _, coeff := range subframe.Coeffs {
// (prec) bits: Predictor coefficient.
if err := bw.WriteBits(uint64(coeff), uint8(subframe.CoeffPrec)); err != nil {
return errutil.Err(err)
}
}
// Compute residuals (signal errors of the prediction) between audio
// samples and LPC predicted audio samples.
residuals, err := getLPCResiduals(subframe, subframe.Coeffs, subframe.CoeffShift)
if err != nil {
return errutil.Err(err)
}
// Encode subframe residuals.
if err := encodeResiduals(bw, subframe, residuals); err != nil {
return errutil.Err(err)
}
return nil
}
// encodeResiduals encodes the residuals (prediction method error signals) of the
// subframe.
//
// ref: https://www.xiph.org/flac/format.html#residual
func encodeResiduals(bw *bitio.Writer, subframe *frame.Subframe, residuals []int32) error {
// 2 bits: Residual coding method.
if err := bw.WriteBits(uint64(subframe.ResidualCodingMethod), 2); err != nil {
return errutil.Err(err)
}
// The 2 bits are used to specify the residual coding method as follows:
// 00: Rice coding with a 4-bit Rice parameter.
// 01: Rice coding with a 5-bit Rice parameter.
// 10: reserved.
// 11: reserved.
switch subframe.ResidualCodingMethod {
case frame.ResidualCodingMethodRice1:
return encodeRicePart(bw, subframe, 4, residuals)
case frame.ResidualCodingMethodRice2:
return encodeRicePart(bw, subframe, 5, residuals)
default:
return fmt.Errorf("encodeResiduals: reserved residual coding method bit pattern (%02b)", uint8(subframe.ResidualCodingMethod))
}
}
// encodeRicePart encodes a Rice partition of residuals from the subframe, using
// a Rice parameter of the specified size in bits.
//
// ref: https://www.xiph.org/flac/format.html#partitioned_rice
// ref: https://www.xiph.org/flac/format.html#partitioned_rice2
func encodeRicePart(bw *bitio.Writer, subframe *frame.Subframe, paramSize uint, residuals []int32) error {
// 4 bits: Partition order.
riceSubframe := subframe.RiceSubframe
if err := bw.WriteBits(uint64(riceSubframe.PartOrder), 4); err != nil {
return errutil.Err(err)
}
// Parse Rice partitions; in total 2^partOrder partitions.
//
// ref: https://www.xiph.org/flac/format.html#rice_partition
// ref: https://www.xiph.org/flac/format.html#rice2_partition
partOrder := riceSubframe.PartOrder
nparts := 1 << partOrder
curResidualIndex := 0
for i := range riceSubframe.Partitions {
partition := &riceSubframe.Partitions[i]
// (4 or 5) bits: Rice parameter.
param := partition.Param
if err := bw.WriteBits(uint64(param), uint8(paramSize)); err != nil {
return errutil.Err(err)
}
// Determine the number of Rice encoded samples in the partition.
var nsamples int
if partOrder == 0 {
nsamples = subframe.NSamples - subframe.Order
} else if i != 0 {
nsamples = subframe.NSamples / nparts
} else {
nsamples = subframe.NSamples/nparts - subframe.Order
}
if paramSize == 4 && param == 0xF || paramSize == 5 && param == 0x1F {
// 1111 or 11111: Escape code, meaning the partition is in unencoded
// binary form using n bits per sample; n follows as a 5-bit number.
if err := bw.WriteBits(uint64(partition.EscapedBitsPerSample), 5); err != nil {
return errutil.Err(err)
}
for j := 0; j < nsamples; j++ {
// ref: https://datatracker.ietf.org/doc/draft-ietf-cellar-flac/
//
// From section 9.2.7.1. Escaped partition:
//
// The residual samples themselves are stored signed two's
// complement. For example, when a partition is escaped and each
// residual sample is stored with 3 bits, the number -1 is
// represented as 0b111.
residual := residuals[curResidualIndex]
curResidualIndex++
if err := bw.WriteBits(uint64(residual), uint8(partition.EscapedBitsPerSample)); err != nil {
return errutil.Err(err)
}
}
continue
}
// Encode the Rice residuals of the partition.
for j := 0; j < nsamples; j++ {
residual := residuals[curResidualIndex]
curResidualIndex++
if err := encodeRiceResidual(bw, param, residual); err != nil {
return errutil.Err(err)
}
}
}
return nil
}
// encodeRiceResidual encodes a Rice residual (error signal).
func encodeRiceResidual(bw *bitio.Writer, k uint, residual int32) error {
// ZigZag encode.
folded := iobits.EncodeZigZag(residual)
// unfold into low- and high.
lowMask := ^uint32(0) >> (32 - k) // lower k bits.
highMask := ^uint32(0) << k // upper bits.
high := (folded & highMask) >> k
low := folded & lowMask
// Write unary encoded most significant bits.
if err := iobits.WriteUnary(bw, uint64(high)); err != nil {
return errutil.Err(err)
}
// Write binary encoded least significant bits.
if err := bw.WriteBits(uint64(low), uint8(k)); err != nil {
return errutil.Err(err)
}
return nil
}
// getLPCResiduals returns the residuals (signal errors of the prediction)
// between the given audio samples and the LPC predicted audio samples, using
// the coefficients of a given polynomial, and a couple (order of polynomial;
// i.e. len(coeffs)) of unencoded warm-up samples.
func getLPCResiduals(subframe *frame.Subframe, coeffs []int32, shift int32) ([]int32, error) {
if len(coeffs) != subframe.Order {
return nil, fmt.Errorf("getLPCResiduals: prediction order (%d) differs from number of coefficients (%d)", subframe.Order, len(coeffs))
}
if shift < 0 {
return nil, fmt.Errorf("getLPCResiduals: invalid negative shift")
}
if subframe.NSamples != len(subframe.Samples) {
return nil, fmt.Errorf("getLPCResiduals: subframe sample count mismatch; expected %d, got %d", subframe.NSamples, len(subframe.Samples))
}
var residuals []int32
for i := subframe.Order; i < subframe.NSamples; i++ {
var sample int64
for j, c := range coeffs {
sample += int64(c) * int64(subframe.Samples[i-j-1])
}
residual := subframe.Samples[i] - int32(sample>>uint(shift))
residuals = append(residuals, residual)
}
return residuals, nil
}
================================================
FILE: example_test.go
================================================
package flac_test
import (
"bytes"
"crypto/md5"
"fmt"
"io"
"log"
"github.com/mewkiz/flac"
)
func ExampleParseFile() {
// Parse metadata of love.flac
stream, err := flac.ParseFile("testdata/love.flac")
if err != nil {
log.Fatal(err)
}
defer stream.Close()
fmt.Printf("unencoded audio md5sum: %032x\n", stream.Info.MD5sum[:])
for i, block := range stream.Blocks {
fmt.Printf("block %d: %v\n", i, block.Type)
}
// Output:
// unencoded audio md5sum: bdf6f7d31f77cb696a02b2192d192a89
// block 0: seek table
// block 1: vorbis comment
// block 2: padding
}
func ExampleOpen() {
// Open love.flac for audio streaming without parsing metadata.
stream, err := flac.Open("testdata/love.flac")
if err != nil {
log.Fatal(err)
}
defer stream.Close()
// Parse audio samples and verify the MD5 signature of the decoded audio
// samples.
md5sum := md5.New()
for {
// Parse one frame of audio samples at the time, each frame containing one
// subframe per audio channel.
frame, err := stream.ParseNext()
if err != nil {
if err == io.EOF {
break
}
log.Fatal(err)
}
frame.Hash(md5sum)
// Print first three samples from each channel of the first five frames.
if frame.Num < 5 {
fmt.Printf("frame %d\n", frame.Num)
for i, subframe := range frame.Subframes {
fmt.Printf(" subframe %d\n", i)
for j, sample := range subframe.Samples {
if j >= 3 {
break
}
fmt.Printf(" sample %d: %v\n", j, sample)
}
}
}
}
fmt.Println()
got, want := md5sum.Sum(nil), stream.Info.MD5sum[:]
fmt.Println("decoded audio md5sum valid:", bytes.Equal(got, want))
// Output:
// frame 0
// subframe 0
// sample 0: 126
// sample 1: 126
// sample 2: 126
// subframe 1
// sample 0: 126
// sample 1: 126
// sample 2: 126
// frame 1
// subframe 0
// sample 0: 126
// sample 1: 126
// sample 2: 126
// subframe 1
// sample 0: 126
// sample 1: 126
// sample 2: 126
// frame 2
// subframe 0
// sample 0: 121
// sample 1: 130
// sample 2: 137
// subframe 1
// sample 0: 121
// sample 1: 130
// sample 2: 137
// frame 3
// subframe 0
// sample 0: -9501
// sample 1: -6912
// sample 2: -3916
// subframe 1
// sample 0: -9501
// sample 1: -6912
// sample 2: -3916
// frame 4
// subframe 0
// sample 0: 513
// sample 1: 206
// sample 2: 152
// subframe 1
// sample 0: 513
// sample 1: 206
// sample 2: 152
//
// decoded audio md5sum valid: true
}
================================================
FILE: flac.go
================================================
// TODO(u): Evaluate storing the samples (and residuals) during frame audio
// decoding in a buffer allocated for the stream. This buffer would be allocated
// using BlockSize and NChannels from the StreamInfo block, and it could be
// reused in between calls to Next and ParseNext. This should reduce GC
// pressure.
// TODO: Remove note about encoder API.
// Package flac provides access to FLAC (Free Lossless Audio Codec) streams.
//
// A brief introduction of the FLAC stream format [1] follows. Each FLAC stream
// starts with a 32-bit signature ("fLaC"), followed by one or more metadata
// blocks, and then one or more audio frames. The first metadata block
// (StreamInfo) describes the basic properties of the audio stream and it is the
// only mandatory metadata block. Subsequent metadata blocks may appear in an
// arbitrary order.
//
// 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
//
// Note: the Encoder API is experimental until the 1.1.x release. As such, it's
// API is expected to change.
package flac
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"os"
"github.com/mewkiz/flac/frame"
"github.com/mewkiz/flac/internal/bufseekio"
"github.com/mewkiz/flac/meta"
)
// A Stream contains the metadata blocks and provides access to the audio frames
// of a FLAC stream.
//
// ref: https://www.xiph.org/flac/format.html#stream
type Stream struct {
// The StreamInfo metadata block describes the basic properties of the FLAC
// audio stream.
Info *meta.StreamInfo
// Zero or more metadata blocks.
Blocks []*meta.Block
// seekTable contains one or more pre-calculated audio frame seek points of
// the stream; nil if uninitialized.
seekTable *meta.SeekTable
// seekTableSize determines how many seek points the seekTable should have if
// the flac file does not include one in the metadata.
seekTableSize int
// dataStart is the offset of the first frame header since SeekPoint.Offset
// is relative to this position.
dataStart int64
// Underlying io.Reader, or io.ReadCloser.
r io.Reader
}
// New creates a new Stream for accessing the audio samples of r. It reads and
// parses the FLAC signature and the StreamInfo metadata block, but skips all
// other metadata blocks.
//
// Call Stream.Next to parse the frame header of the next audio frame, and call
// Stream.ParseNext to parse the entire next frame including audio samples.
func New(r io.Reader) (stream *Stream, err error) {
// Verify FLAC signature and parse the StreamInfo metadata block.
br := bufio.NewReader(r)
stream = &Stream{r: br}
block, err := stream.parseStreamInfo()
if err != nil {
return nil, err
}
// Skip the remaining metadata blocks.
for !block.IsLast {
block, err = meta.New(br)
if err != nil && err != meta.ErrReservedType {
return stream, err
}
if err = block.Skip(); err != nil {
return stream, err
}
}
return stream, nil
}
// NewSeek returns a Stream that has seeking enabled. The incoming io.ReadSeeker
// will not be buffered, which might result in performance issues. Using an
// in-memory buffer like *bytes.Reader should work well.
func NewSeek(rs io.ReadSeeker) (stream *Stream, err error) {
br := bufseekio.NewReadSeeker(rs)
stream = &Stream{r: br, seekTableSize: defaultSeekTableSize}
// Verify FLAC signature and parse the StreamInfo metadata block.
block, err := stream.parseStreamInfo()
if err != nil {
return stream, err
}
for !block.IsLast {
block, err = meta.Parse(stream.r)
if err != nil {
if err != meta.ErrReservedType {
return stream, err
}
if err = block.Skip(); err != nil {
return stream, err
}
}
if block.Header.Type == meta.TypeSeekTable {
stream.seekTable = block.Body.(*meta.SeekTable)
}
}
// Record file offset of the first frame header.
stream.dataStart, err = br.Seek(0, io.SeekCurrent)
return stream, err
}
var (
// flacSignature marks the beginning of a FLAC stream.
flacSignature = []byte("fLaC")
// id3Signature marks the beginning of an ID3 stream, used to skip over ID3
// data.
id3Signature = []byte("ID3")
// ErrNoSeeker reports that flac.NewSeek was called with an io.Reader not
// implementing io.Seeker, and thus does not allow for seeking.
ErrNoSeeker = errors.New("stream.Seek: reader does not implement io.Seeker")
// ErrNoSeektable reports that no seektable has been generated. Therefore,
// it is not possible to seek in the stream.
ErrNoSeektable = errors.New("stream.searchFromStart: no seektable exists")
)
const (
defaultSeekTableSize = 100
)
// parseStreamInfo verifies the signature which marks the beginning of a FLAC
// stream, and parses the StreamInfo metadata block. It returns a boolean value
// which specifies if the StreamInfo block was the last metadata block of the
// FLAC stream.
func (stream *Stream) parseStreamInfo() (block *meta.Block, err error) {
// Verify FLAC signature.
r := stream.r
var buf [4]byte
if _, err = io.ReadFull(r, buf[:]); err != nil {
return block, err
}
// Skip prepended ID3v2 data.
if bytes.Equal(buf[:3], id3Signature) {
if err := stream.skipID3v2(); err != nil {
return block, err
}
// Second attempt at verifying signature.
if _, err = io.ReadFull(r, buf[:]); err != nil {
return block, err
}
}
if !bytes.Equal(buf[:], flacSignature) {
return block, fmt.Errorf("flac.parseStreamInfo: invalid FLAC signature; expected %q, got %q", flacSignature, buf)
}
// Parse StreamInfo metadata block.
block, err = meta.Parse(r)
if err != nil {
return block, err
}
si, ok := block.Body.(*meta.StreamInfo)
if !ok {
return block, fmt.Errorf("flac.parseStreamInfo: incorrect type of first metadata block; expected *meta.StreamInfo, got %T", block.Body)
}
stream.Info = si
return block, nil
}
// skipID3v2 skips ID3v2 data prepended to flac files.
func (stream *Stream) skipID3v2() error {
r := bufio.NewReader(stream.r)
// Discard unnecessary data from the ID3v2 header.
if _, err := r.Discard(2); err != nil {
return err
}
// Read the size from the ID3v2 header.
var sizeBuf [4]byte
if _, err := r.Read(sizeBuf[:]); err != nil {
return err
}
// The size is encoded as a synchsafe integer.
size := int(sizeBuf[0])<<21 | int(sizeBuf[1])<<14 | int(sizeBuf[2])<<7 | int(sizeBuf[3])
_, err := r.Discard(size)
return err
}
// Parse creates a new Stream for accessing the metadata blocks and audio
// samples of r. It reads and parses the FLAC signature and all metadata blocks.
//
// Call Stream.Next to parse the frame header of the next audio frame, and call
// Stream.ParseNext to parse the entire next frame including audio samples.
func Parse(r io.Reader) (stream *Stream, err error) {
// Verify FLAC signature and parse the StreamInfo metadata block.
br := bufio.NewReader(r)
stream = &Stream{r: br}
block, err := stream.parseStreamInfo()
if err != nil {
return nil, err
}
// Parse the remaining metadata blocks.
for !block.IsLast {
block, err = meta.Parse(br)
if err != nil {
if err != meta.ErrReservedType {
return stream, err
}
// Skip the body of unknown (reserved) metadata blocks, as stated by
// the specification.
//
// ref: https://www.xiph.org/flac/format.html#format_overview
if err = block.Skip(); err != nil {
return stream, err
}
}
stream.Blocks = append(stream.Blocks, block)
}
return stream, nil
}
// Open creates a new Stream for accessing the audio samples of path. It reads
// and parses the FLAC signature and the StreamInfo metadata block, but skips
// all other metadata blocks.
//
// Call Stream.Next to parse the frame header of the next audio frame, and call
// Stream.ParseNext to parse the entire next frame including audio samples.
//
// Note: The Close method of the stream must be called when finished using it.
func Open(path string) (stream *Stream, err error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
stream, err = New(f)
if err != nil {
return nil, err
}
return stream, err
}
// ParseFile creates a new Stream for accessing the metadata blocks and audio
// samples of path. It reads and parses the FLAC signature and all metadata
// blocks.
//
// Call Stream.Next to parse the frame header of the next audio frame, and call
// Stream.ParseNext to parse the entire next frame including audio samples.
//
// Note: The Close method of the stream must be called when finished using it.
func ParseFile(path string) (stream *Stream, err error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
stream, err = Parse(f)
if err != nil {
return nil, err
}
return stream, err
}
// Close closes the stream gracefully if the underlying io.Reader also implements the io.Closer interface.
func (stream *Stream) Close() error {
if closer, ok := stream.r.(io.Closer); ok {
return closer.Close()
}
return nil
}
// Next parses the frame header of the next audio frame. It returns io.EOF to
// signal a graceful end of FLAC stream.
//
// Call Frame.Parse to parse the audio samples of its subframes.
func (stream *Stream) Next() (f *frame.Frame, err error) {
return frame.New(stream.r)
}
// ParseNext parses the entire next frame including audio samples. It returns
// io.EOF to signal a graceful end of FLAC stream.
func (stream *Stream) ParseNext() (f *frame.Frame, err error) {
return frame.Parse(stream.r)
}
// Seek seeks to the frame containing the given absolute sample number. The
// return value specifies the first sample number of the frame containing
// sampleNum.
func (stream *Stream) Seek(sampleNum uint64) (uint64, error) {
if stream.seekTable == nil && stream.seekTableSize > 0 {
if err := stream.makeSeekTable(); err != nil {
return 0, err
}
}
rs := stream.r.(io.ReadSeeker)
isBiggerThanStream := stream.Info.NSamples != 0 && sampleNum >= stream.Info.NSamples
if isBiggerThanStream || sampleNum < 0 {
return 0, fmt.Errorf("unable to seek to sample number %d", sampleNum)
}
point, err := stream.searchFromStart(sampleNum)
if err != nil {
return 0, err
}
if _, err := rs.Seek(stream.dataStart+int64(point.Offset), io.SeekStart); err != nil {
return 0, err
}
for {
// Record seek offset to start of frame.
offset, err := rs.Seek(0, io.SeekCurrent)
if err != nil {
return 0, err
}
frame, err := stream.ParseNext()
if err != nil {
return 0, err
}
if frame.SampleNumber()+uint64(frame.BlockSize) > sampleNum {
// Restore seek offset to the start of the frame containing the
// specified sample number.
_, err := rs.Seek(offset, io.SeekStart)
return frame.SampleNumber(), err
}
}
}
// TODO(_): Utilize binary search in searchFromStart.
// searchFromStart searches for the given sample number from the start of the
// seek table and returns the last seek point containing the sample number. If
// no seek point contains the sample number, the last seek point preceding the
// sample number is returned. If the sample number is lower than the first seek
// point, the first seek point is returned.
func (stream *Stream) searchFromStart(sampleNum uint64) (meta.SeekPoint, error) {
if len(stream.seekTable.Points) == 0 {
return meta.SeekPoint{}, ErrNoSeektable
}
prev := stream.seekTable.Points[0]
for _, p := range stream.seekTable.Points {
if p.SampleNum+uint64(p.NSamples) >= sampleNum {
return prev, nil
}
prev = p
}
return prev, nil
}
// makeSeekTable creates a seek table with seek points to each frame of the FLAC
// stream.
func (stream *Stream) makeSeekTable() (err error) {
rs, ok := stream.r.(io.ReadSeeker)
if !ok {
return ErrNoSeeker
}
pos, err := rs.Seek(0, io.SeekCurrent)
if err != nil {
return err
}
_, err = rs.Seek(stream.dataStart, io.SeekStart)
if err != nil {
return err
}
var i int
var sampleNum uint64
var points []meta.SeekPoint
for {
// Record seek offset to start of frame.
off, err := rs.Seek(0, io.SeekCurrent)
if err != nil {
return err
}
f, err := stream.ParseNext()
if err != nil {
if err == io.EOF {
break
}
return err
}
points = append(points, meta.SeekPoint{
SampleNum: sampleNum,
Offset: uint64(off - stream.dataStart),
NSamples: f.BlockSize,
})
sampleNum += uint64(f.BlockSize)
i++
}
stream.seekTable = &meta.SeekTable{Points: points}
_, err = rs.Seek(pos, io.SeekStart)
return err
}
================================================
FILE: flac_test.go
================================================
package flac_test
import (
"fmt"
"io"
"os"
"testing"
"github.com/mewkiz/flac"
)
func TestSkipID3v2(t *testing.T) {
if _, err := flac.ParseFile("testdata/id3.flac"); err != nil {
t.Fatal(err)
}
}
func TestSeek(t *testing.T) {
f, err := os.Open("testdata/172960.flac")
if err != nil {
t.Fatal(err)
}
defer f.Close()
//Seek Table:
// {SampleNum:0 Offset:8283 NSamples:4096}
// {SampleNum:4096 Offset:17777 NSamples:4096}
// {SampleNum:8192 Offset:27141 NSamples:4096}
// {SampleNum:12288 Offset:36665 NSamples:4096}
// {SampleNum:16384 Offset:46179 NSamples:4096}
// {SampleNum:20480 Offset:55341 NSamples:4096}
// {SampleNum:24576 Offset:64690 NSamples:4096}
// {SampleNum:28672 Offset:74269 NSamples:4096}
// {SampleNum:32768 Offset:81984 NSamples:4096}
// {SampleNum:36864 Offset:86656 NSamples:4096}
// {SampleNum:40960 Offset:89596 NSamples:2723}
testPos := []struct {
seek uint64
expected uint64
err string
}{
{seek: 0, expected: 0},
{seek: 9000, expected: 8192},
{seek: 0, expected: 0},
{seek: 8000, expected: 4096},
{seek: 0, expected: 0},
{seek: 50000, expected: 0, err: "unable to seek to sample number 50000"},
{seek: 100, expected: 0},
{seek: 8192, expected: 8192},
{seek: 8191, expected: 4096},
//{seek: 40960 + 2723 - 1, expected: 40960}, // last sample // TODO: re-enable when it works. See https://github.com/mewkiz/flac/pull/73
{seek: 40960 + 2723, expected: 0, err: "unable to seek to sample number 43683"}, // one after last sample
}
stream, err := flac.NewSeek(f)
if err != nil {
t.Fatal(err)
}
for i, pos := range testPos {
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
p, err := stream.Seek(pos.seek)
if err != nil {
if err.Error() != pos.err {
t.Fatal(err)
}
}
if p != pos.expected {
t.Fatalf("pos %d does not equal %d", p, pos.expected)
}
_, err = stream.ParseNext()
if err != nil && err != io.EOF {
t.Fatal(err)
}
})
}
}
func TestDecode(t *testing.T) {
paths := []string{
"meta/testdata/input-SCPAP.flac",
"meta/testdata/input-SCVA.flac",
"meta/testdata/input-SCVPAP.flac",
"meta/testdata/input-VA.flac",
"meta/testdata/silence.flac",
"testdata/19875.flac",
"testdata/44127.flac",
"testdata/59996.flac",
"testdata/80574.flac",
"testdata/172960.flac",
"testdata/189983.flac",
"testdata/191885.flac",
"testdata/212768.flac",
"testdata/220014.flac",
"testdata/243749.flac",
"testdata/256529.flac",
"testdata/257344.flac",
"testdata/8297-275156-0011.flac",
"testdata/love.flac",
// IETF test cases.
//
// ref: https://github.com/ietf-wg-cellar/flac-test-files/tree/main/subset
"testdata/flac-test-files/subset/01 - blocksize 4096.flac",
"testdata/flac-test-files/subset/02 - blocksize 4608.flac",
"testdata/flac-test-files/subset/03 - blocksize 16.flac",
"testdata/flac-test-files/subset/04 - blocksize 192.flac",
"testdata/flac-test-files/subset/05 - blocksize 254.flac",
"testdata/flac-test-files/subset/06 - blocksize 512.flac",
"testdata/flac-test-files/subset/07 - blocksize 725.flac",
"testdata/flac-test-files/subset/08 - blocksize 1000.flac",
"testdata/flac-test-files/subset/09 - blocksize 1937.flac",
"testdata/flac-test-files/subset/10 - blocksize 2304.flac",
"testdata/flac-test-files/subset/11 - partition order 8.flac",
"testdata/flac-test-files/subset/12 - qlp precision 15 bit.flac",
"testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac",
"testdata/flac-test-files/subset/14 - wasted bits.flac",
"testdata/flac-test-files/subset/15 - only verbatim subframes.flac",
"testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac",
"testdata/flac-test-files/subset/17 - all fixed orders.flac",
"testdata/flac-test-files/subset/18 - precision search.flac",
"testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac",
"testdata/flac-test-files/subset/20 - samplerate 39kHz.flac",
"testdata/flac-test-files/subset/21 - samplerate 22050Hz.flac",
"testdata/flac-test-files/subset/22 - 12 bit per sample.flac",
"testdata/flac-test-files/subset/23 - 8 bit per sample.flac",
"testdata/flac-test-files/subset/24 - variable blocksize file created with flake revision 264.flac",
"testdata/flac-test-files/subset/25 - variable blocksize file created with flake revision 264, modified to create smaller blocks.flac",
"testdata/flac-test-files/subset/26 - variable blocksize file created with CUETools.Flake 2.1.6.flac",
"testdata/flac-test-files/subset/27 - old format variable blocksize file created with Flake 0.11.flac",
"testdata/flac-test-files/subset/28 - high resolution audio, default settings.flac",
"testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac",
"testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac",
"testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac",
"testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac",
"testdata/flac-test-files/subset/33 - samplerate 192kHz.flac",
"testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac",
"testdata/flac-test-files/subset/35 - samplerate 134560Hz.flac",
"testdata/flac-test-files/subset/36 - samplerate 384kHz.flac",
"testdata/flac-test-files/subset/37 - 20 bit per sample.flac",
"testdata/flac-test-files/subset/38 - 3 channels (3.0).flac",
"testdata/flac-test-files/subset/39 - 4 channels (4.0).flac",
"testdata/flac-test-files/subset/40 - 5 channels (5.0).flac",
"testdata/flac-test-files/subset/41 - 6 channels (5.1).flac",
"testdata/flac-test-files/subset/42 - 7 channels (6.1).flac",
"testdata/flac-test-files/subset/43 - 8 channels (7.1).flac",
"testdata/flac-test-files/subset/44 - 8-channel surround, 192kHz, 24 bit, using only 32nd order predictors.flac",
"testdata/flac-test-files/subset/45 - no total number of samples set.flac",
"testdata/flac-test-files/subset/46 - no min-max framesize set.flac",
"testdata/flac-test-files/subset/47 - only STREAMINFO.flac",
"testdata/flac-test-files/subset/48 - Extremely large SEEKTABLE.flac",
"testdata/flac-test-files/subset/49 - Extremely large PADDING.flac",
"testdata/flac-test-files/subset/50 - Extremely large PICTURE.flac",
"testdata/flac-test-files/subset/51 - Extremely large VORBISCOMMENT.flac",
"testdata/flac-test-files/subset/52 - Extremely large APPLICATION.flac",
"testdata/flac-test-files/subset/53 - CUESHEET with very many indexes.flac",
"testdata/flac-test-files/subset/54 - 1000x repeating VORBISCOMMENT.flac",
"testdata/flac-test-files/subset/55 - file 48-53 combined.flac",
"testdata/flac-test-files/subset/56 - JPG PICTURE.flac",
"testdata/flac-test-files/subset/57 - PNG PICTURE.flac",
"testdata/flac-test-files/subset/58 - GIF PICTURE.flac",
"testdata/flac-test-files/subset/59 - AVIF PICTURE.flac",
"testdata/flac-test-files/subset/60 - mono audio.flac",
"testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac",
"testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac",
"testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac",
"testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac",
}
funcs := map[string]func(io.Reader) (*flac.Stream, error){
"new": flac.New,
"newSeek": func(r io.Reader) (*flac.Stream, error) { return flac.NewSeek(r.(io.ReadSeeker)) },
"parse": flac.Parse,
}
for _, path := range paths {
for k, f := range funcs {
t.Run(fmt.Sprintf("%s/%s", k, path), func(t *testing.T) {
file, err := os.Open(path)
if err != nil {
t.Fatal(err)
}
stream, err := f(file)
if err != nil {
t.Fatal(err)
}
_, err = stream.ParseNext()
if err != nil {
t.Fatal(err)
}
file.Close()
})
}
}
}
================================================
FILE: frame/frame.go
================================================
// Package frame implements access to FLAC audio frames.
//
// A brief introduction of the FLAC audio format [1] follows. FLAC encoders
// divide the audio stream into blocks through a process called blocking [2]. A
// block contains the unencoded audio samples from all channels during a short
// period of time. Each audio block is divided into subblocks, one per channel.
//
// There is often a correlation between the left and right channel of stereo
// audio. Using inter-channel decorrelation [3] it is possible to store only one
// 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
//
// 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
package frame
import (
"encoding/binary"
"errors"
"fmt"
"hash"
"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"
)
// A Frame contains the header and subframes of an audio frame. It holds the
// encoded samples from a block (a part) of the audio stream. Each subframe
// holding the samples from one of its channel.
//
// ref: https://www.xiph.org/flac/format.html#frame
type Frame struct {
// Audio frame header.
Header
// One subframe per channel, containing encoded audio samples.
Subframes []*Subframe
// CRC-16 hash sum, calculated by read operations on hr.
crc hashutil.Hash16
// A bit reader, wrapping read operations to hr.
br *bits.Reader
// A CRC-16 hash reader, wrapping read operations to r.
hr io.Reader
// Underlying io.Reader.
r io.Reader
}
// New creates a new Frame for accessing the audio samples of r. It reads and
// parses an audio frame header. It returns io.EOF to signal a graceful end of
// FLAC stream.
//
// Call Frame.Parse to parse the audio samples of its subframes.
func New(r io.Reader) (frame *Frame, err error) {
// Create a new CRC-16 hash reader which adds the data from all read
// operations to a running hash.
crc := crc16.NewIBM()
hr := io.TeeReader(r, crc)
// Parse frame header.
frame = &Frame{crc: crc, hr: hr, r: r}
err = frame.parseHeader()
return frame, err
}
// Parse reads and parses the header, and the audio samples from each subframe
// of a frame. If the samples are inter-channel decorrelated between the
// subframes, it correlates them. It returns io.EOF to signal a graceful end of
// FLAC stream.
//
// ref: https://www.xiph.org/flac/format.html#interchannel
func Parse(r io.Reader) (frame *Frame, err error) {
// Parse frame header.
frame, err = New(r)
if err != nil {
return frame, err
}
// Parse subframes.
err = frame.Parse()
return frame, err
}
// Parse reads and parses the audio samples from each subframe of the frame. If
// the samples are inter-channel decorrelated between the subframes, it
// correlates them.
//
// ref: https://www.xiph.org/flac/format.html#interchannel
func (frame *Frame) Parse() error {
// Parse subframes.
frame.Subframes = make([]*Subframe, frame.Channels.Count())
var err error
for channel := range frame.Subframes {
// The side channel requires an extra bit per sample when using
// inter-channel decorrelation.
bps := uint(frame.BitsPerSample)
switch frame.Channels {
case ChannelsSideRight:
// channel 0 is the side channel.
if channel == 0 {
bps++
}
case ChannelsLeftSide, ChannelsMidSide:
// channel 1 is the side channel.
if channel == 1 {
bps++
}
}
// Parse subframe.
frame.Subframes[channel], err = frame.parseSubframe(frame.br, bps)
if err != nil {
return err
}
}
// Inter-channel correlation of subframe samples.
frame.Correlate()
// 2 bytes: CRC-16 checksum.
var want uint16
if err = binary.Read(frame.r, binary.BigEndian, &want); err != nil {
return unexpected(err)
}
got := frame.crc.Sum16()
if got != want {
return fmt.Errorf("frame.Frame.Parse: CRC-16 checksum mismatch; expected 0x%04X, got 0x%04X", want, got)
}
return nil
}
// Hash adds the decoded audio samples of the frame to a running MD5 hash. It
// can be used in conjunction with StreamInfo.MD5sum to verify the integrity of
// the decoded audio samples.
//
// Note: The audio samples of the frame must be decoded before calling Hash.
func (frame *Frame) Hash(md5sum hash.Hash) {
// Write decoded samples to a running MD5 hash.
bps := frame.BitsPerSample
var buf [3]byte
if len(frame.Subframes) == 0 {
return
}
// Use the length of the first subframe's samples as they should all be the same length
nsamples := len(frame.Subframes[0].Samples)
for i := 0; i < nsamples; i++ {
for _, subframe := range frame.Subframes {
sample := subframe.Samples[i]
switch {
case 1 <= bps && bps <= 8:
buf[0] = uint8(sample)
md5sum.Write(buf[:1])
case 9 <= bps && bps <= 16:
buf[0] = uint8(sample)
buf[1] = uint8(sample >> 8)
md5sum.Write(buf[:2])
case 17 <= bps && bps <= 24:
buf[0] = uint8(sample)
buf[1] = uint8(sample >> 8)
buf[2] = uint8(sample >> 16)
md5sum.Write(buf[:])
default:
log.Printf("frame.Frame.Hash: support for %d-bit sample size not yet implemented", bps)
}
}
}
}
// A Header contains the basic properties of an audio frame, such as its sample
// rate and channel count. To facilitate random access decoding each frame
// header starts with a sync-code. This allows the decoder to synchronize and
// locate the start of a frame header.
//
// ref: https://www.xiph.org/flac/format.html#frame_header
type Header struct {
// Specifies if the block size is fixed or variable.
HasFixedBlockSize bool
// Block size in inter-channel samples, i.e. the number of audio samples in
// each subframe.
BlockSize uint16
// Sample rate in Hz; a 0 value implies unknown, get sample rate from
// StreamInfo.
SampleRate uint32
// Specifies the number of channels (subframes) that exist in the frame,
// their order and possible inter-channel decorrelation.
Channels Channels
// Sample size in bits-per-sample; a 0 value implies unknown, get sample size
// from StreamInfo.
BitsPerSample uint8
// Specifies the frame number if the block size is fixed, and the first
// sample number in the frame otherwise. When using fixed block size, the
// first sample number in the frame can be derived by multiplying the frame
// number with the block size (in samples).
Num uint64
}
// Errors returned by Frame.parseHeader.
var (
ErrInvalidSync = errors.New("frame.Frame.parseHeader: invalid sync-code")
)
// parseHeader reads and parses the header of an audio frame.
func (frame *Frame) parseHeader() error {
// Create a new CRC-8 hash reader which adds the data from all read
// operations to a running hash.
h := crc8.NewATM()
hr := io.TeeReader(frame.hr, h)
// Create bit reader.
br := bits.NewReader(hr)
frame.br = br
// 14 bits: sync-code (11111111111110)
x, err := br.Read(14)
if err != nil {
// This is the only place an audio frame may return io.EOF, which signals
// a graceful end of a FLAC stream.
return err
}
if x != 0x3FFE {
return ErrInvalidSync
}
// 1 bit: reserved.
x, err = br.Read(1)
if err != nil {
return unexpected(err)
}
if x != 0 {
return errors.New("frame.Frame.parseHeader: non-zero reserved value")
}
// 1 bit: HasFixedBlockSize.
x, err = br.Read(1)
if err != nil {
return unexpected(err)
}
if x == 0 {
frame.HasFixedBlockSize = true
}
// 4 bits: BlockSize. The block size parsing is simplified by deferring it to
// the end of the header.
blockSize, err := br.Read(4)
if err != nil {
return unexpected(err)
}
// 4 bits: SampleRate. The sample rate parsing is simplified by deferring it
// to the end of the header.
sampleRate, err := br.Read(4)
if err != nil {
return unexpected(err)
}
// Parse channels.
if err := frame.parseChannels(br); err != nil {
return err
}
// Parse bits per sample.
if err := frame.parseBitsPerSample(br); err != nil {
return err
}
// 1 bit: reserved.
x, err = br.Read(1)
if err != nil {
return unexpected(err)
}
if x != 0 {
return errors.New("frame.Frame.parseHeader: non-zero reserved value")
}
// if (fixed block size)
// 1-6 bytes: UTF-8 encoded frame number.
// else
// 1-7 bytes: UTF-8 encoded sample number.
frame.Num, err = utf8.Decode(hr)
if err != nil {
return unexpected(err)
}
// Parse block size.
if err := frame.parseBlockSize(br, blockSize); err != nil {
return err
}
// Parse sample rate.
if err := frame.parseSampleRate(br, sampleRate); err != nil {
return err
}
// 1 byte: CRC-8 checksum.
var want uint8
if err = binary.Read(frame.hr, binary.BigEndian, &want); err != nil {
return unexpected(err)
}
got := h.Sum8()
if want != got {
return fmt.Errorf("frame.Frame.parseHeader: CRC-8 checksum mismatch; expected 0x%02X, got 0x%02X", want, got)
}
return nil
}
// parseBitsPerSample parses the bits per sample of the header.
func (frame *Frame) parseBitsPerSample(br *bits.Reader) error {
// 3 bits: BitsPerSample.
x, err := br.Read(3)
if err != nil {
return unexpected(err)
}
// The 3 bits are used to specify the sample size as follows:
// 000: unknown sample size; get from StreamInfo.
// 001: 8 bits-per-sample.
// 010: 12 bits-per-sample.
// 011: reserved.
// 100: 16 bits-per-sample.
// 101: 20 bits-per-sample.
// 110: 24 bits-per-sample.
// 111: reserved.
switch x {
case 0x0:
// 000: unknown bits-per-sample; get from StreamInfo.
case 0x1:
// 001: 8 bits-per-sample.
frame.BitsPerSample = 8
case 0x2:
// 010: 12 bits-per-sample.
frame.BitsPerSample = 12
case 0x4:
// 100: 16 bits-per-sample.
frame.BitsPerSample = 16
case 0x5:
// 101: 20 bits-per-sample.
frame.BitsPerSample = 20
case 0x6:
// 110: 24 bits-per-sample.
frame.BitsPerSample = 24
default:
// 011: reserved.
// 111: reserved.
return fmt.Errorf("frame.Frame.parseHeader: reserved sample size bit pattern (%03b)", x)
}
return nil
}
// parseChannels parses the channels of the header.
func (frame *Frame) parseChannels(br *bits.Reader) error {
// 4 bits: Channels.
//
// The 4 bits are used to specify the channels as follows:
// 0000: (1 channel) mono.
// 0001: (2 channels) left, right.
// 0010: (3 channels) left, right, center.
// 0011: (4 channels) left, right, left surround, right surround.
// 0100: (5 channels) left, right, center, left surround, right surround.
// 0101: (6 channels) left, right, center, LFE, left surround, right surround.
// 0110: (7 channels) left, right, center, LFE, center surround, side left, side right.
// 0111: (8 channels) left, right, center, LFE, left surround, right surround, side left, side right.
// 1000: (2 channels) left, side; using inter-channel decorrelation.
// 1001: (2 channels) side, right; using inter-channel decorrelation.
// 1010: (2 channels) mid, side; using inter-channel decorrelation.
// 1011: reserved.
// 1100: reserved.
// 1101: reserved.
// 1111: reserved.
x, err := br.Read(4)
if err != nil {
return unexpected(err)
}
if x >= 0xB {
return fmt.Errorf("frame.Frame.parseHeader: reserved channels bit pattern (%04b)", x)
}
frame.Channels = Channels(x)
return nil
}
// parseBlockSize parses the block size of the header.
func (frame *Frame) parseBlockSize(br *bits.Reader, blockSize uint64) error {
// The 4 bits of n are used to specify the block size as follows:
// 0000: reserved.
// 0001: 192 samples.
// 0010-0101: 576 * 2^(n-2) samples.
// 0110: get 8 bit (block size)-1 from the end of the header.
// 0111: get 16 bit (block size)-1 from the end of the header.
// 1000-1111: 256 * 2^(n-8) samples.
n := blockSize
switch {
case n == 0x0:
// 0000: reserved.
return errors.New("frame.Frame.parseHeader: reserved block size bit pattern (0000)")
case n == 0x1:
// 0001: 192 samples.
frame.BlockSize = 192
case n >= 0x2 && n <= 0x5:
// 0010-0101: 576 * 2^(n-2) samples.
frame.BlockSize = 576 * (1 << (n - 2))
case n == 0x6:
// 0110: get 8 bit (block size)-1 from the end of the header.
x, err := br.Read(8)
if err != nil {
return unexpected(err)
}
frame.BlockSize = uint16(x + 1)
case n == 0x7:
// 0111: get 16 bit (block size)-1 from the end of the header.
x, err := br.Read(16)
if err != nil {
return unexpected(err)
}
frame.BlockSize = uint16(x + 1)
default:
// 1000-1111: 256 * 2^(n-8) samples.
frame.BlockSize = 256 * (1 << (n - 8))
}
return nil
}
// parseSampleRate parses the sample rate of the header.
func (frame *Frame) parseSampleRate(br *bits.Reader, sampleRate uint64) error {
// The 4 bits are used to specify the sample rate as follows:
// 0000: unknown sample rate; get from StreamInfo.
// 0001: 88.2 kHz.
// 0010: 176.4 kHz.
// 0011: 192 kHz.
// 0100: 8 kHz.
// 0101: 16 kHz.
// 0110: 22.05 kHz.
// 0111: 24 kHz.
// 1000: 32 kHz.
// 1001: 44.1 kHz.
// 1010: 48 kHz.
// 1011: 96 kHz.
// 1100: get 8 bit sample rate (in kHz) from the end of the header.
// 1101: get 16 bit sample rate (in Hz) from the end of the header.
// 1110: get 16 bit sample rate (in daHz) from the end of the header.
// 1111: invalid.
switch sampleRate {
case 0x0:
// 0000: unknown sample rate; get from StreamInfo.
case 0x1:
// 0001: 88.2 kHz.
frame.SampleRate = 88200
case 0x2:
// 0010: 176.4 kHz.
frame.SampleRate = 176400
// TODO(u): Remove log message when the test cases have been extended.
log.Printf("frame.Frame.parseHeader: The flac library test cases do not yet include any audio files with sample rate %d. If possible please consider contributing this audio sample to improve the reliability of the test cases.", frame.SampleRate)
case 0x3:
// 0011: 192 kHz.
frame.SampleRate = 192000
case 0x4:
// 0100: 8 kHz.
frame.SampleRate = 8000
case 0x5:
// 0101: 16 kHz.
frame.SampleRate = 16000
case 0x6:
// 0110: 22.05 kHz.
frame.SampleRate = 22050
case 0x7:
// 0111: 24 kHz.
frame.SampleRate = 24000
// TODO(u): Remove log message when the test cases have been extended.
log.Printf("frame.Frame.parseHeader: The flac library test cases do not yet include any audio files with sample rate %d. If possible please consider contributing this audio sample to improve the reliability of the test cases.", frame.SampleRate)
case 0x8:
// 1000: 32 kHz.
frame.SampleRate = 32000
case 0x9:
// 1001: 44.1 kHz.
frame.SampleRate = 44100
case 0xA:
// 1010: 48 kHz.
frame.SampleRate = 48000
case 0xB:
// 1011: 96 kHz.
frame.SampleRate = 96000
case 0xC:
// 1100: get 8 bit sample rate (in kHz) from the end of the header.
x, err := br.Read(8)
if err != nil {
return unexpected(err)
}
frame.SampleRate = uint32(x * 1000)
case 0xD:
// 1101: get 16 bit sample rate (in Hz) from the end of the header.
x, err := br.Read(16)
if err != nil {
return unexpected(err)
}
frame.SampleRate = uint32(x)
case 0xE:
// 1110: get 16 bit sample rate (in daHz) from the end of the header.
x, err := br.Read(16)
if err != nil {
return unexpected(err)
}
frame.SampleRate = uint32(x * 10)
default:
// 1111: invalid.
return errors.New("frame.Frame.parseHeader: invalid sample rate bit pattern (1111)")
}
return nil
}
// Channels specifies the number of channels (subframes) that exist in a frame,
// their order and possible inter-channel decorrelation.
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)
//
// The first 6 channel constants follow the SMPTE/ITU-R channel order:
//
// L R C Lfe Ls Rs
const (
ChannelsMono Channels = iota // 1 channel: mono.
ChannelsLR // 2 channels: left, right.
ChannelsLRC // 3 channels: left, right, center.
ChannelsLRLsRs // 4 channels: left, right, left surround, right surround.
ChannelsLRCLsRs // 5 channels: left, right, center, left surround, right surround.
ChannelsLRCLfeLsRs // 6 channels: left, right, center, LFE, left surround, right surround.
ChannelsLRCLfeCsSlSr // 7 channels: left, right, center, LFE, center surround, side left, side right.
ChannelsLRCLfeLsRsSlSr // 8 channels: left, right, center, LFE, left surround, right surround, side left, side right.
ChannelsLeftSide // 2 channels: left, side; using inter-channel decorrelation.
ChannelsSideRight // 2 channels: side, right; using inter-channel decorrelation.
ChannelsMidSide // 2 channels: mid, side; using inter-channel decorrelation.
)
// nChannels specifies the number of channels used by each channel assignment.
var nChannels = [...]int{
ChannelsMono: 1,
ChannelsLR: 2,
ChannelsLRC: 3,
ChannelsLRLsRs: 4,
ChannelsLRCLsRs: 5,
ChannelsLRCLfeLsRs: 6,
ChannelsLRCLfeCsSlSr: 7,
ChannelsLRCLfeLsRsSlSr: 8,
ChannelsLeftSide: 2,
ChannelsSideRight: 2,
ChannelsMidSide: 2,
}
// Count returns the number of channels (subframes) used by the provided channel
// assignment.
func (channels Channels) Count() int {
return nChannels[channels]
}
// Correlate reverts any inter-channel decorrelation between the samples of the
// subframes.
//
// An encoder decorrelates audio samples as follows:
//
// mid = (left + right)/2
// side = left - right
func (frame *Frame) Correlate() {
switch frame.Channels {
case ChannelsLeftSide:
// 2 channels: left, side; using inter-channel decorrelation.
left := frame.Subframes[0].Samples
side := frame.Subframes[1].Samples
for i := range side {
// right = left - side
side[i] = left[i] - side[i]
}
case ChannelsSideRight:
// 2 channels: side, right; using inter-channel decorrelation.
side := frame.Subframes[0].Samples
right := frame.Subframes[1].Samples
for i := range side {
// left = right + side
side[i] = right[i] + side[i]
}
case ChannelsMidSide:
// 2 channels: mid, side; using inter-channel decorrelation.
mid := frame.Subframes[0].Samples
side := frame.Subframes[1].Samples
for i := range side {
// left = (2*mid + side)/2
// right = (2*mid - side)/2
m := mid[i]
s := side[i]
m *= 2
// Notice that the integer division in mid = (left + right)/2 discards
// the least significant bit. It can be reconstructed however, since a
// sum A+B and a difference A-B has the same least significant bit.
//
// ref: Data Compression: The Complete Reference (ch. 7, Decorrelation)
m |= s & 1
mid[i] = (m + s) / 2
side[i] = (m - s) / 2
}
}
}
// Decorrelate performs inter-channel decorrelation between the samples of the
// subframes.
//
// An encoder decorrelates audio samples as follows:
//
// mid = (left + right)/2
// side = left - right
func (frame *Frame) Decorrelate() {
switch frame.Channels {
case ChannelsLeftSide:
// 2 channels: left, side; using inter-channel decorrelation.
left := frame.Subframes[0].Samples // already left; no change after inter-channel decorrelation.
right := frame.Subframes[1].Samples // set to side after inter-channel decorrelation.
for i := range left {
l := left[i]
r := right[i]
// inter-channel decorrelation:
// side = left - right
side := l - r
right[i] = side
}
case ChannelsSideRight:
// 2 channels: side, right; using inter-channel decorrelation.
left := frame.Subframes[0].Samples // set to side after inter-channel decorrelation.
right := frame.Subframes[1].Samples // already right; no change after inter-channel decorrelation.
for i := range left {
l := left[i]
r := right[i]
// inter-channel decorrelation:
// side = left - right
side := l - r
left[i] = side
}
case ChannelsMidSide:
// 2 channels: mid, side; using inter-channel decorrelation.
left := frame.Subframes[0].Samples // set to mid after inter-channel decorrelation.
right := frame.Subframes[1].Samples // set to side after inter-channel decorrelation.
for i := range left {
// inter-channel decorrelation:
// mid = (left + right)/2
// side = left - right
l := left[i]
r := right[i]
mid := int32((int64(l) + int64(r)) >> 1) // NOTE: using `(left + right) >> 1`, not the same as `(left + right) / 2`.
side := l - r
left[i] = mid
right[i] = side
}
}
}
// SampleNumber returns the first sample number contained within the frame.
func (frame *Frame) SampleNumber() uint64 {
if frame.HasFixedBlockSize {
return frame.Num * uint64(frame.BlockSize)
}
return frame.Num
}
// unexpected returns io.ErrUnexpectedEOF if err is io.EOF, and returns err
// otherwise.
func unexpected(err error) error {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
================================================
FILE: frame/frame_test.go
================================================
package frame_test
import (
"bytes"
"crypto/md5"
"io"
"testing"
"github.com/mewkiz/flac"
)
var golden = []struct {
path string
}{
{path: "../testdata/love.flac"},
{path: "../testdata/19875.flac"},
{path: "../testdata/44127.flac"},
{path: "../testdata/59996.flac"},
{path: "../testdata/80574.flac"},
{path: "../testdata/172960.flac"},
{path: "../testdata/189983.flac"},
{path: "../testdata/191885.flac"},
{path: "../testdata/212768.flac"},
{path: "../testdata/220014.flac"},
{path: "../testdata/243749.flac"},
{path: "../testdata/256529.flac"},
{path: "../testdata/257344.flac"},
// IETF test cases.
{path: "../testdata/flac-test-files/subset/01 - blocksize 4096.flac"},
{path: "../testdata/flac-test-files/subset/02 - blocksize 4608.flac"},
{path: "../testdata/flac-test-files/subset/03 - blocksize 16.flac"},
{path: "../testdata/flac-test-files/subset/04 - blocksize 192.flac"},
{path: "../testdata/flac-test-files/subset/05 - blocksize 254.flac"},
{path: "../testdata/flac-test-files/subset/06 - blocksize 512.flac"},
{path: "../testdata/flac-test-files/subset/07 - blocksize 725.flac"},
{path: "../testdata/flac-test-files/subset/08 - blocksize 1000.flac"},
{path: "../testdata/flac-test-files/subset/09 - blocksize 1937.flac"},
{path: "../testdata/flac-test-files/subset/10 - blocksize 2304.flac"},
{path: "../testdata/flac-test-files/subset/11 - partition order 8.flac"},
{path: "../testdata/flac-test-files/subset/12 - qlp precision 15 bit.flac"},
{path: "../testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac"},
{path: "../testdata/flac-test-files/subset/14 - wasted bits.flac"},
{path: "../testdata/flac-test-files/subset/15 - only verbatim subframes.flac"},
{path: "../testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac"},
{path: "../testdata/flac-test-files/subset/17 - all fixed orders.flac"},
{path: "../testdata/flac-test-files/subset/18 - precision search.flac"},
{path: "../testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac"},
{path: "../testdata/flac-test-files/subset/20 - samplerate 39kHz.flac"},
{path: "../testdata/flac-test-files/subset/21 - samplerate 22050Hz.flac"},
{path: "../testdata/flac-test-files/subset/22 - 12 bit per sample.flac"},
{path: "../testdata/flac-test-files/subset/23 - 8 bit per sample.flac"},
{path: "../testdata/flac-test-files/subset/24 - variable blocksize file created with flake revision 264.flac"},
{path: "../testdata/flac-test-files/subset/25 - variable blocksize file created with flake revision 264, modified to create smaller blocks.flac"},
{path: "../testdata/flac-test-files/subset/26 - variable blocksize file created with CUETools.Flake 2.1.6.flac"},
{path: "../testdata/flac-test-files/subset/27 - old format variable blocksize file created with Flake 0.11.flac"},
{path: "../testdata/flac-test-files/subset/28 - high resolution audio, default settings.flac"},
{path: "../testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac"},
{path: "../testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac"},
{path: "../testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac"},
{path: "../testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac"},
{path: "../testdata/flac-test-files/subset/33 - samplerate 192kHz.flac"},
{path: "../testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac"},
{path: "../testdata/flac-test-files/subset/35 - samplerate 134560Hz.flac"},
{path: "../testdata/flac-test-files/subset/36 - samplerate 384kHz.flac"},
{path: "../testdata/flac-test-files/subset/37 - 20 bit per sample.flac"},
{path: "../testdata/flac-test-files/subset/38 - 3 channels (3.0).flac"},
{path: "../testdata/flac-test-files/subset/39 - 4 channels (4.0).flac"},
{path: "../testdata/flac-test-files/subset/40 - 5 channels (5.0).flac"},
{path: "../testdata/flac-test-files/subset/41 - 6 channels (5.1).flac"},
{path: "../testdata/flac-test-files/subset/42 - 7 channels (6.1).flac"},
{path: "../testdata/flac-test-files/subset/43 - 8 channels (7.1).flac"},
{path: "../testdata/flac-test-files/subset/44 - 8-channel surround, 192kHz, 24 bit, using only 32nd order predictors.flac"},
{path: "../testdata/flac-test-files/subset/45 - no total number of samples set.flac"},
{path: "../testdata/flac-test-files/subset/46 - no min-max framesize set.flac"},
{path: "../testdata/flac-test-files/subset/47 - only STREAMINFO.flac"},
{path: "../testdata/flac-test-files/subset/48 - Extremely large SEEKTABLE.flac"},
{path: "../testdata/flac-test-files/subset/49 - Extremely large PADDING.flac"},
{path: "../testdata/flac-test-files/subset/50 - Extremely large PICTURE.flac"},
{path: "../testdata/flac-test-files/subset/51 - Extremely large VORBISCOMMENT.flac"},
{path: "../testdata/flac-test-files/subset/52 - Extremely large APPLICATION.flac"},
{path: "../testdata/flac-test-files/subset/53 - CUESHEET with very many indexes.flac"},
{path: "../testdata/flac-test-files/subset/54 - 1000x repeating VORBISCOMMENT.flac"},
{path: "../testdata/flac-test-files/subset/55 - file 48-53 combined.flac"},
{path: "../testdata/flac-test-files/subset/56 - JPG PICTURE.flac"},
{path: "../testdata/flac-test-files/subset/57 - PNG PICTURE.flac"},
{path: "../testdata/flac-test-files/subset/58 - GIF PICTURE.flac"},
{path: "../testdata/flac-test-files/subset/59 - AVIF PICTURE.flac"},
{path: "../testdata/flac-test-files/subset/60 - mono audio.flac"},
{path: "../testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac"},
{path: "../testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac"},
// TODO: fix decoding of "subset/63 - ...flac": MD5 checksum mismatch for decoded audio samples; expected e4e4a6b3a672a849a3e2157c11ad23c6, got a0343afaaaa6229266d78ccf3175eb8d
{path: "../testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac"},
{path: "../testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac"},
}
func TestFrameHash(t *testing.T) {
var zeroHash [md5.Size]byte
for _, g := range golden {
t.Run(g.path, func(t *testing.T) {
stream, err := flac.Open(g.path)
if err != nil {
t.Fatal(err)
}
defer stream.Close()
// Skip frame hash test if no MD5 hash was set in StreamInfo.
want := stream.Info.MD5sum[:]
if bytes.Equal(want, zeroHash[:]) {
t.Skipf("path=%q, skipping frame hash test as no MD5 hash was set in StreamInfo", g.path)
return
}
md5sum := md5.New()
for frameNum := 0; ; frameNum++ {
frame, err := stream.ParseNext()
if err != nil {
if err == io.EOF {
break
}
t.Errorf("path=%q, frameNum=%d: error while parsing frame; %v", g.path, frameNum, err)
continue
}
frame.Hash(md5sum)
}
got := md5sum.Sum(nil)
// Verify the decoded audio samples by comparing the MD5 checksum that is
// stored in StreamInfo with the computed one.
if !bytes.Equal(got, want) {
t.Errorf("path=%q: MD5 checksum mismatch for decoded audio samples; expected %32x, got %32x", g.path, want, got)
}
})
}
}
func BenchmarkFrameParse(b *testing.B) {
// The file 151185.flac is a 119.5 MB public domain FLAC file used to
// benchmark the flac library. Because of its size, it has not been included
// in the repository, but is available for download at
//
// http://freesound.org/people/jarfil/sounds/151185/
for i := 0; i < b.N; i++ {
stream, err := flac.Open("../testdata/benchmark/151185.flac")
if err != nil {
b.Fatal(err)
}
for {
_, err := stream.ParseNext()
if err != nil {
if err == io.EOF {
break
}
stream.Close()
b.Fatal(err)
}
}
stream.Close()
}
}
func BenchmarkFrameHash(b *testing.B) {
// The file 151185.flac is a 119.5 MB public domain FLAC file used to
// benchmark the flac library. Because of its size, it has not been included
// in the repository, but is available for download at
//
// http://freesound.org/people/jarfil/sounds/151185/
for i := 0; i < b.N; i++ {
stream, err := flac.Open("../testdata/benchmark/151185.flac")
if err != nil {
b.Fatal(err)
}
md5sum := md5.New()
for {
frame, err := stream.ParseNext()
if err != nil {
if err == io.EOF {
break
}
stream.Close()
b.Fatal(err)
}
frame.Hash(md5sum)
}
stream.Close()
want := stream.Info.MD5sum[:]
got := md5sum.Sum(nil)
// Verify the decoded audio samples by comparing the MD5 checksum that is
// stored in StreamInfo with the computed one.
if !bytes.Equal(got, want) {
b.Fatalf("MD5 checksum mismatch for decoded audio samples; expected %32x, got %32x", want, got)
}
}
}
================================================
FILE: frame/subframe.go
================================================
package frame
import (
"errors"
"fmt"
"github.com/mewkiz/flac/internal/bits"
)
// A Subframe contains the encoded audio samples from one channel of an audio
// block (a part of the audio stream).
//
// ref: https://www.xiph.org/flac/format.html#subframe
type Subframe struct {
// Subframe header.
SubHeader
// Unencoded audio samples. Samples is initially nil, and gets populated by a
// call to Frame.Parse.
//
// Samples is used by decodeFixed and decodeFIR to temporarily store
// residuals. Before returning they call decodeLPC which decodes the audio
// samples.
Samples []int32
// Number of audio samples in the subframe.
NSamples int
}
// parseSubframe reads and parses the header, and the audio samples of a
// subframe.
func (frame *Frame) parseSubframe(br *bits.Reader, bps uint) (subframe *Subframe, err error) {
// Parse subframe header.
subframe = new(Subframe)
if err = subframe.parseHeader(br); err != nil {
return subframe, err
}
// Adjust bps of subframe for wasted bits-per-sample.
bps -= subframe.Wasted
// Decode subframe audio samples.
subframe.NSamples = int(frame.BlockSize)
subframe.Samples = make([]int32, 0, subframe.NSamples)
switch subframe.Pred {
case PredConstant:
err = subframe.decodeConstant(br, bps)
case PredVerbatim:
err = subframe.decodeVerbatim(br, bps)
case PredFixed:
err = subframe.decodeFixed(br, bps)
case PredFIR:
err = subframe.decodeFIR(br, bps)
}
// Left shift to account for wasted bits-per-sample.
for i, sample := range subframe.Samples {
subframe.Samples[i] = sample << subframe.Wasted
}
return subframe, err
}
// A SubHeader specifies the prediction method and order of a subframe.
//
// ref: https://www.xiph.org/flac/format.html#subframe_header
type SubHeader struct {
// Specifies the prediction method used to encode the audio sample of the
// subframe.
Pred Pred
// Prediction order used by fixed and FIR linear prediction decoding.
Order int
// Wasted bits-per-sample.
Wasted uint
// Residual coding method used by fixed and FIR linear prediction decoding.
ResidualCodingMethod ResidualCodingMethod
// Coefficients' precision in bits used by FIR linear prediction decoding.
CoeffPrec uint
// Predictor coefficient shift needed in bits used by FIR linear prediction
// decoding.
CoeffShift int32
// Predictor coefficients used by FIR linear prediction decoding.
Coeffs []int32
// Rice-coding subframe fields used by residual coding methods rice1 and
// rice2; nil if unused.
RiceSubframe *RiceSubframe
}
// RiceSubframe holds rice-coding subframe fields used by residual coding
// methods rice1 and rice2.
type RiceSubframe struct {
// Partition order used by fixed and FIR linear prediction decoding
// (for residual coding methods, rice1 and rice2).
PartOrder int // TODO: remove PartOrder and infer from int(math.Log2(float64(len(Partitions))))?
// Rice partitions.
Partitions []RicePartition
}
// RicePartition is a partition containing a subset of the residuals of a
// subframe.
type RicePartition struct {
// Rice parameter.
Param uint
// Residual sample size in bits-per-sample used by escaped partitions.
EscapedBitsPerSample uint
}
// parseHeader reads and parses the header of a subframe.
func (subframe *Subframe) parseHeader(br *bits.Reader) error {
// 1 bit: zero-padding.
x, err := br.Read(1)
if err != nil {
return unexpected(err)
}
if x != 0 {
return errors.New("frame.Subframe.parseHeader: non-zero padding")
}
// 6 bits: Pred.
x, err = br.Read(6)
if err != nil {
return unexpected(err)
}
// The 6 bits are used to specify the prediction method and order as follows:
// 000000: Constant prediction method.
// 000001: Verbatim prediction method.
// 00001x: reserved.
// 0001xx: reserved.
// 001xxx:
// if (xxx <= 4)
// Fixed prediction method; xxx=order
// else
// reserved.
// 01xxxx: reserved.
// 1xxxxx: FIR prediction method; xxxxx=order-1
switch {
case x < 1:
// 000000: Constant prediction method.
subframe.Pred = PredConstant
case x < 2:
// 000001: Verbatim prediction method.
subframe.Pred = PredVerbatim
case x < 8:
// 00001x: reserved.
// 0001xx: reserved.
return fmt.Errorf("frame.Subframe.parseHeader: reserved prediction method bit pattern (%06b)", x)
case x < 16:
// 001xxx:
// if (xxx <= 4)
// Fixed prediction method; xxx=order
// else
// reserved.
order := int(x & 0x07)
if order > 4 {
return fmt.Errorf("frame.Subframe.parseHeader: reserved prediction method bit pattern (%06b)", x)
}
subframe.Pred = PredFixed
subframe.Order = order
case x < 32:
// 01xxxx: reserved.
return fmt.Errorf("frame.Subframe.parseHeader: reserved prediction method bit pattern (%06b)", x)
default:
// 1xxxxx: FIR prediction method; xxxxx=order-1
subframe.Pred = PredFIR
subframe.Order = int(x&0x1F) + 1
}
// 1 bit: hasWastedBits.
x, err = br.Read(1)
if err != nil {
return unexpected(err)
}
if x != 0 {
// k wasted bits-per-sample in source subblock, k-1 follows, unary coded;
// e.g. k=3 => 001 follows, k=7 => 0000001 follows.
x, err = br.ReadUnary()
if err != nil {
return unexpected(err)
}
subframe.Wasted = uint(x) + 1
}
return nil
}
// Pred specifies the prediction method used to encode the audio samples of a
// subframe.
type Pred uint8
// Prediction methods.
const (
// PredConstant specifies that the subframe contains a constant sound. The
// audio samples are encoded using run-length encoding. Since every audio
// sample has the same constant value, a single unencoded audio sample is
// stored in practice. It is replicated a number of times, as specified by
// BlockSize in the frame header.
PredConstant Pred = iota
// PredVerbatim specifies that the subframe contains unencoded audio samples.
// Random sound is often stored verbatim, since no prediction method can
// compress it sufficiently.
PredVerbatim
// PredFixed specifies that the subframe contains linear prediction coded
// audio samples. The coefficients of the prediction polynomial are selected
// from a fixed set, and can represent 0th through fourth-order polynomials.
// The prediction order (0 through 4) is stored within the subframe along
// with the same number of unencoded warm-up samples, which are used to kick
// start the prediction polynomial. The remainder of the subframe stores
// encoded residuals (signal errors) which specify the difference between the
// predicted and the original audio samples.
PredFixed
// PredFIR specifies that the subframe contains linear prediction coded audio
// samples. The coefficients of the prediction polynomial are stored in the
// subframe, and can represent 0th through 32nd-order polynomials. The
// prediction order (0 through 32) is stored within the subframe along with
// the same number of unencoded warm-up samples, which are used to kick start
// the prediction polynomial. The remainder of the subframe stores encoded
// residuals (signal errors) which specify the difference between the
// predicted and the original audio samples.
PredFIR
)
// signExtend interprets x as a signed n-bit integer value and sign extends it
// to 32 bits.
func signExtend(x uint64, n uint) int32 {
// x is signed if its most significant bit is set.
if x&(1<<(n-1)) != 0 {
// Sign extend x.
return int32(x | ^uint64(0)<<n)
}
return int32(x)
}
// decodeConstant reads an unencoded audio sample of the subframe. Each sample
// of the subframe has this constant value. The constant encoding can be thought
// of as run-length encoding.
//
// ref: https://www.xiph.org/flac/format.html#subframe_constant
func (subframe *Subframe) decodeConstant(br *bits.Reader, bps uint) error {
// (bits-per-sample) bits: Unencoded constant value of the subblock.
x, err := br.Read(bps)
if err != nil {
return unexpected(err)
}
// Each sample of the subframe has the same constant value.
sample := signExtend(x, bps)
for i := 0; i < subframe.NSamples; i++ {
subframe.Samples = append(subframe.Samples, sample)
}
return nil
}
// decodeVerbatim reads the unencoded audio samples of the subframe.
//
// ref: https://www.xiph.org/flac/format.html#subframe_verbatim
func (subframe *Subframe) decodeVerbatim(br *bits.Reader, bps uint) error {
// Parse the unencoded audio samples of the subframe.
for i := 0; i < subframe.NSamples; i++ {
// (bits-per-sample) bits: Unencoded constant value of the subblock.
x, err := br.Read(bps)
if err != nil {
return unexpected(err)
}
sample := signExtend(x, bps)
subframe.Samples = append(subframe.Samples, sample)
}
return nil
}
// 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]
var FixedCoeffs = [...][]int32{
// ref: Section 2.2 of http://www.hpl.hp.com/techreports/1999/HPL-1999-144.pdf
1: {1},
2: {2, -1},
3: {3, -3, 1},
// ref: Data Compression: The Complete Reference (7.10.1)
4: {4, -6, 4, -1},
}
// decodeFixed decodes the linear prediction coded samples of the subframe,
// using a fixed set of predefined polynomial coefficients.
//
// ref: https://www.xiph.org/flac/format.html#subframe_fixed
func (subframe *Subframe) decodeFixed(br *bits.Reader, bps uint) error {
// Parse unencoded warm-up samples.
for i := 0; i < subframe.Order; i++ {
// (bits-per-sample) bits: Unencoded warm-up sample.
x, err := br.Read(bps)
if err != nil {
return unexpected(err)
}
sample := signExtend(x, bps)
subframe.Samples = append(subframe.Samples, sample)
}
// Decode subframe residuals.
if err := subframe.decodeResiduals(br); err != nil {
return err
}
// Predict the audio samples of the subframe using a polynomial with
// predefined coefficients of a given order. Correct signal errors using the
// decoded residuals.
const shift = 0
return subframe.decodeLPC(FixedCoeffs[subframe.Order], shift)
}
// decodeFIR decodes the linear prediction coded samples of the subframe, using
// polynomial coefficients stored in the stream.
//
// ref: https://www.xiph.org/flac/format.html#subframe_lpc
func (subframe *Subframe) decodeFIR(br *bits.Reader, bps uint) error {
// Parse unencoded warm-up samples.
for i := 0; i < subframe.Order; i++ {
// (bits-per-sample) bits: Unencoded warm-up sample.
x, err := br.Read(bps)
if err != nil {
return unexpected(err)
}
sample := signExtend(x, bps)
subframe.Samples = append(subframe.Samples, sample)
}
// 4 bits: (coefficients' precision in bits) - 1.
x, err := br.Read(4)
if err != nil {
return unexpected(err)
}
if x == 0xF {
return errors.New("frame.Subframe.decodeFIR: invalid coefficient precision bit pattern (1111)")
}
prec := uint(x) + 1
subframe.CoeffPrec = prec
// 5 bits: predictor coefficient shift needed in bits.
x, err = br.Read(5)
if err != nil {
return unexpected(err)
}
shift := signExtend(x, 5)
subframe.CoeffShift = shift
// Parse coefficients.
coeffs := make([]int32, subframe.Order)
for i := range coeffs {
// (prec) bits: Predictor coefficient.
x, err = br.Read(prec)
if err != nil {
return unexpected(err)
}
coeffs[i] = signExtend(x, prec)
}
subframe.Coeffs = coeffs
// Decode subframe residuals.
if err := subframe.decodeResiduals(br); err != nil {
return err
}
// Predict the audio samples of the subframe using a polynomial with
// predefined coefficients of a given order. Correct signal errors using the
// decoded residuals.
return subframe.decodeLPC(coeffs, shift)
}
// ResidualCodingMethod specifies a residual coding method.
type ResidualCodingMethod uint8
// Residual coding methods.
const (
// Rice coding with a 4-bit Rice parameter (rice1).
ResidualCodingMethodRice1 ResidualCodingMethod = 0
// Rice coding with a 5-bit Rice parameter (rice2).
ResidualCodingMethodRice2 ResidualCodingMethod = 1
)
// decodeResiduals decodes the encoded residuals (prediction method error
// signals) of the subframe.
//
// ref: https://www.xiph.org/flac/format.html#residual
func (subframe *Subframe) decodeResiduals(br *bits.Reader) error {
// 2 bits: Residual coding method.
x, err := br.Read(2)
if err != nil {
return unexpected(err)
}
residualCodingMethod := ResidualCodingMethod(x)
subframe.ResidualCodingMethod = residualCodingMethod
// The 2 bits are used to specify the residual coding method as follows:
// 00: Rice coding with a 4-bit Rice parameter.
// 01: Rice coding with a 5-bit Rice parameter.
// 10: reserved.
// 11: reserved.
switch residualCodingMethod {
case 0x0:
return subframe.decodeRicePart(br, 4)
case 0x1:
return subframe.decodeRicePart(br, 5)
default:
return fmt.Errorf("frame.Subframe.decodeResiduals: reserved residual coding method bit pattern (%02b)", uint8(residualCodingMethod))
}
}
// decodeRicePart decodes a Rice partition of encoded residuals from the
// subframe, using a Rice parameter of the specified size in bits.
//
// ref: https://www.xiph.org/flac/format.html#partitioned_rice
// ref: https://www.xiph.org/flac/format.html#partitioned_rice2
func (subframe *Subframe) decodeRicePart(br *bits.Reader, paramSize uint) error {
// 4 bits: Partition order.
x, err := br.Read(4)
if err != nil {
return unexpected(err)
}
partOrder := int(x)
riceSubframe := &RiceSubframe{
PartOrder: partOrder,
}
subframe.RiceSubframe = riceSubframe
// Parse Rice partitions; in total 2^partOrder partitions.
//
// ref: https://www.xiph.org/flac/format.html#rice_partition
// ref: https://www.xiph.org/flac/format.html#rice2_partition
nparts := 1 << partOrder
partitions := make([]RicePartition, nparts)
riceSubframe.Partitions = partitions
for i := 0; i < nparts; i++ {
partition := &partitions[i]
// (4 or 5) bits: Rice parameter.
x, err = br.Read(paramSize)
if err != nil {
return unexpected(err)
}
param := uint(x)
partition.Param = param
// Determine the number of Rice encoded samples in the partition.
var nsamples int
if partOrder == 0 {
nsamples = subframe.NSamples - subframe.Order
} else if i != 0 {
nsamples = subframe.NSamples / nparts
} else {
nsamples = subframe.NSamples/nparts - subframe.Order
}
if paramSize == 4 && param == 0xF || paramSize == 5 && param == 0x1F {
// 1111 or 11111: Escape code, meaning the partition is in unencoded
// binary form using n bits per sample; n follows as a 5-bit number.
x, err := br.Read(5)
if err != nil {
return unexpected(err)
}
n := uint(x)
partition.EscapedBitsPerSample = n
for j := 0; j < nsamples; j++ {
sample, err := br.Read(n)
if err != nil {
return unexpected(err)
}
// ref: https://datatracker.ietf.org/doc/draft-ietf-cellar-flac/
//
// From section 9.2.7.1. Escaped partition:
//
// The residual samples themselves are stored signed two's
// complement. For example, when a partition is escaped and each
// residual sample is stored with 3 bits, the number -1 is
// represented as 0b111.
subframe.Samples = append(subframe.Samples, int32(bits.IntN(sample, n)))
}
continue
}
// Decode the Rice encoded residuals of the partition.
for j := 0; j < nsamples; j++ {
residual, err := subframe.decodeRiceResidual(br, param)
if err != nil {
return err
}
subframe.Samples = append(subframe.Samples, residual)
}
}
return nil
}
// decodeRiceResidual decodes and returns a Rice encoded residual (error
// signal).
func (subframe *Subframe) decodeRiceResidual(br *bits.Reader, k uint) (int32, error) {
// Read unary encoded most significant bits.
high, err := br.ReadUnary()
if err != nil {
return 0, unexpected(err)
}
// Read binary encoded least significant bits.
low, err := br.Read(k)
if err != nil {
return 0, unexpected(err)
}
folded := uint32(high<<k | low)
// ZigZag decode.
residual := bits.DecodeZigZag(folded)
return residual, nil
}
// decodeLPC decodes linear prediction coded audio samples, using the
// coefficients of a given polynomial, a couple of unencoded warm-up samples,
// and the signal errors of the prediction as specified by the residuals.
func (subframe *Subframe) decodeLPC(coeffs []int32, shift int32) error {
if len(coeffs) != subframe.Order {
return fmt.Errorf("frame.Subframe.decodeLPC: prediction order (%d) differs from number of coefficients (%d)", subframe.Order, len(coeffs))
}
if shift < 0 {
return fmt.Errorf("frame.Subframe.decodeLPC: invalid negative shift")
}
if subframe.NSamples != len(subframe.Samples) {
return fmt.Errorf("frame.Subframe.decodeLPC: subframe sample count mismatch; expected %d, got %d", subframe.NSamples, len(subframe.Samples))
}
for i := subframe.Order; i < subframe.NSamples; i++ {
var sample int64
for j, c := range coeffs {
sample += int64(c) * int64(subframe.Samples[i-j-1])
}
subframe.Samples[i] += int32(sample >> uint(shift))
}
return nil
}
================================================
FILE: go.mod
================================================
module github.com/mewkiz/flac
go 1.23.2
toolchain go1.24.5
require (
github.com/icza/bitio v1.1.0
github.com/mewkiz/pkg v0.0.0-20250417130911-3f050ff8c56d
)
require github.com/mewpkg/term v0.0.0-20241026122259-37a80af23985 // indirect
================================================
FILE: go.sum
================================================
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-20250417130911-3f050ff8c56d h1:IL2tii4jXLdhCeQN69HNzYYW1kl0meSG0wt5+sLwszU=
github.com/mewkiz/pkg v0.0.0-20250417130911-3f050ff8c56d/go.mod h1:SIpumAnUWSy0q9RzKD3pyH3g1t5vdawUAPcW5tQrUtI=
github.com/mewpkg/term v0.0.0-20241026122259-37a80af23985 h1:h8O1byDZ1uk6RUXMhj1QJU3VXFKXHDZxr4TXRPGeBa8=
github.com/mewpkg/term v0.0.0-20241026122259-37a80af23985/go.mod h1:uiPmbdUbdt1NkGApKl7htQjZ8S7XaGUAVulJUJ9v6q4=
================================================
FILE: internal/bits/reader.go
================================================
// Package bits provides bit access operations and binary decoding algorithms.
package bits
import (
"fmt"
"io"
)
// A Reader handles bit reading operations. It buffers bits up to the next byte
// boundary.
type Reader struct {
// Underlying reader.
r io.Reader
// Temporary read buffer.
buf [8]uint8
// Between 0 and 7 buffered bits since previous read operations.
x uint8
// The number of buffered bits in x.
n uint
}
// NewReader returns a new Reader that reads bits from r.
func NewReader(r io.Reader) *Reader {
return &Reader{r: r}
}
// Read reads and returns the next n bits, at most 64. It buffers bits up to the
// next byte boundary.
func (br *Reader) Read(n uint) (x uint64, err error) {
if n == 0 {
return 0, nil
}
if n > 64 {
return 0, fmt.Errorf("bit.Reader.Read: invalid number of bits; n (%d) exceeds 64", n)
}
// Read buffered bits.
if br.n > 0 {
switch {
case br.n == n:
br.n = 0
return uint64(br.x), nil
case br.n > n:
br.n -= n
mask := ^uint8(0) << br.n
x = uint64(br.x&mask) >> br.n
br.x &^= mask
return x, nil
}
n -= br.n
x = uint64(br.x)
br.n = 0
}
// Fill the temporary buffer.
bytes := n / 8
bits := n % 8
if bits > 0 {
bytes++
}
_, err = io.ReadFull(br.r, br.buf[:bytes])
if err != nil {
return 0, err
}
// Read bits from the temporary buffer.
for _, b := range br.buf[:bytes-1] {
x <<= 8
x |= uint64(b)
}
b := br.buf[bytes-1]
if bits > 0 {
x <<= bits
br.n = 8 - bits
mask := ^uint8(0) << br.n
x |= uint64(b&mask) >> br.n
br.x = b & ^mask
} else {
x <<= 8
x |= uint64(b)
}
return x, nil
}
================================================
FILE: internal/bits/reader_test.go
================================================
// © 2013 the Bits Authors under the MIT license. See AUTHORS for the list of authors.
//
// Some benchmark functions in this file were adapted from github.com/bamiaux/iobit
// which came with the following copyright notice:
// Copyright 2013 Benoît Amiaux. All rights reserved.
package bits
import (
"bytes"
"io"
"math/rand"
"testing"
)
func TestRead(t *testing.T) {
tests := []struct {
data []byte
ns []uint
vals []uint64
}{
// 11111111
{[]byte{0xFF}, []uint{1, 1, 1, 1, 1, 1, 1, 1}, []uint64{1, 1, 1, 1, 1, 1, 1, 1}},
{[]byte{0xFF}, []uint{2, 2, 2, 2}, []uint64{0x3, 0x3, 0x3, 0x3}},
{[]byte{0xFF}, []uint{3, 3, 2}, []uint64{0x7, 0x7, 0x3}},
{[]byte{0xFF}, []uint{4, 4}, []uint64{0xF, 0xF}},
{[]byte{0xFF}, []uint{5, 3}, []uint64{0x1F, 0x7}},
{[]byte{0xFF}, []uint{6, 2}, []uint64{0x3F, 0x3}},
{[]byte{0xFF}, []uint{7, 1}, []uint64{0x7F, 0x1}},
{[]byte{0xFF}, []uint{8}, []uint64{0xFF}},
// 10101010
{[]byte{0xAA}, []uint{1, 1, 1, 1, 1, 1, 1, 1}, []uint64{1, 0, 1, 0, 1, 0, 1, 0}},
{[]byte{0xAA}, []uint{2, 2, 2, 2}, []uint64{0x2, 0x2, 0x2, 0x2}},
{[]byte{0xAA}, []uint{3, 3, 2}, []uint64{0x5, 0x2, 0x2}},
{[]byte{0xAA}, []uint{4, 4}, []uint64{0xA, 0xA}},
{[]byte{0xAA}, []uint{5, 3}, []uint64{0x15, 0x2}},
{[]byte{0xAA}, []uint{6, 2}, []uint64{0x2A, 0x2}},
{[]byte{0xAA}, []uint{7, 1}, []uint64{0x55, 0x0}},
{[]byte{0xAA}, []uint{8}, []uint64{0xAA}},
{[]byte{0xAA}, []uint{0}, []uint64{0}},
// orig: 101010101010101010101010101010101010101010101010101010101010101010101010
// 6 bits: 101010 (0x2A)
// 64 bits: 1010101010101010101010101010101010101010101010101010101010101010 (0xAAAAAAAAAAAAAAAA)
// 2 bit: 10 (0x2)
{[]byte{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}, []uint{6, 64, 2}, []uint64{0x2A, 0xAAAAAAAAAAAAAAAA, 0x2}},
// 01 1011011 011011 0
{[]byte{0x6D, 0xB6}, []uint{2, 7, 6, 1}, []uint64{0x1, 0x5B, 0x1B, 0x0}},
{
[]byte{0x21, 0x0F, 0xC7, 0xBB, 0x81, 0x86, 0x39, 0xAC, 0x48, 0xA4, 0xC6, 0xAF, 0xA2, 0xF1, 0x58, 0x1A, 0x8B, 0x95, 0x25, 0xE2, 0x0F, 0xDA, 0x68, 0x92, 0x7F, 0x2B, 0x2F, 0xF8, 0x36, 0xF7, 0x35, 0x78, 0xDB, 0x0F, 0xA5, 0x4C, 0x29, 0xF7, 0xFD, 0x92, 0x8D, 0x92, 0xCA, 0x43, 0xF1, 0x93, 0xDE, 0xE4, 0x7F, 0x59, 0x15, 0x49, 0xF5, 0x97, 0xA8, 0x11, 0xC8, 0xFA, 0x67, 0xAB, 0x03, 0x1E, 0xBD, 0x9C, 0x6A, 0xA4, 0xE9, 0x82, 0x9F, 0x22, 0x4B, 0xE8, 0xEA, 0xF6, 0x67, 0x26, 0xC9, 0x07, 0x7C, 0xB4, 0x1F, 0x79, 0x01, 0x9D, 0x89, 0x2B, 0xE9, 0x93, 0x03, 0xB2, 0xBE, 0x58, 0x82, 0xF3, 0x24, 0x07, 0x58, 0xA3, 0x8D, 0x7E},
[]uint{2, 40, 28, 62, 8, 59, 51, 54, 63, 49, 11, 42, 64, 7, 41, 2, 4, 58, 24, 55, 63, 13},
[]uint64{0x00, 0x843F1EEE06, 0x18E6B12, 0xA4C6AFA2F1581A8, 0xB9, 0x292F107ED34493F, 0x4ACBFE0DBDCD5, 0x38DB0FA54C29F7, 0x7EC946C96521F8C9, 0x1DEE47F591549, 0x7AC, 0x2F502391F4C, 0xF56063D7B38D549D, 0x18, 0x53E4497D1D, 0x01, 0x07, 0x2CCE4D920EF9683, 0xEF2033, 0x5892BE99303B2B, 0x72C41799203AC51C, 0xD7E},
},
{
[]byte{0x0D, 0xAF, 0x62, 0xD6, 0x5D, 0xCE, 0x5B, 0xA5, 0x24, 0xF7, 0x35, 0x8E, 0xFB, 0xB5, 0xB8, 0x32, 0x20, 0xCF, 0x58, 0x63, 0x6C, 0xBC, 0x40, 0xCF, 0xAC, 0x9A, 0xEB, 0x3C, 0xC8, 0x47, 0xBC, 0xDC, 0xF1, 0x0F, 0x71, 0x7A, 0xA2, 0x62, 0x77, 0xFF, 0x0A, 0x3A, 0x0E, 0xC7, 0x3E, 0x10, 0xFF, 0x40, 0x8E, 0xCE, 0x87, 0x28, 0xF8, 0x4A, 0xE1, 0xAF, 0x7B, 0xBF, 0x86, 0xE9, 0x94, 0x6F, 0xB0, 0x8F, 0xB6, 0x58, 0x97, 0x5A, 0xB5, 0x52, 0x9D, 0x70, 0x40, 0x74, 0xAF, 0x4A, 0xC8, 0xC0, 0xF5, 0xA4, 0x6F, 0x09, 0x6E, 0xE8, 0x47, 0x7A, 0x77, 0x54, 0x30, 0x03, 0x8F, 0xC0, 0x0E, 0xAC, 0x03, 0xAF, 0x4D, 0xDC, 0xD3, 0x25},
[]uint{62, 44, 50, 50, 7, 53, 11, 9, 57, 37, 35, 54, 30, 45, 5, 8, 59, 9, 13, 48, 62, 46, 6},
[]uint64{0x36BD8B5977396E9, 0x493DCD63BEE, 0x35B83220CF586, 0xDB2F1033EB26, 0x5D, 0xCF3211EF373C4, 0x1EE, 0x5E, 0x151313BFF851D07, 0xC73E10FF4, 0x47674394, 0x1F095C35EF77F0, 0x374CA37D, 0x108FB658975A, 0x16, 0xAA, 0x29D704074AF4AC8, 0x181, 0x1D69, 0x1BC25BBA11DE, 0x2775430038FC00EA, 0x300EBD37734C, 0x25},
},
{
[]byte{0x08, 0x0F, 0x1D, 0xFD, 0xC9, 0xC4, 0xAD, 0x25, 0x6F, 0x47, 0x56, 0x20, 0x46, 0xFC, 0x40, 0x54, 0xF5, 0x9B, 0x5B, 0xE5, 0x46, 0x5E, 0x75, 0xE6, 0xE0, 0xAA, 0x60, 0xC8, 0xEB, 0x2E, 0xE5, 0xD4, 0xCD, 0x26, 0x50, 0xA8, 0x1C, 0xCE, 0xE3, 0x55, 0x07, 0xA1, 0x1A, 0x37, 0x90, 0x71, 0xC7, 0x51, 0xF7, 0x1F, 0xDF, 0x0D, 0xFE, 0xB3, 0xFB, 0xC8, 0xF0, 0x08, 0x25, 0xE6, 0x4C, 0x27, 0x62, 0xFA, 0xC9, 0xFE, 0x63, 0xE2, 0x42, 0x03, 0x7A, 0x8B, 0xC4, 0x03, 0x69, 0x6E, 0x07, 0x33, 0x42, 0x37, 0x10, 0x4C, 0x5E, 0xC5, 0x64, 0x2C, 0xA3, 0xC1, 0xC2, 0x55, 0x0A, 0x87, 0x16, 0xA9, 0x28, 0xE7, 0xCD, 0xBA, 0xEA, 0xC9},
[]uint{64, 38, 1, 25, 10, 6, 13, 38, 27, 13, 48, 53, 3, 30, 60, 39, 32, 34, 5, 1, 56, 26, 47, 21, 43, 32, 35},
[]uint64{0x80F1DFDC9C4AD25, 0x1BD1D58811, 0x01, 0xFC4054, 0x3D6, 0x1B, 0xB7C, 0x2A32F3AF37, 0x2A9832, 0x759, 0x772EA6693285, 0x81CCEE35507A1, 0x00, 0x346F20E3, 0x8EA3EE3FBE1BFD6, 0x3FBC8F0082, 0x5E64C276, 0xBEB27F98, 0x1F, 0x00, 0x242037A8BC4036, 0x25B81CC, 0x6846E2098BD8, 0x1590B2, 0x478384AA150, 0xE2D5251C, 0x7CDBAEAC9},
},
{
[]byte{0x49, 0x2C, 0x95, 0x56, 0xD7, 0x40, 0x88, 0xA9, 0x13, 0x2E, 0x4A, 0x5C, 0x13, 0xCC, 0x15, 0x9A, 0xA6, 0xEB, 0x4A, 0x0E, 0x9B, 0x96, 0x3C, 0xAD, 0xD1, 0x6E, 0x9C, 0x2D, 0xBA, 0xFD, 0xCE, 0x26, 0xC7, 0x18, 0xBC, 0xDC, 0x0F, 0xA7, 0xD4, 0xAD, 0x15, 0x5E, 0xEB, 0xCC, 0xB9, 0x46, 0x71, 0xE3, 0xDD, 0xFB, 0x4B, 0x99, 0x7D, 0x5B, 0x3F, 0xE4, 0xA4, 0x8B, 0x59, 0x8E, 0x7D, 0x89, 0xDF, 0xFF, 0x84, 0x0D, 0xAE, 0xCA, 0xA8, 0x9B, 0x8E, 0xF2, 0x31, 0xF6, 0xF2, 0x7E, 0x13, 0xDA, 0xEB, 0xE2, 0xED, 0xCD, 0xED, 0x9F, 0x38, 0xC6, 0x9E, 0x7F, 0x7A, 0xA1, 0x83, 0x4E, 0xDA, 0x01, 0xE3, 0x35, 0x41, 0x20, 0x10, 0xA6},
[]uint{18, 61, 54, 29, 43, 60, 15, 25, 42, 47, 8, 6, 7, 2, 37, 8, 13, 24, 49, 16, 22, 19, 36, 17, 43, 27, 9, 5, 36, 22},
[]uint64{0x124B2, 0xAAB6BA044548997, 0x94B827982B354, 0x1BAD283A, 0x372C795BA2D, 0xD385B75FB9C4D8E, 0x18BC, 0x1B81F4F, 0x2A568AAF75E, 0x32E519C78F77, 0xED, 0x0B, 0x4C, 0x02, 0x1F56CFF929, 0x22, 0x1ACC, 0x73EC4E, 0x1FFF840DAECAA, 0x89B8, 0x3BC8C7, 0x6DE4F, 0xC27B5D7C5, 0x1B737, 0x5B3E718D3CF, 0x77AA183, 0x9D, 0x16, 0x8078CD504, 0x2010A6},
},
{
[]byte{0x7B, 0x22, 0xD1, 0x15, 0x7D, 0x2A, 0x8F, 0x5E, 0x35, 0x8E, 0xFD, 0x26, 0x3D, 0x98, 0xF0, 0x10, 0x18, 0xD7, 0x1E, 0xDC, 0x1D, 0x54, 0x3A, 0x4D, 0xF3, 0xED, 0xDB, 0x19, 0x46, 0xF8, 0x5B, 0xF3, 0xE5, 0x2C, 0x4B, 0xB6, 0x80, 0x08, 0x4D, 0x27, 0x71, 0x58, 0xAA, 0x81, 0x28, 0x1C, 0x8A, 0xB5, 0x47, 0x6A, 0x84, 0x1B, 0xF2, 0x23, 0xC1, 0xC0, 0x6E, 0x51, 0xF9, 0xB5, 0x19, 0x80, 0xCD, 0xF8, 0x06, 0x6B, 0x31, 0xF6, 0x23, 0x84, 0x1C, 0xB6, 0xBF, 0xEA, 0x59, 0x9B, 0xD8, 0x4F, 0x84, 0x04, 0xDB, 0x4B, 0x71, 0xE4, 0xAE, 0xF2, 0xD6, 0xE9, 0x2A, 0x16, 0x42, 0x9E, 0x0C, 0xFC, 0xA6, 0x84, 0x79, 0xC8, 0x2A, 0x23},
[]uint{52, 58, 42, 30, 54, 55, 26, 15, 18, 43, 47, 34, 58, 3, 15, 17, 48, 8, 50, 49, 37, 18, 23},
[]uint64{0x7B22D1157D2A8, 0x3D78D63BF498F66, 0xF01018D71E, 0x3707550E, 0x24DF3EDDB1946F, 0x42DF9F29625DB4, 0x109A4, 0x7715, 0x22AA0, 0x25039156A8E, 0x6A841BF223C1, 0x301B947E6, 0x351980CDF8066B3, 0x00, 0x7D88, 0x1C20E, 0x5B5FF52CCDEC, 0x27, 0x30809B696E3C9, 0xBBCB5BA4A859, 0x14F067E53, 0x108F3, 0x482A23},
},
{
[]byte{0x0B, 0xBD, 0x5B, 0x49, 0x1C, 0x14, 0x1C, 0xE6, 0x96, 0x97, 0x97, 0x3C, 0x76, 0x70, 0xF4, 0x3E, 0xBA, 0x37, 0x88, 0xB2, 0x46, 0xBF, 0x22, 0xE9, 0xA2, 0x84, 0x7A, 0x3D, 0xF2, 0x12, 0xC9, 0xB5, 0x28, 0x15, 0x0A, 0x31, 0x4E, 0xFC, 0x13, 0x09, 0x02, 0x41, 0x3F, 0xCC, 0x8E, 0x0B, 0x06, 0xD1, 0xA3, 0x80, 0x6E, 0x48, 0x12, 0x00, 0xA7, 0xD2, 0x77, 0xCD, 0x9D, 0xB5, 0x91, 0x13, 0x0A, 0x45, 0xBB, 0xE3, 0xFA, 0x0F, 0xC7, 0x8F, 0x4F, 0x4C, 0x3C, 0xB3, 0xC1, 0xD7, 0xC8, 0x92, 0xB1, 0x32, 0x0B, 0x07, 0x21, 0x27, 0x60, 0x0A, 0xF5, 0x44, 0xDB, 0x90, 0x8C, 0x62, 0xBB, 0x20, 0xB1, 0x84, 0x3B, 0xDB, 0xAF, 0xDB},
[]uint{5, 4, 44, 10, 7, 54, 2, 22, 24, 49, 32, 52, 63, 57, 25, 5, 61, 22, 9, 25, 51, 12, 14, 1, 23, 57, 16, 40, 14},
[]uint64{0x01, 0x07, 0x7AB69238283, 0x273, 0x25, 0x297973C7670F43, 0x03, 0x2BA378, 0x8B246B, 0x1E45D34508F47, 0xBE425936, 0xA502A14629DF8, 0x130902413FCC8E0B, 0xDA34700DC9024, 0x29F49, 0x1B, 0x1CD9DB591130A45B, 0x2F8FE8, 0x7E, 0x78F4F4, 0x61E59E0EBE449, 0x589, 0x2416, 0x00, 0xE424E, 0x1802BD5136E4231, 0x8AEC, 0x82C610EF6E, 0x2FDB},
},
{
[]byte{0x48, 0xB3, 0x01, 0xCE, 0x08, 0x20, 0xE4, 0xBD, 0x27, 0x21, 0x0A, 0x77, 0x34, 0x5A, 0x50, 0x74, 0xD5, 0x56, 0xCB, 0xE2, 0xCB, 0x7A, 0x63, 0x5F, 0xE3, 0x04, 0x52, 0x87, 0xA8, 0x16, 0x3D, 0x78, 0xE5, 0xC3, 0x82, 0x84, 0x80, 0xC9, 0x67, 0xD4, 0x34, 0xB4, 0xAF, 0xEF, 0x9F, 0x91, 0x5E, 0x1B, 0x8D, 0xF5, 0x43, 0x24, 0xB4, 0xDA, 0xD0, 0xBA, 0xC0, 0xEE, 0xF1, 0x94, 0xA1, 0xE8, 0xAC, 0xDB, 0x84, 0xB8, 0xDC, 0x99, 0x62, 0x4B, 0x19, 0xD1, 0xF8, 0xC5, 0x48, 0x7E, 0xEB, 0x9F, 0x82, 0xFF, 0xE9, 0xA4, 0x88, 0x86, 0x5C, 0x28, 0x60, 0x0F, 0xA3, 0xA7, 0x0B, 0x97, 0xFE, 0x4C, 0x99, 0x17, 0x08, 0xB5, 0x58, 0x94},
[]uint{34, 25, 22, 55, 18, 20, 35, 30, 1, 12, 30, 64, 32, 33, 51, 3, 32, 32, 15, 10, 25, 26, 26, 20, 62, 63, 24},
[]uint64{0x122CC0738, 0x410725, 0x3A4E42, 0xA77345A5074D5, 0x15B2F, 0x8B2DE, 0x4C6BFC608, 0x2943D40B, 0x00, 0x3D7, 0x23970E0A, 0x1203259F50D2D2BF, 0xBE7E4578, 0xDC6FAA19, 0x12D36B42EB03B, 0x05, 0xE32943D1, 0x59B70971, 0x5C99, 0x189, 0x58CE8F, 0x318A90F, 0x375CFC1, 0x7FF4D, 0x9110CB850C01F47, 0x270B97FE4C991708, 0xB55894},
},
{
[]byte{0x48, 0x34, 0xA6, 0xF7, 0xD5, 0x71, 0x21, 0x1F, 0x5D, 0x73, 0xC4, 0xCF, 0x93, 0x0B, 0x9C, 0x62, 0xD3, 0xD2, 0x0F, 0x53, 0x68, 0xFC, 0x22, 0x1B, 0x99, 0x91, 0x60, 0x87, 0x45, 0x9C, 0x56, 0x41, 0x66, 0x1C, 0x32, 0x52, 0xB0, 0xAA, 0xA1, 0x65, 0xED, 0x1D, 0x0F, 0x3E, 0x40, 0x5B, 0x80, 0xD1, 0xE8, 0x6B, 0x4C, 0x1A, 0x7E, 0xAD, 0xC2, 0x77, 0x36, 0xA5, 0x02, 0x01, 0x21, 0x98, 0x92, 0x1C, 0x7A, 0xCB, 0x68, 0x3B, 0x03, 0xFC, 0xC9, 0x67, 0xF7, 0x77, 0x65, 0xE7, 0xFA, 0x5E, 0xF9, 0xE5, 0x92, 0x2A, 0x97, 0x7C, 0xAC, 0x82, 0xF5, 0xEE, 0xAD, 0x81, 0xF4, 0xB9, 0xF0, 0xF7, 0xA7, 0x9C, 0x91, 0xC6, 0x51, 0x4D},
[]uint{61, 55, 35, 55, 14, 6, 37, 60, 46, 25, 52, 62, 27, 23, 3, 27, 39, 19, 31, 2, 6, 52, 7, 48, 8},
[]uint64{0x90694DEFAAE2423, 0x75D73C4CF930B9, 0x63169E907, 0x54DA3F0886E664, 0x1608, 0x1D, 0x2CE2B20B3, 0xE1929585550B2F, 0x1A3A1E7C80B7, 0x347A1, 0xAD3069FAB709D, 0x336A502012198921, 0x63D65B4, 0xEC0FF, 0x01, 0x4967F77, 0x3B2F3FD2F7, 0x67964, 0x4552EF95, 0x02, 0x10, 0x5EBDD5B03E973, 0x70, 0xF7A79C91C651, 0x4D},
},
{
[]byte{0x04, 0x2A, 0xDC, 0xC2, 0x25, 0xBF, 0x31, 0x81, 0x18, 0xE5, 0x6F, 0xAD, 0xE0, 0x60, 0x2C, 0xAC, 0x62, 0xF2, 0xD5, 0x59, 0xB9, 0x26, 0xAE, 0x4D, 0x67, 0x86, 0x7B, 0x23, 0xA2, 0xCB, 0xAC, 0x63, 0x06, 0xB2, 0xE3, 0x2F, 0x73, 0x59, 0x64, 0x79, 0xAC, 0x74, 0x15, 0xF2, 0x51, 0x14, 0xFB, 0x45, 0x06, 0xBB, 0xF0, 0x29, 0x5A, 0xD2, 0x90, 0x6F, 0x24, 0xB9, 0x8F, 0x06, 0x54, 0xAE, 0x56, 0x33, 0x3D, 0x79, 0x92, 0x42, 0x50, 0xCF, 0x16, 0x53, 0xCB, 0xC6, 0x57, 0x45, 0x17, 0xEA, 0x69, 0x40, 0xAC, 0xCB, 0x97, 0x74, 0xA0, 0x8A, 0x79, 0x40, 0xA1, 0x2E, 0x63, 0xCA, 0x61, 0xCD, 0x98, 0x2B, 0xCF, 0x55, 0x3A, 0xCB},
[]uint{4, 14, 31, 4, 42, 46, 62, 30, 58, 51, 6, 1, 39, 61, 52, 24, 48, 57, 6, 50, 44, 1, 54, 15},
[]uint64{0x00, 0x10AB, 0x39844B7E, 0x06, 0xC08C72B7D6, 0x3C0C05958C5E, 0x16AACDC935726B3C, 0xCF64745, 0x25D63183597197B, 0x4D6591E6B1D05, 0x1F, 0x00, 0x25114FB450, 0xD77E052B5A520DE, 0x49731E0CA95CA, 0xC667AF, 0x32484A19E2CA, 0xF2F195D145FA9A, 0x14, 0x2B32E5DD2822, 0x9E50284B98F, 0x00, 0x14C39B30579EAA, 0x3ACB},
},
{
[]byte{0x8A, 0xCC, 0x20, 0x56, 0x0B, 0x1B, 0x64, 0xA3, 0x37, 0x3A, 0x54, 0xD7, 0x6E, 0x2B, 0x16, 0x8E, 0x92, 0xE5, 0xC1, 0xCA, 0x2B, 0xE8, 0x00, 0x8A, 0x64, 0xBF, 0x5C, 0x3F, 0x3F, 0xF6, 0x3C, 0x11, 0x80, 0x34, 0x84, 0x3E, 0xE4, 0x04, 0x51, 0x7C, 0x54, 0xA0, 0x07, 0x59, 0xD3, 0x2E, 0x19, 0x3E, 0x1E, 0xAE, 0x16, 0x47, 0x2F, 0xF5, 0xF1, 0x19, 0xB6, 0xA1, 0x36, 0x2D, 0xFC, 0x1B, 0x86, 0x13, 0xE0, 0xF4, 0xF9, 0x68, 0x57, 0x9D, 0x1F, 0xDE, 0xE5, 0x12, 0xD1, 0x94, 0x47, 0xD8, 0xE5, 0x2A, 0xAF, 0xCE, 0xE0, 0xB7, 0x98, 0xB2, 0xE1, 0xEE, 0xA5, 0x7A, 0x89, 0xB4, 0x06, 0x8B, 0x59, 0xD6, 0xBF, 0x69, 0x56, 0x4B},
[]uint{13, 1, 5, 35, 47, 53, 53, 18, 10, 42, 12, 6, 6, 62, 43, 42, 38, 55, 35, 21, 27, 57, 25, 13, 32, 33, 6, 10},
[]uint64{0x1159, 0x01, 0x01, 0x1582C6D9, 0x1466E74A9AED, 0x18AC5A3A4B9707, 0x515F40045325F, 0x2B87E, 0x1FF, 0x2C782300690, 0x87D, 0x32, 0x00, 0x228BE2A5003ACE99, 0x3864F87AB85, 0x2472FF5F119, 0x2DA84D8B7F, 0x370C27C1E9F2D, 0x579D1FDE, 0x1CA25A, 0x19447D8, 0x1CA555F9DC16F31, 0xCB87BA, 0x12BD, 0x44DA0345, 0x159D6BF69, 0x15, 0x24B},
},
{
[]byte{0x47, 0xC2, 0x96, 0xCD, 0x76, 0xCD, 0x5C, 0x93, 0xA4, 0x08, 0xD0, 0x96, 0x39, 0x5C, 0xE1, 0x02, 0x05, 0xBF, 0xD5, 0x7B, 0xF8, 0xD6, 0xCD, 0x5D, 0x30, 0x6E, 0xD2, 0x31, 0x28, 0xEB, 0x5C, 0x3C, 0x4A, 0x95, 0xF1, 0x3F, 0xB6, 0xA8, 0xAD, 0xB8, 0x53, 0xC8, 0xED, 0x3D, 0x9D, 0xB4, 0xC2, 0x2F, 0xE5, 0x79, 0x94, 0x3F, 0x15, 0x38, 0xBE, 0xEB, 0x51, 0x9B, 0xB9, 0x6F, 0x6F, 0xF1, 0x4F, 0xA6, 0x7F, 0xB4, 0xD0, 0x1B, 0xF7, 0x8A, 0xF7, 0xCC, 0xD8, 0x36, 0x17, 0xD4, 0x9A, 0xAE, 0xFF, 0x04, 0x07, 0xAA, 0x86, 0xC6, 0x12, 0x31, 0x77, 0x8A, 0x5B, 0x15, 0x0B, 0xEB, 0x1C, 0xA4, 0xF8, 0xA2, 0x12, 0xD8, 0x81, 0xA2},
[]uint{16, 21, 34, 33, 40, 35, 26, 3, 34, 6, 45, 11, 45, 44, 6, 14, 7, 32, 11, 16, 35, 16, 48, 43, 63, 14, 13, 34, 35, 13, 7},
[]uint64{0x47C2, 0x12D9AE, 0x366AE49D2, 0x8D09639, 0x5CE10205BF, 0x6ABDFC6B6, 0x1ABA60D, 0x06, 0x348C4A3AD, 0x1C, 0x78952BE27F6, 0x6A8, 0x15B70A791DA7, 0xB3B69845FCA, 0x3C, 0x3287, 0x71, 0x538BEEB5, 0xCD, 0xDCB7, 0x5BFC53E99, 0xFED3, 0x406FDE2BDF33, 0x306C2FA9355, 0x6FF0407AA86C6123, 0x5DE, 0x52D, 0x22A17D639, 0x24F8A212D, 0x1103, 0x22},
},
{
[]byte{0xAD, 0x57, 0x64, 0x74, 0x59, 0x9A, 0x31, 0x7D, 0x46, 0x3A, 0xD3, 0x15, 0xEA, 0xE7, 0x3A, 0xBC, 0xBF, 0xE7, 0x6A, 0x36, 0xF2, 0x99, 0x7A, 0x5F, 0x09, 0xB2, 0x3E, 0xE5, 0xD6, 0x7D, 0x84, 0x7A, 0x62, 0xB3, 0xD8, 0xC3, 0x84, 0x42, 0x40, 0x59, 0xBE, 0x8A, 0x59, 0xC7, 0x35, 0xD7, 0xC9, 0xB2, 0x6F, 0xDD, 0x67, 0x04, 0x3B, 0x20, 0xDC, 0x27, 0x63, 0x82, 0x34, 0x3D, 0xBC, 0xE6, 0x29, 0x45, 0x15, 0x94, 0xC9, 0x0C, 0xFA, 0xCF, 0x0F, 0x35, 0x58, 0x06, 0x12, 0x51, 0x18, 0xE7, 0x42, 0x11, 0x39, 0xB3, 0xB4, 0xDD, 0xFE, 0x3F, 0xD7, 0x54, 0xB0, 0xF3, 0x56, 0x61, 0x7D, 0xC4, 0x09, 0xA2, 0x1E, 0x36, 0xFA, 0xFA},
[]uint{23, 21, 29, 16, 60, 23, 38, 41, 14, 27, 15, 61, 34, 40, 47, 21, 23, 51, 2, 30, 50, 53, 38, 4, 29, 10},
[]uint64{0x56ABB2, 0x74599, 0x1462FA8C, 0x75A6, 0x2BD5CE75797FCED, 0x236F29, 0x25E97C26C8, 0x1F72EB3EC23, 0x34C5, 0x33D8C38, 0x2212, 0x59BE8A59C735D7, 0x326C9BF75, 0x9C10EC8370, 0x4EC704687B79, 0x198A51, 0x22B299, 0x10CFACF0F3558, 0x00, 0x6125118, 0x39D0844E6CED3, 0xEFF1FEBAA5879, 0x2ACC2FB881, 0x03, 0x8878DBE, 0x2FA},
},
{
[]byte{0xCD, 0x03, 0x06, 0x80, 0x27, 0x9D, 0x7E, 0x06, 0x6D, 0x29, 0x42, 0xAE, 0x44, 0x8D, 0xA3, 0xC9, 0x85, 0x03, 0xF1, 0x4D, 0x48, 0xB6, 0xC7, 0xDF, 0xBF, 0x87, 0x7E, 0x58, 0xB1, 0x92, 0x87, 0x05, 0x06, 0xE1, 0x6E, 0x0D, 0x15, 0x51, 0x99, 0xC5, 0x6C, 0x71, 0xCF, 0xFB, 0x8F, 0xE2, 0xD3, 0xA2, 0x31, 0x90, 0x4F, 0x38, 0x9C, 0x3A, 0xD7, 0x50, 0xD0, 0x75, 0x70, 0x33, 0x8B, 0x62, 0x44, 0x23, 0x9E, 0x6A, 0x8C, 0xE7, 0xB2, 0xCA, 0x84, 0x3C, 0x9F, 0x57, 0x70, 0x51, 0xA5, 0xBE, 0xD4, 0x4A, 0x3A, 0x61, 0xE8, 0x4E, 0x75, 0x25, 0xCD, 0x4E, 0x72, 0x5C, 0x69, 0xB3, 0x5B, 0x74, 0xF2, 0x4B, 0x76, 0x9C, 0x8B, 0xF0},
[]uint{47, 52, 30, 11, 13, 23, 37, 17, 13, 18, 26, 3, 64, 5, 37, 21, 37, 46, 28, 8, 23, 48, 1, 9, 30, 42, 15, 23, 26, 16, 12, 19},
[]uint64{0x6681834013CE, 0xBF033694A1572, 0x91B4793, 0x50, 0x7E2, 0x4D48B6, 0x18FBF7F0EF, 0x1962C, 0xC94, 0xE0A0, 0x370B706, 0x04, 0x55466715B1C73FEE, 0x07, 0x1E2D3A2319, 0x9E71, 0x70EB5D434, 0x7570338B624, 0x4239E6A, 0x8C, 0x73D965, 0x421E4FABB828, 0x01, 0x14B, 0x1F6A251D, 0xC3D09CEA4B, 0x4D4E, 0x392E34, 0x366B6E9, 0xE496, 0xED3, 0x48BF0},
},
{
[]byte{0x69, 0x4F, 0x3D, 0x68, 0x86, 0x48, 0x1B, 0x9E, 0x94, 0xFF, 0xDE, 0x36, 0xDD, 0xD1, 0xBF, 0x69, 0x48, 0x8D, 0xCF, 0x2C, 0x2A, 0xA0, 0xA2, 0xFF, 0xC9, 0xD9, 0x6A, 0x99, 0x3D, 0x6D, 0xFA, 0x39, 0x79, 0xAC, 0x87, 0xC1, 0xAF, 0xCE, 0x2A, 0xCF, 0x09, 0x84, 0xFD, 0xC1, 0xE6, 0xC4, 0x27, 0x2E, 0x4A, 0x4C, 0x64, 0x0F, 0xBC, 0x81, 0xFA, 0xED, 0xED, 0x23, 0x29, 0x02, 0x6F, 0xF5, 0x81, 0xC5, 0x18, 0x33, 0x08, 0xC8, 0x7F, 0xE0, 0xD0, 0x90, 0xC0, 0x12, 0x77, 0xEE, 0xEB, 0x6A, 0x6C, 0x11, 0x08, 0xA0, 0xBB, 0xF2, 0x94, 0x80, 0xA1, 0x98, 0xBB, 0x44, 0xDC, 0xE4, 0x07, 0x99, 0x1D, 0x54, 0x18, 0x58, 0x14, 0x39},
[]uint{20, 47, 3, 29, 11, 38, 53, 36, 6, 20, 14, 8, 55, 6, 32, 23, 49, 28, 16, 50, 20, 55, 41, 3, 31, 13, 33, 39, 21},
[]uint64{0x694F3, 0x6B443240DCF4, 0x05, 0x7FEF1B6, 0x774, 0x1BF69488DC, 0x1E58554145FF93, 0xB2D5327AD, 0x2F, 0xD1CBC, 0x3590, 0xF8, 0x1AFCE2ACF0984F, 0x37, 0x79B109C, 0x5C9498, 0x1903EF207EBB7, 0xB48CA40, 0x9BFD, 0x181C5183308C8, 0x7FE0D, 0x4860093BF775B, 0xA6C1108A0B, 0x05, 0x7CA52028, 0xCC5, 0x1B44DCE40, 0x3CC8EAA0C2, 0x181439},
},
{
[]byte{0xAA, 0xE8, 0x77, 0xB9, 0x9B, 0xB1, 0xDF, 0xCD, 0x24, 0x21, 0xCA, 0xFC, 0x15, 0x32, 0xFC, 0x71, 0x41, 0x53, 0x20, 0x3C, 0x9A, 0x26, 0x5E, 0x35, 0x58, 0x6E, 0x97, 0xC3, 0xEE, 0x5A, 0x8F, 0x6C, 0x26, 0x9C, 0xD9, 0xB0, 0x54, 0xCE, 0x57, 0x3D, 0xDC, 0x41, 0x56, 0xE6, 0xBE, 0x7A, 0x20, 0xEF, 0x04, 0xF6, 0x14, 0x4F, 0x21, 0x78, 0x5A, 0x55, 0x66, 0xA1, 0x3D, 0xF8, 0x7D, 0x5C, 0x10, 0x3C, 0x3F, 0x28, 0x4C, 0x05, 0x62, 0x3F, 0xDA, 0xBF, 0x11, 0xA7, 0x02, 0x8E, 0xC8, 0x4F, 0xC2, 0x4A, 0x86, 0xE4, 0xFD, 0xD4, 0xAC, 0x37, 0x10, 0xD7, 0x60, 0x05, 0x97, 0xE0, 0x08, 0xD8, 0xB6, 0xAA, 0x08, 0xC9, 0xD5, 0x1F},
[]uint{9, 23, 6, 21, 31, 58, 51, 34, 50, 22, 35, 63, 13, 37, 12, 29, 63, 64, 16, 46, 9, 28, 47, 33},
[]uint64{0x155, 0x6877B9, 0x26, 0x1D8EFE, 0x3490872B, 0x3C1532FC7141532, 0x1E4D132F1AAC, 0xDD2F87DC, 0x2D47B6134E6CD, 0x20A99C, 0x573DDC415, 0x3735F3D1077827B0, 0x144F, 0x42F0B4AAC, 0xD42, 0xF7E1F57, 0x20787E50980AC47, 0xFB57E234E051D909, 0xF849, 0x143727EEA561, 0x171, 0xD76005, 0x4BF0046C5B55, 0x8C9D51F},
},
{
[]byte{0x7E, 0x3B, 0x8C, 0x41, 0x5D, 0x41, 0x24, 0xF4, 0x14, 0x8C, 0x75, 0xCB, 0x0D, 0x8E, 0x08, 0xEA, 0xD9, 0xE5, 0x84, 0x3E, 0x54, 0xA0, 0xD9, 0x22, 0xF5, 0xB8, 0x0D, 0xED, 0x3A, 0x7F, 0x93, 0x06, 0xF8, 0xC8, 0x4A, 0x60, 0x15, 0x65, 0x06, 0x43, 0xFF, 0x3A, 0x50, 0xFE, 0xCE, 0xE0, 0x15, 0x1F, 0x03, 0x7F, 0x2B, 0xB1, 0x04, 0x07, 0x9C, 0xCD, 0x9B, 0xEA, 0xCE, 0xC7, 0xAB, 0x96, 0xD5, 0x42, 0x88, 0x93, 0xBB, 0xD0, 0x2B, 0x74, 0x06, 0x68, 0x3E, 0xE2, 0x80, 0xDA, 0x78, 0x10, 0x94, 0x47, 0x3C, 0x7B, 0xA1, 0x8F, 0x27, 0x55, 0xD7, 0x37, 0xA9, 0x5F, 0xDD, 0x1D, 0xE1, 0xF4, 0x03, 0xA8, 0x99, 0xC2, 0xD0, 0x86},
[]uint{34, 59, 46, 49, 28, 60, 53, 47, 38, 45, 23, 33, 8, 1, 8, 12, 11, 50, 16, 25, 30, 33, 2, 3, 33, 35, 18},
[]uint64{0x1F8EE3105, 0x3A8249E82918EB9, 0x186C704756CF, 0x5843E54A0D92, 0x2F5B80D, 0xED3A7F9306F8C84, 0x14C02ACA0C87FE, 0x3A50FECEE015, 0x7C0DFCAEC, 0x8203CE66CDF, 0x2B3B1E, 0x15CB6AA14, 0x44, 0x01, 0x3B, 0xBD0, 0x15B, 0x280CD07DC501B, 0x4F02, 0x2511CF, 0x7BA18F2, 0xEABAE6F5, 0x00, 0x05, 0xFEE8EF0F, 0x500EA2670, 0x2D086},
},
{
[]byte{0xDD, 0xE8, 0x87, 0xA5, 0xCA, 0xBB, 0xC8, 0x9F, 0x2F, 0xAF, 0x66, 0xE8, 0xB9, 0x48, 0x0D, 0x31, 0xB5, 0x8E, 0xAA, 0x48, 0x6A, 0x74, 0xCB, 0xC5, 0x9E, 0x1C, 0x1D, 0xE5, 0x1D, 0x89, 0x0A, 0x4B, 0x10, 0x12, 0xAA, 0xFB, 0x08, 0x6B, 0x10, 0x62, 0x55, 0x94, 0xA1, 0x38, 0xB0, 0x4D, 0x3F, 0xB1, 0xA8, 0xFC, 0xA2, 0x0E, 0x6C, 0x6B, 0x65, 0x73, 0x2D, 0x61, 0x47, 0x24, 0xB9, 0xBB, 0xA0, 0x4A, 0xF8, 0x05, 0xF4, 0x74, 0x1B, 0x06, 0x99, 0x93, 0x63, 0x4A, 0xF7, 0x9D, 0x43, 0x23, 0x00, 0x30, 0x39, 0x5A, 0x65, 0x8A, 0xA4, 0x13, 0xF1, 0x6A, 0x29, 0xB7, 0x16, 0x24, 0xDD, 0xDB, 0xF7, 0x75, 0x05, 0x94, 0x48, 0x76},
[]uint{32, 10, 14, 19, 40, 24, 28, 60, 31, 59, 43, 11, 27, 19, 22, 33, 46, 51, 41, 10, 29, 31, 34, 9, 25, 28, 24},
[]uint64{0xDDE887A5, 0x32A, 0x3BC8, 0x4F97D, 0x7B3745CA40, 0x698DAC, 0x7552435, 0x3A65E2CF0E0EF28, 0x7624292C, 0x202555F610D620C, 0x25594A138B0, 0x269, 0x7EC6A3F, 0x1441C, 0x3635B2, 0x1732D6147, 0x92E6EE812BE, 0xBE8E8360D33, 0x4D8D2BDE75, 0x32, 0x6006072, 0x5A658AA4, 0x4FC5A8A6, 0x1B8, 0x1624DDD, 0xBF77505, 0x944876},
},
{
[]byte{0x80, 0x94, 0x8F, 0xFF, 0xAB, 0xB3, 0x58, 0x12, 0x91, 0x7D, 0xEB, 0xBA, 0x4F, 0xF2, 0x01, 0x6B, 0xCD, 0xFF, 0x44, 0xB7, 0xD7, 0xC7, 0x19, 0xAE, 0x12, 0x9A, 0x65, 0x48, 0x18, 0xD7, 0x10, 0x30, 0x2D, 0x72, 0x76, 0xC1, 0x97, 0x4E, 0xC2, 0x91, 0x40, 0x30, 0x92, 0x47, 0x5E, 0xCB, 0xC2, 0x85, 0xBA, 0xF4, 0xEF, 0x47, 0x3D, 0x70, 0x2D, 0x64, 0xD8, 0x63, 0xAD, 0xB2, 0x96, 0xC4, 0xF1, 0x1A, 0x57, 0xB2, 0xAB, 0xF4, 0x6E, 0x1E, 0x4E, 0x4E, 0x93, 0x32, 0xF1, 0x6C, 0x76, 0x1F, 0xA1, 0xAE, 0xD6, 0x5A, 0x27, 0x1D, 0x37, 0xA9, 0x2B, 0x32, 0x4A, 0xF6, 0x29, 0x47, 0xC0, 0x29, 0x69, 0xCE, 0xA9, 0x64, 0x93, 0xBC},
[]uint{37, 49, 14, 17, 29, 33, 20, 9, 52, 30, 60, 24, 18, 22, 41, 3, 11, 30, 23, 14, 38, 14, 20, 27, 6, 15, 25, 63, 42, 4, 10},
[]uint64{0x101291FFF5, 0xECD604A45F7A, 0x3BA4, 0x1FE40, 0x5AF37FD, 0x25BEBE38, 0xCD709, 0x9A, 0x654818D710302, 0x35C9DB06, 0x5D3B0A4500C2491, 0xD7B2F0, 0x285BA, 0x3D3BD1, 0x19EB816B26C, 0x01, 0x475, 0x2D94B627, 0x44695E, 0x32AB, 0x3D1B879393, 0x2933, 0x2F16C, 0x3B0FD0D, 0x1D, 0x565A, 0x4E3A6F, 0x292B324AF62947C0, 0xA5A73AA592, 0x04, 0x3BC},
},
{
[]byte{0x00, 0xFA, 0x33, 0x12, 0xCB, 0xA1, 0x5D, 0xC3, 0x6C, 0x6A, 0x85, 0xBF, 0xA2, 0x49, 0x3C, 0x04, 0x16, 0xD2, 0xF2, 0x2E, 0xCA, 0x84, 0x20, 0x29, 0x9D, 0x54, 0x0C, 0xE2, 0x4A, 0x7D, 0x26, 0x36, 0x54, 0xC2, 0x7B, 0x72, 0x3D, 0x4A, 0xA6, 0x6E, 0xAD, 0xDE, 0xF7, 0x94, 0x78, 0xF5, 0xB5, 0x7D, 0x24, 0xB2, 0x9C, 0xC4, 0x5E, 0xA5, 0xE2, 0xF6, 0x2D, 0x5C, 0x7D, 0x8D, 0x32, 0x47, 0x4A, 0xC6, 0x51, 0xBA, 0x66, 0x80, 0xA4, 0xF9, 0x22, 0xF0, 0x3E, 0x51, 0x09, 0xAD, 0x1E, 0x26, 0x1E, 0xC5, 0x0C, 0x2A, 0xFA, 0x7A, 0xDC, 0x8A, 0x6F, 0xF2, 0x3C, 0x0A, 0xD4, 0xAB, 0x25, 0x1F, 0xFD, 0x1A, 0xC1, 0x9E, 0x35, 0x8D},
[]uint{11, 43, 6, 27, 24, 36, 9, 63, 39, 53, 11, 56, 17, 59, 57, 52, 42, 11, 45, 15, 54, 17, 21, 13, 18, 1},
[]uint64{0x07, 0x68CC4B2E857, 0x1C, 0x1B63542, 0xDFD124, 0x9E020B697, 0x122, 0x765421014CEAA067, 0x929F498D9, 0xA613DB91EA553, 0x1BA, 0xB77BDE51E3D6D5, 0x1E925, 0x4A73117A978BD8B, 0xAE3EC69923A563, 0x28DD3340527C9, 0x5E07CA2135, 0x51E, 0x4C3D8A1855F, 0x27AD, 0x3229BFC8F02B52, 0x15928, 0x1FFD1A, 0x1833, 0x31AC6, 0x01},
},
{
[]byte{0x78, 0xF4, 0x61, 0xC2, 0x47, 0x09, 0x4B, 0x98, 0xDD, 0x2A, 0xF5, 0x9F, 0x24, 0x99, 0x71, 0x4A, 0x3E, 0x0E, 0xB0, 0xEF, 0xB0, 0xAA, 0x6C, 0x61, 0xB2, 0xF6, 0x46, 0x0F, 0xB5, 0x94, 0x3E, 0x64, 0x4A, 0x5B, 0x55, 0xF4, 0x16, 0xF0, 0x65, 0xB4, 0x74, 0xD9, 0x3F, 0x07, 0x29, 0x7E, 0x12, 0xBF, 0xF6, 0xC1, 0x39, 0x0B, 0x1E, 0x33, 0xC0, 0x65, 0xEC, 0x68, 0xA2, 0x1E, 0xBE, 0xD1, 0x5A, 0x66, 0xC2, 0xCD, 0xA6, 0xF2, 0x46, 0x39, 0x03, 0x84, 0xE1, 0xF9, 0x72, 0x46, 0xF5, 0x3E, 0xA3, 0x3B, 0x49, 0x47, 0x0D, 0xB2, 0xBA, 0x43, 0x5A, 0x6B, 0x52, 0xF2, 0x01, 0x99, 0x3F, 0xBB, 0x0F, 0xA3, 0x55, 0x95, 0xB3, 0x5E},
[]uint{22, 44, 17, 40, 32, 4, 31, 20, 14, 57, 50, 57, 3, 10, 24, 59, 58, 18, 40, 51, 19, 25, 33, 55, 17},
[]uint64{0x1E3D18, 0x7091C252E63, 0xE957, 0xACF924CB8A, 0x51F07587, 0x07, 0x6C2A9B18, 0x6CBD9, 0x60F, 0x16B287CC894B6AB, 0x3A0B7832DA3A6, 0x193F07297E12BFF, 0x03, 0x182, 0x72163C, 0x33C065EC68A21EB, 0x3B45699B0B369BC, 0x24639, 0x384E1F972, 0x237A9F519DA4A, 0x1C36C, 0x15D21AD, 0x6B52F201, 0x4C9FDD87D1AACA, 0x1B35E},
},
{
[]byte{0x5D, 0x8E, 0x1E, 0xCA, 0x9E, 0xB2, 0x62, 0x1F, 0xC3, 0x5C, 0xD0, 0x64, 0xC8, 0x63, 0xD9, 0x53, 0x2F, 0x2E, 0x5E, 0x6D, 0x03, 0xC6, 0xB1, 0xFE, 0x3A, 0xAE, 0x99, 0x3C, 0x47, 0x91, 0x34, 0x15, 0x1C, 0x95, 0xE4, 0xD1, 0xD0, 0xC0, 0xE7, 0xFD, 0x66, 0x35, 0x33, 0xC3, 0x03, 0xAA, 0x77, 0xCC, 0x1C, 0x77, 0x92, 0xB9, 0xA2, 0xD7, 0xE4, 0xEA, 0xD1, 0x4A, 0x74, 0xF4, 0x05, 0x4C, 0xCB, 0xBF, 0xEB, 0x98, 0x20, 0x8F, 0x77, 0x4D, 0xAA, 0x13, 0xD6, 0xB1, 0xCF, 0x80, 0x9D, 0x6B, 0xDB, 0x02, 0xA9, 0xA3, 0xD2, 0x0F, 0xCA, 0x4D, 0xDC, 0xC5, 0x58, 0x10, 0x3D, 0x96, 0x82, 0xF1, 0x00, 0x32, 0x6B, 0x25, 0xFC, 0x0E},
[]uint{39, 44, 24, 38, 3, 27, 12, 58, 22, 28, 54, 20, 35, 30, 27, 46, 41, 35, 44, 19, 1, 20, 41, 8, 36, 48},
[]uint64{0x2EC70F654F, 0x59310FE1AE6, 0x832643, 0x7B2A65E5C, 0x05, 0x73681E3, 0x58F, 0x3C755D32788F226, 0x20A8E4, 0xAF268E8, 0x181CFFACC6A678, 0x60754, 0x77CC1C779, 0xAE68B5F, 0x49D5A29, 0x13A7A02A665D, 0x1FEB98208F7, 0x3A6D509EB, 0x58E7C04EB5E, 0x6C0AA, 0x00, 0xD1E90, 0xFCA4DDCC55, 0x81, 0x3D9682F1, 0x326B25FC0E},
},
{
[]byte{0xB4, 0x6D, 0x53, 0x49, 0xB7, 0x06, 0x34, 0x33, 0x99, 0x26, 0xC8, 0x16, 0x3E, 0x5F, 0x8E, 0x87, 0x26, 0xDE, 0x13, 0xBD, 0xBA, 0xEA, 0x1A, 0x03, 0xCD, 0x2E, 0xAC, 0x7D, 0x79, 0xFA, 0x25, 0x4F, 0xAF, 0x5B, 0xC4, 0xE4, 0x6A, 0x50, 0x33, 0x83, 0xCC, 0xF5, 0x49, 0x3E, 0xCF, 0xAC, 0xAA, 0x94, 0x89, 0x33, 0xB6, 0xC4, 0x77, 0xBF, 0xAF, 0xE6, 0xFA, 0x07, 0x07, 0x5B, 0x8E, 0x6B, 0x8B, 0xFE, 0x1C, 0xE3, 0x20, 0xF3, 0x17, 0x54, 0x3F, 0x38, 0x99, 0xD4, 0xAB, 0x85, 0xE7, 0x7D, 0x47, 0xE3, 0x41, 0x98, 0xE9, 0x5B, 0xF4, 0x38, 0x18, 0xEE, 0x13, 0x64, 0x2E, 0xC3, 0x5F, 0x22, 0x42, 0x41, 0xCB, 0x62, 0x59, 0xBE},
[]uint{56, 11, 10, 52, 2, 11, 13, 21, 25, 24, 13, 2, 52, 27, 43, 10, 16, 41, 13, 46, 60, 57, 4, 62, 43, 13, 40, 28, 5},
[]uint64{0xB46D5349B70634, 0x19C, 0x324, 0xD902C7CBF1D0E, 0x01, 0x1B7, 0x109D, 0x1DBAEA, 0x34079A, 0x5D58FA, 0x1E7E, 0x02, 0x254FAF5BC4E46, 0x52819C1, 0x733D524FB3E, 0x2CA, 0xA948, 0x12676D88EF7, 0x1EBF, 0x26FA07075B8E, 0x6B8BFE1CE320F31, 0xEA87E7133A9570, 0x0B, 0x33BEA3F1A0CC74AD, 0x7D0E063B84D, 0x1217, 0x61AF912120, 0xE5B12CD, 0x1E},
},
{
[]byte{0x23, 0xFE, 0xE6, 0xE3, 0x2F, 0x43, 0xE0, 0x65, 0xBD, 0xCA, 0xD1, 0xD8, 0x44, 0x1A, 0x37, 0x2C, 0xF8, 0xB3, 0x17, 0x83, 0x0E, 0x12, 0xDB, 0x23, 0x90, 0x83, 0x9C, 0xBF, 0x7D, 0x16, 0x5E, 0x28, 0xCA, 0x6E, 0x86, 0xE0, 0x09, 0x61, 0x71, 0xE5, 0x00, 0x4D, 0xCE, 0xE1, 0x8A, 0xA8, 0xBD, 0xB1, 0xD5, 0xC4, 0xF2, 0xEF, 0x0B, 0xEE, 0x07, 0x6A, 0x12, 0x2F, 0xB1, 0x2B, 0x5D, 0x0B, 0xC4, 0xD3, 0xE0, 0x9A, 0xC6, 0xDC, 0x25, 0x75, 0x87, 0xC8, 0xB2, 0x7B, 0xAE, 0x6A, 0xC8, 0x3C, 0xF9, 0x2A, 0xC6, 0xD7, 0xBD, 0x6D, 0x88, 0x91, 0x82, 0xAB, 0x01, 0xA0, 0x3C, 0x3E, 0xE2, 0x5B, 0x22, 0xB9, 0xF4, 0x40, 0x13, 0x27},
[]uint{46, 17, 6, 2, 47, 18, 58, 46, 1, 3, 45, 56, 64, 21, 53, 35, 1, 38, 57, 31, 7, 49, 8, 60, 31},
[]uint64{0x8FFB9B8CBD0, 0x1F032, 0x37, 0x02, 0x72B47611068D, 0x32CF8, 0x2CC5E0C384B6C8E, 0x10839CBF7D16, 0x00, 0x05, 0x1C5194DD0DC0, 0x12C2E3CA009B9D, 0xC315517B63AB89E5, 0x1BC2FB, 0x103B50917D895A, 0x742F134F8, 0x00, 0x1358DB84AE, 0x161F22C9EEB9AB2, 0x79F2558, 0x6D, 0xF7ADB1123055, 0x60, 0x340787DC4B64573, 0x74401327},
},
{
[]byte{0xD7, 0x29, 0xE8, 0xD8, 0x9D, 0x5F, 0x04, 0x11, 0x02, 0x6B, 0xDE, 0x9E, 0x4F, 0x4B, 0xF9, 0x97, 0x75, 0x01, 0xB6, 0x49, 0xE5, 0x48, 0xFF, 0x34, 0x2A, 0xE6, 0xCF, 0x5D, 0x85, 0x6D, 0xF8, 0x35, 0x8C, 0xEA, 0x04, 0xB3, 0x10, 0x5B, 0x07, 0x80, 0x3B, 0xD5, 0x69, 0x4E, 0xD2, 0xA5, 0x9F, 0x6A, 0x38, 0x77, 0x58, 0x5C, 0x79, 0xEB, 0x03, 0x30, 0x5C, 0x5D, 0x7D, 0x47, 0xD1, 0xD3, 0xAE, 0xC2, 0xE8, 0xB5, 0x69, 0x35, 0x58, 0xD5, 0xC2, 0x91, 0x80, 0x4E, 0x1B, 0x87, 0x92, 0xB2, 0x60, 0x69, 0x02, 0x6F, 0x47, 0x1B, 0x89, 0x14, 0x7E, 0x4F, 0xE4, 0xF9, 0xF0, 0x4D, 0xBD, 0x76, 0x72, 0x36, 0xF3, 0xD8, 0xB8, 0x4D},
[]uint{43, 23, 21, 42, 26, 28, 54, 30, 49, 8, 33, 11, 25, 35, 39, 38, 21, 37, 62, 7, 60, 57, 36, 15},
[]uint64{0x6B94F46C4EA, 0x7C1044, 0x135EF, 0x13C9E97F32E, 0x3A80DB2, 0x4F2A47F, 0x26855CD9EBB0AD, 0x2FC1AC67, 0xA04B3105B078, 0x03, 0x17AAD29DA, 0x2A5, 0x13ED470, 0x77585C79E, 0x581982E2EB, 0x3A8FA3A75D, 0x10BA2D, 0xB49AAC6AE, 0x523009C370F2564, 0x60, 0x69026F471B89147, 0x1C9FC9F3E09B7AE, 0xCE46DE7B1, 0x384D},
},
{
[]byte{0x76, 0x2E, 0x87, 0xCE, 0x9D, 0x1C, 0xF7, 0x87, 0xD8, 0x0E, 0xD4, 0x6B, 0x3D, 0x01, 0x84, 0x6C, 0xDE, 0xF7, 0x72, 0xC4, 0xCC, 0xAE, 0xC4, 0xF4, 0x35, 0xBD, 0xDC, 0xA5, 0x69, 0x4F, 0xFF, 0x98, 0x7D, 0x30, 0xBE, 0x40, 0xE7, 0x39, 0xF6, 0xFD, 0x52, 0x19, 0xD9, 0x51, 0xB4, 0x04, 0x22, 0x5C, 0x93, 0x07, 0x7D, 0xB9, 0xF0, 0x5D, 0x53, 0x67, 0x6E, 0xAA, 0xCF, 0x28, 0x16, 0x14, 0x2C, 0x28, 0x5A, 0xB9, 0x20, 0xD3, 0x8C, 0x42, 0xFC, 0x6D, 0xE5, 0x68, 0x47, 0x84, 0xBF, 0x4D, 0x9C, 0x55, 0x62, 0x56, 0x10, 0xAE, 0xFC, 0x1E, 0x91, 0x8B, 0x52, 0x52, 0x49, 0x25, 0x3C, 0x6F, 0xC0, 0x59, 0x59, 0x2D, 0x80, 0x43},
[]uint{42, 51, 40, 8, 22, 55, 9, 12, 60, 53, 35, 48, 31, 50, 34, 7, 7, 53, 55, 41, 35, 32, 2, 18},
[]uint64{0x1D8BA1F3A74, 0x39EF0FB01DA8D, 0x67A0308D9B, 0xDE, 0x3B9626, 0x32BB13D0D6F772, 0x12B, 0x4A7, 0xFFCC3E985F20739, 0x19F6FD5219D951, 0x5A02112E4, 0x983BEDCF82EA, 0x4D9DBAAB, 0xF2816142C285, 0x2AE4834E3, 0x08, 0x2F, 0x18DBCAD08F097E, 0x4D9C55625610AE, 0x1F83D2316A4, 0x5249253C6, 0xFC059592, 0x03, 0x18043},
},
{
[]byte{0x33, 0xC2, 0xC3, 0xBC, 0x9D, 0x2A, 0x36, 0xB4, 0x92, 0x36, 0x02, 0x93, 0x54, 0xB9, 0x86, 0x32, 0xC1, 0x0C, 0x75, 0xC4, 0x3B, 0xE4, 0x0A, 0x3F, 0xDF, 0x4E, 0xF6, 0x05, 0x4F, 0x30, 0x19, 0xA6, 0xE9, 0xE6, 0x55, 0xAF, 0xE8, 0xC4, 0x3F, 0xFF, 0xE3, 0x40, 0xC1, 0xA2, 0xE1, 0x05, 0xD7, 0x77, 0x82, 0xD5, 0xF9, 0xA6, 0x0F, 0x54, 0xED, 0x96, 0xA0, 0x68, 0xEC, 0xAE, 0x57, 0xE3, 0x6A, 0xD2, 0xCE, 0x18, 0x9A, 0xC2, 0x5E, 0x10, 0x3C, 0x21, 0x5C, 0x38, 0xA9, 0xC4, 0x82, 0x76, 0xF9, 0xA9, 0x9B, 0x33, 0x43, 0x40, 0x61, 0xDD, 0x0D, 0x83, 0x9E, 0xDE, 0x08, 0x4C, 0x13, 0x33, 0x82, 0x6A, 0xF4, 0xAB, 0x61, 0x1C},
[]uint{28, 60, 58, 5, 41, 56, 29, 27, 38, 2, 28, 51, 3, 63, 33, 57, 36, 61, 22, 1, 62, 26, 13},
[]uint64{0x33C2C3B, 0xC9D2A36B4923602, 0x24D52E618CB0431, 0x1A, 0x1C43BE40A3F, 0xDF4EF6054F3019, 0x14DD3CCA, 0x5AFE8C4, 0xFFFF8D030, 0x01, 0xA2E105D, 0x3BBC16AFCD307, 0x05, 0x29DB2D40D1D95CAF, 0x18DAB4B38, 0xC4D612F081E10A, 0xE1C54E241, 0x76F9A99B3343406, 0x77436, 0x00, 0x73DBC1098266704, 0x357A55B, 0x11C},
},
{
[]byte{0xCB, 0x0A, 0x64, 0xC1, 0xEF, 0xEC, 0x67, 0x09, 0xE1, 0x9A, 0x2A, 0xC2, 0xC5, 0xD9, 0xC7, 0x3D, 0x2A, 0x49, 0x3E, 0xF4, 0x30, 0xC9, 0x47, 0x2E, 0xEC, 0xAA, 0x46, 0xDA, 0x31, 0x62, 0x27, 0x4F, 0xAD, 0x4C, 0x50, 0xCD, 0x83, 0x51, 0x37, 0x09, 0x8B, 0xC7, 0x6D, 0x62, 0xFE, 0xC3, 0xE9, 0x91, 0xE5, 0xE8, 0x4D, 0x11, 0x1B, 0xDE, 0x03, 0x23, 0xAA, 0x1E, 0x65, 0xAD, 0x06, 0x23, 0x28, 0xD2, 0xDF, 0x59, 0x47, 0x52, 0xF2, 0x3F, 0xC7, 0x68, 0x50, 0x20, 0xF3, 0x2A, 0xC0, 0xFB, 0xBB, 0xC0, 0xAD, 0x26, 0xA6, 0x75, 0x19, 0x1B, 0xD8, 0x1F, 0xF9, 0xFD, 0x33, 0x10, 0x2C, 0x15, 0x80, 0xDC, 0xA7, 0xF6, 0xF4, 0x50},
[]uint{21, 51, 60, 7, 33, 20, 14, 36, 57, 10, 51, 3, 17, 50, 55, 3, 14, 7, 35, 45, 12, 43, 50, 51, 28, 27},
[]uint64{0x19614C, 0x4C1EFEC6709E1, 0x9A2AC2C5D9C73D2, 0x52, 0x93EF430C, 0x9472E, 0x3B2A, 0x91B68C588, 0x13A7D6A62866C1A, 0x226, 0x7098BC76D62FE, 0x06, 0x3E99, 0x797A134446F7, 0x40647543CCB5A0, 0x06, 0x8CA, 0x1A, 0x2DF594752, 0x1E47F8ED0A04, 0x1E6, 0x2AC0FBBBC0A, 0x349A99D4646F6, 0x3FF3FA662058, 0x2B01B94, 0x7F6F450},
},
{
[]byte{0x56, 0x6B, 0xDA, 0x9E, 0xD9, 0x04, 0x9A, 0xE7, 0x5E, 0x85, 0x25, 0x0B, 0x1D, 0xEF, 0xB8, 0x65, 0x6F, 0xFF, 0xE5, 0x6F, 0x02, 0xA8, 0xE2, 0x9B, 0x18, 0xC2, 0x11, 0x8A, 0x7E, 0xB5, 0xDF, 0x72, 0x44, 0x0C, 0xC7, 0x85, 0x43, 0xC5, 0x75, 0x3A, 0x2B, 0x1F, 0xA5, 0x75, 0x66, 0x42, 0x15, 0x03, 0xB3, 0x2F, 0x90, 0xCB, 0x2B, 0x56, 0x8E, 0x2E, 0xB1, 0x98, 0xD0, 0x5D, 0x53, 0x8D, 0x7C, 0xF8, 0x0E, 0x07, 0x98, 0x60, 0x4E, 0x8D, 0x69, 0xF9, 0x2E, 0xD7, 0x9A, 0xE2, 0x4D, 0x37, 0x49, 0xB9, 0x59, 0x5D, 0x2D, 0xC2, 0x7E, 0x50, 0x7B, 0x97, 0x4F, 0x06, 0x2B, 0xBC, 0xCB, 0x10, 0x3E, 0x0E, 0xD3, 0xF8, 0x7E, 0x78},
[]uint{38, 55, 32, 34, 58, 58, 53, 8, 29, 19, 37, 46, 7, 55, 39, 44, 24, 5, 5, 22, 19, 11, 49, 40, 13},
[]uint64{0x159AF6A7B6, 0x20935CEBD0A4A1, 0x63BDF70C, 0x2B7FFF2B7, 0x20551C536318423, 0x53F5AEFB922066, 0x78543C5753A2B, 0x1F, 0x14AEACC8, 0x21503, 0x1665F21965, 0x1AB471758CC6, 0x41, 0x3AA71AF9F01C0F, 0x18604E8D69, 0xF92ED79AE24, 0xD3749B, 0x12, 0x16, 0x15D2DC, 0x13F28, 0x1EE, 0xBA78315DE658, 0x81F0769FC3, 0x1E78},
},
{
[]byte{0x52, 0xEE, 0x85, 0xDF, 0x00, 0xC1, 0xE3, 0x65, 0x76, 0x46, 0x99, 0x52, 0xDC, 0xA5, 0x26, 0x5C, 0x31, 0x62, 0xEB, 0xC2, 0xCD, 0xC7, 0x27, 0x12, 0xE4, 0xFC, 0xC5, 0x56, 0xB5, 0xDB, 0x87, 0x39, 0x94, 0xFB, 0x3D, 0x31, 0x24, 0xB7, 0x16, 0x4D, 0x6E, 0x51, 0x8E, 0x47, 0x8E, 0xFF, 0xC0, 0x58, 0x09, 0xC3, 0xE7, 0xCC, 0x5C, 0xA8, 0x82, 0x0F, 0xE2, 0x4D, 0xD2, 0x6D, 0xBF, 0x9B, 0x3D, 0x28, 0xD6, 0x65, 0x6D, 0x0A, 0x05, 0x1B, 0xFA, 0x66, 0x9C, 0xF6, 0x15, 0xCE, 0x50, 0xE1, 0x21, 0x90, 0x9B, 0xA0, 0xDE, 0xDB, 0x76, 0x7C, 0xB6, 0x2D, 0x30, 0xEB, 0xCD, 0x74, 0xE5, 0x19, 0x18, 0xC0, 0x7D, 0x43, 0xA3, 0x61},
[]uint{33, 22, 19, 36, 45, 49, 18, 64, 5, 22, 40, 5, 2, 47, 9, 13, 9, 54, 55, 11, 32, 15, 22, 55, 41, 37, 24, 7, 9},
[]uint64{0xA5DD0BBE, 0x60F1, 0x595D9, 0x1A654B729, 0x932E18B175E, 0x2CDC72712E4F, 0x33155, 0xAD76E1CE653ECF4C, 0x09, 0x96E2C, 0x9ADCA31C8F, 0x03, 0x02, 0x7FE02C04E1F3, 0x1CC, 0xB95, 0x20, 0x20FE24DD26DBF9, 0x59E946B32B6850, 0x146, 0xFE99A73D, 0x42B9, 0x328709, 0x6426E837B6DD9, 0x1E5B169875E, 0xD74E51918, 0xC07D43, 0x51, 0x161},
},
{
[]byte{0xB0, 0x67, 0x0E, 0x66, 0x77, 0x4D, 0x4E, 0xDB, 0xEB, 0xDC, 0x05, 0x3B, 0xAA, 0xBB, 0xE8, 0x71, 0x59, 0xD4, 0x71, 0x53, 0xBE, 0xF4, 0x78, 0x2A, 0xB8, 0x9F, 0x09, 0xBB, 0x18, 0x2D, 0x89, 0xD7, 0xDF, 0x15, 0xB9, 0xD6, 0x6D, 0x90, 0x3F, 0x2B, 0xBF, 0xF7, 0xC7, 0x41, 0x1D, 0xCA, 0xAB, 0x52, 0x41, 0x21, 0x6F, 0xB1, 0xF1, 0x2F, 0xCD, 0xC8, 0x85, 0xC3, 0xD7, 0x80, 0x82, 0xFB, 0x86, 0x14, 0x3E, 0x34, 0x95, 0x3E, 0x82, 0xE2, 0x14, 0x51, 0x93, 0xFE, 0xEE, 0x0A, 0xF2, 0xFE, 0xDE, 0x97, 0xB7, 0xEF, 0x1F, 0x95, 0x5D, 0x8F, 0xE8, 0x59, 0xC9, 0x5E, 0x9B, 0x9D, 0x35, 0x0C, 0x84, 0x54, 0x7D, 0x7D, 0x30, 0x42},
[]uint{1, 13, 4, 42, 5, 62, 28, 12, 37, 22, 51, 1, 36, 54, 18, 39, 13, 57, 64, 24, 56, 44, 24, 63, 30},
[]uint64{0x01, 0xC19, 0x0C, 0xE66774D4ED, 0x17, 0x35EE029DD55DF438, 0xACEA38A, 0x9DF, 0xF4782AB89, 0x3C26EC, 0x305B13AFBE2B7, 0x00, 0x759B640FC, 0x2BBFF7C7411DCA, 0x2AD49, 0x242DF63E2, 0xBF3, 0xE442E1EBC0417D, 0xC30A1F1A4A9F4171, 0xA28C9, 0xFF7705797F6F4B, 0xDBF78FCAAEC, 0x7F42CE, 0x257A6E74D4321151, 0x3D7D3042},
},
{
[]byte{0xD8, 0x92, 0xDB, 0xF2, 0x33, 0xA4, 0x8B, 0x06, 0xD6, 0xC5, 0xBE, 0x2D, 0x6B, 0x2B, 0x82, 0x33, 0x75, 0xA7, 0xD4, 0x36, 0x2F, 0x46, 0x81, 0xE1, 0xC7, 0xBB, 0xDC, 0xF9, 0x1C, 0x93, 0xF8, 0xEB, 0xFA, 0x14, 0xF3, 0xD2, 0xCB, 0xD7, 0x70, 0x24, 0xAA, 0x92, 0xE5, 0xB3, 0x14, 0x5F, 0x18, 0x14, 0xEC, 0xC3, 0x5B, 0xF0, 0x33, 0xE7, 0xF6, 0xA7, 0x2D, 0x0F, 0xF7, 0x0A, 0x84, 0xD1, 0x87, 0xEF, 0xDD, 0xCD, 0xDC, 0xA8, 0xA1, 0xEF, 0x18, 0x6F, 0xDB, 0x05, 0x79, 0xD6, 0xF9, 0x33, 0x89, 0x9A, 0x57, 0xB7, 0xAC, 0xFE, 0x1C, 0x49, 0xA5, 0x6B, 0x5D, 0x15, 0x19, 0x1F, 0x74, 0x35, 0x87, 0xB3, 0xDD, 0xF6, 0x91, 0x59},
[]uint{59, 22, 40, 1, 33, 56, 30, 30, 20, 23, 23, 64, 4, 27, 7, 23, 11, 33, 13, 43, 20, 8, 21, 55, 56, 64, 14},
[]uint64{0x6C496DF919D2458, 0xDAD8B, 0x7C5AD65704, 0x00, 0x19BAD3EA1, 0xB17A340F0E3DDE, 0x39F23927, 0x3C75FD0A, 0x79E96, 0x2F5DC0, 0x495525, 0xCB6628BE3029D986, 0x0B, 0x3F033E7, 0x7B, 0x29CB43, 0x7EE, 0x2A13461F, 0x17EE, 0x73772A287BC, 0x61BF6, 0xC1, 0xBCEB7, 0x64CE26695EDEB3, 0xF8712695AD7454, 0x647DD0D61ECF77DA, 0x1159},
},
{
[]byte{0xEE, 0xDC, 0x02, 0xB6, 0x64, 0xD5, 0x98, 0xBA, 0x54, 0x05, 0x83, 0x4E, 0xB1, 0xC6, 0x5E, 0x02, 0x6F, 0x12, 0x3A, 0xC4, 0xD4, 0x99, 0xF8, 0xF4, 0x4E, 0xC5, 0x5F, 0x69, 0xB9, 0xEE, 0xFF, 0xB0, 0x5A, 0x10, 0x69, 0xEF, 0x95, 0x82, 0xA6, 0x51, 0xAC, 0x06, 0x46, 0x6A, 0x69, 0x80, 0x07, 0x5A, 0xDB, 0x0B, 0x58, 0x49, 0xD3, 0x9B, 0xD6, 0x66, 0xFC, 0x14, 0x05, 0x58, 0x46, 0x98, 0x16, 0xC0, 0x3E, 0x50, 0xDB, 0xD7, 0x68, 0xC1, 0xFE, 0x16, 0xA8, 0xE6, 0x80, 0x21, 0xBA, 0xC1, 0x89, 0xB7, 0xD3, 0xCF, 0xDF, 0x3E, 0x5E, 0xB0, 0x76, 0x25, 0xB0, 0xB8, 0x65, 0xA1, 0x57, 0x35, 0x2B, 0x79, 0x35, 0x23, 0x70, 0x7A},
[]uint{19, 14, 28, 59, 53, 55, 20, 4, 1, 40, 36, 2, 42, 20, 60, 61, 59, 46, 62, 23, 50, 4, 42},
[]uint64{0x776E0, 0x56C, 0xC9AB317, 0x25405834EB1C65E, 0x4DE247589A93, 0x1F8F44EC55F69B, 0x9EEFF, 0x0B, 0x00, 0xB420D3DF2, 0xB054CA358, 0x00, 0xC8CD4D3000, 0xEB5B6, 0x16B093A737ACCDF, 0x105015611A605B00, 0x7CA1B7AED183FC2, 0x354734010DD6, 0x3136FA79FBE7CBD, 0x307625, 0x2C2E196855CD4, 0x0A, 0x3793523707A},
},
{
[]byte{0x26, 0x44, 0x9D, 0xFF, 0x6D, 0x96, 0x22, 0x0A, 0xD1, 0xF2, 0xE7, 0x81, 0xD8, 0xEC, 0x90, 0xFD, 0x74, 0x52, 0x63, 0x4A, 0x3C, 0x34, 0xDB, 0x1A, 0xA8, 0xDF, 0xA5, 0x62, 0x34, 0x57, 0x32, 0x2C, 0x53, 0xEC, 0xDF, 0x03, 0xFC, 0xE0, 0x86, 0x03, 0x24, 0xCD, 0x44, 0x36, 0xDF, 0xE2, 0x2F, 0x55, 0x25, 0xD6, 0x27, 0xF3, 0x2E, 0xDB, 0x38, 0x31, 0x5D, 0xAC, 0x2C, 0x28, 0x05, 0x33, 0xA2, 0xFB, 0x0D, 0x7C, 0x02, 0x1B, 0x8A, 0xD4, 0xDF, 0xFC, 0x02, 0x69, 0xC4, 0x2C, 0x65, 0x6F, 0x8C, 0xA4, 0x2F, 0x19, 0x04, 0xBE, 0xC5, 0x0F, 0x8C, 0xF0, 0xB1, 0x8A, 0x2E, 0x58, 0x96, 0xC3, 0x87, 0x1F, 0x89, 0x4F, 0xA9, 0x44},
[]uint{37, 50, 48, 42, 39, 50, 30, 29, 11, 10, 17, 20, 29, 52, 50, 17, 27, 47, 16, 16, 25, 61, 28, 8, 29, 12},
[]uint64{0x4C893BFED, 0x2CB110568F973, 0xC0EC76487EBA, 0xA4C6947869, 0x5B1AA8DFA5, 0x188D15CC8B14F, 0x2CDF03FC, 0x1C10C064, 0x4CD, 0x110, 0x1B6FF, 0x117AA, 0x125D627F, 0x32EDB38315DAC, 0xB0A014CE8BEC, 0x6BE0, 0x86E2B5, 0x1BFF804D3885, 0x8CAD, 0xF194, 0x10BC641, 0x5F6287C67858C51, 0x72C4B61, 0xC3, 0x11F894FA, 0x944},
},
{
[]byte{0x93, 0xC5, 0x74, 0xE2, 0x73, 0x08, 0xB2, 0xDD, 0xB8, 0xD7, 0xD5, 0xC3, 0x88, 0x2F, 0x98, 0xA2, 0xB8, 0x42, 0x98, 0xE2, 0xFD, 0xC6, 0x7F, 0x6C, 0x47, 0xE6, 0xC5, 0x9D, 0x30, 0x31, 0x40, 0x3C, 0x63, 0xE7, 0xD1, 0x20, 0x1E, 0x85, 0xF9, 0x40, 0x98, 0xE8, 0x9F, 0x31, 0xDF, 0x9E, 0x14, 0xEE, 0xB5, 0x62, 0x56, 0x7F, 0x88, 0x3F, 0xE1, 0xD1, 0xEB, 0xAC, 0x09, 0xCD, 0x71, 0xF8, 0x23, 0x07, 0xDA, 0x37, 0x32, 0x37, 0xDE, 0x65, 0x21, 0x72, 0x9B, 0x89, 0x9B, 0xEC, 0x35, 0xBC, 0x6B, 0xB8, 0x20, 0x00, 0xF6, 0xA9, 0x06, 0xDC, 0xAC, 0xE8, 0xC3, 0x52, 0x89, 0x20, 0x74, 0xC9, 0xB3, 0xCC, 0x72, 0x45, 0x0E, 0x76},
[]uint{49, 42, 47, 16, 27, 33, 16, 39, 45, 23, 47, 52, 64, 20, 17, 63, 30, 50, 23, 54, 31, 12},
[]uint64{0x1278AE9C4E611, 0x196EDC6BEAE, 0xE20BE628AE1, 0xA63, 0x45FB8CF, 0x1DB11F9B1, 0x674C, 0x628078C7C, 0x1F44807A17E5, 0x131D1, 0x1F31DF9E14EE, 0xB562567F883FE, 0x1D1EBAC09CD71F82, 0x307DA, 0x6E64, 0x37DE6521729B899B, 0x3B0D6F1A, 0x3B82000F6A906, 0x6E5674, 0x186A51240E9936, 0x3CC72450, 0xE76},
},
{
[]byte{0xCA, 0x4E, 0x83, 0x60, 0x1A, 0xEF, 0xAC, 0x61, 0x4C, 0x22, 0x4A, 0xE3, 0xFC, 0xEF, 0x32, 0x2A, 0xDB, 0x52, 0x73, 0xC3, 0xEB, 0xA6, 0xF0, 0xAE, 0x35, 0x1D, 0x0C, 0xDE, 0x1D, 0x38, 0x41, 0x75, 0x4B, 0xF3, 0x62, 0x98, 0x73, 0x07, 0xB9, 0x58, 0x83, 0x38, 0x29, 0xE3, 0xCD, 0x38, 0xBA, 0xF0, 0x59, 0xDC, 0x74, 0xE4, 0xE4, 0x17, 0x6C, 0x83, 0xBF, 0x52, 0xDB, 0xEA, 0xF5, 0xFA, 0xBF, 0x1D, 0xBA, 0x13, 0xED, 0xDA, 0x93, 0x6E, 0xCB, 0x89, 0x1E, 0x83, 0x72, 0xC5, 0x28, 0x3A, 0x5F, 0x8D, 0xAF, 0xDB, 0xDD, 0x6E, 0xA9, 0xD2, 0x76, 0x4B, 0x7F, 0x4A, 0xD8, 0x0E, 0xBF, 0xE0, 0xC6, 0x5F, 0xA0, 0x77, 0x7A, 0x2B},
[]uint{57, 31, 47, 37, 29, 27, 49, 3, 52, 31, 34, 41, 35, 37, 47, 59, 31, 46, 10, 7, 14, 54, 22},
[]uint64{0x1949D06C035DF58, 0x614C224A, 0x71FE7799156D, 0x15273C3EBA, 0xDE15C6A, 0x1D0CDE1, 0x1A7082EA97E6C, 0x02, 0x987307B958833, 0x414F1E69, 0x3175E0B3B, 0x11D393905DB, 0x1077EA5B7, 0x1ABD7EAFC7, 0x37427DBB526D, 0x6CB891E8372C528, 0x1D2FC6D7, 0x3B7BADD53A4E, 0x325, 0x5F, 0x34AD, 0x203AFF83197E81, 0x377A2B},
},
{
[]byte{0x2C, 0x77, 0x59, 0x98, 0x44, 0xE0, 0xD5, 0x78, 0x5F, 0xFE, 0xD1, 0x44, 0xAD, 0xCC, 0x78, 0x46, 0x69, 0x3B, 0xD5, 0xC2, 0x03, 0xE1, 0x24, 0x54, 0x8C, 0xAB, 0x06, 0x61, 0x78, 0x78, 0x89, 0x42, 0x8B, 0x1C, 0x9E, 0xA1, 0x13, 0xC8, 0x09, 0xAB, 0x7E, 0xD6, 0xC6, 0xB2, 0xAF, 0x4D, 0x1D, 0xB4, 0x85, 0xB5, 0x5D, 0x39, 0x23, 0x8E, 0x67, 0x8D, 0x48, 0xA1, 0x1B, 0x42, 0xDD, 0xBD, 0xCB, 0x53, 0xA8, 0x20, 0x50, 0xF7, 0x44, 0xE7, 0xBC, 0x7A, 0x85, 0x09, 0x71, 0x04, 0xCF, 0x81, 0xCA, 0xB4, 0x10, 0xF2, 0xBF, 0xC7, 0x7C, 0x05, 0xC3, 0x62, 0x19, 0x79, 0x04, 0x7F, 0xF8, 0x54, 0x85, 0x0E, 0x35, 0xE4, 0x64, 0x4C},
[]uint{35, 33, 39, 14, 2, 40, 63, 64, 53, 56, 47, 42, 51, 12, 9, 43, 58, 55, 32, 52},
[]uint64{0x163BACCC2, 0x4E0D5785, 0x7FF68A256E, 0x18F0, 0x02, 0x3349DEAE10, 0xF84915232AC1985, 0xE1E2250A2C727A84, 0x9E404D5BF6B63, 0x5957A68EDA42DA, 0x574E48E399E3, 0x148A11B42DD, 0x5EE5A9D410287, 0xBA2, 0xE7, 0x5E3D4284B88, 0x99F03956821E57, 0x7C77C05C362197, 0x9047FF85, 0x4850E35E4644C},
},
{
[]byte{0x2F, 0x1E, 0xB8, 0x50, 0xC1, 0xF6, 0xD4, 0xD4, 0x33, 0xD8, 0x40, 0xC9, 0x5E, 0xB5, 0x29, 0x9E, 0x60, 0x65, 0xB4, 0xD2, 0x68, 0x4D, 0x3F, 0x7E, 0x0D, 0xCB, 0xE6, 0x9E, 0x0D, 0x2A, 0x4C, 0xF5, 0xD4, 0x0D, 0x20, 0x36, 0x17, 0xCB, 0xCD, 0x2A, 0xA4, 0xBE, 0x08, 0x48, 0x7C, 0xFE, 0x77, 0x28, 0xDA, 0xC0, 0xFF, 0xAC, 0x48, 0xF5, 0xCD, 0x34, 0xCD, 0x1D, 0x6E, 0x13, 0x19, 0xDD, 0x0D, 0xF1, 0x78, 0x41, 0x59, 0x87, 0xDB, 0x13, 0x44, 0xC1, 0xE0, 0xB7, 0x9C, 0x18, 0xF9, 0x4E, 0x09, 0x53, 0x99, 0x95, 0x9D, 0x7C, 0x0E, 0xDB, 0xF5, 0x7D, 0x55, 0x20, 0x19, 0x6A, 0x39, 0x30, 0xC8, 0x6E, 0xE7, 0x0E, 0xCA, 0x02},
[]uint{15, 11, 7, 40, 53, 47, 60, 55, 29, 8, 29, 25, 53, 33, 45, 9, 30, 17, 30, 11, 7, 37, 35, 43, 25, 19, 8, 19},
[]uint64{0x178F, 0x2E1, 0x21, 0x83EDA9A867, 0x16103257AD4A67, 0x4C0CB69A4D09, 0xA7EFC1B97CD3C1A, 0x2A4CF5D40D2036, 0x2F979A5, 0x54, 0x12F82121, 0x1E7F3B9, 0x8DAC0FFAC48F5, 0x19A699A3A, 0x1B84C677437C, 0xBC, 0x82B30FB, 0xC4D1, 0xC1E0B79, 0x60C, 0x3E, 0xA704A9CCC, 0x5675F03B6, 0x7EAFAAA4032, 0x1A8E4C3, 0x10DDC, 0xE1, 0x6CA02},
},
{
[]byte{0x52, 0x18, 0x09, 0x9C, 0xE3, 0xF6, 0x3F, 0xA5, 0xED, 0xF7, 0x0E, 0xB9, 0x49, 0x47, 0x88, 0x47, 0x62, 0x11, 0x91, 0x9A, 0xDD, 0x33, 0x2C, 0xF9, 0x77, 0x0C, 0xFE, 0x5D, 0xBC, 0x11, 0x25, 0x0C, 0x57, 0x41, 0x2E, 0x26, 0x6A, 0x84, 0xF4, 0x6B, 0x74, 0x45, 0x74, 0x06, 0x1F, 0xAF, 0x0E, 0x4D, 0x5A, 0xBF, 0x4E, 0x02, 0x6E, 0xF5, 0x7B, 0xA4, 0xCD, 0x5F, 0xFC, 0x9B, 0xA3, 0x7D, 0x8D, 0x35, 0x11, 0xEE, 0x63, 0x6B, 0xE1, 0xC8, 0x51, 0xDB, 0x79, 0x94, 0x42, 0x4D, 0xEA, 0xAE, 0xBD, 0xC0, 0x24, 0x0C, 0x28, 0x3B, 0xCB, 0x2D, 0x67, 0x10, 0x38, 0x99, 0x8F, 0xFA, 0x9D, 0x76, 0xC5, 0xD9, 0x85, 0x0E, 0xDA, 0x45},
[]uint{33, 3, 51, 28, 16, 63, 3, 16, 33, 58, 33, 12, 64, 41, 13, 11, 52, 27, 8, 15, 1, 20, 30, 61, 34, 39, 35},
[]uint64{0xA4301339, 0x06, 0x1FB1FD2F6FB87, 0x5CA4A3C, 0x423B, 0x846466B74CCB3E5, 0x06, 0xE19F, 0x1976F0449, 0x10C57412E266A84, 0x1E8D6E88A, 0xE80, 0xC3F5E1C9AB57E9C0, 0x9BBD5EE933, 0xAFF, 0x726, 0xE8DF634D447B9, 0x46D7C39, 0x0A, 0x1DB7, 0x01, 0x32884, 0x26F5575E, 0x1C0240C283BCB2D6, 0x1C40E2663, 0x7F53AED8BB, 0x1850EDA45},
},
{
[]byte{0xD6, 0x66, 0x64, 0xE0, 0x81, 0x98, 0x56, 0xB5, 0xF4, 0xA8, 0x1E, 0x12, 0x6F, 0xB0, 0x17, 0xE7, 0x91, 0xF9, 0x6C, 0x82, 0x9F, 0x22, 0xE2, 0x15, 0x5A, 0xCE, 0x73, 0x71, 0x29, 0x69, 0x8F, 0x94, 0xC7, 0xB3, 0x4F, 0x1B, 0x16, 0x28, 0xE7, 0xD6, 0x7E, 0x5F, 0xDE, 0xB6, 0x93, 0xA8, 0xDB, 0x9B, 0x44, 0x19, 0xDC, 0xE7, 0x57, 0x69, 0x4F, 0xA9, 0x33, 0x4C, 0x16, 0x5A, 0x91, 0xE4, 0x69, 0x33, 0x34, 0x93, 0x92, 0xE0, 0x00, 0xA2, 0xF2, 0xFB, 0xA9, 0xE0, 0xB5, 0xE0, 0xC0, 0x9D, 0x39, 0x52, 0xD6, 0xA4, 0x45, 0xB3, 0x9E, 0x96, 0x51, 0x44, 0xAD, 0xF0, 0x70, 0x51, 0x7D, 0xA7, 0x9F, 0xBB, 0x20, 0x41, 0x0C, 0x94},
[]uint{49, 14, 13, 57, 39, 20, 12, 63, 47, 53, 9, 52, 41, 9, 24, 60, 44, 16, 50, 21, 42, 36, 29},
[]uint64{0x1ACCCC9C10330, 0x2B5A, 0x1F4A, 0x103C24DF602FCF2, 0x1F96C829F2, 0x2E215, 0x5AC, 0x739B894B4C7CA63D, 0x4D3C6C58A39F, 0xB3F2FEF5B49D4, 0xDB, 0x9B4419DCE7576, 0x129F5266982, 0x196, 0xA4791A, 0x4CCD24E4B80028B, 0xCBEEA782D78, 0x3027, 0x13952D6A445B3, 0x13D2CA, 0xA256F83828, 0xBED3CFDD9, 0x410C94},
},
{
[]byte{0xA1, 0xA6, 0x11, 0xEE, 0xBB, 0x60, 0x43, 0x9A, 0x10, 0xDA, 0x7D, 0xBB, 0x9D, 0xFC, 0x67, 0x7E, 0xE5, 0x57, 0x36, 0x8C, 0xB4, 0x20, 0x6D, 0x5A, 0xD1, 0x61, 0x1F, 0x1B, 0x1F, 0x23, 0x72, 0x26, 0xB1, 0xFF, 0x12, 0x26, 0xBB, 0x6D, 0x2B, 0x7A, 0x7E, 0x15, 0x5A, 0x2F, 0x0E, 0x17, 0xEF, 0x71, 0xCB, 0x1C, 0x18, 0xD0, 0xFE, 0x00, 0x9F, 0xC6, 0x0C, 0xB7, 0x45, 0xED, 0xF7, 0xB9, 0x93, 0xAF, 0xA5, 0x02, 0xB6, 0xFA, 0x8D, 0x7C, 0xF6, 0x2C, 0x36, 0x9A, 0x81, 0xB8, 0xCE, 0x89, 0x63, 0xAD, 0x26, 0x5C, 0x3B, 0x1B, 0xF7, 0xB8, 0xAE, 0xAF, 0x5C, 0x07, 0x47, 0x3C, 0x79, 0x14, 0x0F, 0x18, 0x35, 0xAA, 0x30, 0xCE},
[]uint{30, 56, 32, 18, 22, 48, 9, 2, 41, 20, 9, 18, 51, 20, 28, 52, 47, 37, 24, 24, 20, 8, 19, 25, 9, 29, 24, 37, 2, 6, 33},
[]uint64{0x2869847B, 0xAED810E684369F, 0x6EE77F19, 0x37EE5, 0x15CDA3, 0x2D081B56B458, 0x8F, 0x02, 0x6C7C8DC89A, 0xC7FC4, 0x113, 0x176DA, 0x2B7A7E155A2F0, 0xE17EF, 0x71CB1C1, 0x8D0FE009FC60C, 0x5BA2F6FBDCC9, 0x1AFA502B6F, 0xA8D7CF, 0x62C369, 0xA81B8, 0xCE, 0x44B1D, 0xD265C3, 0x163, 0xFDEE2BA, 0xBD701D, 0x39E3C8A07, 0x02, 0x0C, 0x35AA30CE},
},
{
[]byte{0x44, 0x4D, 0xAD, 0xF6, 0xC5, 0x49, 0x84, 0x42, 0x7C, 0x1C, 0x52, 0xAB, 0x5E, 0xB4, 0xB1, 0x05, 0x2A, 0x91, 0xE7, 0xAD, 0x2C, 0x17, 0x8F, 0xCE, 0xB5, 0x0A, 0x3A, 0xAA, 0x05, 0x57, 0x36, 0xFD, 0x18, 0xA4, 0x2F, 0x32, 0x14, 0xAE, 0x60, 0x5D, 0xEE, 0x36, 0xBD, 0x7B, 0x1F, 0x6A, 0xB5, 0x10, 0x26, 0x0A, 0x19, 0xD1, 0x25, 0x53, 0xEA, 0x97, 0xF3, 0x9C, 0xE6, 0x71, 0x1E, 0xA6, 0x33, 0x98, 0x6C, 0x3E, 0xB4, 0xBD, 0x1D, 0x5B, 0xDF, 0xAB, 0xEF, 0x5D, 0xDE, 0x17, 0xB0, 0x62, 0x7D, 0x71, 0x8A, 0x36, 0xF5, 0x5B, 0xD2, 0x92, 0x54, 0xB7, 0xD0, 0x1B, 0xAD, 0x75, 0x69, 0xA0, 0x5A, 0x77, 0xFD, 0xF2, 0x81, 0xF5},
[]uint{29, 23, 54, 22, 44, 39, 56, 7, 49, 58, 48, 51, 17, 63, 28, 7, 55, 32, 62, 56},
[]uint64{0x889B5BE, 0x6C5498, 0x1109F0714AAD7A, 0x34B105, 0x2A91E7AD2C1, 0x3C7E75A851, 0xD5502AB9B7E8C5, 0x10, 0x17990A57302EF, 0x1C6D7AF63ED56A2, 0x4C1433A24AA, 0x3EA97F39CE671, 0x3D4C, 0x33986C3EB4BD1D5B, 0xDFABEF5, 0x6E, 0x785EC189F5C628, 0xDBD56F4A, 0x1254B7D01BAD7569, 0xA05A77FDF281F5},
},
{
[]byte{0x0C, 0x0A, 0x46, 0x32, 0x3A, 0x2A, 0x4C, 0xD8, 0x81, 0x7D, 0x88, 0x36, 0xA9, 0x0D, 0xD2, 0xF7, 0x1C, 0x9C, 0xB9, 0xE8, 0x6B, 0x6D, 0x1D, 0xA5, 0x89, 0x16, 0x95, 0x20, 0x42, 0x46, 0x59, 0xD0, 0x4B, 0xEF, 0x6A, 0x1A, 0xD6, 0x92, 0xFF, 0x34, 0x44, 0x7D, 0x2D, 0x61, 0xC6, 0xE1, 0xAD, 0x75, 0x64, 0xDD, 0x00, 0xDA, 0x0F, 0x3E, 0xAB, 0x4D, 0x1B, 0x79, 0x55, 0x02, 0xC8, 0xF6, 0x8C, 0xF0, 0x4F, 0xAD, 0x64, 0x37, 0x08, 0xDC, 0x05, 0x4C, 0xE0, 0x3F, 0xE6, 0x0E, 0x6A, 0xC9, 0x5B, 0x82, 0x8B, 0x54, 0x2B, 0x28, 0x0F, 0xE5, 0x41, 0x4A, 0x53, 0x53, 0x81, 0x9C, 0x22, 0x75, 0xD4, 0x2A, 0x9F, 0x03, 0x14, 0x2D},
[]uint{7, 25, 64, 47, 3, 22, 11, 18, 56, 12, 64, 63, 8, 35, 40, 12, 31, 18, 64, 51, 58, 22, 64, 5},
[]uint64{0x06, 0xA4632, 0x3A2A4CD8817D8836, 0x5486E97B8E4E, 0x02, 0x39E86B, 0x368, 0x3B4B1, 0x22D2A40848CB3A, 0x97, 0xDED435AD25FE6888, 0x7D2D61C6E1AD7564, 0xDD, 0x6D079F5, 0x5A68DBCAA8, 0x164, 0x3DA33C13, 0x3AD64, 0x3708DC054CE03FE6, 0x73564ADC145A, 0x2856501FCA8294A, 0x1A9C0C, 0xE113AEA154F818A1, 0x0D},
},
{
[]byte{0xB0, 0x2B, 0x72, 0xA2, 0xB5, 0xBA, 0x1F, 0xA0, 0x87, 0xEF, 0xEE, 0xE5, 0x01, 0x7F, 0x46, 0x66, 0x05, 0x7E, 0xBD, 0x0B, 0x06, 0x43, 0x3D, 0xA2, 0xCC, 0x6B, 0xA1, 0xB5, 0xBF, 0x91, 0xA7, 0x6C, 0x44, 0xC7, 0xB7, 0x7A, 0xBE, 0x20, 0xE9, 0xB1, 0xA7, 0xF9, 0x58, 0x2E, 0x92, 0x5F, 0xA2, 0xD5, 0x10, 0x98, 0xF9, 0x58, 0x1F, 0x91, 0x84, 0xCE, 0xEC, 0x53, 0x42, 0xE5, 0xBA, 0xD8, 0xC9, 0x3C, 0x5B, 0x4F, 0x7A, 0x8D, 0xC4, 0xFE, 0x6E, 0x56, 0x0A, 0x1A, 0x08, 0x2B, 0xD5, 0xFF, 0x8F, 0x28, 0xAB, 0x6A, 0xB3, 0x6C, 0x8A, 0x0F, 0x2B, 0xA5, 0x73, 0xED, 0xC7, 0x2C, 0xB9, 0xB7, 0xFD, 0x9C, 0xCA, 0xE7, 0x4E, 0xBA},
[]uint{51, 62, 30, 50, 54, 45, 5, 36, 27, 34, 30, 27, 60, 20, 44, 43, 45, 5, 5, 12, 9, 25, 18, 50, 13},
[]uint64{0x5815B9515ADD0, 0x3F410FDFDDCA02FE, 0x233302BF, 0x17A160C867B45, 0x2635D0DADFC8D3, 0x16C44C7B77AB, 0x1C, 0x41D3634FF, 0x1582E92, 0x17E8B5442, 0x18F9581F, 0x48C2677, 0x629A172DD6C649E, 0x2DA7B, 0xD46E27F372B, 0x286820AF57, 0x1FC79455B559, 0x16, 0x19, 0x141, 0x1CA, 0x1D2B9F6, 0x38E59, 0x1CDBFECE6573A, 0xEBA},
},
{
[]byte{0x8E, 0xEB, 0xED, 0x77, 0xFC, 0xB9, 0x57, 0xAA, 0xC6, 0xF4, 0xEA, 0xF7, 0x59, 0xA3, 0x3F, 0xC7, 0x98, 0xF2, 0x6A, 0xA1, 0x0C, 0x08, 0xE5, 0x54, 0x8A, 0x69, 0x24, 0xE8, 0xCD, 0xD2, 0x27, 0x74, 0xC6, 0x96, 0x64, 0x1D, 0x00, 0x76, 0x21, 0xA1, 0x4F, 0xE8, 0xCF, 0x42, 0xFD, 0x51, 0x86, 0xD8, 0xBD, 0xA9, 0x28, 0x00, 0x42, 0xE9, 0x4B, 0xCB, 0xF5, 0xCF, 0x20, 0xFA, 0x96, 0x2F, 0x39, 0x86, 0x1B, 0x22, 0x73, 0x15, 0x65, 0x78, 0xFE, 0xB9, 0x12, 0xCD, 0x70, 0x2C, 0x8D, 0xE6, 0x4B, 0x08, 0x3C, 0xBB, 0x62, 0x96, 0xF9, 0xC3, 0x18, 0x29, 0xB6, 0x01, 0xEF, 0x76, 0xB6, 0x10, 0x8D, 0x00, 0x09, 0xC8, 0xBD, 0xC9},
[]uint{23, 25, 14, 24, 54, 57, 17, 10, 55, 55, 48, 6, 52, 23, 29, 46, 62, 52, 16, 9, 28, 44, 19, 20, 12},
[]uint64{0x4775F6, 0x177FCB9, 0x15EA, 0xB1BD3A, 0x2F759A33FC798F, 0x4D5421811CAA91, 0x9A49, 0xE8, 0x66E913BA634B32, 0x7401D886853FA, 0x33D0BF5461B6, 0x0B, 0xDA9280042E94B, 0x65FAE7, 0x120FA962, 0x3CE6186C89CC, 0x156578FEB912CD70, 0x2C8DE64B083CB, 0xB629, 0xDF, 0x3863053, 0x6C03DEED6C2, 0x8D00, 0x9C8B, 0xDC9},
},
{
[]byte{0xCF, 0x4B, 0x63, 0xE2, 0x82, 0xA4, 0xA3, 0x18, 0x6B, 0x5B, 0x1E, 0xAA, 0x55, 0x8D, 0xBD, 0x1D, 0xE3, 0xA5, 0xAE, 0x26, 0x41, 0xBA, 0x07, 0xC5, 0x85, 0xA2, 0xB0, 0xCC, 0xA9, 0x90, 0x6B, 0xA4, 0x07, 0xBF, 0xE3, 0x01, 0x1F, 0x0D, 0x73, 0xBD, 0xC4, 0xAB, 0x03, 0xC0, 0xD7, 0xEC, 0x47, 0xCE, 0x21, 0x9C, 0x43, 0x3B, 0x88, 0xD4, 0xA3, 0xDE, 0x49, 0x70, 0x48, 0x47, 0x84, 0x97, 0xD8, 0x03, 0x34, 0x74, 0x26, 0x4B, 0x0E, 0x52, 0x32, 0x18, 0xDF, 0x36, 0xD2, 0x34, 0xA1, 0x9C, 0x04, 0x97, 0x83, 0x10, 0xC2, 0x32, 0xF8, 0x5A, 0xD2, 0xCB, 0xD8, 0x3B, 0x35, 0x58, 0x86, 0x00, 0x89, 0xDE, 0xF5, 0x7C, 0x1A, 0xFA},
[]uint{23, 40, 60, 52, 61, 12, 53, 39, 40, 17, 40, 58, 31, 13, 58, 39, 47, 4, 38, 16, 43, 12, 4},
[]uint64{0x67A5B1, 0xF14152518C, 0x35AD8F552AC6DE8, 0xEF1D2D71320DD, 0x7C585A2B0CCA99, 0x6B, 0x1480F7FC6023E1, 0x573BDC4AB0, 0x3C0D7EC47C, 0x1C433, 0x8867711A94, 0x1EF24B82423C24B, 0x7600CD1D, 0x132, 0x161CA46431BE6DA, 0x234A19C049, 0x3C18861197C2, 0x0D, 0x1A597B0766, 0xAB10, 0x60089DEF57C, 0x1AF, 0x0A},
},
{
[]byte{0xC5, 0x28, 0x7C, 0xA6, 0x66, 0xF1, 0xAE, 0xF5, 0xC2, 0x0E, 0xCA, 0x71, 0xCB, 0x22, 0xE0, 0xB5, 0xA6,
gitextract_oegtlq8n/
├── .github/
│ └── workflows/
│ └── go.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── analysis_fixed.go
├── enc_benchmark_test.go
├── enc_test.go
├── encode.go
├── encode_frame.go
├── encode_meta.go
├── encode_subframe.go
├── example_test.go
├── flac.go
├── flac_test.go
├── frame/
│ ├── frame.go
│ ├── frame_test.go
│ └── subframe.go
├── go.mod
├── go.sum
├── internal/
│ ├── bits/
│ │ ├── reader.go
│ │ ├── reader_test.go
│ │ ├── twocomp.go
│ │ ├── twocomp_test.go
│ │ ├── unary.go
│ │ ├── unary_test.go
│ │ ├── zigzag.go
│ │ └── zigzag_test.go
│ ├── bufseekio/
│ │ ├── readseeker.go
│ │ └── readseeker_test.go
│ ├── hashutil/
│ │ ├── crc16/
│ │ │ ├── crc16.go
│ │ │ └── crc16_test.go
│ │ ├── crc8/
│ │ │ ├── crc8.go
│ │ │ └── crc8_test.go
│ │ └── hashutil.go
│ ├── ioutilx/
│ │ ├── byte.go
│ │ └── zero.go
│ └── utf8/
│ ├── decode.go
│ └── encode.go
├── meta/
│ ├── application.go
│ ├── cuesheet.go
│ ├── meta.go
│ ├── meta_test.go
│ ├── padding.go
│ ├── picture.go
│ ├── reader.go
│ ├── seektable.go
│ ├── streaminfo.go
│ ├── testdata/
│ │ └── README.md
│ └── vorbiscomment.go
└── testdata/
├── README.md
└── convert_to_verbatim.sh
SYMBOL INDEX (288 symbols across 42 files)
FILE: analysis_fixed.go
function analyzeFixed (line 20) | func analyzeFixed(sf *frame.Subframe, bps uint) {
function computeFixedResiduals (line 54) | func computeFixedResiduals(samples []int32, order int) []int32 {
function chooseRice (line 94) | func chooseRice(residuals []int32) uint {
function costFixed (line 116) | func costFixed(order int, bps uint, residuals []int32, k uint) int {
function analyzeSubframe (line 136) | func analyzeSubframe(sf *frame.Subframe, bps uint) {
FILE: enc_benchmark_test.go
function BenchmarkEncodeSyntheticAudio (line 15) | func BenchmarkEncodeSyntheticAudio(b *testing.B) {
FILE: enc_test.go
function TestEncodeRoundTrip (line 144) | func TestEncodeRoundTrip(t *testing.T) {
function TestEncodeComment (line 195) | func TestEncodeComment(t *testing.T) {
function TestEncodeAnalysisFixed (line 255) | func TestEncodeAnalysisFixed(t *testing.T) {
function getSamples (line 338) | func getSamples(stream *flac.Stream) ([]int32, error) {
function exists (line 356) | func exists(path string) bool {
FILE: encode.go
type Encoder (line 14) | type Encoder struct
method Close (line 78) | func (enc *Encoder) Close() error {
method EnablePredictionAnalysis (line 117) | func (enc *Encoder) EnablePredictionAnalysis(enable bool) {
function NewEncoder (line 39) | func NewEncoder(w io.Writer, info *meta.StreamInfo, blocks ...*meta.Bloc...
FILE: encode_frame.go
method WriteFrame (line 20) | func (enc *Encoder) WriteFrame(f *frame.Frame) error {
method encodeFrameHeader (line 122) | func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) err...
function encodeFrameHeaderBlockSize (line 220) | func encodeFrameHeaderBlockSize(bw *bitio.Writer, blockSize uint16) (nbl...
function encodeFrameHeaderSampleRate (line 261) | func encodeFrameHeaderSampleRate(bw *bitio.Writer, sampleRate uint32) (s...
function encodeFrameHeaderChannels (line 348) | func encodeFrameHeaderChannels(bw *bitio.Writer, channels frame.Channels...
function encodeFrameHeaderBitsPerSample (line 400) | func encodeFrameHeaderBitsPerSample(bw *bitio.Writer, bps uint8) error {
FILE: encode_meta.go
function encodeBlock (line 17) | func encodeBlock(bw *bitio.Writer, block *meta.Block, last bool) error {
function encodeEmptyBlock (line 46) | func encodeEmptyBlock(bw *bitio.Writer, typ meta.Type, last bool) error {
function encodeBlockHeader (line 62) | func encodeBlockHeader(bw *bitio.Writer, hdr *meta.Header) error {
function encodeStreamInfo (line 81) | func encodeStreamInfo(bw *bitio.Writer, info *meta.StreamInfo, last bool...
function encodePadding (line 136) | func encodePadding(bw *bitio.Writer, length int64, last bool) error {
function encodeApplication (line 156) | func encodeApplication(bw *bitio.Writer, app *meta.Application, last boo...
function encodeSeekTable (line 183) | func encodeSeekTable(bw *bitio.Writer, table *meta.SeekTable, last bool)...
function encodeVorbisComment (line 207) | func encodeVorbisComment(bw *bitio.Writer, comment *meta.VorbisComment, ...
function encodeCueSheet (line 257) | func encodeCueSheet(bw *bitio.Writer, cs *meta.CueSheet, last bool) error {
function encodePicture (line 361) | func encodePicture(bw *bitio.Writer, pic *meta.Picture, last bool) error {
FILE: encode_subframe.go
function encodeSubframe (line 15) | func encodeSubframe(bw *bitio.Writer, hdr frame.Header, subframe *frame....
function encodeSubframeHeader (line 64) | func encodeSubframeHeader(bw *bitio.Writer, subHdr frame.SubHeader) error {
function encodeConstantSamples (line 116) | func encodeConstantSamples(bw *bitio.Writer, hdr frame.Header, subframe ...
function encodeVerbatimSamples (line 135) | func encodeVerbatimSamples(bw *bitio.Writer, hdr frame.Header, subframe ...
function encodeFixedSamples (line 153) | func encodeFixedSamples(bw *bitio.Writer, hdr frame.Header, subframe *fr...
function encodeFIRSamples (line 182) | func encodeFIRSamples(bw *bitio.Writer, hdr frame.Header, subframe *fram...
function encodeResiduals (line 228) | func encodeResiduals(bw *bitio.Writer, subframe *frame.Subframe, residua...
function encodeRicePart (line 253) | func encodeRicePart(bw *bitio.Writer, subframe *frame.Subframe, paramSiz...
function encodeRiceResidual (line 323) | func encodeRiceResidual(bw *bitio.Writer, k uint, residual int32) error {
function getLPCResiduals (line 349) | func getLPCResiduals(subframe *frame.Subframe, coeffs []int32, shift int...
FILE: example_test.go
function ExampleParseFile (line 13) | func ExampleParseFile() {
function ExampleOpen (line 32) | func ExampleOpen() {
FILE: flac.go
type Stream (line 46) | type Stream struct
method parseStreamInfo (line 155) | func (stream *Stream) parseStreamInfo() (block *meta.Block, err error) {
method skipID3v2 (line 193) | func (stream *Stream) skipID3v2() error {
method Close (line 292) | func (stream *Stream) Close() error {
method Next (line 304) | func (stream *Stream) Next() (f *frame.Frame, err error) {
method ParseNext (line 310) | func (stream *Stream) ParseNext() (f *frame.Frame, err error) {
method Seek (line 317) | func (stream *Stream) Seek(sampleNum uint64) (uint64, error) {
method searchFromStart (line 364) | func (stream *Stream) searchFromStart(sampleNum uint64) (meta.SeekPoin...
method makeSeekTable (line 380) | func (stream *Stream) makeSeekTable() (err error) {
function New (line 73) | func New(r io.Reader) (stream *Stream, err error) {
function NewSeek (line 99) | func NewSeek(rs io.ReadSeeker) (stream *Stream, err error) {
constant defaultSeekTableSize (line 148) | defaultSeekTableSize = 100
function Parse (line 218) | func Parse(r io.Reader) (stream *Stream, err error) {
function Open (line 256) | func Open(path string) (stream *Stream, err error) {
function ParseFile (line 278) | func ParseFile(path string) (stream *Stream, err error) {
FILE: flac_test.go
function TestSkipID3v2 (line 12) | func TestSkipID3v2(t *testing.T) {
function TestSeek (line 18) | func TestSeek(t *testing.T) {
function TestDecode (line 84) | func TestDecode(t *testing.T) {
FILE: frame/frame.go
type Frame (line 49) | type Frame struct
method Parse (line 104) | func (frame *Frame) Parse() error {
method Hash (line 153) | func (frame *Frame) Hash(md5sum hash.Hash) {
method parseHeader (line 219) | func (frame *Frame) parseHeader() error {
method parseBitsPerSample (line 324) | func (frame *Frame) parseBitsPerSample(br *bits.Reader) error {
method parseChannels (line 367) | func (frame *Frame) parseChannels(br *bits.Reader) error {
method parseBlockSize (line 398) | func (frame *Frame) parseBlockSize(br *bits.Reader, blockSize uint64) ...
method parseSampleRate (line 439) | func (frame *Frame) parseSampleRate(br *bits.Reader, sampleRate uint64...
method Correlate (line 586) | func (frame *Frame) Correlate() {
method Decorrelate (line 633) | func (frame *Frame) Decorrelate() {
method SampleNumber (line 678) | func (frame *Frame) SampleNumber() uint64 {
function New (line 69) | func New(r io.Reader) (frame *Frame, err error) {
function Parse (line 87) | func Parse(r io.Reader) (frame *Frame, err error) {
type Header (line 191) | type Header struct
type Channels (line 527) | type Channels
method Count (line 575) | func (channels Channels) Count() int {
constant ChannelsMono (line 545) | ChannelsMono Channels = iota
constant ChannelsLR (line 546) | ChannelsLR
constant ChannelsLRC (line 547) | ChannelsLRC
constant ChannelsLRLsRs (line 548) | ChannelsLRLsRs
constant ChannelsLRCLsRs (line 549) | ChannelsLRCLsRs
constant ChannelsLRCLfeLsRs (line 550) | ChannelsLRCLfeLsRs
constant ChannelsLRCLfeCsSlSr (line 551) | ChannelsLRCLfeCsSlSr
constant ChannelsLRCLfeLsRsSlSr (line 552) | ChannelsLRCLfeLsRsSlSr
constant ChannelsLeftSide (line 553) | ChannelsLeftSide
constant ChannelsSideRight (line 554) | ChannelsSideRight
constant ChannelsMidSide (line 555) | ChannelsMidSide
function unexpected (line 687) | func unexpected(err error) error {
FILE: frame/frame_test.go
function TestFrameHash (line 97) | func TestFrameHash(t *testing.T) {
function BenchmarkFrameParse (line 136) | func BenchmarkFrameParse(b *testing.B) {
function BenchmarkFrameHash (line 161) | func BenchmarkFrameHash(b *testing.B) {
FILE: frame/subframe.go
type Subframe (line 14) | type Subframe struct
method parseHeader (line 105) | func (subframe *Subframe) parseHeader(br *bits.Reader) error {
method decodeConstant (line 234) | func (subframe *Subframe) decodeConstant(br *bits.Reader, bps uint) er...
method decodeVerbatim (line 253) | func (subframe *Subframe) decodeVerbatim(br *bits.Reader, bps uint) er...
method decodeFixed (line 288) | func (subframe *Subframe) decodeFixed(br *bits.Reader, bps uint) error {
method decodeFIR (line 316) | func (subframe *Subframe) decodeFIR(br *bits.Reader, bps uint) error {
method decodeResiduals (line 385) | func (subframe *Subframe) decodeResiduals(br *bits.Reader) error {
method decodeRicePart (line 413) | func (subframe *Subframe) decodeRicePart(br *bits.Reader, paramSize ui...
method decodeRiceResidual (line 494) | func (subframe *Subframe) decodeRiceResidual(br *bits.Reader, k uint) ...
method decodeLPC (line 516) | func (subframe *Subframe) decodeLPC(coeffs []int32, shift int32) error {
method parseSubframe (line 30) | func (frame *Frame) parseSubframe(br *bits.Reader, bps uint) (subframe *...
type SubHeader (line 63) | type SubHeader struct
type RiceSubframe (line 87) | type RiceSubframe struct
type RicePartition (line 97) | type RicePartition struct
type Pred (line 184) | type Pred
constant PredConstant (line 193) | PredConstant Pred = iota
constant PredVerbatim (line 197) | PredVerbatim
constant PredFixed (line 206) | PredFixed
constant PredFIR (line 215) | PredFIR
function signExtend (line 220) | func signExtend(x uint64, n uint) int32 {
type ResidualCodingMethod (line 371) | type ResidualCodingMethod
constant ResidualCodingMethodRice1 (line 376) | ResidualCodingMethodRice1 ResidualCodingMethod = 0
constant ResidualCodingMethodRice2 (line 378) | ResidualCodingMethodRice2 ResidualCodingMethod = 1
FILE: internal/bits/reader.go
type Reader (line 11) | type Reader struct
method Read (line 29) | func (br *Reader) Read(n uint) (x uint64, err error) {
function NewReader (line 23) | func NewReader(r io.Reader) *Reader {
FILE: internal/bits/reader_test.go
function TestRead (line 16) | func TestRead(t *testing.T) {
function TestReadEOF (line 607) | func TestReadEOF(t *testing.T) {
function BenchmarkReadAlign1 (line 629) | func BenchmarkReadAlign1(b *testing.B) {
function BenchmarkReadAlign32 (line 633) | func BenchmarkReadAlign32(b *testing.B) {
function BenchmarkReadAlign64 (line 637) | func BenchmarkReadAlign64(b *testing.B) {
function benchmarkReads (line 641) | func benchmarkReads(b *testing.B, chunk, align int) {
function prepareBenchmark (line 657) | func prepareBenchmark(size, chunk, align int) ([]byte, []uint, []uint64,...
function getNumBits (line 675) | func getNumBits(read, max, chunk, align int) int {
FILE: internal/bits/twocomp.go
function IntN (line 17) | func IntN(x uint64, n uint) int64 {
FILE: internal/bits/twocomp_test.go
function TestIntN (line 5) | func TestIntN(t *testing.T) {
FILE: internal/bits/unary.go
method ReadUnary (line 19) | func (br *Reader) ReadUnary() (x uint64, err error) {
function WriteUnary (line 45) | func WriteUnary(bw *bitio.Writer, x uint64) error {
FILE: internal/bits/unary_test.go
function TestUnary (line 11) | func TestUnary(t *testing.T) {
FILE: internal/bits/zigzag.go
function DecodeZigZag (line 17) | func DecodeZigZag(x uint32) int32 {
function EncodeZigZag (line 35) | func EncodeZigZag(x int32) uint32 {
FILE: internal/bits/zigzag_test.go
function TestDecodeZigZag (line 7) | func TestDecodeZigZag(t *testing.T) {
function TestEncodeZigZag (line 29) | func TestEncodeZigZag(t *testing.T) {
FILE: internal/bufseekio/readseeker.go
constant defaultBufSize (line 9) | defaultBufSize = 4096
type ReadSeeker (line 15) | type ReadSeeker struct
method reset (line 49) | func (b *ReadSeeker) reset(buf []byte, r io.ReadSeeker) {
method readErr (line 56) | func (b *ReadSeeker) readErr() error {
method Read (line 69) | func (b *ReadSeeker) Read(p []byte) (n int, err error) {
method buffered (line 114) | func (b *ReadSeeker) buffered() int { return b.w - b.r }
method Seek (line 116) | func (b *ReadSeeker) Seek(offset int64, whence int) (int64, error) {
method seek (line 141) | func (b *ReadSeeker) seek(offset int64, whence int) (int64, error) {
method position (line 150) | func (b *ReadSeeker) position() int64 {
constant minReadBufferSize (line 23) | minReadBufferSize = 16
function NewReadSeekerSize (line 28) | func NewReadSeekerSize(rd io.ReadSeeker, size int) *ReadSeeker {
function NewReadSeeker (line 43) | func NewReadSeeker(rd io.ReadSeeker) *ReadSeeker {
FILE: internal/bufseekio/readseeker_test.go
function TestNewReadSeekerSize (line 11) | func TestNewReadSeekerSize(t *testing.T) {
function TestNewReadSeeker (line 31) | func TestNewReadSeeker(t *testing.T) {
function TestReadSeeker_Read (line 38) | func TestReadSeeker_Read(t *testing.T) {
type readAndError (line 131) | type readAndError struct
method Read (line 135) | func (r *readAndError) Read(p []byte) (n int, err error) {
method Seek (line 142) | func (r *readAndError) Seek(offset int64, whence int) (int64, error) {
function TestReadSeeker_Seek (line 146) | func TestReadSeeker_Seek(t *testing.T) {
type seekRecord (line 236) | type seekRecord struct
type seekRecorder (line 241) | type seekRecorder struct
method Read (line 246) | func (r *seekRecorder) Read(p []byte) (n int, err error) {
method Seek (line 250) | func (r *seekRecorder) Seek(offset int64, whence int) (int64, error) {
method assertSeeked (line 255) | func (r *seekRecorder) assertSeeked(t *testing.T, expected []seekRecor...
method reset (line 264) | func (r *seekRecorder) reset() {
FILE: internal/hashutil/crc16/crc16.go
constant Size (line 13) | Size = 2
constant IBM (line 17) | IBM = 0x8005
type Table (line 22) | type Table
function MakeTable (line 28) | func MakeTable(poly uint16) (table *Table) {
function makeTable (line 37) | func makeTable(poly uint16) (table *Table) {
type digest (line 54) | type digest struct
method Size (line 71) | func (d *digest) Size() int {
method BlockSize (line 75) | func (d *digest) BlockSize() int {
method Reset (line 79) | func (d *digest) Reset() {
method Write (line 91) | func (d *digest) Write(p []byte) (n int, err error) {
method Sum16 (line 97) | func (d *digest) Sum16() uint16 {
method Sum (line 101) | func (d *digest) Sum(in []byte) []byte {
function New (line 61) | func New(table *Table) hashutil.Hash16 {
function NewIBM (line 67) | func NewIBM() hashutil.Hash16 {
function Update (line 84) | func Update(crc uint16, table *Table, p []byte) uint16 {
function Checksum (line 108) | func Checksum(data []byte, table *Table) uint16 {
function ChecksumIBM (line 113) | func ChecksumIBM(data []byte) uint16 {
FILE: internal/hashutil/crc16/crc16_test.go
type test (line 8) | type test struct
function TestCrc16IBM (line 48) | func TestCrc16IBM(t *testing.T) {
function BenchmarkNewIBM (line 62) | func BenchmarkNewIBM(b *testing.B) {
function BenchmarkCrc16_1K (line 68) | func BenchmarkCrc16_1K(b *testing.B) {
function BenchmarkCrc16_2K (line 72) | func BenchmarkCrc16_2K(b *testing.B) {
function BenchmarkCrc16_4K (line 76) | func BenchmarkCrc16_4K(b *testing.B) {
function BenchmarkCrc16_8K (line 80) | func BenchmarkCrc16_8K(b *testing.B) {
function BenchmarkCrc16_16K (line 84) | func BenchmarkCrc16_16K(b *testing.B) {
function benchmarkCrc16 (line 88) | func benchmarkCrc16(b *testing.B, count int64) {
FILE: internal/hashutil/crc8/crc8.go
constant Size (line 13) | Size = 1
constant ATM (line 17) | ATM = 0x07
type Table (line 22) | type Table
function MakeTable (line 28) | func MakeTable(poly uint8) (table *Table) {
function makeTable (line 37) | func makeTable(poly uint8) (table *Table) {
type digest (line 54) | type digest struct
method Size (line 71) | func (d *digest) Size() int {
method BlockSize (line 75) | func (d *digest) BlockSize() int {
method Reset (line 79) | func (d *digest) Reset() {
method Write (line 91) | func (d *digest) Write(p []byte) (n int, err error) {
method Sum8 (line 97) | func (d *digest) Sum8() uint8 {
method Sum (line 101) | func (d *digest) Sum(in []byte) []byte {
function New (line 61) | func New(table *Table) hashutil.Hash8 {
function NewATM (line 67) | func NewATM() hashutil.Hash8 {
function Update (line 84) | func Update(crc uint8, table *Table, p []byte) uint8 {
function Checksum (line 107) | func Checksum(data []byte, table *Table) uint8 {
function ChecksumATM (line 112) | func ChecksumATM(data []byte) uint8 {
FILE: internal/hashutil/crc8/crc8_test.go
type test (line 8) | type test struct
function TestCrc8ATM (line 48) | func TestCrc8ATM(t *testing.T) {
function BenchmarkNewATM (line 62) | func BenchmarkNewATM(b *testing.B) {
function BenchmarkCrc8_1K (line 68) | func BenchmarkCrc8_1K(b *testing.B) {
function BenchmarkCrc8_2K (line 72) | func BenchmarkCrc8_2K(b *testing.B) {
function BenchmarkCrc8_4K (line 76) | func BenchmarkCrc8_4K(b *testing.B) {
function BenchmarkCrc8_8K (line 80) | func BenchmarkCrc8_8K(b *testing.B) {
function BenchmarkCrc8_16K (line 84) | func BenchmarkCrc8_16K(b *testing.B) {
function benchmarkCrc8 (line 88) | func benchmarkCrc8(b *testing.B, count int64) {
FILE: internal/hashutil/hashutil.go
type Hash8 (line 7) | type Hash8 interface
type Hash16 (line 14) | type Hash16 interface
FILE: internal/ioutilx/byte.go
function ReadByte (line 9) | func ReadByte(r io.Reader) (byte, error) {
function WriteByte (line 18) | func WriteByte(w io.Writer, b byte) error {
FILE: internal/ioutilx/zero.go
type zero (line 7) | type zero struct
method Read (line 12) | func (zero) Read(b []byte) (n int, err error) {
FILE: internal/utf8/decode.go
constant tx (line 13) | tx = 0x80
constant t2 (line 14) | t2 = 0xC0
constant t3 (line 15) | t3 = 0xE0
constant t4 (line 16) | t4 = 0xF0
constant t5 (line 17) | t5 = 0xF8
constant t6 (line 18) | t6 = 0xFC
constant t7 (line 19) | t7 = 0xFE
constant t8 (line 20) | t8 = 0xFF
constant maskx (line 22) | maskx = 0x3F
constant mask2 (line 23) | mask2 = 0x1F
constant mask3 (line 24) | mask3 = 0x0F
constant mask4 (line 25) | mask4 = 0x07
constant mask5 (line 26) | mask5 = 0x03
constant mask6 (line 27) | mask6 = 0x01
constant rune1Max (line 29) | rune1Max = 1<<7 - 1
constant rune2Max (line 30) | rune2Max = 1<<11 - 1
constant rune3Max (line 31) | rune3Max = 1<<16 - 1
constant rune4Max (line 32) | rune4Max = 1<<21 - 1
constant rune5Max (line 33) | rune5Max = 1<<26 - 1
constant rune6Max (line 34) | rune6Max = 1<<31 - 1
constant rune7Max (line 35) | rune7Max = 1<<36 - 1
function Decode (line 61) | func Decode(r io.Reader) (x uint64, err error) {
FILE: internal/utf8/encode.go
function Encode (line 11) | func Encode(w io.Writer, x uint64) error {
FILE: meta/application.go
type Application (line 11) | type Application struct
method parseApplication (line 21) | func (block *Block) parseApplication() error {
FILE: meta/cuesheet.go
type CueSheet (line 15) | type CueSheet struct
method parseCueSheet (line 30) | func (block *Block) parseCueSheet() error {
method parseTrack (line 94) | func (block *Block) parseTrack(cs *CueSheet, i int, uniq map[uint8]struc...
function stringFromSZ (line 205) | func stringFromSZ(szStr string) string {
type CueSheetTrack (line 215) | type CueSheetTrack struct
type CueSheetTrackIndex (line 236) | type CueSheetTrackIndex struct
FILE: meta/meta.go
type Block (line 42) | type Block struct
method Parse (line 87) | func (block *Block) Parse() error {
method Skip (line 111) | func (block *Block) Skip() error {
method parseHeader (line 133) | func (block *Block) parseHeader(r io.Reader) error {
function New (line 57) | func New(r io.Reader) (block *Block, err error) {
function Parse (line 68) | func Parse(r io.Reader) (block *Block, err error) {
type Header (line 123) | type Header struct
type Type (line 170) | type Type
method String (line 183) | func (t Type) String() string {
constant TypeStreamInfo (line 174) | TypeStreamInfo Type = 0
constant TypePadding (line 175) | TypePadding Type = 1
constant TypeApplication (line 176) | TypeApplication Type = 2
constant TypeSeekTable (line 177) | TypeSeekTable Type = 3
constant TypeVorbisComment (line 178) | TypeVorbisComment Type = 4
constant TypeCueSheet (line 179) | TypeCueSheet Type = 5
constant TypePicture (line 180) | TypePicture Type = 6
function unexpected (line 206) | func unexpected(err error) error {
FILE: meta/meta_test.go
function TestParseBlocks (line 199) | func TestParseBlocks(t *testing.T) {
function TestParsePicture (line 231) | func TestParsePicture(t *testing.T) {
function TestMissingValue (line 256) | func TestMissingValue(t *testing.T) {
function TestVorbisCommentTooManyTags (line 288) | func TestVorbisCommentTooManyTags(t *testing.T) {
function TestVorbisCommentTooManyTagsOOM (line 297) | func TestVorbisCommentTooManyTagsOOM(t *testing.T) {
FILE: meta/padding.go
method verifyPadding (line 13) | func (block *Block) verifyPadding() error {
type zeros (line 26) | type zeros struct
method Read (line 31) | func (zr zeros) Read(p []byte) (n int, err error) {
FILE: meta/picture.go
constant maxPictureDataSize (line 9) | maxPictureDataSize = 128 << 20
type Picture (line 14) | type Picture struct
method parsePicture (line 57) | func (block *Block) parsePicture() error {
FILE: meta/reader.go
function readString (line 10) | func readString(r io.Reader, n int) (string, error) {
FILE: meta/seektable.go
constant maxSeekPoints (line 9) | maxSeekPoints = 1000000
type SeekTable (line 14) | type SeekTable struct
method parseSeekTable (line 20) | func (block *Block) parseSeekTable() error {
type SeekPoint (line 59) | type SeekPoint struct
constant PlaceholderPoint (line 72) | PlaceholderPoint = 0xFFFFFFFFFFFFFFFF
FILE: meta/streaminfo.go
type StreamInfo (line 17) | type StreamInfo struct
method parseStreamInfo (line 43) | func (block *Block) parseStreamInfo() error {
FILE: meta/vorbiscomment.go
constant maxTags (line 9) | maxTags = 50000
type VorbisComment (line 14) | type VorbisComment struct
method parseVorbisComment (line 23) | func (block *Block) parseVorbisComment() (err error) {
Condensed preview — 52 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (362K chars).
[
{
"path": ".github/workflows/go.yml",
"chars": 1398,
"preview": "# This workflow will build a golang project\n# For more information see: https://docs.github.com/en/actions/automating-bu"
},
{
"path": ".gitignore",
"chars": 25,
"preview": "*.flac\n*.wav\n_resources_\n"
},
{
"path": ".gitmodules",
"chars": 120,
"preview": "[submodule \"flac-test-files\"]\n\tpath = testdata/flac-test-files\n\turl = https://github.com/ietf-wg-cellar/flac-test-files\n"
},
{
"path": "LICENSE",
"chars": 1211,
"preview": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, c"
},
{
"path": "README.md",
"chars": 5970,
"preview": "# flac\n\n[](https://gi"
},
{
"path": "analysis_fixed.go",
"chars": 5876,
"preview": "package flac\n\nimport (\n\t\"github.com/mewkiz/flac/frame\"\n\tiobits \"github.com/mewkiz/flac/internal/bits\"\n)\n\n// analyzeFixed"
},
{
"path": "enc_benchmark_test.go",
"chars": 2609,
"preview": "package flac\n\nimport (\n\t\"bytes\"\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/mewkiz/flac/frame\"\n\t\"github.com/mewkiz/flac/meta\"\n)\n\n//"
},
{
"path": "enc_test.go",
"chars": 14209,
"preview": "package flac_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/mewkiz/flac\"\n"
},
{
"path": "encode.go",
"chars": 3989,
"preview": "package flac\n\nimport (\n\t\"crypto/md5\"\n\t\"hash\"\n\t\"io\"\n\n\t\"github.com/icza/bitio\"\n\t\"github.com/mewkiz/flac/meta\"\n\t\"github.com"
},
{
"path": "encode_frame.go",
"chars": 14306,
"preview": "package flac\n\nimport (\n\t\"encoding/binary\"\n\t\"io\"\n\t\"math\"\n\n\t\"github.com/icza/bitio\"\n\t\"github.com/mewkiz/flac/frame\"\n\t\"gith"
},
{
"path": "encode_meta.go",
"chars": 12139,
"preview": "package flac\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/icza/bitio\"\n\t\"github.com/mewkiz/flac/internal/iouti"
},
{
"path": "encode_subframe.go",
"chars": 12486,
"preview": "package flac\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/icza/bitio\"\n\t\"github.com/mewkiz/flac/frame\"\n\tiobits \"github.com/mewkiz/flac/"
},
{
"path": "example_test.go",
"chars": 2594,
"preview": "package flac_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\n\t\"github.com/mewkiz/flac\"\n)\n\nfunc ExampleParseFi"
},
{
"path": "flac.go",
"chars": 12548,
"preview": "// TODO(u): Evaluate storing the samples (and residuals) during frame audio\n// decoding in a buffer allocated for the st"
},
{
"path": "flac_test.go",
"chars": 7978,
"preview": "package flac_test\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/mewkiz/flac\"\n)\n\nfunc TestSkipID3v2(t *testing.T)"
},
{
"path": "frame/frame.go",
"chars": 21948,
"preview": "// Package frame implements access to FLAC audio frames.\n//\n// A brief introduction of the FLAC audio format [1] follows"
},
{
"path": "frame/frame_test.go",
"chars": 8819,
"preview": "package frame_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/md5\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/mewkiz/flac\"\n)\n\nvar golden = []struct"
},
{
"path": "frame/subframe.go",
"chars": 17061,
"preview": "package frame\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/mewkiz/flac/internal/bits\"\n)\n\n// A Subframe contains the encoded "
},
{
"path": "go.mod",
"chars": 241,
"preview": "module github.com/mewkiz/flac\n\ngo 1.23.2\n\ntoolchain go1.24.5\n\nrequire (\n\tgithub.com/icza/bitio v1.1.0\n\tgithub.com/mewkiz"
},
{
"path": "go.sum",
"chars": 816,
"preview": "github.com/icza/bitio v1.1.0 h1:ysX4vtldjdi3Ygai5m1cWy4oLkhWTAi+SyO6HC8L9T0=\ngithub.com/icza/bitio v1.1.0/go.mod h1:0jGn"
},
{
"path": "internal/bits/reader.go",
"chars": 1617,
"preview": "// Package bits provides bit access operations and binary decoding algorithms.\npackage bits\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\n//"
},
{
"path": "internal/bits/reader_test.go",
"chars": 109850,
"preview": "// © 2013 the Bits Authors under the MIT license. See AUTHORS for the list of authors.\n//\n// Some benchmark functions in"
},
{
"path": "internal/bits/twocomp.go",
"chars": 554,
"preview": "package bits\n\n// IntN returns the signed two's complement of x with the specified integer bit\n// width.\n//\n// Examples o"
},
{
"path": "internal/bits/twocomp_test.go",
"chars": 559,
"preview": "package bits\n\nimport \"testing\"\n\nfunc TestIntN(t *testing.T) {\n\tgolden := []struct {\n\t\tx uint64\n\t\tn uint\n\t\twant int"
},
{
"path": "internal/bits/unary.go",
"chars": 1120,
"preview": "package bits\n\nimport (\n\t\"github.com/icza/bitio\"\n)\n\n// ReadUnary decodes and returns an unary coded integer, whose value "
},
{
"path": "internal/bits/unary_test.go",
"chars": 759,
"preview": "package bits_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/icza/bitio\"\n\t\"github.com/mewkiz/flac/internal/bits\"\n)\n\nfun"
},
{
"path": "internal/bits/zigzag.go",
"chars": 816,
"preview": "package bits\n\n// DecodeZigZag decodes a ZigZag encoded integer and returns it.\n//\n// Examples of ZigZag encoded values o"
},
{
"path": "internal/bits/zigzag_test.go",
"chars": 876,
"preview": "package bits\n\nimport (\n\t\"testing\"\n)\n\nfunc TestDecodeZigZag(t *testing.T) {\n\tgolden := []struct {\n\t\tx uint32\n\t\twant in"
},
{
"path": "internal/bufseekio/readseeker.go",
"chars": 3872,
"preview": "package bufseekio\n\nimport (\n\t\"errors\"\n\t\"io\"\n)\n\nconst (\n\tdefaultBufSize = 4096\n)\n\n// ReadSeeker implements buffering for "
},
{
"path": "internal/bufseekio/readseeker_test.go",
"chars": 9828,
"preview": "package bufseekio\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc TestNewReadSeekerSize(t *testing.T) {"
},
{
"path": "internal/hashutil/crc16/crc16.go",
"chars": 2732,
"preview": "// Copyright 2013 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "internal/hashutil/crc16/crc16_test.go",
"chars": 2952,
"preview": "package crc16\n\nimport (\n\t\"io\"\n\t\"testing\"\n)\n\ntype test struct {\n\twant uint16\n\tin string\n}\n\nvar golden = []test{\n\t{0x000"
},
{
"path": "internal/hashutil/crc8/crc8.go",
"chars": 2641,
"preview": "// Copyright 2012 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
},
{
"path": "internal/hashutil/crc8/crc8_test.go",
"chars": 2873,
"preview": "package crc8\n\nimport (\n\t\"io\"\n\t\"testing\"\n)\n\ntype test struct {\n\twant uint8\n\tin string\n}\n\nvar golden = []test{\n\t{0x00, \""
},
{
"path": "internal/hashutil/hashutil.go",
"chars": 455,
"preview": "// Package hashutil provides utility interfaces for hash functions.\npackage hashutil\n\nimport \"hash\"\n\n// Hash8 is the com"
},
{
"path": "internal/ioutilx/byte.go",
"chars": 489,
"preview": "// Package ioutilx implements extended input/output utility functions.\npackage ioutilx\n\nimport (\n\t\"io\"\n)\n\n// ReadByte re"
},
{
"path": "internal/ioutilx/zero.go",
"chars": 370,
"preview": "package ioutilx\n\n// Zero is an io.Reader which always reads zero bytes.\nvar Zero zero\n\n// zero is an io.Reader which alw"
},
{
"path": "internal/utf8/decode.go",
"chars": 4330,
"preview": "// Package utf8 implements encoding and decoding of UTF-8 coded numbers.\npackage utf8\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n"
},
{
"path": "internal/utf8/encode.go",
"chars": 1524,
"preview": "package utf8\n\nimport (\n\t\"io\"\n\n\t\"github.com/mewkiz/flac/internal/ioutilx\"\n\t\"github.com/mewkiz/pkg/errutil\"\n)\n\n// Encode e"
},
{
"path": "meta/application.go",
"chars": 839,
"preview": "package meta\n\nimport (\n\t\"encoding/binary\"\n\t\"io/ioutil\"\n)\n\n// Application contains third party application specific data."
},
{
"path": "meta/cuesheet.go",
"chars": 6475,
"preview": "package meta\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"strings\"\n)\n\n// A CueSheet describes how "
},
{
"path": "meta/meta.go",
"chars": 5770,
"preview": "// Package meta implements access to FLAC metadata blocks.\n//\n// A brief introduction of the FLAC metadata format [1] fo"
},
{
"path": "meta/meta_test.go",
"chars": 17146,
"preview": "package meta_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io/ioutil\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/mewkiz/flac\"\n\t\"github.co"
},
{
"path": "meta/padding.go",
"chars": 820,
"preview": "package meta\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n)\n\n// verifyPadding verifies the body of a Padding metadata block. I"
},
{
"path": "meta/picture.go",
"chars": 3155,
"preview": "package meta\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n)\n\nconst maxPictureDataSize = 128 << 20 // 128 MB\n\n// Picture con"
},
{
"path": "meta/reader.go",
"chars": 772,
"preview": "package meta\n\nimport \"io\"\n\n// readString reads and returns exactly n bytes from the provided io.Reader.\n//\n// The error "
},
{
"path": "meta/seektable.go",
"chars": 2281,
"preview": "package meta\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n)\n\nconst maxSeekPoints = 1000000\n\n// SeekTable contains one o"
},
{
"path": "meta/streaminfo.go",
"chars": 2957,
"preview": "package meta\n\nimport (\n\t\"crypto/md5\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/mewkiz/flac/internal/bits\"\n)\n\n// StreamInfo co"
},
{
"path": "meta/testdata/README.md",
"chars": 993,
"preview": "# Testcase Licences\n\n## BSD License\n\nThe following testcase sounds have been copied from the [reference implementation] "
},
{
"path": "meta/vorbiscomment.go",
"chars": 1778,
"preview": "package meta\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst maxTags = 50000\n\n// VorbisComment contains a list o"
},
{
"path": "testdata/README.md",
"chars": 1471,
"preview": "## Git Submodule\n\nTo fetch the FLAC test files of the `testdata/flac-test-files` directory, run the following command:\n\n"
},
{
"path": "testdata/convert_to_verbatim.sh",
"chars": 977,
"preview": "#!/bin/bash\n\nflac -l 0 --disable-fixed-subframes -V -0 -f -o 19875_verbatim.flac 19875.flac\nflac -l 0 --disable-fixed-su"
}
]
About this extraction
This page contains the full source code of the mewkiz/flac GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 52 files (332.0 KB), approximately 162.6k tokens, and a symbol index with 288 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.