// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie // 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"); }