]> git.donarmstrong.com Git - lilypond.git/blob - lily/volta-engraver.cc
Nitpick run.
[lilypond.git] / lily / volta-engraver.cc
1 /*
2   volta-engraver.cc -- implement Volta_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2000--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "engraver.hh"
10 #include "context.hh"
11 #include "volta-bracket.hh"
12 #include "note-column.hh"
13 #include "bar-line.hh"
14 #include "side-position-interface.hh"
15 #include "warn.hh"
16 #include "staff-symbol.hh"
17
18 #include "translator.icc"
19
20 /*
21   Create Volta spanners, by reading repeatCommands  property, usually
22   set by Unfolded_repeat_iterator.
23 */
24 class Volta_engraver : public Engraver
25 {
26 public:
27   TRANSLATOR_DECLARATIONS (Volta_engraver);
28 protected:
29
30   DECLARE_ACKNOWLEDGER (staff_symbol);
31   DECLARE_ACKNOWLEDGER (note_column);
32   DECLARE_ACKNOWLEDGER (bar_line);
33
34   virtual void finalize ();
35   virtual void derived_mark () const;
36   void stop_translation_timestep ();
37   void process_music ();
38
39   Moment started_mom_;
40   Spanner *volta_span_;
41   Spanner *end_volta_span_;
42   SCM staff_;
43   SCM start_string_;
44
45   bool staff_eligible ();
46 };
47
48 void
49 Volta_engraver::derived_mark () const
50 {
51   scm_gc_mark (staff_);
52   scm_gc_mark (start_string_);
53 }
54
55 Volta_engraver::Volta_engraver ()
56 {
57   staff_ = SCM_EOL;
58   start_string_ = SCM_EOL;
59   volta_span_ = 0;
60   end_volta_span_ = 0;
61 }
62
63 /*
64   TODO: this logic should be rewritten, it is buggy.
65
66   One of the problems is that we can't determine wether or not to
67   print the volta bracket during the first step, since that requires
68   acknowledging the staff.
69 */
70 bool
71 Volta_engraver::staff_eligible ()
72 {
73   SCM doit = get_property ("voltaOnThisStaff");
74   if (scm_is_bool (doit))
75     return to_boolean (doit);
76
77   if (!unsmob_grob (staff_))
78     return false;
79
80   /*
81     TODO: this does weird things when you open a piece with a
82     volta spanner.
83   */
84   SCM staffs = get_property ("stavesFound");
85
86   /* Only put a volta on the top staff.
87      Maybe this is a bit convoluted, and we should have a single
88      volta engraver in score context or somesuch. */
89   if (!scm_is_pair (staffs))
90     {
91       programming_error ("volta engraver can't find staffs");
92       return false;
93     }
94   else if (scm_car (scm_last_pair (staffs)) != staff_)
95     return false;
96   return true;
97 }
98
99 void
100 Volta_engraver::process_music ()
101 {
102   SCM cs = get_property ("repeatCommands");
103
104   if (!staff_eligible ())
105     return;
106
107   bool end = false;
108   start_string_ = SCM_EOL;
109   while (scm_is_pair (cs))
110     {
111       SCM c = scm_car (cs);
112
113       if (scm_is_pair (c)
114           && scm_car (c) == ly_symbol2scm ("volta")
115           && scm_is_pair (scm_cdr (c)))
116         {
117           if (scm_cadr (c) == SCM_BOOL_F)
118             end = true;
119           else
120             start_string_ = scm_cadr (c);
121         }
122
123       cs = scm_cdr (cs);
124     }
125
126   if (volta_span_)
127     {
128       SCM l (get_property ("voltaSpannerDuration"));
129       Moment now = now_mom ();
130
131       bool early_stop = unsmob_moment (l)
132         && *unsmob_moment (l) <= now - started_mom_;
133
134       end = end || early_stop;
135     }
136
137   if (end && !volta_span_)
138     /* fixme: be more verbose.  */
139     warning (_ ("can't end volta spanner"));
140   else if (end)
141     {
142       end_volta_span_ = volta_span_;
143       volta_span_ = 0;
144     }
145
146   if (volta_span_
147       && (scm_is_string (start_string_) || scm_is_pair (start_string_)))
148     {
149       warning (_ ("already have a volta spanner, ending that one prematurely"));
150
151       if (end_volta_span_)
152         {
153           warning (_ ("also already have an ended spanner"));
154           warning (_ ("giving up"));
155           return;
156         }
157
158       end_volta_span_ = volta_span_;
159       volta_span_ = 0;
160     }
161
162   if (!volta_span_
163       && (scm_is_string (start_string_) || scm_is_pair (start_string_)))
164     {
165       started_mom_ = now_mom ();
166
167       volta_span_ = make_spanner ("VoltaBracket", SCM_EOL);
168
169       volta_span_->set_property ("text", start_string_);
170     }
171 }
172
173 void
174 Volta_engraver::acknowledge_note_column (Grob_info i)
175 {
176   if (volta_span_)
177     Volta_bracket_interface::add_column (volta_span_, i.grob ());
178 }
179
180 void
181 Volta_engraver::acknowledge_bar_line (Grob_info i)
182 {
183   if (volta_span_)
184     Volta_bracket_interface::add_bar (volta_span_, i.item ());
185   if (end_volta_span_)
186     Volta_bracket_interface::add_bar (end_volta_span_, i.item ());
187 }
188
189 void
190 Volta_engraver::acknowledge_staff_symbol (Grob_info i)
191 {
192   /*
193     We only want to know about a single staff: then we add to the
194     support.  */
195   if (staff_ != SCM_EOL)
196     staff_ = SCM_UNDEFINED;
197
198   if (staff_ != SCM_UNDEFINED)
199     staff_ = i.grob ()->self_scm ();
200 }
201
202 void
203 Volta_engraver::finalize ()
204 {
205 }
206
207 void
208 Volta_engraver::stop_translation_timestep ()
209 {
210   if (volta_span_ && !staff_eligible ())
211     {
212       /*
213         THIS IS A KLUDGE.
214
215         we need to do this here, because STAFF_ is not initialized yet
216         in the 1st call of process_music ()
217       */
218
219       volta_span_->suicide ();
220       volta_span_ = 0;
221     }
222
223   if (end_volta_span_ && !end_volta_span_->get_bound (RIGHT))
224     {
225       Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
226       Item *ci = dynamic_cast<Item *> (cc);
227       end_volta_span_->set_bound (RIGHT, ci);
228     }
229
230   end_volta_span_ = 0;
231
232   if (volta_span_ && !volta_span_->get_bound (LEFT))
233     {
234       Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
235       Item *ci = dynamic_cast<Item *> (cc);
236       volta_span_->set_bound (LEFT, ci);
237     }
238 }
239
240 /*
241   TODO: should attach volta to paper-column if no bar is found.
242 */
243 ADD_ACKNOWLEDGER (Volta_engraver, staff_symbol);
244 ADD_ACKNOWLEDGER (Volta_engraver, note_column);
245 ADD_ACKNOWLEDGER (Volta_engraver, bar_line);
246 ADD_TRANSLATOR (Volta_engraver,
247                 /* doc */ "Make volta brackets.",
248                 /* create */ "VoltaBracket",
249                 /* accept */ "",
250                 /* read */ "repeatCommands voltaSpannerDuration stavesFound",
251                 /* write */ "");