]> git.donarmstrong.com Git - lilypond.git/blob - lily/volta-engraver.cc
Update.
[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 /*
19   Create Volta spanners, by reading repeatCommands  property, usually
20   set by Unfolded_repeat_iterator.
21 */
22 class Volta_engraver : public Engraver
23 {
24 public:
25   TRANSLATOR_DECLARATIONS (Volta_engraver);
26 protected:
27
28   virtual void acknowledge_grob (Grob_info);
29   virtual void finalize ();
30   virtual void stop_translation_timestep ();
31   virtual void process_music ();
32
33   Moment started_mom_;
34   Spanner *volta_span_;
35   Spanner *end_volta_span_;
36   SCM staff_;
37   SCM start_string_;
38
39   bool staff_eligible ();
40 };
41
42 Volta_engraver::Volta_engraver ()
43 {
44   staff_ = SCM_EOL;
45   volta_span_ = 0;
46   end_volta_span_ = 0;
47 }
48
49 /*
50   TODO: this logic should be rewritten, it is buggy.
51
52   One of the problems is that we can't determine wether or not to
53   print the volta bracket during the first step, since that requires
54   acknowledging the staff.
55 */
56 bool
57 Volta_engraver::staff_eligible ()
58 {
59   SCM doit = get_property ("voltaOnThisStaff");
60   if (scm_is_bool (doit))
61     {
62       return to_boolean (doit);
63     }
64
65   if (!unsmob_grob (staff_))
66     return false;
67
68   /*
69     TODO: this does weird things when you open a piece with a
70     volta spanner.
71   */
72   SCM staffs = get_property ("stavesFound");
73
74   /*
75     only put a volta on the top staff.
76
77     May be this is a bit convoluted, and we should have a single
78     volta engraver in score context or somesuch.
79
80   */
81   if (!scm_is_pair (staffs))
82     {
83       programming_error ("Huh? Volta engraver can't find staffs?");
84       return false;
85     }
86   else if (scm_car (scm_last_pair (staffs)) != staff_)
87     {
88       return false;
89     }
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     {
133       warning (_ ("No volta spanner to end")); // fixme: be more verbose.
134     }
135   else if (end)
136     {
137       end_volta_span_ = volta_span_;
138       volta_span_ = 0;
139     }
140
141   if (volta_span_
142       && (scm_is_string (start_string_) || scm_is_pair (start_string_)))
143     {
144       warning (_ ("Already have a volta spanner.  Stopping that one prematurely."));
145
146       if (end_volta_span_)
147         {
148           warning (_ ("Also have a stopped spanner.  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_grob (Grob_info i)
169 {
170   if (Item *item = dynamic_cast<Item *> (i.grob_))
171     {
172       if (Note_column::has_interface (item))
173         {
174           if (volta_span_)
175             Volta_bracket_interface::add_column (volta_span_, item);
176         }
177       if (Bar_line::has_interface (item))
178         {
179           if (volta_span_)
180             Volta_bracket_interface::add_bar (volta_span_, item);
181           if (end_volta_span_)
182             Volta_bracket_interface::add_bar (end_volta_span_, item);
183         }
184     }
185   else if (Staff_symbol::has_interface (i.grob_))
186     {
187       /*
188         We only want to know about a single staff: then we add to the
189         support.  */
190       if (staff_ != SCM_EOL)
191         staff_ = SCM_UNDEFINED;
192
193       if (staff_ != SCM_UNDEFINED)
194         staff_ = i.grob_->self_scm ();
195     }
196 }
197
198 void
199 Volta_engraver::finalize ()
200 {
201 }
202
203 void
204 Volta_engraver::stop_translation_timestep ()
205 {
206   if (volta_span_ && !staff_eligible ())
207     {
208       /*
209         THIS IS A KLUDGE.
210
211         we need to do this here, because STAFF_ is not initialized yet
212         in the 1st call of process_music ()
213       */
214
215       volta_span_->suicide ();
216       volta_span_ = 0;
217     }
218
219   if (end_volta_span_ && !end_volta_span_->get_bound (RIGHT))
220     {
221       Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
222       Item *ci = dynamic_cast<Item *> (cc);
223       end_volta_span_->set_bound (RIGHT, ci);
224     }
225
226   end_volta_span_ = 0;
227
228   if (volta_span_ && !volta_span_->get_bound (LEFT))
229     {
230       Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
231       Item *ci = dynamic_cast<Item *> (cc);
232       volta_span_->set_bound (LEFT, ci);
233     }
234 }
235
236 /*
237   TODO: should attach volta to paper-column if no bar is found.
238 */
239
240 ADD_TRANSLATOR (Volta_engraver,
241                 /* descr */ "Make volta brackets.",
242                 /* creats*/ "VoltaBracket",
243                 /* accepts */ "",
244                 /* acks  */ "bar-line-interface staff-symbol-interface note-column-interface",
245                 /* reads */ "repeatCommands voltaSpannerDuration stavesFound",
246                 /* write */ "");