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_ = make_spanner (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 p->item_ = make_item (propname.to_str0 ());
313 p->item_->set_grob_property ("text", s);
314 Axis_group_interface::add_element (p->line_spanner_, p->item_);
316 announce_grob (p->item_,
317 (p->event_drul_[START]
318 ? p->event_drul_[START]
319 : p->event_drul_[STOP])->self_scm ());
324 p->event_drul_[START] = 0;
325 p->event_drul_[STOP] = 0;
330 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
332 if (!p->bracket_ && p->event_drul_[STOP])
334 String msg =_f ("can't find start of piano pedal bracket: `%s'", p->name_);
335 p->event_drul_[STOP]->origin ()->warning (msg);
336 p->event_drul_[STOP] = 0;
339 if (p->event_drul_[STOP])
341 if (!p->event_drul_[START])
343 if (previous_.size())
347 assert (!p->finished_bracket_);
349 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
351 if (!p->bracket_->get_bound (RIGHT))
352 p->bracket_->set_bound (RIGHT, cmc);
355 Set properties so that the molecule-creating function will
356 know whether the right edge should be flared ___/
359 if (!p->event_drul_[START])
361 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
362 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_car (flare),
366 p->finished_bracket_ = p->bracket_;
368 p->current_bracket_ev_ = 0;
371 if (p->event_drul_[START])
373 p->start_ev_ = p->event_drul_[START];
374 p->current_bracket_ev_ = p->event_drul_[START];
376 p->bracket_ = make_spanner ("PianoPedalBracket");
379 Set properties so that the molecule-creating function will
380 know whether the left edge should be flared \___
383 if (!p->finished_bracket_)
385 SCM flare = p->bracket_->get_grob_property ("bracket-flare");
386 p->bracket_->set_grob_property ("bracket-flare", scm_cons (gh_double2scm (0),gh_cdr (flare)));
390 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
391 so the molecule function will shorten the ____ line by the length of the Ped. text.
397 Mixed style: Store a pointer to the preceding text for use in
398 calculating the length of the line
403 WTF is pedal-text not the bound of the object? --hwn
406 p->bracket_->set_grob_property ("pedal-text", p->item_->self_scm ());
411 We do not use currentMusicalColumn for the left span-point.
412 If the column as accidentals (eg on a different stave), the
413 currentMusicalColumn is too wide, making the bracket too big.
417 Hmm. What do we do when there are no notes when the spanner starts?
421 what about the right span point?
424 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
425 announce_grob (p->bracket_, p->event_drul_[START]->self_scm ());
427 if (!p->event_drul_[STOP])
433 // position new pedal spanner below the current one
435 if (previous_.size())
436 Side_position_interface::add_support (p->line_spanner_, previous_.top());
438 previous_.push (p->line_spanner_);
442 p->event_drul_[START] = 0;
443 p->event_drul_[STOP] = 0;
447 Piano_pedal_engraver::finalize ()
449 for (Pedal_info*p = info_list_; p && p->name_; p ++)
455 && !p->line_spanner_->live())
456 p->line_spanner_ = 0;
458 if (p->line_spanner_)
460 p->finished_line_spanner_ = p->line_spanner_;
464 && !p->bracket_->live())
469 p->current_bracket_ev_->origin ()->warning (_ ("unterminated pedal bracket"));
470 p->bracket_->suicide ();
478 Piano_pedal_engraver::stop_translation_timestep ()
480 for (Pedal_info*p = info_list_; p && p->name_; p ++)
484 p->finished_line_spanner_ = p->line_spanner_;
485 p->line_spanner_ = 0;
491 for (Pedal_info*p = info_list_; p->name_; p ++)
493 p->event_drul_[STOP] = 0;
494 p->event_drul_[START] = 0;
500 Piano_pedal_engraver::typeset_all ()
503 for (Pedal_info*p = info_list_; p->name_; p ++)
508 if (p->finished_line_spanner_
509 && !p->finished_line_spanner_->live ())
510 p->finished_line_spanner_ = 0;
511 if (p->finished_bracket_
512 && !p->finished_bracket_->live())
513 p->finished_bracket_ = 0;
516 if (p->name_ == String ("Sustain"))
524 if (p->name_ != String ("Sustain") && sustain)
526 Side_position_interface::add_support (p->item_,sustain);
528 typeset_grob (p->item_);
532 if (p->finished_bracket_)
534 Grob * r = p->finished_bracket_->get_bound (RIGHT);
537 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
540 typeset_grob (p->finished_bracket_);
542 p->finished_bracket_ =0;
545 if (p->finished_line_spanner_)
547 Side_position_interface::add_staff_support (p->finished_line_spanner_);
548 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
549 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
551 p->finished_line_spanner_->set_bound (RIGHT, l);
553 p->finished_line_spanner_->set_bound (LEFT, r);
556 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
557 Item * ci = dynamic_cast<Item*> (cc);
558 p->finished_line_spanner_->set_bound (RIGHT, ci);
559 p->finished_line_spanner_->set_bound (LEFT, ci);
561 typeset_grob (p->finished_line_spanner_);
562 p->finished_line_spanner_ = 0;
567 ENTER_DESCRIPTION (Piano_pedal_engraver,
568 /* descr */ "Engrave piano pedal symbols and brackets.",
569 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
570 /* accepts */ "pedal-event abort-event",
571 /* acks */ "note-column-interface",
572 /* reads */ "pedalSostenutoStrings pedalSustainStrings pedalUnaCordaStrings pedalSostenutoStyle pedalSustainStyle pedalUnaCordaStyle",