In brief

spArtitI is a (web)app (Python/FastAPI and Next.js) built on open-source software that turns the URL of a YouTube video, an MP4 or an MP3 of piano music — solo or in a mix, even just a short excerpt — into an MP3, MIDI, MusicXML and a PDF with proposed fingering. The sequence of operations it runs is: audio extraction with yt-dlp and FFmpeg, optional piano separation with Demucs, transcription with Transkun, score with music21 and PDF with MuseScore 4. On a real 6.7-minute piece the pipeline takes about 100 seconds on an RTX 4070 GPU with 8 GB of VRAM, and about 3.5 times longer on a CPU. It now also accepts a score PDF (even a scanned one) or an image, recognized with homr (open-source OMR) and then handled as an incoming MusicXML. The limits are stated openly:

The sequence of operations in spartiti Source (YouTube URL, MP4 or MP3), audio with yt-dlp and FFmpeg, optional separation with Demucs, transcription to MIDI with Transkun, MusicXML score with music21, PDF with MuseScore 4, synchronized player. Source YouTube URL · MP4 · MP3 (Start/End) 1 · Audio yt-dlp + FFmpeg → MP3 2 · Separation (optional) Demucs htdemucs_6s → isolated piano 3 · Transcription Transkun → MIDI 4 · Score music21 → MusicXML, fingering 5 · PDF MuseScore 4 from the command line Synchronized player scrolling score · 88-key keyboard · pedal
The sequence of operations in spArtitI; the dashed step is optional
The spartiti interface in dark theme: the six pipeline steps, the YouTube URL field with Start and End, the MP3 or MP4 upload and the Jobs panel
The spArtitI interface: the video address, the excerpt, the six steps and the Jobs panel — click to enlarge
Part 1 · The problem

Hearing a piece and wanting to play it.

I am a self-taught pianist and last year I decided to take a short course (16 lessons of 2 hours) on the piano, its history, classical music… and a little practice on the instrument. And after the course…

It happens to anyone who plays: you hear a piano piece, maybe in a video, and you wish you had the sheet music in front of you. Sometimes it exists, sometimes it costs money, sometimes it is somebody else's transcription that doesn't resemble what you are listening to. The question is whether a computer can listen and write it down for you.

Transcribing music from an audio file is hard for a simple reason: audio is a single wave in which all the notes, the pedals, the reverb of the room and the other instruments are already mixed together. The piano makes things worse, because it plays many notes at once and the pedal keeps them alive even after the key has been released. A note that lasts a quarter note on the score may keep ringing much longer in the recording.

What a piece of music is to a computer

A piece of music is a multidimensional acoustic signal made up of:

As I usually do, if I can't find the right application I write it myself (or rather, I have an AI write it): I didn't want to use an external service and I didn't want it to stop at MIDI. MIDI on its own can't be read, and a “raw” MIDI turned into a score usually produces unreadable pages. I needed a real score, with fingering, and a way to listen to it and correct it.

The spartiti player in dark theme: Corrections panel with a selected note, score with fingering, 88-key keyboard and pedal indicator
The corrections, the score with fingering and the keyboard with the pedal — click to enlarge
✦
Part 2 · The chain

From a URL to a PDF in five steps.

Each step of the pipeline reads and writes files, and can be tested on its own. This is the complete path, from the address of the video to the sheet you put on the music stand.

1. Audio

From a URL, yt-dlp and FFmpeg download the video (at most 720p) and extract its audio to MP3; from an uploaded MP4 or MP3 you start right there. You can set a Start and an End to work on just an excerpt, and you also get the trimmed video.

2. Separation (if needed)

If the piece is not solo piano, Demucs (htdemucs_6s) splits the audio into six tracks — vocals, drums, bass, guitar, piano, other — and isolates the piano. In automatic mode the app measures how much energy the piano track has and, if it exceeds 90%, uses the original audio directly.

3. Transcription

Transkun (MIT license, the default engine) turns the audio into MIDI: which notes, when they start, how long they last, how loud. Alternatively you can choose the ByteDance model.

4. Score

music21 builds the MusicXML: it splits the hands, quantizes the rhythm, estimates the key, adds dynamics, pedal and fingering. This is also where the tempo is decided, and it is the most delicate step (I talk about it in Part 3).

5. PDF

MuseScore 4, from the command line, lays the score out as a PDF. In the browser the score is displayed with OpenSheetMusicDisplay, which drives the player.

yt-dlp + FFmpeg — audio and video
Demucs — track separation
Transkun — audio to MIDI
music21 — MIDI to score
MuseScore 4 — PDF
What MIDI is

MIDI (Musical Instrument Digital Interface) contains no sound: it contains instructions, like a score for machines. For each note it says which key, when it starts, how long it lasts and how hard it was pressed, plus events such as the pedal. That is why a MIDI file weighs a few kilobytes, can be played by any virtual instrument and can be corrected note by note, which is impossible with an MP3. It is the bridge between the audio, which the transcriber listens to, and the score, which music21 writes.

Which transcription engine? A comparison on three real pieces.

Before choosing I ran an A/B comparison on three real pieces: La cura by Franco Battiato, In The Air Tonight by Phil Collins and Una lunga storia d'amore by Gino Paoli. Transkun applied to the piano isolated by Demucs won. Another route, removing only the voice from the mix with BS-RoFormer and transcribing the rest, did not improve the result and costs about once the length of the piece, so it did not make it into the pipeline.

Solo piano

Direct transcription

  • No separation: the audio goes straight to the transcriber
  • The transcriber receives the original audio, without the artifacts of separation
  • Faster: no Demucs step
Mix with other instruments

Separation + transcription

  • Demucs isolates the piano, which stays “dirty”
  • Transkun writes 2 to 8 times fewer notes than the ByteDance model and is stable
  • Separation adds about 10–20% of the piece's length on GPU

One detail made a difference even on solo piano. Transkun writes the real duration of the key, not that of the note perceived under the pedal. Without correction, on a solo piano piece the median note duration was 0.23 seconds against 0.83 for the corrected version: a score chopped into very short notes. That is why the app lengthens the notes released while the pedal is down.

✦
Part 3 · The tempo

The day Clementi played at 108 instead of 205.

To write a score you need the tempo, that is, how many beats per minute (BPM). The app estimates this value by analyzing the audio through two main clues: the frequency of the notes (the rhythm of the individual attacks) and the cadence of the harmonic changes (how often the chord changes). On the pieces I tried the estimate gives 95 for In The Air Tonight, 61 for Una lunga storia d'amore, 90 for La cura and 70 for A Whiter Shade of Pale. The standard librosa beat tracking on the mix, for La cura, gave 129 instead.

Then, on 20 October 2026, I tried Clementi's Sonatina op. 36 no. 1, a lively piece, and the estimate came out at 108 BPM. The PDF filled up with eighth and sixteenth notes, unreadable.

Where the error was

I measured the attacks: C at 0.98 s, E at 1.28, C at 1.39, G at 1.53, G at 1.84, C at 2.15. A bar lasts 1.17 s, so a quarter note about 0.29 s: about 205 BPM, not 108. The estimate was right in its method and wrong in its result because the search was limited to 60–180 BPM, and the true tempo, outside the range, was being halved.

Raising the upper limit to 240 BPM was enough to make Clementi's estimate jump from 108 to 214 BPM, leaving the results of the other four pieces untouched. The whole problem was right there: by blocking the search at 180 BPM, the algorithm was forced to halve the real tempo, even though the score of that half was only 43% of that of the true tempo.

A good lesson: parameters tuned on just a few slow pieces break at the first fast one. After all, automatic estimates always remain a starting point. Not by chance, in the app the BPM field can be corrected by hand, with the quick buttons ÷2 and ×2 to fix on the spot the doublings and halvings typical of pieces in 2/2.

A number that works on five pieces is not a law: it is a hypothesis waiting for the sixth.

And rubato? A metronome that re-locks.

Nobody plays at a perfectly constant tempo. That is why the score does not use a rigid metronome: an adaptive metronome (a phase-locked loop) realigns itself to the attacks that fall near the eighth-note grid and corrects the period as it goes, within ±25% of the initial tempo. The constants were tuned on the Clementi piece itself: the two passes of the first repeat, transcribed separately, match 99% in note position and pitch. The player uses the same map, so cursor and score stay aligned even when the performer speeds up or slows down.

Two scores of Clementi op. 36 no. 1: with the tempo estimated at 108 BPM, full of eighth and sixteenth notes, and with the tempo corrected to 214 BPM, much more readable
Clementi with the estimate at 108 BPM (top) and at 214 BPM (bottom) — click to enlarge
✦
Part 4 · The fingers

A fingering proposal, not an edition.

For each hand the app chooses the fingers with a Viterbi algorithm: it looks for the fingering path that, over the whole phrase, minimizes hand stretches, crossings and leaps. The weights are heuristic and sit at the top of the module. Fingering is added at chord level, one finger for each pitch; with more than five notes in the same chord it assigns none.

Let me be clear: it is a proposal. It does not replace the fingering of an edition prepared by a pianist, who takes the music into account, not just the geometry of the hand. It is meant to give you a starting point that you can correct note by note.

✦
Part 5 · Correcting and listening again

The editor, the player and a piano in the browser.

Automatic transcription is imperfect, and pretending otherwise would be dishonest. That is why, after processing, the app does not stop at the PDF:

The spartiti corrections panel in dark theme: controls for listening, movement, pitch, duration, note and history (Undo, Redo, Reset edits, Save edits), with the score and the keyboard below
The corrections panel, with the score and the keyboard below — click to enlarge

Stopping a long job

A long piece occupies the only work queue and, at first, there was no way to stop it other than restarting the server, losing all the jobs. Today the Jobs panel lists those known to the server — queued, running (with step and percentage), finished, failed, interrupted — and the Interrupt button stops a job within a few seconds, frees the GPU and deletes the temporary files, such as partial downloads. An interrupted job is not an error and offers no files.

Finished, failed or interrupted jobs can be removed from the list (Remove) or deleted together with their folder on disk (Delete, after a confirmation). Folders not modified for more than a day are deleted automatically when the server starts and at every new job, never those of running or queued jobs; the limit can be changed with an environment variable. At the first start with this rule 34 folders out of 50 disappeared, from about 923 to 311 MB.

Interruption is cooperative: each job has its own token and the steps check it. A subprocess such as FFmpeg or MuseScore is terminated, separation stops between one 60-second block and the next, and transcription checks at every segment.

The interface is in Italian, English and Spanish, with automatic, light or dark theme and notes written as Do Re Mi or as A B C.

✦
Part 6 · From paper

Also from a PDF or a photo of the score.

Until now spArtitI always started from audio. You can now also drop a score PDF (even a scanned one) or an image (.png, .jpg, .jpeg) into the app. A new step, Recognition, turns the pages into MusicXML with homr, an open-source optical music recognition (OMR) tool built on ONNX models. From there the path is the one for an incoming MusicXML: score with proposed fingering, virtual keyboard, editor, PDF and a synthesized piano in the browser. There is no original audio: you only hear the synthesized piano.

What OMR is

OMR (Optical Music Recognition) is the equivalent of OCR for music notation: it takes the image of a score — a scan, a photo or a PDF — and turns it into a format the computer understands, such as MusicXML. It has to recognize staves, clefs, key signatures, notes (pitch and duration), rests, slurs and repeats. It is harder than OCR because the meaning of a symbol depends on its position and context, symbols overlap, and the rhythm has to be added up within each bar: that is why it gets rhythms wrong more often than pitches. It is a different problem from audio transcription: Transkun listens to a piece and writes the notes, homr looks at a page that is already written.

How it works: omr.py converts the PDF into grayscale images at 200 dpi with PyMuPDF (long side at most 4000 pixels) and hands each page to homr. The pages, up to 30, are merged in order into a single score and the bar numbering carries on. End-of-score repeat signs with no matching start are fixed, otherwise the player would replay the previous pages. An unreadable or blank page is skipped with a warning; an error is raised only if no page is recognized. The title is the file name, because OCR of the title is often wrong. For the app it is a new job type, with the steps recognition, score and PDF.

A recognition to double-check

OMR gets mostly the rhythms wrong (arpeggios across staves, two voices) and the pitches less often. So when the job ends, the app shows an amber box with a warning to check rhythms and bars, and a button to download the recognized MusicXML. At first it was a small grey line: too easy to miss. The recommended path for an exact result is scan, recognition, correction in MuseScore and re-upload of the corrected MusicXML. I do not quote accuracy percentages because I have not measured them: on three real pages the chain produced 534 notes.

homr uses the GPU too: measured on one page, inference takes 0.44 seconds per staff on an RTX 4070 against 2.0 on CPU, and a page costs about 16–18 seconds including startup (on CPU the first measurement was about 1 minute 44 seconds per page). On first use about 130 MB of weights are downloaded, so the network is needed.

Then there is a question that came straight out of the OMR: homr recognizes phrase slurs (not very reliably) and not the pedal, while the “from score” path discarded both anyway. The app now reads pedal and phrase slurs from the MusicXML. The technical surprise: music21's expandRepeats() detaches these marks from the notes (I checked it on a test file), so they are read from the unexpanded file and carried over to the repeats by bar number. The pedal reaches the timeline, keyboard, synthesized piano and PDF; the slurs reach the PDF and the displayed score, without changing the sound. A note deleted in the editor takes its slur with it.

✦
Part 7 · Limits and choices

What it doesn't do, and why everything runs locally.

I prefer a list of limits written today to a surprise six months from now. These are the known ones:

As for the choice of running locally: the app starts with uv run spartiti-serve (or with the avvia.bat script) and the server listens only on 127.0.0.1. The music does not go through any external transcription service. The network is needed to download the video from YouTube, for the Demucs model (about 300 MB, on first use) and for the piano samples (once only). A reminder that always applies: download only content you have the right to make a personal copy of, in compliance with YouTube's terms and copyright law.

For now, then, spArtitI runs locally, on my computer. In the future it could be moved to the virtual servers already up and running, whose architecture is described in Two VPSes, a GPU That Wakes Itself Up: an always-on ARM64 server and an A10 GPU that starts only when needed.

✦
Note on the method

How it was built.

spArtitI is developed with Claude Code, starting from a specification and a plan written before the code. It uses only open-source libraries. For the PDF input I followed the same scheme (brainstorming, specification, plan, one implementer and one reviewer per task): the final review of the whole branch found four important problems that the per-task reviews had not seen — repeat signs that replay earlier pages, a title taken from OCR, transparent PNGs and a blank page. The Clementi episode still teaches that tests on prepared data do not replace a trial on a real piece, never seen before.

✦
FAQ

Frequently asked questions.

How do you turn a YouTube video into sheet music?

With spArtitI you paste the URL of the video (optionally setting the Start and End of the excerpt): the app extracts the audio, transcribes it to MIDI with Transkun and produces MusicXML and a PDF with proposed fingering. On a 6.7-minute piece it takes about 100 seconds on an RTX 4070 GPU.

Does it work with pieces with several instruments?

Yes, but with less certain results. Demucs first isolates the piano from the mix, but the resulting track contains artifacts and the transcriber may invent or miss notes. It works best with solo piano; on mixes you should judge the result by ear.

How accurate is the transcription?

It is good but imperfect, which is why the app includes an editor. The comparison on three real pieces favored Transkun on the isolated piano: it writes 2 to 8 times fewer notes than the ByteDance model and is stable. The tempo is estimated and can be corrected by hand.

Can I correct the score?

Yes. You can edit one note at a time (pitch, duration, hand, finger), delete it or add one, with “Undo” and “Redo”, even on a tablet thanks to the button-based controls. “Save edits” regenerates PDF, MusicXML and MIDI with the corrections. The MP3 and the video do not change.

Is the fingering reliable?

It is a proposal computed with a Viterbi algorithm that reduces hand stretches, crossings and leaps. It does not replace the fingering of an edition prepared by a pianist: use it as a starting point.

Can I interrupt a long job?

Yes. The Jobs panel lists queued, running, finished, failed and interrupted jobs, and “Interrupt” stops a job within a few seconds, frees the GPU and deletes the temporary files. The exception is downloading from a URL with Start and End, which stops only when it finishes.

Can I start from a PDF or a photo of a score?

Yes. Drop a PDF (even a scanned one, up to 30 pages) or a PNG or JPG image into the app: homr recognizes the pages and turns them into MusicXML, then the path is the one for a score with proposed fingering, editor and PDF. OMR gets mostly the rhythms wrong, so it is best to download the recognized MusicXML, correct it in MuseScore and upload it again.

Do I need a GPU? Does my data stay on my computer?

An NVIDIA GPU is not required: without one, the app uses the CPU and is about 3.5 times slower. Processing happens locally and the server listens only on your computer; the network is needed only to download the video, the Demucs model and the piano samples.

✦
Demo

See it in action.

▶ Demo
spArtitI — demo video
From the YouTube link to the score with fingering.