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