Skip to content

Commit

Permalink
Implemented control over automatic linebreaks between unison notes.
Browse files Browse the repository at this point in the history
  • Loading branch information
henryso committed May 24, 2021
1 parent 94d99b5 commit ddc6164
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,4 @@ ctan
*.pyg
.agignore
*.orig
compile_commands.json
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ As of v3.0.0 this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased][develop]

- 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).

## [Unreleased][CTAN]

Expand Down
13 changes: 13 additions & 0 deletions doc/Command_Index_User.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,19 @@ \subsubsection{End of Line Behavior}
lines. Defaults to \getgrecount{unbreakablefinalnotes}.\\
\end{argtable}

\macroname{\textbackslash gresetunisonbreakbehavior}{\{\#1\}}{gregoriotex-main.tex}
Macro to determine whether an automatic linebreak may occur between unison notes
over a syllable. This behavior governs how the system works when no explicit
space is put between the notes. In other words, any explicit space between the
notes take precedence over this setting.

\begin{argtable}
\#1 & \texttt{breakable} & Allow automatic linebreaks between unison notes
(default)\\
& \texttt{unbreakable} & Disallow automatic linebreaks between unison
notes\\
\end{argtable}


\subsubsection{Bar spacing}

Expand Down
4 changes: 3 additions & 1 deletion doc/Command_Index_gregorio.tex
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ \section{Gregorio Controls}
& \texttt{4} & Ad-hoc space.\\
\#2 & \texttt{0} & Space is breakable.\\
& \texttt{1} & Space is unbreakable.\\
& \texttt{2} & Space is breakable according to the \verb=\setunisonbreakbehavior= setting.\\
\#3 & integer & The number of notes in the syllable prior to this macro.\\
\end{argtable}

Expand Down Expand Up @@ -444,11 +445,12 @@ \section{Gregorio Controls}
& \texttt{20} & Space between a punctum inclinatum and a ``no-bar'' glyph two pitches above. \\
& \texttt{21} & Space between a punctum inclinatum and a ``no-bar'' glyph three or four pitches above \\
& \texttt{22} & Half-space. \\
& \texttt{23} & Space between unison puncta inclinata. \\
\end{argtable}

\macroname{\textbackslash GreFinalCustos}{\#1\#2}{gregoriotex-signs.tex}
Typesets a custos after the final bar in a score.

um
\begin{argtable}
\#1 & integer & Height number of custos.\\
\#2 & \texttt{Flat} & The custos should have a flat.\\
Expand Down
4 changes: 4 additions & 0 deletions doc/Command_Index_internal.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1961,6 +1961,10 @@ \subsection{Flags}
\macroname{\textbackslash ifgre@unbreakableendofelement}{}{gregoriotex-main.tex}
Boolean used by \verb=\GreEndOfElement= to store whether the line may be broken at that point.
\macroname{\textbackslash gre@unbreakableendofelement@unison}{}{gregoriotex-main.tex}
Alias that sets \verb=\ifgre@unbreakableendofelement= according to the
\verb=\setunisonbreakbehavior= preference.
\macroname{\textbackslash gre@count@syllablenotes}{}{gregoriotex-syllable.tex}
Count containing the number of notes in the syllable.
Expand Down
80 changes: 71 additions & 9 deletions src/gregoriotex/gregoriotex-write.c
Original file line number Diff line number Diff line change
Expand Up @@ -3847,6 +3847,75 @@ static bool is_before_linebreak(const gregorio_syllable *syllable,
return false;
}

static void write_default_end_of_element(FILE *f,
const gregorio_element *const element,
const unsigned int note_unit_count) {
const gregorio_element *next_element;
const gregorio_glyph *last_glyph;
const gregorio_note *last_note, *next_note;
signed char last_pitch = NO_PITCH;
int break_flag = 0;

/* This is only used in write_syllable, so element is assumed to be:
* 1. not NULL
* 2. of type GRE_ELEMENT
*/
if (element->next) {
next_element = element->next;
if (next_element->type == GRE_ALT) {
next_element = next_element->next;
}
if (next_element && next_element->type == GRE_ELEMENT) {
for (last_glyph = element->u.first_glyph; last_glyph->next;
last_glyph = last_glyph->next) {
/* iterate to find the last glyph */
}
if (last_glyph->type == GRE_GLYPH) {
last_note = gregorio_glyph_last_note(last_glyph);
assert(last_note != NULL);
if (last_note->type == GRE_NOTE)
switch(last_note->u.note.shape) {
case S_FLAT:
case S_FLAT_PAREN:
case S_SHARP:
case S_SHARP_PAREN:
case S_NATURAL:
case S_NATURAL_PAREN:
break;
default:
last_pitch = last_note->u.note.pitch;
break;
}
}
if (last_pitch != NO_PITCH && next_element->u.first_glyph
&& next_element->u.first_glyph->type == GRE_GLYPH) {
next_note = next_element->u.first_glyph->u.notes.first_note;
if (next_note->type == GRE_NOTE) {
switch(next_note->u.note.shape) {
case S_FLAT:
case S_FLAT_PAREN:
case S_SHARP:
case S_SHARP_PAREN:
case S_NATURAL:
case S_NATURAL_PAREN:
break;
default:
if (next_note->u.note.pitch != NO_PITCH &&
next_note->u.note.pitch - last_pitch == 0) {
/* at a unison */
break_flag = 2;
}
break;
}
}
}

fprintf(f, "\\GreEndOfElement{0}{%d}{%u}%%\n", break_flag,
note_unit_count);
}
}
}

/*
* Arguments are relatively obvious. The most obscure is certainly first_of_disc
* which is 0 all the time, except in the case of a "clef change syllable". In
Expand Down Expand Up @@ -4204,19 +4273,12 @@ static void write_syllable(FILE *f, gregorio_syllable *syllable,
break;

default:
/* here current_element->type is GRE_ELEMENT */
/* here element->type is GRE_ELEMENT */
assert(element->type == GRE_ELEMENT);
handle_last_of_voice(f, syllable, element, *last_of_voice);
note_unit_count += write_element(f, syllable, element, status,
score);
if (element->next && (element->next->type == GRE_ELEMENT
|| (element->next->next
&& element->next->type == GRE_ALT
&& element->next->next->type ==
GRE_ELEMENT))) {
fprintf(f, "\\GreEndOfElement{0}{0}{%u}%%\n",
note_unit_count);
}
write_default_end_of_element(f, element, note_unit_count);
break;
}
}
Expand Down
29 changes: 25 additions & 4 deletions tex/gregoriotex-main.tex
Original file line number Diff line number Diff line change
Expand Up @@ -1506,13 +1506,28 @@
}%

\newif\ifgre@unbreakableendofelement %
\def\gresetunisonbreakbehavior#1{%
\IfStrEqCase{#1}{%
{breakable}%
{\global\let\gre@unbreakableendofelement@unison\gre@unbreakableendofelementfalse\relax}%
{unbreakable}%
{\global\let\gre@unbreakableendofelement@unison\gre@unbreakableendofelementtrue\relax}%
}[% all other cases
\gre@error{Unrecognized option "#1" for \protect\gresetunisonbreakbehavior\MessageBreak Possible options are: 'breakable' and 'unbreakable'}%
]%
}%
\gresetunisonbreakbehavior{breakable}

% macro to end elements, #1 is the type of space, it can be :
%% 0: default space
%% 1: larger space
%% 2: glyph space
%% 3: zero-width space
%% 4: custom space
% #2 is if the space is unbreakable (1) or not (0)
% #2 is whether the space is breakable :
%% 0: breakable
%% 1: unbreakable
%% 2: unison (breakable according to the unisonbreakbehavior setting)
% #3 is the number of notes emitted in this syllable before this macro
\def\GreEndOfElement#1#2#3{%
\ifnum\gre@count@syllablenotes<\gre@count@unbreakabletotalnotes\relax %
Expand All @@ -1525,10 +1540,14 @@
\gre@count@unbreakablefinalnotes\relax %
\gre@unbreakableendofelementtrue %
\else %
\ifnum#2=1\relax %
\ifcase#2\relax %
\gre@unbreakableendofelementfalse %
\or% case 1
\gre@unbreakableendofelementtrue %
\or% case 2
\gre@unbreakableendofelement@unison %
\else %
\gre@unbreakableendofelementfalse %
\gre@error{Unrecognized breakable argument #2}%
\fi %
\fi %
\fi %
Expand All @@ -1538,7 +1557,7 @@
\else %
\gre@penalty{\the\gre@space@count@endofelementpenalty}%
\fi %
\ifcase#1%
\ifcase#1\relax%
\gre@skip@temp@four = \gre@space@skip@interelementspace\relax%
\gre@hskip\gre@skip@temp@four %
\or% case 1
Expand All @@ -1552,6 +1571,8 @@
\gre@hskip\gre@skip@temp@four %
\or% case 4
\gre@hskip\gre@skip@temp@four %
\else%
\gre@error{Unrecognized space type #1}%
\fi%
\ifgre@unbreakableendofelement %
\GreNoBreak %
Expand Down

0 comments on commit ddc6164

Please sign in to comment.