Spaces:
Sleeping
Sleeping
Mina Emadi Claude Sonnet 4.6 commited on
Commit Β·
e38e511
1
Parent(s): e631a15
Add preset tracks with OGG stems and metadata overrides for key/BPM detection
Browse files- Add 6 preset tracks as OGG Vorbis (~10x smaller than WAV, no audible quality loss)
- Add metadata.json override system for presets with incorrect MIDI detection
- Fix Sea-to-Sky and Ocean-to-Horizon BPM (90 instead of 95)
- Fix Silver-lining key (D major instead of G major)
- Fix Static-Summer key (A major instead of D major)
- Backend resolves .ogg before .wav for forward/backward compatibility
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- .gitattributes +1 -0
- backend/models/session.py +2 -0
- backend/presets/{sample-track/bass.wav β 274-SUNSPILL/bass.ogg} +2 -2
- backend/presets/{sample-track/click_record.wav β 274-SUNSPILL/click_record.ogg} +2 -2
- backend/presets/{sample-track/drums.wav β 274-SUNSPILL/drums.ogg} +2 -2
- backend/presets/{sample-track/guitar.wav β 274-SUNSPILL/guitar.ogg} +2 -2
- backend/presets/{sample-track/MIDI.mid β 274-SUNSPILL/midi.mid} +0 -0
- backend/presets/274-SUNSPILL/synth.ogg +3 -0
- backend/presets/281-New-Drive/click_record.ogg +3 -0
- backend/presets/281-New-Drive/drums.ogg +3 -0
- backend/presets/281-New-Drive/guitar.ogg +3 -0
- backend/presets/281-New-Drive/midi.mid +0 -0
- backend/presets/281-New-Drive/synth.ogg +3 -0
- backend/presets/282-Static-Summer/282A- STATIC SUMMER- A- 85.mid +0 -0
- backend/presets/282-Static-Summer/click_record.ogg +3 -0
- backend/presets/282-Static-Summer/drums.ogg +3 -0
- backend/presets/282-Static-Summer/guitar.ogg +3 -0
- backend/presets/282-Static-Summer/metadata.json +1 -0
- backend/presets/282-Static-Summer/synth.ogg +3 -0
- backend/presets/291-Blue-Jazz/click_record.ogg +3 -0
- backend/presets/291-Blue-Jazz/drums.ogg +3 -0
- backend/presets/291-Blue-Jazz/guitar.ogg +3 -0
- backend/presets/291-Blue-Jazz/midi.mid +0 -0
- backend/presets/291-Blue-Jazz/synth.ogg +3 -0
- backend/presets/292-Silver-lining/Midi.mid +0 -0
- backend/presets/292-Silver-lining/click_record.ogg +3 -0
- backend/presets/292-Silver-lining/drums.ogg +3 -0
- backend/presets/292-Silver-lining/guitar.ogg +3 -0
- backend/presets/292-Silver-lining/metadata.json +1 -0
- backend/presets/292-Silver-lining/synth.ogg +3 -0
- backend/presets/294-Sea-to-Sky/click_record.ogg +3 -0
- backend/presets/294-Sea-to-Sky/drums.ogg +3 -0
- backend/presets/294-Sea-to-Sky/guitar.ogg +3 -0
- backend/presets/294-Sea-to-Sky/metadata.json +1 -0
- backend/presets/294-Sea-to-Sky/midi.mid +0 -0
- backend/presets/294-Sea-to-Sky/synth.ogg +3 -0
- backend/presets/295-Ocean-to-Horizon/click_record.ogg +3 -0
- backend/presets/295-Ocean-to-Horizon/drums.ogg +3 -0
- backend/presets/295-Ocean-to-Horizon/guitar.ogg +3 -0
- backend/presets/295-Ocean-to-Horizon/metadata.json +1 -0
- backend/presets/295-Ocean-to-Horizon/midi.mid +0 -0
- backend/presets/295-Ocean-to-Horizon/synth.ogg +3 -0
- backend/presets/sample-track/synth.wav +0 -3
- backend/routers/detection.py +18 -2
- backend/routers/presets.py +26 -4
.gitattributes
CHANGED
|
@@ -34,3 +34,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
backend/presets/**/*.wav filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
backend/presets/**/*.wav filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
backend/presets/**/*.ogg filter=lfs diff=lfs merge=lfs -text
|
backend/models/session.py
CHANGED
|
@@ -36,6 +36,8 @@ class Session:
|
|
| 36 |
original_sr: int = 44100
|
| 37 |
# Cache for encoded WAV bytes to avoid re-encoding on each request
|
| 38 |
wav_cache: dict[str, bytes] = field(default_factory=dict)
|
|
|
|
|
|
|
| 39 |
|
| 40 |
|
| 41 |
# In-memory session store
|
|
|
|
| 36 |
original_sr: int = 44100
|
| 37 |
# Cache for encoded WAV bytes to avoid re-encoding on each request
|
| 38 |
wav_cache: dict[str, bytes] = field(default_factory=dict)
|
| 39 |
+
# Optional metadata overrides loaded from preset's metadata.json
|
| 40 |
+
preset_metadata: Optional[dict] = None
|
| 41 |
|
| 42 |
|
| 43 |
# In-memory session store
|
backend/presets/{sample-track/bass.wav β 274-SUNSPILL/bass.ogg}
RENAMED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:19e3c525887f1cc0e9fc54e7604b07e273d3d7be5a6b642c7dc155ac7679d7ef
|
| 3 |
+
size 1775218
|
backend/presets/{sample-track/click_record.wav β 274-SUNSPILL/click_record.ogg}
RENAMED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7c3cda91ce4b648c6a624dcde24994275d8a06ed9575aca33f8ee159229e7ad5
|
| 3 |
+
size 677440
|
backend/presets/{sample-track/drums.wav β 274-SUNSPILL/drums.ogg}
RENAMED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e52f1689c33fc77996692739a8b468f2570523cf83d7ae2f65d9c52b1afa79ef
|
| 3 |
+
size 5849946
|
backend/presets/{sample-track/guitar.wav β 274-SUNSPILL/guitar.ogg}
RENAMED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:32c4165659d43522bffb3ad4d3f8984fb4139bbac78091d24708ee1520752996
|
| 3 |
+
size 4202989
|
backend/presets/{sample-track/MIDI.mid β 274-SUNSPILL/midi.mid}
RENAMED
|
File without changes
|
backend/presets/274-SUNSPILL/synth.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:37fef05c433225778d69ca05e0792504f7bdda87d13b4595787efc20748725bd
|
| 3 |
+
size 4969407
|
backend/presets/281-New-Drive/click_record.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b57f2056adad41ebdf5c857906087196fac0a15c513e54a12c5e2a5898be63aa
|
| 3 |
+
size 955426
|
backend/presets/281-New-Drive/drums.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1b225eacde295cb8d5171fa5caac8c009c9dd661f86d9b9dd90e57be2f838698
|
| 3 |
+
size 9873395
|
backend/presets/281-New-Drive/guitar.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8edfbb3d8d8fb6eca4d332f39e0c0b7f946fd27618da01c730e6136564b80c9e
|
| 3 |
+
size 6052516
|
backend/presets/281-New-Drive/midi.mid
ADDED
|
Binary file (35.6 kB). View file
|
|
|
backend/presets/281-New-Drive/synth.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0d48b8df19153c8dee5f3d8b03e31613506a5f3aaf93d3e51895d3718ee42e3a
|
| 3 |
+
size 3570314
|
backend/presets/282-Static-Summer/282A- STATIC SUMMER- A- 85.mid
ADDED
|
Binary file (30.7 kB). View file
|
|
|
backend/presets/282-Static-Summer/click_record.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:599d74905a741a7acd33931ff89373f469fe98edd27b543e9563472692de3214
|
| 3 |
+
size 1275261
|
backend/presets/282-Static-Summer/drums.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6175a8ce69bc827eb939da4f9c67fe7d4a1def1118eb3965bda7617b087a3dfa
|
| 3 |
+
size 14258389
|
backend/presets/282-Static-Summer/guitar.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:010119a51c2078573cfa91e9521cc20b5d0eac0944e710ec993672e01ea1a341
|
| 3 |
+
size 9248029
|
backend/presets/282-Static-Summer/metadata.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{ "key": "A", "mode": "major" }
|
backend/presets/282-Static-Summer/synth.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7a85e1128abb36af56ef122d5c46935f93defa8883666d05d44059e64e7e0ac0
|
| 3 |
+
size 10177662
|
backend/presets/291-Blue-Jazz/click_record.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c509be5861393346b9171e4fae7d6da1258dbba01890c91d43b7c026f83ad974
|
| 3 |
+
size 1248321
|
backend/presets/291-Blue-Jazz/drums.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3d07798a8b0c2087f2cd672f5a111063ded392b1c3151121684228010b80b1e1
|
| 3 |
+
size 17954847
|
backend/presets/291-Blue-Jazz/guitar.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b68969f1be0e5b77c76f71cc51a58c4f3607a84ea30ad6bb09a5fedfae23235b
|
| 3 |
+
size 7622816
|
backend/presets/291-Blue-Jazz/midi.mid
ADDED
|
Binary file (34.4 kB). View file
|
|
|
backend/presets/291-Blue-Jazz/synth.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e94da4bf9cce3ef54df934286d9c5d043152bdaf655f34f13e653ef37f533404
|
| 3 |
+
size 5147257
|
backend/presets/292-Silver-lining/Midi.mid
ADDED
|
Binary file (54.4 kB). View file
|
|
|
backend/presets/292-Silver-lining/click_record.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:64bcb9637c8f29f2192035fd03f56be5a05cb4e0f8d6fe7d8baddf8a9ad88745
|
| 3 |
+
size 1224237
|
backend/presets/292-Silver-lining/drums.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1141913045b3a85cfba368d32a748c6bbd83514f48384dd41d3dadb2f849da06
|
| 3 |
+
size 13762812
|
backend/presets/292-Silver-lining/guitar.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1327a2b61936f78d514a3c528ca604379c69399f6e1d28de8f51f5aa9afcc8ba
|
| 3 |
+
size 6776410
|
backend/presets/292-Silver-lining/metadata.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{ "key": "D", "mode": "major" }
|
backend/presets/292-Silver-lining/synth.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:28cd6533535ad035391a864687d5f6fe1bbede08e2e6a090b07655be9a6e3cc4
|
| 3 |
+
size 5794283
|
backend/presets/294-Sea-to-Sky/click_record.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ba642c37eca52f14055a320b3b105bc52b73e711e6c69e036eb24dff05437bbe
|
| 3 |
+
size 1294507
|
backend/presets/294-Sea-to-Sky/drums.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e66ca65d5e4b034442e8a106b01c32d352a2f723964ad222b3f9cbbee6287b70
|
| 3 |
+
size 11734610
|
backend/presets/294-Sea-to-Sky/guitar.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:887f057845958f0fccbfb1cb867b16e564ac6dc8b8f59aa407f1b949c6f70185
|
| 3 |
+
size 7145674
|
backend/presets/294-Sea-to-Sky/metadata.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{ "bpm": 90 }
|
backend/presets/294-Sea-to-Sky/midi.mid
ADDED
|
Binary file (32.5 kB). View file
|
|
|
backend/presets/294-Sea-to-Sky/synth.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:924694244bea0ee8e022bf86bedd8516cb4b51b23f579b5c2e18eb111b2cf52c
|
| 3 |
+
size 5323721
|
backend/presets/295-Ocean-to-Horizon/click_record.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f5d69c2527d02d8f25694149c0c55f7e1b2636fbc09bcd8ae0bd7eadc2c99fd7
|
| 3 |
+
size 1294507
|
backend/presets/295-Ocean-to-Horizon/drums.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4d97ad6d139174592d9dacbd8c260cc291a5f1a8e0fbe5866b430ff24bf7b167
|
| 3 |
+
size 11734851
|
backend/presets/295-Ocean-to-Horizon/guitar.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a3c6458920495eec37134e11a514c8983670818de9069d67b02f9a2a7f6e9a5e
|
| 3 |
+
size 7235754
|
backend/presets/295-Ocean-to-Horizon/metadata.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{ "bpm": 90 }
|
backend/presets/295-Ocean-to-Horizon/midi.mid
ADDED
|
Binary file (28.1 kB). View file
|
|
|
backend/presets/295-Ocean-to-Horizon/synth.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:822c8d86bbb900451978218c0ca657771cb2caa46d1054924bda6ad70ad0c612
|
| 3 |
+
size 4499162
|
backend/presets/sample-track/synth.wav
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:ba8a34d85b65a69e09ba0a319136bba8c9d92a6e0fa10e9dc3770d6e26d25a49
|
| 3 |
-
size 70893820
|
|
|
|
|
|
|
|
|
|
|
|
backend/routers/detection.py
CHANGED
|
@@ -29,11 +29,22 @@ async def detect_bpm_and_key(session_id: str):
|
|
| 29 |
if session.full_mix is None:
|
| 30 |
raise HTTPException(status_code=400, detail="No audio data in session")
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
# BPM Detection - prefer MIDI (instant)
|
| 33 |
bpm_source = "audio"
|
| 34 |
bpm_result = None
|
| 35 |
|
| 36 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
# Use MIDI directly - it's exact data
|
| 38 |
bpm_result = extract_bpm_from_midi(session.midi_data)
|
| 39 |
bpm_source = "midi"
|
|
@@ -63,7 +74,12 @@ async def detect_bpm_and_key(session_id: str):
|
|
| 63 |
key_source = "audio"
|
| 64 |
key_result = None
|
| 65 |
|
| 66 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
# Use MIDI directly
|
| 68 |
key_result = extract_key_from_midi(session.midi_data)
|
| 69 |
if key_result["confidence"] > 0: # Accept any MIDI key result
|
|
|
|
| 29 |
if session.full_mix is None:
|
| 30 |
raise HTTPException(status_code=400, detail="No audio data in session")
|
| 31 |
|
| 32 |
+
# Preset metadata overrides β highest priority, skips all detection
|
| 33 |
+
meta = session.preset_metadata or {}
|
| 34 |
+
bpm_override = meta.get("bpm")
|
| 35 |
+
key_override = meta.get("key")
|
| 36 |
+
mode_override = meta.get("mode")
|
| 37 |
+
|
| 38 |
# BPM Detection - prefer MIDI (instant)
|
| 39 |
bpm_source = "audio"
|
| 40 |
bpm_result = None
|
| 41 |
|
| 42 |
+
if bpm_override is not None:
|
| 43 |
+
bpm_result = {"bpm": float(bpm_override), "confidence": 1.0}
|
| 44 |
+
bpm_source = "preset"
|
| 45 |
+
print(f"BPM from preset metadata: {bpm_result['bpm']}")
|
| 46 |
+
|
| 47 |
+
elif session.midi_data is not None:
|
| 48 |
# Use MIDI directly - it's exact data
|
| 49 |
bpm_result = extract_bpm_from_midi(session.midi_data)
|
| 50 |
bpm_source = "midi"
|
|
|
|
| 74 |
key_source = "audio"
|
| 75 |
key_result = None
|
| 76 |
|
| 77 |
+
if key_override is not None and mode_override is not None:
|
| 78 |
+
key_result = {"key": key_override, "mode": mode_override, "confidence": 1.0}
|
| 79 |
+
key_source = "preset"
|
| 80 |
+
print(f"Key from preset metadata: {key_result['key']} {key_result['mode']}")
|
| 81 |
+
|
| 82 |
+
elif session.midi_data is not None:
|
| 83 |
# Use MIDI directly
|
| 84 |
key_result = extract_key_from_midi(session.midi_data)
|
| 85 |
if key_result["confidence"] > 0: # Accept any MIDI key result
|
backend/routers/presets.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
| 3 |
from pathlib import Path
|
| 4 |
|
| 5 |
import io
|
|
|
|
| 6 |
import numpy as np
|
| 7 |
import soundfile as sf
|
| 8 |
import mido
|
|
@@ -16,6 +17,7 @@ router = APIRouter()
|
|
| 16 |
|
| 17 |
PRESETS_DIR = Path(__file__).parent.parent / "presets"
|
| 18 |
STEM_NAMES = ['guitar', 'drums', 'bass', 'synth', 'click_record']
|
|
|
|
| 19 |
|
| 20 |
|
| 21 |
@router.get("/presets")
|
|
@@ -30,9 +32,15 @@ async def list_presets():
|
|
| 30 |
@router.get("/preset-stem/{preset_name}/{stem_name}")
|
| 31 |
async def get_preset_stem_pcm(preset_name: str, stem_name: str):
|
| 32 |
"""Serve a single preset stem as raw int16 PCM β stateless, no session created."""
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
raise HTTPException(status_code=404, detail=f"Stem '{stem_name}' not found in preset '{preset_name}'")
|
|
|
|
| 36 |
|
| 37 |
audio, sr = sf.read(str(wav_path))
|
| 38 |
audio = audio.astype(np.float32)
|
|
@@ -66,9 +74,15 @@ async def load_preset(preset_name: str):
|
|
| 66 |
sample_rates = []
|
| 67 |
|
| 68 |
for stem_name in STEM_NAMES:
|
| 69 |
-
|
| 70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
continue
|
|
|
|
| 72 |
audio, sr = sf.read(str(wav_path))
|
| 73 |
audio = audio.astype(np.float32)
|
| 74 |
if audio.ndim == 2:
|
|
@@ -95,11 +109,19 @@ async def load_preset(preset_name: str):
|
|
| 95 |
except Exception as e:
|
| 96 |
print(f"Warning: could not load MIDI from preset '{preset_name}': {e}")
|
| 97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
# Build session
|
| 99 |
session = create_session()
|
| 100 |
session.stems = stems
|
| 101 |
session.original_sr = sample_rates[0]
|
| 102 |
session.midi_data = midi_data
|
|
|
|
| 103 |
|
| 104 |
# Generate mix
|
| 105 |
max_length = max(len(s.audio) for s in stems.values())
|
|
|
|
| 3 |
from pathlib import Path
|
| 4 |
|
| 5 |
import io
|
| 6 |
+
import json
|
| 7 |
import numpy as np
|
| 8 |
import soundfile as sf
|
| 9 |
import mido
|
|
|
|
| 17 |
|
| 18 |
PRESETS_DIR = Path(__file__).parent.parent / "presets"
|
| 19 |
STEM_NAMES = ['guitar', 'drums', 'bass', 'synth', 'click_record']
|
| 20 |
+
AUDIO_EXTENSIONS = ['.ogg', '.wav'] # prefer OGG, fall back to WAV
|
| 21 |
|
| 22 |
|
| 23 |
@router.get("/presets")
|
|
|
|
| 32 |
@router.get("/preset-stem/{preset_name}/{stem_name}")
|
| 33 |
async def get_preset_stem_pcm(preset_name: str, stem_name: str):
|
| 34 |
"""Serve a single preset stem as raw int16 PCM β stateless, no session created."""
|
| 35 |
+
audio_path = None
|
| 36 |
+
for ext in AUDIO_EXTENSIONS:
|
| 37 |
+
candidate = PRESETS_DIR / preset_name / f"{stem_name}{ext}"
|
| 38 |
+
if candidate.exists():
|
| 39 |
+
audio_path = candidate
|
| 40 |
+
break
|
| 41 |
+
if audio_path is None:
|
| 42 |
raise HTTPException(status_code=404, detail=f"Stem '{stem_name}' not found in preset '{preset_name}'")
|
| 43 |
+
wav_path = audio_path
|
| 44 |
|
| 45 |
audio, sr = sf.read(str(wav_path))
|
| 46 |
audio = audio.astype(np.float32)
|
|
|
|
| 74 |
sample_rates = []
|
| 75 |
|
| 76 |
for stem_name in STEM_NAMES:
|
| 77 |
+
audio_path = None
|
| 78 |
+
for ext in AUDIO_EXTENSIONS:
|
| 79 |
+
candidate = preset_dir / f"{stem_name}{ext}"
|
| 80 |
+
if candidate.exists():
|
| 81 |
+
audio_path = candidate
|
| 82 |
+
break
|
| 83 |
+
if audio_path is None:
|
| 84 |
continue
|
| 85 |
+
wav_path = audio_path
|
| 86 |
audio, sr = sf.read(str(wav_path))
|
| 87 |
audio = audio.astype(np.float32)
|
| 88 |
if audio.ndim == 2:
|
|
|
|
| 109 |
except Exception as e:
|
| 110 |
print(f"Warning: could not load MIDI from preset '{preset_name}': {e}")
|
| 111 |
|
| 112 |
+
# Load metadata overrides if present
|
| 113 |
+
preset_metadata = None
|
| 114 |
+
metadata_path = preset_dir / "metadata.json"
|
| 115 |
+
if metadata_path.exists():
|
| 116 |
+
with open(metadata_path) as f:
|
| 117 |
+
preset_metadata = json.load(f)
|
| 118 |
+
|
| 119 |
# Build session
|
| 120 |
session = create_session()
|
| 121 |
session.stems = stems
|
| 122 |
session.original_sr = sample_rates[0]
|
| 123 |
session.midi_data = midi_data
|
| 124 |
+
session.preset_metadata = preset_metadata
|
| 125 |
|
| 126 |
# Generate mix
|
| 127 |
max_length = max(len(s.audio) for s in stems.values())
|