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