diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/leadsheets/leadsheets.library.songs.code.tex |
Initial commit
Diffstat (limited to 'macros/latex/contrib/leadsheets/leadsheets.library.songs.code.tex')
-rw-r--r-- | macros/latex/contrib/leadsheets/leadsheets.library.songs.code.tex | 792 |
1 files changed, 792 insertions, 0 deletions
diff --git a/macros/latex/contrib/leadsheets/leadsheets.library.songs.code.tex b/macros/latex/contrib/leadsheets/leadsheets.library.songs.code.tex new file mode 100644 index 0000000000..8a377a04ca --- /dev/null +++ b/macros/latex/contrib/leadsheets/leadsheets.library.songs.code.tex @@ -0,0 +1,792 @@ +% -------------------------------------------------------------------------- +% the LEADSHEETS package +% +% typesetting leadsheets and songbooks +% +% -------------------------------------------------------------------------- +% Clemens Niederberger +% E-Mail: contact@mychemistry.eu +% -------------------------------------------------------------------------- +% Copyright 2014-2017 Clemens Niederberger +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) 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 work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is Clemens Niederberger. +% -------------------------------------------------------------------------- +\LeadsheetsExplLibrary{songs}{2016/07/02 typesetting songs} + +% -------------------------------------------------------------------------- +% messages: +\msg_new:nnn {leadsheets} {unknown-verse-type} + { + The~ verse~ type~ `#1'~ is~ unknown.~ Using~ `verse'~ instead~ + \msg_line_context: + } + +\msg_new:nnn {leadsheets} {song-defined} + { + A~ song~ with~ the~ ID~ `#1'~ has~ already~ been~ defined! Check~ your~ + source~ \msg_line_context: + } + +\msg_new:nnn {leadsheets} {transpose-key} + { + You~ need~ to~ specify~ the~ `key'~ property~ for~ song~ `#1'~ + ( \leadsheets_get_property:nn {#1} {title} )~ in~ order~ to~ use~ the~ + transposing~ mechanism~ \msg_line_context: + } + +\msg_new:nnn {leadsheets} {verse-exists} + { + The~ verse~ type~ `#1'~ you~ are~ about~ to~ define~ \msg_line_context: + \c_space_tl already~ exists. + } + +% -------------------------------------------------------------------------- +% variables: +\tl_const:Nn \c_leadsheets_sharp_tl {sharp} +\tl_const:Nn \c_leadsheets_flat_tl {flat} + +\tl_new:N \l__leadsheets_songtext_format_tl +\tl_new:N \l__leadsheets_song_format_tl +\tl_new:N \l_leadsheets_current_song_id_tl +\tl_new:N \l_leadsheets_verse_type_tl +\tl_set:Nn \l_leadsheets_verse_type_tl {verse} +\tl_new:N \l__leadsheets_verses_format_tl +\tl_new:N \l__leadsheets_verses_label_format_tl +\tl_new:N \l__leadsheets_verses_after_label_tl +\tl_set:Nn \l__leadsheets_verses_after_label_tl {:} +\tl_new:N \l__leadsheets_enharmonic_tl +\tl_new:N \l__leadsheets_capo_number_format_tl +\tl_new:N \l__leadsheets_recall_verse_type_tl +\tl_new:N \l__leadsheets_song_body_tl +\tl_new:N \l__leadsheets_song_pre_hook_tl +\tl_new:N \l__leadsheets_song_post_hook_tl +\tl_new:N \l__leadsheets_song_mid_hook_tl + +\bool_new:N \l__leadsheets_print_selected_bool +\bool_new:N \l__leadsheets_transpose_bool +\bool_new:N \l__leadsheets_transpose_capo_bool +\bool_new:N \l__leadsheets_enharmonic_bool +\bool_new:N \l__leadsheets_obey_lines_bool +\bool_new:N \l__leadsheets_bar_shorthands_bool +\bool_new:N \l__leadsheets_measuring_bool +\bool_new:N \l__leadsheets_disable_measuring_bool +\bool_new:N \l__leadsheets_recall_verse_type_bool + +\clist_new:N \l__leadsheets_print_tags_clist + +\seq_new:N \l__leadsheets_defined_songs_seq +\seq_new:N \l__leadsheets_songs_print_seq +\seq_new:N \l__leadsheets_reset_counters_seq + +\int_new:N \l__leadsheets_transpose_steps_int +\int_new:N \l__leadsheets_capo_int +\int_new:N \g__leadsheets_song_id_int + +\skip_new:N \l__leadsheets_obey_parskip_skip +\skip_new:N \l__leadsheets_obey_parindent_skip + +% -------------------------------------------------------------------------- +% load necessary libraries: +\leadsheets_load_libraries:n + { + musicsymbols, + chordnames, + chords, + shorthands, + properties, + transposing, + templates, + translations + } + +% -------------------------------------------------------------------------- +% define shorthands +\cs_new_protected:Npn \leadsheets_bar:w #1 + { + \str_case:nnF {#1} + { + {:} {\leftrepeat} + {|} {\__leadsheets_checkbartype:} + } + {\normalbar\space #1} + } +\cs_new_protected:Npn \__leadsheets_checkbartype: + { + \peek_charcode_remove:NTF | + {\stopbar} + {\doublebar} + } + +\cs_new_protected:Npn \leadsheets_bar_repeat: + { + \peek_charcode_remove:NTF | + {\__leadsheets_checkrepeat:} + {\token_to_str:N :} + } +\cs_new_protected:Npn \__leadsheets_checkrepeat: + { + \peek_charcode_remove:NTF : + {\leftrightrepeat} + {\rightrepeat} + } + +\leadsheets_define_shorthand:NN ^ \getorprintchord +\leadsheets_define_shorthand:NN _ \writechord +\leadsheets_define_shorthand:NN | \leadsheets_bar:w +\leadsheets_define_shorthand:NN : \leadsheets_bar_repeat: + +% -------------------------------------------------------------------------- +% the `song' environment: +\NewDocumentEnvironment {song} { O{} } + { + \int_gincr:N \g__leadsheets_song_id_int + \tl_set:Nx \l__leadsheets_tmpa_tl + { song-\int_to_arabic:n { \g__leadsheets_song_id_int } } + \char_set_catcode_other:N \# + \skip_set_eq:NN \l__leadsheets_obey_parskip_skip \parskip + \leadsheets_startsong:nVn {#1} \l__leadsheets_tmpa_tl + } + {} + +% some hacks for the `obey-lines' option: +\group_begin: +\ExplSyntaxOff +\catcode`\:=11 +\catcode`\_=11 +\cs_new:Npn \__leadsheets_active_eol: { \catcode`\^^M=\active } + +\__leadsheets_active_eol: % +\tl_const:Nn \c__leadsheets_eol_tl {^^M}% +\cs_new_protected:Npn \leadsheets_obey_lines: {% + \bool_if:NT \l__leadsheets_obey_lines_bool {% + \skip_set_eq:NN \l__leadsheets_obey_parindent_skip \parindent% + \skip_zero:N \parindent% + }% + \cs_set:Npn ^^M{% + \peek_meaning:NTF ^^M% + {\par \skip_vertical:N \l__leadsheets_obey_parskip_skip}% + {\par}% + }% +}% +\cs_new_protected:Npn \leadsheets_ignore_lines:{% + \cs_set:Npn ^^M{% + \peek_meaning:NTF^^M% + {\par}% + {\c_space_tl}% + }% + \bool_if:NT \l__leadsheets_obey_lines_bool {% + \skip_set_eq:NN \parindent \l__leadsheets_obey_parindent_skip% + \skip_zero:N \l__leadsheets_obey_parindent_skip% + }% +}% +\group_end: + +% #1: options +% #2: ID +% #3: properties +\cs_new_protected:Npn \leadsheets_startsong:nnn #1#2#3 + { + \leadsheets_song_define:nn {#2} {#3} + \leadsheets_set_duplicate_properties:n {#2} + \leadsheets_check_print:n {#2} + \prop_gclear:N \g__leadsheets_chords_sequences_prop + \group_begin: + \keys_set:nn {leadsheets} {#1} + \leadsheets_specials: + \tl_use:N \l__leadsheets_song_format_tl + \leadsheets_ignore_lines: + \leadsheets_print_song:nwn {#2} + } +\cs_generate_variant:Nn \leadsheets_startsong:nnn { nV } + + +\cs_new_protected:Npn \leadsheets_specials: + { + \leadsheets_activate_shorthands:n {^_} + \bool_if:NT \l__leadsheets_bar_shorthands_bool + { \leadsheets_activate_shorthands:n {:|} } + \char_set_catcode_other:N \# + \bool_if:NT \l__leadsheets_obey_lines_bool + { \__leadsheets_active_eol: } + } + +% -------------------------------------------------------------------------- +% define song properties: +\leadsheets_define_property:n {title} +\leadsheets_define_property:n {subtitle} +\leadsheets_define_property:n {short-title} +\leadsheets_define_property:n {sort-title} +\leadsheets_define_property:n {sort-short-title} +\leadsheets_define_property:n {composer} +\leadsheets_define_property:n {sort-composer} +\leadsheets_define_property:n {music} +\leadsheets_define_property:n {sort-music} +\leadsheets_define_property:n {lyrics} +\leadsheets_define_property:n {sort-lyrics} +\leadsheets_define_property:n {arr} +\leadsheets_define_property:n {sort-arr} +\leadsheets_define_property:n {band} +\leadsheets_define_property:n {sort-band} +\leadsheets_define_property:n {genre} +\leadsheets_define_property:n {interpret} +\leadsheets_define_property:n {sort-interpret} +\leadsheets_define_property:n {key} +\leadsheets_define_property:n {capo} +\leadsheets_define_property:n {tempo} +\leadsheets_define_property:n {tags} +\leadsheets_define_property:n {counter} +\leadsheets_define_property:n {ID} + +% properties that should take the value of another property if they're not set +% explicitly: +\copysongproperty {composer} {sort-composer} +\copysongproperty {lyrics} {sort-lyrics} +\copysongproperty {music} {sort-music} +\copysongproperty {title} {sort-title} +\copysongproperty {short-title} {sort-short-title} +\copysongproperty {arr} {sort-arr} +\copysongproperty {interpret} {sort-interpret} + +% -------------------------------------------------------------------------- +% defining a new song: +\cs_new_protected:Npn \leadsheets_song_define:nn #1#2 + { + \seq_if_in:NnTF \l__leadsheets_defined_songs_seq {#1} + { \msg_error:nnn {leadsheets} {song-defined} {#1} } + { \seq_put_right:Nn \l__leadsheets_defined_songs_seq {#1} } + \leadsheets_define_song_properties:n {#1} + \keys_set:nn {leadsheets/song/#1} {#2} + \leadsheets_set_property:nnn {#1} {ID} {#1} + \leadsheets_set_property:nnx {#1} {counter} + { \int_to_arabic:n {\g__leadsheets_song_id_int} } + } +\cs_generate_variant:Nn \keys_set:nn {nV} +\cs_generate_variant:Nn \leadsheets_song_define:nn {nV} + +\cs_new_protected:Npn \leadsheets_define_song_properties:n #1 + { + \seq_map_inline:Nn \l__leadsheets_song_properties_seq + { + \keys_define:nn {leadsheets/song/#1} + { ##1 .code:n = \leadsheets_set_property:nnn {#1} {##1} {####1} } + } + } + +% -------------------------------------------------------------------------- +\cs_new_protected:Npn \leadsheets_print_song:nwn #1#2\end#3 + { + \tl_clear:N \l__leadsheets_song_body_tl + \leadsheets_if_print_song:nT {#1} + { + \tl_set:Nn \l_leadsheets_current_song_id_tl {#1} + \tl_put_right:Nn \l__leadsheets_song_body_tl + { + \__leadsheets_check_capo: + \__leadsheets_songtitle: + \tl_use:N \l__leadsheets_songtext_format_tl + } + \tl_put_right:NV \l__leadsheets_song_body_tl + \l__leadsheets_song_mid_hook_tl + \tl_put_right:Nn \l__leadsheets_song_body_tl {#2} + } + \__leadsheets_continue_or_end_song:nn {#1} {#3} + } + +\cs_new:Npn \__leadsheets_continue_song:nwn #1#2\end#3 + { + \leadsheets_if_print_song:nT {#1} + { \tl_put_right:Nn \l__leadsheets_song_body_tl {#2} } + \__leadsheets_continue_or_end_song:nn {#1} {#3} + } + +\cs_new_protected:Npn \__leadsheets_continue_or_end_song:nn #1#2 + { + \tl_if_eq:nnTF {#2} {song} + { + \leadsheets_if_print_song:nT {#1} + { \leadsheets_end_song:n {#1} } + \group_end: + \end{song} + } + { + \tl_put_right:Nn \l__leadsheets_song_body_tl { \end{#2} } + \__leadsheets_continue_song:nwn {#1} + } + } + +\cs_new_protected:Npn \leadsheets_end_song:n #1 + { + \__leadsheets_start_measuring:nw {#1} + \tl_put_left:NV \l__leadsheets_song_body_tl + \l__leadsheets_song_pre_hook_tl + \tl_put_right:NV \l__leadsheets_song_body_tl + \l__leadsheets_song_post_hook_tl + \box_clear:N \l__leadsheets_tmpa_box + \vbox_set:NV \l__leadsheets_tmpa_box \l__leadsheets_song_body_tl + \leadsheets_set_property:nnx {#1} {height} + { + \dim_to_decimal:n + { + \box_ht:N \l__leadsheets_tmpa_box + + \box_dp:N \l__leadsheets_tmpa_box + } + pt + } + \__leadsheets_stop_measuring: + \tl_use:N \l__leadsheets_song_body_tl + } + +\cs_new_protected:Npn \__leadsheets_save_macro:N #1 + { \cs_set_eq:cN { __leadsheets_ \cs_to_str:N #1 } #1 } + +\cs_new_protected:Npn \__leadsheets_restore_macro:N #1 + { + \cs_set_eq:Nc #1 { __leadsheets_ \cs_to_str:N #1 } + \cs_undefine:c { __leadsheets_ \cs_to_str:N #1 } + } + +\cs_new_protected:Npn \__leadsheets_start_measuring:nw #1#2 \__leadsheets_stop_measuring: + { + \bool_if:NF \l__leadsheets_disable_measuring_bool + { \bool_set_true:N \l__leadsheets_measuring_bool } + \bool_if:NTF \l__leadsheets_measuring_bool + { + \__leadsheets_save_macro:N \if@filesw + \__leadsheets_reset_counters: \@fileswfalse #2 + \__leadsheets_restore_macro:N \if@filesw + } + { \leadsheets_set_property:nnn {#1} {height} {0pt} } + \__leadsheets_stop_measuring: + } + +\cs_new_protected:Npn \__leadsheets_stop_measuring: + { + \bool_set_false:N \l__leadsheets_measuring_bool + \__leadsheets_reset_counters: + } + +\cs_new_protected:Npn \leadsheets_add_to_reset:n #1 + { \seq_put_right:Nn \l__leadsheets_reset_counters_seq {#1} } + +\cs_new_protected:Npn \__leadsheets_reset_counters: + { + \seq_map_inline:Nn \l__leadsheets_reset_counters_seq + { \setcounter {##1} {0} } + } + +\prg_new_conditional:Npnn \leadsheets_if_print_song:n #1 {T,F,TF} + { + \seq_if_in:NnTF \l__leadsheets_songs_print_seq {#1} + { \prg_return_true: } + { \prg_return_false: } + } + +\prg_new_conditional:Npnn \leadsheets_if_measuring: {T,F,TF} + { + \bool_if:NTF \l__leadsheets_measuring_bool + { \prg_return_true: } + { \prg_return_false: } + } + +\cs_new_protected:Npn \leadsheets_check_print:n #1 + { + \leadsheets_if_print_tags:nT {#1} + { \seq_put_right:Nn \l__leadsheets_songs_print_seq {#1} } + } + +\prg_new_protected_conditional:Npnn \leadsheets_if_print_tags:n #1 {T,F,TF} + { + \bool_if:NTF \l__leadsheets_print_selected_bool + { + \leadsheets_if_property:nnTF {#1} {tags} + { + \bool_set_false:N \l__leadsheets_tmpa_bool + \tl_set:Nx \l__leadsheets_tmpa_tl + { \leadsheets_get_property:nn {#1} {tags} } + \clist_map_inline:Nn \l__leadsheets_print_tags_clist + { + \clist_if_in:NnT \l__leadsheets_tmpa_tl {##1} + { + \bool_set_true:N \l__leadsheets_tmpa_bool + \clist_map_break: + } + } + \bool_if:NTF \l__leadsheets_tmpa_bool + { \prg_return_true: } + { \prg_return_false: } + } + { \prg_return_false: } + } + { \prg_return_true: } + } + +% -------------------------------------------------------------------------- +% predefined title templates +\definesongtitletemplate {minimal} + { \section*{ \songproperty {title} } } + +\definesongtitletemplate {tabular} + { + \ifsongmeasuring + { \section* } + { \section } + { \songproperty {title} } + \begingroup\footnotesize + \begin{tabular}{ + @{} + >{\raggedright\arraybackslash}p{.5\linewidth} + @{} + >{\raggedleft\arraybackslash}p{.5\linewidth} + @{} + } + \ifsongproperty{interpret} + {\GetTranslation{leadsheets/interpret}} + {} + \ifsongproperty{composer} + { + & \GetTranslation{leadsheets/composer}:~ + \printsongpropertylist{composer}{~\&~}{,~}{~\&~} + \ifsongproperty{lyrics} + {\\ & \GetTranslation{leadsheets/lyrics}:~ + \printsongpropertylist{lyrics}{~\&~}{,~}{~\&~} + } + {} + } + {} + \ifsongproperty{interpret}{\\}{\ifsongproperty{composer}{\\}{}} + \ifsongproperty{genre} + {& Genre:~ \songproperty{genre} \\} + {} + \ifsongproperty{tempo} + {& Tempo:~ \songproperty{tempo} \\} + {} + \ifsongproperty{key} + { + & + \setchords{ + major = -\GetTranslation{leadsheets/major} , + minor = -\GetTranslation{leadsheets/minor} + } + \GetTranslation{leadsheets/key}:~ + \expandcode{\writechord{\songproperty{key}}} \\ + } + {} + \end{tabular} + \par\endgroup + } + +% -------------------------------------------------------------------------- +% capo settings: +\cs_new_protected:Npn \__leadsheets_check_capo: + { + \leadsheets_if_property:VnTF \l_leadsheets_current_song_id_tl {capo} + { + \int_set:Nn \l__leadsheets_capo_int + { \leadsheets_get_property:Vn \l_leadsheets_current_song_id_tl {capo} } + } + { \int_zero:N \l__leadsheets_capo_int } + \int_set:Nn \l__leadsheets_transpose_steps_int + { + \bool_if:NTF \l__leadsheets_transpose_bool + { \l__leadsheets_transpose_steps_int } + {12} + - \l__leadsheets_capo_int + } + } + +\cs_new_protected:Npn \leadsheets_capo_number_print:n #1 {#1.} + +\cs_new_protected:Npn \leadsheets_capo: + { + \leadsheets_if_property:VnT \l_leadsheets_current_song_id_tl {capo} + { + \leadsheets_translation:n {capo} :~ + \leadsheets_capo_number_print:n + { + \use:c {int_to_ \l__leadsheets_capo_number_format_tl :n} + { \l__leadsheets_capo_int } + } + \nobreakspace + \leadsheets_translation:n {fret} + } + } + +\NewDocumentCommand \capo {} { \leadsheets_capo: } + +% -------------------------------------------------------------------------- +% verses and the like: +\tl_new:N \l__leadsheets_verses_default_class_tl +\tl_set:Nn \l__leadsheets_verses_default_class_tl {default} + +\cs_new_protected:Npn \leadsheets_verse_label:n #1 + { + \bool_if:cF {l__leadsheets_#1_empty_bool} + { + \tl_use:c {l__leadsheets_#1_label_format_tl} + \bool_if:cT {l__leadsheets_#1_named_bool} + { + \leadsheets_translation:n {#1} + \bool_if:cT {l__leadsheets_#1_numbered_bool} { ~ } + } + \bool_if:cT {l__leadsheets_#1_numbered_bool} + { \use:c {the#1} } + \tl_use:c {l__leadsheets_#1_after_label_tl} + } + } + +\cs_new_protected:Npn \leadsheets_verse_begin:n #1 + { + \stepcounter {#1} + \tl_set:Nn \verselabel { \leadsheets_verse_label:n {#1} } + \tl_set:Nn \verselabelformat + { \tl_use:c {l__leadsheets_#1_label_format_tl} } + \tl_set:Nn \versenumber { \use:c {the#1} } + \tl_set:Nn \verseafterlabel { \tl_use:c {l__leadsheets_#1_after_label_tl} } + \tl_set:Nn \versename { \leadsheets_translation:n {#1} } + \tl_set:Nn \ifversestarred { \bool_if:cTF {l__leadsheets_#1_empty_bool} } + \tl_set:Nn \ifversenamed { \bool_if:cTF {l__leadsheets_#1_named_bool} } + \tl_set:Nn \ifversenumbered + { \bool_if:cTF {l__leadsheets_#1_numbered_bool} } + \leadsheets_obey_lines: + \leadsheets_use_verse_template:nn {begin} {#1} + } + +\cs_new_protected:Npn \leadsheets_verse_end:n #1 + { + \leadsheets_ignore_lines: + \leadsheets_use_verse_template:nn {end} {#1} + \ignorespacesafterend + } + +\seq_new:N \l__leadsheets_verse_types_seq + +\prg_new_conditional:Npnn \leadsheets_if_verse_type_exist:n #1 {p,T,F,TF} + { + \seq_if_in:NnTF \l__leadsheets_verse_types_seq {#1} + { \prg_return_true: } + { \prg_return_false: } + } + +% #1: boolean +% #2: name +% #3: options +\cs_new_protected:Npn \__leadsheets_new_verse_type:nnn #1#2#3 + { + \seq_put_right:Nn \l__leadsheets_verse_types_seq {#2} + \clist_map_inline:nn {empty,numbered,named} + { + \bool_if_exist:cF {l__leadsheets_#2_##1_bool} + { \bool_new:c {l__leadsheets_#2_##1_bool} } + } + \bool_set_true:c {l__leadsheets_#2_named_bool} + \bool_if:nTF {#1} + { \bool_set_true:c {l__leadsheets_#2_empty_bool} } + { \bool_set_false:c {l__leadsheets_#2_empty_bool} } + \clist_map_inline:nn {class,format,template,label_format,after_label} + { + \tl_if_exist:cF {l__leadsheets_#2_##1_tl} + { \tl_new:c {l__leadsheets_#2_##1_tl} } + } + \cs_if_exist:cF {the#2} + { \newcounter {#2} } + \leadsheets_add_to_reset:n {#2} + \tl_set:cn {the#2} { \arabic {#2} . } + \keys_define:nn {leadsheets/#2} + { + numbered .bool_set:c = {l__leadsheets_#2_numbered_bool} , + named .bool_set:c = {l__leadsheets_#2_named_bool} , + class .tl_set:c = {l__leadsheets_#2_class_tl} , + class .initial:V = \l__leadsheets_verses_default_class_tl , + format .code:n = + \tl_set:cn {l__leadsheets_#2_format_tl} {##1} , + format .initial:n = \l__leadsheets_verses_format_tl , + label-format .code:n = + \tl_set:cn {l__leadsheets_#2_label_format_tl} {##1} , + label-format .initial:n = \l__leadsheets_verses_label_format_tl , + after-label .code:n = + \tl_set:cn {l__leadsheets_#2_after_label_tl} {##1} , + after-label .initial:n = \l__leadsheets_verses_after_label_tl , + template .code:n = + \tl_set:cn {l__leadsheets_#2_template_tl} {##1} , + template .initial:n = itemize , + recall-chords .code:n = + \tl_set:Nn \l__leadsheets_recall_verse_type_tl {##1} + \bool_set_true:N \l__leadsheets_recall_verse_type_bool , + name .code:n = + \leadsheets_declare_translation:nnn {fallback} {#2} {##1} + \leadsheets_declare_translation:nnn {English} {#2} {##1} + } + \NewDocumentEnvironment {#2} {O{}} + { + \par + \bool_set_false:N \l__leadsheets_recall_verse_type_bool + \keys_set:nn {leadsheets/#2} {##1} + \tl_set:Nx \l_leadsheets_verse_type_tl + { #2-\tl_use:c {l__leadsheets_#2_class_tl} } + \bool_if:NTF \l__leadsheets_recall_verse_type_bool + { + \tl_set_eq:NN + \l_leadsheets_verse_type_tl + \l__leadsheets_recall_verse_type_tl + } + { + \tl_set_eq:NN + \l__leadsheets_recall_verse_type_tl + \l_leadsheets_verse_type_tl + } + \leadsheets_if_record_chords:T + { \seq_gclear:N \g__leadsheets_chords_sequences_seq } + \leadsheets_if_recall_chords:T + { + \prop_get:NVN + \g__leadsheets_chords_sequences_prop + \l__leadsheets_recall_verse_type_tl + \l__leadsheets_tmpa_tl + \seq_gclear:N \g__leadsheets_chords_sequences_seq + \tl_map_inline:Nn \l__leadsheets_tmpa_tl + { \seq_gput_right:Nn \g__leadsheets_chords_sequences_seq {####1} } + } + \leadsheets_verse_begin:n {#2} + \tl_use:c {l__leadsheets_#2_format_tl} + } + { + \leadsheets_if_record_chords:T + { + \prop_gput:NVf \g__leadsheets_chords_sequences_prop + \l_leadsheets_verse_type_tl + { \seq_use:Nn \g__leadsheets_chords_sequences_seq {} } + } + \leadsheets_verse_end:n {#2} + \par + } + \leadsheets_declare_translation:nnn {fallback} {#2} {} + \leadsheets_declare_translation:nnn {English} {#2} {} + \keys_set:nn {leadsheets/#2} {#3} + } + +% #1: boolean +% #2: name +% #3: options +\cs_new_protected:Npn \leadsheets_new_verse_type:nnn #1#2#3 + { + \leadsheets_if_verse_type_exist:nTF {#2} + { \msg_error:nnn {leadsheets} {verse-exists} {#2} } + { \__leadsheets_new_verse_type:nnn {#1} {#2} {#3} } + } + +% #1: boolean +% #2: name +% #3: options +\cs_new_protected:Npn \leadsheets_provide_verse_type:nnn #1#2#3 + { + \leadsheets_if_verse_type_exist:nF {#2} + { \__leadsheets_new_verse_type:nnn {#1} {#2} {#3} } + } + +\NewDocumentCommand \newversetype {smO{}} + { \leadsheets_new_verse_type:nnn {#1} {#2} {#3} } + +\NewDocumentCommand \provideversetype {smO{}} + { \leadsheets_provide_verse_type:nnn {#1} {#2} {#3} } + +\cs_undefine:N \verse +\cs_undefine:N \endverse + +\newversetype {verse} [ name=Verse, named=false, after-label= ] +\newversetype*{verse*} [ name=Verse ] +\newversetype {chorus} [ name=Chorus ] +\newversetype*{chorus*} [ name=Chorus ] +\newversetype {intro} [ name=Intro ] +\newversetype*{intro*} [ name=Intro ] +\newversetype {outro} [ name=Outro ] +\newversetype {interlude} [ name=Interlude ] +\newversetype {bridge} [ name=Bridge ] +\newversetype*{info} +\newversetype*{solo*} [ name=Solo ] +\newversetype {solo} [ name=Solo ] + +% -------------------------------------------------------------------------- +% predefined verse templates: +\defineversetypetemplate {itemize} + { + \itemize + \int_zero:N \@itemdepth + \bool_if:NT \l__leadsheets_obey_lines_bool + { + \dim_zero:N \parskip + \keys_set:nn {leadsheets} + { obey-lines-parskip = \parsep } + } + \item[{\verselabel}] + } + { \enditemize } + +% -------------------------------------------------------------------------- + +\keys_define:nn {leadsheets} + { + title-template .tl_set:N = \l__leadsheets_songtitle_template_tl , + title-template .initial:n = minimal , + text-format .tl_set:N = \l__leadsheets_songtext_format_tl , + song-format .tl_set:N = \l__leadsheets_song_format_tl , + verse/type .choice: , + verse/type/verse .code:n = + \tl_set:Nn \l_leadsheets_verse_type_tl {verse} , + verse/type/unknown .code:n = + \msg_warning:nnn {leadsheets} {unknown-verse-type} {#1} + \tl_set:Nn \l_leadsheets_verse_type_tl {verse} , + verse/format .tl_set:N = \l__leadsheets_verse_format_tl , + verse/format .initial:n = \l__leadsheets_verses_format_tl , + verse/label-format .tl_set:N = \l__leadsheets_verse_label_format_tl , + verse/label-format .initial:n = \l__leadsheets_verses_label_format_tl , + verses-format .tl_set:N = \l__leadsheets_verses_format_tl , + verses-label-format .tl_set:N = \l__leadsheets_verses_label_format_tl , + verses-after-label .tl_set:N = \l__leadsheets_verses_after_label_tl , + verses-default-class .tl_set:N = \l__leadsheets_verses_default_class_tl , + obey-lines .bool_set:N = \l__leadsheets_obey_lines_bool , + obey-lines-parskip .skip_set:N = \l__leadsheets_obey_parskip_skip , + bar-shortcuts .bool_set:N = \l__leadsheets_bar_shorthands_bool , + bar-shortcuts .initial:n = true , + capo-nr-format .choices:nn = + { arabic , roman , Roman } + { \tl_set:NV \l__leadsheets_capo_number_format_tl \l_keys_choice_tl } , + capo-nr-format .initial:n = {Roman} , + capo-nr .code:n = + \cs_set_protected:Npn \leadsheets_capo_number_print:n ##1 {#1} , + capo-nr .initial:n = #1. , + before-song .tl_set:N = \l__leadsheets_song_pre_hook_tl , + after-song .tl_set:N = \l__leadsheets_song_post_hook_tl , + after-title .tl_set:N = \l__leadsheets_song_mid_hook_tl , + add-to-reset .code:n = + \clist_map_inline:nn {#1} { \leadsheets_add_to_reset:n {##1} } , + print-tags .code:n = + \bool_set_true:N \l__leadsheets_print_selected_bool + \clist_set:Nn \l__leadsheets_print_tags_clist {#1} , + disable-measuring .bool_set:N = \l__leadsheets_disable_measuring_bool , + disable-measuring .initial:n = false + } + +\file_input_stop: + +2015/05/22: \l__leadsheets_chords_sequences_prop changed into global +2015/07/02: added `class' option to verses +2015/07/05: enable usage of # in the key property +2015/07/27: new options `before-song', `after-song', `after-title' and + `add-to-reset' +2015/02/02: enable to recall chords even if verse is used the first time +2016/05/18: new option `disable-measuring' + set \@fileswfalse during the measuring phase + if measuring is disabled the `height' property is set to 0pt +2016/06/29: - adapt to changed shorthand library + - activate bar-shortcuts per default +2016/07/02: fix issue when \capo is used in a title template |