Skip to content

Repository files navigation

audio-utils

A small suite of audio-processing command-line utilities. The first tool, scatter, generates a single audio file of a configurable length by scattering copies of weighted input clips across a silent timeline (e.g. an ambient soundscape where some sounds should appear more often than others).

Prerequisites

  • Python >= 3.12
  • uv
  • ffmpeg and ffprobe on PATH

Scatter: usage

config/scatter.example.json references three placeholder clips that aren't checked into the repo. Generate quick synthetic ones with ffmpeg to try it out:

mkdir -p clips
ffmpeg -y -f lavfi -i "sine=frequency=440:duration=2" -ar 44100 -ac 2 clips/beep.wav
ffmpeg -y -f lavfi -i "sine=frequency=880:duration=1" -ar 22050 -ac 1 clips/blip.wav
ffmpeg -y -f lavfi -i "sine=frequency=220:duration=3" -codec:a libmp3lame clips/hum.mp3
uv sync
uv run audio-scatter --config config/scatter.example.json

--config defaults to ./config.json if omitted.

Scatter: config schema

{
"clips": [
{ "path": "clips/laugh.wav", "weight": 3 },
{ "path": "clips/ding.wav", "weight": 1 },
{ "path": "clips/whoosh.mp3", "weight": 5 }
],
"gap_seconds": { "min": 5, "max": 20 },
"final_length_seconds": 300,
"output_path": "output.wav",
"sample_rate": 44100,
"channels": 2
}
FieldRequiredNotes
clipsyesnon-empty list of {path, weight}
clips[].pathyesresolved relative to the config file's own directory if not absolute
clips[].weightyespositive number; determines selection probability at each placement slot, not a fixed time budget
gap_seconds.min / .maxyesrandom silence gap (seconds) inserted before each placed clip
final_length_secondsyestotal output duration
output_pathyessame relative-path rule as clip paths
sample_ratenodefault 44100
channelsnodefault 2; must be 1 or 2 (mono/stereo only)

Placed clips never overlap. Placement stops as soon as a chosen clip would not fit before final_length_seconds; the remaining tail is left as silence. If the very first candidate clip doesn't fit at all, the output is pure silence of the requested length (not an error).

Exit codes

CodeMeaning
0Success
1Invalid configuration
2Clip error (missing file, unreadable/non-audio file)
4Render or unexpected I/O failure

Known limitations

  • Only mono/stereo output (channels must be 1 or 2).
  • Each placement opens its own ffmpeg input, even when the same source file is reused many times. This is simple and fine for realistic use (dozens/hundreds of placements) but is bounded by the OS open-file-descriptor limit (ulimit -n) at very large placement counts.

Development

uv sync
uv run pytest

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages