Musical scales

Programming with musical scales can be assisted by a collection of functions in tabr that check and manipulate musical scales, modes and key signatures.

Key signatures

For key signatures, keys lists valid key signature abbreviation strings for each key as used in tabr. There are several key_is* functions that return a logical result regarding properties of keys:

There are also the functions, key_n_flats and key_n_sharps, that give the number of respective accidentals in a key signature.

keys()
#>  [1] "c"   "g"   "d"   "a"   "e"   "b"   "f#"  "c#"  "f"   "b_"  "e_" 
#> [12] "a_"  "d_"  "g_"  "c_"  "am"  "em"  "bm"  "f#m" "c#m" "g#m" "d#m"
#> [23] "a#m" "dm"  "gm"  "cm"  "fm"  "b_m" "e_m" "a_m"

key_is_flat("f")
#> [1] TRUE
key_n_flats("f")
#> [1] 1

The previous section gave an overview of noteworthy strings. While some of the functions that help enforce proper notation in R seemed like they did not offer much utility in terms of direct use, it was clear that they were integral to the robustness of other tabr functions. Now, looking at these key signature helpers, it may be tempting to dismiss their utility even more quickly because a trained musician does not need to invoke them at the command line to know what result they will return.

These functions are not provided to answer basic questions in an interactive R session so much as they are for programming. These are some of the initial building blocks on top of which more complex functions are built, including many functions in tabr. As the collection of music programming helper functions in tabr grows, it becomes easy to do more with less.

Scales

Several predefined musical scales are provided and accessible by calling various scale_* functions.

scale_hungarian_minor(key = "am", collapse = TRUE)
#> <Noteworthy string>
#>   Format: space-delimited time
#>   Values: a2 b2 c d# e f g#

You can specify whether the vector result should be returned as is, for convenient vectorized programming pipelines, or collapsed to a single string in keeping with the space-delimited time syntax format common throughout tabr. Many functions in tabr accept both formats as inputs and/or offer them as outputs.

You can also specify if octave numbering should be included or stripped. Octave numbering is included by default because this maintains pitch order when the scale does not start on C. Every note in a noteworthy string has an implicit octave-3 position if not explicitly stated. Octave numbering attempts to be somewhat balanced around C3. If the result is not what is desired, it can be shifted by 12 semitones with transpose.

scale_major("f", TRUE, ignore_octave = TRUE)
#> <Noteworthy string>
#>   Format: space-delimited time
#>   Values: f g a b_ c d e
scale_major("f", TRUE, ignore_octave = FALSE)
#> <Noteworthy string>
#>   Format: space-delimited time
#>   Values: f g a b_ c4 d4 e4

See help("scale-helpers") for details. Depending on the scale, other arguments are available.

Modes

The seven modern modes are also available with mode_* functions or through modern_mode by passing the mode string name. Other functions include is_mode and rotate_mode.

modes()
#> [1] "ionian"     "dorian"     "phrygian"   "lydian"     "mixolydian"
#> [6] "aeolian"    "locrian"
mode_aeolian("c")
#> <Noteworthy string>
#>   Format: vectorized time
#>   Values: c d e_ f g a_ b_

Diatonic scale chords

The scale_chords function provides a list of diatonic scale chords based on the root note and scale chosen. It returns triads by default and can also return seventh chords.

scale_chords("b_", "major", "seventh", collapse = TRUE)
#> <Noteworthy string>
#>   Format: space-delimited time
#>   Values: <b_2dfa> <ce_gb_> <dfac4> <e_gb_d4> <fac4e_4> <gb_d4f4> <ac4e_4g4>
scale_chords("f#", "minor", "triad", collapse = TRUE)
#> <Noteworthy string>
#>   Format: space-delimited time
#>   Values: <f#ac#4> <g#bd4> <ac#4e4> <bd4f#4> <c#4e4g#4> <d4f#4a4> <e4g#4b4>

Scale degrees

The functions scale_note and scale_degree map between notes and degree in a given scale. For chords in a noteworthy string, only the root note is considered. For scale_degree, if a note is not diatonic to the scale, NA is returned. For scale_note, degrees outside the range of the scale return NA.

note_in_scale can be used to check whether a note is diatonic to a scale. Unlike the other two functions, it strictly accepts single notes. This is more strict that a noteworthy check, which permits chords.

x <- "c e gb'd'"
scale_degree(x)
#> [1] 1 3 5
scale_degree(x, key = "a")
#> [1] NA  5 NA
scale_degree(x, key = "am")
#> [1] 3 5 7
scale_degree(x, scale = "chromatic")
#> [1] 1 5 8

scale_note(1:7, "d")
#> [1] "d"   "e"   "f#"  "g"   "a"   "b"   "c#4"
scale_note(c(1:8), "dm", "harmonic minor")
#> [1] "d"   "e"   "f"   "g"   "a"   "b_"  "d_4" NA

note_in_scale("a_ b c", "a_", ignore_octave = TRUE)
#> [1]  TRUE FALSE  TRUE

Other functions in tabr also work with scales and some build upon functions introduced here.

Musical intervals

Musical intervals can be referenced by a name or a numeric value defining the separation of two notes. interval_semitones returns a positive integer describing the number of semitones spanned by a common interval. It takes a name or abbreviation of a common interval as input. Essentially, any entry from any other column in the mainIntervals dataset can be used to obtain the interval in semitones. It’s a simple filter and match, but it is convenient to map between different representations of the same property in tabr without typing the extra bit of code to do so each time.

mainIntervals
#> # A tibble: 26 x 5
#>    semitones mmp            mmp_abb ad                               ad_abb
#>        <int> <chr>          <chr>   <chr>                            <chr> 
#>  1         0 perfect unison P1      diminished second                d2    
#>  2         1 minor second   m2      augmented unison                 A1    
#>  3         2 major second   M2      diminished third                 d3    
#>  4         3 minor third    m3      augmented second                 A2    
#>  5         4 major third    M3      diminished fourth                d4    
#>  6         5 perfect fourth P4      augmented third                  A3    
#>  7         6 tritone        TT      diminished fifth/augmented four~ d5/A4 
#>  8         7 perfect fifth  P5      diminished sixth                 d6    
#>  9         8 minor sixth    m6      augmented fifth                  A5    
#> 10         9 major sixth    M6      diminished seventh               d7    
#> # ... with 16 more rows

interval_semitones(c("m3", "M7"))
#> [1]  3 11

Likely more useful for programming, the function pitch_interval provides the number of semitones between two input notes. This function does not relate to specific scales, but is worth mentioning on the topic of interval helpers. It provides both magnitude and direction. The result is negative if the first note is of higher pitch than the second.

pitch_interval("c", "c,")
#> [1] -12
pitch_interval("a2", "c")
#> [1] 3

pitch_interval accepts a single note for each both note inputs, not sequences, nor chords.

Next is scale_interval. This function is similar to pitch_interval in that it takes a note for each of two arguments, which together define an interval. It is almost an inverse of interval_semitones except that you provide two distinct notes rather than the semitone distance they define. The function returns a main interval name or abbreviation from mainIntervals, depending on format.

scale_interval("c", "c,")
#> [1] "P8"
scale_interval("a2", "c", format = "mmp")
#> [1] "minor third"

There is not much else to these interval helper functions, but pitch_interval is leveraged extensively in support of more complex music programming.