Pedalboard-powered batch audio power-tool for the command line.
Project description
AudioCLI
A scriptable, batch-capable, cross-platform audio power-tool that runs DAW-quality effects from the command line. Built on Spotify's pedalboard — pre-built wheels for Linux, macOS, and Windows mean no system ffmpeg/sox to wrangle.
Install
pip install audiocli-tools
Note on the name: the PyPI distribution is
audiocli-tools. The bareaudioclion PyPI is an unrelated audio-measurement project —pip install audiocliwill get you the wrong tool. Once installed, everything in your shell and your code staysaudiocli/audiocli-gui/from audiocli import ....
Python ≥ 3.10. No torch, no librosa, no scipy. audiocli --help returns in under 150 ms.
The optional desktop GUI is being developed as a cross-platform PySide6 app:
pip install "audiocli-tools[gui]"
audiocli-gui
The GUI uses the same capability metadata as the CLI/library, with a compact workspace for browsing tools, building chains, and running batches.
One-shot mode
Every command takes one or more --target paths (files or directories), an optional --output, and --workers N for parallelism. Directory targets recurse by default; pass --no-recursive to flatten.
# Apply 6 dB of gain to every WAV in a folder, write to a new dir
audiocli gain --target ./stems --db 6 --output ./stems-louder
# Normalize a folder of stems to -1 dBFS peak in parallel
audiocli normalize --target ./stems --peak-db -1 --workers 8
# Convert WAVs to FLAC in place (writing alongside the source)
audiocli convert --target ./stems --format flac
# LUFS normalization for streaming targets
audiocli normalize --target ./mixes --lufs -14
# A 1000-file batch where 50 files are corrupt — 950 succeed, 50 are
# reported, exit code is non-zero, the job never hangs
audiocli compress --target ./big-folder --ratio 4 --threshold-db -20 --workers 16
Interactive REPL
audiocli shell
Chain commands with ;. set targets <paths>, set output <dir>, set workers N configure session state and persist to disk so they survive restarts. show prints the current session.
audiocli> set targets ./stems ; set output ./out ; resample 22050 ; mono -o
First-party ops
| Command | Description | Example |
|---|---|---|
gain |
Apply gain in decibels | audiocli gain --target … --db 6 |
normalize |
Peak (dBFS) or LUFS normalization | audiocli normalize --target … --peak-db -1 |
polarity |
Invert sample polarity | audiocli polarity --target … |
mono |
Mix down to 1 channel | audiocli mono --target … |
stereo |
Duplicate mono → 2-channel stereo | audiocli stereo --target … |
resample |
Change sample rate (libsamplerate) | audiocli resample --target … --sr 22050 |
pitch |
Pitch-shift in semitones | audiocli pitch --target … --semitones -2 |
trim |
Strip leading/trailing silence | audiocli trim --target … --threshold-db -60 |
fade |
Fade in/out (linear, exp, cosine) | audiocli fade --target … --fade-in-s 0.5 --shape cosine |
convert |
Change output format (wav/flac/mp3/ogg) | audiocli convert --target … --format flac |
bitdepth |
Set output bit depth (8/16/24/32) | audiocli bitdepth --target … --bits 24 |
compress |
Dynamic range compression | audiocli compress --target … --ratio 4 --threshold-db -20 |
limit |
Peak limiting | audiocli limit --target … --threshold-db -1 |
highpass |
High-pass filter | audiocli highpass --target … --hz 80 |
lowpass |
Low-pass filter | audiocli lowpass --target … --hz 8000 |
reverb |
Algorithmic reverb | audiocli reverb --target … --room-size 0.6 --wet 0.3 |
delay |
Feedback delay | audiocli delay --target … --time-s 0.4 --feedback 0.4 |
chorus |
Modulated chorus | audiocli chorus --target … --rate-hz 1.0 --depth 0.25 |
phaser |
All-pass phaser | audiocli phaser --target … --rate-hz 1.0 |
distortion |
Soft-clip distortion | audiocli distortion --target … --drive-db 25 |
bitcrush |
Bit-depth reduction | audiocli bitcrush --target … --bit-depth 8 |
vst |
Host any VST3 / AU plugin | audiocli vst --target … --plugin-path ./MyComp.vst3 --param Threshold=-12 |
info |
Print sr, channels, duration, peak, RMS, LUFS | audiocli info --target … |
remove-silent |
Delete files below an RMS threshold | audiocli remove-silent --target … --threshold-db -55 |
chunk |
Split files into N-second pieces | audiocli chunk --target … --seconds 5.0 |
hook |
Run a one-off Python transform | audiocli hook ./my_transform.py --target … |
run-script |
Run a .acli batch file |
audiocli run-script ./pipeline.acli |
shell |
Start the interactive REPL | audiocli shell |
Run audiocli <command> --help for the full flag set on any op.
--json event mode
Every op accepts --json. When set, the CLI emits one JSON object per line on stdout — newline-delimited so any other process can parse it.
audiocli normalize --target ./stems --peak-db -1 --json
{"type": "start", "total": 12, "workers": 8}
{"type": "file_done", "path": "./stems/a.wav", "ok": true, "error": null}
{"type": "progress", "done": 1, "total": 12, "current": "./stems/a.wav"}
…
{"type": "done", "ok": 12, "failed": 0, "duration_s": 3.42}
Exit code is 0 on full success, otherwise the failure count (capped at 255). Pipe straight into your CI script or progress UI.
Desktop GUI
audiocli-gui is the v2 desktop direction for macOS, Windows, and Linux. It is a thin workspace over the same pipeline and capability model: tool metadata drives the browser and parameter panel, saved chains can round-trip through native chain files or .acli scripts, and long runs use the library event/cancellation path.
For VST/AU work, the GUI discovers installed plugin bundles from conservative platform defaults without loading native code. Selecting a VST / AU Plugin node shows detected plugins, accepts an explicit plugin path, and can open the plugin's native editor in a helper process. Parameters reported by the editor are mirrored back into the node as repeatable key=value entries, with a paged, read-only parameter view in the GUI.
The current GUI polish favors dense desktop use: compact controls, icon buttons where practical, and code-font lists/empty states for scan- and capability-heavy surfaces.
Use as a library
from audiocli import run_per_file, list_ops, get_op
# Enumerate registered ops with full param metadata
for op in list_ops():
print(op.name, [p.name for p in op.params])
# Drive a batch from Python with a progress callback
gain = get_op("gain")
report = run_per_file(
["song1.wav", "song2.wav"],
gain,
{"db": 6.0},
output="./out",
workers=4,
on_event=lambda evt: print(evt),
)
print(report.ok_count, "ok,", report.failed_count, "failed")
The library API is intentionally GUI-friendly:
cancel_token: threading.Event— flip from any thread to abort a long batch. In-flight files complete; pending submissions skip.on_event— same protocol as the--jsonCLI mode, so a desktop app can render progress without shelling out.list_ops()returns frozen dataclasses (OpInfo/ParamInfo) describing every op's parameters — type, default, help, required — for dynamic UI generation.- No
print()orsys.exit()in any library module. Errors are raised from the public hierarchy:AudioCLIError→LoadError,SaveError,OpError,PluginError,ConfigError.
Plugin authors
A plugin is a regular pip-installable package that registers ops via Python entry-points. The minimum viable plugin:
# my_plugin/ops.py
from audiocli import op, AudioBuffer
@op(name="reverse", help="Reverse the audio along the time axis.")
def reverse(buf: AudioBuffer) -> AudioBuffer:
return AudioBuffer(data=buf.data[:, ::-1], sr=buf.sr, subtype=buf.subtype)
# my_plugin/pyproject.toml
[project]
name = "audiocli-plugin-reverse"
version = "0.1.0"
dependencies = ["audiocli>=2"]
[project.entry-points."audiocli.ops"]
reverse = "my_plugin.ops:reverse"
pip install audiocli-plugin-reverse
audiocli reverse --target ./stems # appears as a first-class command
The plugin contract is filter-shape only in v2.0: (buf: AudioBuffer, **params) -> AudioBuffer. First-party special-case ops (info, chunk, remove-silent, vst) bypass the contract because their shape is multi-output / analysis / side-effect; the plugin contract may broaden in v2.1+.
If a plugin's name collides with a first-party op, the first-party op wins and the conflict is logged at startup. Malformed plugin signatures raise PluginError at registration time, not at run time.
Power-user escape hatches
Don't want to publish a package for a one-off experiment? Drop a Python file and:
audiocli hook ./my_transform.py --target ./stems --custom-key value
# my_transform.py
from audiocli import AudioBuffer
def transform(buf: AudioBuffer, custom_key: str = "") -> AudioBuffer:
return AudioBuffer(data=buf.data * 0.5, sr=buf.sr, subtype=buf.subtype)
Save a sequence of commands as a .acli script and re-run it:
# pipeline.acli
gain --target ./stems --db -6 --output ./out
trim --target ./out --threshold-db -55
fade --target ./out --fade-out-s 0.5
audiocli run-script ./pipeline.acli
Settings
Persisted at the platformdirs user-config location (XDG on Linux, ~/Library/Application Support/AudioCLI on macOS, %APPDATA%\AudioCLI on Windows). JSON with a "schema": 1 field for forward-compatibility. Stores: targets, output dir, workers, recursive flag, last-used overwrite preference. Override with AUDIOCLI_SETTINGS_FILE for testing.
Development
git clone https://github.com/diontimmer/AudioCLI
cd AudioCLI
pip install -e ".[dev]"
ruff check .
ruff format --check .
pytest --cov=audiocli
CI runs the suite on {ubuntu, macos, windows} × {3.10, 3.11, 3.12}.
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file audiocli_tools-2.0.0.tar.gz.
File metadata
- Download URL: audiocli_tools-2.0.0.tar.gz
- Upload date:
- Size: 212.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1819cb0d27e117759956156265e325b93ab1326ead363d9f282a37649014c94
|
|
| MD5 |
a74778f9f75f49be46bce615aa060488
|
|
| BLAKE2b-256 |
f79e1abb4dcf52574f4197eaa9ca50ed80b784ec6e3054a7221624d3761786c8
|
Provenance
The following attestation bundles were made for audiocli_tools-2.0.0.tar.gz:
Publisher:
release.yml on diontimmer/AudioCLI
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
audiocli_tools-2.0.0.tar.gz -
Subject digest:
e1819cb0d27e117759956156265e325b93ab1326ead363d9f282a37649014c94 - Sigstore transparency entry: 1515175562
- Sigstore integration time:
-
Permalink:
diontimmer/AudioCLI@71590767b5c20f08e97eb2d62943ab1da25cb6d5 -
Branch / Tag:
refs/tags/v2.0.0 - Owner: https://github.com/diontimmer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@71590767b5c20f08e97eb2d62943ab1da25cb6d5 -
Trigger Event:
push
-
Statement type:
File details
Details for the file audiocli_tools-2.0.0-py3-none-any.whl.
File metadata
- Download URL: audiocli_tools-2.0.0-py3-none-any.whl
- Upload date:
- Size: 171.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ecffcbb7148f4b602443385f44c00837b7c9422d013603a8fca0936e5fd71236
|
|
| MD5 |
d5175409f2cd11a299650d998f4c8fb2
|
|
| BLAKE2b-256 |
db092300a909f4c56e811a4ed236fd742356363f69b4a35785a849e4ca8d32fd
|
Provenance
The following attestation bundles were made for audiocli_tools-2.0.0-py3-none-any.whl:
Publisher:
release.yml on diontimmer/AudioCLI
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
audiocli_tools-2.0.0-py3-none-any.whl -
Subject digest:
ecffcbb7148f4b602443385f44c00837b7c9422d013603a8fca0936e5fd71236 - Sigstore transparency entry: 1515175664
- Sigstore integration time:
-
Permalink:
diontimmer/AudioCLI@71590767b5c20f08e97eb2d62943ab1da25cb6d5 -
Branch / Tag:
refs/tags/v2.0.0 - Owner: https://github.com/diontimmer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@71590767b5c20f08e97eb2d62943ab1da25cb6d5 -
Trigger Event:
push
-
Statement type: