From: Joe Neeman Date: Tue, 19 Aug 2008 19:00:28 +0000 (-0700) Subject: Merge accidental callbacks from dev/rune. X-Git-Tag: release/2.11.58-1~37 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=d98b136f8ab9b84552e8a6d76b3965055e8a77ae;p=lilypond.git Merge accidental callbacks from dev/rune. --- diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc index aaf8307cd7..4d8fbc06a1 100644 --- a/lily/accidental-engraver.cc +++ b/lily/accidental-engraver.cc @@ -9,16 +9,17 @@ #include "accidental-placement.hh" #include "arpeggio.hh" -#include "spanner.hh" #include "context.hh" -#include "item.hh" +#include "duration.hh" #include "engraver.hh" #include "international.hh" +#include "item.hh" #include "pitch.hh" #include "protected-scm.hh" #include "rhythmic-head.hh" #include "separation-item.hh" #include "side-position-interface.hh" +#include "spanner.hh" #include "stream-event.hh" #include "tie.hh" #include "warn.hh" @@ -141,7 +142,7 @@ recent_enough (int bar_number, SCM alteration_def, SCM laziness) || laziness == SCM_BOOL_T) return true; - return (bar_number <= scm_to_int (scm_cdr (alteration_def)) + scm_to_int (laziness)); + return (bar_number <= scm_to_int (scm_cadr (alteration_def)) + scm_to_int (laziness)); } static Rational @@ -171,11 +172,25 @@ struct Accidental_result bool need_acc; bool need_restore; - Accidental_result () { + Accidental_result () + { need_restore = need_acc = false; } - int score () const { + 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; } @@ -239,12 +254,46 @@ check_pitch_against_signature (SCM key_signature, Pitch const &pitch, 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 pp, SCM barnum, SCM laziness, SCM octaveness ), + "Checks the need for an accidental and a 'restore' accidental against a" + " key signature. The laziness is the number of bars for which reminder" + " accidentals are used (ie. if laziness is zero, we only cancel accidentals" + " in the same bar; if laziness is three, we cancel accidentals up to three" + " bars after they first appear. Octaveness is either 'same-octave or" + " 'any-octave and it specifies whether accidentals should be canceled in" + " different octaves.") +{ + LY_ASSERT_TYPE (unsmob_pitch, pp, 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 (pp); + + 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, - SCM rules, int bar_number) + SCM rules, int bar_number, SCM measurepos) { Accidental_result result; + SCM pitch_scm = pitch.smobbed_copy (); + SCM barnum_scm = scm_from_int (bar_number); + if (scm_is_pair (rules) && !scm_is_symbol (scm_car (rules))) warning (_f ("accidental typesetting list must begin with context-name: %s", ly_scm2string (scm_car (rules)).c_str ())); @@ -253,28 +302,15 @@ check_pitch_against_rules (Pitch const &pitch, Context *origin, rules = scm_cdr (rules)) { SCM rule = scm_car (rules); - if (scm_is_pair (rule)) + if (ly_is_procedure (rule)) { - SCM type = scm_car (rule); - SCM laziness = scm_cdr (rule); - SCM localsig = origin->get_property ("localKeySignature"); - - bool same_octave - = (ly_symbol2scm ("same-octave") == type); - bool any_octave - = (ly_symbol2scm ("any-octave") == type); + SCM rule_result_scm = scm_call_4 (rule, origin->self_scm (), + pitch_scm, barnum_scm, measurepos); - if (same_octave || any_octave) - { - Accidental_result rule_result = check_pitch_against_signature - (localsig, pitch, bar_number, laziness, any_octave); + Accidental_result rule_result (rule_result_scm); - result.need_acc |= rule_result.need_acc; - result.need_restore |= rule_result.need_restore; - } - else - warning (_f ("ignoring unknown accidental rule: %s", - ly_symbol2string (type).c_str ())); + 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 @@ -289,8 +325,8 @@ check_pitch_against_rules (Pitch const &pitch, Context *origin, origin = dad; } else - warning (_f ("pair or context-name expected for accidental rule, found %s", - ly_scm2string (rule).c_str ())); + warning (_f ("procedure or context-name expected for accidental rule, found %s", + print_scm_val (rule).c_str ())); } return result; @@ -303,6 +339,7 @@ Accidental_engraver::process_acknowledged () { SCM accidental_rules = get_property ("autoAccidentals"); SCM cautionary_rules = get_property ("autoCautionaries"); + SCM measure_position = get_property ("measurePosition"); int barnum = measure_number (context()); for (vsize i = 0; i < accidentals_.size (); i++) @@ -318,10 +355,10 @@ Accidental_engraver::process_acknowledged () if (!pitch) continue; - Accidental_result acc = check_pitch_against_rules (*pitch, origin, - accidental_rules, barnum); - Accidental_result caut = check_pitch_against_rules (*pitch, origin, - cautionary_rules, barnum); + Accidental_result acc = check_pitch_against_rules (*pitch, origin, accidental_rules, + barnum, measure_position); + Accidental_result caut = check_pitch_against_rules (*pitch, origin, cautionary_rules, + barnum, measure_position); bool cautionary = to_boolean (note->get_property ("cautionary")); if (caut.score () > acc.score ()) @@ -475,6 +512,16 @@ Accidental_engraver::stop_translation_timestep () Rational a = pitch->get_alteration (); SCM key = scm_cons (scm_from_int (o), scm_from_int (n)); + Duration *dur = unsmob_duration (note->get_property ("duration")); + Rational dur_length = dur ? dur->get_length () : Rational (0); + Moment mp = robust_scm2moment (get_property ("measurePosition"), Moment (0)); + + Moment end_mp = mp.grace_part_ < Rational(0) + ? Moment(mp.main_part_, mp.grace_part_ + dur_length) + : Moment(mp.main_part_ + dur_length, 0); + + SCM position = scm_cons (scm_from_int (barnum), end_mp.smobbed_copy ()); + SCM localsig = SCM_EOL; while (origin && origin->where_defined (ly_symbol2scm ("localKeySignature"), &localsig)) @@ -487,8 +534,8 @@ Accidental_engraver::stop_translation_timestep () Remember an alteration that is different both from that of the tied note and of the key signature. */ - localsig = ly_assoc_prepend_x (localsig, key, scm_cons (ly_symbol2scm ("tied"), - scm_from_int (barnum))); + localsig = ly_assoc_prepend_x (localsig, key,scm_cons (ly_symbol2scm ("tied"), + position)); change = true; } @@ -499,8 +546,8 @@ Accidental_engraver::stop_translation_timestep () noteheads with the same notename. */ localsig = ly_assoc_prepend_x (localsig, key, - scm_cons (ly_rational2scm (a), - scm_from_int (barnum))); + scm_cons (ly_rational2scm (a), + position)); change = true; } @@ -603,6 +650,7 @@ ADD_TRANSLATOR (Accidental_engraver, "internalBarNumber " "extraNatural " "harmonicAccidentals " + "keySignature " "localKeySignature ", /* write */ diff --git a/lily/pitched-trill-engraver.cc b/lily/pitched-trill-engraver.cc index 39cb899acc..3555a99d45 100644 --- a/lily/pitched-trill-engraver.cc +++ b/lily/pitched-trill-engraver.cc @@ -85,7 +85,7 @@ Pitched_trill_engraver::make_trill (Stream_event *ev) SCM handle = scm_assoc (key, keysig); if (handle != SCM_BOOL_F) { - bool same_bar = (bn == robust_scm2int (scm_cddr (handle), 0)); + bool same_bar = (bn == robust_scm2int (scm_caddr (handle), 0)); bool same_alt = (p->get_alteration () == robust_scm2rational (scm_cadr (handle), 0)); diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 022fb8a1d9..80700b8584 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -548,7 +548,7 @@ automatically when an output definition (a @code{\score} or subdivideBeams = ##f allowBeamBreak = ##f extraNatural = ##t - autoAccidentals = #'(Staff (same-octave . 0)) + autoAccidentals = #`(Staff ,(make-accidental-rule 'same-octave 0)) autoCautionaries = #'() printKeyCancellation = ##t @@ -906,7 +906,7 @@ accommodated for typesetting a piece in mensural style." %% Accidentals are valid only once (same as %% #(set-accidental-style 'forget)) extraNatural = ##f - autoAccidentals = #'(Staff (same-octave . -1)) + autoAccidentals = #`(Staff ,(make-accidental-rule 'same-octave -1)) autoCautionaries = #'() printKeyCancellation = ##f } diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index cbd0e1544b..59ea0820e6 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -47,41 +47,43 @@ accidental. For determining when to print an accidental, several different rules are tried. The rule that gives the highest number of accidentals is -used. Each rule consists of +used. + +Each entry in the list is either a symbol or a procedure. @table @var -@item context -In which context is the rule applied. For example, if @var{context} -is @rinternals{Score} then all staves share accidentals, and if -@var{context} is @rinternals{Staff} then all voices in the same staff -share accidentals, but staves do not. +@item symbol +The symbol is the name of the context in which the following rules are to be +applied. For example, if @var{context} is @internalsref{Score} then all +staves share accidentals, and if @var{context} is @internalsref{Staff} then +all voices in the same staff share accidentals, but staves do not. + +@item procedure +The procedure represents an accidental rule to be applied to the previously +specified context. -@item octavation -Whether the accidental changes all octaves or only the current octave. -Valid choices are +The procedure takes the following arguments: @table @code -@item same-octave -This is the default algorithm. Accidentals are typeset if the note -changes the accidental of that note in that octave. Accidentals lasts -to the end of the measure and then as many measures as specified in the -value. This is, @code{1}@tie{}means to the end of next measure, -@code{-1}@tie{}means to the end of previous measure (that is: no -duration at all), etc. @code{#t} means forever. +@item context +The current context to which the rule should be applied. + +@item pitch +The pitch of the note to be evaluated. + +@item barnum +The current bar number. -@item any-octave -Accidentals are typeset if the note is different from the previous note -on the same pitch in any octave. The value has same meaning as in -@code{same-octave}. +@item measurepos +The current measure position. @end table -@item laziness -Over how many bar lines the accidental lasts. If @var{laziness} is -@code{-1} then the accidental is forgotten immediately, and if -@var{laziness} is @code{#t} then the accidental lasts forever. +The procedure returns a pair of booleans. The first states whether an extra +natural should be added. The second states whether an accidental should be +printed. @code{(#t . #f)} does not make sense. @end table") (autoBeamCheck ,procedure? "A procedure taking three @@ -546,8 +548,8 @@ instrument name to.") signature change.") (localKeySignature ,list? "The key signature at this point in the measure. The format is the same as for @code{keySignature}, but can -also contain @code{((@var{octave} . @var{name}) . (@var{alter} . -@var{barnumber}))} pairs.") +also contain @code{((@var{octave} . @var{name}) . (@var{alter} +@var{barnumber} . @var{measureposition}))} pairs.") (melismaBusy ,boolean? "Signifies whether a melisma is active. diff --git a/scm/music-functions.scm b/scm/music-functions.scm index 7b2cc3404f..9e100235c6 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -893,6 +893,94 @@ if appropriate. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; accidentals +(define-public ((make-accidental-rule octaveness lazyness) 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 + respond to accidental changes in other octaves than the current. 'same-octave is the + 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. + 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))) + +(define (key-entry-notename entry) + "Return the pitch of an entry in localKeySignature. The entry is either of the form + '(notename . alter) or '((octave . notename) . (alter barnum . measurepos))." + (if (number? (car entry)) + (car entry) + (cdar entry))) + +(define (key-entry-octave entry) + "Return the octave of an entry in localKeySignature (or #f if the entry does not have + an octave)." + (if (number? (car entry)) + #f + (caar entry))) + +(define (key-entry-bar-number entry) + "Return the bar number of an entry in localKeySignature (or #f if the entry does not + have a bar number)." + (if (number? (car entry)) + #f + (caddr entry))) + +(define (key-entry-measure-position entry) + "Return the measure position of an entry in localKeySignature (or #f if the entry does + not have a measure position)." + (if (number? (car entry)) + #f + (cdddr entry))) + +(define (key-entry-alteration entry) + "Return the alteration of an entry in localKeySignature." + (if (number? (car entry)) + (cdr entry) + (cadr entry))) + +(define-public (find-pitch-entry keysig pitch accept-global accept-local) + "Return the first entry in keysig that matches the pitch. + accept-global states whether key signature entries should be included. + accept-local states whether local accidentals should be included. + if no matching entry is found, #f is returned." + (if (pair? keysig) + (let* ((entry (car keysig)) + (entryoct (key-entry-octave entry)) + (entrynn (key-entry-notename entry)) + (oct (ly:pitch-octave pitch)) + (nn (ly:pitch-notename pitch))) + (if (and (equal? nn entrynn) + (or (and accept-global (equal? #f entryoct)) + (and accept-local (equal? oct entryoct)))) + entry + (find-pitch-entry (cdr keysig) pitch accept-global accept-local))) + #f)) + +(define-public (neo-modern-accidental-rule context pitch barnum measurepos) + "an accidental rule that typesets an accidental if it differs from the key signature + AND does not directly follow a note on the same staff-line. + This rule should not be used alone because it does neither look at bar lines + nor different accidentals at the same notename" + (let* ((keysig (ly:context-property context 'localKeySignature)) + (entry (find-pitch-entry keysig pitch #t #t))) + (if (equal? #f entry) + (cons #f #f) + (let* ((global-entry (find-pitch-entry keysig pitch #t #f)) + (key-acc (if (equal? global-entry #f) + 0 + (key-entry-alteration global-entry))) + (acc (ly:pitch-alteration pitch)) + (entrymp (key-entry-measure-position entry)) + (entrybn (key-entry-bar-number entry))) + (cons #f (not (or (equal? acc key-acc) + (and (equal? entrybn barnum) (equal? entrymp measurepos))))))))) + + (define-public (set-accidentals-properties extra-natural auto-accs auto-cauts context) @@ -907,7 +995,7 @@ if appropriate. (define-public (set-accidental-style style . rest) "Set accidental style to STYLE. Optionally takes a context argument, -e.g. 'Staff or 'Voice. The context defaults to Voice, except for piano styles, which +e.g. 'Staff or 'Voice. The context defaults to Staff, except for piano styles, which use GrandStaff as a context. " (let ((context (if (pair? rest) (car rest) 'Staff)) @@ -917,54 +1005,101 @@ use GrandStaff as a context. " (cond ;; accidentals as they were common in the 18th century. ((equal? style 'default) - (set-accidentals-properties #t '(Staff (same-octave . 0)) - '() context)) + (set-accidentals-properties #t + `(Staff ,(make-accidental-rule 'same-octave 0)) + '() + context)) ;; accidentals from one voice do NOT get cancelled in other voices ((equal? style 'voice) - (set-accidentals-properties #t '(Voice (same-octave . 0)) - '() context)) + (set-accidentals-properties #t + `(Voice ,(make-accidental-rule 'same-octave 0)) + '() + context)) ;; accidentals as suggested by Kurt Stone, Music Notation in the 20th century. ;; This includes all the default accidentals, but accidentals also needs cancelling ;; in other octaves and in the next measure. ((equal? style 'modern) - (set-accidentals-properties #f '(Staff (same-octave . 0) (any-octave . 0) (same-octave . 1)) - '() context)) + (set-accidentals-properties #f + `(Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) + '() + context)) ;; the accidentals that Stone adds to the old standard as cautionaries ((equal? style 'modern-cautionary) - (set-accidentals-properties #f '(Staff (same-octave . 0)) - '(Staff (any-octave . 0) (same-octave . 1)) + (set-accidentals-properties #f + `(Staff ,(make-accidental-rule 'same-octave 0)) + `(Staff ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) + context)) + ;; same as modern, but accidentals different from the key signature are always + ;; typeset - unless they directly follow a note of the same pitch. + ((equal? style 'neo-modern) + (set-accidentals-properties #f + `(Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + ,neo-modern-accidental-rule) + '() + context)) + ((equal? style 'neo-modern-cautionary) + (set-accidentals-properties #f + `(Staff ,(make-accidental-rule 'same-octave 0)) + `(Staff ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + ,neo-modern-accidental-rule) + context)) + ;; Accidentals as they were common in dodecaphonic music with no tonality. + ;; Each note gets one accidental. + ((equal? style 'dodecaphonic) + (set-accidentals-properties #f + `(Staff ,(lambda (c p bn mp) '(#f . #t))) + '() context)) ;; Multivoice accidentals to be read both by musicians playing one voice ;; and musicians playing all voices. ;; Accidentals are typeset for each voice, but they ARE cancelled across voices. ((equal? style 'modern-voice) (set-accidentals-properties #f - '(Voice (same-octave . 0) (any-octave . 0) (same-octave . 1) - Staff (same-octave . 0) (any-octave . 0) (same-octave . 1)) + `(Voice ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) '() context)) ;; same as modernVoiceAccidental eccept that all special accidentals are typeset ;; as cautionaries ((equal? style 'modern-voice-cautionary) (set-accidentals-properties #f - '(Voice (same-octave . 0)) - '(Voice (any-octave . 0) (same-octave . 1) - Staff (same-octave . 0) (any-octave . 0) (same-octave . 1)) + `(Voice ,(make-accidental-rule 'same-octave 0)) + `(Voice ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) context)) ;; stone's suggestions for accidentals on grand staff. ;; Accidentals are cancelled across the staves in the same grand staff as well ((equal? style 'piano) (set-accidentals-properties #f - '(Staff (same-octave . 0) - (any-octave . 0) (same-octave . 1) - GrandStaff (any-octave . 0) (same-octave . 1)) + `(Staff ,(make-accidental-rule 'same-octave 0) + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + GrandStaff + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) '() pcontext)) ((equal? style 'piano-cautionary) (set-accidentals-properties #f - '(Staff (same-octave . 0)) - '(Staff (any-octave . 0) (same-octave . 1) - GrandStaff (any-octave . 0) (same-octave . 1)) + `(Staff ,(make-accidental-rule 'same-octave 0)) + `(Staff ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1) + GrandStaff + ,(make-accidental-rule 'any-octave 0) + ,(make-accidental-rule 'same-octave 1)) pcontext)) ;; do not set localKeySignature when a note alterated differently from @@ -973,17 +1108,17 @@ use GrandStaff as a context. " ;; remembered for the duration of a measure. ;; accidentals not being remembered, causing accidentals always to ;; be typeset relative to the time signature - ((equal? style 'forget) (set-accidentals-properties '() - '(Staff (same-octave . -1)) - '() context)) + `(Staff ,(make-accidental-rule 'same-octave -1)) + '() + context)) ;; Do not reset the key at the start of a measure. Accidentals will be ;; printed only once and are in effect until overridden, possibly many ;; measures later. ((equal? style 'no-reset) (set-accidentals-properties '() - '(Staff (same-octave . #t)) + `(Staff ,(make-accidental-rule 'same-octave #t)) '() context)) (else