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 ("pedal-event"))
164 for (Pedal_info*p = info_list_; p->name_; p ++)
166 String nm = p->name_ + String ("Event");
167 if (gh_equal_p (m->get_mus_property ("name") ,
168 gh_symbol2scm (nm.to_str0())))
170 Direction d = to_dir (m->get_mus_property ("span-direction"));
171 p->event_drul_[d] = m;
180 Piano_pedal_engraver::process_music ()
182 for (Pedal_info*p = info_list_; p && p->name_; p ++)
184 if (p->event_drul_[STOP] || p->event_drul_[START])
186 if (!p->line_spanner_)
188 String name = String (p->name_) + "PedalLineSpanner";
189 p->line_spanner_ = make_spanner (name.to_str0 ());
191 Music * rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
192 announce_grob (p->line_spanner_, rq->self_scm ());
195 /* Choose the appropriate grobs to add to the line spanner
196 These can be text items or text-spanners
200 ugh, code dup, should read grob to create from other
203 bracket: |_________/\____|
205 mixed: Ped. _____/\____|
209 String prop = String ("pedal") + p->name_ + "Style";
210 SCM style = get_property (prop.to_str0 ());
211 bool mixed = style == ly_symbol2scm ("mixed");
212 if (style == ly_symbol2scm ("text") ||
216 create_text_grobs (p, mixed);
218 if (style == ly_symbol2scm ("bracket") ||
221 create_bracket_grobs (p, mixed);
228 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
231 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
233 if (scm_ilength (strings) < 3)
235 Music * m = p->event_drul_[START];
236 if (!m) m = p->event_drul_ [STOP];
238 String msg = _ ("Need 3 strings for piano pedals. No pedal made. ");
240 m->origin()->warning (msg);
247 if (p->event_drul_[STOP] && p->event_drul_[START])
253 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
257 s = ly_cadr (strings);
259 p->start_ev_ = p->event_drul_[START];
262 else if (p->event_drul_[STOP])
268 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
272 s = ly_caddr (strings);
273 if (previous_.size ())
279 else if (p->event_drul_[START])
281 p->start_ev_ = p->event_drul_[START];
282 s = ly_car (strings);
286 Code dup?! see below.
288 if (previous_.size ())
289 // add extra space below the previous already-occuring pedal
290 Side_position_interface::add_support (p->line_spanner_,
292 previous_.push ( p->line_spanner_);
298 String propname = String (p->name_) + "Pedal";
300 p->item_ = make_item (propname.to_str0 ());
301 p->item_->set_grob_property ("text", s);
302 Axis_group_interface::add_element (p->line_spanner_, p->item_);
304 announce_grob (p->item_,
305 (p->event_drul_[START]
306 ? p->event_drul_[START]
307 : p->event_drul_[STOP])->self_scm ());
312 p->event_drul_[START] = 0;
313 p->event_drul_[STOP] = 0;
318 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
320 if (!p->bracket_ && p->event_drul_[STOP])
322 String msg =_f ("can't find start of piano pedal bracket: `%s'", p->name_);
323 p->event_drul_[STOP]->origin ()->warning (msg);
324 p->event_drul_[STOP] = 0;
327 if (p->event_drul_[STOP])
329 if (!p->event_drul_[START])
331 if (previous_.size())
335 assert (!p->finished_bracket_);
337 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
339 if (!p->bracket_->get_bound (RIGHT))
340 p->bracket_->set_bound (RIGHT, cmc);
343 Set properties so that the molecule-creating function will
344 know whether the right edge should be flared ___/
347 if (!p->event_drul_[START])
349 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
350 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_car (flare),
354 p->finished_bracket_ = p->bracket_;
356 p->current_bracket_ev_ = 0;
359 if (p->event_drul_[START])
361 p->start_ev_ = p->event_drul_[START];
362 p->current_bracket_ev_ = p->event_drul_[START];
364 p->bracket_ = make_spanner ("PianoPedalBracket");
367 Set properties so that the molecule-creating function will
368 know whether the left edge should be flared \___
371 if (!p->finished_bracket_)
373 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
374 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_double2scm (0),gh_cdr (flare)));
378 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
379 so the molecule function will shorten the ____ line by the length of the Ped. text.
385 Mixed style: Store a pointer to the preceding text for use in
386 calculating the length of the line
391 WTF is pedal-text not the bound of the object? --hwn
394 p->bracket_->set_grob_property ("pedal-text", p->item_->self_scm ());
399 We do not use currentMusicalColumn for the left span-point.
400 If the column as accidentals (eg on a different stave), the
401 currentMusicalColumn is too wide, making the bracket too big.
405 Hmm. What do we do when there are no notes when the spanner starts?
409 what about the right span point?
412 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
413 announce_grob (p->bracket_, p->event_drul_[START]->self_scm ());
415 if (!p->event_drul_[STOP])
421 // position new pedal spanner below the current one
423 if (previous_.size())
424 Side_position_interface::add_support (p->line_spanner_, previous_.top());
426 previous_.push (p->line_spanner_);
430 p->event_drul_[START] = 0;
431 p->event_drul_[STOP] = 0;
435 Piano_pedal_engraver::finalize ()
437 for (Pedal_info*p = info_list_; p && p->name_; p ++)
443 && !p->line_spanner_->live())
444 p->line_spanner_ = 0;
446 if (p->line_spanner_)
448 p->finished_line_spanner_ = p->line_spanner_;
452 && !p->bracket_->live())
457 p->current_bracket_ev_->origin ()->warning (_ ("unterminated pedal bracket"));
458 p->bracket_->suicide ();
466 Piano_pedal_engraver::stop_translation_timestep ()
468 for (Pedal_info*p = info_list_; p && p->name_; p ++)
472 p->finished_line_spanner_ = p->line_spanner_;
473 p->line_spanner_ = 0;
479 for (Pedal_info*p = info_list_; p->name_; p ++)
481 p->event_drul_[STOP] = 0;
482 p->event_drul_[START] = 0;
488 Piano_pedal_engraver::typeset_all ()
491 for (Pedal_info*p = info_list_; p->name_; p ++)
496 if (p->finished_line_spanner_
497 && !p->finished_line_spanner_->live ())
498 p->finished_line_spanner_ = 0;
499 if (p->finished_bracket_
500 && !p->finished_bracket_->live())
501 p->finished_bracket_ = 0;
504 if (p->name_ == String ("Sustain"))
512 if (p->name_ != String ("Sustain") && sustain)
514 Side_position_interface::add_support (p->item_,sustain);
516 typeset_grob (p->item_);
520 if (p->finished_bracket_)
522 Grob * r = p->finished_bracket_->get_bound (RIGHT);
525 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
528 typeset_grob (p->finished_bracket_);
530 p->finished_bracket_ =0;
533 if (p->finished_line_spanner_)
535 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
536 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
538 p->finished_line_spanner_->set_bound (RIGHT, l);
540 p->finished_line_spanner_->set_bound (LEFT, r);
543 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
544 Item * ci = dynamic_cast<Item*> (cc);
545 p->finished_line_spanner_->set_bound (RIGHT, ci);
546 p->finished_line_spanner_->set_bound (LEFT, ci);
548 typeset_grob (p->finished_line_spanner_);
549 p->finished_line_spanner_ = 0;
554 ENTER_DESCRIPTION (Piano_pedal_engraver,
555 /* descr */ "Engrave piano pedal symbols and brackets.",
556 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
557 /* accepts */ "pedal-event",
558 /* acks */ "note-column-interface",
559 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings pedalSostenutoStyle pedalSustainStyle pedalUnaCordaStyle",