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"
27 Urgh. This engraver is too complex. rewrite. --hwn
36 Event for currently running pedal.
38 Music* current_bracket_ev_;
41 Event for currently starting pedal, (necessary?
43 distinct from current_bracket_ev_, since current_bracket_ev_ only
44 necessary for brackets, not for text style.
51 Events that were found in this timestep.
53 Drul_array<Music*> event_drul_;
55 Spanner* bracket_; // A single portion of a pedal bracket
56 Spanner* finished_bracket_;
59 This grob contains all the pedals of the same type on the same staff
61 Spanner* line_spanner_;
62 Spanner* finished_line_spanner_;
66 class Piano_pedal_engraver : public Engraver
69 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
70 ~Piano_pedal_engraver ();
72 virtual void initialize ();
73 virtual void finalize ();
74 virtual bool try_music (Music*);
75 virtual void stop_translation_timestep ();
76 virtual void acknowledge_grob (Grob_info);
77 virtual void process_music ();
81 Pedal_info *info_list_;
84 Record a stack of the current pedal spanners, so if more than one pedal
85 occurs simultaneously then extra space can be added between them.
88 Link_array<Spanner> previous_;
90 void create_text_grobs (Pedal_info *p, bool);
91 void create_bracket_grobs (Pedal_info *p, bool);
96 Piano_pedal_engraver::Piano_pedal_engraver ()
102 Piano_pedal_engraver::initialize ()
106 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
108 info_list_ = new Pedal_info[sizeof (names)/ sizeof (const char*)];
109 Pedal_info *p = info_list_;
117 p->finished_bracket_ = 0;
118 p->line_spanner_ = 0;
119 p->finished_line_spanner_ = 0;
120 p->current_bracket_ev_ = 0;
121 p->event_drul_[START] = 0;
122 p->event_drul_[STOP] = 0;
130 Piano_pedal_engraver::~Piano_pedal_engraver ()
140 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
142 for (Pedal_info*p = info_list_; p && p->name_; p ++)
144 if (Note_column::has_interface (info.grob_))
146 if (p->line_spanner_)
148 Side_position_interface::add_support (p->line_spanner_, info.grob_);
149 add_bound_item (p->line_spanner_,info.grob_);
152 add_bound_item (p->bracket_,info.grob_);
153 if (p->finished_bracket_)
154 add_bound_item (p->finished_bracket_,info.grob_);
160 Piano_pedal_engraver::try_music (Music *m)
162 if (m->is_mus_type ("abort-event"))
164 for (Pedal_info*p = info_list_; p->name_; p ++)
166 p->event_drul_[START] = 0;
167 p->event_drul_[STOP] = 0;
170 p->bracket_->suicide ();
174 else if (m->is_mus_type ("pedal-event"))
176 for (Pedal_info*p = info_list_; p->name_; p ++)
178 String nm = p->name_ + String ("Event");
179 if (gh_equal_p (m->get_mus_property ("name") ,
180 gh_symbol2scm (nm.to_str0())))
182 Direction d = to_dir (m->get_mus_property ("span-direction"));
183 p->event_drul_[d] = m;
192 Piano_pedal_engraver::process_music ()
194 for (Pedal_info*p = info_list_; p && p->name_; p ++)
196 if (p->event_drul_[STOP] || p->event_drul_[START])
198 if (!p->line_spanner_)
200 String name = String (p->name_) + "PedalLineSpanner";
201 p->line_spanner_ = new Spanner (get_property (name.to_str0 ()));
203 Music * rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_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
212 ugh, code dup, should read grob to create from other
215 bracket: |_________/\____|
217 mixed: Ped. _____/\____|
221 String prop = String ("pedal") + p->name_ + "Style";
222 SCM style = get_property (prop.to_str0 ());
223 bool mixed = style == ly_symbol2scm ("mixed");
224 if (style == ly_symbol2scm ("text") ||
228 create_text_grobs (p, mixed);
230 if (style == ly_symbol2scm ("bracket") ||
233 create_bracket_grobs (p, mixed);
240 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
243 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
245 if (scm_ilength (strings) < 3)
247 Music * m = p->event_drul_[START];
248 if (!m) m = p->event_drul_ [STOP];
250 String msg = _ ("Need 3 strings for piano pedals. No pedal made. ");
252 m->origin()->warning (msg);
259 if (p->event_drul_[STOP] && p->event_drul_[START])
265 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
269 s = ly_cadr (strings);
271 p->start_ev_ = p->event_drul_[START];
274 else if (p->event_drul_[STOP])
280 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
284 s = ly_caddr (strings);
285 if (previous_.size ())
291 else if (p->event_drul_[START])
293 p->start_ev_ = p->event_drul_[START];
294 s = ly_car (strings);
298 Code dup?! see below.
300 if (previous_.size ())
301 // add extra space below the previous already-occuring pedal
302 Side_position_interface::add_support (p->line_spanner_,
304 previous_.push ( p->line_spanner_);
310 String propname = String (p->name_) + "Pedal";
312 SCM b = get_property (propname.to_str0 ());
313 p->item_ = new Item (b);
314 p->item_->set_grob_property ("text", s);
315 Axis_group_interface::add_element (p->line_spanner_, p->item_);
317 announce_grob (p->item_,
318 (p->event_drul_[START]
319 ? p->event_drul_[START]
320 : p->event_drul_[STOP])->self_scm ());
325 p->event_drul_[START] = 0;
326 p->event_drul_[STOP] = 0;
331 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
333 if (!p->bracket_ && p->event_drul_[STOP])
335 String msg =_f ("can't find start of piano pedal bracket: `%s'", p->name_);
336 p->event_drul_[STOP]->origin ()->warning (msg);
337 p->event_drul_[STOP] = 0;
340 if (p->event_drul_[STOP])
342 if (!p->event_drul_[START])
344 if (previous_.size())
348 assert (!p->finished_bracket_);
350 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
352 if (!p->bracket_->get_bound (RIGHT))
353 p->bracket_->set_bound (RIGHT, cmc);
356 Set properties so that the molecule-creating function will
357 know whether the right edge should be flared ___/
360 if (!p->event_drul_[START])
362 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
363 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_car (flare),
367 p->finished_bracket_ = p->bracket_;
369 p->current_bracket_ev_ = 0;
372 if (p->event_drul_[START])
374 p->start_ev_ = p->event_drul_[START];
375 p->current_bracket_ev_ = p->event_drul_[START];
377 p->bracket_ = new Spanner (get_property ("PianoPedalBracket"));
380 Set properties so that the molecule-creating function will
381 know whether the left edge should be flared \___
384 if (!p->finished_bracket_)
386 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
387 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_double2scm (0),gh_cdr (flare)));
391 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
392 so the molecule function will shorten the ____ line by the length of the Ped. text.
398 Mixed style: Store a pointer to the preceding text for use in
399 calculating the length of the line
404 WTF is pedal-text not the bound of the object? --hwn
407 p->bracket_->set_grob_property ("pedal-text", p->item_->self_scm ());
412 We do not use currentMusicalColumn for the left span-point.
413 If the column as accidentals (eg on a different stave), the
414 currentMusicalColumn is too wide, making the bracket too big.
418 Hmm. What do we do when there are no notes when the spanner starts?
422 what about the right span point?
425 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
426 announce_grob (p->bracket_, p->event_drul_[START]->self_scm ());
428 if (!p->event_drul_[STOP])
434 // position new pedal spanner below the current one
436 if (previous_.size())
437 Side_position_interface::add_support (p->line_spanner_, previous_.top());
439 previous_.push (p->line_spanner_);
443 p->event_drul_[START] = 0;
444 p->event_drul_[STOP] = 0;
448 Piano_pedal_engraver::finalize ()
450 for (Pedal_info*p = info_list_; p && p->name_; p ++)
456 && !p->line_spanner_->live())
457 p->line_spanner_ = 0;
459 if (p->line_spanner_)
461 p->finished_line_spanner_ = p->line_spanner_;
465 && !p->bracket_->live())
470 p->current_bracket_ev_->origin ()->warning (_ ("unterminated pedal bracket"));
471 p->bracket_->suicide ();
479 Piano_pedal_engraver::stop_translation_timestep ()
481 for (Pedal_info*p = info_list_; p && p->name_; p ++)
485 p->finished_line_spanner_ = p->line_spanner_;
486 p->line_spanner_ = 0;
492 for (Pedal_info*p = info_list_; p->name_; p ++)
494 p->event_drul_[STOP] = 0;
495 p->event_drul_[START] = 0;
501 Piano_pedal_engraver::typeset_all ()
504 for (Pedal_info*p = info_list_; p->name_; p ++)
509 if (p->finished_line_spanner_
510 && !p->finished_line_spanner_->live ())
511 p->finished_line_spanner_ = 0;
512 if (p->finished_bracket_
513 && !p->finished_bracket_->live())
514 p->finished_bracket_ = 0;
517 if (p->name_ == String ("Sustain"))
525 if (p->name_ != String ("Sustain") && sustain)
527 Side_position_interface::add_support (p->item_,sustain);
529 typeset_grob (p->item_);
533 if (p->finished_bracket_)
535 Grob * r = p->finished_bracket_->get_bound (RIGHT);
538 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
541 typeset_grob (p->finished_bracket_);
543 p->finished_bracket_ =0;
546 if (p->finished_line_spanner_)
548 Side_position_interface::add_staff_support (p->finished_line_spanner_);
549 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
550 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
552 p->finished_line_spanner_->set_bound (RIGHT, l);
554 p->finished_line_spanner_->set_bound (LEFT, r);
557 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
558 Item * ci = dynamic_cast<Item*> (cc);
559 p->finished_line_spanner_->set_bound (RIGHT, ci);
560 p->finished_line_spanner_->set_bound (LEFT, ci);
562 typeset_grob (p->finished_line_spanner_);
563 p->finished_line_spanner_ = 0;
568 ENTER_DESCRIPTION (Piano_pedal_engraver,
569 /* descr */ "Engrave piano pedal symbols and brackets.",
570 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
571 /* accepts */ "pedal-event abort-event",
572 /* acks */ "note-column-interface",
573 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings pedalSostenutoStyle pedalSustainStyle pedalUnaCordaStyle",