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"
32 * fix vertical placement of orphaned items
36 class Dynamic_line_spanner : public Spanner
39 Dynamic_line_spanner ();
40 VIRTUAL_COPY_CONS(Score_element);
41 void add_column (Item*);
42 Direction get_default_dir () const;
45 Dynamic_line_spanner::Dynamic_line_spanner ()
47 set_elt_property ("transparent", SCM_BOOL_T);
48 side_position (this).set_axis (Y_AXIS);
52 Dynamic_line_spanner::add_column (Item* n)
54 if (!get_bound (LEFT))
63 Dynamic_line_spanner::get_default_dir () const
69 print text & hairpin dynamics.
71 class Dynamic_engraver : public Engraver
74 Crescendo * finished_cresc_p_;
77 Text_script_req* text_req_l_;
78 Span_req * span_start_req_l_;
79 Drul_array<Span_req*> span_req_l_drul_;
81 Dynamic_line_spanner* line_spanner_;
82 Moment last_request_mom_;
84 Note_column* pending_column_;
85 Link_array<Score_element> pending_element_arr_;
90 VIRTUAL_COPY_CONS(Translator);
94 void announce_element (Score_element_info);
96 virtual void do_removal_processing ();
97 virtual void acknowledge_element (Score_element_info);
98 virtual bool do_try_music (Music *req_l);
99 virtual void do_process_music ();
100 virtual void do_pre_move_processing ();
101 virtual void do_post_move_processing ();
102 virtual void typeset_element (Score_element*);
105 ADD_THIS_TRANSLATOR (Dynamic_engraver);
108 Dynamic_engraver::announce_element (Score_element_info i)
110 group (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
112 Engraver::announce_element (i);
116 Dynamic_engraver::Dynamic_engraver ()
119 finished_cresc_p_ = 0;
121 span_start_req_l_ = 0;
126 span_req_l_drul_[START] = 0;
127 span_req_l_drul_[STOP] = 0;
131 Dynamic_engraver::do_post_move_processing ()
134 span_req_l_drul_[START] = 0;
135 span_req_l_drul_[STOP] = 0;
137 /* ugr; we must attach the Dynamic_line_spanner to something
138 to be sure that the linebreaker will not be confused
140 // if (line_spanner_)
141 // line_spanner_->add_column (LEFT, get_staff_info ().command_pcol_l ());
145 Dynamic_engraver::do_try_music (Music * m)
147 if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
149 if (d->style_str_ == "dynamic")
155 else if (Span_req* s = dynamic_cast <Span_req*> (m))
157 if ((s->span_type_str_ == "crescendo"
158 || s->span_type_str_ == "decrescendo"))
160 span_req_l_drul_[s->span_dir_] = s;
168 Dynamic_engraver::do_process_music ()
170 if ((span_req_l_drul_[START] || text_req_l_)
172 && pending_element_arr_.size ())
174 line_spanner_ = new Dynamic_line_spanner;
175 assert (pending_column_);
176 line_spanner_->add_column (pending_column_);
177 side_position (line_spanner_).set_axis (Y_AXIS);
178 announce_element (Score_element_info
180 text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
184 if (line_spanner_ && pending_element_arr_.size ())
186 for (int i = 0; i < pending_element_arr_.size (); i++)
187 pending_element_arr_[i]->set_parent (line_spanner_, Y_AXIS);
188 pending_element_arr_.clear ();
191 if (span_req_l_drul_[START] || text_req_l_)
192 last_request_mom_ = now_mom ();
194 pending_element_arr_.clear ();
199 String loud = text_req_l_->text_str_;
201 text_p_ = new Text_item;
202 text_p_->set_elt_property ("text",
203 ly_str02scm (loud.ch_C ()));
204 text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
205 text_p_->set_elt_property ("script-priority",
207 pending_element_arr_.push (text_p_);
208 text_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
209 text_p_->dim_cache_[Y_AXIS]->off_callbacks_.push
210 (Side_position_interface::aligned_on_self);
212 Don't crash into staff
216 text_p_->dim_cache_[Y_AXIS]->off_callbacks_.push
217 (Side_position_interface::aligned_side);
219 // doet't ook niet, maar breekt wel alignment op line-spanner
220 //side_position (text_p_).set_axis (Y_AXIS);
222 announce_element (Score_element_info (text_p_, text_req_l_));
225 if (span_req_l_drul_[STOP])
229 span_req_l_drul_[STOP]->warning
230 (_ ("can't find start of (de)crescendo"));
234 assert (!finished_cresc_p_);
235 cresc_p_->set_bound(RIGHT, get_staff_info ().musical_pcol_l ());
236 finished_cresc_p_ = cresc_p_;
238 span_start_req_l_ = 0;
242 if (span_req_l_drul_[START])
244 if (span_start_req_l_)
246 span_req_l_drul_[START]->warning
247 (span_start_req_l_->span_dir_ == 1
249 _ ("already have a crescendo")
250 : _ ("already have a decrescendo"));
254 span_start_req_l_ = span_req_l_drul_[START];
255 cresc_p_ = new Crescendo;
256 cresc_p_->set_elt_property
258 gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
259 ? BIGGER : SMALLER));
261 SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
264 cresc_p_->set_elt_property ("start-text", s);
265 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
266 + "Text", SCM_UNDEFINED);
269 s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
270 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
272 cresc_p_->set_elt_property ("spanner", s);
273 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
274 + "Spanner", SCM_UNDEFINED);
277 cresc_p_->set_bound(LEFT, get_staff_info ().musical_pcol_l ());
281 We know how wide the text is, if we can be sure that the
282 text already has relevant pointers into the paperdef,
283 and it has its font-size property set.
285 Since font-size may be set by a context higher up, we
286 can not be sure of the size.
289 We shouldn't try to do this stuff here, the Item should
290 do it when the score is finished. We could maybe
291 set a callback to have the Item do the alignment if
292 it is not a special symbol, like Crescendo.
298 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
300 if (finished_cresc_p_)
301 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
304 pending_element_arr_.push (cresc_p_);
305 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
306 cresc_p_->dim_cache_[Y_AXIS]->off_callbacks_.push
307 (Side_position_interface::aligned_on_self);
309 Don't crash into staff
313 cresc_p_->dim_cache_[Y_AXIS]->off_callbacks_.push
314 (Side_position_interface::aligned_side);
316 // doet't ook niet, maar breekt wel alignment op line-spanner
317 //side_position (cresc_p_).set_axis (Y_AXIS);
319 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
325 Dynamic_engraver::do_pre_move_processing ()
332 Dynamic_engraver::do_removal_processing ()
336 typeset_element (cresc_p_ );
337 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
343 typeset_element (line_spanner_);
349 Dynamic_engraver::typeset_element (Score_element* e)
351 side_position (e).add_staff_support ();
352 Engraver::typeset_element (e);
356 Dynamic_engraver::typeset_all ()
358 if (finished_cresc_p_)
360 typeset_element (finished_cresc_p_);
361 finished_cresc_p_ =0;
366 typeset_element (text_p_);
371 TODO: This should be optionised:
372 * break when group of dynamic requests ends
374 * continue through piece */
375 if (line_spanner_ && last_request_mom_ < now_mom ())
377 typeset_element (line_spanner_);
383 Dynamic_engraver::acknowledge_element (Score_element_info i)
385 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
389 side_position (line_spanner_).add_support (n);
390 line_spanner_->add_column (n);