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
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_;
89 void del_linespanner (Spanner*);
91 void create_text_grobs (Pedal_info *p, bool);
92 void create_bracket_grobs (Pedal_info *p, bool);
93 void typeset_all (Pedal_info*p);
97 Piano_pedal_engraver::Piano_pedal_engraver ()
103 Piano_pedal_engraver::initialize ()
105 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
107 info_list_ = new Pedal_info[sizeof (names)/ sizeof (const char*)];
108 Pedal_info *p = info_list_;
116 p->finished_bracket_ = 0;
117 p->line_spanner_ = 0;
118 p->finished_line_spanner_ = 0;
119 p->current_bracket_ev_ = 0;
120 p->event_drul_[START] = 0;
121 p->event_drul_[STOP] = 0;
129 Piano_pedal_engraver::~Piano_pedal_engraver ()
139 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
141 for (Pedal_info*p = info_list_; p && p->name_; p ++)
143 if (Note_column::has_interface (info.grob_))
145 if (p->line_spanner_)
147 Side_position_interface::add_support (p->line_spanner_, info.grob_);
148 add_bound_item (p->line_spanner_,info.grob_);
151 add_bound_item (p->bracket_,info.grob_);
152 if (p->finished_bracket_)
153 add_bound_item (p->finished_bracket_,info.grob_);
159 Piano_pedal_engraver::try_music (Music *m)
161 if (m->is_mus_type ("pedal-event"))
163 for (Pedal_info*p = info_list_; p->name_; p ++)
165 String nm = p->name_ + String ("Event");
166 if (gh_equal_p (m->get_property ("name") ,
167 scm_str2symbol (nm.to_str0())))
169 Direction d = to_dir (m->get_property ("span-direction"));
170 p->event_drul_[d] = m;
179 Piano_pedal_engraver::process_music ()
181 for (Pedal_info*p = info_list_; p && p->name_; p ++)
183 if (p->event_drul_[STOP] || p->event_drul_[START])
185 if (!p->line_spanner_)
187 String name = String (p->name_) + "PedalLineSpanner";
188 p->line_spanner_ = make_spanner (name.to_str0 ());
190 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 ());
213 bool mixed = style == ly_symbol2scm ("mixed");
214 bool bracket = (mixed
215 || style == ly_symbol2scm ("bracket"));
216 bool text = (style == ly_symbol2scm ("text")
219 if (text && !p->item_)
220 create_text_grobs (p, mixed);
222 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);
277 else if (p->event_drul_[START])
279 p->start_ev_ = p->event_drul_[START];
280 s = ly_car (strings);
284 Code dup?! see below.
286 if (previous_.size ())
287 // add extra space below the previous already-occuring pedal
288 Side_position_interface::add_support (p->line_spanner_,
290 previous_.push (p->line_spanner_);
296 String propname = String (p->name_) + "Pedal";
298 p->item_ = make_item (propname.to_str0 ());
299 p->item_->set_property ("text", s);
300 Axis_group_interface::add_element (p->line_spanner_, p->item_);
302 announce_grob (p->item_,
303 (p->event_drul_[START]
304 ? p->event_drul_[START]
305 : p->event_drul_[STOP])->self_scm ());
310 p->event_drul_[START] = 0;
311 p->event_drul_[STOP] = 0;
317 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
319 if (!p->bracket_ && p->event_drul_[STOP])
321 String msg =_f ("can't find start of piano pedal bracket: `%s'", p->name_);
322 p->event_drul_[STOP]->origin ()->warning (msg);
323 p->event_drul_[STOP] = 0;
326 if (p->event_drul_[STOP])
328 assert (!p->finished_bracket_);
330 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
332 if (!p->bracket_->get_bound (RIGHT))
333 p->bracket_->set_bound (RIGHT, cmc);
336 Set properties so that the stencil-creating function will
337 know whether the right edge should be flared ___/
340 if (!p->event_drul_[START])
342 SCM flare = p->bracket_->get_property ("bracket-flare");
343 p->bracket_->set_property ("bracket-flare", scm_cons (gh_car (flare),
347 p->finished_bracket_ = p->bracket_;
349 p->current_bracket_ev_ = 0;
352 if (p->event_drul_[START])
354 p->start_ev_ = p->event_drul_[START];
355 p->current_bracket_ev_ = p->event_drul_[START];
357 p->bracket_ = make_spanner ("PianoPedalBracket");
360 Set properties so that the stencil-creating function will
361 know whether the left edge should be flared \___
364 if (!p->finished_bracket_)
366 SCM flare = p->bracket_->get_property ("bracket-flare");
367 p->bracket_->set_property ("bracket-flare", scm_cons (gh_double2scm (0),gh_cdr (flare)));
371 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
372 so the stencil function will shorten the ____ line by the length of the Ped. text.
378 Mixed style: Store a pointer to the preceding text for use in
379 calculating the length of the line
384 WTF is pedal-text not the bound of the object? --hwn
387 p->bracket_->set_property ("pedal-text", p->item_->self_scm ());
392 We do not use currentMusicalColumn for the left span-point.
393 If the column as accidentals (eg on a different stave), the
394 currentMusicalColumn is too wide, making the bracket too big.
398 Hmm. What do we do when there are no notes when the spanner starts?
402 what about the right span point?
405 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
406 announce_grob (p->bracket_, p->event_drul_[START]->self_scm ());
408 if (!p->event_drul_[STOP])
414 // position new pedal spanner below the current one
416 if (previous_.size ())
417 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
419 previous_.push (p->line_spanner_);
423 p->event_drul_[START] = 0;
424 p->event_drul_[STOP] = 0;
428 Piano_pedal_engraver::finalize ()
430 for (Pedal_info*p = info_list_; p && p->name_; p ++)
436 && !p->line_spanner_->live ())
437 p->line_spanner_ = 0;
440 && !p->bracket_->live ())
445 SCM cc = get_property ("currentCommandColumn");
446 Item *c = unsmob_item (cc);
447 if (p->line_spanner_)
449 p->line_spanner_->set_bound (RIGHT, c);
451 p->bracket_ ->set_bound (RIGHT, c);
453 p->finished_bracket_ = p->bracket_;
455 p->finished_line_spanner_ = p->line_spanner_;
456 p->line_spanner_ = 0;
460 if (p->line_spanner_)
462 p->finished_line_spanner_ = p->line_spanner_;
469 Piano_pedal_engraver::del_linespanner (Spanner *g)
471 int idx = previous_.find_index (g);
477 Piano_pedal_engraver::stop_translation_timestep ()
479 for (Pedal_info*p = info_list_; p && p->name_; p ++)
483 p->finished_line_spanner_ = p->line_spanner_;
484 p->line_spanner_ = 0;
485 del_linespanner (p->finished_line_spanner_);
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 (Pedal_info * p)
506 if (p->finished_line_spanner_
507 && !p->finished_line_spanner_->live ())
508 p->finished_line_spanner_ = 0;
509 if (p->finished_bracket_
510 && !p->finished_bracket_->live ())
511 p->finished_bracket_ = 0;
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;
553 ENTER_DESCRIPTION (Piano_pedal_engraver,
554 /* descr */ "Engrave piano pedal symbols and brackets.",
555 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
556 /* accepts */ "pedal-event",
557 /* acks */ "note-column-interface",
558 /* reads */ "currentCommandColumn "
559 "pedalSostenutoStrings pedalSustainStrings "
560 "pedalUnaCordaStrings pedalSostenutoStyle "
561 "pedalSustainStyle pedalUnaCordaStyle",