Spaces:
Sleeping
Sleeping
Ewan Claude Opus 4.6 commited on
Commit Β·
a14f449
1
Parent(s): 83ff7ad
Use direct melodic transcription for piano roll instead of arrangement
Browse filesThe arrangement engine (vocals + chord voicings) was producing poor
results because vocal transcription via Basic Pitch is inherently noisy
and chord detection on mixed stems compounds errors. Now the piano roll
uses the "other" stem transcription directly β the same data that
produces good guitar tabs. This is the actual transcribed melodic
instruments (guitar, piano, synths) rather than a lossy derivation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- api/server.py +6 -2
- api/static/assets/{BassTab-S8WkcUIi.js β BassTab-DYMUP74N.js} +1 -1
- api/static/assets/{GuitarTab-CwGZfqd9.js β GuitarTab-CAe9Arke.js} +1 -1
- api/static/assets/{SheetMusic-DJu-kILP.js β SheetMusic-DAPl-kkp.js} +0 -0
- api/static/assets/{index-BtDnEmF3.js β index-8qL2GjUN.js} +0 -0
- api/static/index.html +1 -1
- app/src/App.jsx +1 -1
api/server.py
CHANGED
|
@@ -206,10 +206,14 @@ def run_full_transcription(job_id, audio_path, job_dir):
|
|
| 206 |
with open(bass_tab_path, 'w') as f:
|
| 207 |
json.dump(bass_tab, f)
|
| 208 |
|
| 209 |
-
# Step 7: Merge
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
job_status[job_id] = {"step": 7, "label": "Assembling final result...", "done": False}
|
| 211 |
merged_path = job_dir / "transcription.mid"
|
| 212 |
-
merge_stems(str(
|
| 213 |
|
| 214 |
# Clean up large stem files and intermediates
|
| 215 |
stems_dir = job_dir / "stems"
|
|
|
|
| 206 |
with open(bass_tab_path, 'w') as f:
|
| 207 |
json.dump(bass_tab, f)
|
| 208 |
|
| 209 |
+
# Step 7: Merge melodic transcription + bass into final MIDI
|
| 210 |
+
# Use the "other" stem directly β it's the actual transcribed melodic
|
| 211 |
+
# instruments (guitar, piano, synths). The arrangement engine (vocals +
|
| 212 |
+
# chord voicings) introduces too many errors from vocal transcription
|
| 213 |
+
# and chord detection inaccuracy.
|
| 214 |
job_status[job_id] = {"step": 7, "label": "Assembling final result...", "done": False}
|
| 215 |
merged_path = job_dir / "transcription.mid"
|
| 216 |
+
merge_stems(str(piano_opt), str(bass_opt), str(merged_path))
|
| 217 |
|
| 218 |
# Clean up large stem files and intermediates
|
| 219 |
stems_dir = job_dir / "stems"
|
api/static/assets/{BassTab-S8WkcUIi.js β BassTab-DYMUP74N.js}
RENAMED
|
@@ -1 +1 @@
|
|
| 1 |
-
import{r as S,C as i,j as B}from"./index-
|
|
|
|
| 1 |
+
import{r as S,C as i,j as B}from"./index-8qL2GjUN.js";const O=4,H=["G","D","A","E"];function q({tabData:f,currentTimeRef:P,width:s,height:c}){const M=S.useRef(null),d=S.useRef(null),v=S.useCallback(()=>{const l=M.current;if(!l||!f)return;const t=l.getContext("2d"),a=window.devicePixelRatio||1;(l.width!==s*a||l.height!==c*a)&&(l.width=s*a,l.height=c*a,l.style.width=`${s}px`,l.style.height=`${c}px`,t.scale(a,a));const A=P?.current??0,o=f.strings||4,r=50,w=30,x=40,k=20,E=c-r-w,u=E/(o-1),j=s-x-k,T=x+j*.2,C=j*.8/O;t.fillStyle=i.tabBg,t.fillRect(0,0,s,c),t.font="13px Inter, monospace",t.textAlign="right",t.textBaseline="middle";for(let e=0;e<o;e++){const n=r+e*u;t.fillStyle=i.textMuted;const g=o-1-e;t.fillText(H[g]||"",x-10,n)}t.strokeStyle=i.tabString,t.lineWidth=1;for(let e=0;e<o;e++){const n=r+e*u;t.beginPath(),t.moveTo(x,n),t.lineTo(s-k,n),t.stroke()}const F=f.events||[];t.textAlign="center",t.textBaseline="middle",t.font="bold 14px Inter, monospace";for(const e of F){const n=T+(e.time-A)*C;if(n<x-30||n>s+30)continue;const g=e.time<=A,I=g&&e.time+e.duration>A;for(let m=0;m<o;m++){const p=e.frets[m];if(p==null)continue;const L=o-1-m,R=r+L*u,W=t.measureText(String(p)).width,b=Math.max(W+8,18),y=18;I&&(t.fillStyle="rgba(139, 92, 246, 0.3)",t.beginPath(),t.roundRect(n-b/2,R-y/2,b,y,4),t.fill()),t.fillStyle=i.tabBg,t.fillRect(n-b/2,R-y/2,b,y),t.fillStyle=g?i.tabFretPlayed:i.tabFret,t.fillText(String(p),n,R)}}t.strokeStyle=i.tabProgressLine,t.lineWidth=2,t.shadowColor="rgba(139, 92, 246, 0.5)",t.shadowBlur=8,t.beginPath(),t.moveTo(T,r-10),t.lineTo(T,r+(o-1)*u+10),t.stroke(),t.shadowBlur=0,t.fillStyle=i.textMuted,t.font="bold 16px Inter, sans-serif",t.textAlign="center",t.textBaseline="middle";const h=r+E/2;t.fillText("T",15,h-12),t.fillText("A",15,h),t.fillText("B",15,h+12),d.current=requestAnimationFrame(v)},[f,P,s,c]);return S.useEffect(()=>(d.current=requestAnimationFrame(v),()=>{d.current&&cancelAnimationFrame(d.current)}),[v]),f?B.jsx("canvas",{ref:M,style:{display:"block",width:"100%",height:"100%"}}):B.jsx("div",{className:"tab-empty",children:B.jsx("p",{children:"No bass tab data available."})})}export{q as default};
|
api/static/assets/{GuitarTab-CwGZfqd9.js β GuitarTab-CAe9Arke.js}
RENAMED
|
@@ -1 +1 @@
|
|
| 1 |
-
import{r as v,C as s,j as P}from"./index-
|
|
|
|
| 1 |
+
import{r as v,C as s,j as P}from"./index-8qL2GjUN.js";const O=4,G=["E","B","G","D","A","E"];function N({tabData:u,currentTimeRef:E,width:i,height:a,chords:g}){const M=v.useRef(null),m=v.useRef(null),h=v.useCallback(()=>{const l=M.current;if(!l||!u)return;const t=l.getContext("2d"),c=window.devicePixelRatio||1;(l.width!==i*c||l.height!==a*c)&&(l.width=i*c,l.height=a*c,l.style.width=`${i}px`,l.style.height=`${a}px`,t.scale(c,c));const d=E?.current??0,r=u.strings||6,o=50,C=30,f=40,k=20,F=a-o-C,p=F/(r-1),I=i-f-k,b=f+I*.2,j=I*.8/O;t.fillStyle=s.tabBg,t.fillRect(0,0,i,a),t.font="13px Inter, monospace",t.textAlign="right",t.textBaseline="middle";for(let e=0;e<r;e++){const n=o+e*p;t.fillStyle=s.textMuted;const x=r-1-e;t.fillText(G[x]||"",f-10,n)}t.strokeStyle=s.tabString,t.lineWidth=1;for(let e=0;e<r;e++){const n=o+e*p;t.beginPath(),t.moveTo(f,n),t.lineTo(i-k,n),t.stroke()}if(g&&g.length>0){t.font="12px Inter, sans-serif",t.textAlign="center",t.textBaseline="bottom";for(const e of g){const n=b+(e.start_time-d)*j;if(n<f-50||n>i+50)continue;const x=e.start_time<=d;t.fillStyle=x?s.tabFretPlayed:"rgba(139, 92, 246, 0.5)",t.fillText(e.chord_name,n,o-8)}}const L=u.events||[];t.textAlign="center",t.textBaseline="middle",t.font="bold 14px Inter, monospace";for(const e of L){const n=b+(e.time-d)*j;if(n<f-30||n>i+30)continue;const x=e.time<=d,W=x&&e.time+e.duration>d;for(let y=0;y<r;y++){const S=e.frets[y];if(S==null)continue;const _=r-1-y,R=o+_*p,w=t.measureText(String(S)).width,A=Math.max(w+8,18),T=18;W&&(t.fillStyle="rgba(139, 92, 246, 0.3)",t.beginPath(),t.roundRect(n-A/2,R-T/2,A,T,4),t.fill()),t.fillStyle=s.tabBg,t.fillRect(n-A/2,R-T/2,A,T),t.fillStyle=x?s.tabFretPlayed:s.tabFret,t.fillText(String(S),n,R)}}t.strokeStyle=s.tabProgressLine,t.lineWidth=2,t.shadowColor="rgba(139, 92, 246, 0.5)",t.shadowBlur=8,t.beginPath(),t.moveTo(b,o-10),t.lineTo(b,o+(r-1)*p+10),t.stroke(),t.shadowBlur=0,t.fillStyle=s.textMuted,t.font="bold 16px Inter, sans-serif",t.textAlign="center",t.textBaseline="middle";const B=o+F/2;t.fillText("T",15,B-12),t.fillText("A",15,B),t.fillText("B",15,B+12),m.current=requestAnimationFrame(h)},[u,E,i,a,g]);return v.useEffect(()=>(m.current=requestAnimationFrame(h),()=>{m.current&&cancelAnimationFrame(m.current)}),[h]),u?P.jsx("canvas",{ref:M,style:{display:"block",width:"100%",height:"100%"}}):P.jsx("div",{className:"tab-empty",children:P.jsx("p",{children:"No guitar tab data available."})})}export{N as default};
|
api/static/assets/{SheetMusic-DJu-kILP.js β SheetMusic-DAPl-kkp.js}
RENAMED
|
The diff for this file is too large to render.
See raw diff
|
|
|
api/static/assets/{index-BtDnEmF3.js β index-8qL2GjUN.js}
RENAMED
|
The diff for this file is too large to render.
See raw diff
|
|
|
api/static/index.html
CHANGED
|
@@ -9,7 +9,7 @@
|
|
| 9 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
| 10 |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
| 11 |
<title>Mr. Octopus</title>
|
| 12 |
-
<script type="module" crossorigin src="/assets/index-
|
| 13 |
<link rel="stylesheet" crossorigin href="/assets/index-1_DPe19x.css">
|
| 14 |
</head>
|
| 15 |
<body>
|
|
|
|
| 9 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
| 10 |
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
| 11 |
<title>Mr. Octopus</title>
|
| 12 |
+
<script type="module" crossorigin src="/assets/index-8qL2GjUN.js"></script>
|
| 13 |
<link rel="stylesheet" crossorigin href="/assets/index-1_DPe19x.css">
|
| 14 |
</head>
|
| 15 |
<body>
|
app/src/App.jsx
CHANGED
|
@@ -402,7 +402,7 @@ export default function App() {
|
|
| 402 |
className={`view-tab ${activeTab === 'sheet' ? 'active' : ''}`}
|
| 403 |
onClick={() => setActiveTab('sheet')}
|
| 404 |
>
|
| 405 |
-
|
| 406 |
</button>
|
| 407 |
{songMode === 'full' && (
|
| 408 |
<>
|
|
|
|
| 402 |
className={`view-tab ${activeTab === 'sheet' ? 'active' : ''}`}
|
| 403 |
onClick={() => setActiveTab('sheet')}
|
| 404 |
>
|
| 405 |
+
Sheet Music
|
| 406 |
</button>
|
| 407 |
{songMode === 'full' && (
|
| 408 |
<>
|