]> git.donarmstrong.com Git - lilypond.git/blob - lily/piano-pedal-align-engraver.cc
Issue 5024: Rework the Preinit framework into something simpler
[lilypond.git] / lily / piano-pedal-align-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2006--2015 Han-Wen Nienhuys <hanwen@lilypond.org>
5
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "engraver.hh"
22
23 #include "spanner.hh"
24 #include "item.hh"
25 #include "side-position-interface.hh"
26 #include "stream-event.hh"
27 #include "warn.hh"
28 #include "axis-group-interface.hh"
29
30 #include "translator.icc"
31
32 /*
33   TODO:
34
35
36   * Detach from pedal specifics,
37
38   * Also use this engraver for dynamics.
39 */
40
41 struct Pedal_align_info
42 {
43   Spanner *line_spanner_;
44   Grob *carrying_item_;
45   Spanner *carrying_spanner_;
46   Spanner *finished_carrying_spanner_;
47
48   Pedal_align_info ()
49   {
50     clear ();
51
52   }
53   void clear ()
54   {
55     line_spanner_ = 0;
56     carrying_spanner_ = 0;
57     carrying_item_ = 0;
58     finished_carrying_spanner_ = 0;
59   }
60   bool is_finished ()
61   {
62     bool do_continue = carrying_item_;
63
64     do_continue |= (carrying_spanner_ && !finished_carrying_spanner_);
65     do_continue |= (carrying_spanner_ && finished_carrying_spanner_ != carrying_spanner_);
66
67     return !do_continue;
68   }
69 };
70
71 class Piano_pedal_align_engraver : public Engraver
72 {
73 public:
74   TRANSLATOR_DECLARATIONS (Piano_pedal_align_engraver);
75
76 protected:
77   virtual void finalize ();
78
79   void acknowledge_piano_pedal_script (Grob_info);
80   void acknowledge_piano_pedal_bracket (Grob_info);
81   void acknowledge_note_column (Grob_info);
82
83   void acknowledge_end_piano_pedal_bracket (Grob_info);
84
85   void stop_translation_timestep ();
86   void start_translation_timestep ();
87
88 private:
89   enum Pedal_type
90   {
91     SOSTENUTO,
92     SUSTAIN,
93     UNA_CORDA,
94     NUM_PEDAL_TYPES
95   };
96   Pedal_align_info pedal_info_[NUM_PEDAL_TYPES];
97   vector<Grob *> supports_;
98
99   Pedal_type get_grob_pedal_type (Grob_info g);
100   Spanner *make_line_spanner (Pedal_type t, SCM);
101 };
102
103 Piano_pedal_align_engraver::Piano_pedal_align_engraver ()
104 {
105 }
106
107 void
108 Piano_pedal_align_engraver::start_translation_timestep ()
109 {
110   supports_.clear ();
111 }
112
113 void
114 Piano_pedal_align_engraver::stop_translation_timestep ()
115 {
116   for (int i = 0; i < NUM_PEDAL_TYPES; i++)
117     {
118       if (pedal_info_[i].line_spanner_)
119         {
120
121           if (pedal_info_[i].carrying_item_)
122             {
123               if (!pedal_info_[i].line_spanner_->get_bound (LEFT))
124                 pedal_info_[i].line_spanner_->set_bound (LEFT,
125                                                          pedal_info_[i].carrying_item_);
126
127               pedal_info_[i].line_spanner_->set_bound (RIGHT,
128                                                        pedal_info_[i].carrying_item_);
129             }
130           else if (pedal_info_[i].carrying_spanner_
131                    || pedal_info_[i].finished_carrying_spanner_
132                   )
133             {
134               if (!pedal_info_[i].line_spanner_->get_bound (LEFT)
135                   && pedal_info_[i].carrying_spanner_->get_bound (LEFT))
136                 pedal_info_[i].line_spanner_->set_bound (LEFT,
137                                                          pedal_info_[i].carrying_spanner_->get_bound (LEFT));
138
139               if (pedal_info_[i].finished_carrying_spanner_)
140                 pedal_info_[i].line_spanner_->set_bound (RIGHT,
141                                                          pedal_info_[i].finished_carrying_spanner_->get_bound (RIGHT));
142             }
143
144           for (vsize j = 0; j < supports_.size (); j++)
145             {
146               Side_position_interface::add_support (pedal_info_[i].line_spanner_, supports_[j]);
147             }
148
149           if (pedal_info_[i].is_finished ())
150             {
151               announce_end_grob (pedal_info_[i].line_spanner_, SCM_EOL);
152               pedal_info_[i].clear ();
153             }
154         }
155
156       pedal_info_[i].carrying_item_ = 0;
157     }
158 }
159
160 Piano_pedal_align_engraver::Pedal_type
161 Piano_pedal_align_engraver::get_grob_pedal_type (Grob_info g)
162 {
163   if (g.event_cause ()->in_event_class ("sostenuto-event"))
164     return SOSTENUTO;
165   if (g.event_cause ()->in_event_class ("sustain-event"))
166     return SUSTAIN;
167   if (g.event_cause ()->in_event_class ("una-corda-event"))
168     return UNA_CORDA;
169
170   programming_error ("Unknown piano pedal type.  Defaulting to sustain");
171   return SUSTAIN;
172 }
173
174 Spanner *
175 Piano_pedal_align_engraver::make_line_spanner (Pedal_type t, SCM cause)
176 {
177   Spanner *sp = pedal_info_[t].line_spanner_;
178   if (!sp)
179     {
180       switch (t)
181         {
182         case (SOSTENUTO):
183           sp = make_spanner ("SostenutoPedalLineSpanner", cause);
184           break;
185         case (SUSTAIN):
186           sp = make_spanner ("SustainPedalLineSpanner", cause);
187           break;
188         case (UNA_CORDA):
189           sp = make_spanner ("UnaCordaPedalLineSpanner", cause);
190           break;
191         default:
192           programming_error ("No pedal type fonud!");
193           return sp;
194         }
195
196       pedal_info_[t].line_spanner_ = sp;
197     }
198
199   return sp;
200 }
201
202 void
203 Piano_pedal_align_engraver::acknowledge_note_column (Grob_info gi)
204 {
205   supports_.push_back (gi.grob ());
206 }
207
208 void
209 Piano_pedal_align_engraver::acknowledge_piano_pedal_bracket (Grob_info gi)
210 {
211   Pedal_type type = get_grob_pedal_type (gi);
212   Grob *sp = make_line_spanner (type, gi.grob ()->self_scm ());
213
214   Axis_group_interface::add_element (sp, gi.grob ());
215   pedal_info_[type].carrying_spanner_ = gi.spanner ();
216 }
217
218 void
219 Piano_pedal_align_engraver::acknowledge_end_piano_pedal_bracket (Grob_info gi)
220 {
221   Pedal_type type = get_grob_pedal_type (gi);
222   pedal_info_[type].finished_carrying_spanner_ = gi.spanner ();
223 }
224
225 void
226 Piano_pedal_align_engraver::acknowledge_piano_pedal_script (Grob_info gi)
227 {
228   Pedal_type type = get_grob_pedal_type (gi);
229
230   Grob *sp = make_line_spanner (type, gi.grob ()->self_scm ());
231   Axis_group_interface::add_element (sp, gi.grob ());
232   pedal_info_[type].carrying_item_ = gi.grob ();
233 }
234
235 void
236 Piano_pedal_align_engraver::finalize ()
237 {
238   for (int i = 0; i < NUM_PEDAL_TYPES; i++)
239     {
240       if (pedal_info_[i].line_spanner_)
241         {
242           SCM cc = get_property ("currentCommandColumn");
243           Item *c = unsmob<Item> (cc);
244           pedal_info_[i].line_spanner_->set_bound (RIGHT, c);
245
246           pedal_info_[i].clear ();
247         }
248     }
249 }
250
251
252
253 void
254 Piano_pedal_align_engraver::boot ()
255 {
256   ADD_ACKNOWLEDGER (Piano_pedal_align_engraver, note_column);
257   ADD_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_bracket);
258   ADD_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_script);
259   ADD_END_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_bracket);
260 }
261
262 ADD_TRANSLATOR (Piano_pedal_align_engraver,
263                 /* doc */
264                 "Align piano pedal symbols and brackets.",
265
266                 /* create */
267                 "SostenutoPedalLineSpanner "
268                 "SustainPedalLineSpanner "
269                 "UnaCordaPedalLineSpanner ",
270
271                 /* read */
272                 "currentCommandColumn ",
273
274                 /* write */
275                 ""
276                );