]> git.donarmstrong.com Git - lilypond.git/blob - lily/repeat-engraver.cc
release: 1.3.33
[lilypond.git] / lily / repeat-engraver.cc
1 /*
2   repeat-engraver.cc -- implement Repeat_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2000 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
8
9 #include "repeat-engraver.hh"
10 #include "bar.hh"
11 #include "bar-engraver.hh"
12 #include "musical-request.hh"
13 #include "multi-measure-rest.hh"
14 #include "command-request.hh"
15 #include "timing-translator.hh"
16 #include "engraver-group-engraver.hh"
17 #include "repeated-music.hh"
18 #include "timing-translator.hh"
19 #include "volta-spanner.hh"
20 #include "note-column.hh"
21 #include "paper-def.hh"
22 #include "music-list.hh"
23
24 ADD_THIS_TRANSLATOR (Repeat_engraver);
25
26 bool
27 Repeat_engraver::do_try_music (Music* m)
28 {
29   if (Repeated_music* r = dynamic_cast<Repeated_music *> (m))
30     {
31       if (repeated_music_l_)
32         return false;
33       
34       if (r->volta_fold_b_)
35         {
36           repeated_music_l_ = r;
37         }
38
39       /*
40         We acknowledge other types of unfolded music as well, to
41         get auto context selection right.
42        */
43       return true;
44
45     }
46   return false;
47 }
48
49 /**
50  Walk through repeat music, and generate events for appropriate times.
51
52  UGH. Should use Music_iteration for this.
53
54  Should also queue some event to get timing information reset during
55  2nd and following voltas.
56 */
57 void
58 Repeat_engraver::queue_events ()
59 {
60   Music_sequence* alt = repeated_music_l_->alternatives_p_;
61   Moment walk_mom = now_mom () + repeated_music_l_->repeat_body_p_->length_mom ();
62
63   SCM novolta = get_property ("noVoltaBraces");
64   bool create_volta = !to_boolean (novolta);
65
66   Cons_list<Bar_create_event> becel;
67   becel.append (new Bar_create_event (now_mom (), "|:"));
68
69   if (!alt)
70     {
71       becel.append  (new Bar_create_event (walk_mom, ":|"));
72       becel.append  (new Bar_create_event (walk_mom, "stop"));
73    }
74   else
75     {
76       int last_number = 0;
77       int volta_number = repeated_music_l_->repeats_i_ - alt->length_i () + 1;
78
79       /*
80         all repeat alternatives, and generate events with
81         appropriate timestamps. The volta spanner event (a number string)
82         happens at the begin of the alt. The :| bar event at the ending.
83       */
84       for (Cons<Music> *i = alt->music_p_list_p_->head_; i; i = i->next_)
85         {
86
87           /*
88             some idiot might typeset a repeat not starting on a
89             barline.  Make sure there is one.
90
91             (todo: should try to avoid line breaks?)
92           */
93           if (last_number == 0)
94             {
95               becel.append (new Bar_create_event (walk_mom, ""));
96             }
97
98           
99           if (create_volta)
100             {
101               Bar_create_event * c = new Bar_create_event (walk_mom, last_number+ 1,
102                                                            volta_number);
103               
104               if (!i->next_)
105                 c->last_b_ = true;
106               
107               becel.append (c);
108               last_number = volta_number;
109               volta_number ++;
110               SCM l (get_property ("voltaSpannerDuration"));
111               if (SMOB_IS_TYPE_B (Moment, l))
112                 {
113                   Moment vSD_mom = *SMOB_TO_TYPE (Moment,l);
114                   if ( vSD_mom < i->car_->length_mom() ) // terminate volta early ?
115                     {
116                       vSD_mom += walk_mom;
117                       c->last_b_ = true;
118                       becel.append (new Bar_create_event (vSD_mom, "stop"));
119                     }
120                 }
121             }
122           walk_mom += i->car_->length_mom();
123
124           if (i->next_)
125             becel.append (new Bar_create_event (walk_mom, ":|"));
126           else
127             becel.append (new Bar_create_event (walk_mom, "stop"));
128         }
129     }
130
131   Cons<Bar_create_event> *&tail = create_barmoments_queue_
132     ? last_cons (create_barmoments_queue_)->next_
133     : create_barmoments_queue_;
134
135   tail = becel.head_ ;
136   becel.head_ = 0;
137 }
138
139 void
140 Repeat_engraver::do_process_music ()
141 {
142   if (repeated_music_l_ && !done_this_one_b_)
143     { 
144       queue_events ();
145       done_this_one_b_ = true;
146     }
147   
148   
149   Cons<Bar_create_event> * head =   create_barmoments_queue_;
150   if (!head)
151     return;
152
153   Bar_engraver* bar_engraver_l = dynamic_cast <Bar_engraver*>
154     (daddy_grav_l ()->get_simple_translator ("Bar_engraver"));
155
156   /*
157     Do all the events that need to be done now.
158   */
159   while (head && now_mom () == head->car_->when_)
160     {
161       create_barmoments_queue_ = create_barmoments_queue_->next_;
162       head->next_ =0;
163       if (bar_engraver_l)
164         {
165           String t = head->car_->type_;
166           if (head->car_->bar_b_)
167             {
168               if (t == "stop" || t == ":|")
169                 {
170                   end_volta_span_p_ = volta_span_p_;
171                   volta_span_p_ =0;
172                 }
173
174               if (t != "stop")
175                 bar_engraver_l->request_bar (t);
176               else
177                 bar_engraver_l->request_bar (""); 
178             }
179           else
180             {
181               assert (!volta_span_p_);
182               volta_span_p_ = new Volta_spanner;
183               announce_element (Score_element_info (volta_span_p_,0));
184               volta_span_p_->set_elt_property ("text",
185                                                ly_str02scm (t.ch_C()));
186               volta_span_p_->set_elt_property ("last-volta",
187                                                gh_bool2scm (head->car_->last_b_));
188               // voltaSpannerDuration stuff here.
189               // other property stuff here.
190             }
191           
192         }
193       else
194         {
195           warning (_ ("No bar engraver found.  Ignoring repeats."));
196         }
197
198       delete head->car_;
199       delete head;
200
201       head = create_barmoments_queue_;
202     }
203
204   assert (!head || head->car_->when_ > now_mom ());
205 }  
206
207
208 void
209 Repeat_engraver::acknowledge_element (Score_element_info i)
210 {
211   if (Note_column *c = dynamic_cast<Note_column *> (i.elem_l_))
212     {
213       if (volta_span_p_)
214         volta_span_p_->add_column (c);
215       if (end_volta_span_p_)
216         end_volta_span_p_->add_column (c);      
217     }
218   if (Bar *c = dynamic_cast<Bar*> (i.elem_l_))
219     {
220       if (volta_span_p_)
221         volta_span_p_->add_bar (c);
222       if (end_volta_span_p_)
223         end_volta_span_p_ ->add_bar(c);
224     }
225 }
226
227
228 void
229 Repeat_engraver::do_removal_processing ()
230 {
231   if (volta_span_p_)
232     {
233       typeset_element(volta_span_p_);
234     }
235   if (end_volta_span_p_)
236     {
237       typeset_element (end_volta_span_p_);
238     }
239   // todo: the paranoid may also delete create_barmoments_queue_
240 }
241
242 void
243 Repeat_engraver::do_post_move_processing ()
244 {
245   for (Cons<Bar_create_event> *p = create_barmoments_queue_;
246        p && p->car_->when_ == now_mom (); p = p->next_)
247     if (p->car_->type_ == "stop")
248       {
249         repeated_music_l_ = 0;
250         done_this_one_b_ = false;
251       }
252 }
253
254 void 
255 Repeat_engraver::do_pre_move_processing ()
256 {
257   if (end_volta_span_p_)
258     {
259       typeset_element (end_volta_span_p_ );
260       end_volta_span_p_ =0;
261     }
262     
263 }
264
265
266 Repeat_engraver::Repeat_engraver()
267 {
268   repeated_music_l_ =0;
269   end_volta_span_p_ =0;
270   volta_span_p_ =0;
271   done_this_one_b_ = false;
272   create_barmoments_queue_ =0;
273 }
274                                  
275 /* ************** */
276 Bar_create_event::Bar_create_event()
277 {
278   last_b_ =false;
279   bar_b_ = true;
280 }
281
282 Bar_create_event::Bar_create_event (Moment w, String s)
283 {
284   last_b_ =false;
285   when_ = w;
286   type_ = s;
287   bar_b_ = true;
288 }
289
290 Bar_create_event::Bar_create_event (Moment w, int i, int j)
291 {
292   last_b_ =false;
293   when_ = w ;
294   bar_b_ = false;
295
296   if (i!=j)
297     type_ = to_str (i) + ".-" ;
298
299   type_ += to_str(j) + ".";
300 }