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