Musical phrases

description syntax example
note/pitch a b … g a
sharp # a#
flat _ a_
drop or raise one octave , or ’ a, a a’
octave number 0 1 … a2 a3 a4
tied notes ~ a~ a
note duration 2^n 1 2 4 8 16
dotted note .
  1. 2..
slide - 2-
bend ^ 2^
staccato ] 2[
muted/dead note x 2x
slur/hammer/pull off () 2( 2)
rest r r
silent rest s s
expansion operator * ceg*8, 1*4


This section goes into deeper detail on building musical phrases out of individual notes using the various component parts available for phrase construction. It also describes how to add information, note metadata, to the notes in a phrase so that the phrase is defined unambiguously.

As mentioned in the last section, phrases in tabr do not require a strict definition. It is recommended to keep phrases short enough that they do not cause you difficulty dissecting them again visually. They should also represent meaningful or at least convenient segments of music, for example whole measures, a particular rhythm section, or an identifiable section of a longer solo.

Writing out music in R code is not intended to be any more readable than writing out LilyPond markup. The driving motivation here is a preference for avoiding writing LilyPond markup directly, aimed at people who specifically want to do this from R. Care must still be taken to not write phrases that are so long and complex that even you can not adequately parse their information by eye afterward.

The opening section showed a basic example using a single, and very simple, phrase. This section will cover phrases that include notes and rests of different duration, slides, hammer ons and pull offs, simple string bends, and various other elements. Phrases will become longer and more visually complex. There is no way around this fact. But with proper care they can be kept manageable and interpretable, depending on your comfort level with music theory, notation and R programming.

Before diving in, take a look at the table to the right for an overview of some syntax and operators that are used throughout this section.


The first argument to phrase is notes. Notes are represented simply by the lowercase letters c d e f g a b.

Sharps and flats

Sharps are represented by appending # and flats with _, for example a# or b_. In phrases and the various tabr functions that operate on them, these two-character notes are tightly bound and treated as specific notes just like single letters.

Space-delimited time

A string of notes is separated in time by spaces. Simultaneous notes are not. For example, "a b c" represents a sequence of notes in time whereas "ceg" represents simultaneously played notes of a C major triad chord. For now the focus will remain on individual notes. The end of this section includes a tiny chord example. Chords are discussed in more detail in later sections.

Unambiguous pitch

While it is allowable to specify note sequences such as "a b c", this assumes octave number 3. But this may not be what you intend and there is no reason to assume anything. In the example here, what is likely intended might be "a2 b2 c3".

This is the recommended way to specify notes and requires this level of familiarity with describing musical pitch. LilyPond markup uses single or multiple consecutive commas for lower octaves and single quote marks for higher octaves. This notation is permitted by tabr as well. In fact, if you specify integer suffixes for octave numbering, phrase will reinterpret these for you. The following are equivalent, as shown when printing the LilyPond syntax generated by phrase.

The second example here also shows the convenient multiplicative expansion operator * that can be used inside character strings passed to the three main phrase arguments. Use this wherever convenient, though this tutorial section will continue to write things out explicitly for increased clarity. Other operators like this one to help shorten repetitive code are introduced later.

phrase("c1 c2 c3 c4 c5", "1 1 1 1 1")
#> <c,,>1 <c,>1 <c>1 <c'>1 <c''>1
phrase("c,, c, c c' c''", "1*5")
#> <c,,>1 <c,>1 <c>1 <c'>1 <c''>1

For more extreme octaves, the latter style requires more typing and is more difficult to read. However, some may find it easier to read for chords like an open E minor "e,b,egbe'" compared to either "e2b2e3g3b3e4" or "e2b2egbe4".

In tabr the two formats are referred to as integer and tick octave numbering. Note that octave number three corresponds to the central (no comma or single quote tick) octave with the tick numbering style. This is why 3 can be left out and not a number you might otherwise have suspected like 1 or 0. c3 corresponds to the lowest C note on a standard tuned guitar: fifth string, third fret. The lowest note in standard tuning on a six string guitar is the low open E, which is e2. Octave numbering begins from C: ...B2 C3 C#3...

Time: the essential note metadata

Additional information about a note is passed to the second phrase argument, info. This enables removing ambiguities other than the pitch itself. For the moment, only time duration is introduced. A brief diversion from the info argument follows in order to cover rests, tied notes, and string specification; three important elements that can be described with phrase, but which are not actually passed via the info argument. Afterward, focus returns to info with more detailed coverage of the various note metadata that is supplied to phrase via info.


The most basic, and always required at a bare minimum, is the time duration of each note. Notes always have duration. The previous example showed a string of ones, info = "1 1 1 1 1", of equal length (in terms of space-delimited entries in the character string) to the first argument giving a sequence of five C notes from different octaves. These ones represent whole notes, lasting for an entire measure of music. Other possible integer values are 2, 4, 8, 16, 32 and 64, though most users probably won’t have reason to go beyond 16. The possible integers represent whole notes, half notes, quarter notes, eighth notes, sixteenth notes, etc.

The format is technically specifying the denominator. You might be inclined toward 1, 1/2, 1/4, etc., since the durations represent fractions of a single measure, not a total number of measures. This denominator shorthand where the implicit numerator is always one saves typing, but is also consistently with LilyPond itself. Below is an example using different durations. Entire songs are much longer and more complex and do not meaningfully benefit from piping, but for this and other short examples that follow, it is convenient so it will be used. Other arguments in tab are not relevant yet so for now just accept the defaults.

phrase("c3 d3 e3 f3 g3 a3 b3 c4 b3 c4", "16 16 8 8 4 4 8 2 2 1") %>% track %>% 
    score %>% tab("ex01.pdf")

Rests and ties

Rests and tied notes are actually part of the note argument. Both have duration, which is what belongs in info.

Rests are denoted by "r". In general, string specification is irrelevant for rests because nothing is played, so you can use a placeholder like x instead of a string number (see next section on string numbers). For the moment this example is not specifying the optional argument, string, so this can be ignored. Replacing some notes in the previous phrase with rests looks like the following.

phrase("r d3 e3 r g3 r b3 r b3 r", "16 16 8 8 4 4 8 2 2 1") %>% track %>% score %>% 

At first glance, tied notes might seem like something that ought to be described via info, but even though the note is only played once initially and not played second time where the tie ends, a tied note is still distinct from the note to which it is tied as far as notation is concerned.

For example, when tying a note over to a new measure, it must be included twice in notes. The tie is annotated on the original note with a ~ as follows.

phrase("r a2 b2 c3~ c3", "2 8 8 4 1") %>% track %>% score %>% tab("ex03.pdf")

The note is played once and last for one and a quarter measures, but is still annotated as one quarter note tied to one whole note.

Explicit string-fret combinations

Specifying the exact pitch is still ambiguous for guitar tablature because the same note can be played in different positions along the neck of a guitar. Tabs show which string is fretted and where. For example, in standard tuning, the same C3 note can be played on the fifth string, third fret, or on the sixth string, eighth fret. If left unspecified, most guitar tablature software will attempt to guess where to play notes on the guitar. This is not done by some kind of impressive, reliable artificial intelligence. It usually just means arbitrarily reducing notes to the lowest possible frets even if a combination of notes would not make sense or be physically practical for someone to play them that way.

There is one degree of freedom when the note is locked in but its position is not. It is not necessary to specify both the string number and the fret number. Providing one implicitly locks in the other. If you know the pitch and the string number, the fret is known. LilyPond accepts string numbers readily. To isolate these numbers from the info argument notation in phrase, they are provided in the third argument, string, which is also helpful because string is always optional.

Returning to the earlier phrase, without the rests, the equivalent phrase with explicit string numbers would have had string = "5 4 4 4 3 3 2 2 2 2". The second version with rests could have been provided as string = "x 4 4 x 3 x 2 x 2 x". Instead, play further up the neck beginning with C3 on the sixth string, eighth fret.

notes <- "c3 d3 e3 f3 g3 a3 b3 c4 b3 c4"
info <- "16 16 8 8 4 4 8 2 2 1"
strings <- "6 6 5 5 5 4 4 4 4 4"
phrase(notes, info, strings) %>% track %>% score %>% tab("ex04.pdf")

Some programs like LilyPond allow for specifying a minimum fret threshold, such that every note is played at that fret or above. This would work better for some songs than others of course. It is still not as powerful or ideal as being explicit about every note’s position. This threshold option is not currently supported by tabr. It is recommended to always be explicit anyway, as it leads to more accurate guitar tablature. There is a preponderance of highly inaccurate guitar tabs in the online world. Please do not add to the heap.

Note metadata continued

This section returns to the info argument to phrase with more examples of various pieces of note information that can be bound to notes.

Dotted notes

Note duration was introduced earlier, but incompletely. Dotted notes can be used to add 50% more time to a note. For example, a dotted quarter note, given by "4.", is equal in length to a quarter note plus an eighth note, covering three eighths of a measure. Double dotted may also be supplied. "2.." represents one half note plus one quarter note plus another eight note duration, for a total of 4 + 2 + 1 = 7 eighths of a measure.

A couple measures with no rests that contains dotted and double dotted notes might look like this.

phrase("c3 d3 e3 e3 e3 d3 c3", "4. 4. 8 8 2.. 8 1") %>% track %>% score %>% 

Dots are tightly bound in dotted notes. tabr treats these multi-character time durations as singular elements, just as it does for, say, sixteenth notes given by a "16".


Notes played staccato are specified by appending a closing square bracket directly on the note duration, e.g., altering "16" to "16]". This will place a dot in the output below notes that are played staccato.

phrase("c3 e3 g3 e3 c3", "8] 8] 8] 8] 2") %>% track %>% score %>% tab("ex06.pdf")

Muted or dead notes

Muted or dead notes are indicated by appending an "x" to a note duration, e.g., "8x".

phrase("c3 e3 g3 e3 c3", "8x] 8x] 8x] 8x] 2x") %>% track %>% score %>% tab("ex07.pdf")

Multiple pieces of information can be strung together for a single note. For example, combining a muted note with staccato can be given as "8x]". In this early version of tabr, do this with caution, as not all orderings of note information have been thoroughly tested yet. Duration always comes first though. Some pieces of information are not meant to go together either, such as a staccato note that must essentially be held rather than released, for the purpose of sliding to another note. Use human judgement. If you don’t ever see something in sheet music, it may not work in tabr either.

In this case, the example will work with "8x]" or "8]x". In fact, even accidentally leaving an extra staccato indicator in as "8]x]", which does undesirably alter the output of phrase, will still be parsed by LilyPond correctly. Nevertheless, stick closely to patterns shown in these examples if possible.


Slides are partially implemented. They work well in tabr when sliding from one note to another note. Slides to a note that do not begin from a previous note and slides from a note that do not terminate at subsequent note are not implemented. This is usually done with a bit of a hack in LilyPond by bending from or to a grace note and then making the grace note invisible. This hack or some another approach has not been ported to tabr.

phrase("c3 b2 c3 d3 e3 e3 d3 c3 b2 c3 c3 c4", "8- 8- 4 8- 8 8- 8 8- 8- 8 4.- 4", 
    "5*12") %>% track %>% score %>% tab("ex08.pdf")

As a brief aside, note the use of * above in the string argument to reduce typing. It is necessary to specify string here in order to ensure the notes are all on the fifth string in the output. Any space-delimited elements in phrase can take advantage of this terminal element notation for multiplicative expansion of an element. Terminal means that it must be appended to the end of whatever is being expanded; nothing can follow it. c*4 a*2 expands to c c c c a a inside phrase. 4.-*2 is replaced with 4.- 4.-. This convenient multiplicative expansion operator within character strings passed to phrase is available for the notes, info and string arguments.

Hammer ons and pull offs

Hammer ons and pull offs use the same notation and are essentially equivalent to slurs. They require a starting and stopping point. Therefore, they must always come in pairs. Providing an odd number of slur indicators will throw an error. The beginning of a slur is indicated using an open parenthesis, (, and the end of a slur is indicated with a closing parenthesis, ).

Editing the previous example, change some of the slides to hammer ons and pull offs.

notes <- glue("c3 b2 c3 d3 e3 e3 d3 c3 b2 c3 c3 c4", "c4 b3 c4 d4 e4 e4 d4 c4 b3 c4 c4 c5")
info <- dup("8( 8)( 4) 8( 8) 8( 8) 8 8( 8) 4.- 4", 2)
strings <- "5*12 3*12"
phrase(notes, info, strings) %>% track %>% score %>% tab("ex09.pdf")

Another brief aside: tabr has some helper functions that make your work a bit easier and your code a bit more legible, ideally both. Using meaningful separation helps keep the code relatively readable and easier to make changes to when you realize you made a mistake somewhere. Don’t write one enormous string representing an entire song. Aside from the avoiding code duplication where there is musical repetition, even something that might not repeat such as a guitar solo still benefits greatly from being broken up in to manageable parts.

glue is used above to combine both parts fed to notes rather than write a single character string. glue is a convenient function for joining strings in tabr. It’s a simple wrapper around paste that maintains space-delimitation as well as the phrase class when at least one element passed to glue is a phrase object. The string passed to info does not change between parts so it can be duplicated. Using the *n within-string operator from earlier does not apply here, but another function much like glue is dup. It is a wrapper around rep that is convenient in a tabr context. Like glue, it maintains the phrase class when applicable.

String bending

String bends are available but currently have a limited implementation in tabr and bend engraving in LilyPond itself is not fully developed. Specifying all kinds of bending, and doing so elegantly and yielding an aesthetically pleasing and accurate result, is immensely difficult. Bends are specified with a ^. Bend engraving does not look very good at the moment and control over how a bend is drawn and any associated notation indicating the number of semitones to bend is currently excluded.

In the example below, a half step bend-release-bend is attempted over the three B notes shown at the end of the first phrase. Because the string is only plucked one time, the first two B notes are tied through to the third. Since a tied note is a note, this is done in notes. The two bends are indicated with ^ on the first and third notes via info. A similar approach is taken with the second phrase, although with full step bends from G to A. In both cases, the initial bend is not a pre-bend, but should be very quick. None of these fine details can be provided with the current version of tabr.

notes <- glue("r a2 c3 f3 d3 a3 f3 b3~ b3~ b3", "r a3 c4 d4 a3 f4 d4 g4~ g4~ g4")
info <- dup("4 8 8 8 8 8 8 16^ 16 2..^", 2)
strings <- glue("x 5 5 4 4 3 4 3 3 3", "x 4 3 3 4 2 3 2 2 2")
phrase(notes, info, strings) %>% track %>% score %>% tab("ex10.pdf")

As you can see, the implementation is limited in tabr. It is also relatively difficult to achieve natively in LilyPond. The bends are different but the number of steps must be inferred from the key. The timing of bends and releases is challenging. The engraving is poor. But it is a start point.


Chords are covered in detail in later sections. For now, a brief example is given to more fully demonstrate the concept of space-delimited time and the use of simultaneous vs. sequential notes in tabr. The example below shows how to include some open C major chords inside notes. It is simply a matter of removing spaces. The tightly bound notes are simultaneous in time. info applies to the entire chord because it describes attributes of notes played at a given moment. There are obvious limitations to this though fortunately not hugely detrimental. string numbers are tightly bound for chords as well.

p1 <- phrase("c cegc'e' c3 c3e3g3c4e4", "4*4", "5 54321 5 5s")
track(p1) %>% score %>% tab("ex11.pdf")

It can be seen above that just like individual notes, chords can be specified using any combination of tick or integer octave numbering. They are equivalent. Tick style may be more readable for some. Leaving out the integer 3 can help for many chords. Note the shorthand string numbering, 5s, used for the second C chord. This is useful for bar chords. [n]s runs from n to 1.

This covers the detailed introduction to phrases. The next section will cover related helper functions, some of which have already been seen.