flac

package module
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 1 Imported by: 0

README

go-flac

CI Go Reference Go Report Card codecov Go Version Latest tag OpenSSF Scorecard Sponsor

Native Go FLAC encoder and decoder. No CGO and no external binaries, with a simple high-level PCM streaming API. The encoder hot paths are SIMD-accelerated (AVX2 on amd64, NEON on arm64) with a pure-Go fallback, so the library still builds and runs on every Go target; the SIMD kernels are bit-identical to the scalar path, so encoded output is byte-for-byte the same with or without SIMD. The integer kernels live in-tree under internal/i32; the github.com/tphakala/simd module supplies CPU feature detection, LPC autocorrelation, and CRC-16, and brings one transitive dependency, golang.org/x/sys.

Install

go get github.com/tphakala/go-flac

Status

Both decoder and encoder are implemented. pcm.NewDecoder reads real FLAC streams and exposes the audio as interleaved little-endian PCM through io.Reader and io.WriterTo. It is validated bit-exactly against the IETF FLAC test corpus (every subset file's decoded-audio MD5 matches its STREAMINFO signature), byte-for-byte against the reference libFLAC flac -d, and fuzzed for panic-freedom. The decoder uses a 64-bit bulk-refill bit reader with no per-byte interface dispatch and allocates only a single reusable read buffer per stream.

pcm.NewEncoder encodes interleaved little-endian PCM to FLAC. It supports bit depths 4-32, constant/verbatim/fixed and LPC predictors, full four-way stereo decorrelation (independent, left-side, right-side, mid-side), and the 0-8 compression-level API. Levels 0-2 use fixed predictors; levels 3-8 add quantized LPC with deeper residual-partition search. Depths up to 24 bps run an int32 path; depths 25-32 bps run a dedicated int64 path (encoder and decoder), and the int32 output for <= 24 bps is byte-identical to before the wide-depth work. The encoder is allocation-light: a per-encoder reusable scratch buffer keeps steady-state per-block heap allocations near zero.

SeekToSample is sample-accurate and requires an io.Seeker; it returns ErrSeekUnsupported when the source is not seekable and ErrInvalidSeek on a negative sample index. Mid-stream resync from a non-fLaC start position remains future work.

Usage

Decode a FLAC file to raw interleaved little-endian PCM:

package main

import (
	"io"
	"log"
	"os"

	"github.com/tphakala/go-flac/pcm"
)

func main() {
	f, err := os.Open("input.flac")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	dec, err := pcm.NewDecoder(f)
	if err != nil {
		log.Fatal(err)
	}

	info := dec.Info()
	log.Printf("%d Hz, %d channel(s), %d-bit", info.SampleRate, info.Channels, info.BitDepth)

	// dec is an io.Reader and io.WriterTo of interleaved little-endian PCM.
	out, err := os.Create("output.pcm")
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()
	if _, err := io.Copy(out, dec); err != nil {
		log.Fatal(err)
	}
}

Encode interleaved little-endian PCM to a FLAC file:

package main

import (
	"io"
	"log"
	"os"

	"github.com/tphakala/go-flac/pcm"
)

func main() {
	// pcmReader is any io.Reader of interleaved little-endian PCM matching the
	// Config below; here it is a raw PCM file.
	pcmReader, err := os.Open("input.pcm")
	if err != nil {
		log.Fatal(err)
	}
	defer pcmReader.Close()

	// out is an *os.File (an io.WriteSeeker) so Close can finalize the STREAMINFO
	// MD5, total-sample count, and frame sizes.
	out, err := os.Create("output.flac")
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()

	enc, err := pcm.NewEncoder(out, pcm.Config{SampleRate: 44100, BitDepth: 16, Channels: 2, CompressionLevel: 5})
	if err != nil {
		log.Fatal(err)
	}
	if _, err := io.Copy(enc, pcmReader); err != nil {
		log.Fatal(err)
	}
	if err := enc.Close(); err != nil {
		log.Fatal(err)
	}
}

Pass an io.WriteSeeker (for example an *os.File) as the destination so the encoder can finalize the STREAMINFO MD5, total-sample count, and frame sizes when Close is called. A non-seekable writer still produces a valid FLAC stream, but those fields are left as "unknown".

API notes:

import "github.com/tphakala/go-flac/pcm"

// Decoder: implemented.
dec, err := pcm.NewDecoder(r)
// dec implements io.Reader and io.WriterTo, yielding interleaved little-endian
// PCM. dec.Info() returns the stream's STREAMINFO properties.
// SeekToSample requires an io.Seeker: it returns ErrSeekUnsupported for
// non-seekable sources and ErrInvalidSeek on a negative index.

// Encoder: implemented.
enc, err := pcm.NewEncoder(w, pcm.Config{SampleRate: 44100, BitDepth: 16, Channels: 2})
// enc implements io.WriteCloser; write interleaved little-endian PCM and call
// Close to flush the final frame and finalize STREAMINFO. Pass an io.WriteSeeker
// so STREAMINFO totals and MD5 can be written back after encoding.

Command-line example

cmd/wav2flac encodes a PCM WAV file to FLAC with the streaming encoder. It is a runnable demo of the API and the go-flac side of the benchmark harness below:

go run ./cmd/wav2flac -level 5 input.wav output.flac

It accepts integer PCM WAV input (for example pcm_s16le, s24, s32); IEEE-float WAV is rejected.

Benchmarking

scripts/bench-encoders.sh compares go-flac against libFLAC, SoX, and ffmpeg on the same input (encode, level 5, single-threaded), reporting wall time, CPU seconds, peak RSS, throughput, and compression ratio. With no argument it generates a deterministic 30-minute input so runs are reproducible across machines:

scripts/bench-encoders.sh          # generated reproducible input
scripts/bench-encoders.sh my.wav   # your own WAV

It requires GNU time; flac, sox, and ffmpeg are each optional and skipped if absent.

Results on the default input (deterministic 30-minute mono 48 kHz/16-bit mix, level 5, single-threaded); throughput is input MB/s, ratio is encoded size over input size:

Encoder amd64 (i7-1260P) arm64 (Cortex-A76) Compression ratio
go-flac 147 MB/s 51 MB/s 0.8523
libFLAC 229 MB/s 76 MB/s 0.8523
SoX 194 MB/s n/a 0.8519
ffmpeg 128 MB/s 48 MB/s 0.8519

go-flac matches libFLAC's compression ratio exactly and beats ffmpeg on both throughput and ratio on each architecture; libFLAC's reference encoder remains about 1.5x faster. Numbers vary with hardware and input, so re-run the script to reproduce them on your own machine.

Sponsor

go-flac is free and MIT-licensed, maintained in my own time. If it is useful to you or your project, you can support continued maintenance through GitHub Sponsors:

Sponsor on GitHub

Sponsorship is entirely optional and never gates any feature; the whole library stays MIT-licensed regardless.

License

MIT. See LICENSE and THIRD_PARTY.md. go-flac is an independent reimplementation; no third-party source is copied.

Documentation

Overview

Package flac provides a native Go FLAC encoder and decoder. It uses no CGO and no external binaries; the encoder hot paths are SIMD-accelerated behind a pure-Go fallback (bit-identical output), so it builds and runs on every Go target.

The high-level PCM streaming API lives in the pcm subpackage (github.com/tphakala/go-flac/pcm). Use pcm.NewDecoder to decode a FLAC stream to interleaved little-endian PCM, and pcm.NewEncoder to encode interleaved little-endian PCM to a FLAC stream. This root package exposes only shared types used across the public API. Codec internals live under internal/.

Index

Constants

View Source
const Version = "0.4.2"

Version is the current library version. go-flac follows semantic versioning.

Variables

View Source
var (
	// ErrSeekUnsupported is returned by SeekToSample when the source is not seekable.
	ErrSeekUnsupported = errors.New("go-flac: seek unsupported (source is not an io.Seeker)")
	// ErrMissingStreamInfo means the stream had no STREAMINFO metadata block, or it did
	// not appear first.
	ErrMissingStreamInfo = errors.New("go-flac: missing or misplaced STREAMINFO block")
	// ErrCRCMismatch means a frame header CRC-8 or frame CRC-16 did not match.
	ErrCRCMismatch = errors.New("go-flac: CRC mismatch")
	// ErrMD5Mismatch means the decoded-audio MD5 did not match the STREAMINFO MD5.
	ErrMD5Mismatch = errors.New("go-flac: MD5 mismatch")
	// ErrUnsupported marks a reserved or illegal coded value, or an unsupported layout.
	ErrUnsupported = errors.New("go-flac: unsupported or reserved bitstream value")
	// ErrEncoderClosed is returned by Encoder.Write after Close has been called.
	ErrEncoderClosed = errors.New("go-flac: encoder is closed")
	// ErrTruncatedStream means the stream ended before delivering the sample count
	// STREAMINFO declares (an inter-frame cut on a zero-MD5 stream), or a frame body
	// was cut short. Mid-frame truncation wraps io.ErrUnexpectedEOF.
	ErrTruncatedStream = errors.New("go-flac: truncated stream")
	// ErrInvalidSeek means SeekToSample was called with a negative sample index.
	ErrInvalidSeek = errors.New("go-flac: invalid seek (negative sample index)")
)

Sentinel errors returned by the decoder and the pcm streaming layer. Callers can test for them with errors.Is.

Functions

This section is empty.

Types

type StreamInfo

type StreamInfo struct {
	SampleRate   int      // samples per second, e.g. 44100
	Channels     int      // number of channels, 1..8
	BitDepth     int      // bits per sample, e.g. 16 or 24
	TotalSamples uint64   // inter-channel sample count; 0 if unknown
	MD5          [16]byte // MD5 of the unencoded audio; all-zero if absent
}

StreamInfo describes a FLAC stream's global properties, mirroring the STREAMINFO metadata block.

Directories

Path Synopsis
cmd
wav2flac command
Command wav2flac encodes a PCM WAV file to FLAC using the pure-Go go-flac encoder.
Command wav2flac encodes a PCM WAV file to FLAC using the pure-Go go-flac encoder.
internal
bitio
Package bitio implements MSB-first bit-level reading and writing in the bit order used by the FLAC bitstream.
Package bitio implements MSB-first bit-level reading and writing in the bit order used by the FLAC bitstream.
crc
Package crc provides the checksums FLAC requires: CRC-8 over each frame header, CRC-16 over each complete frame, and the MD5 of the unencoded audio stored in STREAMINFO.
Package crc provides the checksums FLAC requires: CRC-8 over each frame header, CRC-16 over each complete frame, and the MD5 of the unencoded audio stored in STREAMINFO.
frame
Package frame implements FLAC frame and subframe coding: the frame header (with CRC-8 sync validation and frame-sync scanning used for seek and resync), the four subframe types (constant, verbatim, fixed, LPC), and inter-channel decorrelation (left/side, right/side, mid/side).
Package frame implements FLAC frame and subframe coding: the frame header (with CRC-8 sync validation and frame-sync scanning used for seek and resync), the four subframe types (constant, verbatim, fixed, LPC), and inter-channel decorrelation (left/side, right/side, mid/side).
i32
Package i32 provides SIMD-accelerated operations on int32 slices that back go-flac's integer hot loops (Rice cost search, fixed predictors, quantized LPC, stereo decorrelation) where the per-sample work is integer arithmetic and channel (de)interleaving rather than floating-point math.
Package i32 provides SIMD-accelerated operations on int32 slices that back go-flac's integer hot loops (Rice cost search, fixed predictors, quantized LPC, stereo decorrelation) where the per-sample work is integer arithmetic and channel (de)interleaving rather than floating-point math.
lpc
Package lpc, analysis side: windowing, autocorrelation, Levinson-Durbin, coefficient quantization, and order estimation for the encoder.
Package lpc, analysis side: windowing, autocorrelation, Levinson-Durbin, coefficient quantization, and order estimation for the encoder.
meta
Package meta implements FLAC metadata blocks: STREAMINFO, VORBIS_COMMENT, SEEKTABLE, PICTURE, CUESHEET, PADDING, and APPLICATION.
Package meta implements FLAC metadata blocks: STREAMINFO, VORBIS_COMMENT, SEEKTABLE, PICTURE, CUESHEET, PADDING, and APPLICATION.
rice
Package rice implements FLAC's Rice/Golomb residual coding: encoding and decoding of partitioned residuals and the parameter search that picks the cheapest Rice parameter per partition.
Package rice implements FLAC's Rice/Golomb residual coding: encoding and decoding of partitioned residuals and the parameter search that picks the cheapest Rice parameter per partition.
Package pcm is the high-level, clean-room PCM streaming API for go-flac.
Package pcm is the high-level, clean-room PCM streaming API for go-flac.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL