2 a2-engraver.cc -- implement A2_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2002 Jan Nieuwenhuizen <janneke@gnu.org>
11 #include "note-head.hh"
14 #include "translator-group.hh"
15 #include "side-position-interface.hh"
16 #include "directional-element-interface.hh"
17 #include "multi-measure-rest.hh"
20 class A2_engraver : public Engraver
22 TRANSLATOR_DECLARATIONS(A2_engraver);
25 virtual void acknowledge_grob (Grob_info);
26 virtual void process_acknowledged_grobs ();
27 virtual void stop_translation_timestep ();
30 enum State { SOLO, SPLIT_INTERVAL, UNIRHYTHM, UNISILENCE, UNISON } state_;
35 A2_engraver::A2_engraver ()
42 A2_engraver::process_acknowledged_grobs ()
44 if (!to_boolean (get_property ("combineParts")))
48 SCM unison = get_property ("unison");
49 SCM solo = get_property ("solo");
50 SCM solo_adue = get_property ("soloADue");
52 if (solo_adue == SCM_BOOL_T
53 && ((solo == SCM_BOOL_T && state_ != SOLO)
54 || (unison == SCM_BOOL_T && state_ != UNISON
55 && daddy_trans_->id_string_.left_string (3) == "one")))
57 text_ = new Item (get_property ("TextScript"));
58 Side_position_interface::set_axis (text_, Y_AXIS);
59 announce_grob(text_, SCM_EOL);
63 if (solo == SCM_BOOL_T)
66 if (daddy_trans_->id_string_.left_string (3) == "one")
68 text = get_property ("soloText");
72 text = get_property ("soloIIText");
76 else if (unison == SCM_BOOL_T)
79 if (daddy_trans_->id_string_.left_string (3) == "one")
80 text = get_property ("aDueText");
83 Side_position_interface::set_direction (text_, dir);
84 text_->set_grob_property ("text", text);
90 A2_engraver::acknowledge_grob (Grob_info i)
92 if (!to_boolean (get_property ("combineParts")))
97 if (Note_head::has_interface (i.grob_))
100 Side_position_interface::add_support (t, i.grob_);
101 if (Side_position_interface::get_axis (t) == X_AXIS
102 && !t->get_parent (Y_AXIS))
103 t->set_parent (i.grob_, Y_AXIS);
105 if (Stem::has_interface (i.grob_))
107 Side_position_interface::add_support (text_, i.grob_);
111 SCM unisilence = get_property ("unisilence");
112 SCM unison = get_property ("unison");
113 SCM unirhythm = get_property ("unirhythm");
114 SCM solo = get_property ("solo");
115 SCM split_interval = get_property ("split-interval");
116 SCM solo_adue = get_property ("soloADue");
118 State previous_state = state_;
119 if (unisilence == SCM_BOOL_T)
124 else if (solo == SCM_BOOL_T)
126 else if (unison == SCM_BOOL_T)
128 else if (unirhythm == SCM_BOOL_T && split_interval == SCM_BOOL_T)
129 state_ = SPLIT_INTERVAL;
133 Direction d = CENTER;
134 if (daddy_trans_->id_string_.left_string (3) == "one")
136 else if (daddy_trans_->id_string_.left_string (3) == "two")
139 /* Must only set direction for VoiceCombines, not for StaffCombines:
140 we can't detect that here, so we use yet another property */
141 if (!to_boolean (get_property ("noDirection"))
142 && (Stem::has_interface (i.grob_)
143 || Slur::has_interface (i.grob_)
144 || Tie::has_interface (i.grob_)
145 /* Usually, dynamics are removed by *_devnull_engravers for
146 the second voice. On the one hand, we don't want all
147 dynamics for the first voice to be placed above the
148 staff. On the other hand, colliding of scripts may be
149 worse. So, we don't set directions for these when we're
151 || (i.grob_->internal_has_interface (ly_symbol2scm
152 ("dynamic-interface"))
154 || (i.grob_->internal_has_interface (ly_symbol2scm
159 /* When in solo a due mode, and we have solo, every grob in
160 other thread gets annihilated, so we don't set dir.
162 Maybe that should be optional? */
163 if ((solo != SCM_BOOL_T && solo_adue == SCM_BOOL_T)
165 /* When not same rhythm, we set dir */
166 && (unirhythm != SCM_BOOL_T
167 /* When both have rests, but previously played something
168 different, we set dir */
169 || ((unisilence == SCM_BOOL_T && previous_state != UNISON))
170 /* When same rhythm, and split stems, but not same pitch
171 or not solo a du mode, we set dir */
172 || (unirhythm == SCM_BOOL_T && split_interval == SCM_BOOL_T
173 && (unison != SCM_BOOL_T || solo_adue != SCM_BOOL_T))))
176 /* Blunt axe method: every grob gets a propertysetting. */
177 i.grob_->set_grob_property ("direction", scm_int2num (d));
181 /* Should we have separate state variable for being "rest
182 while other has solo?" */
183 if (Multi_measure_rest::has_interface (i.grob_) && d)
184 if (state_ == UNIRHYTHM
185 && unisilence != SCM_BOOL_T)
187 i.grob_->set_grob_property ("staff-position", scm_int2num (d * 6));
192 A2_engraver::stop_translation_timestep ()
196 Side_position_interface::add_staff_support (text_);
197 typeset_grob (text_);
202 ENTER_DESCRIPTION(A2_engraver,
203 /* descr */ "Part combine engraver for orchestral scores. \
205 The markings @emph{a2}, @emph{Solo} and @emph{Solo II}, are \
206 created by this engraver. It also acts upon instructions of the part \
207 combiner. Another thing that the this engraver, is forcing of stem, \
208 slur and tie directions, always when both threads are not identical; \
209 up for the musicexpr called @code{one}, down for the musicexpr called \
213 /* creats*/ "TextScript",
215 /* acks */ "multi-measure-rest-interface
216 slur-interface stem-interface tie-interface note-head-interface dynamic-interface text-interface"
217 ,/* reads */ "combineParts noDirection soloADue soloText soloIIText aDueText split-interval unison solo unisilence unirhythm",