]> git.donarmstrong.com Git - lilypond.git/blob - lily/new-dynamic-engraver.cc
Merge commit 'origin' into beamlets2
[lilypond.git] / lily / new-dynamic-engraver.cc
1 /* 
2   new-dynamic-engraver.cc -- implement New_dynamic_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2008 Han-Wen Nienhuys <hanwen@lilypond.org>
7   
8 */
9
10
11 #include "engraver.hh"
12
13 #include "hairpin.hh"
14 #include "international.hh"
15 #include "item.hh"
16 #include "note-column.hh"
17 #include "pointer-group-interface.hh"
18 #include "self-alignment-interface.hh"
19 #include "spanner.hh"
20 #include "stream-event.hh"
21 #include "text-interface.hh"
22
23 #include "translator.icc"
24
25 class New_dynamic_engraver : public Engraver
26 {
27   TRANSLATOR_DECLARATIONS (New_dynamic_engraver);
28   DECLARE_ACKNOWLEDGER (note_column);
29   DECLARE_TRANSLATOR_LISTENER (absolute_dynamic);
30   DECLARE_TRANSLATOR_LISTENER (span_dynamic);
31
32 protected:
33   virtual void process_music ();
34   virtual void stop_translation_timestep ();
35 private:
36   Drul_array<Stream_event *> accepted_spanevents_drul_;
37   Spanner *current_spanner_;
38   Spanner *finished_spanner_;
39   
40   Item *script_;
41   Stream_event *script_event_;
42   Stream_event *current_span_event_;
43 };
44
45 New_dynamic_engraver::New_dynamic_engraver ()
46 {
47   script_event_ = 0;
48   current_span_event_ = 0;
49   script_ = 0;
50   finished_spanner_ = 0;
51   current_spanner_ = 0;
52   accepted_spanevents_drul_.set (0, 0);
53 }
54
55 IMPLEMENT_TRANSLATOR_LISTENER (New_dynamic_engraver, absolute_dynamic);
56 void
57 New_dynamic_engraver::listen_absolute_dynamic (Stream_event *ev)
58 {
59   ASSIGN_EVENT_ONCE (script_event_, ev);
60 }
61
62 IMPLEMENT_TRANSLATOR_LISTENER (New_dynamic_engraver, span_dynamic);
63 void
64 New_dynamic_engraver::listen_span_dynamic (Stream_event *ev)
65 {
66   Direction d = to_dir (ev->get_property ("span-direction"));
67
68   ASSIGN_EVENT_ONCE (accepted_spanevents_drul_[d], ev);
69 }
70
71
72 void
73 New_dynamic_engraver::process_music ()
74 {
75   if (current_spanner_
76       && (accepted_spanevents_drul_[STOP] || script_event_ || accepted_spanevents_drul_[START]))
77     {
78       Stream_event* ender = accepted_spanevents_drul_[STOP];
79       if (!ender)
80         ender = script_event_;
81
82       if (!ender)
83         ender = accepted_spanevents_drul_[START];
84       
85       finished_spanner_ = current_spanner_;
86       announce_end_grob (finished_spanner_, ender->self_scm ());
87       current_spanner_ = 0;
88       current_span_event_ = 0;
89     }
90
91   if (accepted_spanevents_drul_[START])
92     {
93       current_span_event_ = accepted_spanevents_drul_[START];
94       
95       SCM start_sym = current_span_event_->get_property ("class");
96       string start_type;
97           
98       if (start_sym == ly_symbol2scm ("decrescendo-event"))
99         start_type = "decrescendo";
100       else if (start_sym == ly_symbol2scm ("crescendo-event"))
101         start_type = "crescendo";
102       else
103         {
104           programming_error ("unknown dynamic spanner type");
105           return;
106         }
107       
108       SCM cresc_type = get_property ((start_type + "Spanner").c_str ());
109
110       if (cresc_type == ly_symbol2scm ("text"))
111         {
112           current_spanner_
113             = make_spanner ("DynamicTextSpanner",
114                             accepted_spanevents_drul_[START]->self_scm ());
115
116           SCM text = get_property ((start_type + "Text").c_str ());
117           if (Text_interface::is_markup (text))
118             {
119               current_spanner_->set_property ("text", text);
120             }
121         }
122       else
123         {
124           if (cresc_type != ly_symbol2scm ("hairpin"))
125             {
126               // Fixme: should put value in error message.
127               string as_string = ly_scm_write_string (cresc_type);
128               current_span_event_
129                 ->origin()->warning (_f ("unknown crescendo style: %s\ndefaulting to hairpin.", as_string.c_str()));
130             }
131           current_spanner_ = make_spanner ("Hairpin",
132                                            current_span_event_->self_scm ());
133           if (finished_spanner_)
134             {
135               Pointer_group_interface::add_grob (finished_spanner_,
136                                                  ly_symbol2scm ("adjacent-hairpins"),
137                                                  current_spanner_);
138
139               Pointer_group_interface::add_grob (current_spanner_,
140                                                  ly_symbol2scm ("adjacent-hairpins"),
141                                                  finished_spanner_);
142             }
143         }
144     }
145
146   if (script_event_)
147     {
148       script_ = make_item ("DynamicText", script_event_->self_scm ());
149       script_->set_property ("text",
150                              script_event_->get_property ("text"));
151
152       if (finished_spanner_)
153         finished_spanner_->set_bound (RIGHT, script_);
154       if (current_spanner_)
155         {
156           current_spanner_->set_bound (LEFT, script_);
157
158           if (!Hairpin::has_interface (current_spanner_))
159             set_nested_property (current_spanner_,
160                                  scm_list_3 (ly_symbol2scm ("bound-details"),
161                                              ly_symbol2scm ("left"),
162                                              ly_symbol2scm ("attach-dir")
163                                              ),
164                                  scm_from_int (RIGHT));
165
166         }
167     }
168 }
169
170
171
172 void
173 New_dynamic_engraver::stop_translation_timestep ()
174 {
175   if (finished_spanner_ && !finished_spanner_->get_bound (RIGHT))
176     finished_spanner_->set_bound (RIGHT,
177                                   unsmob_grob (get_property ("currentMusicalColumn")));
178
179   if (current_spanner_ && !current_spanner_->get_bound (LEFT))
180     current_spanner_->set_bound (LEFT,
181                                  unsmob_grob (get_property ("currentMusicalColumn")));
182   script_ = 0;
183   script_event_ = 0;
184   accepted_spanevents_drul_.set (0, 0);
185   finished_spanner_ = 0;
186 }
187
188 void
189 New_dynamic_engraver::acknowledge_note_column (Grob_info info)
190 {
191   if (script_ && !script_->get_parent (X_AXIS))
192     {
193       extract_grob_set (info.grob (), "note-heads", heads);
194       if (heads.size ())
195         {
196           Grob *head = heads[0];
197           script_->set_parent (head, X_AXIS);
198           Self_alignment_interface::set_center_parent (script_, X_AXIS);
199         }
200     }
201
202   if (current_spanner_ && !current_spanner_->get_bound (LEFT))
203     current_spanner_->set_bound (LEFT, info.grob ());
204   if (finished_spanner_ && !finished_spanner_->get_bound (RIGHT))
205     finished_spanner_->set_bound (RIGHT, info.grob ());
206 }
207
208 ADD_ACKNOWLEDGER (New_dynamic_engraver, note_column);
209 ADD_TRANSLATOR (New_dynamic_engraver,
210                 /* doc */
211                 "Create hairpins, dynamic texts, and their vertical"
212                 " alignments.  The symbols are collected onto a"
213                 " @code{DynamicLineSpanner} grob which takes care of vertical"
214                 " positioning.",
215
216                 /* create */
217                 "DynamicTextSpanner "
218                 "DynamicText "
219                 "Hairpin "
220                 "TextSpanner ",
221
222                 /* read */
223                 "crescendoSpanner "
224                 "crescendoText "
225                 "currentMusicalColumn "
226                 "decrescendoSpanner "
227                 "decrescendoText ",
228
229                 /* write */
230                 ""
231                 );