From 3ae07bb3289011e1fe6fdc6a5cbbbadfa9c87e37 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Wed, 22 Jan 2025 12:41:21 -0500 Subject: [PATCH 01/19] Adds a new option (alteration-scope: line in header, \setalterationscope{line} in TeX) that causes only the first alteration (flat) on each line to be printed. Uses the .gaux file, so multiple TeX runs are needed. --- tex/gregoriotex-main.tex | 20 ++++++++++++ tex/gregoriotex-signs.tex | 21 ++++++++++++- tex/gregoriotex-syllable.tex | 2 ++ tex/gregoriotex.lua | 59 ++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/tex/gregoriotex-main.tex b/tex/gregoriotex-main.tex index 2155f4d0..53b82154 100644 --- a/tex/gregoriotex-main.tex +++ b/tex/gregoriotex-main.tex @@ -102,6 +102,11 @@ % attribute for syllable tracking \newluatexattribute\gre@attr@syllable@id % +% attributes for soft alterations +\newluatexattribute\gre@attr@alteration@type % + \edef\gre@attrid@alteration@type{\the\allocationnumber}% +\newluatexattribute\gre@attr@alteration@id % + \newluatexcatcodetable\gre@atletter % \setluatexcatcodetable\gre@atletter{% \catcode`\@=11 % @@ -1269,6 +1274,7 @@ \gre@resetledgerlineheuristics% \global\setluatexattribute\gre@attr@glyph@id{0}% \global\setluatexattribute\gre@attr@syllable@id{0}% + \global\setluatexattribute\gre@attr@alteration@id{0}% \let\gre@pitch@cleftop\gre@pitch@dummy % \let\gre@pitch@clefbottom\gre@pitch@dummy % \xdef\gre@gabcname{#6}% @@ -2127,4 +2133,18 @@ % We load the default space configuration. \greloadspaceconf{default}% +\newif\ifgre@alteration@line +\gre@alteration@linefalse +\def\gresetalterationscope#1{% + \IfStrEqCase{#1}{% + {none}% + {\gre@alteration@linefalse}% + {line}% + {\gre@alteration@linetrue}% + }[% all other cases + \gre@error{Unrecognized option "#1" for \protect\gresetalterationscope\MessageBreak Possible options are: 'none' and 'line'}% + ]% +} +\gresetheadercapture{alteration-scope}{gresetalterationscope}{} + \input gregoriotex-nabc.tex diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index 409107f8..8f3a0555 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -537,6 +537,7 @@ \gre@debugmsg{custos}{not blocked}% \gre@calculate@glyphraisevalue{#1}{0}{}% %here we need some tricks to draw the line before the custos (for the color) + \edef\gre@saved@attr@alteration@id{\number\gre@attr@alteration@id\relax}% save alteration id to avoid double-counting \setbox\gre@box@temp@width=\hbox{% % we type a hskip and the we type the custos \gre@hskip\gre@space@skip@spacebeforeeolcustos\relax % @@ -547,6 +548,7 @@ \gre@pickcustos{#1}{2}\relax % }% }% + \global\gre@attr@alteration@id=\gre@saved@attr@alteration@id\relax % \gre@dimen@temp@three=\wd\gre@box@temp@width % % we make \wd\gre@box@temp@sign contain the width of a custos \setbox\gre@box@temp@sign=\hbox{% @@ -2703,7 +2705,24 @@ % #7 is the line:char:column for a textedit link \def\gre@alteration#1#2#3#4#5#6#7{% \gre@trace{gre@alteration{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% - \setbox\gre@box@temp@width=\hbox{\gre@pointandclick{#2}{#7}}% + \global\advance\gre@attr@alteration@id by 1\relax % + \ifgre@alteration@line + \ifcase\directlua{gregoriotex.is_first_alteration()}% + \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}% + \or + #5\relax % + \hbox attr \gre@attrid@alteration@type=#1\relax{}% + #6\relax % + \fi + \else + \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}% + \fi +} + +\def\gre@alteration@visible#1#2#3#4#5#6#7{% + \gre@trace{gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% + \setbox\gre@box@temp@width=\hbox attr \gre@attrid@alteration@type=#1\relax + {\gre@pointandclick{#2}{#7}}% \ifnum#4=0\relax % \gre@newglyphcommon % \fi % diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index d184b831..00c5d187 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -373,6 +373,7 @@ \global\gre@boxingtrue% \let\ifgre@saved@prenotes@lastendswithmora\ifgre@lastendswithmora% \xdef\gre@saved@prenotes@lastoflinecount{\number\gre@lastoflinecount\relax }% + \edef\gre@saved@attr@alteration@id{\number\gre@attr@alteration@id\relax}% \ifgre@shownotes% \setbox\gre@box@syllablenotes=\hbox{#1}% \else% @@ -394,6 +395,7 @@ \fi % \let\ifgre@lastendswithmora\ifgre@saved@prenotes@lastendswithmora% \global\gre@lastoflinecount=\gre@saved@prenotes@lastoflinecount\relax % + \global\gre@attr@alteration@id=\gre@saved@attr@alteration@id\relax % \global\gre@count@lastglyphiscavum=0\relax % \global\gre@skip@bar@lastskip=0pt\relax % \global\gre@endofscorefalse % diff --git a/tex/gregoriotex.lua b/tex/gregoriotex.lua index eb2628f2..681605f4 100644 --- a/tex/gregoriotex.lua +++ b/tex/gregoriotex.lua @@ -64,6 +64,9 @@ local glyph_top_attr = luatexbase.attributes['gre@attr@glyph@top'] local glyph_bottom_attr = luatexbase.attributes['gre@attr@glyph@bottom'] local prev_line_id = nil +local alteration_type_attr = luatexbase.attributes['gre@attr@alteration@type'] +local alteration_id_attr = luatexbase.attributes['gre@attr@alteration@id'] + local syllable_id_attr = luatexbase.attributes['gre@attr@syllable@id'] local cur_score_id = nil @@ -81,6 +84,8 @@ local last_syllables = nil local new_last_syllables = nil local score_last_syllables = nil local new_score_last_syllables = nil +local first_alterations = nil +local new_first_alterations = nil local state_hashes = nil local new_state_hashes = nil local auxname = nil @@ -268,6 +273,12 @@ local function is_greaux_write_needed() if saved_computations_changed(saved_newline_before_euouae, new_saved_newline_before_euouae) then return true end + for id, tab in pairs(new_first_alterations) do + if keys_changed(tab, first_alterations[id]) or entries_changed(tab, first_alterations[id]) then return true end + end + for id, tab in pairs(first_alterations) do + if keys_changed(tab, new_first_alterations[id]) or entries_changed(tab, first_alterations[id]) then return true end + end return false end @@ -332,6 +343,14 @@ local function write_greaux() for id, value in pairs(new_state_hashes) do aux:write(string.format(' ["%s"]="%s",\n', id, value)) end + aux:write(' },\n ["first_alterations"]={\n') + for id, tab in pairs(new_first_alterations) do + aux:write(string.format(' ["%s"]={\n ', id)) + for i, value in pairs(tab) do + aux:write(string.format('[%s]=%s,', i, value)) + end + aux:write(string.format('},\n')) + end aux:write(' },\n}\n') aux:close() else @@ -378,12 +397,14 @@ local function init(arg, enable_height_computation) state_hashes = score_info.state_hashes or {} saved_lengths = score_info.saved_lengths or {} saved_newline_before_euouae = score_info.saved_newline_before_euouae or {} + first_alterations = score_info.first_alterations or {} else line_heights = {} last_syllables = {} state_hashes = {} saved_lengths = {} saved_newline_before_euouae = {} + first_alterations = {} end if enable_height_computation then @@ -414,6 +435,7 @@ local function init(arg, enable_height_computation) saved_positions = {} new_saved_lengths = {} new_saved_newline_before_euouae = {} + new_first_alterations = {} end -- node factory @@ -634,6 +656,19 @@ local function post_linebreak(h, groupcode, glyphes) currentshift=0 end end + -- Record whether each alteration is the first on the line + for line in traverse_id(hlist, h) do + local seen = {} + for n in traverse_id(hlist, line.head) do + if has_attribute(n, alteration_type_attr) ~= nil then + local i = has_attribute(n, alteration_id_attr) + local t = has_attribute(n, alteration_type_attr) + new_score_first_alterations[i] = not seen[t] + debugmessage("alteration", "id=%s type=%s seen=%s first=%s", i, t, seen[t], new_score_first_alterations[i]) + seen[t] = true + end + end + end --dump_nodes(h) -- due to special cases, we don't return h here (see comments in bug #20974) return true @@ -740,6 +775,10 @@ local function at_score_beginning(score_id, top_height, bottom_height, if score_last_syllables and state_hashes[score_id] ~= state then score_last_syllables = nil end + score_first_alterations = first_alterations[score_id] + if score_first_alterations and state_hashes[score_id] ~= state then + score_first_alterations = nil + end if new_state_hashes then new_state_hashes[score_id] = state end @@ -747,6 +786,10 @@ local function at_score_beginning(score_id, top_height, bottom_height, new_score_last_syllables = {} new_last_syllables[score_id] = new_score_last_syllables end + if new_first_alterations then + new_score_first_alterations = {} + new_first_alterations[score_id] = new_score_first_alterations + end luatexbase.add_to_callback('post_linebreak_filter', post_linebreak, 'gregoriotex.post_linebreak', 1) luatexbase.add_to_callback("hyphenate", disable_hyphenation, "gregoriotex.disable_hyphenation", 1) @@ -1519,6 +1562,21 @@ local function hash_spaces(name, value) space_hash = md5.sumhexa(mash) end +-- prints 0 for true and 1 for false +local function is_first_alteration() + if score_first_alterations then + local i = tex.getattribute(alteration_id_attr) + local v = score_first_alterations[i] + if v == true or v == nil then + tex.print(0) + else + tex.print(1) + end + else + tex.print(0) + end +end + gregoriotex.number_to_letter = number_to_letter gregoriotex.init = init gregoriotex.include_score = include_score @@ -1557,6 +1615,7 @@ gregoriotex.save_dim = save_dim gregoriotex.save_count = save_count gregoriotex.change_next_score_line_dim = change_next_score_line_dim gregoriotex.change_next_score_line_count = change_next_score_line_count +gregoriotex.is_first_alteration = is_first_alteration dofile(kpse.find_file('gregoriotex-nabc.lua', 'lua')) dofile(kpse.find_file('gregoriotex-signs.lua', 'lua')) From f16aa96722acb621b9b93acfaf969d9e46503af3 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Wed, 22 Jan 2025 12:41:21 -0500 Subject: [PATCH 02/19] Adds a new option (alteration-scope: line in header, \setalterationscope{line} in TeX) that causes only the first alteration (flat) on each line to be printed. Uses the .gaux file, so multiple TeX runs are needed. --- tex/gregoriotex-main.tex | 20 ++++++++++++ tex/gregoriotex-signs.tex | 21 ++++++++++++- tex/gregoriotex-syllable.tex | 2 ++ tex/gregoriotex.lua | 59 ++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/tex/gregoriotex-main.tex b/tex/gregoriotex-main.tex index 9e357fac..73ac8402 100644 --- a/tex/gregoriotex-main.tex +++ b/tex/gregoriotex-main.tex @@ -102,6 +102,11 @@ % attribute for syllable tracking \newluatexattribute\gre@attr@syllable@id % +% attributes for soft alterations +\newluatexattribute\gre@attr@alteration@type % + \edef\gre@attrid@alteration@type{\the\allocationnumber}% +\newluatexattribute\gre@attr@alteration@id % + \newluatexcatcodetable\gre@atletter % \setluatexcatcodetable\gre@atletter{% \catcode`\@=11 % @@ -1276,6 +1281,7 @@ \gre@resetledgerlineheuristics% \global\setluatexattribute\gre@attr@glyph@id{0}% \global\setluatexattribute\gre@attr@syllable@id{0}% + \global\setluatexattribute\gre@attr@alteration@id{0}% \let\gre@pitch@cleftop\gre@pitch@dummy % \let\gre@pitch@clefbottom\gre@pitch@dummy % \xdef\gre@gabcname{#6}% @@ -2134,4 +2140,18 @@ % We load the default space configuration. \greloadspaceconf{default}% +\newif\ifgre@alteration@line +\gre@alteration@linefalse +\def\gresetalterationscope#1{% + \IfStrEqCase{#1}{% + {none}% + {\gre@alteration@linefalse}% + {line}% + {\gre@alteration@linetrue}% + }[% all other cases + \gre@error{Unrecognized option "#1" for \protect\gresetalterationscope\MessageBreak Possible options are: 'none' and 'line'}% + ]% +} +\gresetheadercapture{alteration-scope}{gresetalterationscope}{} + \input gregoriotex-nabc.tex diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index 44c903ca..b662ed4c 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -537,6 +537,7 @@ \gre@debugmsg{custos}{not blocked}% \gre@calculate@glyphraisevalue{#1}{0}{}% %here we need some tricks to draw the line before the custos (for the color) + \edef\gre@saved@attr@alteration@id{\number\gre@attr@alteration@id\relax}% save alteration id to avoid double-counting \setbox\gre@box@temp@width=\hbox{% % we type a hskip and the we type the custos \gre@hskip\gre@space@skip@spacebeforeeolcustos\relax % @@ -547,6 +548,7 @@ \gre@pickcustos{#1}{2}\relax % }% }% + \global\gre@attr@alteration@id=\gre@saved@attr@alteration@id\relax % \gre@dimen@temp@three=\wd\gre@box@temp@width % % we make \wd\gre@box@temp@sign contain the width of a custos \setbox\gre@box@temp@sign=\hbox{% @@ -2703,7 +2705,24 @@ % #7 is the line:char:column for a textedit link \def\gre@alteration#1#2#3#4#5#6#7{% \gre@trace{gre@alteration{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% - \setbox\gre@box@temp@width=\hbox{\gre@pointandclick{#2}{#7}}% + \global\advance\gre@attr@alteration@id by 1\relax % + \ifgre@alteration@line + \ifcase\directlua{gregoriotex.is_first_alteration()}% + \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}% + \or + #5\relax % + \hbox attr \gre@attrid@alteration@type=#1\relax{}% + #6\relax % + \fi + \else + \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}% + \fi +} + +\def\gre@alteration@visible#1#2#3#4#5#6#7{% + \gre@trace{gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% + \setbox\gre@box@temp@width=\hbox attr \gre@attrid@alteration@type=#1\relax + {\gre@pointandclick{#2}{#7}}% \ifnum#4=0\relax % \gre@newglyphcommon % \fi % diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index d184b831..00c5d187 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -373,6 +373,7 @@ \global\gre@boxingtrue% \let\ifgre@saved@prenotes@lastendswithmora\ifgre@lastendswithmora% \xdef\gre@saved@prenotes@lastoflinecount{\number\gre@lastoflinecount\relax }% + \edef\gre@saved@attr@alteration@id{\number\gre@attr@alteration@id\relax}% \ifgre@shownotes% \setbox\gre@box@syllablenotes=\hbox{#1}% \else% @@ -394,6 +395,7 @@ \fi % \let\ifgre@lastendswithmora\ifgre@saved@prenotes@lastendswithmora% \global\gre@lastoflinecount=\gre@saved@prenotes@lastoflinecount\relax % + \global\gre@attr@alteration@id=\gre@saved@attr@alteration@id\relax % \global\gre@count@lastglyphiscavum=0\relax % \global\gre@skip@bar@lastskip=0pt\relax % \global\gre@endofscorefalse % diff --git a/tex/gregoriotex.lua b/tex/gregoriotex.lua index 4d194147..f45f5aa3 100644 --- a/tex/gregoriotex.lua +++ b/tex/gregoriotex.lua @@ -64,6 +64,9 @@ local glyph_top_attr = luatexbase.attributes['gre@attr@glyph@top'] local glyph_bottom_attr = luatexbase.attributes['gre@attr@glyph@bottom'] local prev_line_id = nil +local alteration_type_attr = luatexbase.attributes['gre@attr@alteration@type'] +local alteration_id_attr = luatexbase.attributes['gre@attr@alteration@id'] + local syllable_id_attr = luatexbase.attributes['gre@attr@syllable@id'] local cur_score_id = nil @@ -81,6 +84,8 @@ local last_syllables = nil local new_last_syllables = nil local score_last_syllables = nil local new_score_last_syllables = nil +local first_alterations = nil +local new_first_alterations = nil local state_hashes = nil local new_state_hashes = nil local auxname = nil @@ -273,6 +278,12 @@ local function is_greaux_write_needed() if saved_computations_changed(saved_newline_before_euouae, new_saved_newline_before_euouae) then return true end + for id, tab in pairs(new_first_alterations) do + if keys_changed(tab, first_alterations[id]) or entries_changed(tab, first_alterations[id]) then return true end + end + for id, tab in pairs(first_alterations) do + if keys_changed(tab, new_first_alterations[id]) or entries_changed(tab, first_alterations[id]) then return true end + end return false end @@ -337,6 +348,14 @@ local function write_greaux() for id, value in pairs(new_state_hashes) do aux:write(string.format(' ["%s"]="%s",\n', id, value)) end + aux:write(' },\n ["first_alterations"]={\n') + for id, tab in pairs(new_first_alterations) do + aux:write(string.format(' ["%s"]={\n ', id)) + for i, value in pairs(tab) do + aux:write(string.format('[%s]=%s,', i, value)) + end + aux:write(string.format('},\n')) + end aux:write(' },\n}\n') aux:close() else @@ -383,12 +402,14 @@ local function init(arg, enable_height_computation) state_hashes = score_info.state_hashes or {} saved_lengths = score_info.saved_lengths or {} saved_newline_before_euouae = score_info.saved_newline_before_euouae or {} + first_alterations = score_info.first_alterations or {} else line_heights = {} last_syllables = {} state_hashes = {} saved_lengths = {} saved_newline_before_euouae = {} + first_alterations = {} end if enable_height_computation then @@ -419,6 +440,7 @@ local function init(arg, enable_height_computation) saved_positions = {} new_saved_lengths = {} new_saved_newline_before_euouae = {} + new_first_alterations = {} end -- node factory @@ -639,6 +661,19 @@ local function post_linebreak(h, groupcode, glyphes) currentshift=0 end end + -- Record whether each alteration is the first on the line + for line in traverse_id(hlist, h) do + local seen = {} + for n in traverse_id(hlist, line.head) do + if has_attribute(n, alteration_type_attr) ~= nil then + local i = has_attribute(n, alteration_id_attr) + local t = has_attribute(n, alteration_type_attr) + new_score_first_alterations[i] = not seen[t] + debugmessage("alteration", "id=%s type=%s seen=%s first=%s", i, t, seen[t], new_score_first_alterations[i]) + seen[t] = true + end + end + end --dump_nodes(h) -- due to special cases, we don't return h here (see comments in bug #20974) return true @@ -745,6 +780,10 @@ local function at_score_beginning(score_id, top_height, bottom_height, if score_last_syllables and state_hashes[score_id] ~= state then score_last_syllables = nil end + score_first_alterations = first_alterations[score_id] + if score_first_alterations and state_hashes[score_id] ~= state then + score_first_alterations = nil + end if new_state_hashes then new_state_hashes[score_id] = state end @@ -752,6 +791,10 @@ local function at_score_beginning(score_id, top_height, bottom_height, new_score_last_syllables = {} new_last_syllables[score_id] = new_score_last_syllables end + if new_first_alterations then + new_score_first_alterations = {} + new_first_alterations[score_id] = new_score_first_alterations + end luatexbase.add_to_callback('post_linebreak_filter', post_linebreak, 'gregoriotex.post_linebreak', 1) luatexbase.add_to_callback("hyphenate", disable_hyphenation, "gregoriotex.disable_hyphenation", 1) @@ -1614,6 +1657,21 @@ local function hash_spaces(name, value) space_hash = md5.sumhexa(mash) end +-- prints 0 for true and 1 for false +local function is_first_alteration() + if score_first_alterations then + local i = tex.getattribute(alteration_id_attr) + local v = score_first_alterations[i] + if v == true or v == nil then + tex.print(0) + else + tex.print(1) + end + else + tex.print(0) + end +end + gregoriotex.number_to_letter = number_to_letter gregoriotex.init = init gregoriotex.include_score = include_score @@ -1653,6 +1711,7 @@ gregoriotex.save_count = save_count gregoriotex.change_next_score_line_dim = change_next_score_line_dim gregoriotex.change_next_score_line_count = change_next_score_line_count gregoriotex.set_base_output_dir = set_base_output_dir +gregoriotex.is_first_alteration = is_first_alteration dofile(kpse.find_file('gregoriotex-nabc.lua', 'lua')) dofile(kpse.find_file('gregoriotex-signs.lua', 'lua')) From a2a2e0c81dd9ae6c0e13cc2689676aa86ffdcc83 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Thu, 23 Jan 2025 21:35:46 -0500 Subject: [PATCH 03/19] correctly compute space before suppressed flats --- tex/gregoriotex-signs.tex | 29 +++++++++++++++++++++-------- tex/gregoriotex-syllable.tex | 23 +++++++++++++++++------ tex/gregoriotex.lua | 15 +++++++++++++-- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index b662ed4c..9a368708 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -2705,17 +2705,30 @@ % #7 is the line:char:column for a textedit link \def\gre@alteration#1#2#3#4#5#6#7{% \gre@trace{gre@alteration{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% - \global\advance\gre@attr@alteration@id by 1\relax % + \global\advance\gre@attr@alteration@id by 1\relax + \gre@alteration@isfirst{0}% + \ifgre@alteration@isfirst + \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}% + \else + #5\relax + \hbox attr \gre@attrid@alteration@type=#1\relax{}% + #6\relax + \fi +} + +% Test whether an alteration is the first on its line. +% #1 = 0 for current alteration, 1 for next alteration. +% Sets \ifgre@alteration@isfirsttrue or \ifgre@alteration@isfirstfalse. +\newif\ifgre@alteration@isfirst +\def\gre@alteration@isfirst#1{% \ifgre@alteration@line - \ifcase\directlua{gregoriotex.is_first_alteration()}% - \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}% - \or - #5\relax % - \hbox attr \gre@attrid@alteration@type=#1\relax{}% - #6\relax % + \ifcase\directlua{gregoriotex.is_first_alteration(#1)}\relax + \global\gre@alteration@isfirsttrue + \else + \global\gre@alteration@isfirstfalse \fi \else - \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}% + \global\gre@alteration@isfirstfalse \fi } diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index 00c5d187..522d1bcc 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -906,7 +906,18 @@ % by default, gre@attr@dash will be 2 \gre@attr@dash=2\relax % #5% - \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}#7% + % if the next glyph has an alteration, check if it is suppressed; + % if so, pretend there's no alteration + \def\nextalignment{\gre@arg@oftwo@first#7}% + \def\nextalteration{\gre@arg@oftwo@second#7}% + \ifnum\nextalteration>0\relax + \gre@alteration@isfirst{1}% + \ifgre@alteration@isfirst + \else + \def\nextalteration{0}% + \fi + \fi + \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\nextalignment}{\nextalteration}% \gre@unsetfixednexttextformat % \ifgre@showlyrics% \setbox\gre@box@syllabletext=\hbox{% @@ -924,10 +935,10 @@ \setbox\gre@box@syllabletext=\box\voidb@x% \fi% \gre@calculate@enddifference{\wd\gre@box@syllablenotes}{\wd\gre@box@syllabletext}{\gre@dimen@textaligncenter}{\gre@dimen@notesaligncenter}{1}% - % gre@count@temp@one holds 0 if next is a not bar, 1 if it is + % gre@count@temp@one holds 1 if next is a bar, 2 if an alteration, else 0 \gre@count@temp@one=0% - \ifnum\gre@arg@oftwo@second#7=0\relax % - \ifnum\gre@arg@oftwo@first#7>9\relax % + \ifnum\nextalteration=0\relax % + \ifnum\nextalignment>9\relax % \gre@count@temp@one=1\relax % \fi % \else % @@ -993,7 +1004,7 @@ \fi% \fi % % recomputing end difference and final skip with the final hyphen - \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}#7% + \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\nextalignment}{\nextalteration}% \gre@calculate@enddifference{\wd\gre@box@syllablenotes}{\wd\gre@box@syllabletext}{\gre@dimen@textaligncenter}{\gre@dimen@notesaligncenter}{0}% \gre@calculate@syllablefinalskip{#4}{\gre@count@temp@one}% \else % @@ -1064,7 +1075,7 @@ \GreNoBreak % \fi% % we call end of syllable - \gre@syllable@end#7{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart\gre@nextmiddlesyllablepart\gre@nextendsyllablepart}}{#4}% + \gre@syllable@end{\nextalignment}{\nextalteration}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart\gre@nextmiddlesyllablepart\gre@nextendsyllablepart}}{#4}% \gre@push@endsyllable{#6}\relax % \global\gre@dimen@notesaligncenter=0pt\relax% very important, see flat and natural \gre@unsetfixedtextformat % diff --git a/tex/gregoriotex.lua b/tex/gregoriotex.lua index f45f5aa3..32756651 100644 --- a/tex/gregoriotex.lua +++ b/tex/gregoriotex.lua @@ -352,7 +352,11 @@ local function write_greaux() for id, tab in pairs(new_first_alterations) do aux:write(string.format(' ["%s"]={\n ', id)) for i, value in pairs(tab) do - aux:write(string.format('[%s]=%s,', i, value)) + if i == 'last' then + aux:write(string.format('["%s"]=%s,', i, value)) + else + aux:write(string.format('[%s]=%s,', i, value)) + end end aux:write(string.format('},\n')) end @@ -669,6 +673,7 @@ local function post_linebreak(h, groupcode, glyphes) local i = has_attribute(n, alteration_id_attr) local t = has_attribute(n, alteration_type_attr) new_score_first_alterations[i] = not seen[t] + new_score_first_alterations['last'] = i debugmessage("alteration", "id=%s type=%s seen=%s first=%s", i, t, seen[t], new_score_first_alterations[i]) seen[t] = true end @@ -1658,9 +1663,15 @@ local function hash_spaces(name, value) end -- prints 0 for true and 1 for false -local function is_first_alteration() +local function is_first_alteration(next) if score_first_alterations then local i = tex.getattribute(alteration_id_attr) + if next == 1 then + i = i + 1 + while score_first_alterations[i] == nil and i < score_first_alterations['last'] do + i = i + 1 + end + end local v = score_first_alterations[i] if v == true or v == nil then tex.print(0) From 7043fdb0f181da7ed0d428824c7b9909c9da3c72 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Fri, 24 Jan 2025 11:01:37 -0500 Subject: [PATCH 04/19] fix bug in previous commit --- tex/gregoriotex-signs.tex | 2 +- tex/gregoriotex-syllable.tex | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index 9a368708..b785534e 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -537,7 +537,7 @@ \gre@debugmsg{custos}{not blocked}% \gre@calculate@glyphraisevalue{#1}{0}{}% %here we need some tricks to draw the line before the custos (for the color) - \edef\gre@saved@attr@alteration@id{\number\gre@attr@alteration@id\relax}% save alteration id to avoid double-counting + \edef\gre@saved@attr@alteration@id{\number\gre@attr@alteration@id\relax}% \setbox\gre@box@temp@width=\hbox{% % we type a hskip and the we type the custos \gre@hskip\gre@space@skip@spacebeforeeolcustos\relax % diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index 522d1bcc..1822b660 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -373,7 +373,6 @@ \global\gre@boxingtrue% \let\ifgre@saved@prenotes@lastendswithmora\ifgre@lastendswithmora% \xdef\gre@saved@prenotes@lastoflinecount{\number\gre@lastoflinecount\relax }% - \edef\gre@saved@attr@alteration@id{\number\gre@attr@alteration@id\relax}% \ifgre@shownotes% \setbox\gre@box@syllablenotes=\hbox{#1}% \else% @@ -395,7 +394,6 @@ \fi % \let\ifgre@lastendswithmora\ifgre@saved@prenotes@lastendswithmora% \global\gre@lastoflinecount=\gre@saved@prenotes@lastoflinecount\relax % - \global\gre@attr@alteration@id=\gre@saved@attr@alteration@id\relax % \global\gre@count@lastglyphiscavum=0\relax % \global\gre@skip@bar@lastskip=0pt\relax % \global\gre@endofscorefalse % @@ -858,6 +856,10 @@ \gre@firstglyphtrue% \gre@dimen@bolextra = 0pt\relax% \gre@calculate@textaligncenter{\gre@saved@syllable@endsyllablepart}{\gre@firstsyllablepart}{\gre@middlesyllablepart}{0}% we first get the width between the alignment point and the end of the syllable + % Before measuring the notes, save the alteration id. We will + % restore it later, so that the measured notes and the actual notes + % have the same alteration ids, if any. + \edef\gre@saved@attr@alteration@id{\number\gre@attr@alteration@id\relax}% \gre@syllablenotes{#9}% we put the notes in a box, so that we have the width of it % now we calculate the begin difference, that is to say \gre@dimen@notesaligncenter - \gre@dimen@textaligncenter \gre@dimen@begindifference=\dimexpr(\gre@dimen@notesaligncenter - \gre@dimen@textaligncenter)\relax % @@ -911,12 +913,14 @@ \def\nextalignment{\gre@arg@oftwo@first#7}% \def\nextalteration{\gre@arg@oftwo@second#7}% \ifnum\nextalteration>0\relax - \gre@alteration@isfirst{1}% + \gre@alteration@isfirst{1}% this uses the alteration id after the notes \ifgre@alteration@isfirst \else \def\nextalteration{0}% \fi \fi + % Now we can restore the alteration id. + \global\gre@attr@alteration@id=\gre@saved@attr@alteration@id\relax % \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\nextalignment}{\nextalteration}% \gre@unsetfixednexttextformat % \ifgre@showlyrics% From 949b7947296445ef8de7a44bff32a067d7d86987 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Fri, 24 Jan 2025 13:46:27 -0500 Subject: [PATCH 05/19] with alteration-scope:line, if a natural follows a flat on the same line, it is still printed --- tex/gregoriotex-main.tex | 4 ++- tex/gregoriotex-signs.tex | 68 ++++++++++++++++++++++-------------- tex/gregoriotex-spaces.tex | 2 +- tex/gregoriotex-syllable.tex | 4 +-- tex/gregoriotex.lua | 14 ++++---- 5 files changed, 54 insertions(+), 38 deletions(-) diff --git a/tex/gregoriotex-main.tex b/tex/gregoriotex-main.tex index 73ac8402..402438bf 100644 --- a/tex/gregoriotex-main.tex +++ b/tex/gregoriotex-main.tex @@ -103,7 +103,9 @@ \newluatexattribute\gre@attr@syllable@id % % attributes for soft alterations -\newluatexattribute\gre@attr@alteration@type % +\newluatexattribute\gre@attr@alteration@height % + \edef\gre@attrid@alteration@height{\the\allocationnumber}% +\newluatexattribute\gre@attr@alteration@type % see \gre@calculate@nextnotesaligncenter for codes \edef\gre@attrid@alteration@type{\the\allocationnumber}% \newluatexattribute\gre@attr@alteration@id % diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index b785534e..941948a8 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -2697,22 +2697,26 @@ % the top level macro: % #1 is the height -% #2 is the char of the alteration -% #3 is the char of the alteration hole -% #4 is 1 if the alteration is the flat in a clef -% #5 are the signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph) -% #6 are the signs to typeset after the glyph (almost all signs) -% #7 is the line:char:column for a textedit link -\def\gre@alteration#1#2#3#4#5#6#7{% - \gre@trace{gre@alteration{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% +% #2 is the alteration type: 0 = none, 1 = flat, 2 = natural, 3 = sharp, +% 4 = parenthesized flat, 5 = parenthesized natural, +% 6 = parenthesized flat +% #3 is 1 if the alteration is the flat in a clef +% #4 are the signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph) +% #5 are the signs to typeset after the glyph (almost all signs) +% #6 is the line:char:column for a textedit link +\def\gre@alteration#1#2#3#4#5#6{% + \gre@trace{gre@alteration{#1}{#2}{#3}{#4}{#5}{#6}}% \global\advance\gre@attr@alteration@id by 1\relax \gre@alteration@isfirst{0}% \ifgre@alteration@isfirst - \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}% + \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}% \else + #4\relax + \hbox + attr \gre@attrid@alteration@height=#1\relax + attr \gre@attrid@alteration@type=#2\relax + {}% #5\relax - \hbox attr \gre@attrid@alteration@type=#1\relax{}% - #6\relax \fi } @@ -2732,11 +2736,21 @@ \fi } -\def\gre@alteration@visible#1#2#3#4#5#6#7{% - \gre@trace{gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% - \setbox\gre@box@temp@width=\hbox attr \gre@attrid@alteration@type=#1\relax - {\gre@pointandclick{#2}{#7}}% - \ifnum#4=0\relax % +\def\gre@alteration@visible#1#2#3#4#5#6{% + \gre@trace{gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}}% + \ifcase#2\relax + \or\def\alterationchar{\gre@fontchar@flat}\def\alterationhole{\gre@fontchar@flathole}% flat + \or\def\alterationchar{\gre@fontchar@natural}\def\alterationhole{\gre@fontchar@naturalhole}% natural + \or\def\alterationchar{\gre@fontchar@sharp}\def\alterationhole{\gre@fontchar@sharphole}% sharp + \or\def\alterationchar{\gre@fontchar@flatparen}\def\alterationhole{\gre@fontchar@flatparenhole}% parenthesized flat + \or\def\alterationchar{\gre@fontchar@naturalparen}\def\alterationhole{\gre@fontchar@naturalparenhole}% parenthesized natural + \or\def\alterationchar{\gre@fontchar@sharpparen}\def\alterationhole{\gre@fontchar@sharpparenhole}% parenthesized sharp + \fi + \setbox\gre@box@temp@width=\hbox + attr \gre@attrid@alteration@height=#1\relax + attr \gre@attrid@alteration@type=#2\relax + {\gre@pointandclick{\alterationchar}{#6}}% + \ifnum#3=0\relax % \gre@newglyphcommon % \fi % \ifgre@in@custos\else\relax % @@ -2745,16 +2759,16 @@ % the three next lines are a trick to get the additional lines below the glyphs \gre@skip@temp@one = \gre@dimen@lastglyphwidth\relax% \kern\gre@skip@temp@one % - #5\relax % + #4\relax % \kern-\gre@skip@temp@one % \gre@calculate@glyphraisevalue{#1}{0}{}% \ifgre@hidealtlines % - \gre@fillhole{#3}{0}% + \gre@fillhole{\alterationhole}{0}% \fi % \raise \gre@dimen@glyphraisevalue% \copy\gre@box@temp@width% - #6\relax % - \ifnum#4=0\relax % + #5\relax % + \ifnum#3=0\relax % % we try to avoid line breaking after a flat or a natural \GreNoBreak % \gre@skip@temp@four = \gre@space@dimen@alterationspace\relax% @@ -2780,7 +2794,7 @@ \def\GreFlat#1#2#3#4#5{% \gre@trace{GreFlat{#1}{#2}{#3}{#4}{#5}}% - \gre@alteration{#1}{\gre@fontchar@flat}{\gre@fontchar@flathole}{#2}{#3}{#4}{#5}% + \gre@alteration{#1}{1}{#2}{#3}{#4}{#5}% \relax% \gre@trace@end% }% @@ -2789,7 +2803,7 @@ \def\GreFlatParen#1#2#3#4#5{% \gre@trace{GreFlatParen{#1}{#2}{#3}{#4}{#5}}% - \gre@alteration{#1}{\gre@fontchar@flatparen}{\gre@fontchar@flatparenhole}{#2}{#3}{#4}{#5}% + \gre@alteration{#1}{4}{#2}{#3}{#4}{#5}% \relax% \gre@trace@end% }% @@ -2798,7 +2812,7 @@ \def\GreNatural#1#2#3#4#5{% \gre@trace{GreNatural{#1}{#2}{#3}{#4}{#5}}% - \gre@alteration{#1}{\gre@fontchar@natural}{\gre@fontchar@naturalhole}{#2}{#3}{#4}{#5}% + \gre@alteration{#1}{2}{#2}{#3}{#4}{#5}% \relax% \gre@trace@end% }% @@ -2807,7 +2821,7 @@ \def\GreNaturalParen#1#2#3#4#5{% \gre@trace{GreNaturalParen{#1}{#2}{#3}{#4}{#5}}% - \gre@alteration{#1}{\gre@fontchar@naturalparen}{\gre@fontchar@naturalparenhole}{#2}{#3}{#4}{#5}% + \gre@alteration{#1}{5}{#2}{#3}{#4}{#5}% \relax% \gre@trace@end% }% @@ -2816,7 +2830,7 @@ \def\GreSharp#1#2#3#4#5{% \gre@trace{GreSharp{#1}{#2}{#3}{#4}{#5}}% - \gre@alteration{#1}{\gre@fontchar@sharp}{\gre@fontchar@sharphole}{#2}{#3}{#4}{#5}% + \gre@alteration{#1}{3}{#2}{#3}{#4}{#5}% \relax% \gre@trace@end% }% @@ -2824,8 +2838,8 @@ % Same as the one before, but for sharps. \def\GreSharpParen#1#2#3#4#5{% - \gre@trace{GreSharpParem{#1}{#2}{#3}{#4}{#5}}% - \gre@alteration{#1}{\gre@fontchar@sharpparen}{\gre@fontchar@sharpparenhole}{#2}{#3}{#4}{#5}% + \gre@trace{GreSharpParen{#1}{#2}{#3}{#4}{#5}}% + \gre@alteration{#1}{6}{#2}{#3}{#4}{#5}% \relax% \gre@trace@end% }% diff --git a/tex/gregoriotex-spaces.tex b/tex/gregoriotex-spaces.tex index 9acf0a76..c2d6b063 100644 --- a/tex/gregoriotex-spaces.tex +++ b/tex/gregoriotex-spaces.tex @@ -1116,7 +1116,7 @@ %% 3 : the middle letters of the next syllable %% 4 : the end letters of the next syllable %% 5 : the type of notes alignment -%% 6 : alteration type (see gre@calculate@nextnotesaligncenter) +%% 6 : alteration type (see \gre@alteration) \def\gre@calculate@nextbegindifference#1#2#3#4#5#6{% \gre@trace{gre@calculate@nextbegindifference{#1}{#2}{#3}{#4}{#5}{#6}}% \ifnum\gre@lastoflinecount=1\relax % diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index 1822b660..76ca63a4 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -305,9 +305,7 @@ % this is the function that we call when we try to determine the next aligncenter of the notes. % #1 is the note type -% #2 is the alteration style : 0 = none, 1 = flat, 2 = natural, 3 = sharp, -% 4 = parenthesized flat, 5 = parenthesized natural, -% 6 = parenthesized flat +% #2 is the alteration type (see \gre@alteration) \def\gre@calculate@nextnotesaligncenter#1#2{% \gre@trace{gre@calculate@nextnotesaligncenter{#1}{#2}}% \gre@calculate@simplenotesaligncenter{#1}{1}% diff --git a/tex/gregoriotex.lua b/tex/gregoriotex.lua index 32756651..0868a447 100644 --- a/tex/gregoriotex.lua +++ b/tex/gregoriotex.lua @@ -65,6 +65,7 @@ local glyph_bottom_attr = luatexbase.attributes['gre@attr@glyph@bottom'] local prev_line_id = nil local alteration_type_attr = luatexbase.attributes['gre@attr@alteration@type'] +local alteration_height_attr = luatexbase.attributes['gre@attr@alteration@height'] local alteration_id_attr = luatexbase.attributes['gre@attr@alteration@id'] local syllable_id_attr = luatexbase.attributes['gre@attr@syllable@id'] @@ -665,17 +666,18 @@ local function post_linebreak(h, groupcode, glyphes) currentshift=0 end end - -- Record whether each alteration is the first on the line + -- Record whether each alteration is the first on the line, or is different than the previous alteration for line in traverse_id(hlist, h) do local seen = {} for n in traverse_id(hlist, line.head) do - if has_attribute(n, alteration_type_attr) ~= nil then + local t = has_attribute(n, alteration_type_attr) + if t ~= nil and t > 0 then local i = has_attribute(n, alteration_id_attr) - local t = has_attribute(n, alteration_type_attr) - new_score_first_alterations[i] = not seen[t] + local h = has_attribute(n, alteration_height_attr) + new_score_first_alterations[i] = seen[h] ~= t new_score_first_alterations['last'] = i - debugmessage("alteration", "id=%s type=%s seen=%s first=%s", i, t, seen[t], new_score_first_alterations[i]) - seen[t] = true + debugmessage("alteration", "id=%s type=%s height=%s seen=%s first=%s", i, t, h, seen[t], new_score_first_alterations[i]) + seen[h] = t end end end From 3eac5d4ee43ee11d19e5f30035c10853f77614d0 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Fri, 24 Jan 2025 19:56:12 -0500 Subject: [PATCH 06/19] fix bug in last commit and clean up --- tex/gregoriotex-signs.tex | 18 +++++++++--------- tex/gregoriotex-syllable.tex | 24 ++++++++++++------------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index 941948a8..5c3bc406 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -2707,8 +2707,8 @@ \def\gre@alteration#1#2#3#4#5#6{% \gre@trace{gre@alteration{#1}{#2}{#3}{#4}{#5}{#6}}% \global\advance\gre@attr@alteration@id by 1\relax - \gre@alteration@isfirst{0}% - \ifgre@alteration@isfirst + \gre@alteration@isvisible{0}% + \ifgre@alteration@isvisible \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}% \else #4\relax @@ -2720,19 +2720,19 @@ \fi } -% Test whether an alteration is the first on its line. +% Test whether an alteration should be visible. % #1 = 0 for current alteration, 1 for next alteration. -% Sets \ifgre@alteration@isfirsttrue or \ifgre@alteration@isfirstfalse. -\newif\ifgre@alteration@isfirst -\def\gre@alteration@isfirst#1{% +% Sets \ifgre@alteration@isvisibletrue or \ifgre@alteration@isvisiblefalse. +\newif\ifgre@alteration@isvisible +\def\gre@alteration@isvisible#1{% \ifgre@alteration@line \ifcase\directlua{gregoriotex.is_first_alteration(#1)}\relax - \global\gre@alteration@isfirsttrue + \global\gre@alteration@isvisibletrue \else - \global\gre@alteration@isfirstfalse + \global\gre@alteration@isvisiblefalse \fi \else - \global\gre@alteration@isfirstfalse + \global\gre@alteration@isvisibletrue \fi } diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index 76ca63a4..409d4099 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -908,18 +908,18 @@ #5% % if the next glyph has an alteration, check if it is suppressed; % if so, pretend there's no alteration - \def\nextalignment{\gre@arg@oftwo@first#7}% - \def\nextalteration{\gre@arg@oftwo@second#7}% - \ifnum\nextalteration>0\relax - \gre@alteration@isfirst{1}% this uses the alteration id after the notes - \ifgre@alteration@isfirst + \def\next@alignment{\gre@arg@oftwo@first#7}% + \def\next@alteration{\gre@arg@oftwo@second#7}% + \ifnum\next@alteration>0\relax + \gre@alteration@isvisible{1}% if the notes contain an alteration, the id was incremented, so this checks the alteration after the notes + \ifgre@alteration@isvisible \else - \def\nextalteration{0}% + \def\next@alteration{0}% \fi \fi - % Now we can restore the alteration id. + % now we can restore the alteration id to typeset the notes for real \global\gre@attr@alteration@id=\gre@saved@attr@alteration@id\relax % - \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\nextalignment}{\nextalteration}% + \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\next@alignment}{\next@alteration}% \gre@unsetfixednexttextformat % \ifgre@showlyrics% \setbox\gre@box@syllabletext=\hbox{% @@ -939,8 +939,8 @@ \gre@calculate@enddifference{\wd\gre@box@syllablenotes}{\wd\gre@box@syllabletext}{\gre@dimen@textaligncenter}{\gre@dimen@notesaligncenter}{1}% % gre@count@temp@one holds 1 if next is a bar, 2 if an alteration, else 0 \gre@count@temp@one=0% - \ifnum\nextalteration=0\relax % - \ifnum\nextalignment>9\relax % + \ifnum\next@alteration=0\relax % + \ifnum\next@alignment>9\relax % \gre@count@temp@one=1\relax % \fi % \else % @@ -1006,7 +1006,7 @@ \fi% \fi % % recomputing end difference and final skip with the final hyphen - \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\nextalignment}{\nextalteration}% + \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\next@alignment}{\next@alteration}% \gre@calculate@enddifference{\wd\gre@box@syllablenotes}{\wd\gre@box@syllabletext}{\gre@dimen@textaligncenter}{\gre@dimen@notesaligncenter}{0}% \gre@calculate@syllablefinalskip{#4}{\gre@count@temp@one}% \else % @@ -1077,7 +1077,7 @@ \GreNoBreak % \fi% % we call end of syllable - \gre@syllable@end{\nextalignment}{\nextalteration}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart\gre@nextmiddlesyllablepart\gre@nextendsyllablepart}}{#4}% + \gre@syllable@end{\next@alignment}{\next@alteration}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart\gre@nextmiddlesyllablepart\gre@nextendsyllablepart}}{#4}% \gre@push@endsyllable{#6}\relax % \global\gre@dimen@notesaligncenter=0pt\relax% very important, see flat and natural \gre@unsetfixedtextformat % From e2f293b06b65e7b3fef7d2580d542bb02aec4788 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Fri, 24 Jan 2025 21:31:29 -0500 Subject: [PATCH 07/19] suppressed flats shouldn't have ledger lines --- tex/gregoriotex-main.tex | 2 +- tex/gregoriotex-signs.tex | 3 +-- tex/gregoriotex.lua | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tex/gregoriotex-main.tex b/tex/gregoriotex-main.tex index 402438bf..b49cefa7 100644 --- a/tex/gregoriotex-main.tex +++ b/tex/gregoriotex-main.tex @@ -105,7 +105,7 @@ % attributes for soft alterations \newluatexattribute\gre@attr@alteration@height % \edef\gre@attrid@alteration@height{\the\allocationnumber}% -\newluatexattribute\gre@attr@alteration@type % see \gre@calculate@nextnotesaligncenter for codes +\newluatexattribute\gre@attr@alteration@type % see \gre@alteration for codes \edef\gre@attrid@alteration@type{\the\allocationnumber}% \newluatexattribute\gre@attr@alteration@id % diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index 5c3bc406..ee723372 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -2711,12 +2711,11 @@ \ifgre@alteration@isvisible \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}% \else - #4\relax + % ignore #4 (ledger line) and #5 (not used anyway?) \hbox attr \gre@attrid@alteration@height=#1\relax attr \gre@attrid@alteration@type=#2\relax {}% - #5\relax \fi } diff --git a/tex/gregoriotex.lua b/tex/gregoriotex.lua index 0868a447..ce178e47 100644 --- a/tex/gregoriotex.lua +++ b/tex/gregoriotex.lua @@ -666,10 +666,11 @@ local function post_linebreak(h, groupcode, glyphes) currentshift=0 end end - -- Record whether each alteration is the first on the line, or is different than the previous alteration + -- For each alteration, record true if it is the first on the line or it is different than the previous alteration; record false otherwise for line in traverse_id(hlist, h) do local seen = {} for n in traverse_id(hlist, line.head) do + -- This skips custos alterations because they're one level deeper. As a result, they are always printed. local t = has_attribute(n, alteration_type_attr) if t ~= nil and t > 0 then local i = has_attribute(n, alteration_id_attr) From 1a0b474125ecdb4de64a29d99762cb26b1888167 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Sat, 25 Jan 2025 13:14:11 -0500 Subject: [PATCH 08/19] rename some local macros with \gre@ prefix --- tex/gregoriotex-signs.tex | 16 ++++++++-------- tex/gregoriotex-syllable.tex | 18 +++++++++--------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index ee723372..a90321ea 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -2738,17 +2738,17 @@ \def\gre@alteration@visible#1#2#3#4#5#6{% \gre@trace{gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}}% \ifcase#2\relax - \or\def\alterationchar{\gre@fontchar@flat}\def\alterationhole{\gre@fontchar@flathole}% flat - \or\def\alterationchar{\gre@fontchar@natural}\def\alterationhole{\gre@fontchar@naturalhole}% natural - \or\def\alterationchar{\gre@fontchar@sharp}\def\alterationhole{\gre@fontchar@sharphole}% sharp - \or\def\alterationchar{\gre@fontchar@flatparen}\def\alterationhole{\gre@fontchar@flatparenhole}% parenthesized flat - \or\def\alterationchar{\gre@fontchar@naturalparen}\def\alterationhole{\gre@fontchar@naturalparenhole}% parenthesized natural - \or\def\alterationchar{\gre@fontchar@sharpparen}\def\alterationhole{\gre@fontchar@sharpparenhole}% parenthesized sharp + \or\def\gre@alteration@char{\gre@fontchar@flat}\def\gre@alteration@hole{\gre@fontchar@flathole}% flat + \or\def\gre@alteration@char{\gre@fontchar@natural}\def\gre@alteration@hole{\gre@fontchar@naturalhole}% natural + \or\def\gre@alteration@char{\gre@fontchar@sharp}\def\gre@alteration@hole{\gre@fontchar@sharphole}% sharp + \or\def\gre@alteration@char{\gre@fontchar@flatparen}\def\gre@alteration@hole{\gre@fontchar@flatparenhole}% parenthesized flat + \or\def\gre@alteration@char{\gre@fontchar@naturalparen}\def\gre@alteration@hole{\gre@fontchar@naturalparenhole}% parenthesized natural + \or\def\gre@alteration@char{\gre@fontchar@sharpparen}\def\gre@alteration@hole{\gre@fontchar@sharpparenhole}% parenthesized sharp \fi \setbox\gre@box@temp@width=\hbox attr \gre@attrid@alteration@height=#1\relax attr \gre@attrid@alteration@type=#2\relax - {\gre@pointandclick{\alterationchar}{#6}}% + {\gre@pointandclick{\gre@alteration@char}{#6}}% \ifnum#3=0\relax % \gre@newglyphcommon % \fi % @@ -2762,7 +2762,7 @@ \kern-\gre@skip@temp@one % \gre@calculate@glyphraisevalue{#1}{0}{}% \ifgre@hidealtlines % - \gre@fillhole{\alterationhole}{0}% + \gre@fillhole{\gre@alteration@hole}{0}% \fi % \raise \gre@dimen@glyphraisevalue% \copy\gre@box@temp@width% diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index 409d4099..cacbeaa9 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -908,18 +908,18 @@ #5% % if the next glyph has an alteration, check if it is suppressed; % if so, pretend there's no alteration - \def\next@alignment{\gre@arg@oftwo@first#7}% - \def\next@alteration{\gre@arg@oftwo@second#7}% - \ifnum\next@alteration>0\relax + \def\gre@nextalignment{\gre@arg@oftwo@first#7}% + \def\gre@nextalteration{\gre@arg@oftwo@second#7}% + \ifnum\gre@nextalteration>0\relax \gre@alteration@isvisible{1}% if the notes contain an alteration, the id was incremented, so this checks the alteration after the notes \ifgre@alteration@isvisible \else - \def\next@alteration{0}% + \def\gre@nextalteration{0}% \fi \fi % now we can restore the alteration id to typeset the notes for real \global\gre@attr@alteration@id=\gre@saved@attr@alteration@id\relax % - \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\next@alignment}{\next@alteration}% + \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\gre@nextalignment}{\gre@nextalteration}% \gre@unsetfixednexttextformat % \ifgre@showlyrics% \setbox\gre@box@syllabletext=\hbox{% @@ -939,8 +939,8 @@ \gre@calculate@enddifference{\wd\gre@box@syllablenotes}{\wd\gre@box@syllabletext}{\gre@dimen@textaligncenter}{\gre@dimen@notesaligncenter}{1}% % gre@count@temp@one holds 1 if next is a bar, 2 if an alteration, else 0 \gre@count@temp@one=0% - \ifnum\next@alteration=0\relax % - \ifnum\next@alignment>9\relax % + \ifnum\gre@nextalteration=0\relax % + \ifnum\gre@nextalignment>9\relax % \gre@count@temp@one=1\relax % \fi % \else % @@ -1006,7 +1006,7 @@ \fi% \fi % % recomputing end difference and final skip with the final hyphen - \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\next@alignment}{\next@alteration}% + \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\gre@nextalignment}{\gre@nextalteration}% \gre@calculate@enddifference{\wd\gre@box@syllablenotes}{\wd\gre@box@syllabletext}{\gre@dimen@textaligncenter}{\gre@dimen@notesaligncenter}{0}% \gre@calculate@syllablefinalskip{#4}{\gre@count@temp@one}% \else % @@ -1077,7 +1077,7 @@ \GreNoBreak % \fi% % we call end of syllable - \gre@syllable@end{\next@alignment}{\next@alteration}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart\gre@nextmiddlesyllablepart\gre@nextendsyllablepart}}{#4}% + \gre@syllable@end{\gre@nextalignment}{\gre@nextalteration}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart\gre@nextmiddlesyllablepart\gre@nextendsyllablepart}}{#4}% \gre@push@endsyllable{#6}\relax % \global\gre@dimen@notesaligncenter=0pt\relax% very important, see flat and natural \gre@unsetfixedtextformat % From a0054fd2c048c13c5610468ecd7be209a6fb4717 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Sat, 25 Jan 2025 22:17:07 -0500 Subject: [PATCH 09/19] Add "soft" flat (X), sharp (#*), and natural (Y), which appear only if they are the first on the line or different from the previous alteration. Remove the header option alteration-scope. --- src/gabc/gabc-glyphs-determination.c | 3 ++ src/gabc/gabc-notes-determination.l | 12 ++++++ src/gabc/gabc-write.c | 9 +++++ src/gregoriotex/gregoriotex-position.c | 12 ++++++ src/gregoriotex/gregoriotex-write.c | 33 ++++++++++++++++ src/gregoriotex/gregoriotex.h | 5 ++- src/struct.c | 3 ++ src/struct.h | 3 ++ tex/gregoriotex-main.tex | 14 ------- tex/gregoriotex-signs.tex | 53 +++++++++++++++++++++----- tex/gregoriotex-syllable.tex | 2 +- 11 files changed, 123 insertions(+), 26 deletions(-) diff --git a/src/gabc/gabc-glyphs-determination.c b/src/gabc/gabc-glyphs-determination.c index bf9b0a61..5d412975 100644 --- a/src/gabc/gabc-glyphs-determination.c +++ b/src/gabc/gabc-glyphs-determination.c @@ -138,10 +138,13 @@ static char add_note_to_a_glyph(gregorio_glyph_type current_glyph_type, break; case S_FLAT: case S_FLAT_PAREN: + case S_FLAT_SOFT: case S_SHARP: case S_SHARP_PAREN: + case S_SHARP_SOFT: case S_NATURAL: case S_NATURAL_PAREN: + case S_NATURAL_SOFT: next_glyph_type = G_ALTERATION; *end_of_glyph = DET_END_OF_BOTH; break; diff --git a/src/gabc/gabc-notes-determination.l b/src/gabc/gabc-notes-determination.l index 9fc185f3..da16d227 100644 --- a/src/gabc/gabc-notes-determination.l +++ b/src/gabc/gabc-notes-determination.l @@ -1302,6 +1302,10 @@ x\? { gregorio_change_shape(current_note, S_FLAT_PAREN, legacy_oriscus_orientation); } +X { + gregorio_change_shape(current_note, S_FLAT_SOFT, + legacy_oriscus_orientation); + } # { gregorio_change_shape(current_note, S_SHARP, legacy_oriscus_orientation); @@ -1310,6 +1314,10 @@ x\? { gregorio_change_shape(current_note, S_SHARP_PAREN, legacy_oriscus_orientation); } +#\* { + gregorio_change_shape(current_note, S_SHARP_SOFT, + legacy_oriscus_orientation); + } y { gregorio_change_shape(current_note, S_NATURAL, legacy_oriscus_orientation); @@ -1318,6 +1326,10 @@ y\? { gregorio_change_shape(current_note, S_NATURAL_PAREN, legacy_oriscus_orientation); } +Y { + gregorio_change_shape(current_note, S_NATURAL_SOFT, + legacy_oriscus_orientation); + } !?\/0 { gregorio_add_space_as_note(¤t_note, SP_HALF_SPACE, NULL, ¬es_lloc); diff --git a/src/gabc/gabc-write.c b/src/gabc/gabc-write.c index 9ebed376..0da6c5e7 100644 --- a/src/gabc/gabc-write.c +++ b/src/gabc/gabc-write.c @@ -631,18 +631,27 @@ static void gabc_write_gregorio_note(FILE *f, gregorio_note *note, case S_FLAT_PAREN: fprintf(f, "%cx?", pitch_letter(note->u.note.pitch)); break; + case S_FLAT_SOFT: + fprintf(f, "%cX", pitch_letter(note->u.note.pitch)); + break; case S_NATURAL: fprintf(f, "%cy", pitch_letter(note->u.note.pitch)); break; case S_NATURAL_PAREN: fprintf(f, "%cy?", pitch_letter(note->u.note.pitch)); break; + case S_NATURAL_SOFT: + fprintf(f, "%cY", pitch_letter(note->u.note.pitch)); + break; case S_SHARP: fprintf(f, "%c#", pitch_letter(note->u.note.pitch)); break; case S_SHARP_PAREN: fprintf(f, "%c#?", pitch_letter(note->u.note.pitch)); break; + case S_SHARP_SOFT: + fprintf(f, "%c#*", pitch_letter(note->u.note.pitch)); + break; case S_VIRGA: fprintf(f, "%cv", pitch_letter(note->u.note.pitch)); break; diff --git a/src/gregoriotex/gregoriotex-position.c b/src/gregoriotex/gregoriotex-position.c index 76c7765c..dca8dd9b 100644 --- a/src/gregoriotex/gregoriotex-position.c +++ b/src/gregoriotex/gregoriotex-position.c @@ -90,10 +90,13 @@ OFFSET_CASE(LeadingQuilisma); OFFSET_CASE(LeadingOriscus); OFFSET_CASE(Flat); OFFSET_CASE(FlatParen); +OFFSET_CASE(FlatSoft); OFFSET_CASE(Sharp); OFFSET_CASE(SharpParen); +OFFSET_CASE(SharpSoft); OFFSET_CASE(Natural); OFFSET_CASE(NaturalParen); +OFFSET_CASE(NaturalSoft); static __inline const char *note_before_last_note_case_ignoring_deminutus( const gregorio_note *const current_note) @@ -951,18 +954,27 @@ static gregorio_vposition advise_positioning(const gregorio_glyph *const glyph, case S_FLAT_PAREN: note->gtex_offset_case = FlatParen; break; + case S_FLAT_SOFT: + note->gtex_offset_case = FlatSoft; + break; case S_SHARP: note->gtex_offset_case = Sharp; break; case S_SHARP_PAREN: note->gtex_offset_case = SharpParen; break; + case S_SHARP_SOFT: + note->gtex_offset_case = SharpSoft; + break; case S_NATURAL: note->gtex_offset_case = Natural; break; case S_NATURAL_PAREN: note->gtex_offset_case = NaturalParen; break; + case S_NATURAL_SOFT: + note->gtex_offset_case = NaturalSoft; + break; default: note->gtex_offset_case = last_note_case(glyph, fused_single_note_case(glyph, FinalPunctum, LeadingPunctum), diff --git a/src/gregoriotex/gregoriotex-write.c b/src/gregoriotex/gregoriotex-write.c index ddf0537e..3714849d 100644 --- a/src/gregoriotex/gregoriotex-write.c +++ b/src/gregoriotex/gregoriotex-write.c @@ -90,6 +90,7 @@ SHAPE(DescendensOriscusScapusOpenqueue); SHAPE(DescendensPunctumInclinatum); SHAPE(Flat); SHAPE(FlatParen); +SHAPE(FlatSoft); SHAPE(Flexus); SHAPE(FlexusLongqueue); SHAPE(FlexusNobar); @@ -106,6 +107,7 @@ SHAPE(Linea); SHAPE(LineaPunctum); SHAPE(Natural); SHAPE(NaturalParen); +SHAPE(NaturalSoft); SHAPE(OriscusDeminutus); SHAPE(Pes); SHAPE(PesAscendensOriscus); @@ -145,6 +147,7 @@ SHAPE(SalicusLongqueue); SHAPE(Scandicus); SHAPE(Sharp); SHAPE(SharpParen); +SHAPE(SharpSoft); SHAPE(Stropha); SHAPE(StrophaAucta); SHAPE(StrophaAuctaLongtail); @@ -789,14 +792,20 @@ static const char *determine_note_glyph_name(const gregorio_note *const note, return SHAPE_Flat; case S_FLAT_PAREN: return SHAPE_FlatParen; + case S_FLAT_SOFT: + return SHAPE_FlatSoft; case S_SHARP: return SHAPE_Sharp; case S_SHARP_PAREN: return SHAPE_SharpParen; + case S_SHARP_SOFT: + return SHAPE_SharpSoft; case S_NATURAL: return SHAPE_Natural; case S_NATURAL_PAREN: return SHAPE_NaturalParen; + case S_NATURAL_SOFT: + return SHAPE_NaturalSoft; default: /* not reachable unless there's a programming error */ /* LCOV_EXCL_START */ @@ -2609,14 +2618,20 @@ static __inline const char *alteration_name( return "Flat"; case S_FLAT_PAREN: return "FlatParen"; + case S_FLAT_SOFT: + return "FlatSoft"; case S_SHARP: return "Sharp"; case S_SHARP_PAREN: return "SharpParen"; + case S_SHARP_SOFT: + return "SharpSoft"; case S_NATURAL: return "Natural"; case S_NATURAL_PAREN: return "NaturalParen"; + case S_NATURAL_SOFT: + return "NaturalSoft"; default: return ""; } @@ -2689,10 +2704,13 @@ static void write_note(FILE *f, gregorio_note *note, switch (note->u.note.shape) { case S_FLAT: case S_FLAT_PAREN: + case S_FLAT_SOFT: case S_NATURAL: case S_NATURAL_PAREN: + case S_NATURAL_SOFT: case S_SHARP: case S_SHARP_PAREN: + case S_SHARP_SOFT: fprintf(f, "\\Gre%s{%d}{0}", alteration_name(note->u.note.shape), pitch_value(note->u.note.pitch)); break; @@ -2783,18 +2801,27 @@ static void syllable_first_type(gregorio_syllable *syllable, case S_FLAT_PAREN: *alteration = ALT_FLAT_PAREN; break; + case S_FLAT_SOFT: + *alteration = ALT_FLAT_SOFT; + break; case S_NATURAL: *alteration = ALT_NATURAL; break; case S_NATURAL_PAREN: *alteration = ALT_NATURAL_PAREN; break; + case S_NATURAL_SOFT: + *alteration = ALT_NATURAL_SOFT; + break; case S_SHARP: *alteration = ALT_SHARP; break; case S_SHARP_PAREN: *alteration = ALT_SHARP_PAREN; break; + case S_SHARP_SOFT: + *alteration = ALT_SHARP_SOFT; + break; default: /* not reachable unless there's a programming error */ /* LCOV_EXCL_START */ @@ -3938,10 +3965,13 @@ static void write_default_end_of_element(FILE *f, switch(last_note->u.note.shape) { case S_FLAT: case S_FLAT_PAREN: + case S_FLAT_SOFT: case S_SHARP: case S_SHARP_PAREN: + case S_SHARP_SOFT: case S_NATURAL: case S_NATURAL_PAREN: + case S_NATURAL_SOFT: break; default: last_pitch = last_note->u.note.pitch; @@ -3955,10 +3985,13 @@ static void write_default_end_of_element(FILE *f, switch(next_note->u.note.shape) { case S_FLAT: case S_FLAT_PAREN: + case S_FLAT_SOFT: case S_SHARP: case S_SHARP_PAREN: + case S_SHARP_SOFT: case S_NATURAL: case S_NATURAL_PAREN: + case S_NATURAL_SOFT: break; default: if (next_note->u.note.pitch != NO_PITCH && diff --git a/src/gregoriotex/gregoriotex.h b/src/gregoriotex/gregoriotex.h index b61b26c5..7fc71f36 100644 --- a/src/gregoriotex/gregoriotex.h +++ b/src/gregoriotex/gregoriotex.h @@ -89,7 +89,10 @@ typedef enum gtex_alteration { ALT_SHARP = 3, ALT_FLAT_PAREN = 4, ALT_NATURAL_PAREN = 5, - ALT_SHARP_PAREN = 6 + ALT_SHARP_PAREN = 6, + ALT_FLAT_SOFT = 7, + ALT_NATURAL_SOFT = 8, + ALT_SHARP_SOFT = 9 } gtex_alteration; /* Here we define a function that will determine the number of the diff --git a/src/struct.c b/src/struct.c index 6871df42..a1fb0082 100644 --- a/src/struct.c +++ b/src/struct.c @@ -1301,10 +1301,13 @@ static __inline signed char next_pitch_from_glyph(const gregorio_glyph *glyph, switch (note->u.note.shape) { case S_FLAT: case S_FLAT_PAREN: + case S_FLAT_SOFT: case S_SHARP: case S_SHARP_PAREN: + case S_SHARP_SOFT: case S_NATURAL: case S_NATURAL_PAREN: + case S_NATURAL_SOFT: if (note->u.note.pitch >= LOWEST_PITCH && note->u.note.pitch <= MAX_PITCH) { alterations[note->u.note.pitch] = diff --git a/src/struct.h b/src/struct.h index 7c1e95e6..971eba70 100644 --- a/src/struct.h +++ b/src/struct.h @@ -123,10 +123,13 @@ ENUM(gregorio_clef, GREGORIO_CLEF); E(S_LINEA_PUNCTUM) \ E(S_FLAT) \ E(S_FLAT_PAREN) \ + E(S_FLAT_SOFT) \ E(S_SHARP) \ E(S_SHARP_PAREN) \ + E(S_SHARP_SOFT) \ E(S_NATURAL) \ E(S_NATURAL_PAREN) \ + E(S_NATURAL_SOFT) \ /* special shapes that must not appear in the final form of the score : * quadratum is the shape of the first note of a punctum quadratum * and quilisma quadratum is the shape of the first note of a pes diff --git a/tex/gregoriotex-main.tex b/tex/gregoriotex-main.tex index b49cefa7..57b9031e 100644 --- a/tex/gregoriotex-main.tex +++ b/tex/gregoriotex-main.tex @@ -2142,18 +2142,4 @@ % We load the default space configuration. \greloadspaceconf{default}% -\newif\ifgre@alteration@line -\gre@alteration@linefalse -\def\gresetalterationscope#1{% - \IfStrEqCase{#1}{% - {none}% - {\gre@alteration@linefalse}% - {line}% - {\gre@alteration@linetrue}% - }[% all other cases - \gre@error{Unrecognized option "#1" for \protect\gresetalterationscope\MessageBreak Possible options are: 'none' and 'line'}% - ]% -} -\gresetheadercapture{alteration-scope}{gresetalterationscope}{} - \input gregoriotex-nabc.tex diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index a90321ea..34b358e1 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -2698,8 +2698,8 @@ % the top level macro: % #1 is the height % #2 is the alteration type: 0 = none, 1 = flat, 2 = natural, 3 = sharp, -% 4 = parenthesized flat, 5 = parenthesized natural, -% 6 = parenthesized flat +% 4/5/6 = parenthesized flat/natural/sharp, +% 7 = soft flat % #3 is 1 if the alteration is the flat in a clef % #4 are the signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph) % #5 are the signs to typeset after the glyph (almost all signs) @@ -2707,30 +2707,35 @@ \def\gre@alteration#1#2#3#4#5#6{% \gre@trace{gre@alteration{#1}{#2}{#3}{#4}{#5}{#6}}% \global\advance\gre@attr@alteration@id by 1\relax - \gre@alteration@isvisible{0}% + \def\gre@alteration@type{#2}% + \gre@alteration@isvisible{0}{\gre@alteration@type}% + \ifnum\gre@alteration@type>6\relax % treat soft alterations like hard + \edef\gre@alteration@type{\numexpr\gre@alteration@type-6\relax}% + \fi \ifgre@alteration@isvisible - \gre@alteration@visible{#1}{#2}{#3}{#4}{#5}{#6}% + \gre@alteration@visible{#1}{\gre@alteration@type}{#3}{#4}{#5}{#6}% \else % ignore #4 (ledger line) and #5 (not used anyway?) \hbox attr \gre@attrid@alteration@height=#1\relax - attr \gre@attrid@alteration@type=#2\relax + attr \gre@attrid@alteration@type=\gre@alteration@type\relax {}% \fi } % Test whether an alteration should be visible. -% #1 = 0 for current alteration, 1 for next alteration. +% #1: 0 for current alteration, 1 for next alteration. +% #2: alteration type % Sets \ifgre@alteration@isvisibletrue or \ifgre@alteration@isvisiblefalse. \newif\ifgre@alteration@isvisible -\def\gre@alteration@isvisible#1{% - \ifgre@alteration@line +\def\gre@alteration@isvisible#1#2{% + \ifnum#2>6 % soft: depends on whether it's the first \ifcase\directlua{gregoriotex.is_first_alteration(#1)}\relax \global\gre@alteration@isvisibletrue \else \global\gre@alteration@isvisiblefalse \fi - \else + \else % hard: always visible \global\gre@alteration@isvisibletrue \fi } @@ -2744,6 +2749,7 @@ \or\def\gre@alteration@char{\gre@fontchar@flatparen}\def\gre@alteration@hole{\gre@fontchar@flatparenhole}% parenthesized flat \or\def\gre@alteration@char{\gre@fontchar@naturalparen}\def\gre@alteration@hole{\gre@fontchar@naturalparenhole}% parenthesized natural \or\def\gre@alteration@char{\gre@fontchar@sharpparen}\def\gre@alteration@hole{\gre@fontchar@sharpparenhole}% parenthesized sharp + \else\gre@error{Invalid alteration type}% soft alterations should have been changed to hard \fi \setbox\gre@box@temp@width=\hbox attr \gre@attrid@alteration@height=#1\relax @@ -2807,6 +2813,15 @@ \gre@trace@end% }% +% Same as the one before, but for soft flats. + +\def\GreFlatSoft#1#2#3#4#5{% + \gre@trace{GreFlatSoft{#1}{#2}{#3}{#4}{#5}}% + \gre@alteration{#1}{7}{#2}{#3}{#4}{#5}% + \relax% + \gre@trace@end% +}% + % Same as the one before, but for naturals. \def\GreNatural#1#2#3#4#5{% @@ -2825,6 +2840,15 @@ \gre@trace@end% }% +% Same as the one before, but for soft naturals. + +\def\GreNaturalSoft#1#2#3#4#5{% + \gre@trace{GreNaturalSoft{#1}{#2}{#3}{#4}{#5}}% + \gre@alteration{#1}{8}{#2}{#3}{#4}{#5}% + \relax% + \gre@trace@end% +}% + % Same as the one before, but for sharps. \def\GreSharp#1#2#3#4#5{% @@ -2834,7 +2858,7 @@ \gre@trace@end% }% -% Same as the one before, but for sharps. +% Same as the one before, but for parenthesized sharps. \def\GreSharpParen#1#2#3#4#5{% \gre@trace{GreSharpParen{#1}{#2}{#3}{#4}{#5}}% @@ -2843,6 +2867,15 @@ \gre@trace@end% }% +% Same as the one before, but for soft sharps. + +\def\GreSharpSoft#1#2#3#4#5{% + \gre@trace{GreSharpSoft{#1}{#2}{#3}{#4}{#5}}% + \gre@alteration{#1}{9}{#2}{#3}{#4}{#5}% + \relax% + \gre@trace@end% +}% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% macros for typesetting punctum cavum %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index cacbeaa9..8dc57b61 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -911,7 +911,7 @@ \def\gre@nextalignment{\gre@arg@oftwo@first#7}% \def\gre@nextalteration{\gre@arg@oftwo@second#7}% \ifnum\gre@nextalteration>0\relax - \gre@alteration@isvisible{1}% if the notes contain an alteration, the id was incremented, so this checks the alteration after the notes + \gre@alteration@isvisible{1}{\gre@nextalteration}% if the notes contain an alteration, the id was incremented, so this checks the alteration after the notes \ifgre@alteration@isvisible \else \def\gre@nextalteration{0}% From d28a7e654aca721fe159637cc64b8388aa334007 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Sat, 25 Jan 2025 22:31:29 -0500 Subject: [PATCH 10/19] a soft natural shouldn't be printed if it's the first on the line --- tex/gregoriotex-signs.tex | 17 +++++++++++++++-- tex/gregoriotex.lua | 20 +++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index 34b358e1..8475d46d 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -2729,10 +2729,23 @@ % Sets \ifgre@alteration@isvisibletrue or \ifgre@alteration@isvisiblefalse. \newif\ifgre@alteration@isvisible \def\gre@alteration@isvisible#1#2{% - \ifnum#2>6 % soft: depends on whether it's the first + \ifnum#2>6\relax % soft: depends on whether it's the first + \gre@debugmsg{alteration}{\directlua{gregoriotex.is_first_alteration(#1)}}% \ifcase\directlua{gregoriotex.is_first_alteration(#1)}\relax + % 0: don't know \global\gre@alteration@isvisibletrue - \else + \or + % 1: first in line + \ifnum#2=8\relax % natural: don't print + \global\gre@alteration@isvisiblefalse + \else + \global\gre@alteration@isvisibletrue + \fi + \or + % 2: different from previous + \global\gre@alteration@isvisibletrue + \or + % 3: not first \global\gre@alteration@isvisiblefalse \fi \else % hard: always visible diff --git a/tex/gregoriotex.lua b/tex/gregoriotex.lua index ce178e47..bcb1dc54 100644 --- a/tex/gregoriotex.lua +++ b/tex/gregoriotex.lua @@ -675,7 +675,13 @@ local function post_linebreak(h, groupcode, glyphes) if t ~= nil and t > 0 then local i = has_attribute(n, alteration_id_attr) local h = has_attribute(n, alteration_height_attr) - new_score_first_alterations[i] = seen[h] ~= t + if seen[h] == nil then + new_score_first_alterations[i] = 1 + elseif seen[h] ~= t then + new_score_first_alterations[i] = 2 + else + new_score_first_alterations[i] = 3 + end new_score_first_alterations['last'] = i debugmessage("alteration", "id=%s type=%s height=%s seen=%s first=%s", i, t, h, seen[t], new_score_first_alterations[i]) seen[h] = t @@ -1665,8 +1671,11 @@ local function hash_spaces(name, value) space_hash = md5.sumhexa(mash) end --- prints 0 for true and 1 for false local function is_first_alteration(next) +-- Arguments +-- next: 0 for current alteration, 1 for next alteration +-- Returns: +-- 0 = don't know, 1 = first in line, 2 = different from previous alteration, 3 = not first if score_first_alterations then local i = tex.getattribute(alteration_id_attr) if next == 1 then @@ -1676,10 +1685,11 @@ local function is_first_alteration(next) end end local v = score_first_alterations[i] - if v == true or v == nil then - tex.print(0) + if v ~= nil then + debugmessage("alteration", "%s", v) + tex.print(v) else - tex.print(1) + tex.print(0) end else tex.print(0) From 348de3cd5b89c8b098bf1c627e12f60223073ebd Mon Sep 17 00:00:00 2001 From: David Chiang Date: Mon, 27 Jan 2025 09:40:05 -0500 Subject: [PATCH 11/19] new cases needed for soft flats with ledger lines --- tex/gregoriotex-signs.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tex/gregoriotex-signs.lua b/tex/gregoriotex-signs.lua index 621a21eb..2ad5ef40 100644 --- a/tex/gregoriotex-signs.lua +++ b/tex/gregoriotex-signs.lua @@ -485,6 +485,24 @@ local offset_cases = { v = [[\gre@vepisemaorrareaux{0}{\GreCPNaturalParen}{1}{0}{#2}{#3}{#4}]], h = [[\gre@hepisorlineaux{\GreCPNaturalParen}{\gre@char@he@naturalparen{#4}}{2}{#3}]], }, + -- soft flat + { + case = 'FlatSoft', + v = [[\gre@vepisemaorrareaux{0}{\GreCPFlat}{1}{0}{#2}{#3}{#4}]], + h = [[\gre@hepisorlineaux{\GreCPFlat}{\gre@char@he@flat{#4}}{2}{#3}]], + }, + -- soft sharp + { + case = 'SharpSoft', + v = [[\gre@vepisemaorrareaux{0}{\GreCPSharp}{1}{0}{#2}{#3}{#4}]], + h = [[\gre@hepisorlineaux{\GreCPSharp}{\gre@char@he@sharp{#4}}{2}{#3}]], + }, + -- soft natural + { + case = 'NaturalSoft', + v = [[\gre@vepisemaorrareaux{0}{\GreCPNatural}{1}{0}{#2}{#3}{#4}]], + h = [[\gre@hepisorlineaux{\GreCPNatural}{\gre@char@he@natural{#4}}{2}{#3}]], + }, } local function emit_offset_macros() From 24b60df1c2ae8b0e590e7314b76cc3fd7fe5a30d Mon Sep 17 00:00:00 2001 From: David Chiang Date: Mon, 27 Jan 2025 16:17:06 -0500 Subject: [PATCH 12/19] Add \gresetalterationeffect option and some documentation --- doc/Command_Index_User.tex | 13 ++++++++ doc/Command_Index_gregorio.tex | 36 ++++++++++++++++++++ doc/Command_Index_internal.tex | 5 ++- doc/Gabc.tex | 21 +++++++++--- tex/gregoriotex-common.tex | 26 +++++++++++++++ tex/gregoriotex-signs.tex | 60 ++++++++++++++++++++++++++-------- 6 files changed, 141 insertions(+), 20 deletions(-) diff --git a/doc/Command_Index_User.tex b/doc/Command_Index_User.tex index 0581d157..680d1073 100644 --- a/doc/Command_Index_User.tex +++ b/doc/Command_Index_User.tex @@ -1408,6 +1408,19 @@ \subsubsection{Ancient Notation} \#2 & integer & point size at which the font should be loaded\\ \end{argtable} +\subsubsection{Alterations (Flats, Naturals, and Sharps)}\label{setalterationeffect} + +\macroname{\textbackslash gresetalterationeffect}{\{\#1\}}{gregoriotex-signs.tex} +Macro to set the effect of alterations (flats and sharps), for the purpose of deciding whether to print soft alterations (see \S\ref{softalterations}). +\begin{argtable} + \#1 & \texttt{note} (default) & effect ends immediately \\ + & \texttt{line} & effect ends at the end of the line \\ +\end{argtable} +Setting \verb|\gresetalterationeffect{note}| causes all soft sharps and flats, and no soft naturals, to be printed. +Setting \verb|\gresetalterationeffect{line}|, and making all alterations soft, gives the Dominican convention. + +(Argument \#1 is actually a comma-separated list of keywords, but currently, it must not be empty, and \texttt{note,line} has the same effect as \texttt{note}. In the future, other options may be added.) + \subsection{Counts}\label{counts} Each of the following counts controls some aspect of the configuration of the Gregorio\TeX\ score. They are changed using \verb=\grechangecount=, documented above. diff --git a/doc/Command_Index_gregorio.tex b/doc/Command_Index_gregorio.tex index 949c7264..4eaca552 100644 --- a/doc/Command_Index_gregorio.tex +++ b/doc/Command_Index_gregorio.tex @@ -530,6 +530,18 @@ \section{Gregorio Controls} \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} +\macroname{\textbackslash GreFlatSoft}{\#1\#2\#3\#4\#5}{gregoriotex-signs.tex} +Macro to typeset a soft flat. + +\begin{argtable} + \#1 & integer & Height number of the flat.\\ + \#2 & \texttt{0} & The flat is not part of the clef.\\ + & \texttt{1} & The flat is part of the clef.\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ + \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ +\end{argtable} + \macroname{\textbackslash GreForceHyphen}{}{gregoriotex-syllable.tex} Macro that indicates that a hyphen should be forced (if enabled) after the given syllable. @@ -810,6 +822,18 @@ \section{Gregorio Controls} \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} +\macroname{\textbackslash GreNaturalSoft}{\#1\#2\#3\#4\#5}{gregoriotex-signs.tex} +Macro to typeset a soft natural. + +\begin{argtable} + \#1 & integer & Height number of the natural.\\ + \#2 & \texttt{0} & The natural is not part of the clef.\\ + & \texttt{1} & The natural is part of the clef (doesn't happen).\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ + \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ +\end{argtable} + \macroname{\textbackslash GreNewLine}{}{gregoriotex-main.tex} Macro to call if you want to go to the next line. @@ -1080,6 +1104,18 @@ \section{Gregorio Controls} \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} +\macroname{\textbackslash GreSharpSoft}{\#1\#2\#3\#4\#5}{gregoriotex-signs.tex} +Macro to typeset a soft sharp. + +\begin{argtable} + \#1 & integer & Height number of the sharp.\\ + \#2 & \texttt{0} & The sharp is not part of the clef.\\ + & \texttt{1} & The sharp is part of the clef (doesn't happen).\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ + \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ +\end{argtable} + \macroname{\textbackslash GreSmallCaps}{\#1}{gregoriotex.sty and gregoriotex.tex} Makes argument small capitals. Accesses \LaTeX\ \verb=\textsc= or Plain \TeX\ \verb=\sc= as appropriate Corresponds to ``'' tags diff --git a/doc/Command_Index_internal.tex b/doc/Command_Index_internal.tex index b2d6ef07..cb1b4ca3 100644 --- a/doc/Command_Index_internal.tex +++ b/doc/Command_Index_internal.tex @@ -2386,7 +2386,10 @@ \subsection{Alteration Type}\label{alterationtype} \texttt{3} & sharp\\ \texttt{4} & parenthesized flat\\ \texttt{5} & parenthesized natural\\ - \texttt{6} & parenthesized sharp + \texttt{6} & parenthesized sharp \\ + \texttt{7} & soft flat\\ + \texttt{8} & soft natural\\ + \texttt{9} & soft sharp\\ \end{tabulary} \subsection{Note Offset Specifier}\label{NoteOffset} diff --git a/doc/Gabc.tex b/doc/Gabc.tex index e0af9601..bc41a901 100644 --- a/doc/Gabc.tex +++ b/doc/Gabc.tex @@ -452,10 +452,6 @@ \subsubsection{One-Note Neumes} to the pitch letter. These characters may be used together, and Gregorio\TeX{} will try to typeset them together. -Things like flats, sharps, and naturals, while not technically notes, are -treated as one-note neumes by Gregorio\TeX. Thus, they are also added by -appending characters to pitch letters. - \begin{tabularx}{\textwidth}{l|X} Gabc & Description \\ \hline @@ -480,6 +476,12 @@ \subsubsection{One-Note Neumes} \pitchchar\texttt{x} & flat \\ \pitchchar\texttt{\#} & sharp \\ \pitchchar\texttt{y} & natural \\ + \pitchchar\texttt{x?} & parenthesized flat \\ + \pitchchar\texttt{\#?} & parenthesized sharp \\ + \pitchchar\texttt{y?} & parenthesized natural \\ + \pitchchar\texttt{X} & soft flat \\ + \pitchchar\texttt{\#*} & soft sharp \\ + \pitchchar\texttt{Y} & soft natural \\ \end{tabularx} In the above table, \pitchchar{} represents a pitch character and @@ -490,17 +492,26 @@ \subsubsection{One-Note Neumes} { \gresetinitiallines{0}\gresetlyriccentering{firstletter}% \gresetclef{invisible}\gresetlastline{justified}\greseteolcustos{manual}% + \ttfamily \gabcsnippet{ ( ) g(g) g~~(g~) g<(g<) g>(g>) go(go) go~~(go~) gw(gw) gv(gv) gV(gV) gs(gs) gs<(gs<) g=(g=) ( ) (z) ( ) gr(gr) gR(gR) gr0(gr0) G(G) G0(G0) G1(G1) G~~(G~) G>(G>) Gr(Gr) gx(gx) - g#(g#) gy(gy) + g#(g#) gy(gy) gx?(gx?) g#?(g#?) gy?(gy?) ( ) } } +\subsubsection{Alterations (Flats, Naturals, and Sharps)} \label{softalterations} + +Things like flats, sharps, and naturals (called ``alterations''), while not technically notes, are +treated as one-note neumes by Gregorio\TeX. Thus, they are also added by +appending characters to pitch letters. + +Flats, sharps, and naturals each have a ``soft'' version (\verb|X|, \verb|#*|, and \verb|Y|, respectively), whose appearance is controlled by the \verb|\gresetalterationeffect| macro (see \S\ref{setalterationeffect}). For Dominican chant, use \verb|\gresetalterationeffect{line}| and make all alterations soft. + \subsubsection{Oriscus Orientation} Under the default rules for oriscus orientation, the direction of an oriscus diff --git a/tex/gregoriotex-common.tex b/tex/gregoriotex-common.tex index b7f89e24..cd5f1bc4 100644 --- a/tex/gregoriotex-common.tex +++ b/tex/gregoriotex-common.tex @@ -23,6 +23,32 @@ \gre@error{Error: this document must be compiled with LuaTeX (lualatex) 0.76 or later}% \fi% +% Run a command for each string in a comma-separated list of strings. +% #1: a comma-separated list of strings +% #2: a command +% Examples: +% \greparsecommas{}{\typeout} does nothing. +% \greparsecommas{foo}{\typeout} -> \typeout{foo} +% \greparsecommas{foo,bar}{\typeout} -> \typeout{foo}\typeout{bar} +% Note: Does not strip out any whitespace. +\newcount\gre@parsecommas@cur +\def\gre@parsecommas#1#2{% + % https://tex.stackexchange.com/a/510410 + \def\gre@options{,#1,}% + \gre@debugmsg{parsecommas}{\gre@options}% + \IfStrEq{\gre@options}{,,}{% + % do nothing + }{% + \StrCount{\gre@options}{,}[\gre@total]% number of items plus one + \gre@parsecommas@cur=1\relax + \loop\ifnum\gre@parsecommas@cur<\gre@total\relax + \StrBetween[\the\gre@parsecommas@cur,\the\numexpr\gre@parsecommas@cur+1]{\gre@options}{,}{,}[\gre@option]% + #2{\gre@option}% + \advance\gre@parsecommas@cur by 1\relax + \repeat + }% +} + %%%%%%%%% %% Debugging %%%%%%%%% diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index 8475d46d..b62a65a1 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -2723,30 +2723,62 @@ \fi } +% Sets the behavior of soft alterations, which are not printed if the +% same alteration (at the same pitch) is already in effect. A (hard or +% soft) alteration's effect is always cancelled by another alteration, +% as well as argument #1, whose default is "note": +% "note" = effect ends immediately (i.e., print all soft alterations) +% "line" = effect extends to the end of the line +% In the future, "word" and "bar" may also be allowed. +\newif\ifgre@alteration@effect@note\gre@alteration@effect@notefalse +\newif\ifgre@alteration@effect@line\gre@alteration@effect@linetrue +\def\gresetalterationeffect#1{% + \global\gre@alteration@effect@notefalse + \global\gre@alteration@effect@linefalse + \IfStrEq{#1}{}{\gre@error{Empty argument for \protect\gresetalterationeffect. Allowed arguments are: 'note', 'line'}}{% + \def\gre@alteration@effect@process##1{% + \IfStrEqCase{##1}{% + {note}{\global\gre@alteration@effect@notetrue}% + {line}{\global\gre@alteration@effect@linetrue}% + }[\gre@error{Unrecognized argument '##1' for \protect\gresetalterationeffect. Allowed arguments are: 'note', 'line'}]}% + \gre@parsecommas{#1}{\gre@alteration@effect@process}% + }% +} + % Test whether an alteration should be visible. % #1: 0 for current alteration, 1 for next alteration. % #2: alteration type % Sets \ifgre@alteration@isvisibletrue or \ifgre@alteration@isvisiblefalse. \newif\ifgre@alteration@isvisible \def\gre@alteration@isvisible#1#2{% - \ifnum#2>6\relax % soft: depends on whether it's the first - \gre@debugmsg{alteration}{\directlua{gregoriotex.is_first_alteration(#1)}}% - \ifcase\directlua{gregoriotex.is_first_alteration(#1)}\relax - % 0: don't know - \global\gre@alteration@isvisibletrue - \or - % 1: first in line + \global\gre@alteration@isvisiblefalse + \ifnum#2>6\relax % soft + % alterationeffect includes "line" + \ifgre@alteration@effect@line + \gre@debugmsg{alteration}{line}% + \ifcase\directlua{gregoriotex.is_first_alteration(#1)}\relax + % 0: don't know + \global\gre@alteration@isvisibletrue + \or + % 1: first in line + \ifnum#2=8\relax % natural: don't print + \else + \global\gre@alteration@isvisibletrue + \fi + \or + % 2: different from previous + \global\gre@alteration@isvisibletrue + \or + % 3: not first + \fi + \fi + % alterationeffect includes "note" + \ifgre@alteration@effect@note + \gre@debugmsg{alteration}{note}% \ifnum#2=8\relax % natural: don't print - \global\gre@alteration@isvisiblefalse \else \global\gre@alteration@isvisibletrue \fi - \or - % 2: different from previous - \global\gre@alteration@isvisibletrue - \or - % 3: not first - \global\gre@alteration@isvisiblefalse \fi \else % hard: always visible \global\gre@alteration@isvisibletrue From a35eb55d1bb99005409070f0ba21cd3ef172aa25 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Mon, 27 Jan 2025 19:19:00 -0500 Subject: [PATCH 13/19] fix spacing between bar and suppressed flat --- tex/gregoriotex-syllable.tex | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index 8dc57b61..ad22347f 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -1276,7 +1276,18 @@ \gre@dimen@begindifference=\dimexpr(\gre@dimen@notesaligncenter - \gre@dimen@textaligncenter)\relax% \gre@calculate@enddifference{\wd\gre@box@syllablenotes}{\wd\gre@box@syllabletext}{\gre@dimen@textaligncenter}{\gre@dimen@notesaligncenter}{1}% #5% - \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}#7% + % if the next glyph has an alteration, check if it is suppressed; + % if so, pretend there's no alteration + \def\gre@nextalignment{\gre@arg@oftwo@first#7}% + \def\gre@nextalteration{\gre@arg@oftwo@second#7}% + \ifnum\gre@nextalteration>0\relax + \gre@alteration@isvisible{1}{\gre@nextalteration}% + \ifgre@alteration@isvisible + \else + \def\gre@nextalteration{0}% + \fi + \fi + \gre@calculate@nextbegindifference{\gre@emit@endsyllablepartfornextsyllable}{\gre@evaluatenextsyllable{\gre@nextfirstsyllablepart}}{\gre@evaluatenextsyllable{\gre@nextmiddlesyllablepart}}{\gre@evaluatenextsyllable{\gre@nextendsyllablepart}}{\gre@nextalignment}{\gre@nextalteration}% \gre@unsetfixednexttextformat % \gre@debugmsg{barspacing}{previousenddifference: \the\gre@dimen@previousenddifference}% \gre@debugmsg{barspacing}{begindifference: \the\gre@dimen@begindifference}% @@ -1286,7 +1297,7 @@ % % New bar spacing algorithm % - \gre@calculate@barposition{#4}{\gre@arg@oftwo@second#7}% + \gre@calculate@barposition{#4}{\gre@nextalteration}% \ifgre@textcleared% \gre@clearsyllable{bar}% \fi% From fc38e7aa58ba1b8628bb1e9444f1ef5034bfdea0 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Tue, 28 Jan 2025 15:28:08 -0500 Subject: [PATCH 14/19] change soft sharp to ## --- doc/Gabc.tex | 2 +- src/gabc/gabc-notes-determination.l | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Gabc.tex b/doc/Gabc.tex index bc41a901..a7950991 100644 --- a/doc/Gabc.tex +++ b/doc/Gabc.tex @@ -480,7 +480,7 @@ \subsubsection{One-Note Neumes} \pitchchar\texttt{\#?} & parenthesized sharp \\ \pitchchar\texttt{y?} & parenthesized natural \\ \pitchchar\texttt{X} & soft flat \\ - \pitchchar\texttt{\#*} & soft sharp \\ + \pitchchar\texttt{\#\#} & soft sharp \\ \pitchchar\texttt{Y} & soft natural \\ \end{tabularx} diff --git a/src/gabc/gabc-notes-determination.l b/src/gabc/gabc-notes-determination.l index da16d227..784d84de 100644 --- a/src/gabc/gabc-notes-determination.l +++ b/src/gabc/gabc-notes-determination.l @@ -1314,7 +1314,7 @@ X { gregorio_change_shape(current_note, S_SHARP_PAREN, legacy_oriscus_orientation); } -#\* { +## { gregorio_change_shape(current_note, S_SHARP_SOFT, legacy_oriscus_orientation); } From 4005bb82299303ea99698b40d861843fcbf96b3f Mon Sep 17 00:00:00 2001 From: David Chiang Date: Tue, 28 Jan 2025 19:43:21 -0500 Subject: [PATCH 15/19] update docs for soft alterations --- doc/Command_Index_User.tex | 12 ++++++++---- doc/Gabc.tex | 27 ++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/doc/Command_Index_User.tex b/doc/Command_Index_User.tex index 680d1073..df03e426 100644 --- a/doc/Command_Index_User.tex +++ b/doc/Command_Index_User.tex @@ -1412,14 +1412,18 @@ \subsubsection{Alterations (Flats, Naturals, and Sharps)}\label{setalterationeff \macroname{\textbackslash gresetalterationeffect}{\{\#1\}}{gregoriotex-signs.tex} Macro to set the effect of alterations (flats and sharps), for the purpose of deciding whether to print soft alterations (see \S\ref{softalterations}). + \begin{argtable} \#1 & \texttt{note} (default) & effect ends immediately \\ - & \texttt{line} & effect ends at the end of the line \\ + & \texttt{line} & effect ends at the end of the line \\ \end{argtable} -Setting \verb|\gresetalterationeffect{note}| causes all soft sharps and flats, and no soft naturals, to be printed. -Setting \verb|\gresetalterationeffect{line}|, and making all alterations soft, gives the Dominican convention. -(Argument \#1 is actually a comma-separated list of keywords, but currently, it must not be empty, and \texttt{note,line} has the same effect as \texttt{note}. In the future, other options may be added.) +Soft flats are printed if no previous flat (on the same pitch) is in effect. Similarly for soft sharps. Soft naturals are printed if a previous flat or sharp (on the same pitch) is in effect. + +Thus, under \verb|\gresetalterationeffect{note}|, all sharps and flats lose their effect immediately, so all soft sharps and flats are printed, but no soft naturals are printed. +Under \verb|\gresetalterationeffect{line}|, all sharps and flats are in effect until the end of the line (unless cancelled by a natural), which is the convention used in Dominican chant scores. + +(Argument \#1 is actually a comma-separated list of keywords, but currently, it must not be empty, and \texttt{note,line} has the same effect as \texttt{note}. In the future, other options like \texttt{word} and \texttt{bar} may be added.) \subsection{Counts}\label{counts} diff --git a/doc/Gabc.tex b/doc/Gabc.tex index a7950991..69dcd56a 100644 --- a/doc/Gabc.tex +++ b/doc/Gabc.tex @@ -510,7 +510,32 @@ \subsubsection{Alterations (Flats, Naturals, and Sharps)} \label{softalterations treated as one-note neumes by Gregorio\TeX. Thus, they are also added by appending characters to pitch letters. -Flats, sharps, and naturals each have a ``soft'' version (\verb|X|, \verb|#*|, and \verb|Y|, respectively), whose appearance is controlled by the \verb|\gresetalterationeffect| macro (see \S\ref{setalterationeffect}). For Dominican chant, use \verb|\gresetalterationeffect{line}| and make all alterations soft. +Flats, sharps, and naturals each have a ``soft'' version (\verb|X|, \verb|##|, and \verb|Y|, respectively). Soft flats are printed if no previous flat (on the same pitch) is in effect. Similarly for soft sharps. Soft naturals are printed if a previous flat or sharp (on the same pitch) is in effect. +What ``in effect'' means is controlled by the \verb|\gresetalterationeffect| macro (see \S\ref{setalterationeffect}). Soft alterations currently have two use cases. + +For Dominican chant (in which flats take effect until the end of a line or until cancelled by a natural), use \verb|\gresetalterationeffect{line}|, and type a soft flat (\verb|X|) in front of \emph{every} note that is to be sung a half-step flat. Naturals should also be soft (\verb|Y|), but only naturals that cancel flats need to be typed. For example: + +\begin{center}\parbox{5in}{% + \gresetinitiallines{0}\gresetlyriccentering{firstletter}% + \grechangestyle{translation}{\ttfamily}% + \grechangedim{spacelinestext}{0.4cm}{scalable}% + \grechangedim{translationheight}{0.4cm}{scalable}% + \grechangedim{spaceabovelines}{0.5cm}{scalable}% + \gresetalterationeffect{line}% + \ttfamily + \gabcsnippet{(e) (e) (e) gX(gXge) (f)gX(gXghED) (eddc) (;) (efef//hhv) gX(gXfe//fgED//efDC//ef) (;) (hhvFEf)(fv_//hhf)gY(gYghghf) (::)} +}\end{center} + +Even under the convention that flats only take effect until the end of a word, if a long word has a flat that applies to two notes, one may want a flat to appear on the second note if a line break occurs between them. To do this, again use \verb|\gresetalterationeffect{line}| and type a soft flat (\verb|X|) before the second note. For example: +\begin{center}\parbox{4in}{% + \gresetinitiallines{0}\gresetlyriccentering{firstletter}% + \grechangestyle{translation}{\ttfamily}% + \grechangedim{spacelinestext}{0.4cm}{scalable}% + \grechangedim{translationheight}{0.4cm}{scalable}% + \grechangedim{spaceabovelines}{0.5cm}{scalable}% + \gresetalterationeffect{line}% + \gabcsnippet{(c3) (d)(fh) (fe/hh)(ih..) (,) (hij) (kvJIH'i)(h.) (,) (k)(ij)(k) (jvIH'i) (h.) (;) mi[gx](gxfghz)se[gX](gXhvGF)re(e[ll:1]d)re(ef) (d_[oh:h]e_[oh:h]d_[oh:h])(d.) (::)} +}\end{center} \subsubsection{Oriscus Orientation} From 88c89286f79c854fb2000751e293391dd04a34b8 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Tue, 28 Jan 2025 19:58:37 -0500 Subject: [PATCH 16/19] change many double quotes --- doc/Command_Index_gregorio.tex | 24 ++++++++++++------------ doc/Command_Index_internal.tex | 4 ++-- doc/Gabc.tex | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/doc/Command_Index_gregorio.tex b/doc/Command_Index_gregorio.tex index 4eaca552..f96974fb 100644 --- a/doc/Command_Index_gregorio.tex +++ b/doc/Command_Index_gregorio.tex @@ -513,7 +513,7 @@ \section{Gregorio Controls} \#1 & integer & Height number of the flat.\\ \#2 & \texttt{0} & The flat is not part of the clef.\\ & \texttt{1} & The flat is part of the clef.\\ - \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} @@ -525,7 +525,7 @@ \section{Gregorio Controls} \#1 & integer & Height number of the flat.\\ \#2 & \texttt{0} & The flat is not part of the clef.\\ & \texttt{1} & The flat is part of the clef.\\ - \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} @@ -537,7 +537,7 @@ \section{Gregorio Controls} \#1 & integer & Height number of the flat.\\ \#2 & \texttt{0} & The flat is not part of the clef.\\ & \texttt{1} & The flat is part of the clef.\\ - \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} @@ -573,7 +573,7 @@ \section{Gregorio Controls} & \texttt{7} & case of a stropha\\ & \texttt{8} & flexus with an ambitus of one\\ & \texttt{9} & flexus deminutus\\ - \#5 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#5 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#6 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#7 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled \end{argtable} @@ -621,7 +621,7 @@ \section{Gregorio Controls} & \texttt{r} & a small episema aligned right\\ \#6 & integer & Replacement for \#1 if a bridge causes a height substitution.\\ \#7 & \TeX\ code & code that sets heuristics\\ - \#8 & string & a positive or negative "nudge" (dimension) for the vertical position of the horizontal episema\\ + \#8 & string & a positive or negative ``nudge'' (dimension) for the vertical position of the horizontal episema\\ \#9 & \texttt{0} & for horizontal episema cases, use automatic positioning within the space\\ & \texttt{1} & for horizontal episema cases, position in the middle of the space\\ & \texttt{2} & for horizontal episema cases, position low within the space as if the episema is over the note\\ @@ -651,7 +651,7 @@ \section{Gregorio Controls} & \texttt{10} & Space between puncta inclinata (also debilis for now), larger ambitus (range=3rd).\\ & \texttt{11} & Space between puncta inclinata (also debilis for now), larger ambitus (range=4th or more).\\ \#4 & \TeX\ code & code that sets heuristics\\ - \#5 & string & a positive or negative "nudge" (dimension) for the vertical position of the horizontal episema\\ + \#5 & string & a positive or negative ``nudge'' (dimension) for the vertical position of the horizontal episema\\ \#6 & \texttt{0} & for horizontal episema cases, use automatic positioning within the space\\ & \texttt{1} & for horizontal episema cases, position in the middle of the space\\ & \texttt{2} & for horizontal episema cases, position low within the space as if the episema is over the note\\ @@ -805,7 +805,7 @@ \section{Gregorio Controls} \#1 & integer & Height number of the natural.\\ \#2 & \texttt{0} & The natural is not part of the clef.\\ & \texttt{1} & The natural is part of the clef (doesn't happen).\\ - \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} @@ -817,7 +817,7 @@ \section{Gregorio Controls} \#1 & integer & Height number of the natural.\\ \#2 & \texttt{0} & The natural is not part of the clef.\\ & \texttt{1} & The natural is part of the clef (doesn't happen).\\ - \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} @@ -829,7 +829,7 @@ \section{Gregorio Controls} \#1 & integer & Height number of the natural.\\ \#2 & \texttt{0} & The natural is not part of the clef.\\ & \texttt{1} & The natural is part of the clef (doesn't happen).\\ - \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} @@ -1087,7 +1087,7 @@ \section{Gregorio Controls} \#1 & integer & Height number of the sharp.\\ \#2 & \texttt{0} & The sharp is not part of the clef.\\ & \texttt{1} & The sharp is part of the clef (doesn't happen).\\ - \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} @@ -1099,7 +1099,7 @@ \section{Gregorio Controls} \#1 & integer & Height number of the sharp.\\ \#2 & \texttt{0} & The sharp is not part of the clef.\\ & \texttt{1} & The sharp is part of the clef (doesn't happen).\\ - \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} @@ -1111,7 +1111,7 @@ \section{Gregorio Controls} \#1 & integer & Height number of the sharp.\\ \#2 & \texttt{0} & The sharp is not part of the clef.\\ & \texttt{1} & The sharp is part of the clef (doesn't happen).\\ - \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#3 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#4 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#5 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} diff --git a/doc/Command_Index_internal.tex b/doc/Command_Index_internal.tex index cb1b4ca3..b4286001 100644 --- a/doc/Command_Index_internal.tex +++ b/doc/Command_Index_internal.tex @@ -510,7 +510,7 @@ \section{Gregorio\TeX{} Controls} \#3 & character alias & the hole of the alteration\\ \#4 & \texttt{1} & the alteration is part of the clef\\ & \texttt{0} & the alteration is not part of the clef\\ - \#5 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be "behind" the glyph)\\ + \#5 & \TeX\ code & signs to typeset before the glyph (typically additional bars, as they must be ``behind'' the glyph)\\ \#6 & \TeX\ code & signs to typeset after the glyph (almost all signs)\\ \#7 & string & the line, byte offset, and column address for textedit links when point-and-click is enabled\\ \end{argtable} @@ -685,7 +685,7 @@ \section{Gregorio\TeX{} Controls} & \texttt{l} & a small episema aligned left\\ & \texttt{c} & a small episema aligned center\\ & \texttt{r} & for a small episema aligned right\\ - \#6 & string & a positive or negative "nudge" (dimension) for the vertical position of the horizontal episema\\ + \#6 & string & a positive or negative ``nudge'' (dimension) for the vertical position of the horizontal episema\\ \#7 & \texttt{0} & for horizontal episema cases, use automatic positioning within the space\\ & \texttt{1} & for horizontal episema cases, position in the middle of the space\\ & \texttt{2} & for horizontal episema cases, position low within the space as if the episema is over the note\\ diff --git a/doc/Gabc.tex b/doc/Gabc.tex index 69dcd56a..206eb3d5 100644 --- a/doc/Gabc.tex +++ b/doc/Gabc.tex @@ -563,9 +563,9 @@ \subsubsection{Complex Neumes} \texttt{-}\pitchchar & (prior to the pitch it modifies) initio debilis \\ \pitchchar\texttt{O} & oriscus scapus (an oriscus with stems that connect to the note prior to it) \\ - \pitchchar\texttt{q} & quadratum (for making a "square" pes shape; see + \pitchchar\texttt{q} & quadratum (for making a ``square'' pes shape; see example below) \\ - \pitchchar\texttt{W} & quilisma quadratum (similarly, for making a "square" + \pitchchar\texttt{W} & quilisma quadratum (similarly, for making a ``square'' quilisma shape) \\ \pitchchar\texttt{ss} & distropha \\ \pitchchar\texttt{sss} & tristropha \\ @@ -1184,7 +1184,7 @@ \subsection{Vowel file}\label{customvowels} \item[secondary] -The "secondary" keyword lists strings of characters which do not contain +The \texttt{secondary} keyword lists strings of characters which do not contain vowels, but for which, when there are no vowels present in a syllable, define the center of the syllable. These strings follow the keyword and must be separated by space and end with a semicolon. Examples of From 48dce0b9b7bb3f7ab35efe952a6722cebe8117d4 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Thu, 30 Jan 2025 10:37:08 -0500 Subject: [PATCH 17/19] improve "rerun to fix" warning and some comments --- tex/gregoriotex-main.tex | 15 ++++++++++++--- tex/gregoriotex-signs.tex | 13 +++++++++---- tex/gregoriotex.lua | 33 +++++++++++++++++++++------------ 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/tex/gregoriotex-main.tex b/tex/gregoriotex-main.tex index 57b9031e..f5dc0fa2 100644 --- a/tex/gregoriotex-main.tex +++ b/tex/gregoriotex-main.tex @@ -103,11 +103,20 @@ \newluatexattribute\gre@attr@syllable@id % % attributes for soft alterations -\newluatexattribute\gre@attr@alteration@height % - \edef\gre@attrid@alteration@height{\the\allocationnumber}% + +% Alterations are numbered consecutively starting from 1. If an +% alteration is set twice, once for measurement and once for printing, +% they have the same id (unlike glyph ids). +\newluatexattribute\gre@attr@alteration@id % + +% The pitch and type of an alteration. If an alteration has a glyph +% id, then \gre@attr@alteration@pitch = \gre@attr@glyph@top +% = \gre@attr@glyph@bottom, but we can't use the latter because we +% also keep track of custos alterations, which don't have glyph ids. +\newluatexattribute\gre@attr@alteration@pitch + \edef\gre@attrid@alteration@pitch{\the\allocationnumber}% \newluatexattribute\gre@attr@alteration@type % see \gre@alteration for codes \edef\gre@attrid@alteration@type{\the\allocationnumber}% -\newluatexattribute\gre@attr@alteration@id % \newluatexcatcodetable\gre@atletter % \setluatexcatcodetable\gre@atletter{% diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index b62a65a1..728367b5 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -537,6 +537,8 @@ \gre@debugmsg{custos}{not blocked}% \gre@calculate@glyphraisevalue{#1}{0}{}% %here we need some tricks to draw the line before the custos (for the color) + % We want both the measured and real alteration to have the same id, + % so save the id to restore it later. \edef\gre@saved@attr@alteration@id{\number\gre@attr@alteration@id\relax}% \setbox\gre@box@temp@width=\hbox{% % we type a hskip and the we type the custos @@ -2708,16 +2710,19 @@ \gre@trace{gre@alteration{#1}{#2}{#3}{#4}{#5}{#6}}% \global\advance\gre@attr@alteration@id by 1\relax \def\gre@alteration@type{#2}% + % Check if the alteration should be visible or not \gre@alteration@isvisible{0}{\gre@alteration@type}% - \ifnum\gre@alteration@type>6\relax % treat soft alterations like hard + % After the above check, we treat soft alterations like hard alterations + \ifnum\gre@alteration@type>6\relax \edef\gre@alteration@type{\numexpr\gre@alteration@type-6\relax}% \fi \ifgre@alteration@isvisible \gre@alteration@visible{#1}{\gre@alteration@type}{#3}{#4}{#5}{#6}% \else - % ignore #4 (ledger line) and #5 (not used anyway?) + % Print an empty \hbox because it still needs to be counted + % Don't print #4 (ledger line) and #5 (not used anyway?) \hbox - attr \gre@attrid@alteration@height=#1\relax + attr \gre@attrid@alteration@pitch=#1\relax attr \gre@attrid@alteration@type=\gre@alteration@type\relax {}% \fi @@ -2797,7 +2802,7 @@ \else\gre@error{Invalid alteration type}% soft alterations should have been changed to hard \fi \setbox\gre@box@temp@width=\hbox - attr \gre@attrid@alteration@height=#1\relax + attr \gre@attrid@alteration@pitch=#1\relax attr \gre@attrid@alteration@type=#2\relax {\gre@pointandclick{\gre@alteration@char}{#6}}% \ifnum#3=0\relax % diff --git a/tex/gregoriotex.lua b/tex/gregoriotex.lua index bcb1dc54..2724346b 100644 --- a/tex/gregoriotex.lua +++ b/tex/gregoriotex.lua @@ -65,7 +65,7 @@ local glyph_bottom_attr = luatexbase.attributes['gre@attr@glyph@bottom'] local prev_line_id = nil local alteration_type_attr = luatexbase.attributes['gre@attr@alteration@type'] -local alteration_height_attr = luatexbase.attributes['gre@attr@alteration@height'] +local alteration_pitch_attr = luatexbase.attributes['gre@attr@alteration@pitch'] local alteration_id_attr = luatexbase.attributes['gre@attr@alteration@id'] local syllable_id_attr = luatexbase.attributes['gre@attr@syllable@id'] @@ -279,6 +279,7 @@ local function is_greaux_write_needed() if saved_computations_changed(saved_newline_before_euouae, new_saved_newline_before_euouae) then return true end + -- For alterations, check if either the keys or values changed. for id, tab in pairs(new_first_alterations) do if keys_changed(tab, first_alterations[id]) or entries_changed(tab, first_alterations[id]) then return true end end @@ -349,15 +350,17 @@ local function write_greaux() for id, value in pairs(new_state_hashes) do aux:write(string.format(' ["%s"]="%s",\n', id, value)) end - aux:write(' },\n ["first_alterations"]={\n') + aux:write(' },\n') + + -- Write information about alterations and line breaks. This + -- needs to go into the .gaux file because it affects whether + -- alterations are printed, which in turn affects which lines + -- alterations fall on. + aux:write(' ["first_alterations"]={\n') for id, tab in pairs(new_first_alterations) do - aux:write(string.format(' ["%s"]={\n ', id)) + aux:write(string.format(' ["%s"]={', id)) for i, value in pairs(tab) do - if i == 'last' then - aux:write(string.format('["%s"]=%s,', i, value)) - else - aux:write(string.format('[%s]=%s,', i, value)) - end + aux:write(string.format('[%q]=%s,', i, value)) end aux:write(string.format('},\n')) end @@ -367,7 +370,7 @@ local function write_greaux() err("\n Unable to open %s", auxname) end - warn("Line heights or variable brace lengths may have changed. Rerun to fix.") + warn("Line heights, variable brace lengths, or soft flats/sharps may have changed. Rerun to fix.") end end @@ -666,15 +669,20 @@ local function post_linebreak(h, groupcode, glyphes) currentshift=0 end end - -- For each alteration, record true if it is the first on the line or it is different than the previous alteration; record false otherwise + + -- Collect information about each alteration (flat, sharp, or natural): + -- 1 if it is the first alteration on the line (on the same pitch) + -- 2 if it has a different type from the previous alteration on the line (on the same pitch) + -- 3 otherwise. for line in traverse_id(hlist, h) do local seen = {} for n in traverse_id(hlist, line.head) do - -- This skips custos alterations because they're one level deeper. As a result, they are always printed. + -- This skips custos alterations because they're one level + -- deeper. As a result, they are always printed. local t = has_attribute(n, alteration_type_attr) if t ~= nil and t > 0 then local i = has_attribute(n, alteration_id_attr) - local h = has_attribute(n, alteration_height_attr) + local h = has_attribute(n, alteration_pitch_attr) if seen[h] == nil then new_score_first_alterations[i] = 1 elseif seen[h] ~= t then @@ -688,6 +696,7 @@ local function post_linebreak(h, groupcode, glyphes) end end end + --dump_nodes(h) -- due to special cases, we don't return h here (see comments in bug #20974) return true From 08328a8dbf5a877f81e6b4a47e36ff0bec02b6c6 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Mon, 3 Feb 2025 20:28:29 -0500 Subject: [PATCH 18/19] CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e6e5b2b..18f26b9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ As of v3.0.0 this project adheres to [Semantic Versioning](http://semver.org/). - Added a configurable setting `\gresetunisonbreakbehavior` to control automatic line breaks between unison notes above a syllable. Defaults to `breakable` for backwards compatibility, but may be set to `unbreakable` if that behavior is desired. See [#1504](https://github.com/gregorio-project/gregorio/issues/1504). - Added the ability to fuse upwards to a virga. See [#1558](https://github.com/gregorio-project/gregorio/issues/1558) - Added the ability to use the "stroke" form of a clivis instead of the default two-notes form by specifying `[shape:stroke]` after the clivis to change. See [#1558](https://github.com/gregorio-project/gregorio/issues/1558) +- Added new alterations, soft flat (X), soft natural (Y), and soft sharp (##), that only appear when necessary, as determined by a new option `\gresetalterationeffect`. These can be used for Dominican chant. See [#157](https://github.com/gregorio-project/gregorio/issues/157) and also [#1575](https://github.com/gregorio-project/gregorio/issues/1575). ## [6.0.0] - 2021-03-13 From bffbe36bab930d96b053743e4a0ecbf00b5cb418 Mon Sep 17 00:00:00 2001 From: David Chiang Date: Tue, 4 Feb 2025 19:35:50 -0500 Subject: [PATCH 19/19] improve documentation of soft alterations and document that \gresetalterationeffect{line} is the default --- CHANGELOG.md | 2 +- UPGRADE.md | 4 ++++ doc/Command_Index_User.tex | 11 ++++++----- doc/Gabc.tex | 6 ++---- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18f26b9a..8f4d54cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ As of v3.0.0 this project adheres to [Semantic Versioning](http://semver.org/). - Added a configurable setting `\gresetunisonbreakbehavior` to control automatic line breaks between unison notes above a syllable. Defaults to `breakable` for backwards compatibility, but may be set to `unbreakable` if that behavior is desired. See [#1504](https://github.com/gregorio-project/gregorio/issues/1504). - Added the ability to fuse upwards to a virga. See [#1558](https://github.com/gregorio-project/gregorio/issues/1558) - Added the ability to use the "stroke" form of a clivis instead of the default two-notes form by specifying `[shape:stroke]` after the clivis to change. See [#1558](https://github.com/gregorio-project/gregorio/issues/1558) -- Added new alterations, soft flat (X), soft natural (Y), and soft sharp (##), that only appear when necessary, as determined by a new option `\gresetalterationeffect`. These can be used for Dominican chant. See [#157](https://github.com/gregorio-project/gregorio/issues/157) and also [#1575](https://github.com/gregorio-project/gregorio/issues/1575). +- Added new alterations: soft flat (X) and sharp (##), which appear when there is no previous flat or sharp (respectively) in effect, and soft natural (Y), which appears when there is a previous flat or sharp in effect. A new option `\gresetalterationeffect` determines what the "effect" of an alteration is. It defaults to `line`, which is useful for Dominican chant. See [#157](https://github.com/gregorio-project/gregorio/issues/157) and also [#1575](https://github.com/gregorio-project/gregorio/issues/1575). ## [6.0.0] - 2021-03-13 diff --git a/UPGRADE.md b/UPGRADE.md index 00dbef43..d9541134 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -2,6 +2,10 @@ This file contains instructions to upgrade to a new release of Gregorio. These instructions are cumulative; meaning that you should apply the instructions from all versions between the one you are upgrading from and the current version. +## [Unreleased][develop] + +GABC now has some new alterations: soft flat (`X`) and sharp (`##`), which appear when there is no previous flat or sharp (respectively) in effect, and soft natural (`Y`), which appears when there is a previous flat or sharp in effect. A new option `\gresetalterationeffect` determines what the "effect" of an alteration is. It defaults to `line`, meaning that an alteration's effect extends to the end of the line. Thus, for Dominican chant, type a soft flat (`X`) in front of _every_ note that is to be sung a half-step flat; naturals should also be soft (`Y`), but only naturals that cancel flats need to be typed. + ## 6.0 ### Upright punctum inclinatum diff --git a/doc/Command_Index_User.tex b/doc/Command_Index_User.tex index df03e426..e949d0a8 100644 --- a/doc/Command_Index_User.tex +++ b/doc/Command_Index_User.tex @@ -1414,16 +1414,17 @@ \subsubsection{Alterations (Flats, Naturals, and Sharps)}\label{setalterationeff Macro to set the effect of alterations (flats and sharps), for the purpose of deciding whether to print soft alterations (see \S\ref{softalterations}). \begin{argtable} - \#1 & \texttt{note} (default) & effect ends immediately \\ - & \texttt{line} & effect ends at the end of the line \\ + \#1 & \texttt{line} (default) & effect ends at the end of the line \\ + & \texttt{note} & effect ends immediately \\ \end{argtable} Soft flats are printed if no previous flat (on the same pitch) is in effect. Similarly for soft sharps. Soft naturals are printed if a previous flat or sharp (on the same pitch) is in effect. -Thus, under \verb|\gresetalterationeffect{note}|, all sharps and flats lose their effect immediately, so all soft sharps and flats are printed, but no soft naturals are printed. -Under \verb|\gresetalterationeffect{line}|, all sharps and flats are in effect until the end of the line (unless cancelled by a natural), which is the convention used in Dominican chant scores. +Thus, under \verb|\gresetalterationeffect{line}|, all sharps and flats are in effect until the end of the line (unless cancelled by a natural), which is the convention used in Dominican chant scores. For the currently envisioned uses of soft alterations, this is the right setting. -(Argument \#1 is actually a comma-separated list of keywords, but currently, it must not be empty, and \texttt{note,line} has the same effect as \texttt{note}. In the future, other options like \texttt{word} and \texttt{bar} may be added.) +Under \verb|\gresetalterationeffect{note}|, all sharps and flats lose their effect immediately, so all soft flats and sharps are printed (but no soft naturals are printed). + +(Argument \#1 is actually a comma-separated list of options. If multiple options are given, then an alteration's effect ends as soon as \emph{any} of the options says it should end. However, currently, the list must not be empty, and \texttt{note,line} has the same effect as \texttt{note}, because ``immediately'' always occurs before the end of the line. In the future, other options like \texttt{word} and \texttt{bar} may be added; \texttt{word,bar} would then be the convention used in most Gregorian chant scores.) \subsection{Counts}\label{counts} diff --git a/doc/Gabc.tex b/doc/Gabc.tex index 206eb3d5..54c38fec 100644 --- a/doc/Gabc.tex +++ b/doc/Gabc.tex @@ -513,20 +513,18 @@ \subsubsection{Alterations (Flats, Naturals, and Sharps)} \label{softalterations Flats, sharps, and naturals each have a ``soft'' version (\verb|X|, \verb|##|, and \verb|Y|, respectively). Soft flats are printed if no previous flat (on the same pitch) is in effect. Similarly for soft sharps. Soft naturals are printed if a previous flat or sharp (on the same pitch) is in effect. What ``in effect'' means is controlled by the \verb|\gresetalterationeffect| macro (see \S\ref{setalterationeffect}). Soft alterations currently have two use cases. -For Dominican chant (in which flats take effect until the end of a line or until cancelled by a natural), use \verb|\gresetalterationeffect{line}|, and type a soft flat (\verb|X|) in front of \emph{every} note that is to be sung a half-step flat. Naturals should also be soft (\verb|Y|), but only naturals that cancel flats need to be typed. For example: +For Dominican chant (in which flats take effect until the end of a line or until cancelled by a natural), use \verb|\gresetalterationeffect{line}| (which is the default), and type a soft flat (\verb|X|) in front of \emph{every} note that is to be sung a half-step flat. Naturals should also be soft (\verb|Y|), but only naturals that cancel flats need to be typed. For example: \begin{center}\parbox{5in}{% \gresetinitiallines{0}\gresetlyriccentering{firstletter}% - \grechangestyle{translation}{\ttfamily}% \grechangedim{spacelinestext}{0.4cm}{scalable}% - \grechangedim{translationheight}{0.4cm}{scalable}% \grechangedim{spaceabovelines}{0.5cm}{scalable}% \gresetalterationeffect{line}% \ttfamily \gabcsnippet{(e) (e) (e) gX(gXge) (f)gX(gXghED) (eddc) (;) (efef//hhv) gX(gXfe//fgED//efDC//ef) (;) (hhvFEf)(fv_//hhf)gY(gYghghf) (::)} }\end{center} -Even under the convention that flats only take effect until the end of a word, if a long word has a flat that applies to two notes, one may want a flat to appear on the second note if a line break occurs between them. To do this, again use \verb|\gresetalterationeffect{line}| and type a soft flat (\verb|X|) before the second note. For example: +Even under the convention that flats only take effect until the end of a word, if a long word has a flat that applies to two notes, one may want a flat to appear on the second note if a line break occurs between them. To do this, again use \verb|\gresetalterationeffect{line}| (the default) and type a soft flat (\verb|X|) before the second note. For example: \begin{center}\parbox{4in}{% \gresetinitiallines{0}\gresetlyriccentering{firstletter}% \grechangestyle{translation}{\ttfamily}%