2 piano-pedal-engraver.cc -- implement Piano_pedal_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2006 Jan Nieuwenhuizen <janneke@gnu.org>,
7 Erik Sandberg <mandolaerik@gmail.com>
9 Chris Jackson <chris@fluffhouse.org.uk> - extended to support
13 #include "engraver.hh"
15 #include "axis-group-interface.hh"
17 #include "directional-element-interface.hh"
18 #include "international.hh"
19 #include "lily-guile.hh"
20 #include "note-column.hh"
21 #include "side-position-interface.hh"
22 #include "staff-symbol-referencer.hh"
23 #include "stream-event.hh"
24 #include "string-convert.hh"
26 #include "protected-scm.hh"
27 #include "translator.icc"
30 Urgh. This engraver is too complex. rewrite. --hwn
33 /* Ugh: This declaration is duplicated in piano-pedal-performer */
34 typedef enum Pedal_type {SOSTENUTO, SUSTAIN, UNA_CORDA, NUM_PEDAL_TYPES};
37 Static precalculated data (symbols and strings) for the different
40 struct Pedal_type_info
43 Protected_scm event_class_sym_;
44 Protected_scm style_sym_;
45 Protected_scm strings_sym_;
47 const char *pedal_line_spanner_c_str_;
48 const char *pedal_c_str_;
53 const Pedal_type_info *type_;
56 Event for currently running pedal.
58 Stream_event *current_bracket_ev_;
61 Event for currently starting pedal, (necessary?
63 distinct from current_bracket_ev_, since current_bracket_ev_ only
64 necessary for brackets, not for text style.
66 Stream_event *start_ev_;
69 Events that were found in this timestep.
71 Drul_array<Stream_event *> event_drul_;
73 Spanner *bracket_; // A single portion of a pedal bracket
74 Spanner *finished_bracket_;
77 This grob contains all the pedals of the same type on the same staff
79 Spanner *line_spanner_;
80 Spanner *finished_line_spanner_;
83 static Pedal_type_info pedal_types_[NUM_PEDAL_TYPES];
85 class Piano_pedal_engraver : public Engraver
88 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
89 ~Piano_pedal_engraver ();
91 virtual void initialize ();
92 virtual void finalize ();
93 DECLARE_TRANSLATOR_LISTENER (sustain);
94 DECLARE_TRANSLATOR_LISTENER (una_corda);
95 DECLARE_TRANSLATOR_LISTENER (sostenuto);
96 void stop_translation_timestep ();
97 DECLARE_ACKNOWLEDGER (note_column);
98 void process_music ();
101 Pedal_info info_list_[NUM_PEDAL_TYPES + 1];
104 Record a stack of the current pedal spanners, so if more than one pedal
105 occurs simultaneously then extra space can be added between them.
108 vector<Spanner*> previous_;
109 void del_linespanner (Spanner *);
111 void create_text_grobs (Pedal_info *p, bool);
112 void create_bracket_grobs (Pedal_info *p, bool);
113 void typeset_all (Pedal_info *p);
119 const char *names [NUM_PEDAL_TYPES];
120 names[SOSTENUTO] = "Sostenuto";
121 names[SUSTAIN] = "Sustain";
122 names[UNA_CORDA] = "UnaCorda";
124 for (int i = 0; i < NUM_PEDAL_TYPES; i++)
126 const char *name = names[i];
128 string base_name = name;
130 string base_ident = "";
133 for (cur_pos = 1; name[cur_pos]; cur_pos++)
134 if (isupper (name[cur_pos]))
136 base_ident = base_ident + String_convert::to_lower (string (name, prev_pos, cur_pos - prev_pos)) + "-";
139 base_ident += String_convert::to_lower (string (name, prev_pos, cur_pos - prev_pos));
141 Pedal_type_info *tbl = &pedal_types_[i];
142 tbl->base_name_ = name;
143 tbl->event_class_sym_ = scm_str2symbol ((base_ident + "-event").c_str ());
144 tbl->pedal_line_spanner_c_str_ = strdup ((base_name + "PedalLineSpanner").c_str ());
145 tbl->style_sym_ = scm_str2symbol (("pedal" + base_name + "Style").c_str ());
146 tbl->strings_sym_ = scm_str2symbol (("pedal" + base_name + "Strings").c_str ());
147 tbl->pedal_c_str_ = strdup ((base_name + "Pedal").c_str ());
150 ADD_SCM_INIT_FUNC (Piano_pedal_engraver_init_pedal_types_, init_pedal_types);
152 Piano_pedal_engraver::Piano_pedal_engraver ()
157 Piano_pedal_engraver::initialize ()
159 for (int i = 0; i < NUM_PEDAL_TYPES; i++)
161 Pedal_type_info *s = &pedal_types_[i];
162 Pedal_info *info = &info_list_[i];
167 info->finished_bracket_ = 0;
168 info->line_spanner_ = 0;
169 info->finished_line_spanner_ = 0;
170 info->current_bracket_ev_ = 0;
171 info->event_drul_[START] = 0;
172 info->event_drul_[STOP] = 0;
175 info_list_[NUM_PEDAL_TYPES].type_ = 0;
178 Piano_pedal_engraver::~Piano_pedal_engraver ()
187 Piano_pedal_engraver::acknowledge_note_column (Grob_info info)
189 for (Pedal_info *p = info_list_; p->type_; p++)
191 if (p->line_spanner_)
193 Side_position_interface::add_support (p->line_spanner_, info.grob ());
194 add_bound_item (p->line_spanner_, info.grob ());
197 add_bound_item (p->bracket_, info.grob ());
198 if (p->finished_bracket_)
199 add_bound_item (p->finished_bracket_, info.grob ());
203 IMPLEMENT_TRANSLATOR_LISTENER (Piano_pedal_engraver, sostenuto);
205 Piano_pedal_engraver::listen_sostenuto (Stream_event *r)
207 Direction d = to_dir (r->get_property ("span-direction"));
208 info_list_[SOSTENUTO].event_drul_[d] = r;
211 IMPLEMENT_TRANSLATOR_LISTENER (Piano_pedal_engraver, sustain);
213 Piano_pedal_engraver::listen_sustain (Stream_event *r)
215 Direction d = to_dir (r->get_property ("span-direction"));
216 info_list_[SUSTAIN].event_drul_[d] = r;
219 IMPLEMENT_TRANSLATOR_LISTENER (Piano_pedal_engraver, una_corda);
221 Piano_pedal_engraver::listen_una_corda (Stream_event *r)
223 Direction d = to_dir (r->get_property ("span-direction"));
224 info_list_[UNA_CORDA].event_drul_[d] = r;
228 Piano_pedal_engraver::process_music ()
230 for (Pedal_info *p = info_list_; p->type_; p++)
232 if (p->event_drul_[STOP] || p->event_drul_[START])
234 if (!p->line_spanner_)
236 const char *name = p->type_->pedal_line_spanner_c_str_;
237 Stream_event *rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
238 p->line_spanner_ = make_spanner (name, rq->self_scm ());
241 /* Choose the appropriate grobs to add to the line spanner
242 These can be text items or text-spanners
246 ugh, code dup, should read grob to create from other
249 bracket: |_________/\____|
251 mixed: Ped. _____/\____|
254 SCM style = internal_get_property (p->type_->style_sym_);
256 bool mixed = style == ly_symbol2scm ("mixed");
257 bool bracket = (mixed
258 || style == ly_symbol2scm ("bracket"));
259 bool text = (style == ly_symbol2scm ("text")
262 if (text && !p->item_)
263 create_text_grobs (p, mixed);
265 create_bracket_grobs (p, mixed);
271 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
274 SCM strings = internal_get_property (p->type_->strings_sym_);
276 if (scm_ilength (strings) < 3)
278 Stream_event *m = p->event_drul_[START];
279 if (!m) m = p->event_drul_ [STOP];
281 string msg = _f ("expect 3 strings for piano pedals, found: %ld",
282 scm_ilength (strings));
284 m->origin ()->warning (msg);
291 if (p->event_drul_[STOP] && p->event_drul_[START])
296 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->type_->base_name_.c_str ()));
298 s = scm_cadr (strings);
299 p->start_ev_ = p->event_drul_[START];
302 else if (p->event_drul_[STOP])
307 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->type_->base_name_.c_str ()));
309 s = scm_caddr (strings);
313 else if (p->event_drul_[START])
315 p->start_ev_ = p->event_drul_[START];
316 s = scm_car (strings);
320 Code dup?! see below.
322 if (previous_.size ())
323 // add extra space below the previous already-occuring pedal
324 Side_position_interface::add_support (p->line_spanner_,
326 previous_.push_back (p->line_spanner_);
330 if (scm_is_string (s))
332 const char *propname = p->type_->pedal_c_str_;
334 p->item_ = make_item (propname, (p->event_drul_[START]
335 ? p->event_drul_[START]
336 : p->event_drul_[STOP])->self_scm ());
338 p->item_->set_property ("text", s);
339 Axis_group_interface::add_element (p->line_spanner_, p->item_);
344 p->event_drul_[START] = 0;
345 p->event_drul_[STOP] = 0;
350 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
352 if (!p->bracket_ && p->event_drul_[STOP])
354 string msg = _f ("can't find start of piano pedal bracket: `%s'", p->type_->base_name_.c_str ());
355 p->event_drul_[STOP]->origin ()->warning (msg);
356 p->event_drul_[STOP] = 0;
359 if (p->event_drul_[STOP])
361 assert (!p->finished_bracket_);
363 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
365 if (!p->bracket_->get_bound (RIGHT))
366 p->bracket_->set_bound (RIGHT, cmc);
369 Set properties so that the stencil-creating function will
370 know whether the right edge should be flared ___/
373 if (!p->event_drul_[START])
375 SCM flare = p->bracket_->get_property ("bracket-flare");
376 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
377 scm_from_double (0)));
380 p->finished_bracket_ = p->bracket_;
382 p->current_bracket_ev_ = 0;
385 if (p->event_drul_[START])
387 p->start_ev_ = p->event_drul_[START];
388 p->current_bracket_ev_ = p->event_drul_[START];
390 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
393 Set properties so that the stencil-creating function will
394 know whether the left edge should be flared \___
397 if (!p->finished_bracket_)
399 SCM flare = p->bracket_->get_property ("bracket-flare");
400 p->bracket_->set_property ("bracket-flare", scm_cons (scm_from_double (0), scm_cdr (flare)));
403 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
404 so the stencil function will shorten the ____ line by the length of the Ped. text.
410 Mixed style: Store a pointer to the preceding text for use in
411 calculating the length of the line
416 WTF is pedal-text not the bound of the object? --hwn
419 p->bracket_->set_object ("pedal-text", p->item_->self_scm ());
423 We do not use currentMusicalColumn for the left span-point.
424 If the column as accidentals (eg on a different stave), the
425 currentMusicalColumn is too wide, making the bracket too big.
429 Hmm. What do we do when there are no notes when the spanner starts?
433 what about the right span point?
436 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
438 if (!p->event_drul_[STOP])
444 // position new pedal spanner below the current one
446 if (previous_.size ())
447 Side_position_interface::add_support (p->line_spanner_, previous_.back ());
449 previous_.push_back (p->line_spanner_);
453 p->event_drul_[START] = 0;
454 p->event_drul_[STOP] = 0;
458 Piano_pedal_engraver::finalize ()
460 for (Pedal_info *p = info_list_; p->type_; p++)
466 && !p->line_spanner_->is_live ())
467 p->line_spanner_ = 0;
470 && !p->bracket_->is_live ())
475 SCM cc = get_property ("currentCommandColumn");
476 Item *c = unsmob_item (cc);
477 if (p->line_spanner_)
478 p->line_spanner_->set_bound (RIGHT, c);
479 p->bracket_->set_bound (RIGHT, c);
481 p->finished_bracket_ = p->bracket_;
483 p->finished_line_spanner_ = p->line_spanner_;
484 p->line_spanner_ = 0;
488 if (p->line_spanner_)
490 p->finished_line_spanner_ = p->line_spanner_;
497 Piano_pedal_engraver::del_linespanner (Spanner *g)
499 vsize idx = find (previous_, g) - previous_.begin ();
500 if (idx != VPOS && idx < previous_.size ())
501 previous_.erase (previous_.begin () + idx);
505 Piano_pedal_engraver::stop_translation_timestep ()
507 for (Pedal_info *p = info_list_; p->type_; p++)
511 p->finished_line_spanner_ = p->line_spanner_;
512 p->line_spanner_ = 0;
513 del_linespanner (p->finished_line_spanner_);
519 for (Pedal_info *p = info_list_; p->type_; p++)
521 p->event_drul_[STOP] = 0;
522 p->event_drul_[START] = 0;
527 Piano_pedal_engraver::typeset_all (Pedal_info *p)
532 if (p->finished_line_spanner_
533 && !p->finished_line_spanner_->is_live ())
534 p->finished_line_spanner_ = 0;
535 if (p->finished_bracket_
536 && !p->finished_bracket_->is_live ())
537 p->finished_bracket_ = 0;
542 if (p->finished_bracket_)
544 Grob *r = p->finished_bracket_->get_bound (RIGHT);
546 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
548 p->finished_bracket_ = 0;
551 if (p->finished_line_spanner_)
553 Grob *l = p->finished_line_spanner_->get_bound (LEFT);
554 Grob *r = p->finished_line_spanner_->get_bound (RIGHT);
556 p->finished_line_spanner_->set_bound (RIGHT, l);
558 p->finished_line_spanner_->set_bound (LEFT, r);
561 Grob *cc = unsmob_grob (get_property ("currentMusicalColumn"));
562 Item *ci = dynamic_cast<Item *> (cc);
563 p->finished_line_spanner_->set_bound (RIGHT, ci);
564 p->finished_line_spanner_->set_bound (LEFT, ci);
567 p->finished_line_spanner_ = 0;
571 ADD_ACKNOWLEDGER (Piano_pedal_engraver, note_column);
573 ADD_TRANSLATOR (Piano_pedal_engraver,
576 "Engrave piano pedal symbols and brackets.",
580 "SostenutoPedalLineSpanner "
582 "SustainPedalLineSpanner "
584 "UnaCordaPedalLineSpanner ",
590 "currentCommandColumn "
591 "pedalSostenutoStrings "
592 "pedalSostenutoStyle "
593 "pedalSustainStrings "
595 "pedalUnaCordaStrings "
596 "pedalUnaCordaStyle",