Skip to content

Speed up Smart Fades beat tracking with a numba-accelerated decoder#4204

Draft
marcelveldt wants to merge 1 commit into
devfrom
speedup-smart-fades-dbn
Draft

Speed up Smart Fades beat tracking with a numba-accelerated decoder#4204
marcelveldt wants to merge 1 commit into
devfrom
speedup-smart-fades-dbn

Conversation

@marcelveldt

Copy link
Copy Markdown
Member

What does this implement/fix?

The Smart Fades beat/downbeat tracker ran its DBN (HMM/Viterbi) post-processing as a pure-Python per-frame loop, which pegged a CPU core for the full duration of every track's analysis and contributed to sluggishness while streaming. This adds a compiled (numba) decoder that produces bit-identical beats/downbeats while running ~4-5x faster, reducing the per-track CPU spike.

  • Add a numba-jitted Viterbi decoder (nogil, compiled once at provider init) used by default, with the existing numpy decoder kept as an automatic fallback and readable reference implementation.
  • Precompute the per-meter decode plan (state classification, predecessor tables) once at init instead of rebuilding it for every track.
  • Declare numba in the Smart Fades manifest (already present transitively via the core librosa dependency).
  • Add tests asserting the numba and numpy decode paths are bit-identical to each other and to a naive reference Viterbi.

Related issue (if applicable):

  • N/A

Types of changes

  • Bugfix (non-breaking change which fixes an issue) — bugfix
  • New feature (non-breaking change which adds functionality) — new-feature
  • Enhancement to an existing feature — enhancement
  • New music/player/metadata/plugin provider — new-provider
  • Breaking change (fix or feature that would cause existing functionality to not work as expected) — breaking-change
  • Refactor (no behaviour change) — refactor
  • Documentation only — documentation
  • Maintenance / chore — maintenance
  • CI / workflow change — ci
  • Dependencies bump — dependencies

Checklist

  • The code change is tested and works locally.
  • pre-commit run --all-files passes.
  • pytest passes, and tests have been added/updated under tests/ where applicable.
  • For changes to shared models, the companion PR in music-assistant/models is linked.
  • For changes affecting the UI, the companion PR in music-assistant/frontend is linked.
  • I have read and complied with the project's AI Policy for any AI-assisted contributions.
  • I have raised a PR against the documentation repository targeting the main or beta branch as appropriate.

The DBN Viterbi post-processing ran as a pure-Python per-frame loop that
pegged a CPU core for the full duration of each track's beat analysis. Add a
numba-jitted decoder that produces bit-identical beats/downbeats but runs
~4-5x faster, keeping the numpy decoder as an automatic fallback.
Copilot AI review requested due to automatic review settings June 13, 2026 13:28
@github-actions

Copy link
Copy Markdown
Contributor

🔒 Dependency Security Report

📦 Modified Dependencies

music_assistant/providers/smart_fades/manifest.json

Added:

Unchanged dependencies

The following dependencies were added or modified:

diff --git a/requirements_all.txt b/requirements_all.txt
index 17ac2851..be7f45fd 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -53,6 +53,7 @@ music-assistant-models==1.1.129
 mutagen==1.47.0
 niconico.py-ma==2.1.0.post2
 nnAudio==0.3.3
+numba>=0.51
 numpy==2.3.5
 orjson==3.11.6
 pillow==12.2.0

New/modified packages to review:

  • numba>=0.51

🔍 Vulnerability Scan Results

No known vulnerabilities found

Name Skip Reason
torch Dependency not found on PyPI and could not be audited: torch (2.11.0+cpu)
torchaudio Dependency not found on PyPI and could not be audited: torchaudio (2.11.0+cpu)
✅ No known vulnerabilities found

Automated Security Checks

  • Vulnerability Scan: Passed - No known vulnerabilities
  • Trusted Sources: All packages have verified source repositories
  • Typosquatting Check: No suspicious package names detected
  • License Compatibility: All licenses are OSI-approved and compatible
  • Supply Chain Risk: Passed - packages appear mature and maintained

Manual Review

Maintainer approval required:

  • I have reviewed the changes above and approve these dependency updates

To approve: Comment /approve-dependencies or manually add the dependencies-reviewed label.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR accelerates Smart Fades’ DBN/HMM (Viterbi) beat/downbeat post-processing by adding an optional numba-jitted decoder and by precomputing decode-plans per meter at tracker initialization, aiming to reduce per-track CPU spikes during analysis.

Changes:

  • Add a numba-accelerated Viterbi decoder with a numpy fallback path.
  • Precompute per-meter decode plan (state classification / predecessor tables) once at init instead of per-track.
  • Add tests to assert bit-identical outputs across numba vs numpy vs a naive reference implementation, and add numba to dependencies.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
music_assistant/providers/smart_fades/dbn_postprocessor.py Adds numba-jitted decoder, decode-plan precompute, and switches runtime decode to a numba-first path with numpy fallback.
music_assistant/providers/smart_fades/manifest.json Declares numba as a Smart Fades provider requirement.
requirements_all.txt Adds numba to the aggregated dependency list used in CI installs.
tests/providers/smart_fades/test_dbn_postprocessor.py Adds correctness tests ensuring numba/numpy/naive Viterbi decoders are consistent and output-identical.

Comment on lines +251 to +253
"""The numba-jitted decode must return bit-identical beats to the numpy fallback."""
combined = _synth_activations(seed, num_frames, bpm, meter)
tracker = DBNDownBeatTracker(beats_per_bar=[3, 4], min_bpm=55, max_bpm=215, fps=50)
@MarvinSchenkel

Copy link
Copy Markdown
Contributor

Just be aware that the gains are not substantial. Postprocessing takes around 5% of the the total inference time, so we are optimizing on a small portion already. For example, total inference time on my prod setup takes like 30s with 2s being the post processing time.

@marcelveldt marcelveldt marked this pull request as draft June 13, 2026 14:11
@marcelveldt

Copy link
Copy Markdown
Member Author

Let this one for you to decide @MarvinSchenkel - in general a C-backed library is always better than pure python so maybe good to do some comparison - no rush.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants