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
12 #include "engraver.hh"
13 #include "musical-request.hh"
16 #include "lily-guile.hh"
17 #include "side-position-interface.hh"
18 #include "staff-symbol-referencer.hh"
20 #include "axis-group-interface.hh"
21 #include "translator-group.hh"
22 #include "directional-element-interface.hh"
23 #include "note-column.hh"
28 Span_req* start_req_l_;
29 Drul_array<Span_req*> req_l_drul_;
31 Spanner* bracket_p_; // A single portion of a pedal bracket
32 Spanner* finished_bracket_p_;
35 This grob contains all the pedals of the same type on the same staff
37 Spanner* line_spanner_;
38 Spanner* finished_line_spanner_;
39 Span_req* current_bracket_req_;
43 class Piano_pedal_engraver : public Engraver
46 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
47 ~Piano_pedal_engraver ();
49 virtual void initialize ();
50 virtual void finalize ();
51 virtual bool try_music (Music*);
52 virtual void stop_translation_timestep ();
53 virtual void start_translation_timestep ();
54 virtual void acknowledge_grob (Grob_info);
55 virtual void create_grobs ();
59 Pedal_info *info_list_;
62 Record a stack of the current pedal spanners, so if more than one pedal
63 occurs simultaneously then extra space can be added between them.
66 Why 4, why not 3. Why not 3423 ? ---hwn.
69 Spanner *previous_p_ [4];
74 Left and right flare widths of a \___/, as specified by the grob
77 Drul_array<SCM> edge_width_drul_;
79 void create_text_grobs (Pedal_info *p, SCM pedaltype);
80 void create_bracket_grobs (Pedal_info *p, SCM pedaltype);
85 Piano_pedal_engraver::Piano_pedal_engraver ()
91 Piano_pedal_engraver::initialize ()
93 info_list_ = new Pedal_info[4];
94 Pedal_info *p = info_list_;
97 for (int i = 0; i < 3; ++i)
101 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
108 p->finished_bracket_p_ = 0;
109 p->line_spanner_ = 0;
110 p->finished_line_spanner_ = 0;
111 p->current_bracket_req_ = 0;
112 p->req_l_drul_[START] = 0;
113 p->req_l_drul_[STOP] = 0;
121 Piano_pedal_engraver::~Piano_pedal_engraver ()
131 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
133 for (Pedal_info*p = info_list_; p && p->name_; p ++)
135 Grob *gs[] = {p->item_p_,
137 for (int i = 0; i < 2 ; i++)
140 if (g && p->line_spanner_)
142 if (Note_column::has_interface (info.grob_l_))
144 Side_position_interface::add_support (p->line_spanner_, info.grob_l_);
145 add_bound_item (p->line_spanner_,info.grob_l_);
148 add_bound_item (p->bracket_p_,info.grob_l_);
151 What the h*ll is this supposed to do? --hwn
154 if (Side_position_interface::get_axis (g) == X_AXIS
155 && !g->get_parent (Y_AXIS))
156 g->set_parent (info.grob_l_, Y_AXIS);
165 Piano_pedal_engraver::try_music (Music *m)
167 if (Span_req * s = dynamic_cast<Span_req*> (m))
169 for (Pedal_info*p = info_list_; p->name_; p ++)
171 if (ly_scm2string (s->get_mus_property ("span-type")) == "abort")
173 p->req_l_drul_[START] = 0;
174 p->req_l_drul_[STOP] = 0;
177 p->bracket_p_->suicide (); /* as in dynamic-engraver.cc */
180 if (scm_equal_p (s->get_mus_property ("span-type"),
181 ly_str02scm (p->name_))==SCM_BOOL_T)
183 p->req_l_drul_[s->get_span_dir ()] = s;
192 Piano_pedal_engraver::create_grobs ()
194 for (Pedal_info*p = info_list_; p && p->name_; p ++)
196 if (p->req_l_drul_[STOP] || p->req_l_drul_[START])
198 if (!p->line_spanner_)
200 String name = String (p->name_) + "PedalLineSpanner";
201 p->line_spanner_ = new Spanner (get_property (name.ch_C ()));
202 Side_position_interface::set_axis (p->line_spanner_, Y_AXIS);
203 Music * rq = (p->req_l_drul_[START] ? p->req_l_drul_[START] : p->req_l_drul_[STOP]);
204 announce_grob (p->line_spanner_, rq->self_scm ());
207 /* Choose the appropriate grobs to add to the line spanner
208 These can be text items or text-spanners
210 SCM type = ly_cdr (scm_assoc (ly_symbol2scm ("pedal-type"),
211 get_property ( (String (p->name_) + "Pedal").ch_C ())));
212 if (type == ly_symbol2scm ("text") || // Ped. *Ped. *
213 type == ly_symbol2scm ("mixed") ) // Ped. _____/\____|
216 create_text_grobs (p, type);
218 if (type == ly_symbol2scm ("bracket") || // |_________/\____|
219 type == ly_symbol2scm ("mixed") )
221 create_bracket_grobs (p, type);
229 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, SCM pedaltype)
233 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").ch_C ());
235 if (scm_ilength (strings) >= 3)
237 if (p->req_l_drul_[STOP] && p->req_l_drul_[START])
239 if (pedaltype == ly_symbol2scm ("text"))
241 if (!p->start_req_l_)
243 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
247 s = ly_cadr (strings);
249 p->start_req_l_ = p->req_l_drul_[START];
252 else if (p->req_l_drul_[STOP])
254 if (pedaltype == ly_symbol2scm ("text"))
256 if (!p->start_req_l_)
258 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
262 s = ly_caddr (strings);
268 else if (p->req_l_drul_[START])
270 p->start_req_l_ = p->req_l_drul_[START];
271 s = ly_car (strings);
272 if (pedaltype == ly_symbol2scm ("text"))
275 previous_p_[spanner_count_] = p->line_spanner_;
276 if (spanner_count_ > 1)
277 // add extra space below the previous already-occuring pedal
278 Side_position_interface::add_support (p->line_spanner_,
279 previous_p_[spanner_count_ - 1]);
285 String propname = String (p->name_) + "Pedal";
286 b = get_property (propname.ch_C ());
287 p->item_p_ = new Item (b);
288 p->item_p_->set_grob_property ("text", s);
289 Axis_group_interface::add_element (p->line_spanner_, p->item_p_);
291 announce_grob (p->item_p_,
292 (p->req_l_drul_[START]
293 ? p->req_l_drul_[START]
294 : p->req_l_drul_[STOP])->self_scm ());
297 if (pedaltype == ly_symbol2scm ("text"))
299 p->req_l_drul_[START] = 0;
300 p->req_l_drul_[STOP] = 0;
306 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, SCM pedaltype)
309 if (p->req_l_drul_[STOP])
311 if (!p->start_req_l_)
313 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
315 else if (!p->req_l_drul_[START])
318 assert (!p->finished_bracket_p_ && p->bracket_p_);
320 p->bracket_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
323 Set properties so that the molecule-creating function will
324 know whether the right edge should be flared ___/
326 SCM eleft = ly_car (p->bracket_p_->get_grob_property ("edge-width"));
327 SCM eright = (p->req_l_drul_[START] ? edge_width_drul_[RIGHT] : gh_double2scm (0));
328 p->bracket_p_->set_grob_property ("edge-width", gh_cons (eleft, eright));
330 p->finished_bracket_p_ = p->bracket_p_;
332 p->current_bracket_req_ = 0;
333 p->start_req_l_ = p->req_l_drul_[START];
336 if (p->req_l_drul_[START])
338 p->start_req_l_ = p->req_l_drul_[START];
339 p->current_bracket_req_ = p->req_l_drul_[START];
341 p->bracket_p_ = new Spanner (get_property ("PianoPedalBracket"));
344 Set properties so that the molecule-creating function will
345 know whether the left edge should be flared \___
348 SCM ew = p->bracket_p_->get_grob_property ("edge-width");
349 edge_width_drul_[LEFT] = ly_car (ew);
350 edge_width_drul_[RIGHT] = ly_cdr (ew);
352 SCM eleft = ( (bool) p->req_l_drul_[STOP] ?
353 edge_width_drul_[LEFT] :
355 SCM eright = gh_double2scm (0);
356 p->bracket_p_->set_grob_property ("edge-width", gh_cons (eleft, eright));
358 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
359 so the molecule function will shorten the ____ line by the length of the Ped. text.
362 p->bracket_p_->set_grob_property ("text-start",
363 pedaltype == ly_symbol2scm ("mixed") ?
364 gh_bool2scm ( (bool) ! p->req_l_drul_[STOP]) :
365 gh_bool2scm (false));
367 p->bracket_p_->set_parent (p->item_p_, Y_AXIS);
369 p->bracket_p_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
370 Axis_group_interface::add_element (p->line_spanner_, p->bracket_p_);
372 add_bound_item (p->line_spanner_, p->bracket_p_->get_bound (LEFT));
373 announce_grob (p->bracket_p_, p->req_l_drul_[START]->self_scm ());
375 if (!p->req_l_drul_[STOP])
378 previous_p_[spanner_count_] = p->line_spanner_;
380 if (spanner_count_ > 1)
381 // position new pedal spanner below the current one
382 Side_position_interface::add_support (p->line_spanner_, previous_p_[spanner_count_ - 1]);
386 p->req_l_drul_[START] = 0;
387 p->req_l_drul_[STOP] = 0;
391 Piano_pedal_engraver::finalize ()
393 for (Pedal_info*p = info_list_; p && p->name_; p ++)
399 && p->line_spanner_->immutable_property_alist_ == SCM_EOL)
400 p->line_spanner_ = 0;
402 if (p->line_spanner_)
404 p->finished_line_spanner_ = p->line_spanner_;
408 && p->bracket_p_->immutable_property_alist_ == SCM_EOL)
412 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
413 p->bracket_p_->suicide ();
421 Piano_pedal_engraver::stop_translation_timestep ()
423 for (Pedal_info*p = info_list_; p && p->name_; p ++)
427 p->finished_line_spanner_ = p->line_spanner_;
428 p->line_spanner_ = 0;
437 Piano_pedal_engraver::typeset_all ()
440 for (Pedal_info*p = info_list_; p->name_; p ++)
445 if (p->finished_line_spanner_
446 && p->finished_line_spanner_->immutable_property_alist_ == SCM_EOL)
447 p->finished_line_spanner_ = 0;
448 if (p->finished_bracket_p_
449 && p->finished_bracket_p_->immutable_property_alist_ == SCM_EOL)
450 p->finished_bracket_p_ = 0;
453 if (p->name_ == String ("Sustain"))
454 sustain = p->item_p_;
461 if (p->name_ != String ("Sustain"))
465 Side_position_interface::add_support (p->item_p_,sustain);
468 typeset_grob (p->item_p_);
472 if (p->finished_bracket_p_)
474 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
475 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
478 p->finished_bracket_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
481 typeset_grob (p->finished_bracket_p_);
482 p->finished_bracket_p_ =0;
485 if (p->finished_line_spanner_)
487 Side_position_interface::add_staff_support (p->finished_line_spanner_);
488 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
489 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
491 p->finished_line_spanner_->set_bound (RIGHT, l);
493 p->finished_line_spanner_->set_bound (LEFT, r);
496 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
497 Item * ci = dynamic_cast<Item*> (cc);
498 p->finished_line_spanner_->set_bound (RIGHT, ci);
499 p->finished_line_spanner_->set_bound (LEFT, ci);
501 typeset_grob (p->finished_line_spanner_);
502 p->finished_line_spanner_ = 0;
508 Piano_pedal_engraver::start_translation_timestep ()
510 for (Pedal_info*p = info_list_; p->name_; p ++)
512 p->req_l_drul_[STOP] = 0;
513 p->req_l_drul_[START] = 0;
516 ENTER_DESCRIPTION (Piano_pedal_engraver,
517 /* descr */ "Engrave piano pedal symbols and brackets.",
518 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
519 /* acks */ "note-column-interface",
520 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",