2 piano-pedal-engraver.cc -- implement Piano_pedal_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2004 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"
23 #include "directional-element-interface.hh"
24 #include "note-column.hh"
28 Urgh. This engraver is too complex. rewrite. --hwn
37 Event for currently running pedal.
39 Music* current_bracket_ev_;
42 Event for currently starting pedal, (necessary?
44 distinct from current_bracket_ev_, since current_bracket_ev_ only
45 necessary for brackets, not for text style.
52 Events that were found in this timestep.
54 Drul_array<Music*> event_drul_;
56 Spanner* bracket_; // A single portion of a pedal bracket
57 Spanner* finished_bracket_;
60 This grob contains all the pedals of the same type on the same staff
62 Spanner* line_spanner_;
63 Spanner* finished_line_spanner_;
67 class Piano_pedal_engraver : public Engraver
70 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
71 ~Piano_pedal_engraver ();
73 virtual void initialize ();
74 virtual void finalize ();
75 virtual bool try_music (Music*);
76 virtual void stop_translation_timestep ();
77 virtual void acknowledge_grob (Grob_info);
78 virtual void process_music ();
82 Pedal_info *info_list_;
85 Record a stack of the current pedal spanners, so if more than one pedal
86 occurs simultaneously then extra space can be added between them.
89 Link_array<Spanner> previous_;
91 void create_text_grobs (Pedal_info *p, bool);
92 void create_bracket_grobs (Pedal_info *p, bool);
97 Piano_pedal_engraver::Piano_pedal_engraver ()
103 Piano_pedal_engraver::initialize ()
107 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
109 info_list_ = new Pedal_info[sizeof (names)/ sizeof (const char*)];
110 Pedal_info *p = info_list_;
118 p->finished_bracket_ = 0;
119 p->line_spanner_ = 0;
120 p->finished_line_spanner_ = 0;
121 p->current_bracket_ev_ = 0;
122 p->event_drul_[START] = 0;
123 p->event_drul_[STOP] = 0;
131 Piano_pedal_engraver::~Piano_pedal_engraver ()
141 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
143 for (Pedal_info*p = info_list_; p && p->name_; p ++)
145 if (Note_column::has_interface (info.grob_))
147 if (p->line_spanner_)
149 Side_position_interface::add_support (p->line_spanner_, info.grob_);
150 add_bound_item (p->line_spanner_,info.grob_);
153 add_bound_item (p->bracket_,info.grob_);
154 if (p->finished_bracket_)
155 add_bound_item (p->finished_bracket_,info.grob_);
161 Piano_pedal_engraver::try_music (Music *m)
163 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_property ("name") ,
169 gh_symbol2scm (nm.to_str0())))
171 Direction d = to_dir (m->get_property ("span-direction"));
172 p->event_drul_[d] = m;
181 Piano_pedal_engraver::process_music ()
183 for (Pedal_info*p = info_list_; p && p->name_; p ++)
185 if (p->event_drul_[STOP] || p->event_drul_[START])
187 if (!p->line_spanner_)
189 String name = String (p->name_) + "PedalLineSpanner";
190 p->line_spanner_ = make_spanner (name.to_str0 ());
192 Music * rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
193 announce_grob (p->line_spanner_, rq->self_scm ());
196 /* Choose the appropriate grobs to add to the line spanner
197 These can be text items or text-spanners
201 ugh, code dup, should read grob to create from other
204 bracket: |_________/\____|
206 mixed: Ped. _____/\____|
210 String prop = String ("pedal") + p->name_ + "Style";
211 SCM style = get_property (prop.to_str0 ());
212 bool mixed = style == ly_symbol2scm ("mixed");
213 if (style == ly_symbol2scm ("text") ||
217 create_text_grobs (p, mixed);
219 if (style == ly_symbol2scm ("bracket") ||
222 create_bracket_grobs (p, mixed);
229 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
232 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
234 if (scm_ilength (strings) < 3)
236 Music * m = p->event_drul_[START];
237 if (!m) m = p->event_drul_ [STOP];
239 String msg = _ ("Need 3 strings for piano pedals. No pedal made. ");
241 m->origin ()->warning (msg);
248 if (p->event_drul_[STOP] && p->event_drul_[START])
254 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
258 s = ly_cadr (strings);
260 p->start_ev_ = p->event_drul_[START];
263 else if (p->event_drul_[STOP])
269 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
273 s = ly_caddr (strings);
274 if (previous_.size ())
280 else if (p->event_drul_[START])
282 p->start_ev_ = p->event_drul_[START];
283 s = ly_car (strings);
287 Code dup?! see below.
289 if (previous_.size ())
290 // add extra space below the previous already-occuring pedal
291 Side_position_interface::add_support (p->line_spanner_,
293 previous_.push ( p->line_spanner_);
299 String propname = String (p->name_) + "Pedal";
301 p->item_ = make_item (propname.to_str0 ());
302 p->item_->set_property ("text", s);
303 Axis_group_interface::add_element (p->line_spanner_, p->item_);
305 announce_grob (p->item_,
306 (p->event_drul_[START]
307 ? p->event_drul_[START]
308 : p->event_drul_[STOP])->self_scm ());
313 p->event_drul_[START] = 0;
314 p->event_drul_[STOP] = 0;
319 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
321 if (!p->bracket_ && p->event_drul_[STOP])
323 String msg =_f ("can't find start of piano pedal bracket: `%s'", p->name_);
324 p->event_drul_[STOP]->origin ()->warning (msg);
325 p->event_drul_[STOP] = 0;
328 if (p->event_drul_[STOP])
330 if (!p->event_drul_[START])
332 if (previous_.size ())
336 assert (!p->finished_bracket_);
338 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
340 if (!p->bracket_->get_bound (RIGHT))
341 p->bracket_->set_bound (RIGHT, cmc);
344 Set properties so that the stencil-creating function will
345 know whether the right edge should be flared ___/
348 if (!p->event_drul_[START])
350 SCM flare = p->bracket_->get_property ("bracket-flare");
351 p->bracket_->set_property ("bracket-flare", scm_cons (gh_car (flare),
355 p->finished_bracket_ = p->bracket_;
357 p->current_bracket_ev_ = 0;
360 if (p->event_drul_[START])
362 p->start_ev_ = p->event_drul_[START];
363 p->current_bracket_ev_ = p->event_drul_[START];
365 p->bracket_ = make_spanner ("PianoPedalBracket");
368 Set properties so that the stencil-creating function will
369 know whether the left edge should be flared \___
372 if (!p->finished_bracket_)
374 SCM flare = p->bracket_->get_property ("bracket-flare");
375 p->bracket_->set_property ("bracket-flare", scm_cons (gh_double2scm (0),gh_cdr (flare)));
379 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
380 so the stencil function will shorten the ____ line by the length of the Ped. text.
386 Mixed style: Store a pointer to the preceding text for use in
387 calculating the length of the line
392 WTF is pedal-text not the bound of the object? --hwn
395 p->bracket_->set_property ("pedal-text", p->item_->self_scm ());
400 We do not use currentMusicalColumn for the left span-point.
401 If the column as accidentals (eg on a different stave), the
402 currentMusicalColumn is too wide, making the bracket too big.
406 Hmm. What do we do when there are no notes when the spanner starts?
410 what about the right span point?
413 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
414 announce_grob (p->bracket_, p->event_drul_[START]->self_scm ());
416 if (!p->event_drul_[STOP])
422 // position new pedal spanner below the current one
424 if (previous_.size ())
425 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
427 previous_.push (p->line_spanner_);
431 p->event_drul_[START] = 0;
432 p->event_drul_[STOP] = 0;
436 Piano_pedal_engraver::finalize ()
438 for (Pedal_info*p = info_list_; p && p->name_; p ++)
444 && !p->line_spanner_->live ())
445 p->line_spanner_ = 0;
447 if (p->line_spanner_)
449 p->finished_line_spanner_ = p->line_spanner_;
453 && !p->bracket_->live ())
458 p->current_bracket_ev_->origin ()->warning (_ ("unterminated pedal bracket"));
459 p->bracket_->suicide ();
467 Piano_pedal_engraver::stop_translation_timestep ()
469 for (Pedal_info*p = info_list_; p && p->name_; p ++)
473 p->finished_line_spanner_ = p->line_spanner_;
474 p->line_spanner_ = 0;
480 for (Pedal_info*p = info_list_; p->name_; p ++)
482 p->event_drul_[STOP] = 0;
483 p->event_drul_[START] = 0;
489 Piano_pedal_engraver::typeset_all ()
492 for (Pedal_info*p = info_list_; p->name_; p ++)
497 if (p->finished_line_spanner_
498 && !p->finished_line_spanner_->live ())
499 p->finished_line_spanner_ = 0;
500 if (p->finished_bracket_
501 && !p->finished_bracket_->live ())
502 p->finished_bracket_ = 0;
505 if (p->name_ == String ("Sustain"))
513 if (p->name_ != String ("Sustain") && sustain)
515 Side_position_interface::add_support (p->item_,sustain);
517 typeset_grob (p->item_);
521 if (p->finished_bracket_)
523 Grob * r = p->finished_bracket_->get_bound (RIGHT);
526 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
529 typeset_grob (p->finished_bracket_);
531 p->finished_bracket_ =0;
534 if (p->finished_line_spanner_)
536 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
537 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
539 p->finished_line_spanner_->set_bound (RIGHT, l);
541 p->finished_line_spanner_->set_bound (LEFT, r);
544 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
545 Item * ci = dynamic_cast<Item*> (cc);
546 p->finished_line_spanner_->set_bound (RIGHT, ci);
547 p->finished_line_spanner_->set_bound (LEFT, ci);
549 typeset_grob (p->finished_line_spanner_);
550 p->finished_line_spanner_ = 0;
555 ENTER_DESCRIPTION (Piano_pedal_engraver,
556 /* descr */ "Engrave piano pedal symbols and brackets.",
557 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
558 /* accepts */ "pedal-event",
559 /* acks */ "note-column-interface",
560 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings pedalSostenutoStyle pedalSustainStyle pedalUnaCordaStyle",