X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Faccidental-engraver.cc;h=0c00497d0918ac726b7b753b373d3ca3b489d2e0;hb=3471866d047b2e22f6d42eedb936d5eddcb5a06a;hp=65b83a1b611ca39563e546f1102286229a61d83e;hpb=c3f1e9e806a3d386f82439130f9593c3537ed08c;p=lilypond.git diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc index 65b83a1b61..0c00497d09 100644 --- a/lily/accidental-engraver.cc +++ b/lily/accidental-engraver.cc @@ -1,67 +1,104 @@ /* accidental-engraver.cc -- implement accidental_engraver - (c) 1997--2001 Han-Wen Nienhuys - Modified 2001 by Rune Zedeler + (c) 1997--2002 Han-Wen Nienhuys + Modified 2001-2002 by Rune Zedeler */ #include "musical-request.hh" #include "command-request.hh" -#include "local-key-item.hh" #include "item.hh" #include "tie.hh" #include "rhythmic-head.hh" -#include "timing-translator.hh" #include "engraver-group-engraver.hh" - -#include "staff-symbol-referencer.hh" +#include "accidental-placement.hh" #include "side-position-interface.hh" #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 +FIXME: should not compute vertical positioning of accidentals, but +get them from the noteheads - The algorithm for accidentals should be documented, and made - tweakable. +The algorithm for accidentals should be documented, and made +tweakable. */ +struct Accidental_entry { + bool done_; + Note_req * melodic_; + Grob * accidental_; + Translator_group *origin_; + Grob* head_; + Accidental_entry(); +}; + +Accidental_entry::Accidental_entry() +{ + done_ = false; + melodic_ =0; + accidental_ = 0; + origin_ = 0; + head_ = 0; +} struct Accidental_engraver : Engraver { - Item *key_item_p_; protected: - TRANSLATOR_DECLARATIONS(Accidental_engraver); + TRANSLATOR_DECLARATIONS (Accidental_engraver); virtual void process_music (); virtual void acknowledge_grob (Grob_info); virtual void stop_translation_timestep (); virtual void initialize (); - virtual void create_grobs (); + virtual void process_acknowledged_grobs (); virtual void finalize (); public: - // todo -> property + /* + 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_; /* Urgh. Since the accidentals depend on lots of variables, we have to store all information before we can really create the accidentals. - */ + */ Link_array arpeggios_; + + Grob * accidental_placement_; + + + /* + The next + */ + Array accidentals_; - Link_array mel_l_arr_; - Link_array support_l_arr_; - Link_array forced_l_arr_; - Link_array tie_l_arr_; + Link_array ties_; + }; + +static void set_property_on_children (Translator_group * 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)); + } +} + Accidental_engraver::Accidental_engraver () { - key_item_p_ =0; + accidental_placement_ = 0; last_keysig_ = SCM_EOL; } @@ -69,116 +106,233 @@ void Accidental_engraver::initialize () { last_keysig_ = get_property ("keySignature"); - daddy_trans_l_->set_property ("localKeySignature", last_keysig_); - daddy_trans_l_->set_property ("lazyKeySignature", last_keysig_); + + Translator_group * trans_ = daddy_trans_; + while (trans_) + { + trans_ -> set_property ("localKeySignature", ly_deep_copy (last_keysig_)); + trans_ = trans_->daddy_trans_; + } + set_property_on_children (daddy_trans_,"localKeySignature", last_keysig_); } -/** 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. - **/ +/* + +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, Note_req * note_l) +number_accidentals (SCM sig, Note_req * note, Pitch *pitch, SCM curbarnum, SCM lazyness, + bool ignore_octave_b) { - Pitch *pitch = unsmob_pitch (note_l->get_mus_property ("pitch")); - int n = pitch->notename_i_; - int o = pitch->octave_i () ; - int a = pitch->alteration_i_; + int n = pitch->notename_; + int o = pitch->octave_; + int a = pitch->alteration_; + int curbarnum_i = gh_scm2int (curbarnum); + int accbarnum_i = 0; + + SCM prev; + if (ignore_octave_b) + prev = ly_assoc_cdr (scm_int2num (n), sig); + else + prev = gh_assoc (gh_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))) + { + accbarnum_i = gh_scm2int (ly_cddr (prev)); + prev = gh_cons (ly_car (prev), ly_cadr (prev)); + } - SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), sig); - if (prev == SCM_BOOL_F) - prev = scm_assoc (gh_int2scm (n), sig); - SCM prev_acc = (prev == SCM_BOOL_F) ? gh_int2scm (0) : ly_cdr (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); + + + SCM prev_acc = (prev == SCM_BOOL_F) ? scm_int2num (0) : ly_cdr (prev); - bool different = !gh_equal_p (prev_acc , gh_int2scm (a)); int p = gh_number_p (prev_acc) ? gh_scm2int (prev_acc) : 0; int num; - if (a==p && !to_boolean (note_l->get_mus_property ("force-accidental"))) num=0; - else if ( (abs(a)get_mus_property ("force-accidental")) + && gh_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); + bool any_octave_b = + gh_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)); + } + else + warning (_f ("unknown accidental typesetting: %s. Ignored", + ly_symbol2string (type).to_str0 ())); + } + + + /* + if symbol then it is a context name. Scan parent contexts to find it. + */ + else if (gh_symbol_p (ly_car (accidentals))) + { + String context = ly_symbol2string (ly_car (accidentals)); + + while (origin && !origin->is_alias_b (context)) + origin = origin->daddy_trans_; + + if (!origin) + warning (_f ("Symbol is not a parent context: %s. Ignored", + context.to_str0 ())); + } + else warning (_f ("Accidental typesetting must be pair or context-name: %s", + ly_scm2string (ly_car (accidentals)).to_str0 ())); + + accidentals = ly_cdr (accidentals); + } + return diff ? -number : number; } void -Accidental_engraver::create_grobs () +Accidental_engraver::process_acknowledged_grobs () { - if (!key_item_p_ && mel_l_arr_.size ()) + if (accidentals_.size () && !accidentals_.top().done_) { - SCM localsig = get_property ("localKeySignature"); - SCM lazysig = get_property ("lazyKeySignature"); + //SCM localsig = get_property ("localKeySignature"); + SCM accidentals = get_property ("autoAccidentals"); + SCM cautionaries = get_property ("autoCautionaries"); + SCM barnum = get_property ("currentBarNumber"); - for (int i=0; i < mel_l_arr_.size (); i++) + bool extra_natural_b = get_property ("extraNatural") == SCM_BOOL_T; + for (int i = 0; i < accidentals_.size (); i++) { - Grob * support_l = support_l_arr_[i]; - Note_req * note_l = mel_l_arr_[i]; - - int local_num = number_accidentals(localsig,note_l); - bool local_diff = local_num<0; local_num = abs(local_num); - int lazy_num = number_accidentals(lazysig,note_l); - bool lazy_diff = lazy_num<0; lazy_num = abs(lazy_num); - - int num = local_num;; - bool different= local_diff; - bool cautionary = to_boolean (note_l->get_mus_property ("cautionary")); - if (to_boolean (get_property ("noResetKey"))) { - num = lazy_num; - different = lazy_diff; - } - else if (gh_equal_p (get_property ("autoReminders"),ly_symbol2scm("cautionary")) - || gh_equal_p (get_property ("autoReminders"),ly_symbol2scm("accidental"))) { - num = max(local_num,lazy_num); - if (gh_equal_p (get_property ("autoReminders"),ly_symbol2scm("cautionary")) - && lazy_num>local_num) + if (accidentals_[i].done_ ) + continue; + accidentals_[i].done_ = true; + Grob * support = accidentals_[i].head_; + Note_req * note = accidentals_[i].melodic_; + Translator_group * origin = accidentals_[i].origin_; + + 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")); + + if (abs (num_caut) > abs (num)) + { + num = num_caut; cautionary = true; - } + } + + 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 i=0; i < tie_l_arr_.size (); i++) - if (support_l == Tie::head (tie_l_arr_[i], RIGHT)) + 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. + We only want an accidental on a broken tie, + if the tie changes the accidental. - Maybe check property noTieBreakForceAccidental? */ + Maybe check property noTieBreakForceAccidental? */ if (different) - tie_break_reminder = tie_l_arr_[i]; + tie_break_reminder = ties_[j]; break; } if (num) { - if (!key_item_p_) + Grob * a = new Item (get_property ("Accidental")); + a->set_parent (support, Y_AXIS); + + if (!accidental_placement_) { - key_item_p_ = new Item (get_property ("Accidentals")); - Local_key_item::set_interface (key_item_p_); - - - Staff_symbol_referencer::set_interface (key_item_p_); - SCM c0 = get_property ("centralCPosition"); - if (gh_number_p (c0)) - Staff_symbol_referencer::set_position (key_item_p_, gh_scm2int (c0)); - - announce_grob (key_item_p_, 0); + accidental_placement_ = new Item (get_property ("AccidentalPlacement")); + announce_grob (accidental_placement_, a->self_scm()); } + + Accidental_placement::add_accidental (accidental_placement_, a); + announce_grob (a, SCM_EOL); - Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")), - cautionary, - num==2, - tie_break_reminder); - Side_position_interface::add_support (key_item_p_,support_l); + SCM accs = gh_cons (scm_int2num (pitch->alteration_), SCM_EOL); + if (num == 2 && extra_natural_b) + accs = gh_cons (scm_int2num (0), accs); + + /* TODO: + + add cautionary option in accidental. + */ + + 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()); + } + + + support->set_grob_property ("accidental-grob", a->self_scm ()); + + a->set_grob_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. + + */ + for (int i = 0; i < arpeggios_.size (); i++) + Side_position_interface::add_support (arpeggios_[i], a); } @@ -188,53 +342,57 @@ Accidental_engraver::create_grobs () Checking whether it is tied also works mostly, but will it always do the correct thing? - (???? -Rune ) - */ + */ - Pitch *pitch = unsmob_pitch (note_l->get_mus_property ("pitch")); - int n = pitch->notename_i_; - int o = pitch->octave_i () ; - int a = pitch->alteration_i_; - SCM on = gh_cons (gh_int2scm (o), gh_int2scm (n)); - bool forget = to_boolean (get_property ("forgetAccidentals")); - if (tie_changes) - { - /* - Remember an alteration that is different both from - that of the tied note and of the key signature. - */ - localsig = scm_assoc_set_x (localsig, on, SCM_BOOL_T); - lazysig = scm_assoc_set_x (lazysig, on, SCM_BOOL_T); - } - else if (!forget) - { - /* - not really really correct if there are more than one - noteheads with the same notename. - */ - localsig = scm_assoc_set_x (localsig, on, gh_int2scm (a)); - lazysig = scm_assoc_set_x (lazysig, on, gh_int2scm (a)); - } - } - - daddy_trans_l_->set_property ("localKeySignature", localsig); - daddy_trans_l_->set_property ("lazyKeySignature", lazysig); - } - - if (key_item_p_) - { - /* - Hmm. Which one has to be on the left? - - On which left, code or paper? + int n = pitch->notename_; + int o = pitch->octave_; + int a = pitch->alteration_; + SCM on_s = gh_cons (scm_int2num (o), scm_int2num (n)); - (Arpeggios are engraved left of accidentals, of course.) - */ - for (int i=0; i < arpeggios_.size (); i++) - Side_position_interface::add_support (arpeggios_[i], key_item_p_); - - arpeggios_.clear (); + /* + 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_; + } + } } } @@ -247,79 +405,81 @@ Accidental_engraver::finalize () void Accidental_engraver::stop_translation_timestep () { - if (key_item_p_) + for (int i = 0; i < accidentals_.size(); i++) { - for (int i=0; i < support_l_arr_.size (); i++) - Side_position_interface::add_support (key_item_p_,support_l_arr_[i]); - - typeset_grob (key_item_p_); - key_item_p_ =0; + Grob *a = accidentals_[i].accidental_; + if (a) + { + typeset_grob (a); + } } - - mel_l_arr_.clear (); + if (accidental_placement_) + typeset_grob(accidental_placement_); + accidental_placement_ = 00; + + accidentals_.clear(); arpeggios_.clear (); - tie_l_arr_.clear (); - support_l_arr_.clear (); - forced_l_arr_.clear (); + ties_.clear (); } void Accidental_engraver::acknowledge_grob (Grob_info info) { - Note_req * note_l = dynamic_cast (info.music_cause ()); + Note_req * note = dynamic_cast (info.music_cause ()); - if (note_l && Rhythmic_head::has_interface (info.grob_l_)) + if (note && Rhythmic_head::has_interface (info.grob_)) { - mel_l_arr_.push (note_l); - support_l_arr_.push (info.grob_l_); + Accidental_entry entry ; + entry.head_ = info.grob_; + entry.origin_ = info.origin_trans_->daddy_trans_; + entry.melodic_ = note; + + accidentals_.push (entry); } - else if (Tie::has_interface (info.grob_l_)) + else if (Tie::has_interface (info.grob_)) { - tie_l_arr_.push (info.grob_l_); + ties_.push (info.grob_); } - else if (Arpeggio::has_interface (info.grob_l_)) + else if (Arpeggio::has_interface (info.grob_)) { - arpeggios_.push (info.grob_l_); + arpeggios_.push (info.grob_); } } -/* - ugh. repeated deep_copy generates lots of garbage. - */ void Accidental_engraver::process_music () { - SCM smp = get_property ("measurePosition"); - Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0); - SCM sig = get_property ("keySignature"); - /* - Detect key sig changes. If we haven't found any, check if at start - of measure, and set localKeySignature anyhow. */ - if (last_keysig_ != sig) + /* Detect key sig changes. + Update all parents and children + */ + if (last_keysig_ != sig) { - daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig)); - daddy_trans_l_->set_property ("lazyKeySignature", ly_deep_copy (sig)); + Translator_group * trans_ = daddy_trans_; + while (trans_) + { + trans_ -> set_property ("localKeySignature", ly_deep_copy (sig)); + trans_ = trans_->daddy_trans_; + } + set_property_on_children(daddy_trans_,"localKeySignature", sig); + last_keysig_ = sig; } - else if (!mp.to_bool () ) - { - daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig)); - } } -ENTER_DESCRIPTION(Accidental_engraver, -/* descr */ "Make accidentals. Catches note heads, ties and notices key-change +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. FIXME", -/* creats*/ "Accidentals", -/* acks */ "rhythmic-head-interface tie-interface arpeggio-interface", -/* reads */ "localKeySignature forgetAccidentals noResetKey autoReminders", -/* write */ ""); +with note heads), this needs to be in a context higher than Tie_engraver.", + + "Accidental", + "rhythmic-head-interface tie-interface arpeggio-interface", + "localKeySignature extraNatural autoAccidentals autoCautionaries", + "localKeySignature");