2 piano-pedal-engraver.cc -- implement Piano_pedal_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2002 Jan Nieuwenhuizen <janneke@gnu.org>
8 Chris Jackson <chris@fluffhouse.org.uk> - extended to support
11 TODO: support for __| |__ or __| Ped instead of ___/\__ for pedal up-down
15 #include "engraver.hh"
16 #include "musical-request.hh"
19 #include "lily-guile.hh"
20 #include "side-position-interface.hh"
21 #include "staff-symbol-referencer.hh"
23 #include "axis-group-interface.hh"
24 #include "translator-group.hh"
25 #include "directional-element-interface.hh"
26 #include "note-column.hh"
28 class Piano_pedal_engraver : public Engraver
31 TRANSLATOR_DECLARATIONS(Piano_pedal_engraver);
32 ~Piano_pedal_engraver ();
34 virtual void initialize ();
35 virtual void finalize ();
36 virtual bool try_music (Music*);
37 virtual void stop_translation_timestep ();
38 virtual void start_translation_timestep ();
39 virtual void acknowledge_grob (Grob_info);
40 virtual void create_grobs ();
46 Span_req* start_req_l_;
47 Drul_array<Span_req*> req_l_drul_;
49 Spanner* bracket_p_; // A single portion of a pedal bracket
50 Spanner* finished_bracket_p_;
51 Spanner* line_spanner_; // This grob contains all the pedals of the same type on the same staff
52 Spanner* finished_line_spanner_;
53 Span_req* current_bracket_req_;
57 Pedal_info *info_list_;
59 Spanner *previous_p_ [4]; // Record a stack of the current pedal spanners, so if more than one pedal
60 int nspanners_i; // occurs simultaneously then extra space can be added between them.
61 void create_text_grobs (Pedal_info *p, SCM pedaltype);
62 void create_bracket_grobs (Pedal_info *p, SCM pedaltype);
68 Piano_pedal_engraver::Piano_pedal_engraver ()
73 Piano_pedal_engraver::initialize ()
75 info_list_ = new Pedal_info[4];
76 Pedal_info *p = info_list_;
79 for (int i = 0; i < 3; ++i)
83 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
90 p->finished_bracket_p_ = 0;
92 p->finished_line_spanner_ = 0;
93 p->current_bracket_req_ = 0;
94 p->req_l_drul_[START] = 0;
95 p->req_l_drul_[STOP] = 0;
103 Piano_pedal_engraver::~Piano_pedal_engraver ()
113 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
115 for (Pedal_info*p = info_list_; p && p->name_; p ++)
117 Grob *g = (Grob *) p->item_p_;
121 if (g && p->line_spanner_)
123 if (Note_column::has_interface (info.grob_l_))
125 Side_position_interface::add_support (p->line_spanner_, info.grob_l_);
126 add_bound_item (p->line_spanner_,dynamic_cast<Item*> (info.grob_l_));
128 if (Side_position_interface::get_axis (g) == X_AXIS
129 && !g->get_parent (Y_AXIS))
130 g->set_parent (info.grob_l_, Y_AXIS);
133 g = (Grob *) p->bracket_p_;
140 Piano_pedal_engraver::try_music (Music *m)
142 if (Span_req * s = dynamic_cast<Span_req*> (m))
144 for (Pedal_info*p = info_list_; p->name_; p ++)
146 if (ly_scm2string (s->get_mus_property ("span-type")) == "abort")
148 p->req_l_drul_[START] = 0;
149 p->req_l_drul_[STOP] = 0;
152 p->bracket_p_->suicide (); /* as in dynamic-engraver.cc */
155 if (scm_equal_p (s->get_mus_property ("span-type"),
156 ly_str02scm (p->name_))==SCM_BOOL_T)
158 p->req_l_drul_[s->get_span_dir ()] = s;
167 Piano_pedal_engraver::create_grobs ()
169 for (Pedal_info*p = info_list_; p && p->name_; p ++)
171 if (p->req_l_drul_[STOP] || p->req_l_drul_[START])
173 if (!p->line_spanner_)
175 p->line_spanner_ = new Spanner (get_property ( ( String (p->name_) + "PedalLineSpanner").ch_C() ));
176 Side_position_interface::set_axis (p->line_spanner_, Y_AXIS);
177 Music * rq = (p->req_l_drul_[START] ? p->req_l_drul_[START] : p->req_l_drul_[STOP]);
178 announce_grob (p->line_spanner_, rq->self_scm ());
181 // Choose the appropriate grobs to add to the line spanner
182 // These can be text items or text-spanners
184 SCM type = ly_cdr (scm_assoc (ly_symbol2scm("pedal-type"),
185 get_property( ( String (p->name_) + "Pedal").ch_C () )));
186 if (type == ly_symbol2scm("text") || // Ped. *Ped. *
187 type == ly_symbol2scm("mixed") ) // Ped. _____/\____|
189 create_text_grobs(p, type);
191 if (type == ly_symbol2scm("bracket") || // |_________/\____|
192 type == ly_symbol2scm("mixed") )
193 create_bracket_grobs(p, type);
201 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, SCM pedaltype)
205 SCM strings = get_property (("pedal" + String (p->name_) + "Strings").ch_C ());
207 if (! (scm_ilength (strings) < 3))
209 if (p->req_l_drul_[STOP] && p->req_l_drul_[START])
211 if (pedaltype == ly_symbol2scm("text"))
213 if (!p->start_req_l_)
215 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
219 s = ly_cadr (strings);
221 p->start_req_l_ = p->req_l_drul_[START];
225 else if (p->req_l_drul_[STOP])
227 if (pedaltype == ly_symbol2scm("text"))
229 if (!p->start_req_l_)
231 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
235 s = ly_caddr (strings);
242 else if ( p->req_l_drul_[START] )
244 p->start_req_l_ = p->req_l_drul_[START];
245 s = ly_car (strings);
246 if (pedaltype == ly_symbol2scm("text")) {
248 previous_p_[nspanners_i] = p->line_spanner_;
250 // add extra space below the previous already-occuring pedal
251 Side_position_interface::add_support(p->line_spanner_, previous_p_[nspanners_i - 1]);
257 String propname = String (p->name_) + "Pedal";
258 b = get_property (propname.ch_C ());
259 p->item_p_ = new Item (b);
260 p->item_p_->set_grob_property ("text", s);
261 Axis_group_interface::add_element (p->line_spanner_, p->item_p_);
263 announce_grob (p->item_p_,
264 (p->req_l_drul_[START]
265 ? p->req_l_drul_[START]
266 : p->req_l_drul_[STOP])->self_scm() );
269 if (pedaltype == ly_symbol2scm("text"))
271 p->req_l_drul_[START] = 0;
272 p->req_l_drul_[STOP] = 0;
278 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, SCM pedaltype)
281 if (p->req_l_drul_[STOP])
283 if (!p->start_req_l_)
285 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
287 else if (!p->req_l_drul_[START])
290 assert (!p->finished_bracket_p_ && p->bracket_p_);
292 p->bracket_p_->set_bound (RIGHT, unsmob_grob(get_property ("currentMusicalColumn")));
294 // Set a property so that the molecule-creating function will know whether the right edge should be flared ___/
295 p->bracket_p_->set_grob_property("right-widen", gh_bool2scm((bool) p->req_l_drul_[START]) );
296 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (RIGHT));
298 p->finished_bracket_p_ = p->bracket_p_;
300 p->current_bracket_req_ = 0;
301 p->start_req_l_ = p->req_l_drul_[START];
304 if (p->req_l_drul_[START])
306 p->start_req_l_ = p->req_l_drul_[START];
307 p->current_bracket_req_ = p->req_l_drul_[START];
309 p->bracket_p_ = new Spanner (get_property ("PianoPedalBracket"));
311 // Set a property so that the molecule-creating function will know whether the left edge should be flared \___
312 p->bracket_p_->set_grob_property("left-widen", gh_bool2scm((bool) p->req_l_drul_[STOP]) );
314 // Set this property for 'mixed style' pedals, Ped._______/\ ,
315 // so the molecule function will shorten the ____ line by the length of the Ped. text.
316 p->bracket_p_->set_grob_property("text-start",
317 pedaltype == ly_symbol2scm("mixed") ?
318 gh_bool2scm((bool) ! p->req_l_drul_[STOP]) :
321 p->bracket_p_->set_parent (p->item_p_, Y_AXIS);
323 p->bracket_p_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
324 Axis_group_interface::add_element (p->line_spanner_, p->bracket_p_);
326 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (LEFT));
327 announce_grob (p->bracket_p_, p->req_l_drul_[START]->self_scm());
329 if (!p->req_l_drul_[STOP]) {
332 previous_p_[nspanners_i] = p->line_spanner_;
335 // position new pedal spanner below the current one
336 Side_position_interface::add_support(p->line_spanner_, previous_p_[nspanners_i - 1]);
341 p->req_l_drul_[START] = 0;
342 p->req_l_drul_[STOP] = 0;
346 Piano_pedal_engraver::finalize ()
348 for (Pedal_info*p = info_list_; p && p->name_; p ++)
351 && p->line_spanner_->immutable_property_alist_ == SCM_EOL)
352 p->line_spanner_ = 0;
353 if (p->line_spanner_)
355 p->finished_line_spanner_ = p->line_spanner_;
359 && p->bracket_p_->immutable_property_alist_ == SCM_EOL)
363 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
364 p->bracket_p_->suicide ();
372 Piano_pedal_engraver::stop_translation_timestep ()
374 for (Pedal_info*p = info_list_; p && p->name_; p ++)
376 p->finished_line_spanner_ = p->line_spanner_;
383 Piano_pedal_engraver::typeset_all ()
388 for (Pedal_info*p = info_list_; p->name_; p ++)
390 if (p->finished_line_spanner_
391 && p->finished_line_spanner_->immutable_property_alist_ == SCM_EOL)
392 p->finished_line_spanner_ = 0;
393 if (p->finished_bracket_p_
394 && p->finished_bracket_p_->immutable_property_alist_ == SCM_EOL)
395 p->finished_bracket_p_ = 0;
396 if (p->name_ == String ("Sustain"))
397 sustain = p->item_p_;
404 if (p->name_ != String ("Sustain"))
408 Side_position_interface::add_support (p->item_p_,sustain);
411 typeset_grob (p->item_p_);
415 if (p->finished_bracket_p_)
417 if (!p->finished_bracket_p_->get_bound (RIGHT))
419 p->finished_bracket_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
421 if (p->finished_line_spanner_)
422 add_bound_item (p->finished_line_spanner_,
423 p->finished_bracket_p_->get_bound (RIGHT));
425 typeset_grob (p->finished_bracket_p_);
426 p->finished_bracket_p_ =0;
429 if (p->finished_line_spanner_)
431 Side_position_interface::add_staff_support (p->finished_line_spanner_);
432 Grob * l = p->finished_line_spanner_->get_bound (LEFT );
433 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
435 p->finished_line_spanner_->set_bound (RIGHT, l);
437 p->finished_line_spanner_->set_bound (LEFT, r);
440 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
441 Item * ci = dynamic_cast<Item*>(cc);
442 p->finished_line_spanner_->set_bound (RIGHT, ci);
443 p->finished_line_spanner_->set_bound (LEFT, ci);
445 typeset_grob (p->finished_line_spanner_);
446 p->finished_line_spanner_ = 0;
452 Piano_pedal_engraver::start_translation_timestep ()
454 for (Pedal_info*p = info_list_; p->name_; p ++)
456 p->req_l_drul_[STOP] = 0;
457 p->req_l_drul_[START] = 0;
460 ENTER_DESCRIPTION(Piano_pedal_engraver,
461 /* descr */ "Engrave piano pedal symbols and brackets.",
462 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
463 /* acks */ "note-column-interface",
464 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",