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