soloslot 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. soloslot-0.1.0/.editorconfig +12 -0
  2. soloslot-0.1.0/.gitattributes +2 -0
  3. soloslot-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +40 -0
  4. soloslot-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  5. soloslot-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +21 -0
  6. soloslot-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +9 -0
  7. soloslot-0.1.0/.github/dependabot.yml +17 -0
  8. soloslot-0.1.0/.github/workflows/ci.yml +34 -0
  9. soloslot-0.1.0/.github/workflows/release.yml +60 -0
  10. soloslot-0.1.0/.gitignore +27 -0
  11. soloslot-0.1.0/.python-version +1 -0
  12. soloslot-0.1.0/CHANGELOG.md +37 -0
  13. soloslot-0.1.0/CLAUDE.md +17 -0
  14. soloslot-0.1.0/CONTRIBUTING.md +48 -0
  15. soloslot-0.1.0/LICENSE +21 -0
  16. soloslot-0.1.0/PKG-INFO +254 -0
  17. soloslot-0.1.0/README.md +231 -0
  18. soloslot-0.1.0/SECURITY.md +21 -0
  19. soloslot-0.1.0/docs/icon.svg +26 -0
  20. soloslot-0.1.0/docs/logo.svg +28 -0
  21. soloslot-0.1.0/mise.toml +43 -0
  22. soloslot-0.1.0/pyproject.toml +61 -0
  23. soloslot-0.1.0/solo.example.toml +35 -0
  24. soloslot-0.1.0/songs.example.toml +44 -0
  25. soloslot-0.1.0/src/soloslot/__init__.py +10 -0
  26. soloslot-0.1.0/src/soloslot/__main__.py +4 -0
  27. soloslot-0.1.0/src/soloslot/audio.py +69 -0
  28. soloslot-0.1.0/src/soloslot/cli.py +150 -0
  29. soloslot-0.1.0/src/soloslot/config.py +208 -0
  30. soloslot-0.1.0/src/soloslot/process.py +140 -0
  31. soloslot-0.1.0/src/soloslot/separate.py +118 -0
  32. soloslot-0.1.0/tests/__init__.py +0 -0
  33. soloslot-0.1.0/tests/conftest.py +24 -0
  34. soloslot-0.1.0/tests/test_audio.py +56 -0
  35. soloslot-0.1.0/tests/test_cli.py +212 -0
  36. soloslot-0.1.0/tests/test_config.py +132 -0
  37. soloslot-0.1.0/tests/test_separate.py +222 -0
  38. soloslot-0.1.0/uv.lock +989 -0
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [*.{toml,yml,yaml,json,md}]
12
+ indent_size = 2
@@ -0,0 +1,2 @@
1
+ * text=auto eol=lf
2
+ *.wav binary
@@ -0,0 +1,40 @@
1
+ name: Bug report
2
+ description: Something does not work as documented
3
+ labels: [bug]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Please do not attach copyrighted audio. Describe the files instead.
9
+ - type: textarea
10
+ id: what
11
+ attributes:
12
+ label: What happened, and what did you expect?
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: command
17
+ attributes:
18
+ label: Command and output
19
+ description: The command you ran and its full output.
20
+ render: shell
21
+ validations:
22
+ required: true
23
+ - type: textarea
24
+ id: config
25
+ attributes:
26
+ label: Config
27
+ description: Your `solo.toml` / `songs.toml` (remove anything private).
28
+ render: toml
29
+ - type: input
30
+ id: files
31
+ attributes:
32
+ label: Stem files
33
+ description: Format, sample rate, bit depth, e.g. "WAV 48 kHz 24 bit from Moises".
34
+ - type: input
35
+ id: version
36
+ attributes:
37
+ label: Version and OS
38
+ description: Output of `soloslot --version`, and your operating system.
39
+ validations:
40
+ required: true
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Report a security problem privately
4
+ url: https://github.com/swallat/soloslot/security/advisories/new
5
+ about: Please do not open a public issue for vulnerabilities.
@@ -0,0 +1,21 @@
1
+ name: Feature request
2
+ description: Suggest an idea or an improvement
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: What are you trying to do?
9
+ description: Describe your practice or workflow, not only the feature.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: idea
14
+ attributes:
15
+ label: What would you like the tool to do?
16
+ validations:
17
+ required: true
18
+ - type: textarea
19
+ id: alternatives
20
+ attributes:
21
+ label: Alternatives you tried
@@ -0,0 +1,9 @@
1
+ ## What and why
2
+
3
+ <!-- What does this change, and why? Link the issue if there is one. -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] `mise run check` passes (ruff + pytest)
8
+ - [ ] Tests added or updated (synthetic audio only, no real recordings)
9
+ - [ ] README / example configs / `CHANGELOG.md` updated if behaviour or options changed
@@ -0,0 +1,17 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: uv
4
+ directory: "/"
5
+ schedule:
6
+ interval: monthly
7
+ groups:
8
+ python-dependencies:
9
+ patterns: ["*"]
10
+
11
+ - package-ecosystem: github-actions
12
+ directory: "/"
13
+ schedule:
14
+ interval: monthly
15
+ groups:
16
+ github-actions:
17
+ patterns: ["*"]
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ${{ matrix.os }}
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ os: [ubuntu-latest, windows-latest, macos-latest]
15
+ steps:
16
+ - uses: actions/checkout@v7
17
+ - uses: astral-sh/setup-uv@v7
18
+ with:
19
+ version: "0.13.5"
20
+ - run: uv sync --locked
21
+ - run: uv run pytest
22
+ - name: CLI smoke test
23
+ run: uv run soloslot --version
24
+
25
+ lint:
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v7
29
+ - uses: astral-sh/setup-uv@v7
30
+ with:
31
+ version: "0.13.5"
32
+ - run: uv sync --locked
33
+ - run: uv run ruff check .
34
+ - run: uv run ruff format --check .
@@ -0,0 +1,60 @@
1
+ name: Release
2
+
3
+ # Publishes to PyPI when a version tag (v0.1.0, ...) is pushed. Uses PyPI Trusted Publishing
4
+ # (OIDC), so no API token is stored in GitHub.
5
+ on:
6
+ push:
7
+ tags: ["v*"]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v7
14
+ - uses: astral-sh/setup-uv@v7
15
+ with:
16
+ version: "0.13.5"
17
+ - name: Check that the tag matches the package version
18
+ run: |
19
+ version="$(uv run --no-project python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")"
20
+ if [ "v${version}" != "${GITHUB_REF_NAME}" ]; then
21
+ echo "Tag ${GITHUB_REF_NAME} does not match pyproject.toml version ${version}" >&2
22
+ exit 1
23
+ fi
24
+ - run: uv sync --locked
25
+ - run: uv run pytest
26
+ - run: uv build
27
+ - name: Smoke test the wheel
28
+ run: uv run --no-project --isolated --with dist/*.whl soloslot --version
29
+ - uses: actions/upload-artifact@v4
30
+ with:
31
+ name: dist
32
+ path: dist/
33
+
34
+ publish:
35
+ needs: build
36
+ runs-on: ubuntu-latest
37
+ environment: pypi
38
+ permissions:
39
+ id-token: write # required for Trusted Publishing
40
+ steps:
41
+ - uses: actions/download-artifact@v4
42
+ with:
43
+ name: dist
44
+ path: dist/
45
+ - uses: pypa/gh-action-pypi-publish@release/v1
46
+
47
+ github-release:
48
+ needs: publish
49
+ runs-on: ubuntu-latest
50
+ permissions:
51
+ contents: write
52
+ steps:
53
+ - uses: actions/download-artifact@v4
54
+ with:
55
+ name: dist
56
+ path: dist/
57
+ - name: Create GitHub release
58
+ env:
59
+ GH_TOKEN: ${{ github.token }}
60
+ run: gh release create "${GITHUB_REF_NAME}" dist/* --repo "${GITHUB_REPOSITORY}" --generate-notes --title "${GITHUB_REF_NAME}"
@@ -0,0 +1,27 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .venv/
8
+
9
+ # Tools
10
+ .pytest_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ htmlcov/
14
+
15
+ # IDE / local
16
+ .idea/
17
+ .vscode/
18
+ .claude/settings.local.json
19
+ .claude/worktrees/
20
+
21
+ # User data: audio and personal config never belong in the repo
22
+ *.wav
23
+ *.mp3
24
+ *.flac
25
+ /stems/
26
+ /out/
27
+ /songs.toml
@@ -0,0 +1 @@
1
+ 3.14
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Changed
10
+ - Renamed from stem-solo-gap to **soloslot** (package, command and module).
11
+
12
+ ### Added
13
+ - Stem separation with Demucs (optional `separate` extra): give a full song (MP3, WAV, FLAC,
14
+ ...) instead of a stems folder, on the command line or as `input` in the config. Default
15
+ model `htdemucs_6s` (drums, bass, guitar, piano, vocals, other); choose another with `model`.
16
+ - Command line mode for one song: `soloslot song.mp3 --solo 2:15-3:40 --mute guitar`, with
17
+ `--solo` (repeatable), `--hear`, `--mute`, `--model`, `--format` and `--output`.
18
+ - `mute` as the opposite of `hear`: name the stems to silence in the solo, the rest stays.
19
+ - `--backing-only` / `stems = false` to write only the backing track.
20
+ - Separated stems are cached in the output folder and reused until the input file changes.
21
+
22
+ ## [0.1.0] - 2026-11-08
23
+
24
+ ### Added
25
+ - Silence one or more solo regions in stem files and write the stems plus a mixed
26
+ `<song> - Backing Track`.
27
+ - `hear` / `skip` to choose which stems stay audible in the solo and which files are ignored;
28
+ a `hear` entry that matches no stem is reported as a warning.
29
+ - Solo regions as timestamps (`start`/`end`) or bars (`start_bar`/`end_bar` with `bpm`).
30
+ - Input as WAV, FLAC or MP3; output as WAV or FLAC (`format`).
31
+ - One config per song (default `./solo.toml`, run inside the stems folder) or one config with
32
+ several `[[song]]` tables; several configs can be passed in one call.
33
+ - `--song` to pick a song and `--dry-run` to preview.
34
+ - Refuses an output folder that equals the stems folder, so originals are never overwritten.
35
+
36
+ [Unreleased]: https://github.com/swallat/soloslot/compare/v0.1.0...HEAD
37
+ [0.1.0]: https://github.com/swallat/soloslot/commits/main
@@ -0,0 +1,17 @@
1
+ # soloslot
2
+
3
+ CLI that mutes chosen stems in a solo region and writes a play-along backing track. A full
4
+ song can be split into stems first with Demucs (optional `separate` extra).
5
+
6
+ ## Layout
7
+ - `src/soloslot/`: `config.py` (TOML, validation), `audio.py` (pure helpers),
8
+ `process.py` (one song, file I/O), `separate.py` (Demucs, imported lazily), `cli.py` (click).
9
+ - Config: either `[[song]]` tables (many songs) or top-level `solos` (one song, stems next to the
10
+ config; default `./solo.toml`). `Song.output` is the final output directory.
11
+ - Tests never load Demucs: they replace `separate.load_separator` with a fake (see
12
+ `tests/test_separate.py`).
13
+ - Tests go in `tests/` and use synthetic audio only; never commit real audio (`*.wav` is ignored).
14
+
15
+ ## Workflow
16
+ - `mise run install` once, then `mise run check` (ruff + pytest) before committing.
17
+ - Python and packages are managed by uv (`.python-version`, `uv.lock`); mise only provides uv.
@@ -0,0 +1,48 @@
1
+ # Contributing
2
+
3
+ Thanks for your interest! Bug reports, ideas and pull requests are welcome.
4
+
5
+ ## Reporting bugs and ideas
6
+
7
+ Open an [issue](https://github.com/swallat/soloslot/issues/new/choose). For a bug,
8
+ please include:
9
+
10
+ - the command you ran and the full output,
11
+ - your config file (remove anything private),
12
+ - the file format of your stems (WAV, FLAC, MP3, sample rate, bit depth),
13
+ - your OS and `soloslot --version`.
14
+
15
+ Please **do not attach copyrighted audio**. Describe the files instead.
16
+
17
+ ## Development setup
18
+
19
+ [mise](https://mise.jdx.dev) provides `uv`; `uv` manages Python and the packages.
20
+
21
+ ```bash
22
+ mise install # installs uv
23
+ mise run install # uv sync
24
+ mise run check # ruff + pytest
25
+ ```
26
+
27
+ Without mise, `uv sync` and `uv run pytest` work the same way.
28
+
29
+ ## Pull requests
30
+
31
+ 1. Fork, then create a branch from `main`.
32
+ 2. Keep the change focused. Add or update tests; they use synthetic audio only (see
33
+ `tests/conftest.py`). Never commit real audio: `*.wav`, `*.mp3` and `*.flac` are git-ignored.
34
+ 3. Run `mise run check` (or `uv run ruff check . && uv run ruff format --check . && uv run pytest`).
35
+ CI runs the same on Linux, Windows and macOS.
36
+ 4. Update the README, `solo.example.toml` / `songs.example.toml` and `CHANGELOG.md` if behaviour
37
+ or config options change.
38
+ 5. Open the pull request and describe what changed and why.
39
+
40
+ By contributing you agree that your contribution is licensed under the [MIT License](LICENSE).
41
+
42
+ ## Releasing
43
+
44
+ 1. Move the `Unreleased` entries in `CHANGELOG.md` under a new version heading and bump
45
+ `version` in `pyproject.toml`.
46
+ 2. Merge that change to `main`, then tag it: `git tag v0.1.0 && git push origin v0.1.0`.
47
+ 3. The `Release` workflow checks that the tag matches the version, runs the tests, builds the
48
+ package, publishes to PyPI via Trusted Publishing and creates the GitHub release.
soloslot-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sebastian Wallat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.5
2
+ Name: soloslot
3
+ Version: 0.1.0
4
+ Summary: Mute instruments in the solo of a song to build play-along backing tracks
5
+ Project-URL: Homepage, https://github.com/swallat/soloslot
6
+ Project-URL: Source, https://github.com/swallat/soloslot
7
+ Project-URL: Issues, https://github.com/swallat/soloslot/issues
8
+ Author: Sebastian Wallat
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: audio,backing-track,demucs,play-along,practice,stem-separation,stems
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Multimedia :: Sound/Audio
16
+ Requires-Python: >=3.12
17
+ Requires-Dist: click>=8.1
18
+ Requires-Dist: numpy>=1.26
19
+ Requires-Dist: soundfile>=0.12
20
+ Provides-Extra: separate
21
+ Requires-Dist: demucs>=4.1; extra == 'separate'
22
+ Description-Content-Type: text/markdown
23
+
24
+ <p align="center">
25
+ <img src="docs/logo.svg" alt="soloslot logo" width="420">
26
+ </p>
27
+
28
+ <h1 align="center">soloslot</h1>
29
+
30
+ <p align="center"><strong>Make room for your solo.</strong><br>
31
+ Turn any song into a play-along backing track in one command.</p>
32
+
33
+ <p align="center">
34
+ <a href="https://github.com/swallat/soloslot/actions/workflows/ci.yml"><img src="https://github.com/swallat/soloslot/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
35
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
36
+ </p>
37
+
38
+ You know the song. You want to play the guitar part, the piano solo, the sax line. But the
39
+ record has the original player on it, right where you want to jump in.
40
+
41
+ soloslot takes the song, finds the instruments you name, and takes them **out of the solo
42
+ section only**. The band keeps playing, the song stays whole before and after, and the gap is
43
+ yours.
44
+
45
+ ```bash
46
+ soloslot "Blue Bossa.mp3" --solo 1:05-2:40 --mute guitar
47
+ ```
48
+
49
+ That is the whole workflow: one song in, one backing track out.
50
+
51
+ ## Why soloslot
52
+
53
+ - **Practice with the real recording.** No more generic backing tracks or MIDI band-in-a-box.
54
+ You play with the actual band, the actual groove, the actual song.
55
+ - **Only the solo is muted.** Intro, theme and outro stay intact, so you play the song the way
56
+ it goes, from the top, and step into the gap at the right moment.
57
+ - **Start from a plain MP3.** Drop in an MP3, WAV or FLAC. soloslot splits it into stems with
58
+ [Demucs](https://github.com/adefossez/demucs), a state-of-the-art open-source separator. No
59
+ stems? No problem.
60
+ - **Or bring your own stems.** Already have stems from Moises, Demucs or your DAW? soloslot works
61
+ on those directly and needs no separation, no PyTorch and no GPU.
62
+ - **Say what goes, or what stays.** `--mute guitar` removes one instrument. `--hear
63
+ piano,bass,drums` keeps only the rhythm section. Pick whichever is shorter to type.
64
+ - **Several solos, one run.** Repeat `--solo` for every section you want to play over.
65
+ - **Click-free edits.** Short fades at the edges of each gap, so there are no pops or abrupt
66
+ cuts where the instrument leaves and returns.
67
+ - **Fast to try again.** The separation is cached. Change the solo region, mute another
68
+ instrument, re-run: the song is not split twice.
69
+ - **Safe for your files.** Your originals are never modified. Everything goes to a separate
70
+ output folder, and soloslot refuses to write over your input.
71
+ - **Private and offline.** Everything runs on your computer. Your recordings are never uploaded.
72
+ Only the Demucs model is downloaded, once.
73
+ - **Lossless output.** WAV or FLAC, with the bit depth of your source preserved (MP3 input is
74
+ written as 24 bit).
75
+ - **Plain-text config for repeat use.** Describe a song, or a whole repertoire, in a small TOML
76
+ file. Give solos as timestamps or as bar numbers.
77
+
78
+ ## What you get
79
+
80
+ For every song, an output folder with:
81
+
82
+ | File | What it is |
83
+ | --- | --- |
84
+ | `<song> - Backing Track.wav` | The finished play-along track: the whole song with your chosen instruments missing in the solo. Load it into your player and go. |
85
+ | `drums.wav`, `bass.wav`, `guitar.wav`, ... | The individual stems, each with the same mute applied. Handy for DAWs, for loops, or for mixing your own balance. Skip them with `--backing-only`. |
86
+ | `separated/<model>/` | The untouched stems from separation, kept so the next run is instant. |
87
+
88
+ ## Install
89
+
90
+ You need [uv](https://docs.astral.sh/uv/). It fetches a suitable Python (3.12 or newer) for you.
91
+
92
+ ```bash
93
+ # with stem separation (pulls in PyTorch, a large download)
94
+ uv tool install "soloslot[separate] @ git+https://github.com/swallat/soloslot.git"
95
+
96
+ # without it, if you only work on stems you already have
97
+ uv tool install git+https://github.com/swallat/soloslot.git
98
+
99
+ soloslot --help
100
+ ```
101
+
102
+ Update with `uv tool upgrade soloslot`.
103
+
104
+ The first separation downloads the Demucs model (about 50 to 100 MB) and caches it. Separation
105
+ runs on an NVIDIA GPU if PyTorch finds one, otherwise on the CPU, where a song takes a few
106
+ minutes.
107
+
108
+ ## Quick start
109
+
110
+ ```bash
111
+ # The guitar drops out between 1:05 and 2:40
112
+ soloslot song.mp3 --solo 1:05-2:40 --mute guitar
113
+
114
+ # Only piano, bass and drums stay in the solo
115
+ soloslot song.flac --solo 2:15-3:40 --hear piano,bass,drums
116
+
117
+ # Two solos, two instruments gone
118
+ soloslot song.mp3 --solo 1:05-2:40 --solo 4:10-5:02 --mute guitar,piano
119
+
120
+ # Look first, write nothing
121
+ soloslot song.mp3 --solo 2:15-3:40 --mute guitar --dry-run
122
+ ```
123
+
124
+ | Option | Meaning |
125
+ | --- | --- |
126
+ | `--solo START-END` | A solo region. Repeat it for several. Times like `135.5`, `2:15`, `1:02:15.5`. |
127
+ | `--mute STEMS` | Silence these stems in the solo; everything else stays. |
128
+ | `--hear STEMS` | The opposite: only these stems stay in the solo. Use one of the two. |
129
+ | `--model` | Demucs model. Default `htdemucs_6s` splits into **drums, bass, guitar, piano, vocals, other**. `htdemucs` and `htdemucs_ft` give drums, bass, vocals, other, and are a bit cleaner at that. |
130
+ | `--backing-only` | Write only the backing track. |
131
+ | `--format flac` | Write FLAC instead of WAV. |
132
+ | `-o, --output DIR` | Output folder. Default: `out/<song>/` next to the song. |
133
+ | `--dry-run` | Show what would happen and write nothing. |
134
+
135
+ ## Working with stems you already have
136
+
137
+ Put each song's stems (WAV, FLAC or MP3) in their own folder and describe the solo in a
138
+ `solo.toml` next to them (see `solo.example.toml`):
139
+
140
+ ```toml
141
+ hear = ["piano", "bass", "drums"] # stems that stay audible in the solo
142
+ skip = ["visualizer"] # ignore the full mix
143
+ solos = [ { start = "2:15", end = "3:40" } ]
144
+ ```
145
+
146
+ ```bash
147
+ cd stems/Interplay
148
+ soloslot # uses ./solo.toml
149
+ soloslot --dry-run # show what would happen, write nothing
150
+ ```
151
+
152
+ The song name defaults to the folder name and the result goes to `./out/`. You can also pass
153
+ several configs at once, for example `soloslot stems/*/solo.toml`.
154
+
155
+ ### A whole repertoire in one file
156
+
157
+ Copy `songs.example.toml` to `songs.toml` and list your songs as `[[song]]` tables:
158
+
159
+ ```toml
160
+ [defaults]
161
+ hear = ["piano", "bass", "drums"] # shared by all songs
162
+
163
+ [[song]]
164
+ name = "Interplay"
165
+ folder = "stems/Interplay"
166
+ bpm = 113
167
+ solos = [ { start_bar = 36, end_bar = 97 } ]
168
+
169
+ [[song]]
170
+ name = "Blue Bossa"
171
+ input = "Blue Bossa.mp3" # a full song: split it first
172
+ mute = ["guitar"]
173
+ solos = [ { start = "1:05", end = "2:40" } ]
174
+ ```
175
+
176
+ ```bash
177
+ soloslot songs.toml # all songs
178
+ soloslot songs.toml --song Interplay # one song
179
+ ```
180
+
181
+ Output goes to `out/<song>/`, next to the config file. Defaults live in `[defaults]` and any
182
+ song can override them.
183
+
184
+ ## Configuration reference
185
+
186
+ - **`input`**: a full song to split into stems first, instead of `folder`. The song name
187
+ defaults to the file name.
188
+ - **`model`**: Demucs model for `input`, default `htdemucs_6s`.
189
+ - **`hear`**: stems that stay audible in the solo; every other stem is silenced there. Matching
190
+ is a case-insensitive substring of the stem name (`"piano"` matches `Grand Piano`). Stems a
191
+ song does not have are ignored. A `hear` entry that matches nothing is reported as a warning,
192
+ so a typo cannot silently mute the wrong thing.
193
+ - **`mute`**: the opposite of `hear`. Use either one per song.
194
+ - **`skip`**: files or stems to ignore, such as a full mix (`["visualizer"]`).
195
+ - **`solos`**: one or more solo regions, see below.
196
+ - **`format`**: `"wav"` (default) or `"flac"`. FLAC is lossless and smaller; float or 32 bit
197
+ input becomes 24 bit there.
198
+ - **`stems`**: `stems = false` writes only the backing track.
199
+ - **`fade_ms`**, **`mixdown`**, **`output`**: see `songs.example.toml`.
200
+ - Relative paths are resolved against the directory of the config file.
201
+
202
+ ### Solo regions: timestamps or bars
203
+
204
+ ```toml
205
+ # Timestamps: no tempo needed
206
+ solos = [ { start = "2:15", end = "3:40" } ]
207
+
208
+ # Several solos, mixing seconds and mm:ss
209
+ solos = [ { start = 135.5, end = "3:40" }, { start = "4:10.5", end = "5:02" } ]
210
+
211
+ # Bars: needs bpm on the song
212
+ bpm = 113
213
+ solos = [ { start_bar = 36, end_bar = 97 } ]
214
+ ```
215
+
216
+ - **Timestamps** are seconds from the start of the file: `135.5`, `"2:15"` or `"1:02:15.5"`.
217
+ Read them off your player or DAW.
218
+ - **Bars** count from 1, bar 1 starts at the beginning of the file, and `end_bar` is the bar
219
+ where the solo is over again. Use `beats_per_bar` (default 4) for other meters and `offset`
220
+ if the file has a lead-in before bar 1.
221
+ - Bars assume a constant tempo. For live recordings with a drifting tempo, use timestamps.
222
+
223
+ Stem names are read from Moises file names (`<title>-<Stem>-<key>-<tempo>bpm-<hz>hz.wav`);
224
+ other names are matched on the whole file name.
225
+
226
+ ## Your audio
227
+
228
+ soloslot only processes files you provide, on your own computer. It includes no recordings and
229
+ downloads none; only the Demucs model is fetched. Make sure you have the right to use your
230
+ recordings. The output keeps the copyright status of the original. That is why `*.wav`,
231
+ `*.mp3` and `*.flac` are git-ignored and the tests use synthetic audio only.
232
+
233
+ ## Develop
234
+
235
+ [mise](https://mise.jdx.dev) provides `uv`; `uv` manages Python and packages.
236
+
237
+ ```bash
238
+ mise install # uv
239
+ mise run install # uv sync
240
+ mise run check # ruff + pytest
241
+ mise tasks # all tasks
242
+ ```
243
+
244
+ See [CONTRIBUTING.md](CONTRIBUTING.md) to contribute, [CHANGELOG.md](CHANGELOG.md) for changes
245
+ and [SECURITY.md](SECURITY.md) to report a vulnerability.
246
+
247
+ ## License
248
+
249
+ [MIT](LICENSE) © 2026 Sebastian Wallat.
250
+
251
+ soloslot installs these libraries, which keep their own licenses: click (BSD-3-Clause), NumPy
252
+ (BSD-3-Clause and other permissive licenses) and python-soundfile (BSD-3-Clause), whose binary
253
+ wheels include libsndfile (LGPL-2.1-or-later). The `separate` extra adds Demucs (MIT) and
254
+ PyTorch (BSD-3-Clause).