(Show Table Of Contents)
(Hide Table Of Contents)


Unroll is a Python module for the transcription of piano rolls to sheet music. It will very soon also be a command line tool. It can transcribe from a MIDI file or from a video of a piano roll. It finds the notes, the tempo, roughly separates the hands, and writes the result in a Lilypond file.

See this blog post for a more thorough presentation of the objectives and the method.


Unroll can be called from Python or from a terminal.

To transcribe a MIDI file (terminal, coming soon)

>>> unroll tiger_rag.mid quarter=1.1,10,0.02 score.ly

To transcribe a MIDI file (Python)

from unroll import midi2keystrikes

keystrikes = midi2keystrikes('tiger_rag.mid')

                      quarter_duration = [1.1,10,0.02])

To transcribe a video (terminal, coming soon)

>>> unroll limehouse_nights.mp4 focus=156,58,156,478
           transpose=26 quarter=1.1,10,0.02 score.ly

To transcribe a video (Python)

from unroll import video2scan, rollscan2keystrikes

scan = video2rollscan(videofile = "limehouse_nights.mp4",
                      focus = lambda im : im[[156],58:478])

keystrikes = rollscan2keystrikes(scan)
keystrikes = ks.transposed(26) # transpose notes +26 tones
                      quarter_duration = [1.1,10,0.02])

The output is a Lylipond file (score.ly) that you will need to edit to correct the mistakes (it can take a few hours with a good editor like Frescobaldi), and then compile to beautiful sheet music like this one.


First method: get the source (on Github or PyPI), unzip it into a directory, and in a terminal type:

(sudo) python setup.py install

Second method: with a pip command.

(sudo) pip install unroll


Unroll is a free open-source software originally written by Zulko and released under the MIT licence. Everyone is welcome to contribute and give feedback on Github.

Reference Manual

class unroll.KeyStrikes(keystrikes)


find_quarter_duration(durations, report=False)

Finds the quarter duration by computing the spectrum with different period durations and keeping the optimal duration. If report is True, a image of the specturm is saved.


Returns a new KeyStrikes object obtained by quantizing the notes (regroups chords and corrects durations to the nearest eighth).


Separates the hands by giving all the notes under note to the left hand. Returns 2 Keystrikes objects (left, right).


Converts the Keystrikes object to lilypond format using music21

transcribe(filename, quarter_durations, hands_separation=60, report=False)

Transcribes the KeyStrike Object into piano sheet music. First it finds the tempo, then separates the hands, quantizes each hand and converts each to lilypond format. Finally it writes everything into a nive lilypond template, which can then be compiled with lilypond myfile.ly

quarter_durations must be of the form [min, max, step], with min>1. For instance [2, 40, .1]. Then the duration will be chosen among 2, 2.1, 2.2 ... 40


Returns a new Keystrike object in which the notes n have been replaced by n+tone


unroll.video2rollscan(videofile, focus, start=0, end=None, savefile=None)

Makes a scan of the roll from the video. Requires the pyton module MoviePy


video :

Any videofile that MoviePy (FFMPEG) can read.

focus :

A function ( f(image)->rectangular image ). For instance if the line of interest is defined by y=15 and x=10...230

>>> focus = lambda im : im[ [15], 10:230 ]

start,end :

Where to start and stop, each one either in seconds, or in format (minutes, seconds). By default start=0 and end is the end of the video.

savefile :

If provided, the scan image will be saved under this name.


A W*H*3 RGB picture of the piano roll made by stacking the focus :

lines of the different frames under one another.

unroll.rollscan2keystrikes(roll_image, column_widths=[1.1, 50, 0.01], threshold_keypress=0.8, report=False)

Converts an image of a roll into a KeysStrikes object.


roll_image :

A roll image obtained for instance with video2scan

column_widths :

A triplet of the form [min, max, step] with min>1 for the search of the column width (in pixels) in the roll.

threshold_keypress :

Parameter in range 0-1. A pixel is considered a hole if its luminosity is < threshold_keypress*max_luminosity. If too small, notes strikes will be missed, if too high there will be false note strikes.

report :

If provided, the spectrum used for column-width estimation is stored into a file.


keystrikes :

A KeyStrikes object (conversion of the roll image).


unroll.midi2keystrikes(filename, tracknum=0)

Reads a midifile (thanks to the package music21), returns a list of the keys hits: [{‘time’:15, ‘note’:50} ,{... ]

Fork me on GitHub