]> git.donarmstrong.com Git - lilypond.git/blob - lily/dynamic-engraver.cc
patch::: 1.3.32.hwn2
[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   VIRTUAL_COPY_CONS(Score_element);
32   void add_column (Item*);
33   Direction get_default_dir () const;
34 };
35
36 Dynamic_line_spanner::Dynamic_line_spanner ()
37 {
38   set_elt_property ("transparent", SCM_BOOL_T);
39   side_position (this).set_axis (Y_AXIS);
40 }
41
42 void
43 Dynamic_line_spanner::add_column (Item* n)
44 {
45   if (!get_bound (LEFT))
46     set_bound (LEFT, n);
47   else
48     set_bound (RIGHT, n);
49
50   add_dependency (n);
51 }
52
53 Direction
54 Dynamic_line_spanner::get_default_dir () const
55 {
56   return DOWN;
57 }
58
59 /**
60    print text & hairpin dynamics.
61  */
62 class Dynamic_engraver : public Engraver
63 {
64   Text_item * text_p_;
65   Crescendo * finished_cresc_p_;
66   Crescendo * cresc_p_;
67
68   Text_script_req* text_req_l_;
69   Span_req * span_start_req_l_;
70   Drul_array<Span_req*> span_req_l_drul_;
71
72   Dynamic_line_spanner* line_spanner_;
73   Moment last_request_mom_;
74   
75   void  typeset_all ();
76
77 public:
78   VIRTUAL_COPY_CONS(Translator);
79   Dynamic_engraver ();
80   
81 protected:
82   void announce_element (Score_element_info);
83   
84   virtual void do_removal_processing ();
85   virtual void acknowledge_element (Score_element_info);
86   virtual bool do_try_music (Music *req_l);
87   virtual void do_process_requests ();
88   virtual void do_pre_move_processing ();
89   virtual void do_post_move_processing ();
90 };
91
92 ADD_THIS_TRANSLATOR (Dynamic_engraver);
93
94 void
95 Dynamic_engraver::announce_element (Score_element_info i)
96 {
97   group (i.elem_l_, "interfaces").add_thing (ly_symbol2scm ("dynamic"));
98   
99   Engraver::announce_element (i);
100 }
101
102
103 Dynamic_engraver::Dynamic_engraver ()
104 {
105   text_p_ = 0;
106   finished_cresc_p_ = 0;
107   line_spanner_ = 0;
108   span_start_req_l_ = 0;
109   cresc_p_ =0;
110
111   text_req_l_ = 0;
112   span_req_l_drul_[START] = 0;
113   span_req_l_drul_[STOP] = 0;
114 }
115
116 void
117 Dynamic_engraver::do_post_move_processing ()
118 {
119   text_req_l_ = 0;
120   span_req_l_drul_[START] = 0;
121   span_req_l_drul_[STOP] = 0;
122
123   /* ugr; we must attach the Dynamic_line_spanner to something
124      to be sure that the linebreaker will not be confused
125   */
126   // if (line_spanner_)
127   // line_spanner_->add_column (LEFT, get_staff_info ().command_pcol_l ());
128 }
129
130 bool
131 Dynamic_engraver::do_try_music (Music * m)
132 {
133   if (Text_script_req* d = dynamic_cast <Text_script_req*> (m))
134     {
135       if (d->style_str_ == "dynamic")
136         {
137           text_req_l_ = d;
138           return true;
139         }
140     }
141   else if (Span_req* s =  dynamic_cast <Span_req*> (m))
142     {
143       if ((s->span_type_str_ == "crescendo"
144            || s->span_type_str_ == "decrescendo"))
145         {
146           span_req_l_drul_[s->span_dir_] = s;
147           return true;
148         }
149     }
150   return false;
151 }
152
153 void
154 Dynamic_engraver::do_process_requests ()
155 {
156   if ((span_req_l_drul_[START] || text_req_l_) && !line_spanner_)
157     {
158       line_spanner_ = new Dynamic_line_spanner;
159       side_position (line_spanner_).set_axis (Y_AXIS);
160       announce_element (Score_element_info
161                         (line_spanner_,
162                          text_req_l_ ? text_req_l_ : span_req_l_drul_[START]));
163
164     }
165           
166   if (span_req_l_drul_[START] || text_req_l_)
167     last_request_mom_ = now_mom ();
168   
169   if (text_req_l_)
170     {
171       String loud = text_req_l_->text_str_;
172
173       text_p_ = new Text_item;
174       text_p_->set_elt_property ("text",
175                                           ly_str02scm (loud.ch_C ()));
176       text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
177       text_p_->set_elt_property ("script-priority",
178                                           gh_int2scm (100));
179           
180       assert (line_spanner_);
181       text_p_->set_parent (line_spanner_, Y_AXIS);
182       announce_element (Score_element_info (text_p_, text_req_l_));
183     }
184
185   if (span_req_l_drul_[STOP])
186     {
187       if (!cresc_p_)
188         {
189           span_req_l_drul_[STOP]->warning
190             (_ ("can't find start of (de)crescendo"));
191         }
192       else
193         {
194           assert (!finished_cresc_p_);
195           cresc_p_->set_bound(RIGHT, get_staff_info ().musical_pcol_l ());
196           //      cresc_p_->add_dependency (get_staff_info ().musical_pcol_l ());
197           finished_cresc_p_ = cresc_p_;
198           cresc_p_ = 0;
199           span_start_req_l_ = 0;
200         }
201     }
202
203   if (span_req_l_drul_[START])
204     {
205       if (span_start_req_l_)
206         {
207           span_req_l_drul_[START]->warning
208             (span_start_req_l_->span_dir_ == 1
209              ?
210              _ ("already have a crescendo")
211              : _ ("already have a decrescendo"));
212         }
213       else
214         {
215           span_start_req_l_ = span_req_l_drul_[START];
216           cresc_p_  = new Crescendo;
217           cresc_p_->set_elt_property
218             ("grow-direction",
219              gh_int2scm ((span_req_l_drul_[START]->span_type_str_ == "crescendo")
220                          ? BIGGER : SMALLER));
221               
222           SCM s = get_property (span_req_l_drul_[START]->span_type_str_ + "Text");
223           if (gh_string_p (s))
224             {
225               cresc_p_->set_elt_property ("start-text", s);
226               daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
227                                             + "Text", SCM_UNDEFINED);
228             }
229
230           s = get_property (span_req_l_drul_[START]->span_type_str_ + "Spanner");
231           if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
232             {
233               cresc_p_->set_elt_property ("spanner", s);
234               daddy_trans_l_->set_property (span_req_l_drul_[START]->span_type_str_
235                                             + "Spanner", SCM_UNDEFINED);
236             }
237
238           cresc_p_->set_bound(LEFT, get_staff_info ().musical_pcol_l ());
239
240
241           // cresc_p_->add_dependency (get_staff_info ().musical_pcol_l ());
242
243           /* 
244               We know how wide the text is, if we can be sure that the
245               text already has relevant pointers into the paperdef,
246               and it has its font-size property set.
247
248               Since font-size may be set by a context higher up, we
249               can not be sure of the size.
250           */
251
252              
253           if (text_p_)
254             {
255               index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
256                               LEFT, SCM_BOOL_T);
257               if (finished_cresc_p_)
258                 index_set_cell (finished_cresc_p_->get_elt_property ("dynamic-drul"),
259                                 RIGHT, SCM_BOOL_T);
260             }
261
262           assert (line_spanner_);
263           cresc_p_->set_parent (line_spanner_, Y_AXIS);
264           // cresc_p_->add_dependency (line_spanner_);
265           announce_element (Score_element_info (cresc_p_, span_req_l_drul_[START]));
266         }
267     }
268 }
269
270 void
271 Dynamic_engraver::do_pre_move_processing ()
272 {
273   typeset_all ();
274 }
275
276
277 void
278 Dynamic_engraver::do_removal_processing ()
279 {
280   if (cresc_p_)
281     {
282       typeset_element (cresc_p_ );
283       span_start_req_l_->warning (_ ("unterminated (de)crescendo"));
284       cresc_p_ =0;
285     }
286   typeset_all ();
287   if (line_spanner_)
288     {
289       typeset_element (line_spanner_);
290       line_spanner_ = 0;
291     }
292 }
293
294
295 void
296 Dynamic_engraver::typeset_all ()
297 {  
298   if (finished_cresc_p_)
299     {
300       typeset_element (finished_cresc_p_);
301       finished_cresc_p_ =0;
302     }
303   
304   if (text_p_)
305     {
306       typeset_element (text_p_);
307       text_p_ = 0;
308     }
309
310   /*
311     TODO: This should be optionised:
312       * break when group of dynamic requests ends
313       * break now 
314       * continue through piece */
315   if (line_spanner_ && last_request_mom_ < now_mom ())
316     {
317
318       side_position (line_spanner_).add_staff_support ();
319       
320       typeset_element (line_spanner_);
321       line_spanner_ = 0;
322     }
323 }
324
325 void
326 Dynamic_engraver::acknowledge_element (Score_element_info i)
327 {
328   if (line_spanner_)
329     {
330       if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
331         {
332           side_position (line_spanner_).add_support (n);
333           line_spanner_->add_column (n);
334         }
335     }
336 }