2 piano-pedal-engraver.cc -- implement Piano_pedal_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2003 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 Link_array<Spanner> previous_;
71 Left and right flare widths of a \___/, as specified by the grob
74 UGR. No GC protection.
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_;
99 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
106 p->finished_bracket_ = 0;
107 p->line_spanner_ = 0;
108 p->finished_line_spanner_ = 0;
109 p->current_bracket_req_ = 0;
110 p->req_l_drul_[START] = 0;
111 p->req_l_drul_[STOP] = 0;
119 Piano_pedal_engraver::~Piano_pedal_engraver ()
129 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
131 for (Pedal_info*p = info_list_; p && p->name_; p ++)
133 if (Note_column::has_interface (info.grob_))
135 if (p->line_spanner_)
137 Side_position_interface::add_support (p->line_spanner_, info.grob_);
139 add_bound_item (p->line_spanner_,info.grob_);
142 add_bound_item (p->bracket_,info.grob_);
149 Piano_pedal_engraver::try_music (Music *m)
151 if (m->is_mus_type ("abort-event"))
153 for (Pedal_info*p = info_list_; p->name_; p ++)
155 p->req_l_drul_[START] = 0;
156 p->req_l_drul_[STOP] = 0;
159 p->bracket_->suicide (); /* as in dynamic-engraver.cc */
163 else if (m->is_mus_type ("pedal-event"))
165 for (Pedal_info*p = info_list_; p->name_; p ++)
167 String nm = p->name_ + String ("Event");
168 if (gh_equal_p (m->get_mus_property ("name") ,
169 gh_symbol2scm (nm.to_str0())))
171 Direction d = to_dir (m->get_mus_property ("span-direction"));
172 p->req_l_drul_[d] = m;
181 Piano_pedal_engraver::process_acknowledged_grobs ()
183 for (Pedal_info*p = info_list_; p && p->name_; p ++)
185 if (p->req_l_drul_[STOP] || p->req_l_drul_[START])
187 if (!p->line_spanner_)
189 String name = String (p->name_) + "PedalLineSpanner";
190 p->line_spanner_ = new Spanner (get_property (name.to_str0 ()));
193 Music * rq = (p->req_l_drul_[START] ? p->req_l_drul_[START] : p->req_l_drul_[STOP]);
194 announce_grob (p->line_spanner_, rq->self_scm ());
197 /* Choose the appropriate grobs to add to the line spanner
198 These can be text items or text-spanners
200 SCM type = ly_cdr (scm_assoc (ly_symbol2scm ("pedal-type"),
201 get_property ( (String (p->name_) + "Pedal").to_str0 ())));
202 if (type == ly_symbol2scm ("text") || // Ped. *Ped. *
203 type == ly_symbol2scm ("mixed") ) // Ped. _____/\____|
206 create_text_grobs (p, type);
208 if (type == ly_symbol2scm ("bracket") || // |_________/\____|
209 type == ly_symbol2scm ("mixed") )
211 create_bracket_grobs (p, type);
219 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, SCM pedaltype)
223 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
225 if (scm_ilength (strings) < 3)
227 Music * m = p->req_l_drul_[START];
228 if (!m) m = p->req_l_drul_ [STOP];
230 String msg = _ ("Need 3 strings for piano pedals. No pedal made. ");
232 m->origin().warning (msg);
240 if (p->req_l_drul_[STOP] && p->req_l_drul_[START])
242 if (pedaltype == ly_symbol2scm ("text"))
246 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
250 s = ly_cadr (strings);
252 p->start_req_ = p->req_l_drul_[START];
255 else if (p->req_l_drul_[STOP])
257 if (pedaltype == ly_symbol2scm ("text"))
261 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
265 s = ly_caddr (strings);
267 if (previous_.size ())
273 else if (p->req_l_drul_[START])
275 p->start_req_ = p->req_l_drul_[START];
276 s = ly_car (strings);
277 if (pedaltype == ly_symbol2scm ("text"))
282 Code dup?! see below.
284 if (previous_.size ())
285 // add extra space below the previous already-occuring pedal
286 Side_position_interface::add_support (p->line_spanner_,
288 previous_.push ( p->line_spanner_);
294 String propname = String (p->name_) + "Pedal";
295 b = get_property (propname.to_str0 ());
296 p->item_ = new Item (b);
297 p->item_->set_grob_property ("text", s);
298 Axis_group_interface::add_element (p->line_spanner_, p->item_);
300 announce_grob (p->item_,
301 (p->req_l_drul_[START]
302 ? p->req_l_drul_[START]
303 : p->req_l_drul_[STOP])->self_scm ());
307 if (pedaltype == ly_symbol2scm ("text"))
309 p->req_l_drul_[START] = 0;
310 p->req_l_drul_[STOP] = 0;
315 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, SCM pedaltype)
318 if (p->req_l_drul_[STOP])
322 p->req_l_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
324 else if (!p->req_l_drul_[START])
327 if (previous_.size())
331 assert (!p->finished_bracket_ && p->bracket_);
333 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
334 p->bracket_->set_bound (RIGHT, cmc);
337 Set properties so that the molecule-creating function will
338 know whether the right edge should be flared ___/
340 SCM eleft = ly_car (p->bracket_->get_grob_property ("edge-widen"));
341 SCM eright = (p->req_l_drul_[START] ? edge_width_drul_[RIGHT] : gh_double2scm (0));
342 p->bracket_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
344 p->finished_bracket_ = p->bracket_;
346 p->current_bracket_req_ = 0;
347 p->start_req_ = p->req_l_drul_[START];
350 if (p->req_l_drul_[START])
352 p->start_req_ = p->req_l_drul_[START];
353 p->current_bracket_req_ = p->req_l_drul_[START];
355 p->bracket_ = new Spanner (get_property ("PianoPedalBracket"));
358 Set properties so that the molecule-creating function will
359 know whether the left edge should be flared \___
362 SCM ew = p->bracket_->get_grob_property ("edge-widen");
365 WTF is this doing here?
367 This must go to the backend.
371 edge_width_drul_[LEFT] = ly_car (ew);
372 edge_width_drul_[RIGHT] = ly_cdr (ew);
374 SCM eleft = ( (bool) p->req_l_drul_[STOP] ?
375 edge_width_drul_[LEFT] :
377 SCM eright = gh_double2scm (0);
378 p->bracket_->set_grob_property ("edge-widen", gh_cons (eleft, eright));
380 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
381 so the molecule function will shorten the ____ line by the length of the Ped. text.
384 p->bracket_->set_grob_property ("text-start",
385 pedaltype == ly_symbol2scm ("mixed") ?
386 gh_bool2scm ( (bool) ! p->req_l_drul_[STOP]) :
387 gh_bool2scm (false));
390 Mixed style: Store a pointer to the preceding text for use in
391 calculating the length of the line
394 p->bracket_->set_grob_property ("pedal-text", p->item_->self_scm ());
396 p->bracket_->set_bound (LEFT, unsmob_grob (get_property ("currentMusicalColumn")));
397 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
399 add_bound_item (p->line_spanner_, p->bracket_->get_bound (LEFT));
400 announce_grob (p->bracket_, p->req_l_drul_[START]->self_scm ());
402 if (!p->req_l_drul_[STOP])
409 if (previous_.size())
410 // position new pedal spanner below the current one
411 Side_position_interface::add_support (p->line_spanner_, previous_.top());
413 previous_.push (p->line_spanner_);
417 p->req_l_drul_[START] = 0;
418 p->req_l_drul_[STOP] = 0;
422 Piano_pedal_engraver::finalize ()
424 for (Pedal_info*p = info_list_; p && p->name_; p ++)
430 && !p->line_spanner_->live())
431 p->line_spanner_ = 0;
433 if (p->line_spanner_)
435 p->finished_line_spanner_ = p->line_spanner_;
439 && !p->bracket_->live())
443 p->current_bracket_req_->origin ()->warning (_ ("unterminated pedal bracket"));
444 p->bracket_->suicide ();
452 Piano_pedal_engraver::stop_translation_timestep ()
454 for (Pedal_info*p = info_list_; p && p->name_; p ++)
458 p->finished_line_spanner_ = p->line_spanner_;
459 p->line_spanner_ = 0;
468 Piano_pedal_engraver::typeset_all ()
471 for (Pedal_info*p = info_list_; p->name_; p ++)
476 if (p->finished_line_spanner_
477 && !p->finished_line_spanner_->live ())
478 p->finished_line_spanner_ = 0;
479 if (p->finished_bracket_
480 && !p->finished_bracket_->live())
481 p->finished_bracket_ = 0;
484 if (p->name_ == String ("Sustain"))
492 if (p->name_ != String ("Sustain"))
496 Side_position_interface::add_support (p->item_,sustain);
499 typeset_grob (p->item_);
503 if (p->finished_bracket_)
505 Grob * r = p->finished_bracket_->get_bound (RIGHT);
508 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
511 typeset_grob (p->finished_bracket_);
512 p->finished_bracket_ =0;
515 if (p->finished_line_spanner_)
517 Side_position_interface::add_staff_support (p->finished_line_spanner_);
518 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
519 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
521 p->finished_line_spanner_->set_bound (RIGHT, l);
523 p->finished_line_spanner_->set_bound (LEFT, r);
526 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
527 Item * ci = dynamic_cast<Item*> (cc);
528 p->finished_line_spanner_->set_bound (RIGHT, ci);
529 p->finished_line_spanner_->set_bound (LEFT, ci);
531 typeset_grob (p->finished_line_spanner_);
532 p->finished_line_spanner_ = 0;
538 Piano_pedal_engraver::start_translation_timestep ()
540 for (Pedal_info*p = info_list_; p->name_; p ++)
542 p->req_l_drul_[STOP] = 0;
543 p->req_l_drul_[START] = 0;
546 ENTER_DESCRIPTION (Piano_pedal_engraver,
547 /* descr */ "Engrave piano pedal symbols and brackets.",
548 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
549 /* accepts */ "pedal-event abort-event",
550 /* acks */ "note-column-interface",
551 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings",