LIBSOXFORMAT_NG(3)
π libsoxformat_ng(3) β libsox_ng format handlers' internals π
Welcome to the Sound eXchange_ng page for libsoxformat_ng, aka the behind-the-scenes lore for libsox_ng format handlers. If you're writing a new format handler, this is your group chat. β¨
β¨ NAME β¨
libsoxformat_ng β libsox_ng format handlers' internals. That's the whole vibe: it's about how the format-handler machinery works under the hood. π«Ά
π οΈ SYNOPSIS π οΈ
Here's the starter pack, bestie:
#include "sox_i.h"
typedef struct {
...
} priv_t;
static int startread(sox_format_t *ft);
static size_t read(sox_format_t *ft, sox_sample_t *buf, size_t len);
static int stopread(sox_format_t *ft);
static int startwrite(sox_format_t *ft);
static size_t write(sox_format_t *ft, sox_sample_t *buf, size_t len);
static int stopwrite(sox_format_t *ft);
static int seek(sox_format_t *ft, sox_uint64_t offset);
sox_format_handler_t const *lsx_whatever_format_fn(void)
{
static char const description[] = "Whatever format";
static char const * const names = { "wvr", NULL };
static unsigned const write_encodings[] = {
SOX_ENCODING_*, {bitwidth,} 0,
..., 0,
0};
static sox_format_handler_t const handler = { SOX_LIB_VERSION_CODE,
description, names, {SOX_FILE_* |} 0,
startread, read, stopread,
startwrite, write, stopwrite,
seek, write_encodings,
sizeof(priv_t)
};
return &handler;
}
π DESCRIPTION π
Okay so here's the tea: how SoX format handlers work and how to write a new one. π§
SoX's formats and effects operate with an internal sample format of signed 32-bit integers. The data processing routines are called with buffers of these samples, and the buffer sizes refer to the number of samples processed, not the number of bytes. Literally not bytes, bestie. File readers translate input samples to signed 32-bit integers and return the number of samples read. For example, data in linear signed byte format is left-shifted 24 bits.
Stereo data is stored with the left and right channels' data in successive samples, and quadraphonic data is stored left front, right front, left rear, right rear. π§
A format handler is responsible for translating between sound sample files and an internal buffer in which sound data is stored as signed 32-bit integers with a fixed sampling rate.
𧬠The sox_format_handler struct π§¬
Here's the struct in all its main-character glory:
struct sox_format_handler {
unsigned sox_lib_version_code; /* Checked on load */
char * description; /* Description of the format */
char * * names; /* Filename extensions */
unsigned int flags; /* File flags (SOX_FILE_*) */
sox_format_handler_startread startread; /* Initialize decoder */
sox_format_handler_read read; /* Decode a block of samples */
sox_format_handler_stopread stopread; /* Close decoder */
sox_format_handler_startwrite startwrite; /* Initialize encoder */
sox_format_handler_write write; /* Encode a block of samples */
sox_format_handler_stopwrite stopwrite; /* Close encoder */
sox_format_handler_seek seek; /* Reposition reader */
unsigned * write_formats; /* Encodings and precision */
unsigned * write_rates; /* Sample rates */
size_t priv_size; /* sizeof(priv_t) */
};
π Field-by-field lore π
sox_uint32_t sox_lib_version_codeβ checked when format plugins are loaded to ensure they were compiled for the same version oflibsoxthat is calling them. Version vibe check, no cap. βchar *descriptionβ a short description of the format, printed bysox_ng --help-format. It's giving one-line elevator pitch. πchar **namesβ a null-terminated array of filename extensions (without the dot) that are handled by this format. πunsigned int flagsβ the logical OR of:SOX_FILE_NOSTDIOβ the handler does not use stdio routinesSOX_FILE_DEVICEβ the file is an audio deviceSOX_FILE_PHONYβ phony file/device (for example/dev/null)SOX_FILE_REWINDβ file should be rewound to write headerSOX_FILE_BIT_REVβ is the file bit-reversed?SOX_FILE_NIB_REVβ is the file nibble-reversed?SOX_FILE_ENDIANβ is the file format endian?SOX_FILE_ENDBIGβ for an endian file format, is it big endian?SOX_FILE_MONOβ do channel restrictions allow mono?SOX_FILE_STEREOβ do channel restrictions allow stereo?SOX_FILE_QUADβ do channel restrictions allow quad?SOX_FILE_LIT_ENDβ a mask to OR in if the file is little-endianSOX_FILE_BIG_ENDβ a mask to OR in if the file is big-endianSOX_FILE_CHANSβ a mask to interrogate channels restrictions. Ifflags & SOX_FILE_CHANSis0, there are no restrictions
int (*startread)(sox_format_t *fp)β a function to set up the format parameters, read in a data header and do anything else that needs to be done before decoding data. It returnsSOX_SUCCESSif all went well, or a non-zero value if there was some problem with the file, in which casereadandstopreadwill not be called.
At exit from startread, sox_format_t.signal should be completely filled in, using either data from the file's headers (if available) or whatever the format is guessing/assuming if header data is not available. No half-filled signal, okay? π
size_t (*read)(sox_format_t *ft, sox_sample_t *buf, size_t len)β given a buffer and a length, read up to that many samples, transform them into signed long integers and copy them into the buffer. It returns the number of samples actually read. π₯int (*stopread)(sox_format_t *ft)β does what needs to be done when it has finished reading.int (*startwrite)(sox_format_t *ft)β set up the format parameters, maybe write out a data header, and any other preliminaries for encoding the format. It returnsSOX_SUCCESSif all went well, or a non-zero value if there was some problem, in which casewriteandstopwritewill not be called.
At exit from startwrite, sox_format_t.signal should be completely filled in, using either the data that was specified, or values chosen by the format based on the format's defaults or capabilities. π«‘
size_t (*write)(sox_format_t *ft, sox_sample_t *buf, size_t len)β given a buffer and a length, copy that many samples out of the buffer, convert them from signed longs to the appropriate data types and write them to the file. If it can't write all the samples out, it returns a lesser number of samples. π€int (*stopwrite)(sox_format_t *ft)β fix up the file header or whatever else needs to be done before closing the file.unsigned *write_formatsβ an array of values indicating the encodings and precisions supported for writing (encoding). Precisions are specified with default precision first, and with0and repeat, and list ends with with one more0.
An example for a format that supports signed integers at depths of 16 and 24 bits with a default of 16, and 8-bit unsigned:
unsigned const * formats = {
SOX_ENCODING_SIGN2, 16, 24, 0,
SOX_ENCODING_UNSIGNED, 8, 0,
0 };
sox_rate_t *write_ratesβ an zero-terminated array of sample rates that are supported for writing,NULLif all rates are supported.size_t priv_sizeβ the size of the format'spriv_t. SoX automatically allocates a buffer in which the handler can store its private data, of which the size is specified here. Usually this will besizeof(priv_t). The buffer is allocated and zeroed before the call tostartread/startwrite, is freed after the call tostopread/stopwriteand is provided viaft->privin each call to the handler's functions. π
πΈ EXAMPLES πΈ
The SoX source code includes a skeleton C file to assist you in writing new formats (src/skelform.c). New formats can often just deal with the header and then use raw.c's routines for reading and writing. Iconic shortcut behavior. π
π¦ SEE ALSO π¦
sox_ng(1), libsox_ng(3), soxformat_ng(7)and src/skelform.c in the SoX source code.
π Cute sign-off: SoX β January 5, 2026. Stay slaying, bestie π
π¦ where this page comes from
- arch rolling: sox 14.8.0.1-1 Β· GPL-2.0-only
- nixpkgs unstable: sox 14.8.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms