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);
211 announce_element (Score_element_info (text_p_, text_req_l_));
214 if (span_req_l_drul_[STOP])
218 span_req_l_drul_[STOP]->warning
219 (_ ("can't find start of (de)crescendo"));
223 assert (!finished_cresc_p_);
224 cresc_p_->set_bound(RIGHT, get_staff_info ().musical_pcol_l ());
225 finished_cresc_p_ = cresc_p_;
227 span_start_req_l_ = 0;
231 if (span_req_l_drul_[START])
233 if (span_start_req_l_)
235 span_req_l_drul_[START]->warning
236 (span_start_req_l_->span_dir_ == 1
238 _ ("already have a crescendo")
239 : _ ("already have a decrescendo"));
243 span_start_req_l_ = span_req_l_drul_[START];
244 cresc_p_ = new Crescendo;
245 cresc_p_->set_elt_property
247 gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
248 ? BIGGER : SMALLER));
250 SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
253 cresc_p_->set_elt_property ("start-text", s);
254 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
255 + "Text", SCM_UNDEFINED);
258 s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
259 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
261 cresc_p_->set_elt_property ("spanner", s);
262 daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
263 + "Spanner", SCM_UNDEFINED);
266 cresc_p_->set_bound(LEFT, get_staff_info ().musical_pcol_l ());
270 We know how wide the text is, if we can be sure that the
271 text already has relevant pointers into the paperdef,
272 and it has its font-size property set.
274 Since font-size may be set by a context higher up, we
275 can not be sure of the size.
278 We shouldn't try to do this stuff here, the Item should
279 do it when the score is finished. We could maybe
280 set a callback to have the Item do the alignment if
281 it is not a special symbol, like Crescendo.
287 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
289 if (finished_cresc_p_)
290 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
293 pending_element_arr_.push (cresc_p_);
294 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
295 cresc_p_->dim_cache_[Y_AXIS]->off_callbacks_.push
296 (Side_position_interface::aligned_on_self);
297 announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
303 Dynamic_engraver::do_pre_move_processing ()
310 Dynamic_engraver::do_removal_processing ()
314 typeset_element (cresc_p_ );
315 span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
321 typeset_element (line_spanner_);
327 Dynamic_engraver::typeset_element (Score_element* e)
329 side_position (e).add_staff_support ();
330 Engraver::typeset_element (e);
334 Dynamic_engraver::typeset_all ()
336 if (finished_cresc_p_)
338 typeset_element (finished_cresc_p_);
339 finished_cresc_p_ =0;
344 typeset_element (text_p_);
349 TODO: This should be optionised:
350 * break when group of dynamic requests ends
352 * continue through piece */
353 if (line_spanner_ && last_request_mom_ < now_mom ())
355 typeset_element (line_spanner_);
361 Dynamic_engraver::acknowledge_element (Score_element_info i)
363 if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
367 side_position (line_spanner_).add_support (n);
368 line_spanner_->add_column (n);