Something went wrong. Try again.
A FLAC encoder and decoder for Zig, written against RFC 9639, for native FLAC streams and FLAC in Ogg
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
//! zig-flac -- encoding and decoding the Free Lossless Audio Codec, as//! specified by [RFC 9639](https://www.rfc-editor.org/rfc/rfc9639.html).//!//! This is the library. It has no filesystem and no threads: a decoder reads//! from a `std.Io.Reader` and an encoder writes to a `std.Io.Writer`, so a//! caller with a file, a socket, or a slice of memory supplies its own.//!//! # Decoding//!//! ```zig//! const flac = @import("flac");//!//! var d: flac.Decoder = try .init(gpa, reader, .{});//! defer d.deinit();//!//! while (try d.next()) |frame| {//! for (frame.channels) |channel| {//! // channel[0..frame.header.block_size], one i32 per sample//! }//! }//! try d.finish(); // checks the stream's MD5 and sample count//! ```//!//! `d.streaminfo` describes the audio, `d.blocks` holds every metadata block//! the stream carried, and `d.vorbisComment()` and `d.seekTable()` reach for//! the two of those a caller usually wants.//!//! # Encoding//!//! ```zig//! var e: flac.Encoder = try .init(gpa, writer, .{//! .sample_rate = 44100,//! .channels = 2,//! .bits_per_sample = 16,//! }, .{ .level = .@"5" });//! defer e.deinit();//!//! try e.writeInterleaved(samples);//! try e.finish();//! ```//!//! An encoder cannot know a stream's MD5, its true frame sizes or its length//! until it has seen the whole of it, so the streaminfo block it writes first//! is a placeholder. After `finish`, `e.streaminfo` holds the real one; a//! caller writing to a file it can seek in should put it back with//! `writeStreamInfoBlock`, which is what `flac.wav` and the command-line tool//! do. A stream written to a pipe keeps the placeholder, which is legal and//! is what the format's "value not known" encodings are for.//!//! # What is where//!//! * `bits` -- the bit-level reader and writer a frame is built out of.//! * `crc` -- the frame header and frame footer checks.//! * `format` -- the format's limits, its enumerations, and the coded number.//! * `frame` -- frame and subframe headers.//! * `lpc` -- predictor analysis, which is the only floating-point arithmetic//! in the library and touches no sample that is written.//! * `metadata` -- the blocks between the signature and the first frame.//! * `wav` -- reading and writing RIFF/WAVE, for callers whose audio arrives//! that way.
const std = @import("std");
pub const bits = @import("bits.zig");pub const crc = @import("crc.zig");pub const format = @import("format.zig");pub const frame = @import("frame.zig");pub const lpc = @import("lpc.zig");pub const metadata = @import("metadata.zig");pub const ogg = @import("ogg.zig");pub const wav = @import("wav.zig");
pub const signature = format.signature;pub const limits = format.limits;
pub const BitReader = bits.BitReader;pub const BitWriter = bits.BitWriter;
pub const Blocking = frame.Blocking;pub const FrameHeader = frame.FrameHeader;pub const SubframeHeader = frame.SubframeHeader;pub const ChannelAssignment = format.ChannelAssignment;pub const SubframeType = format.SubframeType;
pub const Block = metadata.Block;pub const BlockType = metadata.BlockType;pub const StreamInfo = metadata.StreamInfo;pub const SeekPoint = metadata.SeekPoint;pub const VorbisComment = metadata.VorbisComment;pub const CueSheet = metadata.CueSheet;pub const Picture = metadata.Picture;pub const Application = metadata.Application;
pub const Decoder = @import("decoder.zig").Decoder;pub const DecodeError = @import("decoder.zig").Error;pub const DecodeOptions = @import("decoder.zig").Options;pub const Frame = @import("decoder.zig").Frame;
pub const Encoder = @import("encoder.zig").Encoder;pub const EncodeError = @import("encoder.zig").Error;pub const EncodeOptions = @import("encoder.zig").Options;pub const Level = @import("encoder.zig").Level;pub const Config = @import("encoder.zig").Config;
pub const OggDecoder = ogg.Decoder;pub const OggEncoder = ogg.Encoder;pub const OggIdentification = ogg.Identification;/// The four bytes an Ogg page starts with, which is how a file carrying an Ogg/// FLAC stream is told from one carrying a native stream.pub const ogg_capture_pattern = ogg.capture_pattern;
/// Where a streaminfo block's body starts: four bytes of signature and four of/// block header, so always 8. An encoder writes a placeholder there before it/// has seen any audio, and a caller whose destination can seek writes the/// finished block back over it -- which is the only thing standing between a/// stream written to a pipe and one written to a file.pub const streaminfo_body_offset = Encoder.streaminfo_body_offset;
/// Write a streaminfo block, header and all, which is 38 bytes at the very/// start of the stream. Use this to replace the whole block; to replace only/// its body, at `streaminfo_body_offset`, call `StreamInfo.write`.pub fn writeStreamInfoBlock(w: *std.Io.Writer, info: StreamInfo, last: bool) metadata.WriteError!void { try metadata.writeBlock(w, .{ .last = last, .body = .{ .streaminfo = info } });}
test { std.testing.refAllDecls(@This()); _ = @import("decoder.zig"); _ = @import("encoder.zig");}