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 (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 (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 (e).set_axis (Y_AXIS);
226 side_position (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");
325 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
327 cresc_p_->set_elt_property ("spanner", s);
328 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
329 + "Spanner", SCM_UNDEFINED);
332 cresc_p_->set_bound (LEFT, get_staff_info ().musical_pcol_l ());
336 We know how wide the text is, if we can be sure that the
337 text already has relevant pointers into the paperdef,
338 and it has its font-size property set.
340 Since font-size may be set by a context higher up, we
341 can not be sure of the size.
344 We shouldn't try to do this stuff here, the Item should
345 do it when the score is finished. We could maybe
346 set a callback to have the Item do the alignment if
347 it is not a special symbol, like Crescendo.
353 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
355 if (finished_cresc_p_)
356 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
359 pending_element_arr_.push (cresc_p_);
360 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
361 cresc_p_->add_offset_callback
362 (Side_position_interface::aligned_on_self, Y_AXIS);
363 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
369 Dynamic_engraver::do_pre_move_processing ()
375 Dynamic_engraver::do_removal_processing ()
379 typeset_element (cresc_p_ );
380 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
386 side_position (line_spanner_).add_staff_support ();
387 typeset_element (line_spanner_);
393 Dynamic_engraver::typeset_all ()
395 if (finished_cresc_p_)
397 typeset_element (finished_cresc_p_);
398 finished_cresc_p_ =0;
403 typeset_element (text_p_);
406 if (finished_line_spanner_)
408 side_position (finished_line_spanner_).add_staff_support ();
409 typeset_element (finished_line_spanner_);
410 finished_line_spanner_ = 0;
415 Dynamic_engraver::acknowledge_element (Score_element_info i)
417 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
421 side_position (line_spanner_).add_support (n);
422 line_spanner_->add_column (n);
426 pending_column_arr_.push (n);