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 (ly_c_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 Music * rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
189 p->line_spanner_ = make_spanner (name.to_str0 (), 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 ());
212 bool mixed = style == ly_symbol2scm ("mixed");
213 bool bracket = (mixed
214 || style == ly_symbol2scm ("bracket"));
215 bool text = (style == ly_symbol2scm ("text")
218 if (text && !p->item_)
219 create_text_grobs (p, mixed);
221 create_bracket_grobs (p, mixed);
227 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
230 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
232 if (scm_ilength (strings) < 3)
234 Music * m = p->event_drul_[START];
235 if (!m) m = p->event_drul_ [STOP];
237 String msg = _ ("Need 3 strings for piano pedals. No pedal made. ");
239 m->origin ()->warning (msg);
246 if (p->event_drul_[STOP] && p->event_drul_[START])
252 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
256 s = ly_cadr (strings);
258 p->start_ev_ = p->event_drul_[START];
261 else if (p->event_drul_[STOP])
267 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
271 s = ly_caddr (strings);
276 else if (p->event_drul_[START])
278 p->start_ev_ = p->event_drul_[START];
279 s = ly_car (strings);
283 Code dup?! see below.
285 if (previous_.size ())
286 // add extra space below the previous already-occuring pedal
287 Side_position_interface::add_support (p->line_spanner_,
289 previous_.push (p->line_spanner_);
293 if (ly_c_string_p (s))
295 String propname = String (p->name_) + "Pedal";
297 p->item_ = make_item (propname.to_str0 (), (p->event_drul_[START]
298 ? p->event_drul_[START]
299 : p->event_drul_[STOP])->self_scm ());
301 p->item_->set_property ("text", s);
302 Axis_group_interface::add_element (p->line_spanner_, p->item_);
307 p->event_drul_[START] = 0;
308 p->event_drul_[STOP] = 0;
314 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
316 if (!p->bracket_ && p->event_drul_[STOP])
318 String msg =_f ("can't find start of piano pedal bracket: `%s'", p->name_);
319 p->event_drul_[STOP]->origin ()->warning (msg);
320 p->event_drul_[STOP] = 0;
323 if (p->event_drul_[STOP])
325 assert (!p->finished_bracket_);
327 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
329 if (!p->bracket_->get_bound (RIGHT))
330 p->bracket_->set_bound (RIGHT, cmc);
333 Set properties so that the stencil-creating function will
334 know whether the right edge should be flared ___/
337 if (!p->event_drul_[START])
339 SCM flare = p->bracket_->get_property ("bracket-flare");
340 p->bracket_->set_property ("bracket-flare", scm_cons (ly_car (flare),
344 p->finished_bracket_ = p->bracket_;
346 p->current_bracket_ev_ = 0;
349 if (p->event_drul_[START])
351 p->start_ev_ = p->event_drul_[START];
352 p->current_bracket_ev_ = p->event_drul_[START];
354 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
357 Set properties so that the stencil-creating function will
358 know whether the left edge should be flared \___
361 if (!p->finished_bracket_)
363 SCM flare = p->bracket_->get_property ("bracket-flare");
364 p->bracket_->set_property ("bracket-flare", scm_cons (scm_make_real (0),ly_cdr (flare)));
368 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
369 so the stencil function will shorten the ____ line by the length of the Ped. text.
375 Mixed style: Store a pointer to the preceding text for use in
376 calculating the length of the line
381 WTF is pedal-text not the bound of the object? --hwn
384 p->bracket_->set_property ("pedal-text", p->item_->self_scm ());
389 We do not use currentMusicalColumn for the left span-point.
390 If the column as accidentals (eg on a different stave), the
391 currentMusicalColumn is too wide, making the bracket too big.
395 Hmm. What do we do when there are no notes when the spanner starts?
399 what about the right span point?
402 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
404 if (!p->event_drul_[STOP])
410 // position new pedal spanner below the current one
412 if (previous_.size ())
413 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
415 previous_.push (p->line_spanner_);
419 p->event_drul_[START] = 0;
420 p->event_drul_[STOP] = 0;
424 Piano_pedal_engraver::finalize ()
426 for (Pedal_info*p = info_list_; p && p->name_; p ++)
432 && !p->line_spanner_->live ())
433 p->line_spanner_ = 0;
436 && !p->bracket_->live ())
441 SCM cc = get_property ("currentCommandColumn");
442 Item *c = unsmob_item (cc);
443 if (p->line_spanner_)
445 p->line_spanner_->set_bound (RIGHT, c);
447 p->bracket_ ->set_bound (RIGHT, c);
449 p->finished_bracket_ = p->bracket_;
451 p->finished_line_spanner_ = p->line_spanner_;
452 p->line_spanner_ = 0;
456 if (p->line_spanner_)
458 p->finished_line_spanner_ = p->line_spanner_;
465 Piano_pedal_engraver::del_linespanner (Spanner *g)
467 int idx = previous_.find_index (g);
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;
481 del_linespanner (p->finished_line_spanner_);
488 for (Pedal_info*p = info_list_; p->name_; p ++)
490 p->event_drul_[STOP] = 0;
491 p->event_drul_[START] = 0;
497 Piano_pedal_engraver::typeset_all (Pedal_info * p)
502 if (p->finished_line_spanner_
503 && !p->finished_line_spanner_->live ())
504 p->finished_line_spanner_ = 0;
505 if (p->finished_bracket_
506 && !p->finished_bracket_->live ())
507 p->finished_bracket_ = 0;
515 if (p->finished_bracket_)
517 Grob * r = p->finished_bracket_->get_bound (RIGHT);
520 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
523 p->finished_bracket_ = 0;
526 if (p->finished_line_spanner_)
528 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
529 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
531 p->finished_line_spanner_->set_bound (RIGHT, l);
533 p->finished_line_spanner_->set_bound (LEFT, r);
536 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
537 Item * ci = dynamic_cast<Item*> (cc);
538 p->finished_line_spanner_->set_bound (RIGHT, ci);
539 p->finished_line_spanner_->set_bound (LEFT, ci);
542 p->finished_line_spanner_ = 0;
546 ENTER_DESCRIPTION (Piano_pedal_engraver,
547 /* descr */ "Engrave piano pedal symbols and brackets.",
548 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
549 /* accepts */ "pedal-event",
550 /* acks */ "note-column-interface",
551 /* reads */ "currentCommandColumn "
552 "pedalSostenutoStrings pedalSustainStrings "
553 "pedalUnaCordaStrings pedalSostenutoStyle "
554 "pedalSustainStyle pedalUnaCordaStyle",