Textbeat
🎹 plaintext music sequencer and midi shell, with vim playback and the powers of music theory 🥁
Install / Use
/learn @flipcoder/TextbeatREADME
textbeat
Plaintext music sequencer and interactive shell.
Write music in vim or your favorite text editor.
Open-source under MIT License (see LICENSE file for information)

Copyright (c) 2018 Grady O'Connell
- Project Board
- Vim integration: vim-textbeat
This project is still very new. Despite number of features, you may quickly run into issues, especially with editor integration.
Overview
Compose music in a plaintext format or type music directly in the shell. The format is vertical and column-based, similar to early music trackers, but with syntax inspired by jazz/music theory.
Features
Textbeat is still in development, but you can already do lots of cool things:
- Strumming
- Arpeggiation
- Tuplets and polyrhythms
- MIDI CC automation
- Vibrato, pitch, and mod wheel control
- Dynamics
- Accents
- Velocity
- Inversions
- Midi channel stacking
- Note length
- Delays
- Scales and modes by name
- Markers, repeats, callstack
Setup
Linux
git clone https://github.com/flipcoder/textbeat
cd textbeat
sudo python setup.py install
textbeat
Windows
git clone https://github.com/flipcoder/textbeat
cd textbeat
pip3 install -r requirements.txt
./txbt.cmd
Test it out!
Once you're in textbeat, try this:
maj&
If you don't hear 3 notes, you need to set up midi (this is the case with Linux).
How to set up midi
You can use the shell with General Midi out-of-the-box on windows, which is great for learning, but sounds bad without a decent soundfont.
If you want to use VST instruments, you'll need to route the MIDI out to something that hosts them, like a DAW. (I'm currently working on headless VST rack generation.)
For windows, you can use a virtual midi driver, such as loopMIDI for usage with a VST host or DAW.
If you're on Linux, you can use soundfonts through qsynth or use a software instrument like helm or dexed. I recommend qsynth.
VSTs should work here as well but you need to pick a host.
If you feed the MIDI into a DAW you'll be able to record the output through the DAW itself.
I'm currently looking into export options and recording via a headless host.
Tutorial
If you're familiar with trackers, you may pick this up quite easily.
First start by creating a .txbt (textbeat) file, inside the file music flows vertically, with separate columns that are separated by whitespace or manually setting a column width.
Each column represents a track, which defaults to separate midi channel numbers. Tracks play sequences of notes. You'll usually play at least 1 track per instrument. This doesn't mean you're limited to just one note per track though, you can keep notes held down and play chords as you wish.
Each cell row in a track can contain both note data and associated effects.
By default, any note event in a track will mute previous notes on that track
The following will play the C major scale using numbered notation:
; Major Scale -- this is a comment, write whatever you want here!
; 120bpm subdivided into 2 (i.e., eighth notes)
%t120 x2
1
2
3
4
5
6
7
1'
The tempo is in BPM, and the grid is based in subdivisions. Musicians can think of grid as fractions of quarter note, The grid is the beat/quarter-note subdivision.
Both Tempo and Grid can be decimal numbers as well.
For example, if you made some chords and you only want
one chord to be played per bar (eg 4 beats)
you could set %t120x0.25.
You can listen to what you've made by running:
textbeat <your file>
Consult the output of textbeat -h for further information.
Note Numbers
Both note numbers and letters are supported. This tutorial will use 1,2,3,4,5,6,7 instead of C,D,E,F,G,A,B. I'm a fan of thinking about notes without implying a key. For this reason, textbeat prefers the relative/transposed note numbers over arbitrary note names. If you're writing a song in D minor, you may choose to set the global or track key to D, making D note 1. (You could also set D to 6 if you're thinking modally) If this is confusing or not beneficial to you: don't worry, it's optional!
In this format, flats and sharps are prefixed instead of suffixed (b7 ("flat 7") instead of Bb ("B flat")).
Be aware that this flexibility introduces a few limits with chord names:
- B7 chords should not be written as 'b7', because this means flat 7
- 7 is a note when used alone, not a chord:
- Write it as dom7
- Alternatively write 1:7, R7, or C7
- 27 is not a 7 chord on 2, it's note 27
- Write it as 2:7 or 2dom7
Transposing Octaves
In the first example, the apostrophe character (') was used to play the note in the next octave. For an octave below, use a comma (,).
Repeat these for additional octaves (,,, for 3 down, '' for 2 up, etc).
To make octave changes persist, use a number for the octave count instead of repeating (,2).
Holding Muting
Notes will continue playing automatically, until they're muted or another note is played in the same track.
You can mute all notes in a track with -
To control releasing of notes, use dash (-).
; hold note 1 until next note
1
; auto-mute by specifying note value (*):
1*
; manually mute with '-'
1
-
Note durations can be manually controlled by adding * to increase value by powers of two, You can also add a fractional value to multiply this. These types of fraction values are used throughout textbeat. The opposite of this is the dot (.) which halves note values
; set note based on percentage (this means 30%)
1*3
; set note based on percentage (33%)
1*33
; set note based on percentage (33.3%)
1*333
; etc...
Now with dots for staccato:
1.
1..
1.30
Notes that are played in the same track as other notes mute the previous notes. In order to override this, hold a note by suffixing it with underscore (_).
A (-) character will then mute them all.
; Let's hold some notes
1_
3_
5_
7_
-
If you want to hold a series of notes like a sustain pedal, simply use two underscores (__) and all future notes will be held until a mute is received.
Chords
Unlike traditional trackers, you can write chords directly: 1maj or Cmaj. 1 ('C') is not required here. as chords without note names are positioned on 1 ('C') (ex. "maj" = "Cmaj" = "1maj"). Other shorthand names that work: "ma", "major", "M", or roman numeral "I"
Let's play a scale with some chords:
%t120 g2
1maj
2m
3m
4maj
5maj
6m
7dim
1maj'
There are lots of chords and voicings (check def/ files) and I'll be adding a lot more. All scales and modes are usable as chords, so arpeggiation and strumming is usable with those as well.
Remember: The note goes before the chord, so 7maj is a maj chord on note 7 (i.e. Bmaj), NOT a maj7.
Arpeggios and Strumming
Chords can be walked if they are suffixed by '&' Be sure to rest in your song long enough to hear it cycle.
maj&
After the &, you can put a number to denote the number of cycles. By default, it cycles infinitely until muted (or until the song ends)
The dollar sign is similar, but walks an entire set of notes within a single grid space:
maj$
Scales and modes are also accessible the same way:
dorian$
To strum, use the hold (_) symbol with this.
maj$_
Velocity and Accents
Use a ! or ? to accent or soften a note respectively.
You can use these on arpeggios as well.
1!
2?
3
4?
1!
2?
3
4?
Use values after accent to set a specific velocity:
1!! # 100%
1!90
2!75
3!5 # 50%
4!333 # 33.3%
5!05 # 5%
Note grouping
For readability, notes can be indented to imply downbeat or grouping
1
2
3
4
1
2
3
4
Volume
Usually you'll want to control velocity through accenting('!') or softening('?') or using values (!30 for 30%)
If you wish to control volume/gain directly, use @v
1maj@v9
-
1maj@v6
-
1maj@v4
-
1maj@v2
-
Unlike accents, volume changes persist.
Interpolation is not yet implemented
Vibrato, Pitch, and Mod Wheel
To add vibrato to a note, suffix it with a tilda (~).
Vibrato uses the mod wheel right now, but will eventually use pitch wheel oscillation.
In the future, articulation will be programmable, per-track or per-song.
Arpeggio Modulation
Notes of arpeggios can be modified as they're running, by having effects in the grid space they occur, for example:
maj7&
.?
.?
.?
!
.?
.?
.?
maj7& starts a repeating 4-note arpeggio, and we indent to show this.
Certain notes of the sequence are modulated with short/staccato '.', soft '?', and accent '!'
For staccato usage w/o a note name, an extra dot is required since '.' is simply a placeholder.
Tracks
Columns are separate tracks, line them up for more than one instrument.
The dots are placeholders.
1,2 1
. 4
. 5
. 1'
. 4'
. 5'
. 1''
Columns can be detected (in some cases), but you'll probably want to specify the column width manually at the top, which allows vim to mark the columns.
# sets column width to 8
%c=8
For best view in an editor, it is recommended that you offset the first column by -2:
# sets column width to 8, offset -2
%c=8,-2
Patches
Another useful global var is 'p', which sets midi patches by name or number across the tracks. The midi names support both patch numbers and partial case-insensitive matches of GM instruments.
%t120 x2 p=piano,guitar,bass,drums c8,-2
For a full list of GM names, see def/gm.yaml.
Tuplets
The 'T' (tuplet) gives us access to the musical concept of tuplets (called triplets in cases of 3). which allows note timing and durations to fall along a ratio instead of the usual note subdivisions.
Tuplets are marked by 'T' and have an o
