2 local-key-engraver.cc -- implement Local_key_engraver
4 (c) 1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 #include "musical-request.hh"
8 #include "command-request.hh"
9 #include "local-key-item.hh"
12 #include "rhythmic-head.hh"
13 #include "timing-translator.hh"
14 #include "engraver-group-engraver.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "side-position-interface.hh"
18 #include "engraver.hh"
19 #include "arpeggio.hh"
24 FIXME: should not compute vertical positioning of accidentals, but
25 get them from the noteheads
27 The algorithm for accidentals should be documented, and made
33 struct Local_key_engraver : Engraver {
36 TRANSLATOR_DECLARATIONS(Local_key_engraver);
37 virtual void process_music ();
38 virtual void acknowledge_grob (Grob_info);
39 virtual void stop_translation_timestep ();
40 virtual void initialize ();
41 virtual void create_grobs ();
42 virtual void finalize ();
49 Urgh. Since the accidentals depend on lots of variables, we have to
50 store all information before we can really create the accidentals.
52 Link_array<Grob> arpeggios_;
54 Link_array<Note_req> mel_l_arr_;
55 Link_array<Grob> support_l_arr_;
56 Link_array<Item> forced_l_arr_;
57 Link_array<Grob> tie_l_arr_;
61 Local_key_engraver::Local_key_engraver ()
64 last_keysig_ = SCM_EOL;
68 Local_key_engraver::initialize ()
70 last_keysig_ = get_property ("keySignature");
71 daddy_trans_l_->set_property ("localKeySignature", last_keysig_);
75 Local_key_engraver::create_grobs ()
77 if (!key_item_p_ && mel_l_arr_.size ())
79 SCM localsig = get_property ("localKeySignature");
81 for (int i=0; i < mel_l_arr_.size (); i++)
83 Grob * support_l = support_l_arr_[i];
84 Note_req * note_l = mel_l_arr_[i];
86 int n = unsmob_pitch (note_l->get_mus_property ("pitch"))->notename_i_;
87 int o = unsmob_pitch (note_l->get_mus_property ("pitch"))->octave_i () ;
88 int a = unsmob_pitch (note_l->get_mus_property ("pitch"))->alteration_i_;
90 /* see if there's a tie that "changes" the accidental */
91 /* works because if there's a tie, the note to the left
92 is of the same pitch as the actual note */
94 SCM prev = scm_assoc (gh_cons (gh_int2scm (o), gh_int2scm (n)), localsig);
95 if (prev == SCM_BOOL_F)
96 prev = scm_assoc (gh_int2scm (n), localsig);
97 SCM prev_acc = (prev == SCM_BOOL_F) ? gh_int2scm (0) : ly_cdr (prev);
98 bool different = !gh_equal_p (prev_acc , gh_int2scm (a));
99 int p = gh_number_p (prev_acc) ? gh_scm2int (prev_acc) : 0;
101 Grob *tie_break_reminder = 0;
102 bool tie_changes = false;
103 for (int i=0; i < tie_l_arr_.size (); i++)
104 if (support_l == Tie::head (tie_l_arr_[i], RIGHT))
106 tie_changes = different;
107 /* Enable accidentals for broken tie
109 We only want an accidental on a broken tie,
110 if the tie changes the accidental.
112 Maybe check property noTieBreakForceAccidental? */
114 tie_break_reminder = tie_l_arr_[i];
118 /* When do we want accidentals:
120 1. when property force-accidental is set, and not
122 2. when different and not tie-changes
123 3. maybe when at end of a tie: we must later see if
124 we're after a line break */
125 if (( (to_boolean (note_l->get_mus_property ("force-accidental"))
128 || tie_break_reminder)
132 key_item_p_ = new Item (get_property ("Accidentals"));
133 Local_key_item::set_interface (key_item_p_);
136 Staff_symbol_referencer::set_interface (key_item_p_);
137 SCM c0 = get_property ("centralCPosition");
138 if (gh_number_p (c0))
139 Staff_symbol_referencer::set_position (key_item_p_, gh_scm2int (c0));
141 announce_grob (key_item_p_, 0);
146 sign (p) * (p - a) == 1
149 Local_key_item::add_pitch (key_item_p_, *unsmob_pitch (note_l->get_mus_property ("pitch")),
150 to_boolean (note_l->get_mus_property ("cautionary")),
153 Side_position_interface::add_support (key_item_p_,support_l);
157 We should not record the accidental if it is the first
158 note and it is tied from the previous measure.
160 Checking whether it is tied also works mostly, but will it
161 always do the correct thing?
164 bool forget = to_boolean (get_property ("forgetAccidentals"));
168 Remember an alteration that is different both from
169 that of the tied note and of the key signature.
172 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
180 not really really correct if there are more than one
181 noteheads with the same notename.
183 localsig = scm_assoc_set_x (localsig, gh_cons (gh_int2scm (o),
193 daddy_trans_l_->set_property ("localKeySignature", localsig);
200 Hmm. Which one has to be on the left?
202 On which left, code or paper?
204 (Arpeggios are engraved left of accidentals, of course.)
206 for (int i=0; i < arpeggios_.size (); i++)
207 Side_position_interface::add_support (arpeggios_[i], key_item_p_);
214 Local_key_engraver::finalize ()
220 Local_key_engraver::stop_translation_timestep ()
224 for (int i=0; i < support_l_arr_.size (); i++)
225 Side_position_interface::add_support (key_item_p_,support_l_arr_[i]);
227 typeset_grob (key_item_p_);
235 support_l_arr_.clear ();
236 forced_l_arr_.clear ();
240 Local_key_engraver::acknowledge_grob (Grob_info info)
242 Note_req * note_l = dynamic_cast <Note_req *> (info.req_l_);
244 if (note_l && Rhythmic_head::has_interface (info.grob_l_))
246 mel_l_arr_.push (note_l);
247 support_l_arr_.push (info.grob_l_);
249 else if (Tie::has_interface (info.grob_l_))
251 tie_l_arr_.push (info.grob_l_);
253 else if (Arpeggio::has_interface (info.grob_l_))
255 arpeggios_.push (info.grob_l_);
261 ugh. repeated deep_copy generates lots of garbage.
264 Local_key_engraver::process_music ()
266 SCM smp = get_property ("measurePosition");
267 Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
269 SCM sig = get_property ("keySignature");
272 Detect key sig changes. If we haven't found any, check if at start
273 of measure, and set localKeySignature anyhow. */
274 if (last_keysig_ != sig)
276 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
279 else if (!mp.to_bool () )
281 if (!to_boolean (get_property ("noResetKey")))
282 daddy_trans_l_->set_property ("localKeySignature", ly_deep_copy (sig));
290 ENTER_DESCRIPTION(Local_key_engraver,
291 /* descr */ "Make accidentals. Catches note heads, ties and notices key-change
292 events. Due to interaction with ties (which don't come together
293 with note heads), this needs to be in a context higher than Tie_engraver. FIXME",
294 /* creats*/ "Accidentals",
295 /* acks */ "rhythmic-head-interface tie-interface arpeggio-interface",
296 /* reads */ "localKeySignature forgetAccidentals noResetKey",