More tabr and LilyPond

Han Oostdijk

2020/01/03

Date last run: 05Jan2020

Introduction

To make life a little easier when using the tabr and Lilypond software I built the package tabraux with a few additional functions. When I asked a question to Matt Leonawicz about the insertion of an end bar he very nicely came up with a solution. In the follow up he had the following suggestions for (working with) the package:

  1. specifying an vector that gives the indices for which specific measures you want to insert a bar at (type of bar can also be a vector if different bars are required).
  2. check out the music class and as_music, it has a more efficient music data entry than how phrase requires up to three separate inputs, and phrase can take a music object as a single input to notes and nothing else needed.
  3. There are also time helper functions in tabr for computing cumulative durations in note info strings. These can be used to inform where new measures begin.
  4. It was a mistake on my part in early releases to promote integer format as the default and use it in lots of examples.
  5. recently the package has gained a lot of generic method implementations for various classes like phrase, making them much easier to concatenate, repeat, etc.

In this blog entry I tried to work with these suggestions in the following code. I will discuss them in the order presented above.

Using the suggestions

1. inserting ‘things’ into notes

At the moment the suggested method for inserting bar ends is not yet implemented. In the code below I have included a bar by using the sub function on the phrase that is contained in track1. This functionality is wrapped in the function tabraux::edit_phrase. I had to visually inspect the ‘phrase’ in track1 to find the point where to insert the ‘bar’ construct. In the suggested solution the measure where to insert the bar would have to be indicated.

I think a more general way (not restricted to measure endings) would be to allow for a ‘insert/anchor point’ indication in the notes. This would have to be a character that is not used until now in the notes: maybe ‘^’ or ‘!’ optionally followed by a sequence number (?). In a later stage the user could then more easily replace the occurrence(s) of the ‘insert point’ and in the lilypond function any remaining ‘insertion points’ should be removed.
Edit: in his answer Matt Leonawicz likes the general idea, but he is a little worried about the impact it could have on the non-LilyPond related functions.

In track2 I used the tabraux::edit_phrase to replace the full measure rests “r2.” by their invisible counterpart “s2.”. I would suggest that the character “s” is allowed to be used in phrases just like the “r” character.
Edit: Matt indicated this feature existed from the start. However it was not supported in the tabraux::expand_notes function in my own package :(

2. making more use of ‘music’

As can be seen below I now use the vx variables to gather the musical information. Apart from the fact that I can use these variables directly in the track function and the option for accidentals (the only place where this can be specified?) I see no further advantages in this use case. Do I miss something here?

3. time helper functions in tabr

I have not yet found these functions (?)
Edit: Matt pointed to Summarize rhythm and time of music objects .

4. integer format for octave indication

I do not see an advantage of the one (integer) method versus the other (tick) ?

5. generic methods

With my way of working (specifying notes and info as character strings) I see no need to use the generic functions.

Suggestions about the code below

If you have any comments about the code below, please let me know.

Code:

library(tabr)
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 | 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")
v1 <- to_music(notes, info,key="c",time="3/4",accidentals='sharp')
track1 <- track(p(v1,bar= ":|."),
                key = music_key(v1),voice = 1,tab=F)
track1 <-  tabraux::edit_phrase(track1," <g>4. <fis>8 <g>4 ", 
                " <g>4. <fis>8 <g>4 \\\\bar \":|.|:\" ",all=F)

notes <- pc(pn("r | ",3)," e3 |",pn("r | ",7)," r r f e | ", 
            pn("r | ",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(v2),
                key = music_key(v2),voice = 2,tab=F)
track2 <-  tabraux::edit_phrase(track2,'r2.','s2.',all=T)

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(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(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}).")

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

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

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

The resulting file sarabande1.png looks like:

Session Info

This document was produced on 05Jan2020 with the following R environment:

  #> 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