v0.2.0 (Alpha)#

Release Date: 20 August 2026

Important Note#

First minor-version bump. Introduces _TranscribeResult - a dict-return with a string-compatible deprecation shim - and continues the fullverbose migration begun in v0.1.6. Both string-return and full= will be removed in v1.0.0.

Release plan updated Alpha phased was scheduled to run for three months from 01 June 2026 - 31 August 2026 inclusive. The alpha phase began in June 2026 and is ongoing; we expect it to run through late 2026 and into 2027 - Beta (1.0.0) is targeted on API stability and benchmark validation rather than a fixed calendar date. In the meantime, we are reaching out to communities, both musicians and academics alike, to find people to test - and hopefully improve - the deterministic classification model. For more info on where this is headed see roadmap or https://github.com/orgs/DrumScript/discussions

Highlights#

Multi-format transcription output with backwards-compatible deprecation shim#

transcribe() now returns a dict with pdf_path, json_path, and midi_path keys, so users can see all the files that were actually written. Previously, score_builder.build_score() silently wrote JSON and MIDI files alongside the PDF, but transcribe() only returned the PDF path.

For backwards compatibility, using the return value as a string still works (returns the PDF path) but emits a DeprecationWarning. String behaviour will be removed in v1.0.0.

Migration:

# v0.1.x (still works, but deprecated)
pdf = ds.transcribe("drums.wav")
print(pdf)  # warns

# v0.2.0+ (recommended)
result = ds.transcribe("drums.wav")
print(result["pdf_path"])
print(result["json_path"])
print(result["midi_path"])

Versioned documentation#

Documentation now deploys to version-specific folders on GitHub Pages. A version dropdown in the navbar lets users switch between latest, dev, and archived releases (e.g. v0.1.6)


v0.2.0 release#

Additions

  • Versioned documentation deployment via docs.yml GitHub Actions workflow (docs/versioned-deploy branch):

    • Documentation now deploys to version-specific folders on gh-pages (e.g. /v0.1.6/, /v0.2.0/)

    • Tag pushes (v*) deploy to both /<tag>/ and /latest/ folders

    • Main branch pushes deploy to /dev/ folder (bleeding-edge docs)

    • Root index.html auto-generated on tag push, redirects to /latest/

    • keep_files: true ensures older version folders are never deleted

    • Existing root-level docs remain untouched until explicit cleanup

    • Contributor and Developer updated guidance (#283, #132, #291)

  • Added version drop down to shibuya documentation (#183, #281)

  • Added repo-stats.yml GitHub Actions workflow: daily (23:00 UTC) collection of repository traffic statistics (views, clones, stars, forks, referrers, popular paths) via github-repo-stats. Data persisted to github-repo-stats branch. Overcomes GitHub’s 14-day traffic data retention limit and tracks usage

  • Added Traffic section to README with links to daily-updated repository statistics report (PDF and HTML), generated by repo-stats.yml via github-repo-stats

  • Added CHANGELOG reference to README table of contents (Sphinx docs already linked via symlink)

  • _TranscribeResult deprecation shim class in drumscript/__init__.py: dict subclass with __str__ and __fspath__ methods that emit DeprecationWarning when the return value of transcribe() is used as a string. Provides smooth migration path from v0.1.x string return to v1.0.0 dict return.

  • Added scripts/verify_release.sh - 56-check release verification script covering every documented CLI command and public API function, run in a clean temporary directory to catch environment assumptions (e.g. the missing-outputs/ bug)

  • Added scripts/close_issues_v020.sh - batch gh issue close script (with per-issue comments) for the GitHub issues resolved in v0.2.0

  • Added timeout to jobs block in tests.yml and add --no-install-recommend to linux system dependencies job to prevent apt-get issues in workflow

Changes

  • Updated table ordering in docs/index.md to match right sidebar ordering and added missing sidebar navigation point for tempogram-detection

  • Amended documentation to remove bold markdown formatting for H1 references feeding into the side-nav bar visual presentation, for all except DrumScript CLI Reference; fixed ordering side in toctree (docs/index.md) for User Guide submenu to 1. remove duplicated usage reference in toctree and 2. reorder items alphabetically. Amended right hand navbar so that H2 links are now alphabetical.

  • Updated and tidied the examples for extract stems in README.md; split example up into extract stems and backing track function examples. (#85)

  • Standardised git tag naming convention from drumscript__vX.Y.Z-alpha to vX.Y.Z (e.g. v0.1.6). Old tags remain on remote (branch protection prevents deletion) but are ignored by the docs.yml workflow which only triggers on v*.

  • transcribe() non-verbose return type changed from str to _TranscribeResult (a dict subclass). The return value is a dict with pdf_path, json_path, and midi_path keys. For backwards compatibility, using the result as a string still works (returns the PDF path) but emits a DeprecationWarning directing users to use result['pdf_path'] instead. String behaviour will be removed in v1.0.0.

  • Updated tests/unit/test_transcribe.py to reflect _TranscribeResult return type: replaced string assertions with dict key checks, added tests for deprecation warning on string usage, added test for verbose dict including json_path and midi_path

  • Updated README.md Quick Start examples to use new dict-based transcribe() return with deprecation note

  • Updated docs/guide/usage.md section 6 with new transcribe() return type examples; filled in previously empty Extract Backing Track and Extract Drum-Only Audio sections

  • Added repository statistics link to docs/index.md homepage

  • Consolidated twine into the dev optional-dependency group in pyproject.toml; removed the now-redundant [dependency-groups] section

  • Excluded markdown from ruff via extend-exclude = ["*.md"] in pyproject.toml. ruff >=0.16 formats Python code blocks inside .md files by default, which reflows deliberate one-liner snippets (e.g. import platform; print(...)) and collapses readable multi-line examples. No-op on the currently locked ruff 0.15.22; prevents CI breaking on a future uv lock --upgrade

  • drumscript/main.py console entry point fixed: [project.scripts] repointed from drumscript.main:main to drumscript.main:cli. The generated console wrapper calls its target with no arguments, but main() requires input_audio_path, so drumscript ... raised TypeError on every invocation since the first PyPI release (v0.1.3). build_parser() and cli() extracted to module level; main() itself unchanged. (#176)

  • docs/guide/cli_reference.md audited: added the missing --rudiment flag, corrected the primary entry point from python drumscript/main.py to the drumscript console command, corrected the onset_detector standalone usage note, and expanded the worked examples from 3 to 6. (#107)

  • docs/guide/usage.md, docs/guide/glossary.md, docs/guide/configuration.md and docs/guide/installation.md audited and corrected: removed references to a non-existent StemSplitter class, ds.AudioLoader, ds.main / python -m ds.main, a threshold parameter on detect_onsets(), and underscore time-signature syntax; configuration.md rewritten to document the real configurable constants; uv sync --all-groups corrected to --all-extras. Superseded blocks commented out rather than deleted, per project convention. (#7)

  • updated transcribe.py and extract_stems.py notebooks/runbooks, as well as audited the Colab notebook https://colab.research.google.com/drive/15yBGu6WURPyiH-sEQ82g_2T2wKqiIPsq#scrollTo=qpnuXCSle5V0

Fixes

  • Adjusted documentation so that when version appears in documentation it is no longer hardcoded, but linked to import importlib.metadata in drumscript/__init__.py [Reduces maintenance burden on contributors]

  • Updated version in pyproject.toml from v0.1.5 to v0.1.6 (This should have been changed prior to pypi release of v0.1.6 on Thursday 18 June 2026)

  • Fixed create_backing_track runbook; replaced and tidied functions in drumscript_interactive_notebook on Colab

  • ds.transcribe() non-verbose return now exposes all output paths (PDF, JSON, MIDI) instead of only the PDF path. Previously, score_builder.build_score() silently wrote JSON and MIDI files but transcribe() only returned the PDF path - users had no way of knowing the other files existed

  • Investigated drumscript/main.py (~line 26) .wav comment: comment was misleading - referred to stem output format, not input format. Clarified to reflect actual behaviour

  • ds.transcribe() now reports only the output files that were actually written. score_builder.build_score() exports JSON, PDF and MIDI in three independent try/except blocks, so a failure in one does not stop the others - but it returned None, giving callers no way to tell which succeeded. transcribe() therefore advertised all three paths unconditionally, including files never written to disk. build_score() now returns a dict of the paths it successfully wrote, and transcribe() reports that; a non-dict return (older build_score, or a test double) falls back to the computed paths so existing callers are unaffected

  • release.yml version-bump sed anchored to leading whitespace. The previous pattern matched any line containing __version__ = "X.Y.Z", so it rewrote the commented-out historical line alongside the live fallback in drumscript/__init__.py, destroying the record of the previous version on every release. Also tightened [0-9]* to [0-9]\+ so it cannot match an empty version string

  • CLI stem flags (--drumless, --all-stems, --mute) now work on the happy path. separate_audio() was only ever called from inside the except handler in drumscript/main.py, so drumscript song.mp3 --drumless ran the transcription pipeline, succeeded, and exited without producing a backing track - silently, with no error. Stem handling moved into the primary try block: full separation for stem flags, the cheaper extract_drum_stem() for --full-song alone, and both combined when transcription follows separation. The Python API (ds.extract_stems()) was never affected

  • Removed the unreachable second except Exception clause in drumscript/main.py. The handler above it already caught Exception, so it could never run; the duplicated pipeline that lived inside the first handler also propagated exceptions uncaught, since a sibling except cannot catch them. Both blocks commented out rather than deleted, per project convention

  • build_score() now creates the output directory before exporting. midi_exporter and xml_exporter each created it themselves, but the JSON write and pdf_exporter did not - so running the CLI from any directory without an outputs/ folder (e.g. a pip-installed user working outside the repo root) silently produced a MIDI file and nothing else, with only warning prints and no failure exit code. Creating it centrally in build_score() fixes every caller, CLI and Python API alike. Caught by the new integration tests, which run in a clean temporary directory

  • amended ds.AudioLoader references in docs/guide/usage.md and fixed to reflect correct version ds.load_audio

  • git-lfs install instructions added to the README.md System Dependencies section - previously undocumented, which left first-time contributors with confusing Git LFS pointer files instead of the example audio. (#272)

  • Confirmed onset_detector.py standalone mode takes a user-supplied audio path (python -m drumscript.audio_processor.onset_detector <audio_file>) rather than hardcoded test paths, and documented it in cli_reference.md. (#102)

  • Removed accidental nbstripout from core runtime dependencies. uv add nbstripout landed it in the main dependencies array of pyproject.toml with a malformed [dev] extra marker (nbstripout[dev]>=0.8.2), which would have made every pip install drumscript pull a Git/notebook dev tool as a runtime dependency. Caught in pre-release wheel-metadata inspection; nbstripout retained correctly under [project.optional-dependencies].dev only.

  • Added nbstripout as a pre-commit hook (kynan/nbstripout rev 0.7.1) and dev dependency, to prevent Jupyter notebooks in docs/guide/interactive/ from committing embedded audio outputs. Fixes the docs.yml deploy failure caused by <input>.ipynb files ballooning to 100+ MB when display(Audio(...)) cells base64-inlined the audio into saved outputs, breaching GitHub’s push size limit.

  • Aligned ruff pre-commit hook rev with the locked ruff version (v0.15.11v0.15.22) in .pre-commit-config.yaml. Both were <0.16 so the markdown-format issue didn’t bite, but the drift meant local pre-commit and CI could format Python differently on the boundary of a ruff upgrade.

Tests

  • Did full audit of all drumscript code to ensure full-flag / full_flag consistency throughout, following v0.1.6 release fix replacing full=True with verbose=True (DeprecationShim)

  • Fixed Sphinx build errors for documentation

  • Amended structure of index in README.md and added missing H2 headers

  • Investigated main.py .wav comment and input/output format behaviour: confirmed load_audio() supports any format librosa can decode (wav, mp3, flac, ogg); ffmpeg only required for MP3 input decoding and MP3 stem output

  • Added 4 tests to tests/unit/test_transcribe.py (16 → 20) covering written-path reporting: failed export omits its path, all-success reports all three, None return falls back to computed paths, verbose dict reflects the same

  • Added tests/integration/test_transcribe_real.py (15 tests) with real end-to-end coverage, nothing mocked. Fast tier (12 tests, drum-only audio, no Demucs) verifies transcribe() writes PDF/JSON/MIDI to disk, the JSON parses, the _TranscribeResult deprecation shim and __fspath__ work, and build_score() reports only files that exist - marked integration but not slow, so it runs in CI under pytest -m "not slow". Slow tier (3 tests, requires Demucs) covers the CLI stem flags including --drumless producing a backing track without a score

Known follow-ups#

  • ds.extract_stems(drumless=True, verbose=True) creates a drumless backing track but does not return its path. The file is on disk (as <input>_no_drums.<ext> inside output_directory), but callers have to reconstruct the path. v0.2.0 ships a doc-only workaround; v0.2.1 will expose a backing_track_path key. (#266)


Contributors#

  • @victoria-mckinney

  • @drumscript-admin