% -------------------------------------------------------------------------- % the LEADSHEETS package % % typesetting leadsheets and songbooks % % -------------------------------------------------------------------------- % Clemens Niederberger % E-Mail: contact@mychemistry.eu % -------------------------------------------------------------------------- % Copyright 2014--2019 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}{2019/10/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 2019/10/02: enable https://tex.stackexchange.com/q/442222/