summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/recorder-fingering/recorder-fingering.sty
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/recorder-fingering/recorder-fingering.sty')
-rw-r--r--macros/latex/contrib/recorder-fingering/recorder-fingering.sty355
1 files changed, 355 insertions, 0 deletions
diff --git a/macros/latex/contrib/recorder-fingering/recorder-fingering.sty b/macros/latex/contrib/recorder-fingering/recorder-fingering.sty
new file mode 100644
index 0000000000..6c5f447f72
--- /dev/null
+++ b/macros/latex/contrib/recorder-fingering/recorder-fingering.sty
@@ -0,0 +1,355 @@
+%%
+%% This is file `recorder-fingerings.sty'
+% Copyright 2023 by Alan Munn
+%
+% This package provides a single command to produce a fingering
+% diagram for any not in the playable range of the recorder.
+%
+% This package may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or any later version.
+% The latest version of this license is in
+% http://www.latex-project.org/lppl.txt
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% This package has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this package is Alan Munn.
+%
+% This package consists of the file
+%
+% recorder-fingering.sty
+%
+% and documentation files:
+%
+% recorder-fingering.tex, recorder-fingering.pdf
+%
+% Version 1.0 2023/02/17
+\NeedsTeXFormat{LaTeX2e}[2022/11/01]
+\ProvidesPackage{recorder-fingering}[2023/02/17 v1.0 Recorder fingering diagrams]
+\RequirePackage{tikz}
+\usetikzlibrary{calc}
+\RequirePackage{graphicx}
+% Split node code from
+% https://tex.stackexchange.com/a/657282/2693
+% These styles are local to the package
+\pgfkeys{/fingering/.style={
+ node split radius/.initial=1,
+ node split color 1/.initial=white,
+ node split color 2/.initial=black,
+ node split color 3/.initial=blue,
+ node split half/.style={node split={##1,##1+180}},
+ node split/.style args={##1,##2}{
+ path picture={
+ \tikzset{
+ x=($(path picture bounding box.east)-(path picture bounding box.center)$),
+ y=($(path picture bounding box.north)-(path picture bounding box.center)$),
+ radius=\pgfkeysvalueof{/tikz/node split radius}}
+ \foreach \ang[count=\iAng, remember=\ang as \prevAng (initially ##1)] in {##2,360+##1}
+ \fill[line join=round, draw, fill=\pgfkeysvalueof{/tikz/node split color \iAng}]
+ (path picture bounding box.center)
+ --++(\prevAng:\pgfkeysvalueof{/tikz/node split radius})
+ arc[start angle=\prevAng, end angle=\ang] --cycle;
+} },
+hole/.style={circle,draw,##1},
+1/.style={fill=black}, % closed hole
+0/.style={fill=none}, % open hole
+t/.style={node split half=0}, % thumb half hole
+h/.style={node split half=-90}, % finger half hole
+top double/.style={circle,minimum size=7pt,inner sep=0pt,draw,##1},
+bottom double/.style={circle,minimum size=6pt,inner sep=0pt,draw,##1},
+}}
+\ExplSyntaxOn
+
+
+% Error messages
+\msg_new:nnnn {recorder-fingering}{too-few}{\\You\ haven't\ provided\ enough\ holes!}{Fingerings\ must\ specify\ all\ 8\ holes\ (thumb\ +\ all\ 7\ fingers)}
+\msg_new:nnnn {recorder-fingering}{key-exists}{\\This\ fingering\ is\ already\ defined!}{Use\ the\ starred\ version\ of\ the\ command\ or\ \token_to_str:N \AddFingerings\ instead\ to\ override\ existing\ fingerings.}
+\msg_new:nnnn {recorder-fingering}{wrong-instrument}{\\This\ command\ only\ permits\ F\ and\ C\ fingerings!}{}
+\msg_new:nnnn {recorder-fingering}{deprecated}{\\This\ command\ is\ deprecated.\ Please\ use\ \token_to_str:N \alto\ or\ \token_to_str:N \soprano\ instead.}{}
+
+% Command parameters
+\keys_define:nn {fingering}{
+ thumboffset.bool_set:N = \g_fingering_thumboffset_bool,
+ width.dim_set:N = \g_fingering_size_dim,
+ thumboffset.initial:n = {true},
+ width.initial:n = {20pt}
+}
+\keys_define:nn {fingering / command}{
+ thumboffset.bool_set:N = \g_fingering_command_thumboffset_bool,
+ width.dim_set:N = \l_fingering_command_size_dim,
+}
+\NewDocumentCommand{\fingeringSetup}{m}{
+ \keys_set:nn {fingering} {#1}
+}
+
+% Manage the thumb offset parameters
+\tl_set:Nn \g_fingering_thumboffset_x {-.5}
+\tl_set:Nn \g_fingering_thumboffset_y {-.25}
+\cs_new:Nn \fingering_offset_reset:
+{\tl_gset:Nn \g_fingering_thumboffset_x {-.5}
+\tl_gset:Nn \g_fingering_thumboffset_y {-.25}
+}
+\cs_new:Nn \fingering_offset_zero:
+{\tl_gset:Nn \g_fingering_thumboffset_x {0}
+\tl_gset:Nn \g_fingering_thumboffset_y {0}
+}
+\cs_new:Nn \fingering_set_thumboffset: {
+\bool_if:nTF {\g_fingering_command_thumboffset_bool}
+ {\fingering_offset_reset:}
+ {\fingering_offset_zero:}
+}
+
+% Set up the property lists for F and C fingerings
+\prop_new:N \l_fingering_F_prop
+\prop_new:N \l_fingering_C_prop
+% Set up transposition tables for later
+\prop_new:N \l_fingering_C_to_F_prop
+\prop_new:N \l_fingering_F_to_C_prop
+
+% Set up the clists for the fingering vectors themselves
+\clist_new:N \l_fingering_fing_clist
+\clist_new:N \l_fingering_topholes_clist
+
+
+% Generic fingering generator: takes a clist, splits it between top holes and bottom holes
+% and produces the corresponding diagram
+% basic idea for splitting the clist using step_inline and pop from Jonathan P. Spratte (Skillmon)
+
+\cs_new_protected:Nn \fingering_generate_fingering:n
+{
+\clist_set:Nn \l_fingering_holes_clist {#1}
+ \clist_clear:N \l_fingering_topholes_clist
+ \int_step_inline:nn { 6 } {
+ \clist_pop:NNF \l_fingering_holes_clist \l_tmpa_tl { \msg_error:nn { recorder-fingering } { too-few }}
+ \clist_put_right:NV \l_fingering_topholes_clist \l_tmpa_tl }
+ \resizebox{\l_fingering_command_size_dim}{!}{
+ \begin{tikzpicture}[/fingering]
+% display the topholes
+ \fingering_set_thumboffset:
+ \foreach[expand~list]~\x~[count=\xi]~in~\l_fingering_topholes_clist {
+ \node[hole=\x]~at~(0+\g_fingering_thumboffset_x,-\xi/2+\g_fingering_thumboffset_y)~{};
+ \fingering_offset_zero:}
+% display the bottom two paired holes
+ \clist_pop:NN \l_fingering_holes_clist \l_tmpa_tl
+ \int_case:nnTF {\l_tmpa_tl}{
+ {0} {\node[top~double=0]~at~(.15,-7/2)~{};
+ \node[bottom~double=0]~at~(-.15,-7.15/2)~{};}
+ {2} {\node[top~double=1,]~at~(.15,-7/2)~{};
+ \node[bottom~double=1]~at~(-.15,-7.15/2)~{};}
+ {1} {\node[top~double=1]~at~(.15,-7/2)~{};
+ \node[bottom~double=0]~at~(-.15,-7.15/2)~{};}
+ }
+ {}
+ {}
+ \clist_pop:NN \l_fingering_holes_clist \l_tmpa_tl
+ \int_case:nnTF {\l_tmpa_tl}{
+ {0} {\node[top~double=0,]~at~(.15,-8/2)~{};
+ \node[bottom~double=0]~at~(-.15,-8.15/2)~{};}
+ {2} {\node[top~double=1,]~at~(.15,-8/2)~{};
+ \node[bottom~double=1]~at~(-.15,-8.15/2)~{};}
+ {1} {\node[top~double=1,]~at~(.15,-8/2)~{};
+ \node[bottom~double=0]~at~(-.15,-8.15/2)~{};}
+ }
+ {}
+ {}
+% display the bell hole if present
+ \clist_if_empty:NTF \l_fingering_holes_clist
+ {}
+ {\clist_pop:NN \l_fingering_holes_clist \l_tmpa_tl
+ \node[hole=\l_tmpa_tl]~at~(0,-9/2)~{};}
+ \end{tikzpicture}}
+ }
+
+% create variable version of the command
+\cs_generate_variant:Nn \fingering_generate_fingering:n { V }
+
+
+% Main user commands and synonyms
+% First basic commands to display the fingering for any note
+\NewDocumentCommand{\Alto}{om}{
+\IfNoValueTF{#1}
+ {\keys_set:nn {fingering / command} {width = \g_fingering_size_dim}
+ \bool_set_eq:NN {\g_fingering_command_thumboffset_bool}{\g_fingering_thumboffset_bool}}
+ {\bool_set_eq:NN {\g_fingering_command_thumboffset_bool}{\g_fingering_thumboffset_bool}
+ \keys_set:nn {fingering /command } {#1}}
+ \prop_get:NnN \l_fingering_F_prop {#2} \l_tmpa_tl
+ \fingering_generate_fingering:V \l_tmpa_tl
+}
+\cs_set_eq:NN \Sopranino \Alto
+\cs_set_eq:NN \Bass \Alto
+
+\NewDocumentCommand{\Soprano}{om}{
+\IfNoValueTF{#1}
+ {\keys_set:nn {fingering / command} {width = \g_fingering_size_dim}
+ \bool_set_eq:NN {\g_fingering_command_thumboffset_bool}{\g_fingering_thumboffset_bool}}
+ {\bool_set_eq:NN {\g_fingering_command_thumboffset_bool}{\g_fingering_thumboffset_bool}
+ \keys_set:nn {fingering /command } {#1}}
+ \prop_get:NnN \l_fingering_C_prop {#2} \l_tmpa_tl
+ \fingering_generate_fingering:V \l_tmpa_tl
+}
+\cs_set_eq:NN \Tenor \Soprano
+
+% Now commands to add new fingerings:
+% First, a note = { } version for multiple fingerings
+% This command will override existing fingerings
+\NewDocumentCommand{\AddFingerings}{mm}{
+ \str_case:nnTF {#1}{
+ {F} {\prop_put_from_keyval:Nn \l_fingering_F_prop {#2}}
+ {C}{\prop_put_from_keyval:Nn \l_fingering_C_prop {#2}}
+ }
+ {}
+ {\msg_error:nn { recorder-fingering }{ wrong-instrument}}
+}
+
+% Second individual fingerings for alto and soprano
+% These commands will throw an error if the note is already defined
+\NewDocumentCommand{\NewFfingering}{smm}{
+\IfBooleanTF{#1}
+ {\prop_put:Nnn \l_fingering_F_prop {#2} {#3}}
+ {\prop_get:NnNTF \l_fingering_F_prop {#2} \tl_tmpa_tl
+ {\msg_error:nn { recorder-fingering } { key-exists }}
+ {\prop_put:Nnn \l_fingering_F_prop {#2} {#3}}
+ }}
+
+\NewDocumentCommand{\NewCfingering}{smm}{
+\IfBooleanTF{#1}
+ {\prop_put:Nnn \l_fingering_C_prop {#2} {#3}}
+ {\prop_get:NnNTF \l_fingering_C_prop {#2} \tl_tmpa_tl
+ {\msg_error:nn { recorder-fingering } { key-exists }}
+ {\prop_put:Nnn \l_fingering_C_prop {#2} {#3}}
+ }}
+
+% Now add all of the basic fingerings
+\AddFingerings{F}{
+ F = {1,1,1,1,1,1,2,2},
+ Gb = {1,1,1,1,1,1,2,1},
+ G = {1,1,1,1,1,1,2,0},
+ Ab = {1,1,1,1,1,1,0,0},
+ A = {1,1,1,1,1,1,0,0},
+ Bb = {1,1,1,1,1,0,2,2},
+ B = {1,1,1,1,0,1,2,0},
+ C = {1,1,1,1,0,0,0,0},
+ Db = {1,1,1,0,1,1,1,0},
+ D = {1,1,1,0,0,0,0,0},
+ Eb = {1,1,0,1,1,0,0,0},
+ E = {1,1,0,0,0,0,0,0},
+ f = {1,0,1,0,0,0,0,0},
+ gb = {0,1,1,0,0,0,0,0},
+ g = {0,0,1,0,0,0,0,0},
+ ab = {0,0,1,1,1,1,2,0},
+ a = {t,1,1,1,1,1,0,0},
+ bb = {t,1,1,1,1,0,2,0},
+ b = {t,1,1,1,0,1,0,0},
+ c = {t,1,1,1,0,0,0,0},
+ db = {t,1,1,0,1,0,0,0},
+ d = {t,1,1,0,0,0,0,0},
+ eb = {t,1,1,0,0,1,2,1},
+ e = {t,1,1,0,1,1,0,0},
+ f' = {t,1,0,0,1,1,0,0},
+ gb' = {t,1,0,1,1,0,2,2,1},
+ g' = {t,1,0,1,1,0,2,2},
+ ab' = {t,0,1,1,0,1,2,0}
+ }
+\AddFingerings{C}{
+ C = {1,1,1,1,1,1,2,2},
+ Db = {1,1,1,1,1,1,2,1},
+ D = {1,1,1,1,1,1,2,0},
+ Eb = {1,1,1,1,1,1,1,0},
+ E = {1,1,1,1,1,1,0,0},
+ F = {1,1,1,1,1,0,2,2},
+ Gb = {1,1,1,1,0,1,1,0},
+ G = {1,1,1,1,0,0,0,0},
+ Ab = {1,1,1,0,1,1,0,0},
+ A = {1,1,1,0,0,0,0,0},
+ Bb = {1,1,0,1,1,0,0,0},
+ B = {1,1,0,0,0,0,0,0},
+ c = {1,0,1,0,0,0,0,0},
+ db = {0,1,1,0,0,0,0,0},
+ d = {0,0,1,0,0,0,0,0},
+ eb = {0,0,1,1,1,1,2,0},
+ e = {t,1,1,1,1,1,0,0},
+ f = {t,1,1,1,1,0,2,0},
+ gb = {t,1,1,1,0,1,0,0},
+ g = {t,1,1,1,0,0,0,0},
+ ab = {t,1,1,0,1,0,0,0},
+ a = {t,1,1,0,0,0,0,0},
+ bb = {t,1,1,0,0,1,2,1},
+ b = {t,1,1,0,1,1,0,0},
+ c' = {t,1,0,0,1,1,0,0},
+ db' = {t,1,0,1,1,0,2,2,1},
+ d' = {t,1,0,1,1,0,2,2},
+ eb' = {t,0,1,1,0,1,2,0}
+}
+
+% Transposition tables (may be useful; currently not used)
+\prop_set_from_keyval:Nn \l_fingering_F_to_C_prop {
+ F = {C},
+ Gb = {Db},
+ G = {D},
+ Ab = {Eb},
+ A = {E},
+ Bb = {F},
+ B = {Gb},
+ C = {G},
+ Db = {Ab},
+ D = {A},
+ Eb = {Bb},
+ E = {B},
+ f = {c},
+ gb = {db},
+ g = {d},
+ ab = {eb},
+ a = {e},
+ bb = {f},
+ b = {gb},
+ c = {g},
+ db = {ab},
+ d = {a},
+ eb = {bb},
+ e = {b},
+ f' = {c'},
+ gb' = {db'},
+ g' = {d'},
+ ab' = {eb'}
+ }
+
+\prop_set_from_keyval:Nn \l_fingering_C_to_F_prop {
+ C = {F},
+ Db = {Gb},
+ D = {G},
+ Eb = {Ab},
+ E = {A},
+ F = {Bb},
+ Gb = {B},
+ G = {C},
+ Ab = {Db},
+ A = {D},
+ Bb = {Eb},
+ B = {E},
+ c = {f},
+ db = {gb},
+ d = {g},
+ eb = {ab},
+ e = {a},
+ f = {bb},
+ gb = {b},
+ g = {c},
+ ab = {db},
+ a = {d},
+ bb = {eb},
+ b = {e},
+ c' = {f'},
+ db' = {gb'},
+ d' = {g'},
+ eb' = {ab'}
+ }
+
+
+% Backwards (in)compatibility with the initial version of the package
+
+\NewDocumentCommand{\fingering}{}{
+ \msg_error:nn {recorder-fingering}{deprecated}}
+\ExplSyntaxOff
+\endinput