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_);
306 p->event_drul_[START] = 0;
307 p->event_drul_[STOP] = 0;
313 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
315 if (!p->bracket_ && p->event_drul_[STOP])
317 String msg =_f ("can't find start of piano pedal bracket: `%s'", p->name_);
318 p->event_drul_[STOP]->origin ()->warning (msg);
319 p->event_drul_[STOP] = 0;
322 if (p->event_drul_[STOP])
324 assert (!p->finished_bracket_);
326 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
328 if (!p->bracket_->get_bound (RIGHT))
329 p->bracket_->set_bound (RIGHT, cmc);
332 Set properties so that the stencil-creating function will
333 know whether the right edge should be flared ___/
336 if (!p->event_drul_[START])
338 SCM flare = p->bracket_->get_property ("bracket-flare");
339 p->bracket_->set_property ("bracket-flare", scm_cons (ly_car (flare),
343 p->finished_bracket_ = p->bracket_;
345 p->current_bracket_ev_ = 0;
348 if (p->event_drul_[START])
350 p->start_ev_ = p->event_drul_[START];
351 p->current_bracket_ev_ = p->event_drul_[START];
353 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
356 Set properties so that the stencil-creating function will
357 know whether the left edge should be flared \___
360 if (!p->finished_bracket_)
362 SCM flare = p->bracket_->get_property ("bracket-flare");
363 p->bracket_->set_property ("bracket-flare", scm_cons (scm_make_real (0),ly_cdr (flare)));
367 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
368 so the stencil function will shorten the ____ line by the length of the Ped. text.
374 Mixed style: Store a pointer to the preceding text for use in
375 calculating the length of the line
380 WTF is pedal-text not the bound of the object? --hwn
383 p->bracket_->set_property ("pedal-text", p->item_->self_scm ());
388 We do not use currentMusicalColumn for the left span-point.
389 If the column as accidentals (eg on a different stave), the
390 currentMusicalColumn is too wide, making the bracket too big.
394 Hmm. What do we do when there are no notes when the spanner starts?
398 what about the right span point?
401 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
403 if (!p->event_drul_[STOP])
409 // position new pedal spanner below the current one
411 if (previous_.size ())
412 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
414 previous_.push (p->line_spanner_);
418 p->event_drul_[START] = 0;
419 p->event_drul_[STOP] = 0;
423 Piano_pedal_engraver::finalize ()
425 for (Pedal_info*p = info_list_; p && p->name_; p ++)
431 && !p->line_spanner_->live ())
432 p->line_spanner_ = 0;
435 && !p->bracket_->live ())
440 SCM cc = get_property ("currentCommandColumn");
441 Item *c = unsmob_item (cc);
442 if (p->line_spanner_)
444 p->line_spanner_->set_bound (RIGHT, c);
446 p->bracket_ ->set_bound (RIGHT, c);
448 p->finished_bracket_ = p->bracket_;
450 p->finished_line_spanner_ = p->line_spanner_;
451 p->line_spanner_ = 0;
455 if (p->line_spanner_)
457 p->finished_line_spanner_ = p->line_spanner_;
464 Piano_pedal_engraver::del_linespanner (Spanner *g)
466 int idx = previous_.find_index (g);
472 Piano_pedal_engraver::stop_translation_timestep ()
474 for (Pedal_info*p = info_list_; p && p->name_; p ++)
478 p->finished_line_spanner_ = p->line_spanner_;
479 p->line_spanner_ = 0;
480 del_linespanner (p->finished_line_spanner_);
487 for (Pedal_info*p = info_list_; p->name_; p ++)
489 p->event_drul_[STOP] = 0;
490 p->event_drul_[START] = 0;
496 Piano_pedal_engraver::typeset_all (Pedal_info * p)
501 if (p->finished_line_spanner_
502 && !p->finished_line_spanner_->live ())
503 p->finished_line_spanner_ = 0;
504 if (p->finished_bracket_
505 && !p->finished_bracket_->live ())
506 p->finished_bracket_ = 0;
511 typeset_grob (p->item_);
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 typeset_grob (p->finished_bracket_);
525 p->finished_bracket_ =0;
528 if (p->finished_line_spanner_)
530 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
531 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
533 p->finished_line_spanner_->set_bound (RIGHT, l);
535 p->finished_line_spanner_->set_bound (LEFT, r);
538 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
539 Item * ci = dynamic_cast<Item*> (cc);
540 p->finished_line_spanner_->set_bound (RIGHT, ci);
541 p->finished_line_spanner_->set_bound (LEFT, ci);
543 typeset_grob (p->finished_line_spanner_);
544 p->finished_line_spanner_ = 0;
548 ENTER_DESCRIPTION (Piano_pedal_engraver,
549 /* descr */ "Engrave piano pedal symbols and brackets.",
550 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
551 /* accepts */ "pedal-event",
552 /* acks */ "note-column-interface",
553 /* reads */ "currentCommandColumn "
554 "pedalSostenutoStrings pedalSustainStrings "
555 "pedalUnaCordaStrings pedalSostenutoStyle "
556 "pedalSustainStyle pedalUnaCordaStyle",