summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Puttock <n.puttock@gmail.com>2009-04-21 22:41:16 +0100
committerNeil Puttock <n.puttock@gmail.com>2009-04-21 22:41:16 +0100
commitd8b3b61b1a74121b65088747b7be2222235c1db3 (patch)
tree402cd0599f751444c36beb81977a9c3fa2d040c0
parent557fde71edeabde3b99cefe9f937fa0df3f3e2d1 (diff)
Fix #733.
- 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
-rw-r--r--input/regression/key-signature-scordatura-persist.ly19
-rw-r--r--lily/accidental-engraver.cc160
-rw-r--r--scm/music-functions.scm103
3 files changed, 134 insertions, 148 deletions
diff --git a/input/regression/key-signature-scordatura-persist.ly b/input/regression/key-signature-scordatura-persist.ly
new file mode 100644
index 0000000000..6e71b36d9b
--- /dev/null
+++ b/input/regression/key-signature-scordatura-persist.ly
@@ -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
+}
diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc
index 24340ed70f..f84e281d48 100644
--- a/lily/accidental-engraver.cc
+++ b/lily/accidental-engraver.cc
@@ -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),
diff --git a/scm/music-functions.scm b/scm/music-functions.scm
index 0263d498e9..28ef5bbe43 100644
--- a/scm/music-functions.scm
+++ b/scm/music-functions.scm
@@ -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