LIBSOXEFFECT_NG(3)
π NAME π
libsoxeffect_ng β SoX effect handlers' internals. Okay so this is LIBSOXEFFECT_NG(3) from the Sound eXchange_ng manual, and we're about to get into the literal internals of how SoX effect handlers work. Buckle up, bestie π
β¨ SYNOPSIS β¨
Here's the shape of an effect, fr fr:
#include "sox_i.h"
typedef struct {
...
} priv_t;
static int getopts(sox_effect_r * effp, int argc, char **argv);
static int start(sox_effect_r * effp);
static int flow(sox_effect_t * effp, sox_sample_t * ibuf,
sox_sample_t * obuf, size_t * isamp, size_t * osamp);
static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp);
static int stop(sox_effect_t * effp);
static int kill(sox_effect_t * effp);
static char *get(sox_effect_t * effp, char *name);
static char *set(sox_effect_t * effp, char *name, char *value);
sox_effect_handler_t * effect(void)
{
static char const usage[] = "[options]";
static char const * const extra_usage = {
"...",
NULL
};
int const flags = 0;
static sox_effect_handler_t handler = {
"effect", usage, extra_usage, flags,
getopt, start, flow, drain, stop, kill,
sizeof(priv_t), get, set
}
return &handler;
}
π¦ DESCRIPTION π¦
How SoX effects work internally and how to write a new one. This is the whole vibe of the page, bestie.
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 buffer sizes which refer to the number of samples processed. 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.
For effects that handle multiple channels simultaneously (see SOX_EFF_MCHAN), 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 and the number of samples that are available or have been processed is a count of mono samples, not of multichannel sample frames.
Each effect runs with one input and one output stream and its implementation comprises six principal functions that are called according to the following pseudocode:
LOOP (invocations with different parameters)
getopts
LOOP (invocations with the same parameters)
LOOP (channels)
start
LOOP (while there is input audio to process)
LOOP (channels)
flow
LOOP (while there is output audio to generate)
LOOP (channels)
drain
LOOP (channels)
stop
kill
Any function that an effect does not need can be NULL and any missing methods are automatically set to the appropriate nothing method.
getoptsβ is called once when the effect is created, with an argv-like array of string arguments whereargv[0]is the effect's name andargv[1]onward contain the effect's options as strings, the same as on the SoX command line, except for input and output whereargv[1]is a pointer to thesox_format_tthey should read or write.startβ is called with the signal parameters for the input and output streams.flowβ is called with input and output data buffers, and (by reference) the input and output data buffer sizes. It processes the input buffer into the output buffer, and sets the size variables to the numbers of samples actually processed: the number read and the number written. It is under no obligation to read from the input buffer or write to the output buffer during the same call. If the call returnsSOX_SUCCESSit will be called again; if it returnsSOX_EOF, this means that the effect will not read any more data and can be switched to drain mode.drainβ is called when there are no more input data samples. If the effect wishes to generate more data samples, it copies the generated data into the given buffer and writes the number of samples generated into*osamp. If it returnsSOX_SUCCESS, it will be called again;SOX_EOFmeans it has no more samples to write.stopβ is called when there are no more input samples and no more output samples to process. It is typically used to close or free resources such as memory and temporary files that were allocated duringstart.killβ is called to allow resources allocated bygetoptsto be released.getβ is used by the keymap mechanism to read the value of one of the effect's parameters from itspriv_t, returned as a string formatted withsprintfin"%g"format in malloc'd memory that it is the caller's responsibility to free, orNULLif there is no such readable parameter.setβ is used to set a parameter's value. The name of the parameter should match what it is called in the effect's usage string but with underscores instead of hyphens, and numerical values are passed as numeric strings (sprintf(3)'s%gformat is recommended). It returns a malloc'd string version of the value that was actually set and which it is the caller's responsibility to free. The return values are sprintfed with"%g"so, if the caller does the same, it canstrcmp()the strings to see if it was set to the requested value or something different, which happens if the specified value is outside the parameter's range, in which case the maximum or minimum is set. It returnsNULLif there is not a settable field of that name or if the value is garbage.
Effects that can have multiple stages, like echo and chorus, accept field names like decay2 to adjust only the decay of the second stage; otherwise the parameter is changed in all of its stages.
π© FLAGS π©
The flags field tell SoX more about how the effect behaves. It is the logical OR of a number of bits:
SOX_EFF_CHANβ The effect might alter the number of channels.SOX_EFF_RATEβ The effect might alter the sample rate.SOX_EFF_PRECβ The effect does its own calculation of output sample precision; otherwise a default value is taken, depending on the presence ofSOX_EFF_MODIFY.SOX_EFF_LENGTHβ The effect might alter the length of the audio as measured in time units, not necessarily in samples.SOX_EFF_MCHANβ IfSOX_EFF_MCHANis not included in an effect's flags, the middle four functions are called once per channel with mono data, the channels may be processed in parallel, each channel has its own copy of thepriv_tthat was filled in bystartandeffp->flowtells them which channel they are working on (0 and 1 in the case of stereo). IfSOX_EFF_MCHANis included, the effect does not use theLOOP (channels)lines and itsstart,flow,drainandstopfunctions are called once to process multichannel data with the samples interleaved, there is only one copy of itspriv_tandeffp->flowis always zero.SOX_EFF_NULLβ The effect does nothing. Thestartfunction can return this value to say it can be optimized out of the chain. This is done, for example, byvol 1andtrim 0.SOX_EFF_GAINβ The effect does not support thegain -h ... gain -rmechanism wherebygain -hautomatically provides headroom for effects between itself and thegain -ror the end of the effects chain. This works through themultfield ofsox_effect_twhich is set to point to the volume adjustment of thegain -heffect and is copied forwards from each effect to the next so that thegain -rcanβ¦ (yep, the original sentence literally trails off there, no cap π) Effects that know the maximum gain they could apply, at the end of theirstartfunction, divide*effp->in_signal.multby whatever their linear amplification is or if, for example, they know that their maximum output has half the amplitude of their maximum input, they multiply it by two. If there is no previousgain -hin the effects chain,multisNULL. Effects that do not affect the maximum signal amplitude do not includeSOX_EFF_GAINin their flags and need do nothing else; the pointer togain -h's volume adjustment is copied forwards in the chain for them. Confusingly,SOX_EFF_GAINmeans "I don't support what-hand-rneed because I don't know how much I might change the maximum amplitude by and I neither copy the pointer forwards nor modify what it points to"; such an effect breaks the link betweengain -handgain -rand a warning will be issued to advise of this.SOX_EFF_MODIFYβ The effect does not modify sample values but might remove or duplicate samples or insert zeros.SOX_EFF_INTERNALβ The effect is present inlibSoXbut is not valid for use by the SoX command-line tools. It applies to input and output.
π SEE ALSO π
sox_ng(1), libsox_ng(3), soxeffect_ng(7) and src/skeleff.c in the SoX source code. Like, go read those too, iykyk π
mwah π that's the whole LIBSOXEFFECT_NG(3) page from SoX, dated January 5, 2026 β now go write an iconic effect, 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