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