Consider accidentals in optical spacing correction.
[lilypond.git] / lily / ambitus-engraver.cc
blob202e691d21d6515060cad0b0325fecc7af781200
1 /*
2 ambitus-engraver.cc -- implement Ambitus_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2002--2009 Juergen Reuter <reuter@ipd.uka.de>
8 Han-Wen Nienhuys <hanwen@xs4all.nl
9 */
11 #include "engraver.hh"
13 #include "accidental-placement.hh"
14 #include "axis-group-interface.hh"
15 #include "item.hh"
16 #include "note-head.hh"
17 #include "pitch-interval.hh"
18 #include "pointer-group-interface.hh"
19 #include "protected-scm.hh"
20 #include "side-position-interface.hh"
21 #include "separation-item.hh"
22 #include "staff-symbol-referencer.hh"
23 #include "stream-event.hh"
25 #include "translator.icc"
27 class Ambitus_engraver : public Engraver
29 public:
30 TRANSLATOR_DECLARATIONS (Ambitus_engraver);
31 protected:
32 DECLARE_ACKNOWLEDGER (note_head);
34 void process_music ();
35 void stop_translation_timestep ();
36 virtual void finalize ();
37 virtual void derived_mark () const;
39 private:
40 void create_ambitus ();
41 Item *ambitus_;
42 Item *group_;
43 Drul_array<Item *> heads_;
44 Drul_array<Item *> accidentals_;
45 Drul_array<Stream_event *> causes_;
46 Pitch_interval pitch_interval_;
47 bool is_typeset_;
48 int start_c0_;
49 SCM start_key_sig_;
52 void
53 Ambitus_engraver::derived_mark () const
55 scm_gc_mark (start_key_sig_);
58 void
59 Ambitus_engraver::create_ambitus ()
61 ambitus_ = make_item ("AmbitusLine", SCM_EOL);
62 group_ = make_item ("Ambitus", SCM_EOL);
63 Direction d = DOWN;
66 heads_[d] = make_item ("AmbitusNoteHead", SCM_EOL);
67 accidentals_[d] = make_item ("AmbitusAccidental", SCM_EOL);
68 accidentals_[d]->set_parent (heads_[d], Y_AXIS);
69 heads_[d]->set_object ("accidental-grob",
70 accidentals_[d]->self_scm ());
71 Axis_group_interface::add_element (group_, heads_[d]);
72 Axis_group_interface::add_element (group_, accidentals_[d]);
74 while (flip (&d) != DOWN);
76 ambitus_->set_parent (heads_[DOWN], X_AXIS);
77 Axis_group_interface::add_element (group_, ambitus_);
79 is_typeset_ = false;
82 Ambitus_engraver::Ambitus_engraver ()
84 ambitus_ = 0;
85 heads_[LEFT] = heads_[RIGHT] = 0;
86 accidentals_[LEFT] = accidentals_[RIGHT] = 0;
87 group_ = 0;
88 is_typeset_ = false;
89 start_key_sig_ = SCM_EOL;
92 void
93 Ambitus_engraver::process_music ()
96 * Ensure that ambitus is created in the very first timestep
98 if (!ambitus_)
99 create_ambitus ();
102 void
103 Ambitus_engraver::stop_translation_timestep ()
105 if (ambitus_ && !is_typeset_)
108 * Evaluate middleCPosition not until now, since otherwise we
109 * may then oversee a clef that is defined in a staff context if
110 * we are in a voice context; middleCPosition would then be
111 * assumed to be 0.
113 start_c0_ = robust_scm2int (get_property ("middleCPosition"), 0);
114 start_key_sig_ = get_property ("keySignature");
116 is_typeset_ = true;
120 void
121 Ambitus_engraver::acknowledge_note_head (Grob_info info)
123 Stream_event *nr = info.event_cause ();
124 SCM p = nr->get_property ("pitch");
126 If the engraver is added to a percussion context,
127 filter out unpitched note heads.
129 if (!unsmob_pitch (p))
130 return;
131 if (nr && nr->in_event_class ("note-event"))
133 Pitch pitch = *unsmob_pitch (p);
134 Drul_array<bool> expands = pitch_interval_.add_point (pitch);
135 if (expands[UP])
136 causes_[UP] = nr;
137 if (expands[DOWN])
138 causes_[DOWN] = nr;
142 void
143 Ambitus_engraver::finalize ()
145 if (ambitus_ && !pitch_interval_.is_empty ())
147 Grob *accidental_placement =
148 make_item ("AccidentalPlacement",
149 accidentals_[DOWN]->self_scm ());
151 Direction d = DOWN;
154 Pitch p = pitch_interval_[d];
155 heads_[d]->set_property ("cause", causes_[d]->self_scm());
156 heads_[d]->set_property ("staff-position",
157 scm_from_int (start_c0_
158 + p.steps ()));
160 SCM handle = scm_assoc (scm_cons (scm_from_int (p.get_octave ()),
161 scm_from_int (p.get_notename ())),
162 start_key_sig_);
164 if (handle == SCM_BOOL_F)
165 handle = scm_assoc (scm_from_int (p.get_notename ()),
166 start_key_sig_);
168 Rational sig_alter = (handle != SCM_BOOL_F)
169 ? robust_scm2rational (scm_cdr (handle), Rational (0)) : Rational (0);
171 if (sig_alter == p.get_alteration ())
173 accidentals_[d]->suicide ();
174 heads_[d]->set_object ("accidental-grob", SCM_EOL);
176 else
178 accidentals_[d]->set_property ("alteration", ly_rational2scm (p.get_alteration ()));
180 Separation_item::add_conditional_item (heads_[d], accidental_placement);
181 Accidental_placement::add_accidental (accidental_placement, accidentals_[d]);
183 while (flip (&d) != DOWN);
186 Pointer_group_interface::add_grob (ambitus_, ly_symbol2scm ("note-heads"), heads_[DOWN]);
187 Pointer_group_interface::add_grob (ambitus_, ly_symbol2scm ("note-heads"), heads_[UP]);
188 Axis_group_interface::add_element (group_, accidental_placement);
190 else
192 Direction d = DOWN;
195 accidentals_[d]->suicide ();
196 heads_[d]->suicide ();
198 while (flip (&d) != DOWN);
200 ambitus_->suicide ();
204 ADD_ACKNOWLEDGER (Ambitus_engraver, note_head);
205 ADD_TRANSLATOR (Ambitus_engraver,
206 /* doc */
209 /* create */
210 "AccidentalPlacement "
211 "Ambitus "
212 "AmbitusAccidental "
213 "AmbitusLine "
214 "AmbitusNoteHead ",
216 /* read */
219 /* write */