You have already seen is_chord
, which is similar to is_note
. Another check you have seen is is_diatonic
. You can also check whether a chords are major or minor, but this is imperfect due to the inability to know if the user is interpreting their notation of a chord as an inversion. Instances where it is too difficult to tell, or inapplicable such as with single notes, return NA
.
#> [1] FALSE TRUE TRUE FALSE
#> [1] NA NA FALSE FALSE
#> [1] NA NA TRUE TRUE
A few functions that compare chords are chord_rank
, chord_order
and chord_sort
. Ranking chords, and the ordering and sorting based on that, requires a definition or set of definitions to work from.
The first argument is a noteworthy string. The second, pitch
, can be "min"
(the default), "mean"
, or "max"
. Each of these refers to the functions that operate on the three available definitions of ranking chords. When ranking individual notes, the result is fixed because there are only two pitches being compared. For chords, however, pitch = "min"
compares only the lowest pitch or root note of a chord. For pitch = "max"
, the highest pitch note in each chord is used for establishing rank. For pitch = "mean"
, the average of all notes in the chord are used for ranking chords.
Rank is from lowest to highest pitch. These options define how chords are ranked, but each function below also passes on additional arguments via ...
to the base functions rank
and order
for the additional control over the more general aspects of how ranking and ordering are done in R. chord_order
works analogously to chord_rank
. chord_sort
wraps around chord_order
.
#> [1] 1.5 4.5 1.5 4.5 4.5 4.5
#> [1] 1.5 3.0 1.5 4.5 4.5 6.0
#> [1] 1.5 3.0 1.5 5.0 4.0 6.0
#> [1] 1 3 2 4 5 6
#> [1] 1 3 2 5 4 6
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: a2 a2 c <ce_g> <ceg> <cea>
Chords can be sliced or indexed using the functions chord_root
, chord_top
and chord_slice
. The first two are special cases of chord_slice
. The first two functions return a noteworthy string containing only the root or top notes of each chord. If the string contains a single note, by definition the note is returned.
For chord_slice
, however, an integer index range is provided and it is possible to reduce a note or chord to nothing by passing indices that are completely out of bounds. Any note or chord that is completely sliced away is dropped.
The example below also shows that what matters is pitch order, not the order in which notes in a chord are entered in the string.
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: a, c c c,
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: a, g g c'
#> [1] TRUE
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: e e_ c
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: g
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: g g <egc'>
The slicing functions deal with position within a chord; they are not a simple reproduction of vector indexing of time steps, which is trivial and can already be done with note_slice
(clearly not slicing a single note, but a noteworthy string). Filtering the sequence rather than the elements within it is best done by taking the results of a function that returns a logical vector and passing them to note_slice
. This tends to fall under the topic of general noteworthy string functions and does not apply strictly to chords, but an example is shown here.
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: <e_gc> <egc,cc'>
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: <ceg> <e_gc> <egc,cc'>
A broken chord can be created with chord_break
, which separates a chord into its component notes, separating in time. It accepts a single chord.
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: c e_ g
chord_invert
creates chord inversions. It also takes a single chord as input. It treats any chord as being in root position as provided. The example below applies the function over a series of inversion values to show how the output changes.
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: <c2e_2g2> <e_2g2c> <g2ce_> <ce_g> <e_gc4> <gc4e_4> <c4e_4g4>
While a chord with n
notes has n - 1
inversions, chord_invert
allows inversions to continue, moving a chord further up or down in octaves. If you want to restrict the function to only allowing the defined number of inversions (excluding root position), set limit = TRUE
. This enforces the rule that, for example, a chord with three notes has two inversions and n
can only take values between -2
and 2
or it will throw and error.
Building up on chord_invert
, chord_arpeggiate
grows a chord up or down the scale in pitch by creating an arpeggio. n
describes how many steps to add onto the original chord. Setting by = "chord"
will replicate the entire chord as is, up or down the scale. In this case n
indicates whole octave transposition steps. By default, n
refers to the number of steps that individual chord notes are arpeggiated, like in chord_invert
. This means for example that in a chord with three notes, setting n = 3
and by = "note"
is equivalent to setting n = 1
and by = "chord"
.
The argument broken = TRUE
will also convert to a broken chord, resulting in an arpeggio of individual notes.
#> <Noteworthy string>
#> Format: vectorized time
#> Values: <ce_gb_> <e_gb_c4> <gb_c4e_4>
#> <Noteworthy string>
#> Format: vectorized time
#> Values: <ce_gb_> <b_2ce_g> <g2b_2ce_>
#> <Noteworthy string>
#> Format: vectorized time
#> Values: <ce_gb_> <c4e_4g4b_4> <c5e_5g5b_5>
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: c e_ g b_ e_ g b_ c4
Before introducing the chord constructors, here is a brief mention and example of the dyad
function for constructing dyads from a root note and and interval. Dyads are not always considered chords, but this is as good a place as any to mention dyad
since the key distinction made in tabr
in this context is whether there is a single note or multiple notes. The interval passed to dyad
can be in semitones, or a named interval from mainIntervals
that corresponds to the number of semitones.
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: <ac'>
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: <ac'> <ac'> <ac'> <ac'>
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: <ac'> <ac'> <ac'> <ac'>
Now to the topic of chord construction, there are two general forms of chord construction currently available in tabr
. The first is for typical chords based on their defining intervals; i.e., “piano chords”. These are not particularly useful for guitar-specific chord shapes and fingerings, which generally span a greater pitch range. See further below for guitar chords.
In tabr
chords are often constructed from scratch by explicitly typing the chord pitches in a noteworthy string, but many chords can also be constructed using helper functions. Currently, helpers exist for common chords up through thirteenths. tabr
offers two options for each chord constructor function name: the longer chord_*
-named function and its x*
alias. The table below shows all available constructors.
#> full_name abbreviation
#> 1 chord_min xm
#> 2 chord_maj xM
#> 3 chord_min7 xm7
#> 4 chord_dom7 x7
#> 5 chord_7s5 x7s5
#> 6 chord_maj7 xM7
#> 7 chord_min6 xm6
#> 8 chord_maj6 xM6
#> 9 chord_dim xdim
#> 10 chord_dim7 xdim7
#> 11 chord_m7b5 xm7b5
#> 12 chord_aug xaug
#> 13 chord_5 x5
#> 14 chord_sus2 xs2
#> 15 chord_sus4 xs4
#> 16 chord_dom9 x9
#> 17 chord_7s9 x7s9
#> 18 chord_maj9 xM9
#> 19 chord_add9 xadd9
#> 20 chord_min9 xm9
#> 21 chord_madd9 xma9
#> 22 chord_min11 xm11
#> 23 chord_7s11 x7s11
#> 24 chord_maj7s11 xM7s11
#> 25 chord_11 x_11
#> 26 chord_maj11 xM11
#> 27 chord_13 x_13
#> 28 chord_min13 xm13
#> 29 chord_maj13 xM13
These functions take root notes and a key signature as input. The given function determines the intervals of the chord. This in combination with a root note is all that is needed to create the chord. However, the key signature can enforce whether the result uses flats or sharps when accidentals are present.
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: <ac'e'g'> <ce_gb_> <egbd'>
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: <ac'e'g'> <ce_gb_> <egbd'>
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: <ac'e'g'> <ce_gb_> <egbd'>
The dataset guitarChords
is a tibble containing 3,967 rows of predefined guitar chords. It is highly redundant, but convenient to use. It is generated from a much smaller chords basis set, that is then transposed over all notes, yielding chord types and shapes for all twelve notes. Chords begin from open position and range up one octave to chords whose lowest fret is eleven. There are also multiple chord voicings for many chord types. Finally, chords containing accidentals are included in the table with both the flat and sharp versions.
There are twelve columns. Again, some of the column-wise information is also redundant, but it is not a big deal to include and removes the need to do a variety of computations to map from one representation of chord information to another. Here are the first ten rows:
#> # A tibble: 3,967 x 12
#> id lp_name root octave root_fret min_fret bass_string notes frets
#> <fct> <chr> <chr> <dbl> <dbl> <dbl> <int> <chr> <chr>
#> 1 M a,:5 a 2 0 0 5 a,ea~ xo22~
#> 2 M a,:5 a 2 0 0 5 a,ea~ xo22~
#> 3 m a,:m a 2 0 0 5 a,ea~ xo22~
#> 4 7 a,:7 a 2 0 0 5 a,eg~ xo2o~
#> 5 7 a,:7 a 2 0 0 5 a,eg~ xo2o~
#> 6 M7 a,:maj7 a 2 0 0 5 a,eg~ xo21~
#> 7 M7 a,:maj7 a 2 0 0 5 a,ea~ xo21~
#> 8 m7 a,:m7 a 2 0 0 5 a,eg~ xo2o~
#> 9 sus2 a,:sus2 a 2 0 0 5 a,ea~ xo22~
#> 10 sus4 a,:sus4 a 2 0 0 5 a,ea~ xo22~
#> # ... with 3,957 more rows, and 3 more variables: semitones <list>,
#> # fretboard <chr>, open <lgl>
You can also define your own chords using chord_def
. All you need are the fret numbers for the fretted chord. Currently it is assumed to be a six-string instrument. The default tuning is standard, but this can be changed arbitrarily. NA
indicates a muted string. Order is from lowest pitch string to highest. In the example below, create a set of minor chords based on the open Am
shape.
frets <- c(NA, 0, 2, 2, 1, 0)
chord_def(frets, "m", 6) # sixth entry (highest string: string #1) is optional
#> # A tibble: 1 x 13
#> id lp_name root octave root_fret min_fret bass_string notes frets
#> <chr> <chr> <chr> <int> <dbl> <dbl> <int> <chr> <chr>
#> 1 m a,:m a 2 0 0 5 a,ea~ xo22~
#> # ... with 4 more variables: semitones <list>, optional <chr>, fretboard <chr>,
#> # open <lgl>
guitarChords
does not currently contain the optional
column, but this is a column where you can indicate optional chord notes, as shown above.
chord_def
is scalar and defines a single chord, always returning a table with one row, but you can map over it however you need in order to define a collection of chords. Below, a set of chords is generated with sharps and again with flats.
#> # A tibble: 12 x 13
#> id lp_name root octave root_fret min_fret bass_string notes frets
#> <chr> <chr> <chr> <int> <dbl> <dbl> <int> <chr> <chr>
#> 1 m b_,:m b_ 2 1 1 5 b_,f~ x133~
#> 2 m b,:m b 2 2 2 5 b,g_~ x244~
#> 3 m c:m c 3 3 3 5 cgc'~ x355~
#> 4 m d_:m d_ 3 4 4 5 d_a_~ x466~
#> 5 m d:m d 3 5 5 5 dad'~ x577~
#> 6 m e_:m e_ 3 6 6 5 e_b_~ x688~
#> 7 m e:m e 3 7 7 5 ebe'~ x799~
#> 8 m f:m f 3 8 8 5 fc'f~ x8(1~
#> 9 m g_:m g_ 3 9 9 5 g_d_~ x9(1~
#> 10 m g:m g 3 10 10 5 gd'g~ x(10~
#> 11 m a_:m a_ 3 11 11 5 a_e_~ x(11~
#> 12 m a:m a 3 12 12 5 ae'a~ x(12~
#> # ... with 4 more variables: semitones <list>, optional <lgl>, fretboard <chr>,
#> # open <lgl>
#> # A tibble: 12 x 13
#> id lp_name root octave root_fret min_fret bass_string notes frets
#> <chr> <chr> <chr> <int> <dbl> <dbl> <int> <chr> <chr>
#> 1 m b_,:m b_ 2 1 1 5 b_,f~ x133~
#> 2 m b,:m b 2 2 2 5 b,g_~ x244~
#> 3 m c:m c 3 3 3 5 cgc'~ x355~
#> 4 m d_:m d_ 3 4 4 5 d_a_~ x466~
#> 5 m d:m d 3 5 5 5 dad'~ x577~
#> 6 m e_:m e_ 3 6 6 5 e_b_~ x688~
#> 7 m e:m e 3 7 7 5 ebe'~ x799~
#> 8 m f:m f 3 8 8 5 fc'f~ x8(1~
#> 9 m g_:m g_ 3 9 9 5 g_d_~ x9(1~
#> 10 m g:m g 3 10 10 5 gd'g~ x(10~
#> 11 m a_:m a_ 3 11 11 5 a_e_~ x(11~
#> 12 m a:m a 3 12 12 5 ae'a~ x(12~
#> # ... with 4 more variables: semitones <list>, optional <lgl>, fretboard <chr>,
#> # open <lgl>
The most interesting use of guitarChords
is in using it to map from chord names to noteworthy strings.
gc_info
can be used to filter guitarChords
. In the examples below, you can see that multiple chord names can be supplied at once. All are used to filter the chord dataset. If the inputs do not exist, an empty tibble with zero rows is returned. The result is not vectorized to match the number of entries in the input; it is simply a row filter for guitarChords
.
#> # A tibble: 6 x 12
#> id lp_name root octave root_fret min_fret bass_string notes frets
#> <fct> <chr> <chr> <dbl> <dbl> <dbl> <int> <chr> <chr>
#> 1 M a,:5 a 2 0 0 5 a,ea~ xo22~
#> 2 M a,:5 a 2 5 5 6 a,ea~ 5776~
#> 3 M a,:5 a 2 5 2 6 a,d_~ 5422~
#> 4 M a:5 a 3 7 7 4 ae'a~ xx79~
#> 5 M a:5 a 3 12 12 5 ae'a~ x(12~
#> 6 M a:5 a 3 12 9 5 ad_'~ x(12~
#> # ... with 3 more variables: semitones <list>, fretboard <chr>, open <lgl>
#> # A tibble: 6 x 12
#> id lp_name root octave root_fret min_fret bass_string notes frets
#> <fct> <chr> <chr> <dbl> <dbl> <dbl> <int> <chr> <chr>
#> 1 m7_5 b_,:m7~ b_ 2 1 0 5 b_,a~ x1x1~
#> 2 m7_5 b_,:m7~ b_ 2 1 1 5 b_,e~ x121~
#> 3 m7_5 b_,:m7~ b_ 2 6 5 6 b_,a~ 6x66~
#> 4 m7_5 b_:m7_5 b_ 3 8 4 4 b_d_~ xx86~
#> 5 m7_5 b_:m7_5 b_ 3 8 8 4 b_e'~ xx89~
#> 6 m7_5 b_:m7_5 b_ 3 13 12 5 b_a_~ x(13~
#> # ... with 3 more variables: semitones <list>, fretboard <chr>, open <lgl>
#> # A tibble: 6 x 12
#> id lp_name root octave root_fret min_fret bass_string notes frets
#> <fct> <chr> <chr> <dbl> <dbl> <dbl> <int> <chr> <chr>
#> 1 m7_5 b_,:m7~ b_ 2 1 0 5 b_,a~ x1x1~
#> 2 m7_5 b_,:m7~ b_ 2 1 1 5 b_,e~ x121~
#> 3 m7_5 b_,:m7~ b_ 2 6 5 6 b_,a~ 6x66~
#> 4 m7_5 b_:m7_5 b_ 3 8 4 4 b_d_~ xx86~
#> 5 m7_5 b_:m7_5 b_ 3 8 8 4 b_e'~ xx89~
#> 6 m7_5 b_:m7_5 b_ 3 13 12 5 b_a_~ x(13~
#> # ... with 3 more variables: semitones <list>, fretboard <chr>, open <lgl>
#> # A tibble: 23 x 12
#> id lp_name root octave root_fret min_fret bass_string notes frets
#> <fct> <chr> <chr> <dbl> <dbl> <dbl> <int> <chr> <chr>
#> 1 m a,:m a 2 0 0 5 a,ea~ xo22~
#> 2 m a,:m a 2 5 5 6 a,ea~ 5775~
#> 3 m a,:m a 2 5 2 6 a,cea 5322~
#> 4 m a:m a 3 7 7 4 ae'a~ xx79~
#> 5 m a:m a 3 12 12 5 ae'a~ x(12~
#> 6 m a:m a 3 12 9 5 ac'e~ x(12~
#> 7 M c:5 c 3 3 3 5 cgc'~ x355~
#> 8 M c:5 c 3 3 0 5 cegc~ x32o~
#> 9 M c:5 c 3 8 8 6 cgc'~ 8(10~
#> 10 M c:5 c 3 8 5 6 cegc~ 8755~
#> # ... with 13 more rows, and 3 more variables: semitones <list>,
#> # fretboard <chr>, open <lgl>
The same properties of gc_info
apply to wrapper functions around it, namely, gc_notes
and gc_fretboard
.
gc_notes
takes chord names that exist in guitarChords
and returns the noteworthy strings needed for phrase construction. Remember, the is just a basic filter. If you specify chords imprecisely, the result will contain many more chords than were in the input. If you specify chords completely unambiguously, then there is one result for each input. However, this also requires you do not provide any chord names that are not in guitarChords
, or these will be dropped.
Keep in mind that these functions are under active development and the approaches they take may change prior to the next CRAN release of tabr
. Currently, the ways you can add precision to your chord mapping include passing the following optional arguments:
root_octave
: the octave number for the root note.root_fret
: the fret for the root note.min_fret
: the lowest fret position for a chord.bass_string
: the lowest unmuted string for a chord.open
: open chords, closed/movable chords, or both (default).key
: key signature, to enforce sharps or flats when present.In this example, possible matches from guitarChord
are filtered to any whose root fret is in 0:2
.
#> <Noteworthy string>
#> Timesteps: 2 (0 notes, 2 chords)
#> Octaves: tick
#> Accidentals: flat
#> Format: space-delimited time
#> Values: <a,egd_'e'> <b,g_bd'g_'>
Notice that the octave information helps further restrict the chord set with ignore_octave = FALSE
.
When creating tablature and sheet music with LilyPond, you may wish to include a chord chart containing fretboard diagrams of the chords as they are played. Currently, tabr
uses the chord_set
function to prepare a named character vector of chords that have quasi-LilyPond chord names and fretboard notation values, ready to be passed to score
for proper injection into LilyPond.
This process and the structure of the data objects involved may change soon (I have not decided for certain yet). But for the time being, this is still the process. Therefore, the new function gc_fretboard
performs the same manipulation using chords from guitarChords
.
#> a,:m c:5 d:5 f,:5
#> "x;o;2;2;1;o;" "x;3;2;o;1;o;" "x;x;o;2;3;2;" "1;3;3;2;1;1;"