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 thefull→verbosemigration begun in v0.1.6. Both string-return andfull=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.ymlGitHub Actions workflow (docs/versioned-deploybranch):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/foldersMain branch pushes deploy to
/dev/folder (bleeding-edge docs)Root
index.htmlauto-generated on tag push, redirects to/latest/keep_files: trueensures older version folders are never deletedExisting 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-statsbranch. Overcomes GitHub’s 14-day traffic data retention limit and tracks usageAdded
Trafficsection to README with links to daily-updated repository statistics report (PDF and HTML), generated byrepo-stats.ymlvia github-repo-statsAdded CHANGELOG reference to README table of contents (Sphinx docs already linked via symlink)
_TranscribeResultdeprecation shim class indrumscript/__init__.py: dict subclass with__str__and__fspath__methods that emitDeprecationWarningwhen the return value oftranscribe()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- batchgh issue closescript (with per-issue comments) for the GitHub issues resolved in v0.2.0Added timeout to jobs block in
tests.ymland add--no-install-recommendto linux system dependencies job to preventapt-getissues in workflow
Changes
Updated table ordering in
docs/index.mdto match right sidebar ordering and added missing sidebar navigation point for tempogram-detectionAmended 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) forUser Guidesubmenu to 1. remove duplicatedusagereference 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-alphatovX.Y.Z(e.g.v0.1.6). Old tags remain on remote (branch protection prevents deletion) but are ignored by thedocs.ymlworkflow which only triggers onv*.transcribe()non-verbose return type changed fromstrto_TranscribeResult(adictsubclass). The return value is a dict withpdf_path,json_path, andmidi_pathkeys. For backwards compatibility, using the result as a string still works (returns the PDF path) but emits aDeprecationWarningdirecting users to useresult['pdf_path']instead. String behaviour will be removed in v1.0.0.Updated
tests/unit/test_transcribe.pyto reflect_TranscribeResultreturn type: replaced string assertions with dict key checks, added tests for deprecation warning on string usage, added test for verbose dict includingjson_pathandmidi_pathUpdated
README.mdQuick Start examples to use new dict-basedtranscribe()return with deprecation noteUpdated
docs/guide/usage.mdsection 6 with newtranscribe()return type examples; filled in previously empty Extract Backing Track and Extract Drum-Only Audio sectionsAdded repository statistics link to
docs/index.mdhomepageConsolidated
twineinto thedevoptional-dependency group inpyproject.toml; removed the now-redundant[dependency-groups]sectionExcluded markdown from ruff via
extend-exclude = ["*.md"]inpyproject.toml. ruff >=0.16 formats Python code blocks inside.mdfiles 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 futureuv lock --upgradedrumscript/main.pyconsole entry point fixed:[project.scripts]repointed fromdrumscript.main:maintodrumscript.main:cli. The generated console wrapper calls its target with no arguments, butmain()requiresinput_audio_path, sodrumscript ...raisedTypeErroron every invocation since the first PyPI release (v0.1.3).build_parser()andcli()extracted to module level;main()itself unchanged. (#176)docs/guide/cli_reference.mdaudited: added the missing--rudimentflag, corrected the primary entry point frompython drumscript/main.pyto thedrumscriptconsole 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.mdanddocs/guide/installation.mdaudited and corrected: removed references to a non-existentStemSplitterclass,ds.AudioLoader,ds.main/python -m ds.main, athresholdparameter ondetect_onsets(), and underscore time-signature syntax;configuration.mdrewritten to document the real configurable constants;uv sync --all-groupscorrected to--all-extras. Superseded blocks commented out rather than deleted, per project convention. (#7)updated
transcribe.pyandextract_stems.pynotebooks/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.metadataindrumscript/__init__.py[Reduces maintenance burden on contributors]Updated version in pyproject.toml from
v0.1.5tov0.1.6(This should have been changed prior to pypi release of v0.1.6 on Thursday 18 June 2026)Fixed
create_backing_trackrunbook; replaced and tidied functions in drumscript_interactive_notebook on Colabds.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 buttranscribe()only returned the PDF path - users had no way of knowing the other files existedInvestigated
drumscript/main.py(~line 26).wavcomment: comment was misleading - referred to stem output format, not input format. Clarified to reflect actual behaviourds.transcribe()now reports only the output files that were actually written.score_builder.build_score()exports JSON, PDF and MIDI in three independenttry/exceptblocks, so a failure in one does not stop the others - but it returnedNone, 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, andtranscribe()reports that; a non-dict return (olderbuild_score, or a test double) falls back to the computed paths so existing callers are unaffectedrelease.ymlversion-bumpsedanchored 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 indrumscript/__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 stringCLI stem flags (
--drumless,--all-stems,--mute) now work on the happy path.separate_audio()was only ever called from inside theexcepthandler indrumscript/main.py, sodrumscript song.mp3 --drumlessran the transcription pipeline, succeeded, and exited without producing a backing track - silently, with no error. Stem handling moved into the primarytryblock: full separation for stem flags, the cheaperextract_drum_stem()for--full-songalone, and both combined when transcription follows separation. The Python API (ds.extract_stems()) was never affectedRemoved the unreachable second
except Exceptionclause indrumscript/main.py. The handler above it already caughtException, so it could never run; the duplicated pipeline that lived inside the first handler also propagated exceptions uncaught, since a siblingexceptcannot catch them. Both blocks commented out rather than deleted, per project conventionbuild_score()now creates the output directory before exporting.midi_exporterandxml_exportereach created it themselves, but the JSON write andpdf_exporterdid not - so running the CLI from any directory without anoutputs/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 inbuild_score()fixes every caller, CLI and Python API alike. Caught by the new integration tests, which run in a clean temporary directoryamended
ds.AudioLoaderreferences indocs/guide/usage.mdand fixed to reflect correct versionds.load_audiogit-lfsinstall instructions added to theREADME.mdSystem Dependencies section - previously undocumented, which left first-time contributors with confusing Git LFS pointer files instead of the example audio. (#272)Confirmed
onset_detector.pystandalone mode takes a user-supplied audio path (python -m drumscript.audio_processor.onset_detector <audio_file>) rather than hardcoded test paths, and documented it incli_reference.md. (#102)Removed accidental
nbstripoutfrom core runtime dependencies.uv add nbstripoutlanded it in the maindependenciesarray ofpyproject.tomlwith a malformed[dev]extra marker (nbstripout[dev]>=0.8.2), which would have made everypip install drumscriptpull a Git/notebook dev tool as a runtime dependency. Caught in pre-release wheel-metadata inspection; nbstripout retained correctly under[project.optional-dependencies].devonly.Added
nbstripoutas a pre-commit hook (kynan/nbstripoutrev0.7.1) and dev dependency, to prevent Jupyter notebooks indocs/guide/interactive/from committing embedded audio outputs. Fixes thedocs.ymldeploy failure caused by<input>.ipynbfiles ballooning to 100+ MB whendisplay(Audio(...))cells base64-inlined the audio into saved outputs, breaching GitHub’s push size limit.Aligned
ruffpre-commit hook rev with the locked ruff version (v0.15.11→v0.15.22) in.pre-commit-config.yaml. Both were<0.16so 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
drumscriptcode to ensurefull-flag/full_flagconsistency throughout, following v0.1.6 release fix replacingfull=Truewithverbose=True(DeprecationShim)Fixed Sphinx build errors for documentation
Amended structure of index in README.md and added missing H2 headers
Investigated
main.py.wavcomment and input/output format behaviour: confirmedload_audio()supports any format librosa can decode (wav, mp3, flac, ogg); ffmpeg only required for MP3 input decoding and MP3 stem outputAdded 4 tests to
tests/unit/test_transcribe.py(16 → 20) covering written-path reporting: failed export omits its path, all-success reports all three,Nonereturn falls back to computed paths, verbose dict reflects the sameAdded
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) verifiestranscribe()writes PDF/JSON/MIDI to disk, the JSON parses, the_TranscribeResultdeprecation shim and__fspath__work, andbuild_score()reports only files that exist - markedintegrationbut notslow, so it runs in CI underpytest -m "not slow". Slow tier (3 tests, requires Demucs) covers the CLI stem flags including--drumlessproducing 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>insideoutput_directory), but callers have to reconstruct the path. v0.2.0 ships a doc-only workaround; v0.2.1 will expose abacking_track_pathkey. (#266)
Contributors#
@victoria-mckinney
@drumscript-admin