]> git.donarmstrong.com Git - lilypond.git/commitdiff
Fix #733.
authorNeil Puttock <n.puttock@gmail.com>
Tue, 21 Apr 2009 21:41:16 +0000 (22:41 +0100)
committerNeil Puttock <n.puttock@gmail.com>
Tue, 21 Apr 2009 21:41:16 +0000 (22:41 +0100)
- when testing whether a pitch matches the key signature, try using
keySignature if no match is found in localKeySignature

- move check_pitch_against_signature () and related code to SCM,
passing context instead of localKeySignature

- remove ly:find-accidentals-simple

input/regression/key-signature-scordatura-persist.ly [new file with mode: 0644]
lily/accidental-engraver.cc
scm/music-functions.scm

diff --git a/input/regression/key-signature-scordatura-persist.ly b/input/regression/key-signature-scordatura-persist.ly
new file mode 100644 (file)
index 0000000..6e71b36
--- /dev/null
@@ -0,0 +1,19 @@
+\version "2.13.1"
+
+\header {
+  texidoc = "When a custom key signature has entries which are
+limited to a particular octave, such alterations should persist
+indefinitely or until a new key signature is set.
+
+Here, only the fis' shows an accidental, since it is outside the
+octave defined in @code{keySignature}.
+"
+}
+
+\relative c' {
+  \set Staff.keySignature = #`(((0 . 3) . ,SHARP)
+                               ((0 . 5) . ,FLAT)
+                               ((0 . 6) . ,FLAT))
+  fis fis as bes
+  fis' as, as bes
+}
index 24340ed70f2057e7fae2964d77723c7df260b192..f84e281d48f4672dbe4abcea5c5434d05b1efcda 100644 (file)
@@ -114,59 +114,19 @@ Accidental_engraver::update_local_key_signature (SCM new_sig)
 
   Context *trans = context ()->get_parent_context ();
 
-  /* Reset parent contexts so that e.g. piano-accidentals won't remember old
-     cross-staff accidentals after key-sig-changes */
+  /*
+    Reset parent contexts so that e.g. piano-accidentals won't remember old
+    cross-staff accidentals after key-sig-changes.
+  */
 
   SCM val;
-  while (trans && trans->where_defined (ly_symbol2scm ("localKeySignature"), &val)==trans)
+  while (trans && trans->where_defined (ly_symbol2scm ("localKeySignature"), &val) == trans)
     {
       trans->set_property ("localKeySignature", ly_deep_copy (last_keysig_));
       trans = trans->get_parent_context ();
     }
 }
 
-
-/** Calculate the number of accidentals on basis of the current local key
-    sig (passed as argument)
-
-    * First check step+octave (taking into account barnumbers if necessary).
-
-    * Then check the global signature (only step).
-
-    Return number of accidentals (0, 1 or 2).  */
-
-static bool
-recent_enough (int bar_number, SCM alteration_def, SCM laziness)
-{
-  if (scm_is_number (alteration_def)
-      || laziness == SCM_BOOL_T)
-    return true;
-
-  return (bar_number <= scm_to_int (scm_cadr (alteration_def)) + scm_to_int (laziness));
-}
-
-static Rational
-extract_alteration (SCM alteration_def)
-{
-  if (scm_is_number (alteration_def))
-    return ly_scm2rational (alteration_def);
-  else if (scm_is_pair (alteration_def))
-    return ly_scm2rational (scm_car (alteration_def));
-  else if (alteration_def == SCM_BOOL_F)
-    return Rational (0);
-  else
-    assert (0);
-  return Rational (0);
-}
-
-bool
-is_tied (SCM alteration_def)
-{
-  SCM tied = ly_symbol2scm ("tied");
-  return (alteration_def == tied
-         || (scm_is_pair (alteration_def) && scm_car (alteration_def) == tied));
-}
-
 struct Accidental_result
 {
   bool need_acc;
@@ -196,95 +156,6 @@ struct Accidental_result
   }
 };
 
-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));
-}
-
 static
 Accidental_result
 check_pitch_against_rules (Pitch const &pitch, Context *origin,
@@ -298,23 +169,23 @@ check_pitch_against_rules (Pitch const &pitch, Context *origin,
     warning (_f ("accidental typesetting list must begin with context-name: %s",
                 ly_scm2string (scm_car (rules)).c_str ()));
 
-  for (; scm_is_pair (rules) && origin;
-       rules = scm_cdr (rules))
+  for (; scm_is_pair (rules) && origin; rules = scm_cdr (rules))
     {
       SCM rule = scm_car (rules);
       if (ly_is_procedure (rule))
        {
          SCM rule_result_scm = scm_call_4 (rule, origin->self_scm (),
                                            pitch_scm, barnum_scm, measurepos);
-
          Accidental_result rule_result (rule_result_scm);
 
          result.need_acc |= rule_result.need_acc;
          result.need_restore |= rule_result.need_restore;
        }
 
-      /* if symbol then it is a context name.  Scan parent contexts to
-        find it. */
+      /*
+       If symbol then it is a context name.  Scan parent contexts to
+       find it.
+      */
       else if (scm_is_symbol (rule))
        {
          Context *dad = origin;
@@ -373,8 +244,10 @@ Accidental_engraver::process_acknowledged ()
          if (!acc.need_acc && forced)
            acc.need_acc = true;
 
-         /* Cannot look for ties: it's not guaranteed that they reach
-            us before the notes. */
+         /*
+           Cannot look for ties: it's not guaranteed that they reach
+           us before the notes.
+         */
          if (!note->in_event_class ("trill-span-event"))
            {
              if (acc.need_acc)       
@@ -526,14 +399,13 @@ Accidental_engraver::stop_translation_timestep ()
              */
              localsig = ly_assoc_prepend_x (localsig, key,scm_cons (ly_symbol2scm ("tied"),
                                                                     position));
-
              change = true;
            }
          else
            {
              /*
-               not really really correct if there are more than one
-               noteheads with the same notename.
+               not really really correct if there is more than one
+               note head with the same notename.
              */
              localsig = ly_assoc_prepend_x (localsig, key,
                                             scm_cons (ly_rational2scm (a),
index 0263d498e94038890c7ce4a30af0e4561e03f5e1..28ef5bbe43abec41d824110f89c51e80b633b644 100644 (file)
@@ -979,7 +979,103 @@ Syntax:
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; accidentals
 
-(define-public ((make-accidental-rule octaveness lazyness) context pitch barnum measurepos)
+(define (recent-enough? bar-number alteration-def laziness)
+  (if (or (number? alteration-def)
+         (equal? laziness #t))
+      #t
+      (<= bar-number (+ (cadr alteration-def) laziness))))
+
+(define (is-tied? alteration-def)
+  (let* ((def (if (pair? alteration-def)
+                (car alteration-def)
+                alteration-def)))
+
+    (if (equal? def 'tied) #t #f)))
+
+(define (extract-alteration alteration-def)
+  (cond ((number? alteration-def)
+        alteration-def)
+       ((pair? alteration-def)
+        (car alteration-def))
+       (else 0)))
+
+(define (check-pitch-against-signature context pitch barnum laziness octaveness)
+  "Checks the need for an accidental and a @q{restore} accidental against
+@code{localKeySignature}. The @var{laziness} is the number of measures
+for which reminder accidentals are used (i.e., if @var{laziness} is zero,
+only cancel accidentals in the same measure; if @var{laziness} is three,
+we cancel accidentals up to three measures after they first appear.
+@var{octaveness} is either @code{'same-octave} or @code{'any-octave} and
+specifies whether accidentals should be canceled in different octaves."
+  (let* ((ignore-octave (cond ((equal? octaveness 'any-octave) #t)
+                             ((equal? octaveness 'same-octave) #f)
+                             (else
+                              (ly:warning (_ "Unknown octaveness type: ~S ") octaveness)
+                              (ly:warning (_ "Defaulting to 'any-octave."))
+                              #t)))
+        (key-sig (ly:context-property context 'keySignature))
+        (local-key-sig (ly:context-property context 'localKeySignature))
+        (notename (ly:pitch-notename pitch))
+        (octave (ly:pitch-octave pitch))
+        (pitch-handle (cons octave notename))
+        (need-restore #f)
+        (need-accidental #f)
+        (previous-alteration #f)
+        (from-other-octaves #f)
+        (from-same-octave (ly:assoc-get pitch-handle local-key-sig))
+        (from-key-sig (ly:assoc-get notename local-key-sig)))
+
+    ;; If no key signature match is found from localKeySignature, we may have a custom
+    ;; type with octave-specific entries of the form ((octave . pitch) alteration)
+    ;; instead of (pitch . alteration).  Since this type cannot coexist with entries in
+    ;; localKeySignature, try extracting from keySignature instead.
+    (if (equal? from-key-sig #f)
+       (set! from-key-sig (ly:assoc-get pitch-handle key-sig)))
+
+    ;; loop through localKeySignature to search for a notename match from other octaves
+    (let loop ((l local-key-sig))
+      (if (pair? l)
+         (let ((entry (car l)))
+           (if (and (pair? (car entry))
+                    (= (cdar entry) notename))
+               (set! from-other-octaves (cdr entry))
+               (loop (cdr l))))))
+
+    ;; find previous alteration-def for comparison with pitch
+    (cond
+     ;; from same octave?
+     ((and (eq? ignore-octave #f)
+          (not (equal? from-same-octave #f))
+          (recent-enough? barnum from-same-octave laziness))
+      (set! previous-alteration from-same-octave))
+
+     ;; from any octave?
+     ((and (eq? ignore-octave #t)
+          (not (equal? from-other-octaves #f))
+          (recent-enough? barnum from-other-octaves laziness))
+      (set! previous-alteration from-other-octaves))
+
+     ;; not recent enough, extract from key signature/local key signature
+     ((not (equal? from-key-sig #f))
+      (set! previous-alteration from-key-sig)))
+
+    (if (is-tied? previous-alteration)
+       (set! need-accidental #t)
+
+       (let* ((prev-alt (extract-alteration previous-alteration))
+              (this-alt (ly:pitch-alteration pitch)))
+
+         (if (not (= this-alt prev-alt))
+             (begin
+               (set! need-accidental #t)
+               (if (and (not (= this-alt 0))
+                        (or (< (abs this-alt) (abs prev-alt))
+                            (< (* prev-alt this-alt) 0)))
+                   (set! need-restore #t))))))
+
+    (cons need-restore need-accidental)))
+
+(define-public ((make-accidental-rule octaveness laziness) context pitch barnum measurepos)
   "Creates an accidental rule that makes its decision based on the octave of the note
   and a laziness value.
   octaveness is either 'same-octave or 'any-octave and defines whether the rule should
@@ -987,13 +1083,12 @@ Syntax:
   normal way to typeset accidentals - an accidental is made if the alteration is different
   from the last active pitch in the same octave. 'any-octave looks at the last active pitch
   in any octave.
-  lazyness states over how many bars an accidental should be remembered.
+  laziness states over how many bars an accidental should be remembered.
   0 is default - accidental lasts over 0 bar lines, that is, to the end of current measure.
   A positive integer means that the accidental lasts over that many bar lines.
   -1 is 'forget immediately', that is, only look at key signature.
   #t is forever."
-  (let ((keysig (ly:context-property context 'localKeySignature)))
-    (ly:find-accidentals-simple keysig pitch barnum lazyness octaveness)))
+  (check-pitch-against-signature context pitch barnum laziness octaveness))
 
 (define (key-entry-notename entry)
   "Return the pitch of an entry in localKeySignature. The entry is either of the form