]> git.donarmstrong.com Git - lilypond.git/blob - lily/piano-pedal-align-engraver.cc
31115925996d2ce309865beccda09152d142e735
[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--2012 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 /*
31   TODO:
32
33
34   * Detach from pedal specifics,
35
36   * Also use this engraver for dynamics.
37 */
38
39 struct Pedal_align_info
40 {
41   Spanner *line_spanner_;
42   Grob *carrying_item_;
43   Spanner *carrying_spanner_;
44   Spanner *finished_carrying_spanner_;
45
46   Pedal_align_info ()
47   {
48     clear ();
49
50   }
51   void clear ()
52   {
53     line_spanner_ = 0;
54     carrying_spanner_ = 0;
55     carrying_item_ = 0;
56     finished_carrying_spanner_ = 0;
57   }
58   bool is_finished ()
59   {
60     bool do_continue = carrying_item_;
61
62     do_continue |= (carrying_spanner_ && !finished_carrying_spanner_);
63     do_continue |= (carrying_spanner_ && finished_carrying_spanner_ != carrying_spanner_);
64
65     return !do_continue;
66   }
67 };
68
69 class Piano_pedal_align_engraver : public Engraver
70 {
71 public:
72   TRANSLATOR_DECLARATIONS (Piano_pedal_align_engraver);
73
74 protected:
75   virtual void finalize ();
76
77   DECLARE_ACKNOWLEDGER (piano_pedal_script);
78   DECLARE_ACKNOWLEDGER (piano_pedal_bracket);
79   DECLARE_ACKNOWLEDGER (note_column);
80
81   DECLARE_END_ACKNOWLEDGER (piano_pedal_bracket);
82
83   void stop_translation_timestep ();
84   void start_translation_timestep ();
85
86 private:
87   enum Pedal_type
88   {
89     SOSTENUTO,
90     SUSTAIN,
91     UNA_CORDA,
92     NUM_PEDAL_TYPES
93   };
94   Pedal_align_info pedal_info_[NUM_PEDAL_TYPES];
95   vector<Grob *> supports_;
96
97   Pedal_type get_grob_pedal_type (Grob_info g);
98   Spanner *make_line_spanner (Pedal_type t, SCM);
99 };
100
101 Piano_pedal_align_engraver::Piano_pedal_align_engraver ()
102 {
103 }
104
105 void
106 Piano_pedal_align_engraver::start_translation_timestep ()
107 {
108   supports_.clear ();
109 }
110
111 void
112 Piano_pedal_align_engraver::stop_translation_timestep ()
113 {
114   for (int i = 0; i < NUM_PEDAL_TYPES; i++)
115     {
116       if (pedal_info_[i].line_spanner_)
117         {
118
119           if (pedal_info_[i].carrying_item_)
120             {
121               if (!pedal_info_[i].line_spanner_->get_bound (LEFT))
122                 pedal_info_[i].line_spanner_->set_bound (LEFT,
123                                                          pedal_info_[i].carrying_item_);
124
125               pedal_info_[i].line_spanner_->set_bound (RIGHT,
126                                                        pedal_info_[i].carrying_item_);
127             }
128           else if (pedal_info_[i].carrying_spanner_
129                    || pedal_info_[i].finished_carrying_spanner_
130                   )
131             {
132               if (!pedal_info_[i].line_spanner_->get_bound (LEFT)
133                   && pedal_info_[i].carrying_spanner_->get_bound (LEFT))
134                 pedal_info_[i].line_spanner_->set_bound (LEFT,
135                                                          pedal_info_[i].carrying_spanner_->get_bound (LEFT));
136
137               if (pedal_info_[i].finished_carrying_spanner_)
138                 pedal_info_[i].line_spanner_->set_bound (RIGHT,
139                                                          pedal_info_[i].finished_carrying_spanner_->get_bound (RIGHT));
140             }
141
142           for (vsize j = 0; j < supports_.size (); j++)
143             {
144               Side_position_interface::add_support (pedal_info_[i].line_spanner_, supports_[j]);
145             }
146
147           if (pedal_info_[i].is_finished ())
148             {
149               announce_end_grob (pedal_info_[i].line_spanner_, SCM_EOL);
150               pedal_info_[i].clear ();
151             }
152         }
153
154       pedal_info_[i].carrying_item_ = 0;
155     }
156 }
157
158 Piano_pedal_align_engraver::Pedal_type
159 Piano_pedal_align_engraver::get_grob_pedal_type (Grob_info g)
160 {
161   if (g.event_cause ()->in_event_class ("sostenuto-event"))
162     return SOSTENUTO;
163   if (g.event_cause ()->in_event_class ("sustain-event"))
164     return SUSTAIN;
165   if (g.event_cause ()->in_event_class ("una-corda-event"))
166     return UNA_CORDA;
167
168   programming_error ("Unknown piano pedal type.  Defaulting to sustain");
169   return SUSTAIN;
170 }
171
172 Spanner *
173 Piano_pedal_align_engraver::make_line_spanner (Pedal_type t, SCM cause)
174 {
175   Spanner *sp = pedal_info_[t].line_spanner_;
176   if (!sp)
177     {
178       switch (t)
179         {
180         case (SOSTENUTO):
181           sp = make_spanner ("SostenutoPedalLineSpanner", cause);
182           break;
183         case (SUSTAIN):
184           sp = make_spanner ("SustainPedalLineSpanner", cause);
185           break;
186         case (UNA_CORDA):
187           sp = make_spanner ("UnaCordaPedalLineSpanner", cause);
188           break;
189         default:
190           programming_error ("No pedal type fonud!");
191           return sp;
192         }
193
194       pedal_info_[t].line_spanner_ = sp;
195     }
196
197   return sp;
198 }
199
200 void
201 Piano_pedal_align_engraver::acknowledge_note_column (Grob_info gi)
202 {
203   supports_.push_back (gi.grob ());
204 }
205
206 void
207 Piano_pedal_align_engraver::acknowledge_piano_pedal_bracket (Grob_info gi)
208 {
209   Pedal_type type = get_grob_pedal_type (gi);
210   Grob *sp = make_line_spanner (type, gi.grob ()->self_scm ());
211
212   Axis_group_interface::add_element (sp, gi.grob ());
213   pedal_info_[type].carrying_spanner_ = gi.spanner ();
214 }
215
216 void
217 Piano_pedal_align_engraver::acknowledge_end_piano_pedal_bracket (Grob_info gi)
218 {
219   Pedal_type type = get_grob_pedal_type (gi);
220   pedal_info_[type].finished_carrying_spanner_ = gi.spanner ();
221 }
222
223 void
224 Piano_pedal_align_engraver::acknowledge_piano_pedal_script (Grob_info gi)
225 {
226   Pedal_type type = get_grob_pedal_type (gi);
227
228   Grob *sp = make_line_spanner (type, gi.grob ()->self_scm ());
229   Axis_group_interface::add_element (sp, gi.grob ());
230   pedal_info_[type].carrying_item_ = gi.grob ();
231 }
232
233 void
234 Piano_pedal_align_engraver::finalize ()
235 {
236   for (int i = 0; i < NUM_PEDAL_TYPES; i++)
237     {
238       if (pedal_info_[i].line_spanner_)
239         {
240           SCM cc = get_property ("currentCommandColumn");
241           Item *c = unsmob_item (cc);
242           pedal_info_[i].line_spanner_->set_bound (RIGHT, c);
243
244           pedal_info_[i].clear ();
245         }
246     }
247 }
248
249 #include "translator.icc"
250
251 ADD_ACKNOWLEDGER (Piano_pedal_align_engraver, note_column);
252 ADD_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_bracket);
253 ADD_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_script);
254
255 ADD_END_ACKNOWLEDGER (Piano_pedal_align_engraver, piano_pedal_bracket);
256
257 ADD_TRANSLATOR (Piano_pedal_align_engraver,
258                 /* doc */
259                 "Align piano pedal symbols and brackets.",
260
261                 /* create */
262                 "SostenutoPedalLineSpanner "
263                 "SustainPedalLineSpanner "
264                 "UnaCordaPedalLineSpanner ",
265
266                 /* read */
267                 "currentCommandColumn ",
268
269                 /* write */
270                 ""
271                );