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"
31 Event for currently running pedal.
33 Music* current_bracket_ev_;
35 Event for currently starting pedal, (necessary?
37 distinct from current_bracket_ev_, since current_bracket_ev_ only
38 necessary for brackets, not for text style.
45 Events that were found in this timestep.
47 Drul_array<Music*> event_drul_;
49 Spanner* bracket_; // A single portion of a pedal bracket
50 Spanner* finished_bracket_;
53 This grob contains all the pedals of the same type on the same staff
55 Spanner* line_spanner_;
56 Spanner* finished_line_spanner_;
60 class Piano_pedal_engraver : public Engraver
63 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
64 ~Piano_pedal_engraver ();
66 virtual void initialize ();
67 virtual void finalize ();
68 virtual bool try_music (Music*);
69 virtual void stop_translation_timestep ();
70 virtual void acknowledge_grob (Grob_info);
71 virtual void process_music ();
75 Pedal_info *info_list_;
78 Record a stack of the current pedal spanners, so if more than one pedal
79 occurs simultaneously then extra space can be added between them.
82 Link_array<Spanner> previous_;
86 void create_text_grobs (Pedal_info *p, bool);
87 void create_bracket_grobs (Pedal_info *p, bool);
92 Piano_pedal_engraver::Piano_pedal_engraver ()
98 Piano_pedal_engraver::initialize ()
102 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
104 info_list_ = new Pedal_info[sizeof (names)/ sizeof (const char*)];
105 Pedal_info *p = info_list_;
113 p->finished_bracket_ = 0;
114 p->line_spanner_ = 0;
115 p->finished_line_spanner_ = 0;
116 p->current_bracket_ev_ = 0;
117 p->event_drul_[START] = 0;
118 p->event_drul_[STOP] = 0;
126 Piano_pedal_engraver::~Piano_pedal_engraver ()
136 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
138 for (Pedal_info*p = info_list_; p && p->name_; p ++)
140 if (Note_column::has_interface (info.grob_))
142 if (p->line_spanner_)
144 Side_position_interface::add_support (p->line_spanner_, info.grob_);
145 add_bound_item (p->line_spanner_,info.grob_);
148 add_bound_item (p->bracket_,info.grob_);
155 Piano_pedal_engraver::try_music (Music *m)
157 if (m->is_mus_type ("abort-event"))
159 for (Pedal_info*p = info_list_; p->name_; p ++)
161 p->event_drul_[START] = 0;
162 p->event_drul_[STOP] = 0;
165 p->bracket_->suicide ();
169 else if (m->is_mus_type ("pedal-event"))
171 for (Pedal_info*p = info_list_; p->name_; p ++)
173 String nm = p->name_ + String ("Event");
174 if (gh_equal_p (m->get_mus_property ("name") ,
175 gh_symbol2scm (nm.to_str0())))
177 Direction d = to_dir (m->get_mus_property ("span-direction"));
178 p->event_drul_[d] = m;
187 Piano_pedal_engraver::process_music ()
189 for (Pedal_info*p = info_list_; p && p->name_; p ++)
191 if (p->event_drul_[STOP] || p->event_drul_[START])
193 if (!p->line_spanner_)
195 String name = String (p->name_) + "PedalLineSpanner";
196 p->line_spanner_ = new Spanner (get_property (name.to_str0 ()));
199 Music * rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
200 announce_grob (p->line_spanner_, rq->self_scm ());
203 /* Choose the appropriate grobs to add to the line spanner
204 These can be text items or text-spanners
208 ugh, code dup, should read grob to create from other
211 bracket: |_________/\____|
213 mixed: Ped. _____/\____|
217 String prop = String ("pedal") + p->name_ + "Style";
218 SCM style = get_property (prop.to_str0 ());
219 bool mixed = style == ly_symbol2scm ("mixed");
220 if (style == ly_symbol2scm ("text") ||
224 create_text_grobs (p, mixed);
226 if (style == ly_symbol2scm ("bracket") ||
229 create_bracket_grobs (p, mixed);
236 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
239 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
241 if (scm_ilength (strings) < 3)
243 Music * m = p->event_drul_[START];
244 if (!m) m = p->event_drul_ [STOP];
246 String msg = _ ("Need 3 strings for piano pedals. No pedal made. ");
248 m->origin()->warning (msg);
255 if (p->event_drul_[STOP] && p->event_drul_[START])
261 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
265 s = ly_cadr (strings);
267 p->start_ev_ = p->event_drul_[START];
270 else if (p->event_drul_[STOP])
276 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
280 s = ly_caddr (strings);
281 if (previous_.size ())
287 else if (p->event_drul_[START])
289 p->start_ev_ = p->event_drul_[START];
290 s = ly_car (strings);
294 Code dup?! see below.
296 if (previous_.size ())
297 // add extra space below the previous already-occuring pedal
298 Side_position_interface::add_support (p->line_spanner_,
300 previous_.push ( p->line_spanner_);
306 String propname = String (p->name_) + "Pedal";
308 SCM b = get_property (propname.to_str0 ());
309 p->item_ = new Item (b);
310 p->item_->set_grob_property ("text", s);
311 Axis_group_interface::add_element (p->line_spanner_, p->item_);
313 announce_grob (p->item_,
314 (p->event_drul_[START]
315 ? p->event_drul_[START]
316 : p->event_drul_[STOP])->self_scm ());
321 p->event_drul_[START] = 0;
322 p->event_drul_[STOP] = 0;
327 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
329 if (!p->bracket_ && p->event_drul_[STOP])
331 String msg =_f ("can't find start of piano pedal bracket: `%s'", p->name_);
332 p->event_drul_[STOP]->origin ()->warning (msg);
333 p->event_drul_[STOP] = 0;
336 if (p->event_drul_[STOP])
338 if (!p->event_drul_[START])
340 if (previous_.size())
344 assert (!p->finished_bracket_);
346 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
347 p->bracket_->set_bound (RIGHT, cmc);
350 Set properties so that the molecule-creating function will
351 know whether the right edge should be flared ___/
354 if (!p->event_drul_[START])
356 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
357 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_car (flare),
361 p->finished_bracket_ = p->bracket_;
363 p->current_bracket_ev_ = 0;
366 if (p->event_drul_[START])
368 p->start_ev_ = p->event_drul_[START];
369 p->current_bracket_ev_ = p->event_drul_[START];
371 p->bracket_ = new Spanner (get_property ("PianoPedalBracket"));
374 Set properties so that the molecule-creating function will
375 know whether the left edge should be flared \___
378 if (!p->finished_bracket_)
380 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
381 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_double2scm (0),gh_cdr (flare)));
385 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
386 so the molecule function will shorten the ____ line by the length of the Ped. text.
392 Mixed style: Store a pointer to the preceding text for use in
393 calculating the length of the line
398 WTF is pedal-text not the bound of the object? --hwn
401 p->bracket_->set_grob_property ("pedal-text", p->item_->self_scm ());
406 We do not use currentMusicalColumn for the left span-point.
407 If the column as accidentals (eg on a different stave), the
408 currentMusicalColumn is too wide, making the bracket too big.
412 Hmm. What do we do when there are no notes when the spanner starts?
416 what about the right span point?
419 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
420 announce_grob (p->bracket_, p->event_drul_[START]->self_scm ());
422 if (!p->event_drul_[STOP])
428 // position new pedal spanner below the current one
430 if (previous_.size())
431 Side_position_interface::add_support (p->line_spanner_, previous_.top());
433 previous_.push (p->line_spanner_);
437 p->event_drul_[START] = 0;
438 p->event_drul_[STOP] = 0;
442 Piano_pedal_engraver::finalize ()
444 for (Pedal_info*p = info_list_; p && p->name_; p ++)
450 && !p->line_spanner_->live())
451 p->line_spanner_ = 0;
453 if (p->line_spanner_)
455 p->finished_line_spanner_ = p->line_spanner_;
459 && !p->bracket_->live())
464 p->current_bracket_ev_->origin ()->warning (_ ("unterminated pedal bracket"));
465 p->bracket_->suicide ();
473 Piano_pedal_engraver::stop_translation_timestep ()
475 for (Pedal_info*p = info_list_; p && p->name_; p ++)
479 p->finished_line_spanner_ = p->line_spanner_;
480 p->line_spanner_ = 0;
486 for (Pedal_info*p = info_list_; p->name_; p ++)
488 p->event_drul_[STOP] = 0;
489 p->event_drul_[START] = 0;
495 Piano_pedal_engraver::typeset_all ()
498 for (Pedal_info*p = info_list_; p->name_; p ++)
503 if (p->finished_line_spanner_
504 && !p->finished_line_spanner_->live ())
505 p->finished_line_spanner_ = 0;
506 if (p->finished_bracket_
507 && !p->finished_bracket_->live())
508 p->finished_bracket_ = 0;
511 if (p->name_ == String ("Sustain"))
519 if (p->name_ != String ("Sustain"))
523 Side_position_interface::add_support (p->item_,sustain);
526 typeset_grob (p->item_);
530 if (p->finished_bracket_)
532 Grob * r = p->finished_bracket_->get_bound (RIGHT);
535 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
538 typeset_grob (p->finished_bracket_);
539 p->finished_bracket_ =0;
542 if (p->finished_line_spanner_)
544 Side_position_interface::add_staff_support (p->finished_line_spanner_);
545 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
546 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
548 p->finished_line_spanner_->set_bound (RIGHT, l);
550 p->finished_line_spanner_->set_bound (LEFT, r);
553 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
554 Item * ci = dynamic_cast<Item*> (cc);
555 p->finished_line_spanner_->set_bound (RIGHT, ci);
556 p->finished_line_spanner_->set_bound (LEFT, ci);
558 typeset_grob (p->finished_line_spanner_);
559 p->finished_line_spanner_ = 0;
564 ENTER_DESCRIPTION (Piano_pedal_engraver,
565 /* descr */ "Engrave piano pedal symbols and brackets.",
566 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
567 /* accepts */ "pedal-event abort-event",
568 /* acks */ "note-column-interface",
569 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings pedalSostenutoStyle pedalSustainStyle pedalUnaCordaStyle",