2 dynamic-engraver.cc -- implement Dynamic_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "dimensions.hh"
10 #include "dimension-cache.hh"
11 #include "crescendo.hh"
12 #include "musical-request.hh"
14 #include "paper-def.hh"
15 #include "paper-column.hh"
16 #include "staff-symbol.hh"
17 #include "note-column.hh"
18 #include "text-item.hh"
19 #include "side-position-interface.hh"
20 #include "engraver.hh"
22 #include "note-head.hh"
23 #include "group-interface.hh"
24 #include "directional-element-interface.hh"
25 #include "staff-symbol-referencer.hh"
26 #include "translator-group.hh"
27 #include "axis-group-interface.hh"
33 * direction of text-dynamic-request if not equalt to direction
36 * FIXME: this has gotten a bit too hairy.
39 class Dynamic_line_spanner : public Spanner
42 Dynamic_line_spanner (SCM);
43 VIRTUAL_COPY_CONS(Score_element);
44 void add_column (Note_column*);
45 void add_element (Score_element*);
48 Dynamic_line_spanner::Dynamic_line_spanner (SCM s)
51 Side_position_interface (this).set_axis (Y_AXIS);
52 Axis_group_interface (this).set_interface ();
53 Axis_group_interface (this).set_axes (X_AXIS, Y_AXIS);
57 Dynamic_line_spanner::add_column (Note_column* n)
59 if (!get_bound (LEFT))
69 Dynamic_line_spanner::add_element (Score_element* e)
71 e->set_parent (this, Y_AXIS);
72 Axis_group_interface (this).add_element (e);
76 print text & hairpin dynamics.
78 class Dynamic_engraver : public Engraver
81 Crescendo * finished_cresc_p_;
84 Text_script_req* text_req_l_;
85 Span_req * span_start_req_l_;
86 Drul_array<Span_req*> span_req_l_drul_;
88 Dynamic_line_spanner* line_spanner_;
89 Dynamic_line_spanner* finished_line_spanner_;
90 Moment last_request_mom_;
92 Array<Note_column*> pending_column_arr_;
93 Link_array<Score_element> pending_element_arr_;
98 VIRTUAL_COPY_CONS(Translator);
102 void announce_element (Score_element_info);
104 virtual void do_removal_processing ();
105 virtual void acknowledge_element (Score_element_info);
106 virtual bool do_try_music (Music *req_l);
107 virtual void do_process_music ();
108 virtual void do_pre_move_processing ();
109 virtual void do_post_move_processing ();
112 ADD_THIS_TRANSLATOR (Dynamic_engraver);
115 Dynamic_engraver::announce_element (Score_element_info i)
117 Group_interface (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
119 Engraver::announce_element (i);
123 Dynamic_engraver::Dynamic_engraver ()
126 finished_cresc_p_ = 0;
128 finished_line_spanner_ = 0;
129 span_start_req_l_ = 0;
133 span_req_l_drul_[START] = 0;
134 span_req_l_drul_[STOP] = 0;
138 Dynamic_engraver::do_post_move_processing ()
141 span_req_l_drul_[START] = 0;
142 span_req_l_drul_[STOP] = 0;
146 Dynamic_engraver::do_try_music (Music * m)
148 if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
150 if (d->style_str_ == "dynamic")
156 else if (Span_req* s = dynamic_cast <Span_req*> (m))
158 if ((s->span_type_str_ == "crescendo"
159 || s->span_type_str_ == "decrescendo"))
161 span_req_l_drul_[s->span_dir_] = s;
169 Dynamic_engraver::do_process_music ()
171 if ((span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
173 && pending_element_arr_.size ())
175 line_spanner_ = new Dynamic_line_spanner (get_property ("basicDynamicLineSpannerProperties"));
176 for (int i = 0; i < pending_column_arr_.size (); i++)
177 line_spanner_->add_column (pending_column_arr_[i]);
178 pending_column_arr_.clear ();
179 announce_element (Score_element_info
181 text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
185 if (line_spanner_ && pending_element_arr_.size ())
187 for (int i = 0; i < pending_element_arr_.size (); i++)
188 line_spanner_->add_element (pending_element_arr_[i]);
189 pending_element_arr_.clear ();
193 TODO: This should be optionised:
194 * break when group of dynamic requests ends
195 * break now (only if no cresc. in progress)
196 * continue through piece */
197 if (span_req_l_drul_[START] || span_req_l_drul_[STOP] || text_req_l_)
199 last_request_mom_ = now_mom ();
204 During a (de)crescendo, pending request will not be cleared,
205 and a line-spanner will always be created, as \< \! are already
208 Maybe always creating a line-spanner for a (de)crescendo (see
209 below) is not a good idea:
213 the \p will be centred on the line-spanner, and thus clash
214 with the hairpin. When axis-group code is in place, the \p
215 should move below the hairpin, which is probably better?
217 Urg, but line-spanner must always have at least same duration
218 as (de)crecsendo, b.o. line-breaking.
220 if (now_mom () > last_request_mom_ && !span_start_req_l_)
222 for (int i = 0; i < pending_element_arr_.size (); i++)
224 Score_element* e = pending_element_arr_[i];
225 Side_position_interface (e).set_axis (Y_AXIS);
226 Side_position_interface (e).add_staff_support ();
231 Direction d = directional_element (e).get ();
234 SCM s = get_property ("dynamicDirection");
236 s = get_property ("verticalDirection");
239 directional_element (e).set (d);
242 SCM s = get_property ("dynamicPadding");
244 e->set_elt_property ("padding", s);
245 s = get_property ("dynamicMinimumSpace");
247 e->set_elt_property ("minimum-space", s);
249 pending_element_arr_.clear ();
252 for (int i = 0; i < pending_column_arr_.size (); i++)
253 line_spanner_->add_column (pending_column_arr_[i]);
254 pending_column_arr_.clear ();
255 finished_line_spanner_ = line_spanner_;
263 String loud = text_req_l_->text_str_;
265 text_p_ = new Text_item (get_property ("basicDynamicTextProperties"));
266 text_p_->set_elt_property ("text", ly_str02scm (loud.ch_C ()));
267 if (Direction d=text_req_l_->get_direction ())
268 directional_element (text_p_).set (d);
269 pending_element_arr_.push (text_p_);
271 text_p_->add_offset_callback (Side_position_interface::aligned_on_self,
273 announce_element (Score_element_info (text_p_, text_req_l_));
276 if (span_req_l_drul_[STOP])
280 span_req_l_drul_[STOP]->warning
281 (_ ("can't find start of (de)crescendo"));
285 assert (!finished_cresc_p_);
286 cresc_p_->set_bound (RIGHT, get_staff_info ().musical_pcol_l ());
287 finished_cresc_p_ = cresc_p_;
289 span_start_req_l_ = 0;
293 if (span_req_l_drul_[START])
295 if (span_start_req_l_)
297 span_req_l_drul_[START]->warning
298 (span_start_req_l_->span_dir_ == 1
300 _ ("already have a crescendo")
301 : _ ("already have a decrescendo"));
305 span_start_req_l_ = span_req_l_drul_[START];
306 cresc_p_ = new Crescendo (get_property ("basicCrescendoProperties"));
307 cresc_p_->set_elt_property
309 gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
310 ? BIGGER : SMALLER));
312 SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
315 cresc_p_->set_elt_property ("start-text", s);
316 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
317 + "Text", SCM_UNDEFINED);
320 s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
326 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
328 cresc_p_->set_elt_property ("spanner", s);
329 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
330 + "Spanner", SCM_UNDEFINED);
333 cresc_p_->set_bound (LEFT, get_staff_info ().musical_pcol_l ());
337 We know how wide the text is, if we can be sure that the
338 text already has relevant pointers into the paperdef,
339 and it has its font-size property set.
341 Since font-size may be set by a context higher up, we
342 can not be sure of the size.
345 We shouldn't try to do this stuff here, the Item should
346 do it when the score is finished. We could maybe
347 set a callback to have the Item do the alignment if
348 it is not a special symbol, like Crescendo.
354 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
356 if (finished_cresc_p_)
357 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
360 pending_element_arr_.push (cresc_p_);
361 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
362 cresc_p_->add_offset_callback
363 (Side_position_interface::aligned_on_self, Y_AXIS);
364 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
370 Dynamic_engraver::do_pre_move_processing ()
376 Dynamic_engraver::do_removal_processing ()
380 typeset_element (cresc_p_ );
381 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
387 Side_position_interface (line_spanner_).add_staff_support ();
388 typeset_element (line_spanner_);
394 Dynamic_engraver::typeset_all ()
396 if (finished_cresc_p_)
398 typeset_element (finished_cresc_p_);
399 finished_cresc_p_ =0;
404 typeset_element (text_p_);
407 if (finished_line_spanner_)
409 Side_position_interface (finished_line_spanner_).add_staff_support ();
410 typeset_element (finished_line_spanner_);
411 finished_line_spanner_ = 0;
416 Dynamic_engraver::acknowledge_element (Score_element_info i)
418 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
422 Side_position_interface (line_spanner_).add_support (n);
423 line_spanner_->add_column (n);
427 pending_column_arr_.push (n);