The central focus of tabr is the creation of guitar tablature and sheet music, but the package also provides a number of functions to support music programming more generally. Like the more focused music transcription-related functions, these functions also use tabr syntax so that they can still be leveraged for music transcription support, but their utility is not specific to transcription.

## Noteworthy strings

Before exploring these functions, it is worth introducing an important concept that is expressed throughout tabr: noteworthiness. Prior to construction of phrase class objects that can be passed to LilyPond for sheet music engraving, you start out with simple character strings. These strings contain letters representing musical notes, and possibly some other characters that indicate such things as sharps and flats, octave number, and rests.

There are a number of requirements strings must meet to have valid tabr syntax that can be transformed meaningfully and unambiguously into LilyPond syntax. In tabr parlance, a string is considered noteworthy if it meets all of these requirements that differentiate from arbitrary character strings.

There is no need to attach a special class to a character string to explicitly differentiate noteworthy strings from ordinary strings in R, though such a class exists (see below). It is fine to work with strings as usual and ignore this class. However, it is important to be familiar with the requirements of a noteworthy string so that you can construct them properly.

### Checking noteworthiness

A string can be checked directly with noteworthy.

x <- "a2 r b2*2 ce_g cd#g"
noteworthy(x)
#> [1] TRUE

noteworthy("h")
#> [1] FALSE


This reports whether the entire string conforms to all requirements for it to be valid tabr syntax.

### Optional noteworthy class

Functions in tabr that take noteworthy strings as input perform internal checks of noteworthiness for you and will throw an error if you provide an unworthy string. These checks are skipped if the input already has the noteworthy class. If a function returns a noteworthy string, the class will also be noteworthy.

This class is mostly used internally by a variety of functions, but otherwise this is an ephemeral class that is easily dropped when performing your own string manipulations. Users do not need to be directly concerned with the class. However, it is important to understand that the notion of noteworthy strings is implemented throughout tabr for the purpose of thorough and strict input validation. This leads to more robust function behavior and consistent user programming experience by rejecting problematic string input early.

as_noteworthy can be used to coerce to the noteworthy class. Coercion will fail if the string is not noteworthy. Using the noteworthy class is generally not needed by the user during an interactive session, but is available and offers its own print and summary methods for noteworthy strings.

x <- "a# b_*2 c, d'' e3*2 g_4 c2e_2g2*2"
x <- as_noteworthy(x)
x
#> <Noteworthy string>
#>   Format: space-delimited time
#>   Values: a# b_ b_ c, d'' e3 e3 g_4 <c2e_2g2> <c2e_2g2>


summary(x)
#> <Noteworthy string>
#>   Timesteps: 10 (8 notes, 2 chords)
#>   Octaves: ambiguous
#>   Accidentals: both/ambiguous
#>   Format: space-delimited time
#>   Values: a# b_ b_ c, d'' e3 e3 g_4 <c2e_2g2> <c2e_2g2>


### Stricter note and chord validation

noteworthy is built upon the more specific, vectorized functions is_note and is_chord, which provide more detailed information on the space-delimited entries in a string. is_note and is_chord return a logical vector reporting whether each entry contains a valid note or valid chord representation, respectively.

Notice how the vectorized results account for the expansion operator in b2*2.

x <- "a2 r b2*2 ce_g cd#g HELLO_WORLD"
is_note(x)
#> [1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE

is_chord(x)
#> [1] FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE


These functions serve simple enough purposes that you are unlikely to use them when writing tabs. However, these and many others can be highly useful when programming more complex musical manipulations.

## Notable phrases

Before moving on, briefly consider the quasi-counterpart to noteworthy strings: notable phrases. If you have used tabr, you are familiar with turning strings into phrases, assembling these phrases into tracks and scores, and sending them on to LilyPond to create sheet music. In this context, you might think of phrase objects as the fundamental unit of musical information and the strings from which you create them seem more like raw data.

tabr offers some ability to reverse direction and decompose phrases back into their component parts: notes, info and string character strings. This is done using notify, which returns a tibble data frame.

For complex phrases, this can be challenging. There should be no expectation of true one to one functional transformation. For example, notify is not complex enough to handle unfolding repeat sections or text notations attached to notes inside phrases. Certainly, this will not work for LilyPond syntax that was originally created in LilyPond rather than with tabr because tabr only provides access to a tiny fraction of what LilyPond can do. But in many simpler cases, you can successfully invert a phrase previously created from strings in R. Such a phrase is considered notable.

phrasey can be used to check if a string at least loosely resembled the content of a valid phrase object. Additional related functions are shown below, which takes a phrase through a complete cycle of deconstruction and reconstruction.

p1 <- phrase("b, c d ec'g'~ ec'g'", "4( 4)- 2*3", "5*3 432*2")
p1
#> <Musical phrase>
#> <b,\5>4( <c\5>4)\glissando <d\5>2 <e~\4 c'~\3 g'~\2>2 <e\4 c'\3 g'\2>2


x <- as.character(p1)
phrasey(x)
#> [1] TRUE

identical(as_phrase(x), p1)
#> [1] TRUE


notable(p1) # safe logical check
#> [1] TRUE

notify(p1)
#> # A tibble: 5 x 3
#>   notes    info  string
#>   <chr>    <chr> <chr>
#> 1 b,       4(    5
#> 2 c        4)-   5
#> 3 d        2     5
#> 4 e~c'~g'~ 2     432
#> 5 ec'g'    2     432


p2 <- p(phrase_notes(p1), phrase_info(p1), phrase_strings(p1))
identical(p1, p2)
#> [1] TRUE


With an understanding noteworthy strings, the next section covers a number of functions related to programming around musical scales.