+
+ Accidental_result (bool restore, bool acc)
+ {
+ need_restore = restore;
+ need_acc = acc;
+ }
+
+ Accidental_result (SCM scm)
+ {
+ need_restore = to_boolean (scm_car (scm));
+ need_acc = to_boolean (scm_cdr (scm));
+ }
+
+ int score () const
+ {
+ return need_acc ? 1 : 0
+ + need_restore ? 1 : 0;
+ }
+};
+
+Accidental_result
+check_pitch_against_signature (SCM key_signature, Pitch const &pitch,
+ int bar_number, SCM laziness, bool ignore_octave)
+{
+ Accidental_result result;
+ int n = pitch.get_notename ();
+ int o = pitch.get_octave ();
+
+ SCM previous_alteration = SCM_BOOL_F;
+
+ SCM from_same_octave = ly_assoc_get (scm_cons (scm_from_int (o),
+ scm_from_int (n)), key_signature, SCM_BOOL_F);
+ SCM from_key_signature = ly_assoc_get (scm_from_int (n), key_signature, SCM_BOOL_F);
+ SCM from_other_octaves = SCM_BOOL_F;
+ for (SCM s = key_signature; scm_is_pair (s); s = scm_cdr (s))
+ {
+ SCM entry = scm_car (s);
+ if (scm_is_pair (scm_car (entry))
+ && scm_cdar (entry) == scm_from_int (n))
+ {
+ from_other_octaves = scm_cdr (entry);
+ break;
+ }
+ }
+
+ if (!ignore_octave
+ && from_same_octave != SCM_BOOL_F
+ && recent_enough (bar_number, from_same_octave, laziness))
+ previous_alteration = from_same_octave;
+ else if (ignore_octave
+ && from_other_octaves != SCM_BOOL_F
+ && recent_enough (bar_number, from_other_octaves, laziness))
+ previous_alteration = from_other_octaves;
+ else if (from_key_signature != SCM_BOOL_F)
+ previous_alteration = from_key_signature;
+
+ if (is_tied (previous_alteration))
+ {
+ result.need_acc = true;
+ }
+ else
+ {
+ Rational prev = extract_alteration (previous_alteration);
+ Rational alter = pitch.get_alteration ();
+
+ if (alter != prev)
+ {
+ result.need_acc = true;
+ if (alter.sign ()
+ && (alter.abs () < prev.abs ()
+ || (prev * alter).sign () < 0))
+ result.need_restore = true;
+ }
+ }
+
+ return result;
+}
+
+// TODO: consider moving check_pitch_against_signature to SCM (in which case
+// we can delete this function).
+LY_DEFINE (ly_find_accidentals_simple, "ly:find-accidentals-simple", 5, 0, 0,
+ (SCM keysig, SCM pitch_scm, SCM barnum, SCM laziness, SCM octaveness ),
+ "Checks the need for an accidental and a @q{restore} accidental against a"
+ " key signature. The @var{laziness} is the number of bars for which reminder"
+ " accidentals are used (ie. if @var{laziness} is zero, we only cancel accidentals"
+ " in the same bar; if @var{laziness} is three, we cancel accidentals up to three"
+ " bars after they first appear. @var{octaveness} is either "
+ " @code{'same-octave} or @code{'any-octave} and it specifies whether "
+ " accidentals should be canceled in different octaves.")
+{
+ LY_ASSERT_TYPE (unsmob_pitch, pitch_scm, 2);
+ LY_ASSERT_TYPE (scm_is_integer, barnum, 3);
+ LY_ASSERT_TYPE (ly_is_symbol, octaveness, 5);
+
+ bool symbol_ok = octaveness == ly_symbol2scm ("any-octave") ||
+ octaveness == ly_symbol2scm ("same-octave");
+
+ SCM_ASSERT_TYPE (symbol_ok, octaveness, SCM_ARG5, __FUNCTION__, "'any-octave or 'same-octave");
+
+ Pitch *pitch = unsmob_pitch (pitch_scm);
+
+ int bar_number = scm_to_int (barnum);
+ bool ignore_octave = ly_symbol2scm ("any-octave") == octaveness;
+ Accidental_result result = check_pitch_against_signature (keysig, *pitch, bar_number,
+ laziness, ignore_octave);
+
+ return scm_cons (scm_from_bool (result.need_restore), scm_from_bool (result.need_acc));