diff --git a/CHANGELOG.md b/CHANGELOG.md index f005d1df6..fcc1572e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ As of v3.0.0 this project adheres to [Semantic Versioning](http://semver.org/). - More control over the placement of the commentary. You can now set the amount of space between the lines of a multi-line commentary with `commentaryseparation` and the distance from the top line of the staff to the baseline of the bottom line of the commentary with `commentaryraise`. See [#662](https://github.com/gregorio-project/gregorio/issues/662) for original request. - Styles for the annotation and the commentary. `annotation` has no default styling. `commentary` defaults to footnote sized italics. - `\grecommentary` now takes an optional argument which will add extra space between the commentary and the score for just the next score. +- The custos can now be selectively enabled/disabled at forced line breaks by appending `+` (to enable) or `-` (to disable) after the `z` or `Z` (see [#800](https://github.com/gregorio-project/gregorio/issues/800)). ### Deprecated diff --git a/doc/Command_Index_gregorio.tex b/doc/Command_Index_gregorio.tex index cf44f6950..06aa5b792 100644 --- a/doc/Command_Index_gregorio.tex +++ b/doc/Command_Index_gregorio.tex @@ -961,6 +961,14 @@ \section{Gregorio Controls} \#1 & string & Text to typeset without any extra styling.\\ \end{argtable} +\macroname{\textbackslash GreUpcomingNewLineForcesCustos}{\#1}{gregoriotex-syllable.tex} +Indicates that the new line in the next syllable forces a custos. + +\begin{argtable} + \#1 & \texttt{0} & The custos is forced off.\\ + & \texttt{1} & The custos is forced on.\\ +\end{argtable} + \macroname{\textbackslash GreVarBraceLength}{\#1}{gregoriotex-signs.tex} Returns the computed length of the given brace or ledger line. diff --git a/doc/Command_Index_internal.tex b/doc/Command_Index_internal.tex index 1064e6651..cb0ce5e4e 100644 --- a/doc/Command_Index_internal.tex +++ b/doc/Command_Index_internal.tex @@ -372,6 +372,9 @@ \section{Gregorio\TeX{} Controls} \#1 & integer & height of the custos character to be placed\\ \end{argtable} +\macroname{\textbackslash gre@nextcustos}{}{gregoriotex-signs.tex} +Macro that saves the next custos height. + \macroname{\textbackslash gre@beginnotes}{}{gregoriotex-main.tex} Macro to draw the staff lines. Comes after the initial but before the clef. diff --git a/src/dump/dump.c b/src/dump/dump.c index cb2829f53..de287ee21 100644 --- a/src/dump/dump.c +++ b/src/dump/dump.c @@ -298,11 +298,13 @@ void dump_write_score(FILE *f, gregorio_score *score) } break; case GRE_END_OF_LINE: - if (element->u.misc.unpitched.info.sub_type) { - fprintf(f, " sub_type %d (%s)\n", - element->u.misc.unpitched.info.sub_type, - gregorio_type_to_string(element->u.misc.unpitched. - info.sub_type)); + if (element->u.misc.unpitched.info.eol_ragged) { + fprintf(f, " ragged true\n"); + } + if (element->u.misc.unpitched.info.eol_forces_custos) { + fprintf(f, " forces custos %s\n", + dump_bool(element + ->u.misc.unpitched.info.eol_forces_custos_on)); } break; case GRE_ELEMENT: diff --git a/src/gabc/gabc-notes-determination.l b/src/gabc/gabc-notes-determination.l index 9b5989636..5af32595a 100644 --- a/src/gabc/gabc-notes-determination.l +++ b/src/gabc/gabc-notes-determination.l @@ -819,15 +819,31 @@ static void end_var_slur(int direction, int index) ¬es_lloc); } [\t\r\n]+ /* ignore ends of line and tabs */; +z0 { + gregorio_add_custo_as_note(¤t_note, ¬es_lloc); + } z { - gregorio_add_end_of_line_as_note(¤t_note, GRE_END_OF_LINE, + gregorio_add_end_of_line_as_note(¤t_note, false, false, false, ¬es_lloc); } -z0 { - gregorio_add_custo_as_note(¤t_note, ¬es_lloc); +z\+ { + gregorio_add_end_of_line_as_note(¤t_note, false, true, true, + ¬es_lloc); + } +z- { + gregorio_add_end_of_line_as_note(¤t_note, false, true, false, + ¬es_lloc); } Z { - gregorio_add_end_of_line_as_note(¤t_note, GRE_END_OF_PAR, + gregorio_add_end_of_line_as_note(¤t_note, true, false, false, + ¬es_lloc); + } +Z\+ { + gregorio_add_end_of_line_as_note(¤t_note, true, true, true, + ¬es_lloc); + } +Z- { + gregorio_add_end_of_line_as_note(¤t_note, true, true, false, ¬es_lloc); } [cf][1-5] { diff --git a/src/gabc/gabc-write.c b/src/gabc/gabc-write.c index 5dd0384c6..9a42517b5 100644 --- a/src/gabc/gabc-write.c +++ b/src/gabc/gabc-write.c @@ -745,7 +745,15 @@ static void gabc_write_gregorio_element(FILE *f, gregorio_element *element) gabc_write_clef(f, element->u.misc.clef); break; case GRE_END_OF_LINE: - fprintf(f, "z"); + if (element->u.misc.unpitched.info.eol_ragged) { + fprintf(f, "Z"); + } else { + fprintf(f, "z"); + } + if (element->u.misc.unpitched.info.eol_forces_custos) { + fprintf(f, element->u.misc.unpitched.info.eol_forces_custos_on? "+" + : "-"); + } break; case GRE_CUSTOS: if (element->u.misc.pitched.force_pitch) { diff --git a/src/gregoriotex/gregoriotex-write.c b/src/gregoriotex/gregoriotex-write.c index fb72d418d..613f66f69 100644 --- a/src/gregoriotex/gregoriotex-write.c +++ b/src/gregoriotex/gregoriotex-write.c @@ -3181,19 +3181,47 @@ static void write_first_syllable_text(FILE *f, const char *const syllable_type, } } -static __inline void anticipate_euouae(FILE *f, gregorio_syllable *syllable) { +static __inline void scan_syllable_for_eol( + const gregorio_syllable *const syllable, + bool *eol_forces_custos, bool *eol_forces_custos_on) { + const gregorio_element *element; + for (element = *(syllable->elements); element; element = element->next) { + if (element->type == GRE_END_OF_LINE) { + if (element->u.misc.unpitched.info.eol_forces_custos) { + *eol_forces_custos = true; + *eol_forces_custos_on = + element->u.misc.unpitched.info.eol_forces_custos_on; + } + } + } +} + +static __inline void anticipate_event(FILE *f, gregorio_syllable *syllable) { static unsigned short euouae_id = 0; + bool eol_forces_custos = false; + bool eol_forces_custos_on = false; if (syllable->next_syllable) { for (syllable = syllable->next_syllable; syllable && syllable->elements && *(syllable->elements) && (*(syllable->elements))->type == GRE_END_OF_LINE; syllable = syllable->next_syllable) { - /* just iterate to find the next "real" syllable */ + /* we are at an end-of-line, so check if custos is forced */ + scan_syllable_for_eol(syllable, &eol_forces_custos, + &eol_forces_custos_on); + } + if (syllable) { + scan_syllable_for_eol(syllable, &eol_forces_custos, + &eol_forces_custos_on); + + if (syllable->euouae == EUOUAE_BEGINNING) { + syllable->euouae_id = ++euouae_id; + fprintf(f, "%%\n\\GreNextSyllableBeginsEUOUAE{%hu}%%\n", euouae_id); + } } - if (syllable && syllable->euouae == EUOUAE_BEGINNING) { - syllable->euouae_id = ++euouae_id; - fprintf(f, "%%\n\\GreNextSyllableBeginsEUOUAE{%hu}%%\n", euouae_id); + if (eol_forces_custos) { + fprintf(f, "%%\n\\GreUpcomingNewLineForcesCustos{%c}%%\n", + eol_forces_custos_on? '1' : '0'); } } } @@ -3219,7 +3247,7 @@ static void write_syllable(FILE *f, gregorio_syllable *syllable, { gregorio_element *clef_change_element = NULL, *element; const char *syllable_type = NULL; - bool euouae_anticipated = false; + bool event_anticipated = false; if (!syllable) { write_this_syllable_text(f, NULL, NULL); return; @@ -3240,11 +3268,10 @@ static void write_syllable(FILE *f, gregorio_syllable *syllable, */ if (syllable->elements && *(syllable->elements)) { if ((syllable->elements)[0]->type == GRE_END_OF_LINE) { - if ((syllable->elements)[0]->u.misc.unpitched.info.sub_type != - GRE_END_OF_PAR) { - fprintf(f, "%%\n%%\n\\GreNewLine %%\n%%\n%%\n"); - } else { + if ((syllable->elements)[0]->u.misc.unpitched.info.eol_ragged) { fprintf(f, "%%\n%%\n\\GreNewParLine %%\n%%\n%%\n"); + } else { + fprintf(f, "%%\n%%\n\\GreNewLine %%\n%%\n%%\n"); } write_this_syllable_text(f, NULL, syllable->text); return; @@ -3305,8 +3332,7 @@ static void write_syllable(FILE *f, gregorio_syllable *syllable, if (syllable->position == WORD_END || syllable->position == WORD_ONE_SYLLABLE || !syllable->text || !syllable->next_syllable - || syllable->next_syllable->type == GRE_END_OF_LINE - || syllable->next_syllable->type == GRE_END_OF_PAR) { + || syllable->next_syllable->type == GRE_END_OF_LINE) { fprintf(f, "{1}"); } else { fprintf(f, "{0}"); @@ -3466,15 +3492,15 @@ static void write_syllable(FILE *f, gregorio_syllable *syllable, case GRE_END_OF_LINE: if (!element->next) { - anticipate_euouae(f, syllable); - euouae_anticipated = true; + anticipate_event(f, syllable); + event_anticipated = true; } /* here we suppose we don't have two linebreaks in the same * syllable */ - if (element->u.misc.unpitched.info.sub_type != GRE_END_OF_PAR) { - fprintf(f, "%%\n%%\n\\GreNewLine %%\n%%\n%%\n"); - } else { + if (element->u.misc.unpitched.info.eol_ragged) { fprintf(f, "%%\n%%\n\\GreNewParLine %%\n%%\n%%\n"); + } else { + fprintf(f, "%%\n%%\n\\GreNewLine %%\n%%\n%%\n"); } break; @@ -3492,8 +3518,8 @@ static void write_syllable(FILE *f, gregorio_syllable *syllable, break; } } - if (!euouae_anticipated) { - anticipate_euouae(f, syllable); + if (!event_anticipated) { + anticipate_event(f, syllable); } fprintf(f, "}%%\n"); if (syllable->position == WORD_END diff --git a/src/struct.c b/src/struct.c index dfec2fe78..c13b0c456 100644 --- a/src/struct.c +++ b/src/struct.c @@ -142,11 +142,14 @@ static void add_pitched_item_as_note(gregorio_note **current_note, } void gregorio_add_end_of_line_as_note(gregorio_note **current_note, - gregorio_type sub_type, const gregorio_scanner_location *const loc) + bool eol_ragged, bool eol_forces_custos, bool eol_forces_custos_on, + const gregorio_scanner_location *const loc) { gregorio_note *element = create_and_link_note(current_note, loc); element->type = GRE_END_OF_LINE; - element->u.other.sub_type = sub_type; + element->u.other.eol_ragged = eol_ragged; + element->u.other.eol_forces_custos = eol_forces_custos; + element->u.other.eol_forces_custos_on = eol_forces_custos_on; } void gregorio_add_custo_as_note(gregorio_note **current_note, diff --git a/src/struct.h b/src/struct.h index db751a17c..5bd132537 100644 --- a/src/struct.h +++ b/src/struct.h @@ -72,7 +72,6 @@ typedef struct gregorio_scanner_location { E(GRE_END_OF_LINE) \ E(GRE_SPACE) \ E(GRE_BAR) \ - E(GRE_END_OF_PAR) \ E(GRE_CUSTOS) \ E(GRE_MANUAL_CUSTOS) \ /* I don't really know how I could use the a TEXVERB_NOTE in gregoriotex, @@ -366,11 +365,12 @@ ENUM(gregorio_word_position, GREGORIO_WORD_POSITION); typedef struct gregorio_extra_info { char *ad_hoc_space_factor; - /* the sub-type of GRE_END_OF_LINE */ - ENUM_BITFIELD(gregorio_type) sub_type:8; - ENUM_BITFIELD(gregorio_bar) bar:8; - ENUM_BITFIELD(gregorio_space) space:8; - ENUM_BITFIELD(gregorio_nlba) nlba:8; + ENUM_BITFIELD(gregorio_bar) bar:4; + ENUM_BITFIELD(gregorio_space) space:4; + ENUM_BITFIELD(gregorio_nlba) nlba:2; + bool eol_ragged:1; + bool eol_forces_custos:1; + bool eol_forces_custos_on:1; } gregorio_extra_info; typedef struct gregorio_clef_info { @@ -809,7 +809,8 @@ void gregorio_add_unpitched_element_as_glyph(gregorio_glyph **current_glyph, gregorio_type type, gregorio_extra_info *info, gregorio_sign sign, char *texverb); void gregorio_add_end_of_line_as_note(gregorio_note **current_note, - gregorio_type sub_type, const gregorio_scanner_location *loc); + bool eol_ragged, bool eol_forces_custos, bool eol_forces_custos_on, + const gregorio_scanner_location *loc); void gregorio_add_custo_as_note(gregorio_note **current_note, const gregorio_scanner_location *loc); void gregorio_add_manual_custos_as_note(gregorio_note **current_note, diff --git a/tex/gregoriotex-main.tex b/tex/gregoriotex-main.tex index bf5727f96..67a8f6c08 100644 --- a/tex/gregoriotex-main.tex +++ b/tex/gregoriotex-main.tex @@ -262,6 +262,7 @@ \gre@penalty{-10001}% \fi % \gre@adjustlineifnecessary\relax % + \gre@reseteolcustos\relax % }% \def\gre@mark@translation{\directlua{gregoriotex.mark_translation()}}% diff --git a/tex/gregoriotex-signs.tex b/tex/gregoriotex-signs.tex index f5a4693bf..0f1ed7273 100644 --- a/tex/gregoriotex-signs.tex +++ b/tex/gregoriotex-signs.tex @@ -309,8 +309,10 @@ } % the argument is the height +\edef\gre@nextcustos{\gre@pitch@dummy}% \def\GreNextCustos#1{% \ifnum\gre@insidediscretionary=0\relax % + \edef\gre@nextcustos{#1}% \ifgre@blockeolcustos\else% \gre@calculate@glyphraisevalue{#1}{0}% %here we need some tricks to draw the line before the custos (for the color) diff --git a/tex/gregoriotex-syllable.tex b/tex/gregoriotex-syllable.tex index 25ed735ab..40b5b6e81 100644 --- a/tex/gregoriotex-syllable.tex +++ b/tex/gregoriotex-syllable.tex @@ -973,6 +973,15 @@ \def\gre@opening@syllabletext{}% }% +\def\GreUpcomingNewLineForcesCustos#1{% + \ifcase#1\relax % 0 - forced off + \gre@usemanualeolcustos % + \or % 1 - forced on + \gre@useautoeolcustos % + \GreNextCustos{\gre@nextcustos}% + \fi % +}% + %% opens a score %% #1 - macros rendering the things after the initial but before the notes %% #2 - macros rendering the things after starting notes but before the syllable