]> git.donarmstrong.com Git - lilypond.git/blob - lily/dynamic-engraver.cc
patch::: 1.3.32.jcn1
[lilypond.git] / lily / dynamic-engraver.cc
1 /*
2   dynamic-engraver.cc -- implement Dynamic_engraver
3
4   source file of the GNU LilyPond music typesetter
5
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 "lookup.hh"
13 #include "paper-def.hh"
14 #include "paper-column.hh"
15 #include "staff-symbol.hh"
16 #include "note-column.hh"
17 #include "text-item.hh"
18 #include "side-position-interface.hh"
19 #include "engraver.hh"
20 #include "stem.hh"
21 #include "note-head.hh"
22 #include "group-interface.hh"
23 #include "directional-element-interface.hh"
24 #include "staff-symbol-referencer.hh"
25 #include "translator-group.hh"
26
27 class Dynamic_line_spanner : public Spanner
28 {
29 public:
30   Dynamic_line_spanner ();
31   
32   void add_column (Note_column*);
33   Direction get_default_dir () const;
34 protected:
35   virtual void do_post_processing ();
36 };
37
38 Dynamic_line_spanner::Dynamic_line_spanner ()
39 {
40   set_elt_property ("transparent", SCM_BOOL_T);
41   side_position (this).set_axis (Y_AXIS);
42 }
43
44 void
45 Dynamic_line_spanner::add_column (Note_column* n)
46 {
47   if (!spanned_drul_[LEFT])
48     set_bounds (LEFT, n);
49   set_bounds (RIGHT, n);
50
51   add_dependency (n);
52 }
53
54 Direction
55 Dynamic_line_spanner::get_default_dir () const
56 {
57   return DOWN;
58 }
59
60 void
61 Dynamic_line_spanner::do_post_processing ()
62 {
63   Spanner::do_post_processing ();
64   Direction dir = directional_element (this).get ();
65   if (!dir)
66     dir = get_default_dir ();
67
68   /*
69     Hier is ook vast iets voor?
70    */
71   Staff_symbol_referencer_interface si (this);
72   Real above_staff = si.line_count () + 2;
73
74 #if 0
75   // Aargh, nu snap ik waarom ik het niet snap
76   // zie Staff_symbol_referencer_interface::set_position 
77
78   if (si.position_f () * dir < above_staff)
79     si.set_position (above_staff * (int)dir);
80
81   SCM s = get_elt_property ("padding");
82   if (gh_number_p (s))
83     {
84       si.set_position (si.position_f () + gh_scm2double (s) * (int) dir);
85     }
86 #else
87   Real dy = 0;
88   Real pos = si.position_f () * dir;
89   if (pos * dir < above_staff)
90     dy = above_staff;
91
92   SCM s = get_elt_property ("padding");
93   if (gh_number_p (s))
94     dy += gh_scm2double (s);
95   
96   Real half_space = si.staff_space () / 2;
97   translate_axis (dy*half_space*dir, Y_AXIS);
98 #endif
99   
100 }
101
102 /**
103    print text & hairpin dynamics.
104  */
105 class Dynamic_engraver : public Engraver
106 {
107   Text_item * text_p_;
108   Crescendo * finished_cresc_p_;
109   Crescendo * cresc_p_;
110
111   Text_script_req* text_req_l_;
112   Span_req * span_start_req_l_;
113   Drul_array<Span_req*> span_req_l_drul_;
114
115   Dynamic_line_spanner* line_spanner_;
116   Moment last_request_mom_;
117   
118   void  typeset_all ();
119
120 public:
121   VIRTUAL_COPY_CONS(Translator);
122   Dynamic_engraver ();
123   
124 protected:
125   void announce_element (Score_element_info);
126   
127   virtual void do_removal_processing ();
128   virtual void acknowledge_element (Score_element_info);
129   virtual bool do_try_music (Music *req_l);
130   virtual void do_process_requests ();
131   virtual void do_pre_move_processing ();
132   virtual void do_post_move_processing ();
133 };
134
135 ADD_THIS_TRANSLATOR (Dynamic_engraver);
136
137 void
138 Dynamic_engraver::announce_element (Score_element_info i)
139 {
140   group (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
141   
142   Engraver::announce_element (i);
143 }
144
145
146 Dynamic_engraver::Dynamic_engraver ()
147 {
148   text_p_ = 0;
149   finished_cresc_p_ = 0;
150   line_spanner_ = 0;
151   span_start_req_l_ = 0;
152   cresc_p_ =0;
153
154   text_req_l_ = 0;
155   span_req_l_drul_[START] = 0;
156   span_req_l_drul_[STOP] = 0;
157 }
158
159 void
160 Dynamic_engraver::do_post_move_processing ()
161 {
162   text_req_l_ = 0;
163   span_req_l_drul_[START] = 0;
164   span_req_l_drul_[STOP] = 0;
165 }
166
167 bool
168 Dynamic_engraver::do_try_music (Music * m)
169 {
170   if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
171     {
172       if (d->style_str_ == "dynamic")
173         {
174           text_req_l_ = d;
175           return true;
176         }
177     }
178   else if (Span_req* s =  dynamic_cast <Span_req*> (m))
179     {
180       if ((s->span_type_str_ == "crescendo"
181            || s->span_type_str_ == "decrescendo"))
182         {
183           span_req_l_drul_[s->span_dir_] = s;
184           return true;
185         }
186     }
187   return false;
188 }
189
190 void
191 Dynamic_engraver::do_process_requests ()
192 {
193   if ((span_req_l_drul_[START] || text_req_l_) && !line_spanner_)
194     {
195       line_spanner_ = new Dynamic_line_spanner;
196       side_position (line_spanner_).set_axis (Y_AXIS);
197       announce_element (Score_element_info
198                         (line_spanner_,
199                          text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
200
201     }
202           
203   if (span_req_l_drul_[START] || text_req_l_)
204     last_request_mom_ = now_mom ();
205   
206   if (text_req_l_)
207     {
208       String loud = text_req_l_->text_str_;
209
210       text_p_ = new Text_item;
211       text_p_->set_elt_property ("text",
212                                           ly_str02scm (loud.ch_C ()));
213       text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
214       text_p_->set_elt_property ("script-priority",
215                                           gh_int2scm (100));
216           
217       assert (line_spanner_);
218       text_p_->set_parent (line_spanner_, Y_AXIS);
219       announce_element (Score_element_info (text_p_, text_req_l_));
220     }
221
222   if (span_req_l_drul_[STOP])
223     {
224       if (!cresc_p_)
225         {
226           span_req_l_drul_[STOP]->warning
227             (_ ("can't find start of (de)crescendo"));
228         }
229       else
230         {
231           assert (!finished_cresc_p_);
232           cresc_p_->set_bounds(RIGHT, get_staff_info ().musical_pcol_l ());
233           cresc_p_->add_dependency (get_staff_info ().musical_pcol_l ());
234           finished_cresc_p_ = cresc_p_;
235           cresc_p_ = 0;
236           span_start_req_l_ = 0;
237         }
238     }
239
240   if (span_req_l_drul_[START])
241     {
242       if (span_start_req_l_)
243         {
244           span_req_l_drul_[START]->warning
245             (span_start_req_l_->span_dir_ == 1
246              ?
247              _ ("already have a crescendo")
248              : _ ("already have a decrescendo"));
249         }
250       else
251         {
252           span_start_req_l_ = span_req_l_drul_[START];
253           cresc_p_  = new Crescendo;
254           cresc_p_->set_elt_property
255             ("grow-direction",
256              gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
257                          ? BIGGER : SMALLER));
258               
259           SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
260           if (gh_string_p (s))
261             {
262               cresc_p_->set_elt_property ("start-text", s);
263               daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
264                                             + "Text", SCM_UNDEFINED);
265             }
266
267           s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
268           if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
269             {
270               cresc_p_->set_elt_property ("spanner", s);
271               daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
272                                             + "Spanner", SCM_UNDEFINED);
273             }
274
275           cresc_p_->set_bounds(LEFT, get_staff_info ().musical_pcol_l ());
276           cresc_p_->set_bounds(RIGHT, get_staff_info ().musical_pcol_l ());
277           cresc_p_->add_dependency (get_staff_info ().musical_pcol_l ());
278
279           // arrragh, brr, urg: we know how wide text is, no?
280           if (text_p_)
281             {
282               index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
283                               LEFT, SCM_BOOL_T);
284               if (finished_cresc_p_)
285                 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
286                                 RIGHT, SCM_BOOL_T);
287             }
288
289           assert (line_spanner_);
290           cresc_p_->set_parent (line_spanner_, Y_AXIS);
291           cresc_p_->add_dependency (line_spanner_);
292           announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
293         }
294     }
295 }
296
297 void
298 Dynamic_engraver::do_pre_move_processing ()
299 {
300   typeset_all ();
301 }
302
303 void
304 Dynamic_engraver::do_removal_processing ()
305 {
306   if (cresc_p_)
307     {
308       typeset_element (cresc_p_ );
309       span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
310       cresc_p_ =0;
311     }
312   typeset_all ();
313   if (line_spanner_)
314     {
315       typeset_element (line_spanner_);
316       line_spanner_ = 0;
317     }
318 }
319
320
321 void
322 Dynamic_engraver::typeset_all ()
323 {  
324   if (finished_cresc_p_)
325     {
326       //finished_cresc_p_->set_bounds (RIGHT, get_staff_info ().musical_pcol_l ());
327       typeset_element (finished_cresc_p_);
328       finished_cresc_p_ =0;
329     }
330   
331   if (text_p_)
332     {
333       typeset_element (text_p_);
334       text_p_ = 0;
335     }
336
337   /*
338     TODO: This should be optionised:
339       * break when group of dynamic requests ends
340       * break now 
341       * continue through piece
342    */
343   if (line_spanner_ && last_request_mom_ < now_mom ())
344     {
345       typeset_element (line_spanner_);
346       line_spanner_ = 0;
347     }
348 }
349
350 void
351 Dynamic_engraver::acknowledge_element (Score_element_info i)
352 {
353   if (line_spanner_)
354     {
355       if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
356         {
357           side_position (line_spanner_).add_support (n);
358           line_spanner_->add_column (n);
359         }
360     }
361 }