Add slices + speech_regions modules
- slices.py: extract overlapping audio chunks for manual review (filename embeds start/end timestamps for easy reference) - speech_regions.py: find/extract only the speech regions (silence stripping), useful as a faster-whisper pre-processing step - waveform.py: fix silencedetect verbosity (info, not error) + regex parser to handle '[silencedetect @ 0x...] silence_start: 0' prefix - cli.py: new 'slices' subcommand - tests: 12 new tests (slices, speech_regions, regex); 61 total all passing - README: updated with subcommand table + step-by-step workflow
This commit is contained in:
@@ -1,3 +1,119 @@
|
||||
# sermon-clean
|
||||
|
||||
Find bad segments in sermon audio, cut them out, splice in ElevenLabs replacements.
|
||||
A one-shot CLI for sermon audio editing: **find** bad segments, **cut** them out, **paste** in ElevenLabs replacements. Built because doing this by hand every time is unbearable.
|
||||
|
||||
## Why
|
||||
|
||||
Recording a sermon is fine. Post-production is not. The current workflow needs:
|
||||
|
||||
1. Manually identify where the bad words are (the painful part — Whisper stalls on long audio, and eyeballing a waveform is imprecise)
|
||||
2. Hand-write ffmpeg trim commands for each bad window
|
||||
3. Render replacement clips via ElevenLabs
|
||||
4. Hand-write the ffmpeg concat command
|
||||
5. Manually upload to Dropbox
|
||||
|
||||
`sermon-clean` collapses steps 1-5 into one command (or a few, if you want to eyeball the audio first).
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
# Requires ffmpeg in PATH (sudo apt install ffmpeg on Debian/Ubuntu)
|
||||
pip install sermon-clean
|
||||
|
||||
# Optional: for ElevenLabs auto-rendering
|
||||
export ELEVENLABS_API_KEY=...
|
||||
export ELEVENLABS_VOICE_ID=IYUnpZr9CQfSylOsOOBo # your cloned voice
|
||||
|
||||
# Optional: for auto-detect mode (transcribe + find bad words)
|
||||
pip install "sermon-clean[auto]"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### One-shot: explicit timestamps + replacement text
|
||||
|
||||
```bash
|
||||
sermon-clean pipe sermon.ogg \
|
||||
--bad "21:38-21:42:the actual sentence you meant to say" \
|
||||
--bad "1450.3-1453.1:the corrected phrase" \
|
||||
--elevenlabs-text \
|
||||
-o sermon-fixed.ogg
|
||||
```
|
||||
|
||||
### Step-by-step workflow
|
||||
|
||||
```bash
|
||||
# 1. Look at the audio — see its shape + find silence gaps
|
||||
sermon-clean scan sermon.ogg --width 100
|
||||
|
||||
# 2. Or: extract overlapping slices for manual review
|
||||
sermon-clean slices sermon.ogg --output-dir ./slices \
|
||||
--slice-seconds 5 --overlap-seconds 1
|
||||
# Listen to ./slices/slice_000_0-00-0-05.ogg in your audio player.
|
||||
# Filename embeds start/end timestamps.
|
||||
|
||||
# 3. Edit the JSON to mark bad segments + replacement text:
|
||||
# segs.json:
|
||||
# [
|
||||
# {"start": 1298.0, "end": 1302.0, "reason": "misspoke", "replacement_text": "the actual sentence"},
|
||||
# {"start": 1450.3, "end": 1453.1, "reason": "misspoke", "replacement_text": "the corrected phrase"}
|
||||
# ]
|
||||
|
||||
# 4. Trim the original around the bad windows
|
||||
sermon-clean cut sermon.ogg --segments-file segs.json
|
||||
|
||||
# 5. Render replacements (if you haven't already) and splice
|
||||
sermon-clean paste sermon.ogg --segments-file segs.json \
|
||||
--replacements "replacements/*.mp3" \
|
||||
-o sermon-fixed.ogg
|
||||
```
|
||||
|
||||
### Auto-detect mode (optional, requires `faster-whisper`)
|
||||
|
||||
```bash
|
||||
sermon-clean auto sermon.ogg --bad-words "fuck,shit,damn" --output segs.json
|
||||
# transcribes the audio, finds timestamps for any of the bad words,
|
||||
# prints a suggested JSON file you can edit before splicing
|
||||
```
|
||||
|
||||
## Subcommands
|
||||
|
||||
| Command | Purpose |
|
||||
|---|---|
|
||||
| `find` | Show audio metadata + silence gaps (no transcription) |
|
||||
| `scan` | ASCII waveform + silence marks (no transcription) |
|
||||
| `slices` | Extract overlapping audio chunks for manual review |
|
||||
| `cut` | Trim the original around bad windows (no splice) |
|
||||
| `paste` | Splice pre-rendered replacements into the trimmed original |
|
||||
| `auto` | Transcribe + find bad-word timestamps |
|
||||
| `pipe` | Run cut + paste in one command |
|
||||
|
||||
## How it works
|
||||
|
||||
- **Find** → `ffmpeg silencedetect` for natural breath pauses, plus your explicit timestamps
|
||||
- **Cut** → trim the original into N+1 good segments using ffmpeg, re-encoding to the source codec (no `wav` intermediate — bitrate-matched)
|
||||
- **Paste** → ElevenLabs renders + ffmpeg concat with bit-exact `-c copy` (no audible clicks at splice boundaries)
|
||||
- **Verify** → ffprobe the output duration against expected; if it drifted >1s, the splice silently changed the runtime
|
||||
|
||||
## Why this exists
|
||||
|
||||
The previous workflow (`audio-splice-workflow.md` in krystie-profile) was a 5-step manual recipe that's already broken twice. Each fix took 30+ minutes of bash. This package makes the same workflow a one-line command.
|
||||
|
||||
## Performance
|
||||
|
||||
- `scan` on a 27-min audio: ~50s (Opus decode is the bottleneck on this CPU)
|
||||
- `slices` on a 27-min audio with 5-sec slices: ~50s
|
||||
- `auto` on a 27-min audio: ~10-20 min with `tiny.en` model on CPU. Use `base.en` or `small.en` for better accuracy at 2-4x the time. Whisper `tiny.en` is the right model for finding a known bad-word list — you don't need higher accuracy than "did the word 'fuck' appear at all."
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
git clone https://git.sami/sami7777/sermon-clean.git
|
||||
cd sermon-clean
|
||||
pip install -e ".[test,auto]"
|
||||
pytest # 61 tests, ~17s
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT — see LICENSE.
|
||||
Reference in New Issue
Block a user