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