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