+ Stream_event *nr = info.event_cause ();
+
+ /*
+ ugh. why not simply check for pitch?
+ */
+ if (!nr->in_event_class ("note-event"))
+ {
+ nr->origin ()->warning
+ (_ ("cannot determine pitch of ligature primitive -> skipping"));
+ at_beginning = true;
+ continue;
+ }
+
+ int pitch = unsmob_pitch (nr->get_property ("pitch"))->steps ();
+ int prim = 0;
+
+ if (at_beginning)
+ {
+ if (i == s - 1)
+ {
+ // we can get here after invalid input
+ nr->origin ()->warning
+ (_ ("single note ligature - skipping"));
+ break;
+ }
+ prev_semibrevis = prev_brevis_shape = false;
+ prev_primitive = NULL;
+ }
+ else
+ {
+ if (pitch == prev_pitch)
+ {
+ nr->origin ()->warning
+ (_ ("prime interval within ligature -> skipping"));
+ at_beginning = true;
+ prim = MLP_NONE;
+ continue;
+ }
+ }
+
+ if (duration_log < -3 // is this possible at all???
+ || duration_log > 0)
+ {
+ nr->origin ()->warning
+ (_ ("mensural ligature: duration none of Mx, L, B, S -> skipping"));
+ prim = MLP_NONE;
+ at_beginning = true;
+ continue;
+ }
+
+ bool general_case = true;
+ bool make_flexa = false;
+ bool allow_flexa = true;
+
+ // first check special cases
+ // 1. beginning
+ if (at_beginning)
+ {
+ // a. semibreves
+ if (duration_log == 0)
+ {
+ prim = MLP_UP | MLP_BREVIS;
+ general_case = false;
+ }
+ // b. descendens longa or brevis
+ else if (i < s - 1
+ && (unsmob_pitch (primitives[i + 1].event_cause ()
+ ->get_property ("pitch"))->steps () < pitch)
+ && duration_log > -3)
+ {
+ int left_stem = duration_log == -1 ? MLP_DOWN : 0;
+ prim = left_stem | MLP_BREVIS;
+ general_case = false;
+ }
+ }
+ // 2. initial semibrevis must be followed by another one
+ else if (prev_semibrevis)
+ {
+ prev_semibrevis = false;
+ if (duration_log == 0)
+ {
+ prim = MLP_BREVIS;
+ general_case = false;
+ }
+ else
+ {
+ nr->origin ()->warning
+ (_ ("semibrevis must be followed by another one -> skipping"));
+ prim = MLP_NONE;
+ at_beginning = true;
+ continue;
+ }
+ }
+ // 3. semibreves are otherwise not allowed
+ else if (duration_log == 0)
+ {
+ nr->origin ()->warning
+ (_ ("semibreves can only appear at the beginning of a ligature,\n"
+ "and there may be only zero or two of them"));
+ prim = MLP_NONE;
+ at_beginning = true;
+ continue;
+ }
+ // 4. end, descendens
+ else if (i == s - 1 && pitch < prev_pitch)
+ {
+ // brevis; previous note must be turned into flexa
+ if (duration_log == -1)
+ {
+ if (prev_brevis_shape)
+ {
+ make_flexa = true;
+ general_case = false;
+ }
+ else
+ {
+ nr->origin ()->warning
+ (_ ("invalid ligatura ending:\n"
+ "when the last note is a descending brevis,\n"
+ "the penultimate note must be another one,\n"
+ "or the ligatura must be LB or SSB"));
+ prim = MLP_NONE;
+ break;
+ }
+ }
+ // longa
+ else if (duration_log == -2)
+ {
+ prim = MLP_BREVIS;
+ general_case = allow_flexa = false;
+ }
+ // else maxima; fall through to regular case below
+ }
+
+ if (allow_flexa
+ && to_boolean (primitive->get_property ("ligature-flexa")))
+ {
+ /*
+ flexa requested, check whether allowed:
+ - there should be a previous note
+ - both of the notes must be of brevis shape
+ (i.e. can't be maxima or flexa;
+ longa is forbidden as well - it's nonexistent anyway)
+ - no compulsory flexa for the next note,
+ i.e. it's not an ultimate descending breve
+ */
+ make_flexa = !at_beginning && prev_brevis_shape && duration_log > -2;
+ if (make_flexa && i == s - 2)
+ {
+ /*
+ check last condition: look ahead to next note
+ */
+ Grob_info next_info = primitives[i + 1];
+ Item *next_primitive = dynamic_cast<Item *> (next_info.grob ());
+ if (Rhythmic_head::duration_log (next_primitive) == -1)
+ {
+ /*
+ breve: check whether descending
+ */
+ int const next_pitch = unsmob_pitch
+ (next_info.event_cause ()->get_property ("pitch"))->steps ();
+ if (next_pitch < pitch)
+ /*
+ sorry, forbidden
+ */
+ make_flexa = false;
+ }
+ }
+ }
+
+ if (general_case)
+ {
+ static int const shape[3] = {MLP_MAXIMA, MLP_LONGA, MLP_BREVIS};
+
+ prim = shape[duration_log + 3];
+ }
+
+ if (make_flexa)
+ {
+ /*
+ turn the note with the previous one into a flexa
+ */
+ prev_primitive->set_property
+ ("primitive",
+ scm_from_int
+ (MLP_FLEXA_BEGIN
+ | (scm_to_int (prev_primitive->get_property ("primitive"))
+ & MLP_STEM)));
+ prev_primitive->set_property
+ ("flexa-interval", scm_from_int (pitch - prev_pitch));
+ prim = MLP_FLEXA_END;
+ primitive->set_property
+ ("flexa-interval", scm_from_int (pitch - prev_pitch));
+ }
+
+ // join_primitives replacement
+ if (!(at_beginning || make_flexa))
+ prev_primitive->set_property ("add-join", ly_bool2scm (true));
+
+ at_beginning = false;
+ prev_primitive = primitive;
+ prev_pitch = pitch;
+ primitive->set_property ("primitive", scm_from_int (prim));
+ prev_brevis_shape = (prim & MLP_BREVIS) != 0;
+ prev_semibrevis = (prim & MLP_UP) != 0;