]> 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 /*
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   /* Only put a volta on the top staff.
75      Maybe this is a bit convoluted, and we should have a single
76      volta engraver in score context or somesuch. */
77   if (!scm_is_pair (staffs))
78     {
79       programming_error ("volta engraver can't find staffs");
80       return false;
81     }
82   else if (scm_car (scm_last_pair (staffs)) != staff_)
83     return false;
84   return true;
85 }
86
87 void
88 Volta_engraver::process_music ()
89 {
90   SCM cs = get_property ("repeatCommands");
91
92   if (!staff_eligible ())
93     return;
94
95   bool end = false;
96   start_string_ = SCM_EOL;
97   while (scm_is_pair (cs))
98     {
99       SCM c = scm_car (cs);
100
101       if (scm_is_pair (c)
102           && scm_car (c) == ly_symbol2scm ("volta")
103           && scm_is_pair (scm_cdr (c)))
104         {
105           if (scm_cadr (c) == SCM_BOOL_F)
106             end = true;
107           else
108             start_string_ = scm_cadr (c);
109         }
110
111       cs = scm_cdr (cs);
112     }
113
114   if (volta_span_)
115     {
116       SCM l (get_property ("voltaSpannerDuration"));
117       Moment now = now_mom ();
118
119       bool early_stop = unsmob_moment (l)
120         && *unsmob_moment (l) <= now - started_mom_;
121
122       end = end || early_stop;
123     }
124
125   if (end && !volta_span_)
126     /* fixme: be more verbose.  */
127     warning (_ ("can't end volta spanner"));
128   else if (end)
129     {
130       end_volta_span_ = volta_span_;
131       volta_span_ = 0;
132     }
133
134   if (volta_span_
135       && (scm_is_string (start_string_) || scm_is_pair (start_string_)))
136     {
137       warning (_ ("already have a volta spanner, ending that one prematurely"));
138
139       if (end_volta_span_)
140         {
141           warning (_ ("also already have an ended spanner"));
142           warning (_ ("giving up"));
143           return;
144         }
145
146       end_volta_span_ = volta_span_;
147       volta_span_ = 0;
148     }
149
150   if (!volta_span_
151       && (scm_is_string (start_string_) || scm_is_pair (start_string_)))
152     {
153       started_mom_ = now_mom ();
154
155       volta_span_ = make_spanner ("VoltaBracket", SCM_EOL);
156
157       volta_span_->set_property ("text", start_string_);
158     }
159 }
160
161 void
162 Volta_engraver::acknowledge_grob (Grob_info i)
163 {
164   if (Item *item = dynamic_cast<Item *> (i.grob_))
165     {
166       if (Note_column::has_interface (item))
167         {
168           if (volta_span_)
169             Volta_bracket_interface::add_column (volta_span_, item);
170         }
171       if (Bar_line::has_interface (item))
172         {
173           if (volta_span_)
174             Volta_bracket_interface::add_bar (volta_span_, item);
175           if (end_volta_span_)
176             Volta_bracket_interface::add_bar (end_volta_span_, item);
177         }
178     }
179   else if (Staff_symbol::has_interface (i.grob_))
180     {
181       /*
182         We only want to know about a single staff: then we add to the
183         support.  */
184       if (staff_ != SCM_EOL)
185         staff_ = SCM_UNDEFINED;
186
187       if (staff_ != SCM_UNDEFINED)
188         staff_ = i.grob_->self_scm ();
189     }
190 }
191
192 void
193 Volta_engraver::finalize ()
194 {
195 }
196
197 void
198 Volta_engraver::stop_translation_timestep ()
199 {
200   if (volta_span_ && !staff_eligible ())
201     {
202       /*
203         THIS IS A KLUDGE.
204
205         we need to do this here, because STAFF_ is not initialized yet
206         in the 1st call of process_music ()
207       */
208
209       volta_span_->suicide ();
210       volta_span_ = 0;
211     }
212
213   if (end_volta_span_ && !end_volta_span_->get_bound (RIGHT))
214     {
215       Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
216       Item *ci = dynamic_cast<Item *> (cc);
217       end_volta_span_->set_bound (RIGHT, ci);
218     }
219
220   end_volta_span_ = 0;
221
222   if (volta_span_ && !volta_span_->get_bound (LEFT))
223     {
224       Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
225       Item *ci = dynamic_cast<Item *> (cc);
226       volta_span_->set_bound (LEFT, ci);
227     }
228 }
229
230 /*
231   TODO: should attach volta to paper-column if no bar is found.
232 */
233
234 ADD_TRANSLATOR (Volta_engraver,
235                 /* descr */ "Make volta brackets.",
236                 /* creats*/ "VoltaBracket",
237                 /* accepts */ "",
238                 /* acks  */ "bar-line-interface staff-symbol-interface note-column-interface",
239                 /* reads */ "repeatCommands voltaSpannerDuration stavesFound",
240                 /* write */ "");