X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Faccidental-engraver.cc;h=808c2408ec5a76947e8de6ff12d16366516ca942;hb=e540311d3f5799216c91d203080f63b65cccde07;hp=fd26acd16c1c3251243f829c828878f586ade08d;hpb=7ea5c74058200ace4b405de82e1088560aeaacb2;p=lilypond.git diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc index fd26acd16c..808c2408ec 100644 --- a/lily/accidental-engraver.cc +++ b/lily/accidental-engraver.cc @@ -1,12 +1,12 @@ /* accidental-engraver.cc -- implement accidental_engraver - (c) 1997--2003 Han-Wen Nienhuys - Modified 2001-2002 by Rune Zedeler + (c) 1997--2004 Han-Wen Nienhuys + Modified 2001--2002 by Rune Zedeler */ #include "event.hh" - +#include "spanner.hh" #include "item.hh" #include "tie.hh" #include "rhythmic-head.hh" @@ -16,30 +16,23 @@ #include "engraver.hh" #include "arpeggio.hh" #include "warn.hh" -#include "translator-group.hh" - -/** - - -FIXME: should not compute vertical positioning of accidentals, but -get them from the noteheads +#include "context.hh" +#include "protected-scm.hh" -The algorithm for accidentals should be documented, and made -tweakable. - -*/ struct Accidental_entry { bool done_; Music * melodic_; Grob * accidental_; - Translator_group *origin_; + Context *origin_; Grob* head_; - Accidental_entry(); + bool tied_; + Accidental_entry (); }; -Accidental_entry::Accidental_entry() +Accidental_entry::Accidental_entry () { + tied_ = false; done_ = false; melodic_ =0; accidental_ = 0; @@ -58,13 +51,7 @@ protected: virtual void finalize (); public: - /* - TODO -> property. - - This is not a property, and it is not protected. This poses a - very small risk of the value being GC'd from under us. - */ - SCM last_keysig_; + Protected_scm last_keysig_; /* Urgh. Since the accidentals depend on lots of variables, we have to @@ -75,21 +62,22 @@ public: Grob * accidental_placement_; - /* - The next - */ Array accidentals_; - Link_array ties_; + Link_array ties_; + + SCM get_bar_num (); }; -static void set_property_on_children (Translator_group * trans, const char * sym, SCM val) +static void +set_property_on_children (Context * trans, const char * sym, SCM val) { trans->set_property (sym, val); - for (SCM p = trans -> trans_group_list_; gh_pair_p (p); p = ly_cdr(p)) { - Translator_group *trg = dynamic_cast (unsmob_translator (ly_car (p))); - set_property_on_children(trg,sym,ly_deep_copy(val)); - } + for (SCM p = trans->children_contexts (); ly_c_pair_p (p); p = ly_cdr (p)) + { + Context *trg = unsmob_context (ly_car (p)); + set_property_on_children (trg, sym, ly_deep_copy (val)); + } } Accidental_engraver::Accidental_engraver () @@ -103,101 +91,107 @@ Accidental_engraver::initialize () { last_keysig_ = get_property ("keySignature"); - Translator_group * trans_ = daddy_trans_; + Context * trans_ = context (); while (trans_) { - trans_ -> set_property ("localKeySignature", ly_deep_copy (last_keysig_)); - trans_ = trans_->daddy_trans_; + trans_ -> set_property ("localKeySignature", + ly_deep_copy (last_keysig_)); + trans_ = trans_->get_parent_context (); } - set_property_on_children (daddy_trans_,"localKeySignature", last_keysig_); + set_property_on_children (context (),"localKeySignature", last_keysig_); } /* -calculates the number of accidentals on basis of the current local key sig - (passed as argument) + calculates the number of accidentals on basis of the current local key + sig (passed as argument) + Returns number of accidentals (0, 1 or 2). - Negative (-1 or -2) if accidental has changed. */ static int -number_accidentals (SCM sig, Music * note, Pitch *pitch, SCM curbarnum, SCM lazyness, - bool ignore_octave_b) +number_accidentals_from_sig (bool *different, + SCM sig, Pitch *pitch, SCM curbarnum, SCM lazyness, + bool ignore_octave) { int n = pitch->get_notename (); - int o = pitch->get_octave(); + int o = pitch->get_octave (); int a = pitch->get_alteration (); - int curbarnum_i = gh_scm2int (curbarnum); + int curbarnum_i = ly_scm2int (curbarnum); int accbarnum_i = 0; SCM prev; - if (ignore_octave_b) + if (ignore_octave) prev = ly_assoc_cdr (scm_int2num (n), sig); else - prev = gh_assoc (gh_cons (scm_int2num (o), scm_int2num (n)), sig); + prev = scm_assoc (scm_cons (scm_int2num (o), scm_int2num (n)), sig); /* should really be true unless prev == SCM_BOOL_F */ - if (gh_pair_p (prev) && gh_pair_p (ly_cdr (prev))) + if (ly_c_pair_p (prev) && ly_c_pair_p (ly_cdr (prev))) { - accbarnum_i = gh_scm2int (ly_cddr (prev)); - prev = gh_cons (ly_car (prev), ly_cadr (prev)); + accbarnum_i = ly_scm2int (ly_cddr (prev)); + prev = scm_cons (ly_car (prev), ly_cadr (prev)); } /* If an accidental was not found or the accidental was too old */ if (prev == SCM_BOOL_F || - (gh_number_p (lazyness) && curbarnum_i > accbarnum_i + gh_scm2int (lazyness))) - prev = gh_assoc (scm_int2num (n), sig); + (ly_c_number_p (lazyness) && curbarnum_i > accbarnum_i + ly_scm2int (lazyness))) + prev = scm_assoc (scm_int2num (n), sig); SCM prev_acc = (prev == SCM_BOOL_F) ? scm_int2num (0) : ly_cdr (prev); - int p = gh_number_p (prev_acc) ? gh_scm2int (prev_acc) : 0; + int p = ly_c_number_p (prev_acc) ? ly_scm2int (prev_acc) : 0; int num; - if (a == p && gh_number_p (prev_acc)) + if (a == p && ly_c_number_p (prev_acc)) num = 0; else if ( (abs (a)get_property ("localKeySignature"); bool same_octave_b = - gh_eq_p (ly_symbol2scm ("same-octave"), type); + ly_c_eq_p (ly_symbol2scm ("same-octave"), type); bool any_octave_b = - gh_eq_p (ly_symbol2scm ("any-octave"), type); + ly_c_eq_p (ly_symbol2scm ("any-octave"), type); if (same_octave_b || any_octave_b) { - int n = number_accidentals - (localsig, note, pitch, curbarnum, lazyness, any_octave_b); - diff = diff || (n < 0); - number = max (number, abs (n)); + bool d = false; + int n = number_accidentals_from_sig + (&d, localsig, pitch, curbarnum, lazyness, any_octave_b); + *different = *different || d; + number = max (number, n); } else - warning (_f ("unknown accidental typesetting: %s. Ignored", + warning (_f ("ignoring unknown accidental: %s", ly_symbol2string (type).to_str0 ())); } @@ -205,37 +199,45 @@ number_accidentals (Music * note, Pitch *pitch, Translator_group * origin, /* if symbol then it is a context name. Scan parent contexts to find it. */ - else if (gh_symbol_p (ly_car (accidentals))) + else if (ly_c_symbol_p (rule)) { - String context = ly_symbol2string (ly_car (accidentals)); - - while (origin && !origin->is_alias_b (context)) - origin = origin->daddy_trans_; + Context * dad = origin; + while (dad && !dad->is_alias (rule)) + dad = dad->get_parent_context (); - if (!origin) - warning (_f ("Symbol is not a parent context: %s. Ignored", - context.to_str0 ())); + if (dad) + origin = dad; } - else warning (_f ("Accidental typesetting must be pair or context-name: %s", - ly_scm2string (ly_car (accidentals)).to_str0 ())); - - accidentals = ly_cdr (accidentals); + else warning (_f ("Accidental rule must be pair or context-name; Found %s", + ly_scm2string (rule).to_str0 ())); } - return diff ? -number : number; + + return number; +} + +SCM +Accidental_engraver::get_bar_num () +{ + SCM barnum = get_property ("currentBarNumber"); + SCM smp = get_property ("measurePosition"); + + Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0); + if (mp.main_part_ < Rational (0) + && ly_c_number_p (barnum)) + barnum = scm_int2num (ly_scm2int (barnum) - 1); + + return barnum ; } void Accidental_engraver::process_acknowledged_grobs () { - if (accidentals_.size () && !accidentals_.top().done_) + if (accidentals_.size () && !accidentals_.top ().done_) { - //SCM localsig = get_property ("localKeySignature"); SCM accidentals = get_property ("autoAccidentals"); SCM cautionaries = get_property ("autoCautionaries"); - SCM barnum = get_property ("currentBarNumber"); - SCM smp = get_property("measurePosition"); - Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0); - if(mp.main_part_get_property ("pitch")); + if (!pitch) + continue; - Pitch * pitch = unsmob_pitch (note->get_mus_property ("pitch")); - int num = number_accidentals (note, pitch, origin, accidentals, barnum); - int num_caut = number_accidentals (note, pitch, origin, cautionaries, barnum); - bool cautionary = to_boolean (note->get_mus_property ("cautionary")); + bool different = false; + bool different_caut = false; + + int num = number_accidentals (&different, + pitch, origin, + accidentals, barnum); + int num_caut = number_accidentals (&different_caut, + pitch, origin, + cautionaries, barnum); + + bool cautionary = to_boolean (note->get_property ("cautionary")); - if (abs (num_caut) > abs (num)) + if (num_caut > num) { num = num_caut; + different = different_caut; cautionary = true; } - if(num==0 && to_boolean (note->get_mus_property ("force-accidental"))) - num=1; + if (num == 0 && to_boolean (note->get_property ("force-accidental"))) + num = 1; - bool different = num < 0; - num = abs (num); - - /* see if there's a tie that "changes" the accidental */ - /* works because if there's a tie, the note to the left - is of the same pitch as the actual note */ - - Grob *tie_break_reminder = 0; - bool tie_changes = false; - for (int j = 0; j < ties_.size (); j++) - if (support == Tie::head (ties_[j], RIGHT)) - { - tie_changes = different; - - /* Enable accidentals for broken tie - - We only want an accidental on a broken tie, - if the tie changes the accidental. - - Maybe check property noTieBreakForceAccidental? */ - if (different) - tie_break_reminder = ties_[j]; - break; - } + /* + Can not look for ties: it's not guaranteed that they reach + us before the notes + */ + if (num) { - Grob * a = new Item (get_property ("Accidental")); + /* + We construct the accidentals at the originating Voice + level, so that we get the property settings for + Accidental from the respective Voice. + */ + Grob * a = make_item_from_properties (origin->implementation (), + ly_symbol2scm ("Accidental"), + note->self_scm () + ); a->set_parent (support, Y_AXIS); if (!accidental_placement_) { - accidental_placement_ = new Item (get_property ("AccidentalPlacement")); - announce_grob (accidental_placement_, a->self_scm()); + accidental_placement_ = make_item ("AccidentalPlacement", a->self_scm ()); } Accidental_placement::add_accidental (accidental_placement_, a); - announce_grob (a, SCM_EOL); - SCM accs = gh_cons (scm_int2num (pitch->get_alteration ()), SCM_EOL); + SCM accs = scm_cons (scm_int2num (pitch->get_alteration ()), SCM_EOL); if (num == 2 && extra_natural_b) - accs = gh_cons (scm_int2num (0), accs); + accs = scm_cons (scm_int2num (0), accs); /* TODO: @@ -311,118 +312,123 @@ Accidental_engraver::process_acknowledged_grobs () if (cautionary) { - a->set_grob_property ("cautionary", SCM_BOOL_T); - } - - if (tie_break_reminder) - { - // TODO. - a->set_grob_property ("tie", tie_break_reminder->self_scm()); + a->set_property ("cautionary", SCM_BOOL_T); } - support->set_grob_property ("accidental-grob", a->self_scm ()); + support->set_property ("accidental-grob", a->self_scm ()); - a->set_grob_property ("accidentals", accs); + a->set_property ("accidentals", accs); accidentals_[i].accidental_ = a; - /* - We add the accidentals to the support of the arpeggio, so it is put left of the - accidentals. - - */ + + /* + We add the accidentals to the support of the arpeggio, + so it is put left of the accidentals. + */ for (int i = 0; i < left_objects_.size (); i++) Side_position_interface::add_support (left_objects_[i], a); for (int i = 0; i < right_objects_.size (); i++) Side_position_interface::add_support (a, right_objects_[i]); } - - - /* - We should not record the accidental if it is the first - note and it is tied from the previous measure. - - Checking whether it is tied also works mostly, but will it - always do the correct thing? - */ - - - int n = pitch->get_notename (); - int o = pitch->get_octave (); - int a = pitch->get_alteration (); - SCM on_s = gh_cons (scm_int2num (o), scm_int2num (n)); - - /* - TODO: Speed this up! - - Perhaps only check translators mentioned in the auto-accidentals? - -rz - - TODO: profile this. - - I'd be surprised if the impact of this would be - measurable. Anyway, it seems localsig doesn't change - every time-step, but a set_property() is done every - time. We could save on that, probably. - - --hwn. - - - */ - - while (origin) - { - SCM localsig = origin->get_property ("localKeySignature"); - if (tie_changes) - { - /* - Remember an alteration that is different both from - that of the tied note and of the key signature. - */ - localsig = ly_assoc_front_x - (localsig, on_s, gh_cons (SCM_BOOL_T, barnum)); - } - else - { - /* - not really really correct if there are more than one - noteheads with the same notename. - */ - localsig = ly_assoc_front_x - (localsig, on_s, gh_cons (scm_int2num (a), barnum)); - } - origin->set_property ("localKeySignature", localsig); - origin = origin->daddy_trans_; - } } } } + + + void Accidental_engraver::finalize () { - + last_keysig_ = SCM_EOL; } void Accidental_engraver::stop_translation_timestep () { - for (int i = 0; i < accidentals_.size(); i++) + for (int j = ties_.size (); j --; ) { - Grob *a = accidentals_[i].accidental_; - if (a) + Grob * r = Tie::head (ties_[j], RIGHT); + for (int i = accidentals_.size (); i--;) + if (accidentals_[i].head_ == r) + { + if (Grob * g = accidentals_[i].accidental_) + { + g->set_property ("tie", ties_[j]->self_scm ()); + accidentals_[i].tied_ = true; + } + + ties_.del (j); + break; + } + } + + for (int i = accidentals_.size (); i--;) + { + SCM barnum = get_bar_num (); + + Music * note = accidentals_[i].melodic_; + Context * origin = accidentals_[i].origin_; + + Pitch * pitch = unsmob_pitch (note->get_property ("pitch")); + if (!pitch) + continue; + + int n = pitch->get_notename (); + int o = pitch->get_octave (); + int a = pitch->get_alteration (); + SCM on_s = scm_cons (scm_int2num (o), scm_int2num (n)); + + while (origin) { - typeset_grob (a); + /* + huh? we set props all the way to the top? + */ + SCM localsig = origin->get_property ("localKeySignature"); + bool change = false; + if (accidentals_[i].tied_) + { + /* + Remember an alteration that is different both from + that of the tied note and of the key signature. + */ + localsig = ly_assoc_front_x + (localsig, on_s, scm_cons (SCM_BOOL_T, barnum)); + + change = true; + } + else + { + /* + not really really correct if there are more than one + noteheads with the same notename. + */ + localsig = ly_assoc_front_x + (localsig, on_s, scm_cons (scm_int2num (a), barnum)); + + change = true; + } + + if (change) + origin->set_property ("localKeySignature", localsig); + origin = origin->get_parent_context (); } } + + for (int i = 0; i < accidentals_.size (); i++) + { + if (Grob *a = accidentals_[i].accidental_) + typeset_grob (a); + } if (accidental_placement_) - typeset_grob(accidental_placement_); - accidental_placement_ = 00; + typeset_grob (accidental_placement_); + + accidental_placement_ = 0; - accidentals_.clear(); + accidentals_.clear (); left_objects_.clear (); right_objects_.clear (); - ties_.clear (); } void @@ -431,25 +437,31 @@ Accidental_engraver::acknowledge_grob (Grob_info info) Music * note = info.music_cause (); if (note - && note->is_mus_type("note-event") + && note->is_mus_type ("note-event") && Rhythmic_head::has_interface (info.grob_)) { - Accidental_entry entry ; - entry.head_ = info.grob_; - entry.origin_ = info.origin_trans_->daddy_trans_; - entry.melodic_ = note; + if (to_boolean ( get_property ("harmonicAccidentals")) + || !ly_c_equal_p (info.grob_->get_property ("style"), + ly_symbol2scm ("harmonic"))) + { + + Accidental_entry entry ; + entry.head_ = info.grob_; + entry.origin_ = info.origin_trans_->context (); + entry.melodic_ = note; - accidentals_.push (entry); + accidentals_.push (entry); + } } else if (Tie::has_interface (info.grob_)) { - ties_.push (info.grob_); + ties_.push (dynamic_cast (info.grob_)); } else if (Arpeggio::has_interface (info.grob_)) { left_objects_.push (info.grob_); } - else if (info.grob_->internal_has_interface (ly_symbol2scm("finger-interface"))) + else if (info.grob_->internal_has_interface (ly_symbol2scm ("finger-interface"))) { left_objects_.push (info.grob_); } @@ -465,13 +477,13 @@ Accidental_engraver::process_music () */ if (last_keysig_ != sig) { - Translator_group * trans_ = daddy_trans_; + Context * trans_ = context (); while (trans_) { trans_ -> set_property ("localKeySignature", ly_deep_copy (sig)); - trans_ = trans_->daddy_trans_; + trans_ = trans_->get_parent_context (); } - set_property_on_children(daddy_trans_,"localKeySignature", sig); + set_property_on_children (context (),"localKeySignature", sig); last_keysig_ = sig; } @@ -482,11 +494,14 @@ Accidental_engraver::process_music () ENTER_DESCRIPTION (Accidental_engraver, -"Make accidentals. Catches note heads, ties and notices key-change " -" events. Due to interaction with ties (which don't come together " -" with note heads), this needs to be in a context higher than Tie_engraver.", - "Accidental", -/* accepts */ "", + "Make accidentals. Catches note heads, ties and notices key-change " + "events. This engraver usually lives at Staff level, but " + "reads the settings for Accidental at @code{Voice} level, " + "so you can @code{\\override} them at @code{Voice}. " + , + + "Accidental", + "", "finger-interface rhythmic-head-interface tie-interface arpeggio-interface", - "localKeySignature extraNatural autoAccidentals autoCautionaries", + "localKeySignature harmonicAccidentals extraNatural autoAccidentals autoCautionaries", "localKeySignature");