Audio toolkit powered by FFmpeg. Convert between formats, trim and split recordings, join files, compress recordings to fit upload limits, normalize loudness, change volume and speed, add fades, remove silence, extract audio from video, render waveform images and prepare recordings for speech recognition — all with short, predictable commands.
aux4 aux4 pkger install aux4/audio
Requires ffmpeg and ffprobe (both ship with FFmpeg). The package tries to install FFmpeg automatically through your system package manager if it is not found. To install it yourself:
brew install ffmpeg # macOS
sudo apt install ffmpeg # Debian / Ubuntu
sudo dnf install ffmpeg-free # Fedora
apk add ffmpeg # Alpine
# Inspect a file
aux4 audio info podcast.mp3
# Convert to MP3 at 128 kbps
aux4 audio convert interview.wav --format mp3 --bitrate 128k --output interview.mp3
# Keep 1:30 to 2:45
aux4 audio trim episode.mp3 --start 01:30 --end 02:45 --output clip.mp3
# Pull the audio out of a video
aux4 audio extract meeting.mp4 --output meeting.m4a
# Shrink a recording to fit a 24 MB upload limit
aux4 audio compress meeting.wav --output meeting.mp3 --maxSize 24MB
# Turn a browser recording into the 16 kHz mono WAV that Whisper expects, and transcribe it
cat recording.webm | aux4 audio speech-prep | aux4 whisper transcribe
--output <file>, the result is saved to that file and its format follows the file extension. Without --output, the result is streamed to stdout (see Streaming and pipes).--overwrite true, and the output can never be the input file itself.--target=-14, --threshold=-40, --level=-6dB.Error: ... with a non-zero exit code.The single-file commands — info, convert, trim, extract, normalize, volume, speed, fade, trim-silence, compress, speech-prep and waveform — read from stdin and write to stdout, so they chain with each other and with other tools:
# Browser recording straight into a transcriber
cat recording.webm | aux4 audio speech-prep | aux4 whisper transcribe
# File in, audio out
aux4 audio convert recording.webm --format wav | aux4 whisper transcribe
# Several steps without temporary files
cat raw.wav | aux4 audio trim-silence | aux4 audio normalize | aux4 audio compress --output episode.mp3
/dev/stdin. MP4/M4A input (for example Safari recordings) is buffered to a temporary file first, because these containers cannot be read from a pipe. Commands that need the whole recording (info, trim, extract, fade, normalize, trim-silence --all, compress --maxSize) buffer piped input the same way. Temporary files are always removed.--output is not given. stdout then carries only the audio (or PNG for waveform); every message goes to stderr, and failures exit with a non-zero code.--format chooses it. convert requires it when streaming, speech-prep always writes WAV, compress defaults to MP3, waveform writes PNG, and the other commands keep the input format (WAV when it cannot be recognized).--output when you need a file with exact length metadata.concat and split produce files only.
Show the properties of the first audio track as JSON: container format, codec, duration (seconds), sample rate, channels, channel layout, bitrate and file size. Works on video files and piped input too, and measures the real duration of streamed browser recordings that have no duration header.
aux4 audio info [<input>]
aux4 audio info podcast.mp3
{
"file": "podcast.mp3",
"format": "mp3",
"codec": "mp3",
"duration": 1834.512,
"sampleRate": 44100,
"channels": 2,
"channelLayout": "stereo",
"bitrate": 128000,
"size": 29352448
}
Convert audio to mp3, wav, flac, ogg, opus, m4a, aac or webm. The format comes from --format, or from the --output extension; --format is required when streaming to stdout.
aux4 audio convert [<input>] [--format <format>] [--output <file>] [--bitrate <rate>] [--sampleRate <hz>] [--channels <n>] [--overwrite <true|false>]
aux4 audio convert interview.wav --format mp3 --bitrate 128k --output interview.mp3
Converted interview.wav -> interview.mp3
--sampleRate and --channels resample and remix, e.g. --sampleRate 16000 --channels 1 for mono 16 kHz.
Keep a section of the audio, defined by --start, --end and/or --duration (--end and --duration are mutually exclusive). Times are seconds (1.5) or timecodes (01:30, 00:01:30.250).
aux4 audio trim [<input>] [--start <time>] [--end <time>] [--duration <time>] [--output <file>] [--format <format>] [--overwrite <true|false>]
aux4 audio trim episode.mp3 --start 00:01:30 --end 00:02:45 --output clip.mp3
Trimmed episode.mp3 (90s - 165s) -> clip.mp3
Save the audio track of a video file. By default the audio is copied without re-encoding into a matching container (AAC → .m4a, MP3 → .mp3, Opus/Vorbis → .ogg, ...). Pass --format to re-encode.
aux4 audio extract [<input>] [--format <format>] [--output <file>] [--bitrate <rate>] [--overwrite <true|false>]
aux4 audio extract meeting.mp4 --output meeting.m4a
Extracted audio from meeting.mp4 -> meeting.m4a
Join two or more files in order. Inputs may differ in format, sample rate and channels; they are converted to match the first file.
aux4 audio concat <input> <input> [<input> ...] --output <file> [--overwrite <true|false>]
aux4 audio concat intro.wav interview.mp3 outro.wav --output episode.mp3
Concatenated 3 files -> episode.mp3
Cut a file into numbered parts, either every --segment seconds or in the middle of each pause with --silence true (pauses are quieter than --threshold dB, default -35, for at least --minSilence seconds, default 0.5). Parts are written as <prefix>-001.<ext>, <prefix>-002.<ext>, ... in --outputDir, and their paths are printed one per line, in order.
aux4 audio split <input> (--segment <seconds> | --silence true) [--threshold <dB>] [--minSilence <seconds>] [--outputDir <dir>] [--prefix <name>] [--format <format>] [--overwrite <true|false>] [--json <true|false>]
aux4 audio split lecture.mp3 --segment 600 --outputDir chunks
Split lecture.mp3 into 3 segments:
chunks/lecture-001.mp3
chunks/lecture-002.mp3
chunks/lecture-003.mp3
With --json true, the output is a JSON array with each part's path, its start offset and its duration in seconds, so timestamps computed on a part (such as a transcript) can be shifted back to the original timeline:
aux4 audio split lecture.mp3 --segment 600 --outputDir chunks --json true
[
{
"path": "chunks/lecture-001.mp3",
"start": 0,
"duration": 600
},
{
"path": "chunks/lecture-002.mp3",
"start": 600,
"duration": 600
},
{
"path": "chunks/lecture-003.mp3",
"start": 1200,
"duration": 287.412
}
]
Bring a recording to a target loudness (EBU R128, two passes, linear gain). Defaults suit podcasts and spoken word: --target -16 LUFS, --truePeak -1.5 dBTP, --loudnessRange 11 LU. Use --target=-14 for music streaming or --target=-23 for broadcast.
aux4 audio normalize [<input>] [--target <LUFS>] [--truePeak <dBTP>] [--loudnessRange <LU>] [--output <file>] [--format <format>] [--overwrite <true|false>]
aux4 audio normalize episode.wav --output episode-normalized.wav
Normalized episode.wav (-16 LUFS) -> episode-normalized.wav
Change the volume by a multiplier (0.5, 2) or a gain in decibels (6dB, --level=-3dB).
aux4 audio volume [<input>] --level <level> [--output <file>] [--format <format>] [--overwrite <true|false>]
aux4 audio volume background.mp3 --level 0.3 --output background-quiet.mp3
Adjusted volume of background.mp3 (0.3) -> background-quiet.mp3
Play faster or slower without changing the pitch. --factor ranges from 0.1 to 10.
aux4 audio speed [<input>] --factor <factor> [--output <file>] [--format <format>] [--overwrite <true|false>]
aux4 audio speed lecture.mp3 --factor 1.5 --output lecture-fast.mp3
Changed speed of lecture.mp3 (1.5x) -> lecture-fast.mp3
Add a fade-in and/or fade-out, lengths in seconds.
aux4 audio fade [<input>] [--fadeIn <seconds>] [--fadeOut <seconds>] [--output <file>] [--format <format>] [--overwrite <true|false>]
aux4 audio fade jingle.wav --fadeIn 0.5 --fadeOut 2 --output jingle-fade.wav
Faded jingle.wav (in: 0.5s, out: 2s) -> jingle-fade.wav
Remove silence at the beginning and end (audio quieter than --threshold dB, default -50). With --all true, pauses inside the recording longer than --maxPause seconds (default 0.5) are shortened to that length.
aux4 audio trim-silence [<input>] [--threshold <dB>] [--all <true|false>] [--maxPause <seconds>] [--output <file>] [--format <format>] [--overwrite <true|false>]
aux4 audio trim-silence voice-note.m4a --output voice-note-clean.m4a
Removed silence from voice-note.m4a -> voice-note-clean.m4a
Make a recording as small as possible while keeping speech clear: mono, 16 kHz, 32 kbps MP3 by default, or --format opus / --format m4a. With --maxSize (bytes, or KB/MB/GB decimal and KiB/MiB/GiB binary), the bitrate is lowered from the input duration so the result fits, down to 8 kbps. If the audio cannot fit even at 8 kbps, nothing is written and the command fails asking you to split the file first. The output path, size in bytes and bitrate used are printed.
aux4 audio compress [<input>] [--output <file>] [--format <mp3|opus|m4a>] [--bitrate <rate>] [--sampleRate <hz>] [--channels <n>] [--maxSize <size>] [--overwrite <true|false>]
aux4 audio compress all-hands.m4a --output upload.mp3 --maxSize 24MB
Compressed all-hands.m4a -> upload.mp3 (21844992 bytes, 24k)
Convert any recording — including browser recordings (WebM/Opus from Chrome and Firefox, MP4/AAC from Safari) — into 16 kHz mono 16-bit WAV, the input format of Whisper, whisper.cpp and most speech-recognition engines. --sampleRate changes the rate when an engine needs something else.
aux4 audio speech-prep [<input>] [--sampleRate <hz>] [--output <file.wav>] [--overwrite <true|false>]
aux4 audio speech-prep recording.webm --output recording-16k.wav
Prepared recording.webm for speech recognition (16000 Hz mono WAV) -> recording-16k.wav
cat recording.webm | aux4 audio speech-prep | aux4 whisper transcribe
Render a waveform image (.png with a transparent background, or .jpg). Without --output, a PNG is streamed to stdout.
aux4 audio waveform [<input>] [--size <WxH>] [--color <color>] [--output <file>] [--overwrite <true|false>]
aux4 audio waveform episode.mp3 --size 800x120 --color "#111827" --output cover-wave.png
Rendered waveform of episode.mp3 (800x120) -> cover-wave.png
| Variable | Description | |----------|-------------| | FFMPEG_PATH | Path to the ffmpeg binary to use instead of the one on PATH | | FFPROBE_PATH | Path to the ffprobe binary to use instead of the one on PATH |