release commit
[lilypond.git] / lily / volta-engraver.cc
blob4112fb45d23630460879ee62bc393f9392a4d4e4
1 /*
2 volta-engraver.cc -- implement Volta_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 */
10 #include "engraver.hh"
11 #include "context.hh"
12 #include "volta-bracket.hh"
13 #include "note-column.hh"
14 #include "bar-line.hh"
15 #include "side-position-interface.hh"
16 #include "warn.hh"
17 #include "staff-symbol.hh"
20 Create Volta spanners, by reading repeatCommands property, usually
21 set by Unfolded_repeat_iterator.
23 class Volta_engraver : public Engraver
25 public:
26 TRANSLATOR_DECLARATIONS (Volta_engraver);
27 protected:
29 virtual void acknowledge_grob (Grob_info);
30 virtual void finalize ();
31 virtual void stop_translation_timestep ();
32 virtual void process_music ();
34 virtual void derived_mark () const;
35 Moment started_mom_;
36 Spanner *volta_span_;
37 Spanner *end_volta_span_;
38 SCM staff_;
39 SCM start_string_;
41 bool staff_eligible ();
44 void
45 Volta_engraver::derived_mark () const
47 scm_gc_mark (staff_);
48 scm_gc_mark (start_string_);
51 Volta_engraver::Volta_engraver ()
53 start_string_ = SCM_EOL;
54 staff_ = SCM_EOL;
55 volta_span_ = 0;
56 end_volta_span_ = 0;
60 TODO: this logic should be rewritten, it is buggy.
62 One of the problems is that we can't determine wether or not to
63 print the volta bracket during the first step, since that requires
64 acknowledging the staff.
66 bool
67 Volta_engraver::staff_eligible ()
69 SCM doit = get_property ("voltaOnThisStaff");
70 if (scm_is_bool (doit))
72 return to_boolean (doit);
75 if (!unsmob_grob (staff_))
76 return false;
79 TODO: this does weird things when you open a piece with a
80 volta spanner.
82 SCM staffs = get_property ("stavesFound");
84 /* Only put a volta on the top staff.
85 Maybe this is a bit convoluted, and we should have a single
86 volta engraver in score context or somesuch. */
87 if (!scm_is_pair (staffs))
89 programming_error ("volta engraver can't find staffs");
90 return false;
92 else if (scm_car (scm_last_pair (staffs)) != staff_)
93 return false;
94 return true;
97 void
98 Volta_engraver::process_music ()
100 SCM cs = get_property ("repeatCommands");
102 if (!staff_eligible ())
103 return;
105 bool end = false;
106 start_string_ = SCM_EOL;
107 while (scm_is_pair (cs))
109 SCM c = scm_car (cs);
111 if (scm_is_pair (c)
112 && scm_car (c) == ly_symbol2scm ("volta")
113 && scm_is_pair (scm_cdr (c)))
115 if (scm_cadr (c) == SCM_BOOL_F)
116 end = true;
117 else
118 start_string_ = scm_cadr (c);
121 cs = scm_cdr (cs);
124 if (volta_span_)
126 SCM l (get_property ("voltaSpannerDuration"));
127 Moment now = now_mom ();
129 bool early_stop = unsmob_moment (l)
130 && *unsmob_moment (l) <= now - started_mom_;
132 end = end || early_stop;
135 if (end && !volta_span_)
136 /* fixme: be more verbose. */
137 warning (_ ("can't end volta spanner"));
138 else if (end)
140 end_volta_span_ = volta_span_;
141 volta_span_ = 0;
144 if (volta_span_
145 && (scm_is_string (start_string_) || scm_is_pair (start_string_)))
147 warning (_ ("already have a volta spanner, ending that one prematurely"));
149 if (end_volta_span_)
151 warning (_ ("also already have an ended spanner"));
152 warning (_ ("giving up"));
153 return;
156 end_volta_span_ = volta_span_;
157 volta_span_ = 0;
160 if (!volta_span_
161 && (scm_is_string (start_string_) || scm_is_pair (start_string_)))
163 started_mom_ = now_mom ();
165 volta_span_ = make_spanner ("VoltaBracket", SCM_EOL);
167 volta_span_->set_property ("text", start_string_);
171 void
172 Volta_engraver::acknowledge_grob (Grob_info i)
174 if (Item *item = dynamic_cast<Item *> (i.grob ()))
176 if (Note_column::has_interface (item))
178 if (volta_span_)
179 Volta_bracket_interface::add_column (volta_span_, item);
181 if (Bar_line::has_interface (item))
183 if (volta_span_)
184 Volta_bracket_interface::add_bar (volta_span_, item);
185 if (end_volta_span_)
186 Volta_bracket_interface::add_bar (end_volta_span_, item);
189 else if (Staff_symbol::has_interface (i.grob ()))
192 We only want to know about a single staff: then we add to the
193 support. */
194 if (staff_ != SCM_EOL)
195 staff_ = SCM_UNDEFINED;
197 if (staff_ != SCM_UNDEFINED)
198 staff_ = i.grob ()->self_scm ();
202 void
203 Volta_engraver::finalize ()
207 void
208 Volta_engraver::stop_translation_timestep ()
210 if (volta_span_ && !staff_eligible ())
213 THIS IS A KLUDGE.
215 we need to do this here, because STAFF_ is not initialized yet
216 in the 1st call of process_music ()
219 volta_span_->suicide ();
220 volta_span_ = 0;
223 if (end_volta_span_ && !end_volta_span_->get_bound (RIGHT))
225 Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
226 Item *ci = dynamic_cast<Item *> (cc);
227 end_volta_span_->set_bound (RIGHT, ci);
230 end_volta_span_ = 0;
232 if (volta_span_ && !volta_span_->get_bound (LEFT))
234 Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
235 Item *ci = dynamic_cast<Item *> (cc);
236 volta_span_->set_bound (LEFT, ci);
241 TODO: should attach volta to paper-column if no bar is found.
244 ADD_TRANSLATOR (Volta_engraver,
245 /* descr */ "Make volta brackets.",
246 /* creats*/ "VoltaBracket",
247 /* accepts */ "",
248 /* acks */ "bar-line-interface staff-symbol-interface note-column-interface",
249 /* reads */ "repeatCommands voltaSpannerDuration stavesFound",
250 /* write */ "");