# More tabr and LilyPond with hook

## Introduction

In an earlier blog entry I suggested to allow an ‘insert/anchor/hook point’ in the notes in tabr that would make it easier to indicate where changes have to be made. In his GitHub answer Matt Leonawicz liked the general idea, but he was a little worried about the impact it could have on the non-LilyPond related functions and about the time that it would take to implement this. Following his suggestion

I do want to keep the “noise” of LilyPond/transcription-specific use cases isolated to the phrase-track-score-render_* pipeline of functions if possible.

I forked the package and adapted the phrase function. I will send Matt a PR request so that he can have a look at it and come up with improvements and suggestions. The remainder of this blog entry handles my experiences and gives a example of use.

### Update 13JAN2020

Matt Leonawicz has two types of objections to the proposed solution:

• it does not fit into the general flow because of the change I made to is_note . E.g. is_note("a ^1 b ^2 c") would indicate 5 valid notes.
This could be avoided by creating an is_note version internal to phrase that accepts a ^.
• he sees little use for the package producing Lilypond input and it is always possible to directly write a Lilypond input file.

I will try to include this functionality in some way in the tabraux package.

## Experiences and remarks

• I decided to use the ^ as the insert hook. Also ^1, ^2 etc. can be used.
• I got it working for the simple things I work with. See the last section of test_phrase.R for the cases that were tested.
• the is_note function and the .phrase function also had to be changed
• the as_music function also builds ‘phrases’ but not via the phrase function. I don’t know why a separate path is taken for this. One more reason to not touch this. So the insert hook will not work in ‘music’ and therefore in the following example the first track is not built from ‘music’ as was done before.
• the as_music function supports the accidentals argument. I did not find another way to specify this. In the example I use this as an opportunity to show how the hook can be used.
• the functions pc and pn now handle redundant whitespaces but this is not yet the case for the phrase (p) function.
• in the package no changes were made to version numbering and documentation
• a hook is considered in phrase as new ‘note’. The rule that the number of items in info and string should match the number of notes is still in force. So when info and string were specified before inserting the ^, then after insertion an extra info (e.g. 1) and string (e.g. x) should be coded. This extra information is ignored. I found no easy solution to avoid this.

## Example

The example is the same as in the previous blog entry. The difference is that in track1 I use the hook character to (later) insert the bar end. In the second part I show that the ‘ges’ notes can be changed in ‘fis’ notes by using the hooks.

## Code:

library(tabr) # in HOQC1 branch
library(tabraux)

to_music <- function (notes,info,key="c",time="3/4",accidentals=NULL) {
notes <- tabraux::expand_notes(notes)
info <- tabraux::check_times(info,steps=4)$times as_music(notes, info,key=key,time=time,accidentals=accidentals) } notes <- paste("e3 f g | g g a b | c4 c b3 | b | c4 d e | d c b3 | a f# g | g f# g ^ |", "d g f | e f g| r g d e f g | a f g | f g a b | c4 c b_3 | a g f | e g a |", "b_ f g | a | b g c4 | c b3 c4" ) info <- paste("4*3 | 4. 8*3 | 4 4. 8 | 2. | 4*3 | 4. 8 4 | 4*3 | 4. 8 4 1 | 4 4. 8 | 4. 8 4 |", "8*6 | 4. 8 4 |","4. 8*3 | 2( 8) 8 | 4*3 | 4. 8 4 | 4. 8 4 | 2. | 4. 8 4 | 4. 8 4") notes <- tabraux::expand_notes(notes) info <- tabraux::check_times(info,steps=4)$times

# as_music does not support the hook character!

track1 <- track(p(notes,info,bar= ":|."),
key = "c",voice = 1,tab=F)

track1 <-  tabraux::edit_phrase(track1,"\\^", " \\\\bar \":|.|:\" ",all=F)

notes <- pc(pn("s | ",3)," e3 |",pn("s | ",7)," r r f e | ",
pn("s | ",3),"e | d | d c d | d r g | f e |")
info  <- pc(pn("2. | ",3)," 2. |",pn("2. | ",7)," 4 8 4 8 | ",
pn("2. | ",3),"2. | 2.( | 4.) 8 4( | 4) 8 4. | 2 4 |")
v2 <- to_music(notes, info,key="c",time="3/4")
track2 <- track(p(music_notes(v2),music_info(v2)),
key = music_key(v2),voice = 2,tab=F)

notes <- paste("g3 f e | r g | r e ae | r g | a b c4 | b3 c4 d | c b3 | a g | r d g |",
"g f e f | g g d e | f g a | a g f | r g a b c4 | c4 b_3 a | g e f |",
"g d e | r f | f f e | d c" )
info  <- paste("4*3 | 4 2 | 8*2 2 | 4 2 | 4*3 | 4*3| 2 4 | 2 4 | 4*2 4( | 8) 8 4. 8 |",
" 4. 8*3 | 8*2 2 | 8*2 2 | 8*4 4( | 4) 4*2 | 4*3 | 4*3 | 4 2 | 4*3 | 2 4")
v3 <- to_music(notes, info,key="c",time="3/4")
track3 <- track(p(music_notes(v3),music_info(v3)),
key = music_key(v3),voice = 1,tab=F)

notes <- paste("c3 | b2d3 | a2 | e3 d |c | g | e d | d g2 | b | c3 | b_2 | a | d3 |",
"e | f | c | b_2 | f | g | g c3 |")
info  <- paste("2. | 2. | 2. | 2 4  | 2. | 2. | 4 2 | 2 4 | 2. | 2. | 2. | 2. | 2. |",
" 2. | 2. | 2. | 2. | 2. | 2. | 2 4")
v4 <- to_music(notes, info,key="c",time="3/4")
track4 <- track(p(music_notes(v4),music_info(v4)),
key = music_key(v4),voice = 2,tab=F)
song <- trackbind(track1,track2,track3,track4,id=c(1,1,2,2)) %>% score()

v = tabraux::lilypond_version()
t1 = "Adapted from Early Dances (Koeneman Music Budapest) p28."
tagline= glue::glue("{t1} Engraving by LilyPond (version {v}).")

opus="Louis Couperin",
tagline= tagline)
paper <- list(first_page_number =1,page_numbers=T,print_first_page_number=F,
textheight = 50,linewidth = 120)
filename = "sarabande2"
filetype = "png"


With the following statement we produce the file sarabande2.png :

tab(song, glue::glue("{filename}.{filetype}"),
key=music_key(v2), time=music_time(v2), tempo=NULL,
midi=F,keep_ly=F,details=F)


The resulting file sarabande2.png looks like:

I don’t like the ges notes that are produced in this sheet (in measures 7 and 8). When I worked with the as_music function to produce track1 I could indicate that I want accidentals to be sharps and here it apparently produces flats. There must be a way to specify this, but I could not find it. Therefore I will overwrite the two occurrences by the corresponding ‘fis’. This is done by replacing the two ‘f#’ in notes by resp. ‘^1’ and ‘^2’ and replacing these by the tabraux::edit_phrase function:

notes <- paste("e3 f g | g g a b | c4 c b3 | b | c4 d e | d c b3 | a ^1 g | g ^2 g ^ |",
"d g f | e f g| r g d e f g | a f g | f g a b | c4 c b_3 | a g f | e g a |",
"b_ f g | a | b g c4 | c b3 c4" )
info <- paste("4*3 | 4. 8*3 | 4 4. 8 | 2. | 4*3 | 4. 8 4 | 4*3 | 4. 8 4 1 | 4 4. 8 | 4. 8 4 |",
"8*6 | 4. 8 4 |","4. 8*3 | 2( 8) 8 | 4*3 | 4. 8 4 | 4. 8 4 | 2. | 4. 8 4 | 4. 8 4")
notes <- tabraux::expand_notes(notes)
info <- tabraux::check_times(info,steps=4)\$times

track1a <- track(p(notes,info,bar= ":|."),
key = "c",voice = 1,tab=F)
track1a <-  tabraux::edit_phrase(track1a,"\\^1", "<fis>4",all=F)
track1a <-  tabraux::edit_phrase(track1a,"\\^2", "<fis>8",all=F)
track1a <-  tabraux::edit_phrase(track1a,"\\^", " \\\\bar \":|.|:\" ",all=F)

song <- trackbind(track1a,track2,track3,track4,id=c(1,1,2,2)) %>% score()
filename = "sarabande2a"

tab(song, glue::glue("{filename}.{filetype}"),
key=music_key(v2), time=music_time(v2), tempo=NULL,
midi=F,keep_ly=F,details=F)


The resulting file sarabande2a.png shows the sharps:

## Session Info

This document was produced on 13Jan2020 with the following R environment. Note that the tabr package was used in the forked version branch HOQC1:

  #> R version 3.6.0 (2019-04-26)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 10 x64 (build 18362)
#>
#> Matrix products: default
#>
#> locale:
#> [1] LC_COLLATE=English_United States.1252
#> [2] LC_CTYPE=English_United States.1252
#> [3] LC_MONETARY=English_United States.1252
#> [4] LC_NUMERIC=C
#> [5] LC_TIME=English_United States.1252
#>
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base
#>
#> other attached packages:
#> [1] tabraux_0.0.2 tabr_0.4.1
#>
#> loaded via a namespace (and not attached):
#>  [1] Rcpp_1.0.3       crayon_1.3.4     dplyr_0.8.3      assertthat_0.2.1
#>  [5] R6_2.4.1         magrittr_1.5     evaluate_0.14    pillar_1.4.3
#>  [9] rlang_0.4.2      stringi_1.4.3    fs_1.3.1         tools_3.6.0
#> [13] stringr_1.4.0    glue_1.3.1       purrr_0.3.3      xfun_0.10
#> [17] compiler_3.6.0   pkgconfig_2.0.3  tidyselect_0.2.5 knitr_1.26
#> [21] tibble_2.1.3