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"
13 #include "lily-guile.hh"
14 #include "side-position-interface.hh"
15 #include "staff-symbol-referencer.hh"
16 #include "axis-group-interface.hh"
18 #include "directional-element-interface.hh"
19 #include "note-column.hh"
23 Urgh. This engraver is too complex. rewrite. --hwn
31 Event for currently running pedal.
33 Music* current_bracket_ev_;
36 Event for currently starting pedal, (necessary?
38 distinct from current_bracket_ev_, since current_bracket_ev_ only
39 necessary for brackets, not for text style.
46 Events that were found in this timestep.
48 Drul_array<Music*> event_drul_;
50 Spanner* bracket_; // A single portion of a pedal bracket
51 Spanner* finished_bracket_;
54 This grob contains all the pedals of the same type on the same staff
56 Spanner* line_spanner_;
57 Spanner* finished_line_spanner_;
61 class Piano_pedal_engraver : public Engraver
64 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
65 ~Piano_pedal_engraver ();
67 virtual void initialize ();
68 virtual void finalize ();
69 virtual bool try_music (Music*);
70 virtual void stop_translation_timestep ();
71 virtual void acknowledge_grob (Grob_info);
72 virtual void process_music ();
76 Pedal_info *info_list_;
79 Record a stack of the current pedal spanners, so if more than one pedal
80 occurs simultaneously then extra space can be added between them.
83 Link_array<Spanner> previous_;
84 void del_linespanner (Spanner*);
86 void create_text_grobs (Pedal_info *p, bool);
87 void create_bracket_grobs (Pedal_info *p, bool);
88 void typeset_all (Pedal_info*p);
92 Piano_pedal_engraver::Piano_pedal_engraver ()
98 Piano_pedal_engraver::initialize ()
100 char * names [] = { "Sostenuto", "Sustain", "UnaCorda", 0 };
102 info_list_ = new Pedal_info[sizeof (names)/ sizeof (const char*)];
103 Pedal_info *p = info_list_;
111 p->finished_bracket_ = 0;
112 p->line_spanner_ = 0;
113 p->finished_line_spanner_ = 0;
114 p->current_bracket_ev_ = 0;
115 p->event_drul_[START] = 0;
116 p->event_drul_[STOP] = 0;
124 Piano_pedal_engraver::~Piano_pedal_engraver ()
134 Piano_pedal_engraver::acknowledge_grob (Grob_info info)
136 for (Pedal_info*p = info_list_; p && p->name_; p ++)
138 if (Note_column::has_interface (info.grob_))
140 if (p->line_spanner_)
142 Side_position_interface::add_support (p->line_spanner_, info.grob_);
143 add_bound_item (p->line_spanner_,info.grob_);
146 add_bound_item (p->bracket_,info.grob_);
147 if (p->finished_bracket_)
148 add_bound_item (p->finished_bracket_,info.grob_);
154 Piano_pedal_engraver::try_music (Music *m)
156 if (m->is_mus_type ("pedal-event"))
158 for (Pedal_info*p = info_list_; p->name_; p ++)
160 String nm = p->name_ + String ("Event");
161 if (ly_c_equal_p (m->get_property ("name") ,
162 scm_str2symbol(nm.to_str0())))
164 Direction d = to_dir (m->get_property ("span-direction"));
165 p->event_drul_[d] = m;
174 Piano_pedal_engraver::process_music ()
176 for (Pedal_info*p = info_list_; p && p->name_; p ++)
178 if (p->event_drul_[STOP] || p->event_drul_[START])
180 if (!p->line_spanner_)
182 String name = String (p->name_) + "PedalLineSpanner";
183 Music * rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
184 p->line_spanner_ = make_spanner (name.to_str0 (), rq->self_scm ());
190 /* Choose the appropriate grobs to add to the line spanner
191 These can be text items or text-spanners
195 ugh, code dup, should read grob to create from other
198 bracket: |_________/\____|
200 mixed: Ped. _____/\____|
204 String prop = String ("pedal") + p->name_ + "Style";
205 SCM style = get_property (prop.to_str0 ());
207 bool mixed = style == ly_symbol2scm ("mixed");
208 bool bracket = (mixed
209 || style == ly_symbol2scm ("bracket"));
210 bool text = (style == ly_symbol2scm ("text")
213 if (text && !p->item_)
214 create_text_grobs (p, mixed);
216 create_bracket_grobs (p, mixed);
222 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
225 SCM strings = get_property ( ("pedal" + String (p->name_) + "Strings").to_str0 ());
227 if (scm_ilength (strings) < 3)
229 Music * m = p->event_drul_[START];
230 if (!m) m = p->event_drul_ [STOP];
232 String msg = _ ("Need 3 strings for piano pedals. No pedal made. ");
234 m->origin ()->warning (msg);
241 if (p->event_drul_[STOP] && p->event_drul_[START])
247 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
251 s = scm_cadr (strings);
253 p->start_ev_ = p->event_drul_[START];
256 else if (p->event_drul_[STOP])
262 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
266 s = scm_caddr (strings);
271 else if (p->event_drul_[START])
273 p->start_ev_ = p->event_drul_[START];
274 s = scm_car (strings);
278 Code dup?! see below.
280 if (previous_.size ())
281 // add extra space below the previous already-occuring pedal
282 Side_position_interface::add_support (p->line_spanner_,
284 previous_.push (p->line_spanner_);
288 if (scm_is_string (s))
290 String propname = String (p->name_) + "Pedal";
292 p->item_ = make_item (propname.to_str0 (), (p->event_drul_[START]
293 ? p->event_drul_[START]
294 : p->event_drul_[STOP])->self_scm ());
296 p->item_->set_property ("text", s);
297 Axis_group_interface::add_element (p->line_spanner_, p->item_);
302 p->event_drul_[START] = 0;
303 p->event_drul_[STOP] = 0;
309 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
311 if (!p->bracket_ && p->event_drul_[STOP])
313 String msg = _f ("can't find start of piano pedal bracket: `%s'", p->name_);
314 p->event_drul_[STOP]->origin ()->warning (msg);
315 p->event_drul_[STOP] = 0;
318 if (p->event_drul_[STOP])
320 assert (!p->finished_bracket_);
322 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
324 if (!p->bracket_->get_bound (RIGHT))
325 p->bracket_->set_bound (RIGHT, cmc);
328 Set properties so that the stencil-creating function will
329 know whether the right edge should be flared ___/
332 if (!p->event_drul_[START])
334 SCM flare = p->bracket_->get_property ("bracket-flare");
335 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
339 p->finished_bracket_ = p->bracket_;
341 p->current_bracket_ev_ = 0;
344 if (p->event_drul_[START])
346 p->start_ev_ = p->event_drul_[START];
347 p->current_bracket_ev_ = p->event_drul_[START];
349 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
352 Set properties so that the stencil-creating function will
353 know whether the left edge should be flared \___
356 if (!p->finished_bracket_)
358 SCM flare = p->bracket_->get_property ("bracket-flare");
359 p->bracket_->set_property ("bracket-flare", scm_cons (scm_make_real (0),scm_cdr (flare)));
363 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
364 so the stencil function will shorten the ____ line by the length of the Ped. text.
370 Mixed style: Store a pointer to the preceding text for use in
371 calculating the length of the line
376 WTF is pedal-text not the bound of the object? --hwn
379 p->bracket_->set_property ("pedal-text", p->item_->self_scm ());
384 We do not use currentMusicalColumn for the left span-point.
385 If the column as accidentals (eg on a different stave), the
386 currentMusicalColumn is too wide, making the bracket too big.
390 Hmm. What do we do when there are no notes when the spanner starts?
394 what about the right span point?
397 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
399 if (!p->event_drul_[STOP])
405 // position new pedal spanner below the current one
407 if (previous_.size ())
408 Side_position_interface::add_support (p->line_spanner_, previous_.top ());
410 previous_.push (p->line_spanner_);
414 p->event_drul_[START] = 0;
415 p->event_drul_[STOP] = 0;
419 Piano_pedal_engraver::finalize ()
421 for (Pedal_info*p = info_list_; p && p->name_; p ++)
427 && !p->line_spanner_->is_live ())
428 p->line_spanner_ = 0;
431 && !p->bracket_->is_live ())
436 SCM cc = get_property ("currentCommandColumn");
437 Item *c = unsmob_item (cc);
438 if (p->line_spanner_)
440 p->line_spanner_->set_bound (RIGHT, c);
442 p->bracket_ ->set_bound (RIGHT, c);
444 p->finished_bracket_ = p->bracket_;
446 p->finished_line_spanner_ = p->line_spanner_;
447 p->line_spanner_ = 0;
451 if (p->line_spanner_)
453 p->finished_line_spanner_ = p->line_spanner_;
460 Piano_pedal_engraver::del_linespanner (Spanner *g)
462 int idx = previous_.find_index (g);
468 Piano_pedal_engraver::stop_translation_timestep ()
470 for (Pedal_info*p = info_list_; p && p->name_; p ++)
474 p->finished_line_spanner_ = p->line_spanner_;
475 p->line_spanner_ = 0;
476 del_linespanner (p->finished_line_spanner_);
483 for (Pedal_info*p = info_list_; p->name_; p ++)
485 p->event_drul_[STOP] = 0;
486 p->event_drul_[START] = 0;
492 Piano_pedal_engraver::typeset_all (Pedal_info * p)
497 if (p->finished_line_spanner_
498 && !p->finished_line_spanner_->is_live ())
499 p->finished_line_spanner_ = 0;
500 if (p->finished_bracket_
501 && !p->finished_bracket_->is_live ())
502 p->finished_bracket_ = 0;
510 if (p->finished_bracket_)
512 Grob * r = p->finished_bracket_->get_bound (RIGHT);
515 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
518 p->finished_bracket_ = 0;
521 if (p->finished_line_spanner_)
523 Grob * l = p->finished_line_spanner_->get_bound (LEFT);
524 Grob * r = p->finished_line_spanner_->get_bound (RIGHT);
526 p->finished_line_spanner_->set_bound (RIGHT, l);
528 p->finished_line_spanner_->set_bound (LEFT, r);
531 Grob * cc = unsmob_grob (get_property ("currentMusicalColumn"));
532 Item * ci = dynamic_cast<Item*> (cc);
533 p->finished_line_spanner_->set_bound (RIGHT, ci);
534 p->finished_line_spanner_->set_bound (LEFT, ci);
537 p->finished_line_spanner_ = 0;
541 ADD_TRANSLATOR (Piano_pedal_engraver,
542 /* descr */ "Engrave piano pedal symbols and brackets.",
543 /* creats*/ "SostenutoPedal SustainPedal UnaCordaPedal SostenutoPedalLineSpanner SustainPedalLineSpanner UnaCordaPedalLineSpanner",
544 /* accepts */ "pedal-event",
545 /* acks */ "note-column-interface",
546 /* reads */ "currentCommandColumn "
547 "pedalSostenutoStrings pedalSustainStrings "
548 "pedalUnaCordaStrings pedalSostenutoStyle "
549 "pedalSustainStyle pedalUnaCordaStyle",