danceflow-stemlab 1.2.0__tar.gz → 1.3.1__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.
Files changed (169) hide show
  1. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/MANIFEST.in +8 -0
  2. {danceflow_stemlab-1.2.0/src/danceflow_stemlab.egg-info → danceflow_stemlab-1.3.1}/PKG-INFO +193 -5
  3. danceflow_stemlab-1.2.0/PKG-INFO → danceflow_stemlab-1.3.1/README.md +152 -89
  4. danceflow_stemlab-1.3.1/docs/branding/README.md +11 -0
  5. danceflow_stemlab-1.3.1/docs/branding/logo-monochrome.svg +6 -0
  6. danceflow_stemlab-1.3.1/docs/branding/logo.png +0 -0
  7. danceflow_stemlab-1.3.1/docs/branding/logo.svg +6 -0
  8. danceflow_stemlab-1.3.1/docs/cue-alignment.md +201 -0
  9. danceflow_stemlab-1.3.1/docs/evidence-models.md +109 -0
  10. danceflow_stemlab-1.3.1/docs/midi.md +353 -0
  11. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/mcp-registry/server.json +4 -4
  12. danceflow_stemlab-1.3.1/plugins/stemlab/.codex-plugin/plugin.json +24 -0
  13. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/plugins/stemlab/README.md +4 -0
  14. danceflow_stemlab-1.3.1/plugins/stemlab/branding/logo-monochrome.svg +6 -0
  15. danceflow_stemlab-1.3.1/plugins/stemlab/branding/logo.png +0 -0
  16. danceflow_stemlab-1.3.1/plugins/stemlab/branding/logo.svg +6 -0
  17. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/plugins/stemlab/plugin.json +4 -4
  18. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/plugins/stemlab/skills/stemlab/SKILL.md +29 -0
  19. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/plugins/stemlab/skills/stemlab/references/tools.md +3 -1
  20. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/pyproject.toml +30 -5
  21. danceflow_stemlab-1.3.1/scripts/benchmark_evidence_corpus.py +46 -0
  22. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/scripts/build_codex_plugin.py +2 -1
  23. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/scripts/prepare_codex_marketplace.py +2 -1
  24. danceflow_stemlab-1.3.1/scripts/smoke_midi.py +44 -0
  25. danceflow_stemlab-1.2.0/README.md → danceflow_stemlab-1.3.1/src/danceflow_stemlab.egg-info/PKG-INFO +277 -3
  26. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/danceflow_stemlab.egg-info/SOURCES.txt +43 -1
  27. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/danceflow_stemlab.egg-info/requires.txt +51 -0
  28. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/__init__.py +1 -1
  29. danceflow_stemlab-1.3.1/src/stemlab/analysis/evidence/__init__.py +4 -0
  30. danceflow_stemlab-1.3.1/src/stemlab/analysis/evidence/adapters.py +230 -0
  31. danceflow_stemlab-1.3.1/src/stemlab/analysis/evidence/registry.py +146 -0
  32. danceflow_stemlab-1.3.1/src/stemlab/analysis/evidence/runner.py +216 -0
  33. danceflow_stemlab-1.3.1/src/stemlab/analysis/evidence/worker.py +35 -0
  34. danceflow_stemlab-1.3.1/src/stemlab/analysis/midi/__init__.py +8 -0
  35. danceflow_stemlab-1.3.1/src/stemlab/analysis/midi/adapters.py +254 -0
  36. danceflow_stemlab-1.3.1/src/stemlab/analysis/midi/artifacts.py +109 -0
  37. danceflow_stemlab-1.3.1/src/stemlab/analysis/midi/registry.py +119 -0
  38. danceflow_stemlab-1.3.1/src/stemlab/analysis/midi/runner.py +238 -0
  39. danceflow_stemlab-1.3.1/src/stemlab/analysis/midi/worker.py +39 -0
  40. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/registry.py +25 -0
  41. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/runner.py +63 -1
  42. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/beats/beatnet.py +16 -3
  43. danceflow_stemlab-1.3.1/src/stemlab/beats/beatthis.py +41 -0
  44. danceflow_stemlab-1.3.1/src/stemlab/bootstrap.py +249 -0
  45. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/branding.py +4 -3
  46. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/canonical.py +5 -12
  47. danceflow_stemlab-1.3.1/src/stemlab/cli.py +452 -0
  48. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/codex/bridge.py +55 -1
  49. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/codex/jobs.py +1 -1
  50. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/codex/server.py +40 -0
  51. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/codex/tasks.py +125 -0
  52. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/codex/worker.py +5 -1
  53. danceflow_stemlab-1.3.1/src/stemlab/cue_cli.py +86 -0
  54. danceflow_stemlab-1.3.1/src/stemlab/cues.py +645 -0
  55. danceflow_stemlab-1.3.1/src/stemlab/lyric_lrc.py +105 -0
  56. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/pipeline.py +79 -2
  57. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/separators/bsroformer.py +27 -0
  58. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/spectrogram.py +57 -27
  59. danceflow_stemlab-1.3.1/src/stemlab/spectrogram_repair.py +86 -0
  60. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/types.py +24 -0
  61. danceflow_stemlab-1.3.1/src/stemlab/word_alignment.py +114 -0
  62. danceflow_stemlab-1.3.1/tests/test_beat_this_bootstrap.py +62 -0
  63. danceflow_stemlab-1.3.1/tests/test_beatnet_bootstrap.py +66 -0
  64. danceflow_stemlab-1.3.1/tests/test_bsroformer_adapter.py +30 -0
  65. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_codex_package.py +3 -0
  66. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_codex_protocol.py +1 -0
  67. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_codex_release.py +1 -1
  68. danceflow_stemlab-1.3.1/tests/test_cue_integration.py +200 -0
  69. danceflow_stemlab-1.3.1/tests/test_cues.py +370 -0
  70. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_distribution_identity.py +7 -1
  71. danceflow_stemlab-1.3.1/tests/test_docker_contract.py +78 -0
  72. danceflow_stemlab-1.3.1/tests/test_evidence_models.py +126 -0
  73. danceflow_stemlab-1.3.1/tests/test_lyric_lrc.py +75 -0
  74. danceflow_stemlab-1.3.1/tests/test_midi_adapters.py +245 -0
  75. danceflow_stemlab-1.3.1/tests/test_midi_extraction.py +207 -0
  76. danceflow_stemlab-1.3.1/tests/test_midi_integration.py +151 -0
  77. danceflow_stemlab-1.3.1/tests/test_midi_registry.py +52 -0
  78. danceflow_stemlab-1.3.1/tests/test_spectrogram.py +55 -0
  79. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_web_frontend.py +5 -4
  80. danceflow_stemlab-1.3.1/tests/test_word_alignment.py +27 -0
  81. danceflow_stemlab-1.2.0/plugins/stemlab/.codex-plugin/plugin.json +0 -24
  82. danceflow_stemlab-1.2.0/src/stemlab/beats/beatthis.py +0 -25
  83. danceflow_stemlab-1.2.0/src/stemlab/bootstrap.py +0 -133
  84. danceflow_stemlab-1.2.0/src/stemlab/cli.py +0 -230
  85. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/.agents/plugins/marketplace.json +0 -0
  86. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/.github/workflows/codex-plugin.yml +0 -0
  87. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/.github/workflows/release.yml +0 -0
  88. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/LICENSE +0 -0
  89. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/docs/codex-plugin.md +0 -0
  90. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/docs/codex-publishing.md +0 -0
  91. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/plugins/stemlab/.mcp.json +0 -0
  92. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/plugins/stemlab/mcp.json +0 -0
  93. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/scripts/capture_loop_workflow.py +0 -0
  94. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/scripts/check_codex_timeline.py +0 -0
  95. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/scripts/loop_demo.py +0 -0
  96. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/scripts/publish_mcp_registry.py +0 -0
  97. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/setup.cfg +0 -0
  98. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/danceflow_stemlab.egg-info/dependency_links.txt +0 -0
  99. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/danceflow_stemlab.egg-info/entry_points.txt +0 -0
  100. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/danceflow_stemlab.egg-info/top_level.txt +0 -0
  101. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/__main__.py +0 -0
  102. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/__init__.py +0 -0
  103. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/harmony.py +0 -0
  104. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/loops.py +0 -0
  105. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/lyrics.py +0 -0
  106. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/rhythm.py +0 -0
  107. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/semantic_audio.py +0 -0
  108. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/semantic_text.py +0 -0
  109. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/song_map.py +0 -0
  110. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/sonic.py +0 -0
  111. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/structure.py +0 -0
  112. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/tempo_regimes.py +0 -0
  113. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/analysis/transcription.py +0 -0
  114. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/audio.py +0 -0
  115. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/beats/__init__.py +0 -0
  116. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/beats/base.py +0 -0
  117. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/beats/beattransformer.py +0 -0
  118. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/beats/common.py +0 -0
  119. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/codex/__init__.py +0 -0
  120. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/codex/__main__.py +0 -0
  121. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/codex/paths.py +0 -0
  122. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/codex/timeline.py +0 -0
  123. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/manifest.py +0 -0
  124. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/models.py +0 -0
  125. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/separators/__init__.py +0 -0
  126. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/separators/base.py +0 -0
  127. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/separators/common.py +0 -0
  128. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/separators/demucs.py +0 -0
  129. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/separators/openunmix.py +0 -0
  130. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/separators/scnet.py +0 -0
  131. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/server.py +0 -0
  132. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/sonic_visualiser.py +0 -0
  133. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/speech.py +0 -0
  134. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/util.py +0 -0
  135. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/vamp.py +0 -0
  136. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/vamp_runtime.py +0 -0
  137. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/web/app.js +0 -0
  138. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/web/arcadians-cover.jpg +0 -0
  139. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/web/arcadians-reference.json +0 -0
  140. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/web/index.html +0 -0
  141. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/web/style.css +0 -0
  142. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/web/timeline.css +0 -0
  143. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/src/stemlab/webui.py +0 -0
  144. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_analysis_registry.py +0 -0
  145. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_arcadians_fixture.py +0 -0
  146. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_audio_normalization.py +0 -0
  147. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_beat_consensus.py +0 -0
  148. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_beatnet_compat.py +0 -0
  149. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_branding.py +0 -0
  150. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_canonical.py +0 -0
  151. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_canonical_extended.py +0 -0
  152. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_codex_bridge.py +0 -0
  153. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_codex_jobs.py +0 -0
  154. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_codex_timeline.py +0 -0
  155. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_deep_harmony.py +0 -0
  156. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_deep_lyrics.py +0 -0
  157. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_deep_sonic_rhythm.py +0 -0
  158. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_loop_integration.py +0 -0
  159. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_loops.py +0 -0
  160. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_manifest.py +0 -0
  161. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_models.py +0 -0
  162. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_repository_hygiene.py +0 -0
  163. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_server.py +0 -0
  164. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_song_map.py +0 -0
  165. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_sonic_visualiser.py +0 -0
  166. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_sonic_visualiser_workspace.py +0 -0
  167. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_speech_repetition.py +0 -0
  168. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_vamp.py +0 -0
  169. {danceflow_stemlab-1.2.0 → danceflow_stemlab-1.3.1}/tests/test_vamp_runtime.py +0 -0
@@ -1,5 +1,6 @@
1
1
  include .agents/plugins/marketplace.json
2
2
  recursive-include plugins/stemlab *.json *.md
3
+ recursive-include plugins/stemlab/branding *.svg *.png
3
4
  include plugins/stemlab/.mcp.json
4
5
  include plugins/stemlab/.codex-plugin/plugin.json
5
6
  include scripts/build_codex_plugin.py
@@ -13,3 +14,10 @@ include .github/workflows/release.yml
13
14
  include scripts/check_codex_timeline.py
14
15
  include scripts/loop_demo.py
15
16
  include scripts/capture_loop_workflow.py
17
+ include docs/midi.md
18
+ include scripts/smoke_midi.py
19
+ include docs/cue-alignment.md
20
+ include docs/evidence-models.md
21
+ include scripts/benchmark_evidence_corpus.py
22
+
23
+ recursive-include docs/branding *.svg *.png *.md
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: danceflow-stemlab
3
- Version: 1.2.0
4
- Summary: StemLab audio timing analysis and loopable sections for creating Shorts videos; DanceFlow and WordPress DanceMoves
3
+ Version: 1.3.1
4
+ Summary: Local music analysis for stems, timing, beats, harmony, lyrics, MIDI and loopable sections for Shorts. https://kieransimkin.co.uk/
5
5
  Author: Kieran Simkin
6
6
  Maintainer: Kieran Simkin
7
7
  License-Expression: MIT
8
+ Project-URL: DanceFlow ecosystem, https://kieransimkin.co.uk/danceflow/
8
9
  Project-URL: Homepage, https://kieransimkin.co.uk/
9
10
  Project-URL: My Songs portfolio, https://kieransimkin.co.uk/my-songs/
10
11
  Project-URL: Arcadians showcase, https://kieransimkin.co.uk/arcadians/
@@ -49,6 +50,8 @@ Provides-Extra: speech
49
50
  Requires-Dist: faster-whisper; extra == "speech"
50
51
  Provides-Extra: beats
51
52
  Requires-Dist: beat-this>=1.1.0; extra == "beats"
53
+ Requires-Dist: madmom-prebuilt==0.17.post1; python_version >= "3.11" and extra == "beats"
54
+ Requires-Dist: mido>=1.2.6; extra == "beats"
52
55
  Provides-Extra: deep
53
56
  Requires-Dist: sentence-transformers<7,>=6.1; extra == "deep"
54
57
  Requires-Dist: all-in-one-infer>=3.1; extra == "deep"
@@ -56,6 +59,40 @@ Provides-Extra: semantic-nc
56
59
  Requires-Dist: muq; extra == "semantic-nc"
57
60
  Provides-Extra: amt
58
61
  Requires-Dist: basic-pitch<0.5,>=0.4; python_version < "3.12" and extra == "amt"
62
+ Provides-Extra: midi
63
+ Requires-Dist: pretty-midi<0.3,>=0.2.10; extra == "midi"
64
+ Requires-Dist: mido<2,>=1.3; extra == "midi"
65
+ Requires-Dist: psutil>=5.9; extra == "midi"
66
+ Provides-Extra: midi-piano
67
+ Requires-Dist: pretty-midi<0.3,>=0.2.10; extra == "midi-piano"
68
+ Requires-Dist: mido<2,>=1.3; extra == "midi-piano"
69
+ Requires-Dist: psutil>=5.9; extra == "midi-piano"
70
+ Requires-Dist: piano-transcription-inference==0.0.6; extra == "midi-piano"
71
+ Provides-Extra: midi-transkun
72
+ Requires-Dist: pretty-midi<0.3,>=0.2.10; extra == "midi-transkun"
73
+ Requires-Dist: mido<2,>=1.3; extra == "midi-transkun"
74
+ Requires-Dist: psutil>=5.9; extra == "midi-transkun"
75
+ Requires-Dist: transkun==2.0.1; extra == "midi-transkun"
76
+ Requires-Dist: setuptools<81; extra == "midi-transkun"
77
+ Provides-Extra: midi-mt3
78
+ Requires-Dist: pretty-midi<0.3,>=0.2.10; extra == "midi-mt3"
79
+ Requires-Dist: mido<2,>=1.3; extra == "midi-mt3"
80
+ Requires-Dist: psutil>=5.9; extra == "midi-mt3"
81
+ Requires-Dist: mt3-infer[torch]==0.2.0; extra == "midi-mt3"
82
+ Provides-Extra: evidence
83
+ Requires-Dist: psutil>=5.9; extra == "evidence"
84
+ Provides-Extra: evidence-vocals
85
+ Requires-Dist: psutil>=5.9; extra == "evidence-vocals"
86
+ Requires-Dist: fireredvad<0.1,>=0.0.2; extra == "evidence-vocals"
87
+ Provides-Extra: evidence-pitch
88
+ Requires-Dist: psutil>=5.9; extra == "evidence-pitch"
89
+ Requires-Dist: swift-f0[audio]<0.4,>=0.3; extra == "evidence-pitch"
90
+ Provides-Extra: evidence-align
91
+ Requires-Dist: psutil>=5.9; extra == "evidence-align"
92
+ Requires-Dist: qwen-asr; extra == "evidence-align"
93
+ Provides-Extra: evidence-chords
94
+ Requires-Dist: psutil>=5.9; extra == "evidence-chords"
95
+ Requires-Dist: lv-chordia; extra == "evidence-chords"
59
96
  Provides-Extra: server
60
97
  Requires-Dist: fastapi<1,>=0.115; extra == "server"
61
98
  Requires-Dist: uvicorn[standard]<1,>=0.34; extra == "server"
@@ -77,6 +114,8 @@ Requires-Dist: openunmix>=1.3.0; extra == "all"
77
114
  Requires-Dist: bs-roformer-infer>=0.1.5; extra == "all"
78
115
  Requires-Dist: faster-whisper; extra == "all"
79
116
  Requires-Dist: beat-this>=1.1.0; extra == "all"
117
+ Requires-Dist: madmom-prebuilt==0.17.post1; python_version >= "3.11" and extra == "all"
118
+ Requires-Dist: mido>=1.2.6; extra == "all"
80
119
  Requires-Dist: sentence-transformers<7,>=6.1; extra == "all"
81
120
  Requires-Dist: all-in-one-infer>=3.1; extra == "all"
82
121
  Requires-Dist: fastapi<1,>=0.115; extra == "all"
@@ -86,13 +125,24 @@ Dynamic: license-file
86
125
 
87
126
  # StemLab
88
127
 
128
+ [![StemLab logo](https://raw.githubusercontent.com/kieransimkin/stemlab/v1.3.1/docs/branding/logo.png)](https://kieransimkin.co.uk/danceflow/)
129
+
130
+ By **[Kieran Simkin](https://kieransimkin.co.uk/)** · [DanceFlow ecosystem](https://kieransimkin.co.uk/danceflow/) · [Vector logo and usage guide](docs/branding/README.md).
131
+
132
+ Local music analysis for stems, timing, beats, harmony, lyrics, MIDI and loopable sections for Shorts. https://kieransimkin.co.uk/
133
+
134
+
89
135
  <!-- mcp-name: io.github.kieransimkin/stemlab -->
90
136
 
91
137
  > **StemLab by [Kieran Simkin](https://kieransimkin.co.uk/)** · [My Songs portfolio](https://kieransimkin.co.uk/my-songs/) · [Arcadians EPK](https://kieransimkin.co.uk/arcadians/) · [Source](https://github.com/kieransimkin/stemlab)
92
138
 
93
139
  > **Packaging identity:** the canonical project name is **StemLab**. StemLab is part of the **Dance Flow** project. The PyPI distribution is named `danceflow-stemlab` solely because Python package-registry names are globally unique. The Python import, CLI, GitHub repository and container image remain `stemlab`.
94
140
 
95
- StemLab provides **audio timing analysis and finds loopable sections for creating Shorts and other short-form videos**. It is the audio-analysis engine in Kieran Simkin's **DanceFlow** BPM and motion-response workflow. It separates and interprets a master track into synchronised stem, BPM/beat, structure, harmony, timbre, speech/lyric and semantic data. Those outputs can drive downstream motion-aware experiences, including the WordPress **DanceMoves** plugin, while StemLab remains usable as a standalone CLI, Python library, web service and container.
141
+ ## Synopsis
142
+
143
+ **StemLab is a local, evidence-led music analysis toolkit that turns a master recording into inspectable stems, timing, structure, harmony, lyric and sonic evidence, then finds complete-bar loopable sections for Shorts and other short-form videos.**
144
+
145
+ It combines independent separation and music-information-retrieval routes rather than treating any single model as the answer. Results remain traceable through source hashes, manifests, JSON/TSV/NPZ artefacts, portable Sonic Visualiser sessions and a shared React timeline for playback and comparison. StemLab can run as a CLI, Python library, web service, container or local Codex MCP plugin. It is the music-understanding layer of Kieran Simkin's **DanceFlow** workflow and can supply downstream motion systems such as the WordPress **DanceMoves** plugin, while remaining useful on its own.
96
146
 
97
147
  > **Model weights are not redistributed by this project.** They are fetched from their upstream registries/releases on first use. This avoids silently republishing checkpoints whose licensing may differ from the source code license, and lets upstream integrity metadata be used where available.
98
148
 
@@ -134,13 +184,19 @@ Relevant upstreams:
134
184
 
135
185
  For every successful separator, **every WAV it emits** is retained. Stem names are discovered from files rather than truncated to a hard-coded four-stem schema, which is important for MVSep Mega 53. For the master and every stem, StemLab writes both a PNG spectrogram and compressed `.npz` spectrogram data (time axis, frequency axis, dB matrix, FFT metadata).
136
186
 
187
+ Full-resolution spectrogram evidence stays in the `.npz`; the PNG renderer is bounded to 8,192 time frames so long tracks cannot expand into multi-gigabyte Matplotlib RGBA buffers. If an older run retained the NPZ but failed while drawing the PNG, repair it in place without rerunning models:
188
+
189
+ ```powershell
190
+ stemlab repair-spectrograms "path\to\analysis-results"
191
+ ```
192
+
137
193
  The preferred vocal stem is passed through the Silero VAD implementation bundled with `faster-whisper`. Speech regions are used to create a timeline-preserving `spoken_word.wav` (non-speech is zeroed rather than concatenated), then Whisper is run with word timestamps. Outputs include `whisper.json`, `speech_regions.json`, `transcript.txt`, `transcript.srt`, and `words.tsv`.
138
194
 
139
195
  Whisper runs in repetition-safe mode by default (`condition_on_previous_text=False`) to prevent a repeated syllable in one window contaminating later windows. `whisper.json` records that setting and includes repeated-token diagnostics. Use `--whisper-condition-on-previous-text` only for an explicit comparison run; a flagged transcript remains evidence requiring section-wise recovery or listening QA, not a trustworthy lyric source.
140
196
 
141
197
  Beat analysis runs:
142
198
 
143
- - **BeatNet** in offline/DBN mode when a compatible legacy environment is separately provisioned; it is not included in the current installable extras because its pinned NumPy/Numba requirements conflict with StemLab's core.
199
+ - **BeatNet** in offline/DBN mode through StemLab's checksum-verified runtime bootstrap. StemLab uses the maintained `madmom-prebuilt` wheel and bypasses only BeatNet 1.1.3's obsolete NumPy/Numba package metadata.
144
200
  - **Beat This!** using the `final0` checkpoint and its minimal postprocessor.
145
201
  - **Beat Transformer**, using the original released model code/checkpoints. The model was trained on five demixed mel streams, so StemLab maps BS-RoFormer-SW to vocals, drums, bass, piano, and `other + guitar`, makes 128-bin mel-power spectrograms at the original 44.1 kHz / 4096 FFT / 1024-hop settings, and averages all eight released fold checkpoints by default. It uses the original madmom DBN decoder if madmom is importable, otherwise a documented SciPy peak-picking fallback.
146
202
 
@@ -305,9 +361,128 @@ sample indexing, thresholds, limitations and reproducible screenshot examples.
305
361
 
306
362
  ![Loop selection and playback in the existing analysis frontend](docs/screenshots/loops-playing.png)
307
363
 
364
+ ## Audio-to-MIDI model comparison
365
+
366
+ MIDI extraction is an **optional, independent model pass**. It adds Transkun V2
367
+ and high-resolution note/pedal piano transcription, plus MR-MT3 and YourMT3
368
+ multi-instrument transcription, alongside Spotify Basic Pitch. Automatic source
369
+ selection uses piano/keyboard stems for the piano specialists, pitched stems for
370
+ Basic Pitch and the mix for MT3-family models. Missing stems are reported, never
371
+ silently substituted. The legacy `--basic-pitch` command remains supported.
372
+
373
+ ```bash
374
+ # Install the chosen runtime; the standard profiles do not install MIDI models.
375
+ python -m pip install -e ".[midi-transkun]"
376
+ stemlab midi-models
377
+
378
+ # Use an existing separated piano, without rerunning any earlier analysis.
379
+ stemlab midi analysis-master --model transkun
380
+
381
+ # Or transcribe a directly supplied piano recording to a new folder.
382
+ stemlab midi piano.wav -o midi-piano --model transkun
383
+
384
+ # Full mix comparison requires the separately installed midi-mt3 extra.
385
+ # Both requested checkpoints need explicit first-use download consent.
386
+ stemlab midi mix.wav -o midi-comparison --model mr_mt3 --model yourmt3 --allow-model-downloads
387
+ ```
388
+
389
+ Each model/source gets its original `.mid`, tempo-aware `notes.json` and
390
+ `notes.csv`, an optional real note `piano-roll.png`, source/checkpoint hashes,
391
+ package versions and a worker log. Native MIDI controllers, pitch bends, tempo
392
+ changes and drums are preserved. Note sample numbers are original-rate
393
+ **estimates**, not a claim that the transcription is sample-accurate ground truth.
394
+ The MIDI clock is not used to overwrite StemLab's measured beat grid.
395
+
396
+ New analyses can opt in with repeated `--midi-model` switches and
397
+ `--midi-allow-downloads`. Existing Codex installations gain a workspace-scoped
398
+ `stemlab_start_midi_scan` job tool after updating the Python installation and
399
+ restarting the session. Models remain optional and no Python dependencies are
400
+ automatically installed. Incompatible research runtimes can use separate
401
+ `--backend-python MODEL=PATH` interpreters.
402
+
403
+ See [the MIDI guide](docs/midi.md) for all models, installation choices, checkpoint
404
+ and licensing caveats, saved-stem targeting, Codex usage, exact output semantics,
405
+ real-inference smoke commands and test limitations. The React timeline remains
406
+ the analysis inspector; this patch adds no MIDI synthesizer or new interactive
407
+ piano-roll lane. Static note plots are not frontend screenshots.
408
+
409
+ ## Align timed musical cues to detected beats
410
+
411
+ Use saved analysis to snap an LRC cue file without rerunning models or editing audio:
412
+
413
+ ```bash
414
+ stemlab snap-cues analysis-master "musical cues.lrc" -o cue-review
415
+ stemlab snap-cues analysis-master "musical cues.lrc" -o cue-review-100ms --tolerance-ms 100
416
+ stemlab generate-cues analysis-master -o generated-cues --title "Song title"
417
+ ```
418
+
419
+ Only timestamps change: bracketed labels such as `[DROP: CHORUS 1]`, metadata,
420
+ encoding and line layout are preserved. A cue with **no detected beat within
421
+ ±150 ms** is highlighted as **REVIEW**, with its nearest-beat gap, and kept unchanged
422
+ by default. `--force-snap` moves distant cues too but retains their warnings.
423
+ `--downbeats` restricts targets to reported bar starts; `--beat-model` selects a
424
+ specific detector. No constant-tempo beats are invented to fill detection gaps.
425
+
426
+ Each new output folder contains the rewritten `.beat-snapped.lrc`, `report.json`,
427
+ a colour-coded `review.html`, and `review.txt`. Exact mode preserves the stored
428
+ beat timestamp; explicit millisecond/centisecond compatibility modes report
429
+ rounding. Source-rate sample-frame estimates are included when the rate is known.
430
+ Use `--fail-on-review` to write results and exit 2 when review is needed.
431
+ Generated section-cue files use a title-specific, WordPress-safe filename so
432
+ multiple releases can be uploaded and mapped without ambiguous duplicate names.
433
+ For the retained 3 October 2026 future-release batch,
434
+ `scripts/run-upcoming-full-cues.ps1` resumes full analyses without overwriting an
435
+ incomplete directory, and `scripts/summarize-upcoming-cues.ps1` reads each closed
436
+ manifest/report to produce one reproducible hash, cue-action and error-count row
437
+ per release. The summary script refuses missing or ambiguous generated LRCs.
438
+
439
+ For a new analysis, add `--snap-cues "musical cues.lrc"` and optionally
440
+ `--cue-tolerance-ms 100`. Cue alignment uses that run's detected events and appears
441
+ in `analysis.json`. See [the cue alignment guide](docs/cue-alignment.md) for exact
442
+ precision, offsets, all switches, safety rules and interpretation of warnings.
443
+
444
+ ## Complementary evidence models
445
+
446
+ StemLab now has an optional **evidence-model layer** for models that add a different
447
+ kind of musical evidence instead of duplicating the normal separation or MIDI
448
+ backends. Nothing in this layer is enabled by a normal profile.
449
+
450
+ ```bash
451
+ stemlab evidence-models
452
+
453
+ # Singing/speech/music activity + continuous pitch on saved vocals.
454
+ stemlab evidence analysis-master -o evidence-vocals \
455
+ --model firered_aed --model swift_f0 \
456
+ --model-path firered_aed=/models/FireRedVAD/AED
457
+
458
+ # Align approved lyrics without replacing them.
459
+ stemlab evidence analysis-master -o evidence-align \
460
+ --model qwen_forced_aligner --canonical-text lyrics.txt --allow-model-downloads
461
+
462
+ # Independent harmony evidence.
463
+ stemlab evidence analysis-master -o evidence-chords --model lv_chordia
464
+ ```
465
+
466
+ The built-in registry covers **FireRed AED**, **HeartTranscriptor**, **Qwen3
467
+ ForcedAligner**, **SwiftF0**, **SongFormer**, **lv-chordia** and **ADTOF PyTorch**.
468
+ It also exposes explicit external-runtime bridges for **GAME**, **SheetSage2**,
469
+ **MOSS-Music** and **AudioSep** so large or restricted research dependencies never
470
+ get silently bundled into StemLab. Outputs stay independent: singing activity,
471
+ forced alignment, pitch, structure, chords and drum hits are review evidence, not
472
+ a hidden combined ground-truth score.
473
+
474
+ Saved analyses automatically route vocal models to a preferred full vocal stem,
475
+ drum transcription to a drum stem, continuous pitch to pitched stems, and
476
+ structure/harmony models to the master. Missing specialist stems are reported.
477
+ Use `--backend-python MODEL=/path/to/python` for conflicting research environments.
478
+
479
+ See [the evidence-model guide](docs/evidence-models.md) for model terms, routing,
480
+ external bridges and interpretation rules. `scripts/benchmark_evidence_corpus.py`
481
+ probes an authorised evaluation collection without copying audio into the repo.
482
+
308
483
  ## Install
309
484
 
310
- Python 3.10 or 3.11 is recommended for the broad optional-model ecosystem. The `beats` and `all` extras install Beat This! but not BeatNet: BeatNet's current published NumPy/Numba pins conflict with StemLab's core Librosa requirement. The BeatNet adapter is retained for separately provisioned compatible legacy setups; a missing BeatNet result must not be mistaken for a successful detector run.
485
+ Python 3.11 is recommended for the broad optional-model ecosystem. The `beats` and `all` extras install Beat This! plus the compatible `madmom-prebuilt` decoder. BeatNet 1.1.3 itself still publishes obsolete NumPy/Numba dependency pins, so StemLab downloads its official pure-Python wheel separately, verifies the published SHA-256, and exposes only the BeatNet code and bundled model weights from its cache. This route is supported on Python 3.11-3.13; a missing BeatNet result must not be mistaken for a successful detector run.
311
486
 
312
487
  From PyPI, install the released StemLab distribution with:
313
488
 
@@ -330,6 +505,18 @@ SCNet and Beat Transformer are research repositories rather than stable pip infe
330
505
  stemlab bootstrap all
331
506
  ```
332
507
 
508
+ For BeatNet alone:
509
+
510
+ ```bash
511
+ pip install "danceflow-stemlab[beats]"
512
+ stemlab bootstrap beatnet
513
+ stemlab doctor
514
+ ```
515
+
516
+ `stemlab doctor` reports BeatNet as ready only when the normal package or the
517
+ verified StemLab cache can actually be found. `analyze --no-bootstrap` never
518
+ downloads BeatNet and records the unavailable backend instead.
519
+
333
520
  For only the Vamp analysis stack:
334
521
 
335
522
  ```bash
@@ -439,6 +626,7 @@ endpoints, events and the Arcadians reference workflow.
439
626
  - [Web service](docs/web.md)
440
627
  - [Containers](docs/containers.md)
441
628
  - [Publishing and releases](docs/publishing.md)
629
+ - [BeatNet compatibility](docs/beatnet.md)
442
630
  - [Changelog](CHANGELOG.md)
443
631
 
444
632
  ## Codex plugin and MCP server
@@ -1,98 +1,23 @@
1
- Metadata-Version: 2.4
2
- Name: danceflow-stemlab
3
- Version: 1.2.0
4
- Summary: StemLab audio timing analysis and loopable sections for creating Shorts videos; DanceFlow and WordPress DanceMoves
5
- Author: Kieran Simkin
6
- Maintainer: Kieran Simkin
7
- License-Expression: MIT
8
- Project-URL: Homepage, https://kieransimkin.co.uk/
9
- Project-URL: My Songs portfolio, https://kieransimkin.co.uk/my-songs/
10
- Project-URL: Arcadians showcase, https://kieransimkin.co.uk/arcadians/
11
- Project-URL: Repository, https://github.com/kieransimkin/stemlab
12
- Project-URL: Issues, https://github.com/kieransimkin/stemlab/issues
13
- Project-URL: Documentation, https://github.com/kieransimkin/stemlab/tree/main/docs
14
- Project-URL: Changelog, https://github.com/kieransimkin/stemlab/blob/main/CHANGELOG.md
15
- Project-URL: About Kieran, https://kieransimkin.co.uk/about-me/
16
- Project-URL: Contact, https://kieransimkin.co.uk/contact/
17
- Keywords: music,audio,MIR,source separation,BPM,rhythm,harmony,DanceFlow,DanceMoves,motion response,WordPress
18
- Classifier: Development Status :: 5 - Production/Stable
19
- Classifier: Programming Language :: Python :: 3
20
- Classifier: Programming Language :: Python :: 3.10
21
- Classifier: Programming Language :: Python :: 3.11
22
- Classifier: Programming Language :: Python :: 3.12
23
- Classifier: Programming Language :: Python :: 3.13
24
- Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
25
- Requires-Python: >=3.10
26
- Description-Content-Type: text/markdown
27
- License-File: LICENSE
28
- Requires-Dist: numpy
29
- Requires-Dist: scipy
30
- Requires-Dist: torch>=2.4
31
- Requires-Dist: torchaudio>=2.4
32
- Requires-Dist: soundfile>=0.12
33
- Requires-Dist: matplotlib
34
- Requires-Dist: typer>=0.12
35
- Requires-Dist: rich>=13.7
36
- Requires-Dist: platformdirs>=4.2
37
- Requires-Dist: librosa>=0.11
38
- Requires-Dist: pyloudnorm>=0.2
39
- Requires-Dist: cmudict>=1.1.3
40
- Provides-Extra: codex
41
- Requires-Dist: mcp<3,>=2.2; extra == "codex"
42
- Requires-Dist: fastapi<1,>=0.115; extra == "codex"
43
- Requires-Dist: uvicorn<1,>=0.34; extra == "codex"
44
- Provides-Extra: separation
45
- Requires-Dist: demucs>=4.0.1; extra == "separation"
46
- Requires-Dist: openunmix>=1.3.0; extra == "separation"
47
- Requires-Dist: bs-roformer-infer>=0.1.5; extra == "separation"
48
- Provides-Extra: speech
49
- Requires-Dist: faster-whisper; extra == "speech"
50
- Provides-Extra: beats
51
- Requires-Dist: beat-this>=1.1.0; extra == "beats"
52
- Provides-Extra: deep
53
- Requires-Dist: sentence-transformers<7,>=6.1; extra == "deep"
54
- Requires-Dist: all-in-one-infer>=3.1; extra == "deep"
55
- Provides-Extra: semantic-nc
56
- Requires-Dist: muq; extra == "semantic-nc"
57
- Provides-Extra: amt
58
- Requires-Dist: basic-pitch<0.5,>=0.4; python_version < "3.12" and extra == "amt"
59
- Provides-Extra: server
60
- Requires-Dist: fastapi<1,>=0.115; extra == "server"
61
- Requires-Dist: uvicorn[standard]<1,>=0.34; extra == "server"
62
- Requires-Dist: python-socketio<6,>=5.12; extra == "server"
63
- Provides-Extra: dev
64
- Requires-Dist: pytest>=8.0; extra == "dev"
65
- Requires-Dist: ruff>=0.6; extra == "dev"
66
- Requires-Dist: build>=1.2; extra == "dev"
67
- Requires-Dist: tomli>=2; python_version < "3.11" and extra == "dev"
68
- Requires-Dist: httpx2; extra == "dev"
69
- Provides-Extra: binary
70
- Requires-Dist: nuitka>=2.7; extra == "binary"
71
- Requires-Dist: ordered-set>=4.1; extra == "binary"
72
- Requires-Dist: zstandard>=0.23; extra == "binary"
73
- Requires-Dist: lazy-loader==0.4; extra == "binary"
74
- Provides-Extra: all
75
- Requires-Dist: demucs>=4.0.1; extra == "all"
76
- Requires-Dist: openunmix>=1.3.0; extra == "all"
77
- Requires-Dist: bs-roformer-infer>=0.1.5; extra == "all"
78
- Requires-Dist: faster-whisper; extra == "all"
79
- Requires-Dist: beat-this>=1.1.0; extra == "all"
80
- Requires-Dist: sentence-transformers<7,>=6.1; extra == "all"
81
- Requires-Dist: all-in-one-infer>=3.1; extra == "all"
82
- Requires-Dist: fastapi<1,>=0.115; extra == "all"
83
- Requires-Dist: uvicorn[standard]<1,>=0.34; extra == "all"
84
- Requires-Dist: python-socketio<6,>=5.12; extra == "all"
85
- Dynamic: license-file
86
-
87
1
  # StemLab
88
2
 
3
+ [![StemLab logo](https://raw.githubusercontent.com/kieransimkin/stemlab/v1.3.1/docs/branding/logo.png)](https://kieransimkin.co.uk/danceflow/)
4
+
5
+ By **[Kieran Simkin](https://kieransimkin.co.uk/)** · [DanceFlow ecosystem](https://kieransimkin.co.uk/danceflow/) · [Vector logo and usage guide](docs/branding/README.md).
6
+
7
+ Local music analysis for stems, timing, beats, harmony, lyrics, MIDI and loopable sections for Shorts. https://kieransimkin.co.uk/
8
+
9
+
89
10
  <!-- mcp-name: io.github.kieransimkin/stemlab -->
90
11
 
91
12
  > **StemLab by [Kieran Simkin](https://kieransimkin.co.uk/)** · [My Songs portfolio](https://kieransimkin.co.uk/my-songs/) · [Arcadians EPK](https://kieransimkin.co.uk/arcadians/) · [Source](https://github.com/kieransimkin/stemlab)
92
13
 
93
14
  > **Packaging identity:** the canonical project name is **StemLab**. StemLab is part of the **Dance Flow** project. The PyPI distribution is named `danceflow-stemlab` solely because Python package-registry names are globally unique. The Python import, CLI, GitHub repository and container image remain `stemlab`.
94
15
 
95
- StemLab provides **audio timing analysis and finds loopable sections for creating Shorts and other short-form videos**. It is the audio-analysis engine in Kieran Simkin's **DanceFlow** BPM and motion-response workflow. It separates and interprets a master track into synchronised stem, BPM/beat, structure, harmony, timbre, speech/lyric and semantic data. Those outputs can drive downstream motion-aware experiences, including the WordPress **DanceMoves** plugin, while StemLab remains usable as a standalone CLI, Python library, web service and container.
16
+ ## Synopsis
17
+
18
+ **StemLab is a local, evidence-led music analysis toolkit that turns a master recording into inspectable stems, timing, structure, harmony, lyric and sonic evidence, then finds complete-bar loopable sections for Shorts and other short-form videos.**
19
+
20
+ It combines independent separation and music-information-retrieval routes rather than treating any single model as the answer. Results remain traceable through source hashes, manifests, JSON/TSV/NPZ artefacts, portable Sonic Visualiser sessions and a shared React timeline for playback and comparison. StemLab can run as a CLI, Python library, web service, container or local Codex MCP plugin. It is the music-understanding layer of Kieran Simkin's **DanceFlow** workflow and can supply downstream motion systems such as the WordPress **DanceMoves** plugin, while remaining useful on its own.
96
21
 
97
22
  > **Model weights are not redistributed by this project.** They are fetched from their upstream registries/releases on first use. This avoids silently republishing checkpoints whose licensing may differ from the source code license, and lets upstream integrity metadata be used where available.
98
23
 
@@ -134,13 +59,19 @@ Relevant upstreams:
134
59
 
135
60
  For every successful separator, **every WAV it emits** is retained. Stem names are discovered from files rather than truncated to a hard-coded four-stem schema, which is important for MVSep Mega 53. For the master and every stem, StemLab writes both a PNG spectrogram and compressed `.npz` spectrogram data (time axis, frequency axis, dB matrix, FFT metadata).
136
61
 
62
+ Full-resolution spectrogram evidence stays in the `.npz`; the PNG renderer is bounded to 8,192 time frames so long tracks cannot expand into multi-gigabyte Matplotlib RGBA buffers. If an older run retained the NPZ but failed while drawing the PNG, repair it in place without rerunning models:
63
+
64
+ ```powershell
65
+ stemlab repair-spectrograms "path\to\analysis-results"
66
+ ```
67
+
137
68
  The preferred vocal stem is passed through the Silero VAD implementation bundled with `faster-whisper`. Speech regions are used to create a timeline-preserving `spoken_word.wav` (non-speech is zeroed rather than concatenated), then Whisper is run with word timestamps. Outputs include `whisper.json`, `speech_regions.json`, `transcript.txt`, `transcript.srt`, and `words.tsv`.
138
69
 
139
70
  Whisper runs in repetition-safe mode by default (`condition_on_previous_text=False`) to prevent a repeated syllable in one window contaminating later windows. `whisper.json` records that setting and includes repeated-token diagnostics. Use `--whisper-condition-on-previous-text` only for an explicit comparison run; a flagged transcript remains evidence requiring section-wise recovery or listening QA, not a trustworthy lyric source.
140
71
 
141
72
  Beat analysis runs:
142
73
 
143
- - **BeatNet** in offline/DBN mode when a compatible legacy environment is separately provisioned; it is not included in the current installable extras because its pinned NumPy/Numba requirements conflict with StemLab's core.
74
+ - **BeatNet** in offline/DBN mode through StemLab's checksum-verified runtime bootstrap. StemLab uses the maintained `madmom-prebuilt` wheel and bypasses only BeatNet 1.1.3's obsolete NumPy/Numba package metadata.
144
75
  - **Beat This!** using the `final0` checkpoint and its minimal postprocessor.
145
76
  - **Beat Transformer**, using the original released model code/checkpoints. The model was trained on five demixed mel streams, so StemLab maps BS-RoFormer-SW to vocals, drums, bass, piano, and `other + guitar`, makes 128-bin mel-power spectrograms at the original 44.1 kHz / 4096 FFT / 1024-hop settings, and averages all eight released fold checkpoints by default. It uses the original madmom DBN decoder if madmom is importable, otherwise a documented SciPy peak-picking fallback.
146
77
 
@@ -305,9 +236,128 @@ sample indexing, thresholds, limitations and reproducible screenshot examples.
305
236
 
306
237
  ![Loop selection and playback in the existing analysis frontend](docs/screenshots/loops-playing.png)
307
238
 
239
+ ## Audio-to-MIDI model comparison
240
+
241
+ MIDI extraction is an **optional, independent model pass**. It adds Transkun V2
242
+ and high-resolution note/pedal piano transcription, plus MR-MT3 and YourMT3
243
+ multi-instrument transcription, alongside Spotify Basic Pitch. Automatic source
244
+ selection uses piano/keyboard stems for the piano specialists, pitched stems for
245
+ Basic Pitch and the mix for MT3-family models. Missing stems are reported, never
246
+ silently substituted. The legacy `--basic-pitch` command remains supported.
247
+
248
+ ```bash
249
+ # Install the chosen runtime; the standard profiles do not install MIDI models.
250
+ python -m pip install -e ".[midi-transkun]"
251
+ stemlab midi-models
252
+
253
+ # Use an existing separated piano, without rerunning any earlier analysis.
254
+ stemlab midi analysis-master --model transkun
255
+
256
+ # Or transcribe a directly supplied piano recording to a new folder.
257
+ stemlab midi piano.wav -o midi-piano --model transkun
258
+
259
+ # Full mix comparison requires the separately installed midi-mt3 extra.
260
+ # Both requested checkpoints need explicit first-use download consent.
261
+ stemlab midi mix.wav -o midi-comparison --model mr_mt3 --model yourmt3 --allow-model-downloads
262
+ ```
263
+
264
+ Each model/source gets its original `.mid`, tempo-aware `notes.json` and
265
+ `notes.csv`, an optional real note `piano-roll.png`, source/checkpoint hashes,
266
+ package versions and a worker log. Native MIDI controllers, pitch bends, tempo
267
+ changes and drums are preserved. Note sample numbers are original-rate
268
+ **estimates**, not a claim that the transcription is sample-accurate ground truth.
269
+ The MIDI clock is not used to overwrite StemLab's measured beat grid.
270
+
271
+ New analyses can opt in with repeated `--midi-model` switches and
272
+ `--midi-allow-downloads`. Existing Codex installations gain a workspace-scoped
273
+ `stemlab_start_midi_scan` job tool after updating the Python installation and
274
+ restarting the session. Models remain optional and no Python dependencies are
275
+ automatically installed. Incompatible research runtimes can use separate
276
+ `--backend-python MODEL=PATH` interpreters.
277
+
278
+ See [the MIDI guide](docs/midi.md) for all models, installation choices, checkpoint
279
+ and licensing caveats, saved-stem targeting, Codex usage, exact output semantics,
280
+ real-inference smoke commands and test limitations. The React timeline remains
281
+ the analysis inspector; this patch adds no MIDI synthesizer or new interactive
282
+ piano-roll lane. Static note plots are not frontend screenshots.
283
+
284
+ ## Align timed musical cues to detected beats
285
+
286
+ Use saved analysis to snap an LRC cue file without rerunning models or editing audio:
287
+
288
+ ```bash
289
+ stemlab snap-cues analysis-master "musical cues.lrc" -o cue-review
290
+ stemlab snap-cues analysis-master "musical cues.lrc" -o cue-review-100ms --tolerance-ms 100
291
+ stemlab generate-cues analysis-master -o generated-cues --title "Song title"
292
+ ```
293
+
294
+ Only timestamps change: bracketed labels such as `[DROP: CHORUS 1]`, metadata,
295
+ encoding and line layout are preserved. A cue with **no detected beat within
296
+ ±150 ms** is highlighted as **REVIEW**, with its nearest-beat gap, and kept unchanged
297
+ by default. `--force-snap` moves distant cues too but retains their warnings.
298
+ `--downbeats` restricts targets to reported bar starts; `--beat-model` selects a
299
+ specific detector. No constant-tempo beats are invented to fill detection gaps.
300
+
301
+ Each new output folder contains the rewritten `.beat-snapped.lrc`, `report.json`,
302
+ a colour-coded `review.html`, and `review.txt`. Exact mode preserves the stored
303
+ beat timestamp; explicit millisecond/centisecond compatibility modes report
304
+ rounding. Source-rate sample-frame estimates are included when the rate is known.
305
+ Use `--fail-on-review` to write results and exit 2 when review is needed.
306
+ Generated section-cue files use a title-specific, WordPress-safe filename so
307
+ multiple releases can be uploaded and mapped without ambiguous duplicate names.
308
+ For the retained 3 October 2026 future-release batch,
309
+ `scripts/run-upcoming-full-cues.ps1` resumes full analyses without overwriting an
310
+ incomplete directory, and `scripts/summarize-upcoming-cues.ps1` reads each closed
311
+ manifest/report to produce one reproducible hash, cue-action and error-count row
312
+ per release. The summary script refuses missing or ambiguous generated LRCs.
313
+
314
+ For a new analysis, add `--snap-cues "musical cues.lrc"` and optionally
315
+ `--cue-tolerance-ms 100`. Cue alignment uses that run's detected events and appears
316
+ in `analysis.json`. See [the cue alignment guide](docs/cue-alignment.md) for exact
317
+ precision, offsets, all switches, safety rules and interpretation of warnings.
318
+
319
+ ## Complementary evidence models
320
+
321
+ StemLab now has an optional **evidence-model layer** for models that add a different
322
+ kind of musical evidence instead of duplicating the normal separation or MIDI
323
+ backends. Nothing in this layer is enabled by a normal profile.
324
+
325
+ ```bash
326
+ stemlab evidence-models
327
+
328
+ # Singing/speech/music activity + continuous pitch on saved vocals.
329
+ stemlab evidence analysis-master -o evidence-vocals \
330
+ --model firered_aed --model swift_f0 \
331
+ --model-path firered_aed=/models/FireRedVAD/AED
332
+
333
+ # Align approved lyrics without replacing them.
334
+ stemlab evidence analysis-master -o evidence-align \
335
+ --model qwen_forced_aligner --canonical-text lyrics.txt --allow-model-downloads
336
+
337
+ # Independent harmony evidence.
338
+ stemlab evidence analysis-master -o evidence-chords --model lv_chordia
339
+ ```
340
+
341
+ The built-in registry covers **FireRed AED**, **HeartTranscriptor**, **Qwen3
342
+ ForcedAligner**, **SwiftF0**, **SongFormer**, **lv-chordia** and **ADTOF PyTorch**.
343
+ It also exposes explicit external-runtime bridges for **GAME**, **SheetSage2**,
344
+ **MOSS-Music** and **AudioSep** so large or restricted research dependencies never
345
+ get silently bundled into StemLab. Outputs stay independent: singing activity,
346
+ forced alignment, pitch, structure, chords and drum hits are review evidence, not
347
+ a hidden combined ground-truth score.
348
+
349
+ Saved analyses automatically route vocal models to a preferred full vocal stem,
350
+ drum transcription to a drum stem, continuous pitch to pitched stems, and
351
+ structure/harmony models to the master. Missing specialist stems are reported.
352
+ Use `--backend-python MODEL=/path/to/python` for conflicting research environments.
353
+
354
+ See [the evidence-model guide](docs/evidence-models.md) for model terms, routing,
355
+ external bridges and interpretation rules. `scripts/benchmark_evidence_corpus.py`
356
+ probes an authorised evaluation collection without copying audio into the repo.
357
+
308
358
  ## Install
309
359
 
310
- Python 3.10 or 3.11 is recommended for the broad optional-model ecosystem. The `beats` and `all` extras install Beat This! but not BeatNet: BeatNet's current published NumPy/Numba pins conflict with StemLab's core Librosa requirement. The BeatNet adapter is retained for separately provisioned compatible legacy setups; a missing BeatNet result must not be mistaken for a successful detector run.
360
+ Python 3.11 is recommended for the broad optional-model ecosystem. The `beats` and `all` extras install Beat This! plus the compatible `madmom-prebuilt` decoder. BeatNet 1.1.3 itself still publishes obsolete NumPy/Numba dependency pins, so StemLab downloads its official pure-Python wheel separately, verifies the published SHA-256, and exposes only the BeatNet code and bundled model weights from its cache. This route is supported on Python 3.11-3.13; a missing BeatNet result must not be mistaken for a successful detector run.
311
361
 
312
362
  From PyPI, install the released StemLab distribution with:
313
363
 
@@ -330,6 +380,18 @@ SCNet and Beat Transformer are research repositories rather than stable pip infe
330
380
  stemlab bootstrap all
331
381
  ```
332
382
 
383
+ For BeatNet alone:
384
+
385
+ ```bash
386
+ pip install "danceflow-stemlab[beats]"
387
+ stemlab bootstrap beatnet
388
+ stemlab doctor
389
+ ```
390
+
391
+ `stemlab doctor` reports BeatNet as ready only when the normal package or the
392
+ verified StemLab cache can actually be found. `analyze --no-bootstrap` never
393
+ downloads BeatNet and records the unavailable backend instead.
394
+
333
395
  For only the Vamp analysis stack:
334
396
 
335
397
  ```bash
@@ -439,6 +501,7 @@ endpoints, events and the Arcadians reference workflow.
439
501
  - [Web service](docs/web.md)
440
502
  - [Containers](docs/containers.md)
441
503
  - [Publishing and releases](docs/publishing.md)
504
+ - [BeatNet compatibility](docs/beatnet.md)
442
505
  - [Changelog](CHANGELOG.md)
443
506
 
444
507
  ## Codex plugin and MCP server
@@ -0,0 +1,11 @@
1
+ # StemLab visual identity
2
+
3
+ ![StemLab logo](logo.svg)
4
+
5
+ By [Kieran Simkin](https://kieransimkin.co.uk/), part of [DanceFlow](https://kieransimkin.co.uk/danceflow/).
6
+
7
+ Split waveforms: inspectable music and stem analysis.
8
+
9
+ Original vector artwork, created 8 October 2026. Shared family: 128-unit square, rounded 30-unit frame, 5.5-unit rounded strokes, plum `#171124`, mint `#bff7df`, gold `#f5ce85`. The symbol remains unique without colour. `logo.svg` is the self-contained dark badge; `logo-monochrome.svg` is a transparent dark mark for light surfaces; `logo.png` is the 256px registry/export companion. Prefer SVG for scaling and label tiny marks with the tool name. No external fonts, scripts, remote references, animation or model-generated assets.
10
+
11
+ Use the files unchanged at a square aspect ratio, with at least 8/128 of their width as clear space. The monochrome mark needs a light background. Do not imply an official association with model providers, React, WordPress or operating-system vendors. Source artwork follows this repository's licence; dependency and third-party notices retain their own terms.
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" role="img" aria-labelledby="title desc">
2
+ <title id="title">StemLab logo</title>
3
+ <desc id="desc">Split waveforms: inspectable music and stem analysis. Original DanceFlow family mark by Kieran Simkin.</desc>
4
+
5
+ <g fill="none" stroke="#171124" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round"><path d="M29 44h9l5-12 8 24 7-12h12M29 64h13l6-8 7 16 6-8h9M29 84h10l7-5 8 10 7-5h9"/><path d="M80 42v44m0-22h12" stroke="#171124"/><circle cx="94" cy="64" r="5" fill="#171124" stroke="none"/></g>
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" role="img" aria-labelledby="title desc">
2
+ <title id="title">StemLab logo</title>
3
+ <desc id="desc">Split waveforms: inspectable music and stem analysis. Original DanceFlow family mark by Kieran Simkin.</desc>
4
+ <rect x="3" y="3" width="122" height="122" rx="30" fill="#171124"/><rect x="8" y="8" width="112" height="112" rx="25" fill="none" stroke="#f5ce85" stroke-opacity=".35" stroke-width="1.5"/>
5
+ <g fill="none" stroke="#bff7df" stroke-width="5.5" stroke-linecap="round" stroke-linejoin="round"><path d="M29 44h9l5-12 8 24 7-12h12M29 64h13l6-8 7 16 6-8h9M29 84h10l7-5 8 10 7-5h9"/><path d="M80 42v44m0-22h12" stroke="#f5ce85"/><circle cx="94" cy="64" r="5" fill="#f5ce85" stroke="none"/></g>
6
+ </svg>