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 ();
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 ()
50 set_elt_property ("transparent", SCM_BOOL_T);
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;
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;
266 text_p_->set_elt_property ("text",
267 ly_str02scm (loud.ch_C ()));
268 text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
269 text_p_->set_elt_property ("script-priority",
271 if (Direction d=text_req_l_->get_direction ())
272 directional_element (text_p_).set (d);
273 pending_element_arr_.push (text_p_);
274 text_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
275 text_p_->add_offset_callback (Side_position_interface::aligned_on_self,
277 announce_element (Score_element_info (text_p_, text_req_l_));
280 if (span_req_l_drul_[STOP])
284 span_req_l_drul_[STOP]->warning
285 (_ ("can't find start of (de)crescendo"));
289 assert (!finished_cresc_p_);
290 cresc_p_->set_bound (RIGHT, get_staff_info ().musical_pcol_l ());
291 finished_cresc_p_ = cresc_p_;
293 span_start_req_l_ = 0;
297 if (span_req_l_drul_[START])
299 if (span_start_req_l_)
301 span_req_l_drul_[START]->warning
302 (span_start_req_l_->span_dir_ == 1
304 _ ("already have a crescendo")
305 : _ ("already have a decrescendo"));
309 span_start_req_l_ = span_req_l_drul_[START];
310 cresc_p_ = new Crescendo;
311 cresc_p_->set_elt_property
313 gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
314 ? BIGGER : SMALLER));
316 SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
319 cresc_p_->set_elt_property ("start-text", s);
320 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
321 + "Text", SCM_UNDEFINED);
324 s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
330 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
332 cresc_p_->set_elt_property ("spanner", s);
333 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
334 + "Spanner", SCM_UNDEFINED);
337 cresc_p_->set_bound (LEFT, get_staff_info ().musical_pcol_l ());
341 We know how wide the text is, if we can be sure that the
342 text already has relevant pointers into the paperdef,
343 and it has its font-size property set.
345 Since font-size may be set by a context higher up, we
346 can not be sure of the size.
349 We shouldn't try to do this stuff here, the Item should
350 do it when the score is finished. We could maybe
351 set a callback to have the Item do the alignment if
352 it is not a special symbol, like Crescendo.
358 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
360 if (finished_cresc_p_)
361 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
364 pending_element_arr_.push (cresc_p_);
365 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
366 cresc_p_->add_offset_callback
367 (Side_position_interface::aligned_on_self, Y_AXIS);
368 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
374 Dynamic_engraver::do_pre_move_processing ()
380 Dynamic_engraver::do_removal_processing ()
384 typeset_element (cresc_p_ );
385 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
391 Side_position_interface (line_spanner_).add_staff_support ();
392 typeset_element (line_spanner_);
398 Dynamic_engraver::typeset_all ()
400 if (finished_cresc_p_)
402 typeset_element (finished_cresc_p_);
403 finished_cresc_p_ =0;
408 typeset_element (text_p_);
411 if (finished_line_spanner_)
413 Side_position_interface (finished_line_spanner_).add_staff_support ();
414 typeset_element (finished_line_spanner_);
415 finished_line_spanner_ = 0;
420 Dynamic_engraver::acknowledge_element (Score_element_info i)
422 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
426 Side_position_interface (line_spanner_).add_support (n);
427 line_spanner_->add_column (n);
431 pending_column_arr_.push (n);