summaryrefslogtreecommitdiff
path: root/Build/source/texk/gregorio/gregorio-src/src/gabc/gabc-score-determination.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/gregorio/gregorio-src/src/gabc/gabc-score-determination.c')
-rw-r--r--Build/source/texk/gregorio/gregorio-src/src/gabc/gabc-score-determination.c474
1 files changed, 350 insertions, 124 deletions
diff --git a/Build/source/texk/gregorio/gregorio-src/src/gabc/gabc-score-determination.c b/Build/source/texk/gregorio/gregorio-src/src/gabc/gabc-score-determination.c
index b6659c18499..433c29f7df0 100644
--- a/Build/source/texk/gregorio/gregorio-src/src/gabc/gabc-score-determination.c
+++ b/Build/source/texk/gregorio/gregorio-src/src/gabc/gabc-score-determination.c
@@ -3,7 +3,7 @@
* This file implements the score parser.
*
* Gregorio score determination from gabc utilities.
- * Copyright (C) 2016 The Gregorio Project (see CONTRIBUTORS.md)
+ * Copyright (C) 2016-2017 The Gregorio Project (see CONTRIBUTORS.md)
*
* This file is part of Gregorio.
*
@@ -24,6 +24,7 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <assert.h>
#include "bool.h"
#include "struct.h"
@@ -31,64 +32,116 @@
#include "gabc.h"
#include "gabc-score-determination.h"
#include "messages.h"
+#include "support.h"
-void fix_custos(gregorio_score *score_to_check)
+void gabc_suppress_extra_custos_at_linebreak(gregorio_score *score)
+{
+ gregorio_syllable *syllable;
+ gregorio_element **custos = NULL;
+
+ for (syllable = score->first_syllable; syllable;
+ syllable = syllable->next_syllable) {
+ gregorio_element **element;
+ for (element = syllable->elements; element && *element;
+ element = &((*element)->next)) {
+ switch ((*element)->type) {
+ case GRE_CUSTOS:
+ if (!((*element)->u.misc.pitched.force_pitch)) {
+ /* save the encountered non-forced custos */
+ custos = element;
+ } else {
+ /* forget the (previous) custos */
+ custos = NULL;
+ }
+ break;
+ case GRE_CLEF:
+ case GRE_BAR:
+ /* remember the custos if only these appear before linebreak */
+ break;
+ case GRE_END_OF_LINE:
+ if (custos) {
+ /* suppress the custos when linebreak follows */
+ gregorio_free_one_element(custos);
+ }
+ /* fall through */
+ default:
+ /* forget the custos */
+ custos = NULL;
+ break;
+ }
+ }
+ }
+}
+
+void gabc_fix_custos_pitches(gregorio_score *score_to_check)
{
gregorio_syllable *current_syllable;
gregorio_element *current_element;
- gregorio_element *custo_element;
- char pitch = 0;
- char pitch_difference = 0;
+ gregorio_element *custos_element;
int newkey;
int current_key;
+
if (!score_to_check || !score_to_check->first_syllable
|| !score_to_check->first_voice_info) {
return;
}
+
current_key = gregorio_calculate_new_key(
score_to_check->first_voice_info->initial_clef);
- current_syllable = score_to_check->first_syllable;
- while (current_syllable) {
- current_element = (current_syllable->elements)[0];
- while (current_element) {
- if (current_element->type == GRE_CUSTOS) {
- custo_element = current_element;
- pitch = custo_element->u.misc.pitched.pitch;
- /* we look for the key */
- while (current_element) {
- if (current_element->type == GRE_CLEF) {
- pitch = gregorio_determine_next_pitch(current_syllable,
- current_element, NULL, NULL);
- newkey = gregorio_calculate_new_key(
- current_element->u.misc.clef);
- pitch_difference = (char) newkey - (char) current_key;
- pitch -= pitch_difference;
- current_key = newkey;
- }
- if (!custo_element->u.misc.pitched.force_pitch) {
- while (pitch < LOWEST_PITCH) {
- pitch += 7;
- }
- while (pitch > score_to_check->highest_pitch) {
- pitch -= 7;
- }
- custo_element->u.misc.pitched.pitch = pitch;
- }
- assert(custo_element->u.misc.pitched.pitch >= LOWEST_PITCH
- && custo_element->u.misc.pitched.pitch
- <= score_to_check->highest_pitch);
- current_element = current_element->next;
- }
+ for (current_syllable = score_to_check->first_syllable; current_syllable;
+ current_syllable = current_syllable->next_syllable) {
+ for (current_element = (current_syllable->elements)[0]; current_element;
+ current_element = current_element->next) {
+ if (current_element->type == GRE_CLEF) {
+ newkey = gregorio_calculate_new_key(
+ current_element->u.misc.clef);
+ current_element->u.misc.clef.pitch_difference =
+ (signed char) newkey - (signed char) current_key;
+ current_key = newkey;
}
- if (current_element) {
- if (current_element->type == GRE_CLEF) {
- current_key = gregorio_calculate_new_key(
- current_element->u.misc.clef);
+ }
+ }
+
+ custos_element = NULL;
+ for (current_syllable = score_to_check->first_syllable; current_syllable;
+ current_syllable = current_syllable->next_syllable) {
+ for (current_element = (current_syllable->elements)[0]; current_element;
+ current_element = current_element->next) {
+ switch (current_element->type) {
+ case GRE_CUSTOS:
+ if (current_element->u.misc.pitched.force_pitch) {
+ /* forget about the preceding custos if a forced one is
+ * encountered */
+ custos_element = NULL;
+ } else {
+ /* the pitch is not forced, so it may need to be adjusted */
+ custos_element = current_element;
+ custos_element->u.misc.pitched.pitch =
+ gregorio_determine_next_pitch(current_syllable,
+ current_element, NULL, NULL);
+ }
+ break;
+
+ case GRE_ELEMENT:
+ /* if it's an element, forget any preceding custos */
+ custos_element = NULL;
+ break;
+
+ case GRE_CLEF:
+ if (custos_element) {
+ /* adjust the preceding custos for the clef */
+ custos_element->u.misc.pitched.pitch =
+ gregorio_adjust_pitch_into_staff(score_to_check,
+ custos_element->u.misc.pitched.pitch
+ - current_element->u.misc.clef.pitch_difference);
}
- current_element = current_element->next;
+ break;
+
+ default:
+ /* to prevent the warning */
+ break;
}
}
- current_syllable = current_syllable->next_syllable;
}
}
@@ -96,7 +149,7 @@ void fix_custos(gregorio_score *score_to_check)
* A function that checks the score integrity.
*/
-bool check_score_integrity(gregorio_score *score_to_check)
+bool gabc_check_score_integrity(gregorio_score *score_to_check)
{
bool good = true;
@@ -144,7 +197,7 @@ bool check_score_integrity(gregorio_score *score_to_check)
* Another function to be improved: this one checks the validity of the voice_infos.
*/
-bool check_infos_integrity(gregorio_score *score_to_check)
+bool gabc_check_infos_integrity(gregorio_score *score_to_check)
{
if (!score_to_check->name) {
gregorio_message(_("no name specified, put `name:...;' at the "
@@ -154,100 +207,100 @@ bool check_infos_integrity(gregorio_score *score_to_check)
return true;
}
-/* data must be (gregorio_note **) */
-static void oriscus_orientation_visit(
- const gregorio_note_iter_position *const p, void *const data)
+static void set_oriscus_descending(const gregorio_note_iter_position *const p,
+ void *const ignored __attribute__((unused)))
{
- gregorio_note *const note = p->note;
- gregorio_note **const oriscus_ptr = (gregorio_note **const)data;
- gregorio_note *const oriscus = *oriscus_ptr;
- /* making oriscus const ensures we don't attempt to change *oriscus_ptr
- * via oriscus */
-
- if (oriscus) {
- if (note->u.note.pitch <= oriscus->u.note.pitch) {
- /* descending or unison */
- switch(oriscus->u.note.shape) {
- case S_ORISCUS_UNDETERMINED:
- oriscus->u.note.shape = S_ORISCUS_DESCENDENS;
- break;
- case S_ORISCUS_SCAPUS_UNDETERMINED:
- oriscus->u.note.shape = S_ORISCUS_SCAPUS_DESCENDENS;
- break;
- case S_ORISCUS_CAVUM_UNDETERMINED:
- oriscus->u.note.shape = S_ORISCUS_CAVUM_DESCENDENS;
- break;
- default:
- /* not reachable unless there's a
- * programming error */
- /* LCOV_EXCL_START */
- gregorio_fail(oriscus_orientation_visit, "bad_shape");
- break;
- /* LCOV_EXCL_STOP */
- }
- } else { /* ascending */
- switch(oriscus->u.note.shape) {
- case S_ORISCUS_UNDETERMINED:
- oriscus->u.note.shape = S_ORISCUS_ASCENDENS;
- break;
- case S_ORISCUS_SCAPUS_UNDETERMINED:
- oriscus->u.note.shape = S_ORISCUS_SCAPUS_ASCENDENS;
- break;
- case S_ORISCUS_CAVUM_UNDETERMINED:
- oriscus->u.note.shape = S_ORISCUS_CAVUM_ASCENDENS;
- break;
- default:
- /* not reachable unless there's a
- * programming error */
- /* LCOV_EXCL_START */
- gregorio_fail(oriscus_orientation_visit, "bad_shape");
- break;
- /* LCOV_EXCL_STOP */
- }
+ switch(p->note->u.note.shape) {
+ case S_ORISCUS_UNDETERMINED:
+ p->note->u.note.shape = S_ORISCUS_DESCENDENS;
+ break;
+ case S_ORISCUS_SCAPUS_UNDETERMINED:
+ p->note->u.note.shape = S_ORISCUS_SCAPUS_DESCENDENS;
+ gregorio_assert_only(p->glyph->u.notes.glyph_type
+ != G_PES_DESCENDENS_ORISCUS, set_oriscus_descending,
+ "glyph type should not be G_PES_DESCENDENS_ORISCUS");
+ if (p->glyph->u.notes.glyph_type == G_PES_ASCENDENS_ORISCUS) {
+ p->glyph->u.notes.glyph_type = G_PES_DESCENDENS_ORISCUS;
}
- *oriscus_ptr = NULL;
+ break;
+ default:
+ break;
}
+}
- switch (note->u.note.shape) {
+static void set_oriscus_ascending(const gregorio_note_iter_position *const p,
+ void *const ignored __attribute__((unused)))
+{
+ switch(p->note->u.note.shape) {
case S_ORISCUS_UNDETERMINED:
+ p->note->u.note.shape = S_ORISCUS_ASCENDENS;
+ break;
case S_ORISCUS_SCAPUS_UNDETERMINED:
- case S_ORISCUS_CAVUM_UNDETERMINED:
- *oriscus_ptr = note;
+ p->note->u.note.shape = S_ORISCUS_SCAPUS_ASCENDENS;
+ gregorio_assert_only(p->glyph->u.notes.glyph_type
+ != G_PES_DESCENDENS_ORISCUS, set_oriscus_ascending,
+ "glyph type should not be G_PES_DESCENDENS_ORISCUS");
break;
-
default:
break;
}
}
-void determine_oriscus_orientation(const gregorio_score *const score)
+/* data must be (gregorio_note_iter_position *) */
+static void oriscus_orientation_visit(
+ const gregorio_note_iter_position *const p, void *const data)
{
- gregorio_note *oriscus = NULL;
+ gregorio_note *const note = p->note;
+ gregorio_note_iter_position *const oriscus =
+ (gregorio_note_iter_position *const)data;
- gregorio_for_each_note(score, oriscus_orientation_visit, &oriscus);
+ if (oriscus->note && note->u.note.pitch != oriscus->note->u.note.pitch) {
+ if (note->u.note.pitch <= oriscus->note->u.note.pitch) {
+ /* descending (or undetermined oriscus in unison) */
+ gregorio_from_note_to_note(oriscus, p, false,
+ set_oriscus_descending, NULL, GRESTRUCT_NONE, NULL);
+ } else {
+ /* ascending */
+ gregorio_from_note_to_note(oriscus, p, false,
+ set_oriscus_ascending, NULL, GRESTRUCT_NONE, NULL);
+ }
+ oriscus->syllable = NULL,
+ oriscus->element = NULL,
+ oriscus->note = NULL;
+ oriscus->glyph = NULL;
+ }
- if (oriscus) {
- /* oriscus at the end of the score */
- switch(oriscus->u.note.shape) {
+ if (!oriscus->note) {
+ switch (note->u.note.shape) {
case S_ORISCUS_UNDETERMINED:
- oriscus->u.note.shape = S_ORISCUS_DESCENDENS;
- break;
case S_ORISCUS_SCAPUS_UNDETERMINED:
- oriscus->u.note.shape = S_ORISCUS_SCAPUS_DESCENDENS;
- break;
- case S_ORISCUS_CAVUM_UNDETERMINED:
- oriscus->u.note.shape = S_ORISCUS_CAVUM_DESCENDENS;
+ *oriscus = *p;
break;
+
default:
- /* not reachable unless there's a programming error */
- /* LCOV_EXCL_START */
- gregorio_fail(determine_oriscus_orientation, "bad_shape");
break;
- /* LCOV_EXCL_STOP */
}
}
}
+void gabc_determine_oriscus_orientation(const gregorio_score *const score)
+{
+ gregorio_note_iter_position oriscus = {
+ /* .syllable = */ NULL,
+ /* .element = */ NULL,
+ /* .glyph = */ NULL,
+ /* .note = */ NULL
+ };
+
+ gregorio_for_each_note(score, oriscus_orientation_visit, NULL,
+ GRESTRUCT_NONE, &oriscus);
+
+ if (oriscus.note) {
+ gregorio_from_note_to_note(&oriscus, NULL, true,
+ set_oriscus_descending, NULL, GRESTRUCT_NONE, NULL);
+ }
+}
+
typedef struct {
gregorio_note_iter_position first, previous;
gregorio_shape orientation;
@@ -298,8 +351,6 @@ static void punctum_inclinatum_orientation_visit(
case S_PUNCTUM_INCLINATUM_DESCENDENS:
case S_PUNCTUM_INCLINATUM_DEMINUTUS:
case S_PUNCTUM_INCLINATUM_AUCTUS:
- case S_PUNCTUM_CAVUM_INCLINATUM:
- case S_PUNCTUM_CAVUM_INCLINATUM_AUCTUS:
v->orientation = S_PUNCTUM_INCLINATUM_DESCENDENS;
is_punctum_inclinatum = true;
break;
@@ -324,8 +375,8 @@ static void punctum_inclinatum_orientation_visit(
? S_PUNCTUM_INCLINATUM_ASCENDENS
: S_PUNCTUM_INCLINATUM_DESCENDENS;
}
- gregorio_from_note_to_note(&v->first, &v->previous, set_shape,
- &v->orientation);
+ gregorio_from_note_to_note(&v->first, &v->previous, true, set_shape,
+ NULL, GRESTRUCT_NONE, &v->orientation);
v->first.syllable = NULL;
v->first.element = NULL;
v->first.glyph = NULL;
@@ -341,7 +392,7 @@ static void punctum_inclinatum_orientation_visit(
v->previous = *p;
}
-void determine_punctum_inclinatum_orientation(
+void gabc_determine_punctum_inclinatum_orientation(
const gregorio_score *const score)
{
punctum_inclinatum_vars v = {
@@ -361,13 +412,188 @@ void determine_punctum_inclinatum_orientation(
/* .running = */ 0,
};
- gregorio_for_each_note(score, punctum_inclinatum_orientation_visit, &v);
-
+ gregorio_for_each_note(score, punctum_inclinatum_orientation_visit, NULL,
+ GRESTRUCT_NONE, &v);
+
if (v.first.note) {
v.orientation = (v.running > 0)
? S_PUNCTUM_INCLINATUM_ASCENDENS
: S_PUNCTUM_INCLINATUM_DESCENDENS;
- gregorio_from_note_to_note(&v.first, &v.previous, set_shape,
- &v.orientation);
+ gregorio_from_note_to_note(&v.first, &v.previous, true, set_shape, NULL,
+ GRESTRUCT_NONE, &v.orientation);
}
}
+
+typedef struct note_stack {
+ gregorio_note *note;
+ struct note_stack *prev;
+} note_stack;
+
+static void note_stack_push(note_stack **const stack, gregorio_note *note) {
+ note_stack *item = gregorio_malloc(sizeof(note_stack));
+ item->note = note;
+ item->prev = *stack;
+ *stack = item;
+}
+
+static gregorio_note *note_stack_pop(note_stack **const stack) {
+ note_stack *item = *stack;
+ if (item) {
+ gregorio_note *note = item->note;
+ note_stack *prev = item->prev;
+ free(item);
+ *stack = prev;
+ return note;
+ }
+ return NULL;
+}
+
+static void note_stack_clear(note_stack **const stack) {
+ note_stack *item = *stack;
+ while (item) {
+ note_stack *prev = item->prev;
+ free(item);
+ item = prev;
+ }
+ *stack = NULL;
+}
+
+typedef struct {
+ note_stack *high, *low;
+ gregorio_note *prev_note;
+ signed char high_ledger_line_pitch;
+ bool running_high, running_low;
+} ledger_line_vars;
+
+static __inline void clear_ledger_line_vars(ledger_line_vars *const v) {
+ note_stack_clear(&v->high);
+ note_stack_clear(&v->low);
+ v->prev_note = NULL;
+ v->running_high = false;
+ v->running_low = false;
+}
+
+static __inline void adjust_ledger(const gregorio_note_iter_position *const p,
+ const gregorio_ledger_specificity specificity, bool ledger_line,
+ note_stack **const stack, bool *const running, gregorio_note *prev_note,
+ const signed char high_ledger_line_pitch,
+ bool (*extend_ledger)(gregorio_note *, const gregorio_note *,
+ const gregorio_note *, signed char))
+{
+ if (specificity & LEDGER_DRAWN) {
+ if (ledger_line) {
+ gregorio_note *after = p->note;
+ gregorio_note *note;
+ /* process from this ledger backwards */
+ while ((note = note_stack_pop(stack))) {
+ if (!extend_ledger(note, NULL, after, high_ledger_line_pitch)) {
+ /* ledger has ended */
+ break;
+ }
+ after = note;
+ }
+ *running = true;
+ } else {
+ *running = false;
+ }
+ note_stack_clear(stack);
+ } else {
+ if (*running) {
+ if (!extend_ledger(p->note, prev_note, NULL,
+ high_ledger_line_pitch)) {
+ /* ledger has ended */
+ note_stack_push(stack, p->note);
+ *running = false;
+ }
+ /* else stack should be empty, keep it that way */
+ } else {
+ note_stack_push(stack, p->note);
+ }
+ }
+}
+
+static bool extend_high_ledger(gregorio_note *const note,
+ const gregorio_note *const note_before,
+ const gregorio_note *const note_after,
+ const signed char high_ledger_line_pitch)
+{
+ bool extend = false;
+
+ if (note_before) {
+ extend = note_before->u.note.pitch < note->u.note.pitch
+ || (note_before->u.note.pitch > high_ledger_line_pitch
+ && note->u.note.pitch < high_ledger_line_pitch);
+ } else if (note_after) {
+ extend = note_after->u.note.pitch < note->u.note.pitch
+ || (note_after->u.note.pitch > high_ledger_line_pitch
+ && note->u.note.pitch < high_ledger_line_pitch);
+ }
+
+ if (extend) {
+ note->high_ledger_line = true;
+ note->high_ledger_specificity = LEDGER_DRAWN;
+ }
+ return extend;
+}
+
+static bool extend_low_ledger(gregorio_note *const note,
+ const gregorio_note *const note_before,
+ const gregorio_note *const note_after,
+ const signed char high_ledger_line_pitch __attribute__((__unused__)))
+{
+ bool extend = false;
+
+ if (note_before) {
+ extend = note_before->u.note.pitch < note->u.note.pitch
+ || (note_before->u.note.pitch > LOW_LEDGER_LINE_PITCH
+ && note->u.note.pitch < LOW_LEDGER_LINE_PITCH);
+ } else if (note_after) {
+ extend = note_after->u.note.pitch < note->u.note.pitch
+ || (note_after->u.note.pitch > LOW_LEDGER_LINE_PITCH
+ && note->u.note.pitch < LOW_LEDGER_LINE_PITCH);
+ }
+
+ if (extend) {
+ note->low_ledger_line = true;
+ note->low_ledger_specificity = LEDGER_DRAWN;
+ }
+ return extend;
+}
+
+/* data must be (ledger_line_vars *) */
+static void ledger_line_visit(const gregorio_note_iter_position *const p,
+ void *const data)
+{
+ ledger_line_vars *const v = (ledger_line_vars *)data;
+
+ adjust_ledger(p, p->note->high_ledger_specificity, p->note->high_ledger_line,
+ &v->high, &v->running_high, v->prev_note, v->high_ledger_line_pitch,
+ &extend_high_ledger);
+ adjust_ledger(p, p->note->low_ledger_specificity, p->note->low_ledger_line,
+ &v->low, &v->running_low, v->prev_note, v->high_ledger_line_pitch,
+ &extend_low_ledger);
+
+ v->prev_note = p->note;
+}
+
+/* data must be (ledger_line_vars *) */
+static void ledger_line_end_item(
+ const gregorio_note_iter_position *const p __attribute__((__unused__)),
+ const gregorio_note_iter_item_type item_type, void *const data)
+{
+ if (item_type == GRESTRUCT_ELEMENT) {
+ clear_ledger_line_vars((ledger_line_vars *)data);
+ }
+}
+
+void gabc_determine_ledger_lines(const gregorio_score *const score)
+{
+ ledger_line_vars v;
+ memset(&v, 0, sizeof v);
+ v.high_ledger_line_pitch = score->high_ledger_line_pitch;
+
+ gregorio_for_each_note(score, ledger_line_visit, ledger_line_end_item,
+ GRESTRUCT_ELEMENT, &v);
+
+ /* stacks should be cleared by ledger_line_end_item */
+}