Date last run: 13Jan2020
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 anis_note
version internal tophrase
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 thephrase
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 theaccidentals
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
andpn
now handle redundant whitespaces but this is not yet the case for thephrase
(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 ininfo
andstring
should match the number ofnotes
is still in force. So wheninfo
andstring
were specified before inserting the^
, then after insertion an extrainfo
(e.g.1
) andstring
(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}).")
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 = "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,
string_names=T,header=header,paper=paper,
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,
string_names=T,header=header,paper=paper,
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