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.
- soloslot-0.1.0/.editorconfig +12 -0
- soloslot-0.1.0/.gitattributes +2 -0
- soloslot-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +40 -0
- soloslot-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- soloslot-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +21 -0
- soloslot-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +9 -0
- soloslot-0.1.0/.github/dependabot.yml +17 -0
- soloslot-0.1.0/.github/workflows/ci.yml +34 -0
- soloslot-0.1.0/.github/workflows/release.yml +60 -0
- soloslot-0.1.0/.gitignore +27 -0
- soloslot-0.1.0/.python-version +1 -0
- soloslot-0.1.0/CHANGELOG.md +37 -0
- soloslot-0.1.0/CLAUDE.md +17 -0
- soloslot-0.1.0/CONTRIBUTING.md +48 -0
- soloslot-0.1.0/LICENSE +21 -0
- soloslot-0.1.0/PKG-INFO +254 -0
- soloslot-0.1.0/README.md +231 -0
- soloslot-0.1.0/SECURITY.md +21 -0
- soloslot-0.1.0/docs/icon.svg +26 -0
- soloslot-0.1.0/docs/logo.svg +28 -0
- soloslot-0.1.0/mise.toml +43 -0
- soloslot-0.1.0/pyproject.toml +61 -0
- soloslot-0.1.0/solo.example.toml +35 -0
- soloslot-0.1.0/songs.example.toml +44 -0
- soloslot-0.1.0/src/soloslot/__init__.py +10 -0
- soloslot-0.1.0/src/soloslot/__main__.py +4 -0
- soloslot-0.1.0/src/soloslot/audio.py +69 -0
- soloslot-0.1.0/src/soloslot/cli.py +150 -0
- soloslot-0.1.0/src/soloslot/config.py +208 -0
- soloslot-0.1.0/src/soloslot/process.py +140 -0
- soloslot-0.1.0/src/soloslot/separate.py +118 -0
- soloslot-0.1.0/tests/__init__.py +0 -0
- soloslot-0.1.0/tests/conftest.py +24 -0
- soloslot-0.1.0/tests/test_audio.py +56 -0
- soloslot-0.1.0/tests/test_cli.py +212 -0
- soloslot-0.1.0/tests/test_config.py +132 -0
- soloslot-0.1.0/tests/test_separate.py +222 -0
- soloslot-0.1.0/uv.lock +989 -0
|
@@ -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,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
|
soloslot-0.1.0/CLAUDE.md
ADDED
|
@@ -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.
|
soloslot-0.1.0/PKG-INFO
ADDED
|
@@ -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).
|