lilypond-1.3.72
[lilypond.git] / lily / dynamic-engraver.cc
blobf0390d479853df753d537b69ad890d2f99005158
1 /*
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>
7 */
8 #include "debug.hh"
9 #include "dimensions.hh"
10 #include "crescendo.hh"
11 #include "musical-request.hh"
12 #include "paper-column.hh"
13 #include "note-column.hh"
14 #include "item.hh"
15 #include "side-position-interface.hh"
16 #include "engraver.hh"
17 #include "group-interface.hh"
18 #include "directional-element-interface.hh"
19 #include "translator-group.hh"
20 #include "axis-group-interface.hh"
24 TODO:
26 * direction of text-dynamic-request if not equal to direction of
27 line-spanner
30 /**
31 print text & hairpin dynamics.
33 class Dynamic_engraver : public Engraver
35 Item * text_p_;
36 Spanner * finished_cresc_p_;
37 Spanner * cresc_p_;
39 Text_script_req* text_req_l_;
41 Span_req * current_cresc_req_;
42 Drul_array<Span_req*> accepted_spanreqs_drul_;
44 Spanner* line_spanner_;
45 Spanner* finished_line_spanner_;
47 Link_array<Note_column> pending_column_arr_;
48 Link_array<Score_element> pending_element_arr_;
50 void typeset_all ();
52 public:
53 VIRTUAL_COPY_CONS(Translator);
54 Dynamic_engraver ();
56 protected:
57 virtual void do_removal_processing ();
58 virtual void acknowledge_element (Score_element_info);
59 virtual bool do_try_music (Music *req_l);
60 virtual void do_process_music ();
61 virtual void do_pre_move_processing ();
62 virtual void do_post_move_processing ();
65 ADD_THIS_TRANSLATOR (Dynamic_engraver);
68 Dynamic_engraver::Dynamic_engraver ()
70 text_p_ = 0;
71 finished_cresc_p_ = 0;
72 line_spanner_ = 0;
73 finished_line_spanner_ = 0;
74 current_cresc_req_ = 0;
75 cresc_p_ =0;
77 text_req_l_ = 0;
78 accepted_spanreqs_drul_[START] = 0;
79 accepted_spanreqs_drul_[STOP] = 0;
82 void
83 Dynamic_engraver::do_post_move_processing ()
85 text_req_l_ = 0;
86 accepted_spanreqs_drul_[START] = 0;
87 accepted_spanreqs_drul_[STOP] = 0;
90 bool
91 Dynamic_engraver::do_try_music (Music * m)
93 if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
95 if (d->style_str_ == "dynamic")
97 text_req_l_ = d;
98 return true;
101 else if (Span_req* s = dynamic_cast <Span_req*> (m))
103 if ((s->span_type_str_ == "crescendo"
104 || s->span_type_str_ == "decrescendo"))
106 accepted_spanreqs_drul_[s->span_dir_] = s;
107 return true;
110 return false;
113 void
114 Dynamic_engraver::do_process_music ()
116 if (accepted_spanreqs_drul_[START] || accepted_spanreqs_drul_[STOP] || text_req_l_)
119 if (!line_spanner_)
121 line_spanner_ = new Spanner (get_property ("basicDynamicLineSpannerProperties"));
123 Side_position::set_axis (line_spanner_, Y_AXIS);
124 Axis_group_interface::set_interface (line_spanner_);
125 Axis_group_interface::set_axes (line_spanner_, Y_AXIS, Y_AXIS);
126 announce_element (Score_element_info
127 (line_spanner_,
128 text_req_l_ ? text_req_l_ : accepted_spanreqs_drul_[START]));
134 TODO: should finish and create new spanner if vertical dyn-direction is changed.
136 else if (!accepted_spanreqs_drul_[START] && !text_req_l_)
138 finished_line_spanner_ = line_spanner_;
139 line_spanner_ = 0;
143 todo: resurrect dynamic{direction, padding,minimumspace}
146 During a (de)crescendo, pending request will not be cleared,
147 and a line-spanner will always be created, as \< \! are already
148 two requests.
150 Maybe always creating a line-spanner for a (de)crescendo (see
151 below) is not a good idea:
153 a\< b\p \!c
155 the \p will be centred on the line-spanner, and thus clash
156 with the hairpin. When axis-group code is in place, the \p
157 should move below the hairpin, which is probably better?
159 Urg, but line-spanner must always have at least same duration
160 as (de)crecsendo, b.o. line-breaking.
164 if (text_req_l_)
166 String loud = text_req_l_->text_str_;
168 text_p_ = new Item (get_property ("basicDynamicTextProperties"));
169 text_p_->set_elt_property ("text", ly_str02scm (loud.ch_C ()));
170 if (Direction d=text_req_l_->get_direction ())
171 Directional_element_interface (line_spanner_).set (d);
173 Axis_group_interface::add_element (line_spanner_, text_p_);
175 text_p_->add_offset_callback (Side_position::aligned_on_self,
176 Y_AXIS);
177 announce_element (Score_element_info (text_p_, text_req_l_));
180 if (accepted_spanreqs_drul_[STOP])
182 if (!cresc_p_)
184 accepted_spanreqs_drul_[STOP]->warning
185 (_ ("can't find start of (de)crescendo"));
187 else
189 assert (!finished_cresc_p_);
190 cresc_p_->set_bound (RIGHT, unsmob_element (get_property ("currentMusicalColumn")));
191 finished_cresc_p_ = cresc_p_;
192 cresc_p_ = 0;
193 current_cresc_req_ = 0;
197 if (accepted_spanreqs_drul_[START])
199 if (current_cresc_req_)
201 accepted_spanreqs_drul_[START]->warning
202 (current_cresc_req_->span_dir_ == 1
204 _ ("already have a crescendo")
205 : _ ("already have a decrescendo"));
207 else
209 current_cresc_req_ = accepted_spanreqs_drul_[START];
210 cresc_p_ = new Spanner (get_property ("basicCrescendoProperties"));
211 Crescendo::set_interface (cresc_p_);
212 cresc_p_->set_elt_property
213 ("grow-direction",
214 gh_int2scm ((accepted_spanreqs_drul_[START]->span_type_str_ == "crescendo")
215 ? BIGGER : SMALLER));
217 SCM s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Text").ch_C());
218 if (gh_string_p (s))
220 cresc_p_->set_elt_property ("start-text", s);
221 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
222 + "Text", SCM_UNDEFINED);
225 s = get_property ((accepted_spanreqs_drul_[START]->span_type_str_ + "Spanner").ch_C());
229 TODO: Use symbols.
231 if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
233 cresc_p_->set_elt_property ("spanner", s);
234 daddy_trans_l_->set_property (accepted_spanreqs_drul_[START]->span_type_str_
235 + "Spanner", SCM_UNDEFINED);
238 cresc_p_->set_bound (LEFT, unsmob_element (get_property ("currentMusicalColumn")));
242 We know how wide the text is, if we can be sure that the
243 text already has relevant pointers into the paperdef,
244 and it has its font-size property set.
246 Since font-size may be set by a context higher up, we
247 can not be sure of the size.
250 We shouldn't try to do this stuff here, the Item should
251 do it when the score is finished. We could maybe
252 set a callback to have the Item do the alignment if
253 it is not a special symbol, like Crescendo.
257 if (text_p_)
259 index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
260 LEFT, text_p_->self_scm_);
261 if (finished_cresc_p_)
262 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
263 RIGHT, text_p_->self_scm_);
266 Axis_group_interface::add_element (line_spanner_, cresc_p_);
267 cresc_p_->set_elt_property ("self-alignment-Y", gh_int2scm (0));
268 cresc_p_->add_offset_callback
269 (Side_position::aligned_on_self, Y_AXIS);
270 announce_element (Score_element_info (cresc_p_, accepted_spanreqs_drul_[START]));
275 void
276 Dynamic_engraver::do_pre_move_processing ()
278 typeset_all ();
281 void
282 Dynamic_engraver::do_removal_processing ()
284 typeset_all ();
286 if (cresc_p_)
288 typeset_element (cresc_p_ );
289 finished_cresc_p_ = cresc_p_;
290 current_cresc_req_->warning (_ ("unterminated (de)crescendo"));
292 if (line_spanner_)
294 finished_line_spanner_ = line_spanner_;
296 typeset_all ();
299 void
300 Dynamic_engraver::typeset_all ()
302 if (finished_cresc_p_)
304 typeset_element (finished_cresc_p_);
305 finished_cresc_p_ =0;
308 if (text_p_)
310 typeset_element (text_p_);
311 text_p_ = 0;
313 if (finished_line_spanner_)
315 Side_position::add_staff_support (finished_line_spanner_);
317 if (!finished_line_spanner_->get_bound (LEFT))
319 Score_element * cmc
320 = unsmob_element (get_property ("currentMusicalColumn"));
321 finished_line_spanner_->set_bound (LEFT, cmc);
323 if (!finished_line_spanner_->get_bound (RIGHT))
324 finished_line_spanner_->set_bound (RIGHT,
325 finished_line_spanner_->get_bound (LEFT));
328 typeset_element (finished_line_spanner_);
329 finished_line_spanner_ = 0;
333 void
334 Dynamic_engraver::acknowledge_element (Score_element_info i)
336 if (Note_column::has_interface (i.elem_l_))
338 if (line_spanner_)
340 Side_position::add_support (line_spanner_,i.elem_l_);
341 add_bound_item (line_spanner_,dynamic_cast<Item*>(i.elem_l_));