*** empty log message ***
[lilypond.git] / lily / piano-pedal-engraver.cc
blobad6741cdb26938c3d520182b467ebd27ca3e43a8
1 /*
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
9 bracketed pedals.
12 #include "engraver.hh"
13 #include "event.hh"
14 #include "grob.hh"
15 #include "item.hh"
16 #include "lily-guile.hh"
17 #include "side-position-interface.hh"
18 #include "staff-symbol-referencer.hh"
19 #include "item.hh"
20 #include "axis-group-interface.hh"
21 #include "context.hh"
23 #include "directional-element-interface.hh"
24 #include "note-column.hh"
25 #include "warn.hh"
28 Urgh. This engraver is too complex. rewrite. --hwn
31 struct Pedal_info
33 char const * name_;
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.
46 Music* start_ev_;
51 Events that were found in this timestep.
53 Drul_array<Music*> event_drul_;
54 Item* item_;
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
68 public:
69 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
70 ~Piano_pedal_engraver ();
71 protected:
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 ();
79 private:
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 ()
99 info_list_ = 0;
102 void
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_;
110 char **np = names ;
113 p->name_ = *np;
114 p->item_ = 0;
115 p->bracket_ = 0;
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;
122 p->start_ev_ = 0;
124 p++;
126 while (* (np ++));
129 Piano_pedal_engraver::~Piano_pedal_engraver ()
131 delete[] info_list_;
135 Urg: Code dup
136 I'm a script
138 void
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_);
150 if (p->bracket_)
151 add_bound_item (p->bracket_,info.grob_);
152 if (p->finished_bracket_)
153 add_bound_item (p->finished_bracket_,info.grob_);
158 bool
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;
171 return true;
175 return false;
178 void
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
201 property.
203 bracket: |_________/\____|
204 text: Ped. *Ped. *
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")
216 || mixed);
218 if (text && !p->item_)
219 create_text_grobs (p, mixed);
220 if (bracket)
221 create_bracket_grobs (p, mixed);
226 void
227 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
229 SCM s = SCM_EOL;
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. ");
238 if (m)
239 m->origin ()->warning (msg);
240 else
241 warning (msg);
243 return ;
246 if (p->event_drul_[STOP] && p->event_drul_[START])
248 if (!mixed)
250 if (!p->start_ev_)
252 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
254 else
256 s = ly_cadr (strings);
258 p->start_ev_ = p->event_drul_[START];
261 else if (p->event_drul_[STOP])
263 if (!mixed)
265 if (!p->start_ev_)
267 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->name_));
269 else
271 s = ly_caddr (strings);
273 p->start_ev_ = 0;
276 else if (p->event_drul_[START])
278 p->start_ev_ = p->event_drul_[START];
279 s = ly_car (strings);
280 if (!mixed)
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_,
288 previous_.top ());
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_);
305 if (!mixed)
307 p->event_drul_[START] = 0;
308 p->event_drul_[STOP] = 0;
313 void
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),
341 scm_make_real (0)));
344 p->finished_bracket_ = p->bracket_;
345 p->bracket_ = 0;
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.
372 if (mixed)
375 Mixed style: Store a pointer to the preceding text for use in
376 calculating the length of the line
379 TODO:
381 WTF is pedal-text not the bound of the object? --hwn
383 if (p->item_)
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.
393 TODO:
395 Hmm. What do we do when there are no notes when the spanner starts?
397 TODO:
399 what about the right span point?
402 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
404 if (!p->event_drul_[STOP])
408 code dup. --hwn.
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;
423 void
424 Piano_pedal_engraver::finalize ()
426 for (Pedal_info*p = info_list_; p && p->name_; p ++)
429 suicide?
431 if (p->line_spanner_
432 && !p->line_spanner_->is_live ())
433 p->line_spanner_ = 0;
435 if (p->bracket_
436 && !p->bracket_->is_live ())
437 p->bracket_ = 0;
439 if (p->bracket_)
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_;
450 p->bracket_ = 0;
451 p->finished_line_spanner_ = p->line_spanner_;
452 p->line_spanner_ = 0;
453 typeset_all (p);
456 if (p->line_spanner_)
458 p->finished_line_spanner_ = p->line_spanner_;
459 typeset_all (p);
464 void
465 Piano_pedal_engraver::del_linespanner (Spanner *g)
467 int idx = previous_.find_index (g);
468 if (idx >= 0)
469 previous_.del (idx);
472 void
473 Piano_pedal_engraver::stop_translation_timestep ()
475 for (Pedal_info*p = info_list_; p && p->name_; p ++)
477 if (!p->bracket_)
479 p->finished_line_spanner_ = p->line_spanner_;
480 p->line_spanner_ = 0;
481 del_linespanner (p->finished_line_spanner_);
484 typeset_all (p);
488 for (Pedal_info*p = info_list_; p->name_; p ++)
490 p->event_drul_[STOP] = 0;
491 p->event_drul_[START] = 0;
496 void
497 Piano_pedal_engraver::typeset_all (Pedal_info * p)
500 Handle suicide.
502 if (p->finished_line_spanner_
503 && !p->finished_line_spanner_->is_live ())
504 p->finished_line_spanner_ = 0;
505 if (p->finished_bracket_
506 && !p->finished_bracket_->is_live ())
507 p->finished_bracket_ = 0;
510 if (p->item_)
512 p->item_ = 0;
515 if (p->finished_bracket_)
517 Grob * r = p->finished_bracket_->get_bound (RIGHT);
518 if (!r)
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);
530 if (!r && l)
531 p->finished_line_spanner_->set_bound (RIGHT, l);
532 else if (!l && r)
533 p->finished_line_spanner_->set_bound (LEFT, r);
534 else if (!r && !l)
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",
555 /* write */ "");