Changelog#
All notable changes related to the repository and pypi distribution of
DrumScriptwill be documented hereFormat follows Keep a Changelog and Semantic Versioning.
Keep a Changelog standard defines this order for naming items in a
Changelog:
Added - new features
Changed - changes to existing functionality
Deprecated - soon-to-be removed features
Removed - removed features
Fixed - bug fixes
Security - vulnerability fixes
Unreleased
forthcoming/in progress
Items listed below are currently in development but have not been distributed on PyPi
Additions
added blurb to
README.md,docs/index.mdanddocs/about.mdabout build process and current development peopleadded issue forms for
bug_report,feature_requestandsubmit_resultsto make giving feedback easieradded troubleshooting page to documentation, with navigation tab for known dependency issues/errors impacting DrumScript
Changes
tidied up branch tree on remote #311
Fixes
Python 3.13 not supported. DrumScript pins
numpy<2, and numpy 1.x has no cp313 wheels on PyPI. This causedpip install drumscripton Python 3.13 to fall back to a source build (which requires a C toolchain most users don’t have), producing a confusingCompiler cc cannot compile programserror rather than a clear “unsupported Python version” message.requires-pythonlowered from<3.14to<3.13inpyproject.toml. Python 3.13 support planned once DrumScript migrates tonumpy>=2(see #303).
Known debt being paid down alongside the alpha’s fundamental work (model + score generation). These are treated as bugs to fix, not future features - but they are not allowed to displace the core classification/score-generation work:
numpy 2.x migration - move from the current
numpy<2pin tonumpy>=2. This is the blocker for Python 3.13 support: the two are a single linked task (migrate to numpy 2 -> unblocks 3.13 -> add 3.13, and test 3.14, to the CI matrix). Requires cross-checking numba, librosa, and scipy at numpy 2, and fixing any numpy 1.x-only API usage in the codebase (see #303).pydub
SyntaxWarningsurfacing in the CLI - pydub has an upstreamSyntaxWarningon Python 3.12 that currently leaks to users when running the CLI. To be suppressed viawarnings.filterwarningstargetingpydub.utils.
Future releases#
Items listed below are fully implemented and published to pypi under an official version
[1.0.0] - Beta release - Target: late-2026#
Additions#
output_midi,output_json,output_xmlflags to be added totranscribe()for multi-format exportExpanded benchmark dataset coverage (ENST-Drums, MDB-Drums) building on the IDMT-SMT-Drums V2 foundation shipped in v0.1.6
Code-to-DrumScript label mapping expanded beyond
KD/SD/HHto cover full-kit classes (toms, crash, ride)Repository statistics badge (shields.io endpoint) for README and docs homepage: extend
repo-stats.ymlto write a small JSON (schemaVersion,label,message,color) to thegithub-repo-statsbranch on each daily run, so shields.io can render live view/clone counts rather than a static link #296Check compatibility for Python 3.13 (#299)
Changes#
Transcription function docstrings to be updated to make clear that drum-only audio is expected as standard input
README to be updated to clarify expected input for transcription functions
Example notebooks to be updated to reflect expected drum-only audio input
Better audio samples needed for runbooks - not synthetic, which has created messy outputs
Runbook presentation to be tidied: one variable per line, properly tested
Improve documentation: clearer docstrings for the
rudimentflag/functionalityCheck if
is_rudimentapplies toscore_builderfunction - is it relevant, perdrumscript/main.py?Refactor
main.pyargparse block into abuild_parser()function sotests/unit/test_cli_args.pycan import the real parser instead of mirroring itClarify in docs/docstrings that input format is not limited to .wav/.mp3 - any format librosa (+ ffmpeg) supports works. ffmpeg is only required for MP3 input decoding and MP3 stem output
(breaking)
fullparameter removed entirely fromtranscribe(),extract_stems(), anddetect_tempo(). Users must useverboseinstead.This was implemented as a deprecation shim in v0.1.6 release
Deprecation warning for
--full= flagwill be removedtests/unit/test_deprecation_warnings.pydeleted (or flipped to assertfullnow raisesTypeError)From 1.0.0 (beta) the flag
verbose=will provide dictionary-based outputs, ie for cli-users and developers.This change, originally, was made in v0.1.6 release to prevent confusion between
--fullflag outputting verbose in drumscript wrappers and thefull=truefunctionality for specifying withintranscribe()function that the input audio is polyphonic (non-drum-only) and therefore requires Demucs extraction prior to applying DrumScript’s deterministic classification model for transcription.As a side note, and for completeness, DrumScript functions default to drum-audio only inputs. User must indicate if the input_audio is not solo drum audio.
_TranscribeResultstring compatibility removed -transcribe()returns a plaindictdocs/guide/usage.md: the silent 4/4 fallback inpdf_exporter.pyline 138 is a code smell independent of the docs - a user typo like--ts 44also silently becomes 4/4. Aprintwarning in thatexcept ValueErrorwould be a small improvement on documentation #297
Fixes#
Cymbal and hi-hat stem rendering: note tails and heads correctly aligned
main.pystructural bug: duplicated pipeline insideexceptblock needs removing, error handling needs restructuringds.transcribe()return value only references PDF path, butscore_builder.build_score()silently writes JSON + MIDI too. Output behaviour needs documenting clearly and aligning between CLI and Python APIds.extract_stems(verbose=True)does not return the backing-track path (#266). It callsseparate_audio(), whose dict includes the backing-track path undermix, but then discards that dict and builds its own (status,drum_stem_path,original_file,output_directory) - dropping the one path the user asked for when calling withdrumless=True. The backing track is created on disk but its location is never reported, so the caller has to reconstruct it fromoutput_directoryplus the<input>_no_drums.<ext>naming convention. Fix: carry the path through fromseparate_audio()under a readable key,backing_track_path(rather than reintroducing the tersemix), and update the README backing-track example to use it. Keeps the readable key names introduced in v0.2.0 while restoring the missing path (#298)
Tests#
Onset timing precision: investigate user feedback on score generation. Though quantisation is used, look at the extent to which slight imperfections in onset detection cause notes to be placed at incorrect positions in the score (e.g. snare hit at 0.503s instead of 0.500s generates spurious rests). https://github.com/DrumScript/DrumScript/issues/274
Released
[0.2.0] - August 2026#
First minor-version bump
Signals the start of the breaking-change track for –full flag (replaced by –verbose) ahead of v1.0.0 beta.–>
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)
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
[0.1.6] - June 2026#
v0.1.6is the final v0.1.x release. After this, the next release jumps to v0.2.0 to signal the deprecation shim for thefull→verboseremoval.
Additions#
Deprecation shim for
fullparameter on the Python API:New
verboseparameter added totranscribe(),extract_stems(), anddetect_tempo()as the canonical replacement forfullPassing
full=True(orfull=False) continues to work but emits aDeprecationWarningdirecting users toverboseWarning explicitly names the v1.0.0 (beta) removal target so users have a clear migration timeline
Passing both
fullandverbosetogether raisesTypeError(ambiguous, almost certainly a bug)Internal helper
_resolve_verbose_flag()centralises the resolution logic so it cannot drift between wrappersDocstrings updated to mark
verboseas primary andfullas deprecated
PR #273 by @nanaoto - IDMT-SMT-Drums V2 benchmark runner with
mir_evalscaffolding:benchmarks/run.pyentrypoint with dataset adapter dispatch, evaluation loop, CSV/JSON archive with git commit trackingdrumscript/datasets/package:BenchmarkItemdataclass and IDMT adapter (XML/SVL annotation parsing)benchmarks/README.mddocumenting conventions, dataset setup, and planned dataset coverageUnit tests for benchmark runner (
test_benchmarks_run.py) and IDMT dataset adapter (test_idmt_dataset.py)mir_evaladded as a dev dependency
New unit test file
tests/unit/test_deprecation_warnings.py(13 tests)New unit test file
tests/unit/test_cli_args.py(4 tests)
Fixes#
Commented-out dead code removed from
drumscript/__init__.pyanddrumscript/main.pyFlag inconsistency between
drumscript/main.pyanddrumscript/__init__.pyresolved:argparsein main block updated so the CLI flag is now--full-song(hyphenated, consistent with--all-stems). Auto-converts toargs.full_songmatching the Python API parameter name.
[0.1.5] - 25 May 2026#
Fixes#
Emergency fix: transcription outputs
Updated docstrings to clarify expected input for transcription functions
[0.1.4] - 20 May 2026#
First PyPI publication
First release
Initial public alpha release to PyPI#
End-to-end CLI pipeline: stem separation → onset detection → classification → score generation
Drum classification (kick, snare, hi-hat open/closed, toms, crash, ride) using deterministic spectral analysis
PDF score generation with custom notation rendering
MIDI and JSON export
XML export support
Drumless and bassless backing track generation
Stem separation (drums, bass, vocals, other) via Demucs htdemucs 4-stem model
Tempo detection from onset pattern
Custom time signature support (e.g. 3/4, 6/8)
ffmpeg-free WAV output path (soundfile + numpy)
Google Colab notebook support