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"
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"
29 Drul_array<Music*> req_l_drul_;
31 Spanner* bracket_; // A single portion of a pedal bracket
32 Spanner* finished_bracket_;
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 Music* 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 process_acknowledged_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_ [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_ = 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 if (Note_column::has_interface (info.grob_))
137 if (p->line_spanner_)
139 Side_position_interface::add_support (p->line_spanner_, info.grob_);
141 add_bound_item (p->line_spanner_,info.grob_);
144 add_bound_item (p->bracket_,info.grob_);
151 Piano_pedal_engraver::try_music (Music *m)
153 if (m->is_mus_type ("abort-event"))
155 for (Pedal_info*p = info_list_; p->name_; p ++)
157 p->req_l_drul_[START] = 0;
158 p->req_l_drul_[STOP] = 0;
161 p->bracket_->suicide (); /* as in dynamic-engraver.cc */
165 else if (m->is_mus_type ("pedal-event"))
167 for (Pedal_info*p = info_list_; p->name_; p ++)
169 String nm = p->name_ + String ("Event");
170 if (gh_equal_p (m->get_mus_property ("name") ,
171 gh_symbol2scm (nm.to_str0())))
173 Direction d = to_dir (m->get_mus_property ("span-direction"));
174 p->req_l_drul_[d] = m;
183 Piano_pedal_engraver::process_acknowledged_grobs ()
185 for (Pedal_info*p = info_list_; p && p->name_; p ++)
187 if (p->req_l_drul_[STOP] || p->req_l_drul_[START])
189 if (!p->line_spanner_)
191 String name = String (p->name_) + "PedalLineSpanner";
192 p->line_spanner_ = new Spanner (get_property (name.to_str0 ()));
195 Music * rq = (p->req_l_drul_[START] ? p->req_l_drul_[START] : p->req_l_drul_[STOP]);
196 announce_grob (p->line_spanner_, rq->self_scm ());
199 /* Choose the appropriate grobs to add to the line spanner
200 These can be text items or text-spanners
202 SCM type = ly_cdr (scm_assoc (ly_symbol2scm ("pedal-type"),
203 get_property ( (String (p->name_) + "Pedal").to_str0 ())));
204 if (type == ly_symbol2scm ("text") || // Ped. *Ped. *
205 type == ly_symbol2scm ("mixed") ) // Ped. _____/\____|
208 create_text_grobs (p, type);
210 if (type == ly_symbol2scm ("bracket") || // |_________/\____|
211 type == ly_symbol2scm ("mixed") )
213 create_bracket_grobs (p, type);
221 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, SCM pedaltype)
225 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
227 if (scm_ilength (strings) >= 3)
229 if (p->req_l_drul_[STOP] && p->req_l_drul_[START])
231 if (pedaltype == ly_symbol2scm ("text"))
235 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
239 s = ly_cadr (strings);
241 p->start_req_ = p->req_l_drul_[START];
244 else if (p->req_l_drul_[STOP])
246 if (pedaltype == ly_symbol2scm ("text"))
250 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
254 s = ly_caddr (strings);
260 else if (p->req_l_drul_[START])
262 p->start_req_ = p->req_l_drul_[START];
263 s = ly_car (strings);
264 if (pedaltype == ly_symbol2scm ("text"))
267 previous_[spanner_count_] = p->line_spanner_;
268 if (spanner_count_ > 1)
269 // add extra space below the previous already-occuring pedal
270 Side_position_interface::add_support (p->line_spanner_,
271 previous_[spanner_count_ - 1]);
277 String propname = String (p->name_) + "Pedal";
278 b = get_property (propname.to_str0 ());
279 p->item_ = new Item (b);
280 p->item_->set_grob_property ("text", s);
281 Axis_group_interface::add_element (p->line_spanner_, p->item_);
283 announce_grob (p->item_,
284 (p->req_l_drul_[START]
285 ? p->req_l_drul_[START]
286 : p->req_l_drul_[STOP])->self_scm ());
289 if (pedaltype == ly_symbol2scm ("text"))
291 p->req_l_drul_[START] = 0;
292 p->req_l_drul_[STOP] = 0;
298 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, SCM pedaltype)
301 if (p->req_l_drul_[STOP])
305 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
307 else if (!p->req_l_drul_[START])
310 assert (!p->finished_bracket_ && p->bracket_);
312 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
313 p->bracket_->set_bound (RIGHT, cmc);
316 Set properties so that the molecule-creating function will
317 know whether the right edge should be flared ___/
319 SCM eleft = ly_car (p->bracket_->get_grob_property ("edge-widen"));
320 SCM eright = (p->req_l_drul_[START] ? edge_width_drul_[RIGHT] : gh_double2scm (0));
321 p->bracket_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
323 p->finished_bracket_ = p->bracket_;
325 p->current_bracket_req_ = 0;
326 p->start_req_ = p->req_l_drul_[START];
329 if (p->req_l_drul_[START])
331 p->start_req_ = p->req_l_drul_[START];
332 p->current_bracket_req_ = p->req_l_drul_[START];
334 p->bracket_ = new Spanner (get_property ("PianoPedalBracket"));
337 Set properties so that the molecule-creating function will
338 know whether the left edge should be flared \___
341 SCM ew = p->bracket_->get_grob_property ("edge-widen");
342 edge_width_drul_[LEFT] = ly_car (ew);
343 edge_width_drul_[RIGHT] = ly_cdr (ew);
345 SCM eleft = ( (bool) p->req_l_drul_[STOP] ?
346 edge_width_drul_[LEFT] :
348 SCM eright = gh_double2scm (0);
349 p->bracket_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
351 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
352 so the molecule function will shorten the ____ line by the length of the Ped. text.
355 p->bracket_->set_grob_property ("text-start",
356 pedaltype == ly_symbol2scm ("mixed") ?
357 gh_bool2scm ( (bool) ! p->req_l_drul_[STOP]) :
358 gh_bool2scm (false));
361 Mixed style: Store a pointer to the preceding text for use in
362 calculating the length of the line
365 p->bracket_->set_grob_property ("pedal-text", p->item_->self_scm ());
367 p->bracket_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
368 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
370 add_bound_item (p->line_spanner_, p->bracket_->get_bound (LEFT));
371 announce_grob (p->bracket_, p->req_l_drul_[START]->self_scm ());
373 if (!p->req_l_drul_[STOP])
376 previous_[spanner_count_] = p->line_spanner_;
378 if (spanner_count_ > 1)
379 // position new pedal spanner below the current one
380 Side_position_interface::add_support (p->line_spanner_, previous_[spanner_count_ - 1]);
384 p->req_l_drul_[START] = 0;
385 p->req_l_drul_[STOP] = 0;
389 Piano_pedal_engraver::finalize ()
391 for (Pedal_info*p = info_list_; p && p->name_; p ++)
397 && !p->line_spanner_->live())
398 p->line_spanner_ = 0;
400 if (p->line_spanner_)
402 p->finished_line_spanner_ = p->line_spanner_;
406 && !p->bracket_->live())
410 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
411 p->bracket_->suicide ();
419 Piano_pedal_engraver::stop_translation_timestep ()
421 for (Pedal_info*p = info_list_; p && p->name_; p ++)
425 p->finished_line_spanner_ = p->line_spanner_;
426 p->line_spanner_ = 0;
435 Piano_pedal_engraver::typeset_all ()
438 for (Pedal_info*p = info_list_; p->name_; p ++)
443 if (p->finished_line_spanner_
444 && !p->finished_line_spanner_->live ())
445 p->finished_line_spanner_ = 0;
446 if (p->finished_bracket_
447 && !p->finished_bracket_->live())
448 p->finished_bracket_ = 0;
451 if (p->name_ == String ("Sustain"))
459 if (p->name_ != String ("Sustain"))
463 Side_position_interface::add_support (p->item_,sustain);
466 typeset_grob (p->item_);
470 if (p->finished_bracket_)
472 Grob * r = p->finished_bracket_->get_bound (RIGHT);
475 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
478 typeset_grob (p->finished_bracket_);
479 p->finished_bracket_ =0;
482 if (p->finished_line_spanner_)
484 Side_position_interface::add_staff_support (p->finished_line_spanner_);
485 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
486 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
488 p->finished_line_spanner_->set_bound (RIGHT, l);
490 p->finished_line_spanner_->set_bound (LEFT, r);
493 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
494 Item * ci = dynamic_cast<Item*> (cc);
495 p->finished_line_spanner_->set_bound (RIGHT, ci);
496 p->finished_line_spanner_->set_bound (LEFT, ci);
498 typeset_grob (p->finished_line_spanner_);
499 p->finished_line_spanner_ = 0;
505 Piano_pedal_engraver::start_translation_timestep ()
507 for (Pedal_info*p = info_list_; p->name_; p ++)
509 p->req_l_drul_[STOP] = 0;
510 p->req_l_drul_[START] = 0;
513 ENTER_DESCRIPTION (Piano_pedal_engraver,
514 /* descr */ "Engrave piano pedal symbols and brackets.",
515 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
516 /* accepts */ "pedal-event abort-event",
517 /* acks */ "note-column-interface",
518 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",