]> git.donarmstrong.com Git - lilypond.git/blob - lily/volta-engraver.cc
(LY_DEFINE): use Scheme style naming for
[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   /*
64     UGH.
65    */
66   if (!unsmob_grob (staff_))
67     return true;
68   
69   if (!to_boolean (get_property ("voltaOnThisStaff")))
70     {
71       /*
72         TODO: this does weird things when you open a piece with a
73         volta spanner.
74         
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 (!gh_pair_p (staffs))
86         {
87           programming_error ("Huh? Volta engraver can't find staffs?");
88           return false;
89         }
90       else if (ly_car (scm_last_pair (staffs)) != staff_)
91         {
92           return false;
93         }
94     }
95   return true;
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 (gh_pair_p (cs))
110     {
111       SCM c = ly_car (cs);
112
113       if (gh_pair_p (c)
114           && ly_car (c) == ly_symbol2scm ("volta")
115           && gh_pair_p (ly_cdr (c)))
116         {
117           if (ly_cadr (c) ==  SCM_BOOL_F)
118             end = true;
119           else
120             start_string_ = ly_cadr (c);
121         }
122       
123       cs = ly_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       (gh_string_p (start_string_) || gh_pair_p (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       (gh_string_p (start_string_) || gh_pair_p (start_string_)))
165     {
166       started_mom_ = now_mom () ;
167
168       volta_span_ = make_spanner ("VoltaBracket");
169
170       announce_grob (volta_span_, SCM_EOL);
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   if (volta_span_)
211     {
212       typeset_grob (volta_span_);
213     }
214   if (end_volta_span_)
215     {
216       typeset_grob (end_volta_span_);
217     }
218 }
219
220
221
222 void 
223 Volta_engraver::stop_translation_timestep ()
224 {
225   if (volta_span_ && !staff_eligible ())
226     {
227       /*
228         THIS IS A KLUDGE.
229
230         we need to do this here, because STAFF_ is not initialized yet
231         in the 1st call of process_music()
232       */
233       
234       volta_span_->suicide( );
235       volta_span_ = 0;
236     }
237   
238   if (end_volta_span_)
239     {
240       typeset_grob (end_volta_span_);
241       end_volta_span_ =0;
242     }
243 }
244
245 /*
246   TODO: should attach volta to paper-column if no bar is found.
247  */
248
249 ENTER_DESCRIPTION(Volta_engraver,
250 /* descr */       "Make volta brackets",
251 /* creats*/       "VoltaBracket",
252 /* accepts */     "",
253 /* acks  */       "bar-line-interface staff-symbol-interface note-column-interface",
254 /* reads */       "repeatCommands voltaSpannerDuration stavesFound",
255 /* write */       "");