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
47 const char *pedal_line_spanner_c_str_;
48 const char *pedal_c_str_;
52 event_class_sym_ = SCM_EOL;
54 strings_sym_ = SCM_EOL;
55 pedal_line_spanner_c_str_ = 0;
60 scm_gc_protect_object (event_class_sym_);
61 scm_gc_protect_object (style_sym_);
62 scm_gc_protect_object (strings_sym_);
68 const Pedal_type_info *type_;
71 Event for currently running pedal.
73 Stream_event *current_bracket_ev_;
76 Event for currently starting pedal, (necessary?
78 distinct from current_bracket_ev_, since current_bracket_ev_ only
79 necessary for brackets, not for text style.
81 Stream_event *start_ev_;
84 Events that were found in this timestep.
86 Drul_array<Stream_event *> event_drul_;
88 Spanner *bracket_; // A single portion of a pedal bracket
89 Spanner *finished_bracket_;
92 This grob contains all the pedals of the same type on the same staff
94 Spanner *line_spanner_;
95 Spanner *finished_line_spanner_;
98 static Pedal_type_info pedal_types_[NUM_PEDAL_TYPES];
100 class Piano_pedal_engraver : public Engraver
103 TRANSLATOR_DECLARATIONS (Piano_pedal_engraver);
104 ~Piano_pedal_engraver ();
106 virtual void initialize ();
107 virtual void finalize ();
108 DECLARE_TRANSLATOR_LISTENER (sustain);
109 DECLARE_TRANSLATOR_LISTENER (una_corda);
110 DECLARE_TRANSLATOR_LISTENER (sostenuto);
111 void stop_translation_timestep ();
112 DECLARE_ACKNOWLEDGER (note_column);
113 void process_music ();
116 Pedal_info info_list_[NUM_PEDAL_TYPES + 1];
119 Record a stack of the current pedal spanners, so if more than one pedal
120 occurs simultaneously then extra space can be added between them.
123 vector<Spanner*> previous_;
124 void del_linespanner (Spanner *);
126 void create_text_grobs (Pedal_info *p, bool);
127 void create_bracket_grobs (Pedal_info *p, bool);
128 void typeset_all (Pedal_info *p);
134 const char *names [NUM_PEDAL_TYPES];
135 names[SOSTENUTO] = "Sostenuto";
136 names[SUSTAIN] = "Sustain";
137 names[UNA_CORDA] = "UnaCorda";
139 for (int i = 0; i < NUM_PEDAL_TYPES; i++)
141 const char *name = names[i];
143 string base_name = name;
145 string base_ident = "";
148 for (cur_pos = 1; name[cur_pos]; cur_pos++)
149 if (isupper (name[cur_pos]))
151 base_ident = base_ident + String_convert::to_lower (string (name, prev_pos, cur_pos - prev_pos)) + "-";
154 base_ident += String_convert::to_lower (string (name, prev_pos, cur_pos - prev_pos));
157 be careful, as we don't want to loose references to the _sym_ members.
159 Pedal_type_info info;
160 info.event_class_sym_ = scm_str2symbol ((base_ident + "-event").c_str ());
161 info.style_sym_ = scm_str2symbol (("pedal" + base_name + "Style").c_str ());
162 info.strings_sym_ = scm_str2symbol (("pedal" + base_name + "Strings").c_str ());
164 info.pedal_line_spanner_c_str_ = strdup ((base_name + "PedalLineSpanner").c_str ());
165 info.base_name_ = name;
166 info.pedal_c_str_ = strdup ((base_name + "Pedal").c_str ());
170 pedal_types_[i] = info;
173 ADD_SCM_INIT_FUNC (Piano_pedal_engraver_init_pedal_types_, init_pedal_types);
175 Piano_pedal_engraver::Piano_pedal_engraver ()
180 Piano_pedal_engraver::initialize ()
182 for (int i = 0; i < NUM_PEDAL_TYPES; i++)
184 Pedal_type_info *s = &pedal_types_[i];
185 Pedal_info *info = &info_list_[i];
190 info->finished_bracket_ = 0;
191 info->line_spanner_ = 0;
192 info->finished_line_spanner_ = 0;
193 info->current_bracket_ev_ = 0;
194 info->event_drul_[START] = 0;
195 info->event_drul_[STOP] = 0;
198 info_list_[NUM_PEDAL_TYPES].type_ = 0;
201 Piano_pedal_engraver::~Piano_pedal_engraver ()
210 Piano_pedal_engraver::acknowledge_note_column (Grob_info info)
212 for (Pedal_info *p = info_list_; p->type_; p++)
214 if (p->line_spanner_)
216 Side_position_interface::add_support (p->line_spanner_, info.grob ());
217 add_bound_item (p->line_spanner_, info.grob ());
220 add_bound_item (p->bracket_, info.grob ());
221 if (p->finished_bracket_)
222 add_bound_item (p->finished_bracket_, info.grob ());
226 IMPLEMENT_TRANSLATOR_LISTENER (Piano_pedal_engraver, sostenuto);
228 Piano_pedal_engraver::listen_sostenuto (Stream_event *r)
230 Direction d = to_dir (r->get_property ("span-direction"));
231 info_list_[SOSTENUTO].event_drul_[d] = r;
234 IMPLEMENT_TRANSLATOR_LISTENER (Piano_pedal_engraver, sustain);
236 Piano_pedal_engraver::listen_sustain (Stream_event *r)
238 Direction d = to_dir (r->get_property ("span-direction"));
239 info_list_[SUSTAIN].event_drul_[d] = r;
242 IMPLEMENT_TRANSLATOR_LISTENER (Piano_pedal_engraver, una_corda);
244 Piano_pedal_engraver::listen_una_corda (Stream_event *r)
246 Direction d = to_dir (r->get_property ("span-direction"));
247 info_list_[UNA_CORDA].event_drul_[d] = r;
251 Piano_pedal_engraver::process_music ()
253 for (Pedal_info *p = info_list_; p->type_; p++)
255 if (p->event_drul_[STOP] || p->event_drul_[START])
257 if (!p->line_spanner_)
259 const char *name = p->type_->pedal_line_spanner_c_str_;
260 Stream_event *rq = (p->event_drul_[START] ? p->event_drul_[START] : p->event_drul_[STOP]);
261 p->line_spanner_ = make_spanner (name, rq->self_scm ());
264 /* Choose the appropriate grobs to add to the line spanner
265 These can be text items or text-spanners
269 ugh, code dup, should read grob to create from other
272 bracket: |_________/\____|
274 mixed: Ped. _____/\____|
277 SCM style = internal_get_property (p->type_->style_sym_);
279 bool mixed = style == ly_symbol2scm ("mixed");
280 bool bracket = (mixed
281 || style == ly_symbol2scm ("bracket"));
282 bool text = (style == ly_symbol2scm ("text")
285 if (text && !p->item_)
286 create_text_grobs (p, mixed);
288 create_bracket_grobs (p, mixed);
294 Piano_pedal_engraver::create_text_grobs (Pedal_info *p, bool mixed)
297 SCM strings = internal_get_property (p->type_->strings_sym_);
299 if (scm_ilength (strings) < 3)
301 Stream_event *m = p->event_drul_[START];
302 if (!m) m = p->event_drul_ [STOP];
304 string msg = _f ("expect 3 strings for piano pedals, found: %ld",
305 scm_ilength (strings));
307 m->origin ()->warning (msg);
314 if (p->event_drul_[STOP] && p->event_drul_[START])
319 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->type_->base_name_.c_str ()));
321 s = scm_cadr (strings);
322 p->start_ev_ = p->event_drul_[START];
325 else if (p->event_drul_[STOP])
330 p->event_drul_[STOP]->origin ()->warning (_f ("can't find start of piano pedal: `%s'", p->type_->base_name_.c_str ()));
332 s = scm_caddr (strings);
336 else if (p->event_drul_[START])
338 p->start_ev_ = p->event_drul_[START];
339 s = scm_car (strings);
343 Code dup?! see below.
345 if (previous_.size ())
346 // add extra space below the previous already-occuring pedal
347 Side_position_interface::add_support (p->line_spanner_,
349 previous_.push_back (p->line_spanner_);
353 if (scm_is_string (s))
355 const char *propname = p->type_->pedal_c_str_;
357 p->item_ = make_item (propname, (p->event_drul_[START]
358 ? p->event_drul_[START]
359 : p->event_drul_[STOP])->self_scm ());
361 p->item_->set_property ("text", s);
362 Axis_group_interface::add_element (p->line_spanner_, p->item_);
367 p->event_drul_[START] = 0;
368 p->event_drul_[STOP] = 0;
373 Piano_pedal_engraver::create_bracket_grobs (Pedal_info *p, bool mixed)
375 if (!p->bracket_ && p->event_drul_[STOP])
377 string msg = _f ("can't find start of piano pedal bracket: `%s'", p->type_->base_name_.c_str ());
378 p->event_drul_[STOP]->origin ()->warning (msg);
379 p->event_drul_[STOP] = 0;
382 if (p->event_drul_[STOP])
384 assert (!p->finished_bracket_);
386 Grob *cmc = unsmob_grob (get_property ("currentMusicalColumn"));
388 if (!p->bracket_->get_bound (RIGHT))
389 p->bracket_->set_bound (RIGHT, cmc);
392 Set properties so that the stencil-creating function will
393 know whether the right edge should be flared ___/
396 if (!p->event_drul_[START])
398 SCM flare = p->bracket_->get_property ("bracket-flare");
399 p->bracket_->set_property ("bracket-flare", scm_cons (scm_car (flare),
400 scm_from_double (0)));
403 p->finished_bracket_ = p->bracket_;
405 p->current_bracket_ev_ = 0;
408 if (p->event_drul_[START])
410 p->start_ev_ = p->event_drul_[START];
411 p->current_bracket_ev_ = p->event_drul_[START];
413 p->bracket_ = make_spanner ("PianoPedalBracket", p->event_drul_[START]->self_scm ());
416 Set properties so that the stencil-creating function will
417 know whether the left edge should be flared \___
420 if (!p->finished_bracket_)
422 SCM flare = p->bracket_->get_property ("bracket-flare");
423 p->bracket_->set_property ("bracket-flare", scm_cons (scm_from_double (0), scm_cdr (flare)));
426 /* Set this property for 'mixed style' pedals, Ped._______/\ ,
427 so the stencil function will shorten the ____ line by the length of the Ped. text.
433 Mixed style: Store a pointer to the preceding text for use in
434 calculating the length of the line
439 WTF is pedal-text not the bound of the object? --hwn
442 p->bracket_->set_object ("pedal-text", p->item_->self_scm ());
446 We do not use currentMusicalColumn for the left span-point.
447 If the column as accidentals (eg on a different stave), the
448 currentMusicalColumn is too wide, making the bracket too big.
452 Hmm. What do we do when there are no notes when the spanner starts?
456 what about the right span point?
459 Axis_group_interface::add_element (p->line_spanner_, p->bracket_);
461 if (!p->event_drul_[STOP])
467 // position new pedal spanner below the current one
469 if (previous_.size ())
470 Side_position_interface::add_support (p->line_spanner_, previous_.back ());
472 previous_.push_back (p->line_spanner_);
476 p->event_drul_[START] = 0;
477 p->event_drul_[STOP] = 0;
481 Piano_pedal_engraver::finalize ()
483 for (Pedal_info *p = info_list_; p->type_; p++)
489 && !p->line_spanner_->is_live ())
490 p->line_spanner_ = 0;
493 && !p->bracket_->is_live ())
498 SCM cc = get_property ("currentCommandColumn");
499 Item *c = unsmob_item (cc);
500 if (p->line_spanner_)
501 p->line_spanner_->set_bound (RIGHT, c);
502 p->bracket_->set_bound (RIGHT, c);
504 p->finished_bracket_ = p->bracket_;
506 p->finished_line_spanner_ = p->line_spanner_;
507 p->line_spanner_ = 0;
511 if (p->line_spanner_)
513 p->finished_line_spanner_ = p->line_spanner_;
520 Piano_pedal_engraver::del_linespanner (Spanner *g)
522 vsize idx = find (previous_, g) - previous_.begin ();
523 if (idx != VPOS && idx < previous_.size ())
524 previous_.erase (previous_.begin () + idx);
528 Piano_pedal_engraver::stop_translation_timestep ()
530 for (Pedal_info *p = info_list_; p->type_; p++)
534 p->finished_line_spanner_ = p->line_spanner_;
535 p->line_spanner_ = 0;
536 del_linespanner (p->finished_line_spanner_);
542 for (Pedal_info *p = info_list_; p->type_; p++)
544 p->event_drul_[STOP] = 0;
545 p->event_drul_[START] = 0;
550 Piano_pedal_engraver::typeset_all (Pedal_info *p)
555 if (p->finished_line_spanner_
556 && !p->finished_line_spanner_->is_live ())
557 p->finished_line_spanner_ = 0;
558 if (p->finished_bracket_
559 && !p->finished_bracket_->is_live ())
560 p->finished_bracket_ = 0;
565 if (p->finished_bracket_)
567 Grob *r = p->finished_bracket_->get_bound (RIGHT);
569 p->finished_bracket_->set_bound (RIGHT, unsmob_grob (get_property ("currentMusicalColumn")));
571 p->finished_bracket_ = 0;
574 if (p->finished_line_spanner_)
576 Grob *l = p->finished_line_spanner_->get_bound (LEFT);
577 Grob *r = p->finished_line_spanner_->get_bound (RIGHT);
579 p->finished_line_spanner_->set_bound (RIGHT, l);
581 p->finished_line_spanner_->set_bound (LEFT, r);
584 Grob *cc = unsmob_grob (get_property ("currentMusicalColumn"));
585 Item *ci = dynamic_cast<Item *> (cc);
586 p->finished_line_spanner_->set_bound (RIGHT, ci);
587 p->finished_line_spanner_->set_bound (LEFT, ci);
590 p->finished_line_spanner_ = 0;
594 ADD_ACKNOWLEDGER (Piano_pedal_engraver, note_column);
596 ADD_TRANSLATOR (Piano_pedal_engraver,
599 "Engrave piano pedal symbols and brackets.",
603 "SostenutoPedalLineSpanner "
605 "SustainPedalLineSpanner "
607 "UnaCordaPedalLineSpanner ",
613 "currentCommandColumn "
614 "pedalSostenutoStrings "
615 "pedalSostenutoStyle "
616 "pedalSustainStrings "
618 "pedalUnaCordaStrings "
619 "pedalUnaCordaStyle",