Skip to content

Repository files navigation

Copyist

Turns what you played in a DAW into parts a band can read.

You write in a DAW. You play the parts in by hand, because that's how the music actually happens. Then you export MIDI, open it in notation software, and the page is unreadable. Sixty-fourth rests everywhere, tied rhythms nobody could count, accidentals fighting the key, both hands crushed onto one staff with the clef flipping mid-bar to cope.

Copyist replaces that second step.

It's built accessibility first, by and for a blind composer, on a premise that turns out to make the tool better for everybody: you can't proofread a page you can't see. So Copyist tells you in words what's on the page, lets you check it by ear, and verifies its own output instead of asking you to look.

Status: working prototype. It builds real charts end to end, with no other software installed. Matthew uses it for actual work. Nobody else has tried it yet, so you would be the first, and hearing what breaks for you would genuinely help. Parts of the design are still unbuilt, and those gaps are listed in the docs rather than glossed over.

It draws its own pages now

Copyist used to hand MusicXML to MuseScore and let MuseScore draw the page and play it back. As of September 2026 both of those live inside Copyist, and it needs no other software installed.

The engraver (prototype/chartengrave.py, pure standard library) draws every part and the conductor score straight to PDF. Staves, clefs, keys, meters, beams, ties, slurs, tuplets, articulations, ghost notes, slashes, rhythmic kicks, cues, lyrics with melisma lines, chord symbols, dynamics, rehearsal boxes, repeats, endings, one-bar repeat signs with the count over every fourth, and multirests that break wherever a player has to look up. A tie across a barline is one true arc, and one broken at a system turn draws its outgoing half to the edge and an incoming half to the landing note. Mid-chart key changes restate each part's own written signature right where they land. Hairpins draw on the dynamics lane and break open-ended at a system turn, the way an engraver continues one. Fermatas sit over notes and rests alike, and playback holds time there for the whole band at once.

Drum parts read like drum books. Point from demo at a played kit track and the page comes out in the two voices drummers expect: cymbals with x heads stems up, kick, snare and toms stems down. Open hats get the circle-x, the ride bell a diamond, ghost notes their parentheses, and durations read spacing rather than gate, so an eighth-note hat pattern prints as eighths and a lone crash gets a beat and rests. A bar identical to the one before it prints as the repeat sign. Hand percussion has its own staff dialect, from bongos and timbales to the shaker, and the read-aloud speaks drummer: "beat 3: eighth together, snare and closed hat." This was proved page against page with a professionally engraved drum book and a played take of the same music.

The conductor score reads like a working one. Landscape, with consecutive parts of a family (winds, brass, strings, voices, rhythm) sharing a bracket and their barlines running through the group. Staff names print in full once, then abbreviate. Every bar carries a boxed number, so nobody has to count to 37.

Pages are set in a real music font. Leland, MuseScore's OFL licensed SMuFL face, is embedded in every PDF Copyist draws. Jazz charts get MuseJazz Text, handwritten charts get Petaluma Script, everything else gets Edwin. Any character those faces can't draw, like a singer's kana or a Japanese subtitle, falls back to Noto Sans JP mid-run, and that font is embedded only when a page actually needs it. A lyric shouldn't vanish for being in the singer's own language.

The playback is Copyist's own too, which means silence is genuinely silent. The old renderer had an audible noise floor under empty bars.

Grace notes draw and play too, including inside a lifted engraving: small heads before their note, a slash through a crushed one, a run of them beamed, and in the listen a quick pickup landing on the beat. Nothing in a chart still needs MuseScore.

Trills and tremolos work for every instrument that plays them. Play a trill into your demo and the page writes one note with "tr" going to the exact note you played, half step to a major third; a fast repeated note becomes a tremolo, and a wide shake between two notes becomes a fingered tremolo. Typed, it's E5 h tr, tr minor 3rd, tr to D#5, trem or trem to C5. The page, the read-aloud and the listen all go to the same upper note.

Keyswitches become articulations. If your demo switches a string patch to pizzicato or a trumpet to a harmon mute, the page says so at that bar, and the switch notes never print as music. When you hit the switch is forgiving: hold a note as long as you like and fire a fall, shake or trill on it, or press a switch a little late, and the page still marks the note you meant. Maps for Logic's articulation sets and for common sample libraries are built in. For anything else, Name the keyswitches asks about each unnamed key once and remembers the answer for every chart that uses that patch.

Drum kits read as kits. Toontrack (EZdrummer, Superior Drummer) and Addictive Drums 2 note layouts are built in. For any other kit, Name the drum notes goes through the notes your take used and saves what you call them. Name the stroke too: a note you call "snare ghost" prints in parentheses, a flam gets its grace note, a rim shot a slashed head, a cymbal choke its comma. The read-aloud says each one.

What makes it different

The output is a chart, not a transcription. Every other tool in this space maximizes fidelity. That's the wrong goal when the reader is a player who's going to interpret the part anyway. Copyist throws detail away on purpose. Slashes, chord symbols, "groove as demo". For that reader, less is usually more useful.

Gate time means articulation, never rests. Letting go of a key 70ms early isn't a sixty-fourth rest. It's a staccato dot. That one rule removes most of the visual noise from a hand-played part.

Hands are separated by physics, not by a split point. Hand span, movement cost, continuity. Crossings come out right, because crossing is cheap when the hands are already close. A fixed split at middle C gets that wrong every time.

It emits MusicXML rather than MIDI. MIDI can't express voices, spelling, staff assignment, dynamics, articulation or pedal, so a MIDI workflow asks the notation program to invent all of it, and it invents badly.

It tells you what it did and what it's unsure about. Findings come severity first, each one carrying the settings change that would fix it, each one suppressible so the second run is quieter than the first.

It verifies itself. Output is rendered back to MIDI and diffed against the performance you played. That caught a bug in development that lost 33 notes while the page still looked perfect.

Every part comes out in braille too. A .brf file per part, in BANA's Music Braille Code 2015, 40 cells by 25 lines, with chord symbols on their own line under the notes; piano and organ in the bar-over-bar keyboard layout; sung parts in line-by-line format, words over music; a drum kit as a small score, one line per instrument. A separate reader reads each file back by the code's rules and checks it against the score, note by note, before the build keeps it. The braille can also be drawn as dots in a PDF for a sighted teacher or bandmate. The settings choose what a build makes: pages, the MP3, braille, braille drawn as dots, read-alouds, any mix.

The front door

Your first chart, from nothing. Three steps, no demo needed.

python3 prototype/chart.py first.chart new

Press Enter at the demo question, then answer the rest: title, key, meter, tempo, and who's in the band ("trumpet, tenor, piano, bass, drums"). A wrong answer just gets asked again.

python3 prototype/chart.py first.chart edit

Say the tune the way you'd tell the band: "blues in F, swing at 140, head twice, solos for everybody, head out". Copyist fills in the changes, gives each soloist a chorus, and writes the sections.

python3 prototype/chart.py first.chart

That builds everything and plays it back. From there, CHART-WRITING.md is the writer's guide.

Once you have a chart, one command does it all:

python3 prototype/chart.py yourtune.chart

There is also Copyist.app, a real Mac app over the same engine, built from app/ with app/build.sh --install. It has two designed looks, Dark Stage and Manuscript, or it can match the system. Same big actions as the CLI, a settings desk in plain groups where every control states its value, and the roadmap conversation held in a chat view. A build shows a real progress bar fed by the engine itself ("the band is playing it in, 46%"), and you can walk away from it: Home shows a live chip that takes you back, and File > New Window opens a second chart while the first one renders. Double-click a .chart in the Finder and it opens in the window in front. Export (Command E) and Emboss work from every tab and live in the Chart menu too; Emboss asks before anything goes to the embosser, and with none chosen it takes you straight to the Embosser setting. Settings also choose where finished files land, a folder each for PDF pages, listen MP3s and spoken read-alouds. The Sounds group installs the sample libraries you pick, wherever you want them, and the group called What the listen makes up switches each made-up part on or off. Export can also send a chart out as an iReal Pro link, a MIDI file of the band, or a plain chord sheet. The app and the terminal share one conversation engine over a JSON line protocol (COPYIST_PORCELAIN=1), so they can't drift apart. The engine and fonts are bundled inside the app, so it runs with nothing else installed. A checkout at ~/copyist wins at runtime, which keeps development live.

One command builds everything: the parts, the conductor score, a listening MP3, a read-aloud of every part, a findings file, and a written range report for each player. It also says what changed since your last build, by part and by bar, out loud. If nothing changed it says that too.

python3 prototype/chart.py yourtune.chart new --demo demo.mid

new interviews a starter chart into existence. It reads your demo first, offers the tempo and count-in it found, announces each track with its name, note count and range, and proposes octave corrections from register evidence.

python3 prototype/chart.py yourtune.chart edit

edit is the roadmap conversation. Describe the tune in one breath, like "in the key of E flat, gospel at 72, intro 4, verse 16, chorus 16, tag 8 open", and it writes the sections, asking one question at a time about only the gaps. It knows the common forms in any key: blues, minor blues, rhythm changes (which carves itself into A, A2, B, A3). It speaks Nashville numbers, so "two five one in C" lands as Dm7, G7, Cmaj7. It understands the bandstand: "bass walks, piano comps", "voice sings the melody", "horns hits on 1, 2+, 4". Chords can also arrive played, as a MIDI file of the changes that it names and reads back for your yes, or lifted from the demo's comping. On a chart that already has its form, edit opens the editing desk instead: change a section's chords or players, add or cut sections, set tempo and feel, or transpose the whole chart. A word it doesn't know gets asked about once and remembered in your vocabulary file for good. It never guesses.

python3 prototype/chart.py yourtune.chart listen --from-bar 65 --solo "bari,trombone"

Proof the ending without sitting through the whole tune, with only the two parts you're arguing about. Bar numbers are your DAW's, not the page's, because that's the number you have in your head.

check compiles without building. read speaks the chart. parts lists the band. diff re-speaks what changed. Every one has a one letter shortcut.

chart settings is the defaults desk: your composer name for new charts, a default look, a phone ping when a build lands, whether the score pops open. Every setting states what it is currently set to before you change it, because a screen reader user should never have to change something to learn what it was.

Bring in what you have

chart import FILE, or the app's Bring in a file card (drop anything on the window): a MusicXML or .mxl score becomes a chart with its band, sections, chords, key and tempo, every part's bars lifted exactly; a MIDI demo goes to the interview; words and chord sheets come in from any text format. On the author's own book, 27 of 27 scores import and compile clean, and 25 of 25 of the Sibelius example scores. Formats it can't read yet are refused in one sentence naming the way in.

The apps

Copyist.app (the app folder, described above) is the Mac front door. On Windows, the windows folder holds Copyist.bat, a menu in native Windows dialogs with the same settings and exports. It was written on a Mac and hasn't been run on real Windows yet; the README in that folder says so too.

The MIDI analysis underneath is still there and still standalone:

python3 prototype/analyze.py yourfile.mid
python3 prototype/convert.py yourfile.mid -o out.musicxml --key "C# minor"

Nothing is required beyond stock Python 3. The MIDI parser, the engraver and the audio are all standard library. ffmpeg is optional and only turns the listening WAV into an MP3. Without it you get the WAV, and Copyist tells you why and how to fix it.

The band

112 instruments, with the doubles. Woodwinds from piccolo through bari including english horn, alto flute and Eb clarinet. Brass including cornet, flugel, euphonium and both trombones. Strings, the keyboard family, all the mallets, timpani, six voice parts, drum set, and the entire percussion wing from three different cowbells to a vibraslap.

It speaks the gig's own slang. Kit, vibes, keys, rhodes, bone, bari, fiddle, upright bass, campana, darbuka. "Bells" means glockenspiel, because that's what it means in a band room.

Two rules run through every pitched instrument. Floors are hardware: below the horn's bottom note, Copyist folds the line up and tells you it did. Ceilings are chops: a high note gets flagged "lead territory, know whose chops are on the chair" and is never touched.

What the band plays

When a chart says solo, backgrounds, vamp, fill into bar 9, break, or how it ends, the listen plays it. Where a part has only slashes, the rhythm section makes up its own part from the chord symbols. The bass walks, the piano comps with both hands, and the drummer keeps time and sets up the next section. The pages keep their slashes, and each of these can be switched off in Settings.

An ending can be a hold, a trash can, a gliss into the last hit, a cadenza, or the drummer taking over and cueing the band in. When the roadmap doesn't say, the band decides in the moment. Every build is a fresh take, and the findings name it so you can keep one you like. The band plays tight unless a section says laid back, loose or on top.

The players learned from real ones. The walking bass comes from 48 transcribed professional lines, the soloists from 347 swing solos in the Weimar Jazz Database, the drummer from the Groove MIDI Dataset's jazz drummers, and the swing feel and the soloing pianist's left hand from the Jazz Trio Database. The scripts that measured them are in prototype/learn_*.py, and only the numbers ship. Credits are under License.

Verified results

On the included fixture, ten bars of two-hand piano, 110 notes:

Result
Round-trip note accuracy 100% onset and pitch
Phantom rests removed 42
Clef changes 0 (a plain MIDI import of comparable material produces six or more, mid-bar)
Humanized input vs click-locked input byte identical output, though humanize shatters every chord into separate events

The fixture is synthetic so the corpus carries no private music, but it was built to reproduce pathologies measured on real DAW exports. That includes the finding that REAPER's humanize moves notes independently and therefore breaks chords apart, which is reversible once you know to look for it (DESIGN.md §7.5.1).

Documentation

  • DESIGN.md: the full design, the locked decisions and the open questions. Read this before proposing anything.
  • CHART-FORMAT.md: the chart language, and an honest status of what's built.
  • CHART-WRITING.md: the writer's guide, in musician language, on an invented tune.
  • CONTRIBUTING.md: the rules. Accessibility first.
  • corpus/: test fixtures. Every bug becomes one of these.

Try it on something you played. If the page comes out wrong, that is worth knowing about, and a bad page is a better bug report than a description of one. Open an issue with the MIDI if you can share it, or with the findings file if you cannot.

License

MIT for the engine. Instrument data derived from MuseScore is GPL-3 and lives in a separate optional package, so the core stays reusable by anybody, commercial notation tools included. See DESIGN.md §17.

The band in the listen learned from real players. prototype/data/walking_stats.json holds statistics derived by prototype/learn_walking.py from FiloBass (Xavier Riley and Simon Dixon, Queen Mary University of London, ISMIR 2023), 48 transcribed professional walking bass lines, licensed CC BY 4.0 (https://zenodo.org/records/10069709). prototype/data/solo_stats.json comes from prototype/learn_solos.py over the Weimar Jazz Database 2.1 (Jazzomat Research Project, Hochschule für Musik Weimar): contains information from the Weimar Jazz Database, which is made available under the ODbL. prototype/data/timing_stats.json (the swing ratio at each tempo) comes from prototype/learn_timing.py over the Jazz Trio Database v0.2 (Huw Cheston et al., University of Cambridge), MIT licence. prototype/data/lefthand_stats.json comes from the same database's piano MIDI. prototype/data/drum_stats.json comes from prototype/learn_drums.py over the jazz swing grooves and fills of the Groove MIDI Dataset (Gillick, Roberts, Engel et al., Google Magenta), CC BY 4.0. Only the derived numbers ship here, not the transcriptions.

About

Accessibility-first charts from what you played: engraved parts, a real band to listen with, and read-alouds for every part. MIDI, MusicXML and chord sheets in; PDFs out.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages