]> git.donarmstrong.com Git - lilypond.git/blob - lily/repeat-engraver.cc
2cae99cb0928efa7c90261d7decb198cc91bc921
[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 "engraver.hh"
10 #include "cons.hh"
11 #include "bar.hh"
12 #include "bar-engraver.hh"
13 #include "musical-request.hh"
14 #include "multi-measure-rest.hh"
15 #include "command-request.hh"
16 #include "timing-translator.hh"
17 #include "engraver-group-engraver.hh"
18 #include "repeated-music.hh"
19 #include "timing-translator.hh"
20 #include "volta-spanner.hh"
21 #include "note-column.hh"
22 #include "paper-def.hh"
23 #include "music-list.hh"
24 #include "side-position-interface.hh"
25 #include "spanner.hh"
26 #include "note-column.hh"
27
28 struct Bar_create_event
29 {
30   Moment when_;
31   bool bar_b_;
32   bool last_b_;
33   String type_;
34   Bar_create_event();
35   Bar_create_event (Moment w, String s);
36   Bar_create_event (Moment w, int i, int j);
37 };
38
39 int compare (Bar_create_event const & c1, Bar_create_event const &c2)
40 {
41   return (c1.when_ - c2.when_).sign();
42 }
43
44 /**
45   Generate repeat-bars |: :| for repeated-music
46   */
47 class Repeat_engraver : public Engraver 
48 {
49 public:
50   VIRTUAL_COPY_CONS(Translator);
51   Repeat_engraver ();
52 protected:
53   virtual void acknowledge_element (Score_element_info i);
54   virtual void do_removal_processing ();
55   virtual bool do_try_music (Music *req_l);
56   virtual void do_process_music();
57   virtual void do_pre_move_processing();
58   virtual void do_post_move_processing ();
59   void queue_events ();
60
61 private:
62   Repeated_music *repeated_music_l_;
63   bool done_this_one_b_;
64
65   /*
66     Royal_brackla_create_queue is only two Whiskies away. :-)
67    */
68   Cons<Bar_create_event> *create_barmoments_queue_;
69
70   Spanner * volta_span_p_;
71   Spanner* end_volta_span_p_;
72 };
73
74
75
76
77 ADD_THIS_TRANSLATOR (Repeat_engraver);
78
79 bool
80 Repeat_engraver::do_try_music (Music* m)
81 {
82   if (Repeated_music* r = dynamic_cast<Repeated_music *> (m))
83     {
84       if (repeated_music_l_)
85         return false;
86       
87       if (r->volta_fold_b_)
88         {
89           repeated_music_l_ = r;
90         }
91
92       /*
93         We acknowledge other types of unfolded music as well, to
94         get auto context selection right.
95        */
96       if (r->type_ == "volta" || r->type_ == "unfolded")
97         return true;
98
99     }
100   return false;
101 }
102
103 /**
104  Walk through repeat music, and generate events for appropriate times.
105
106  UGH. Should use Music_iteration for this.
107
108  Should also queue some event to get timing information reset during
109  2nd and following voltas.
110 */
111 void
112 Repeat_engraver::queue_events ()
113 {
114   Music_sequence* alt = repeated_music_l_->alternatives ();
115   Moment walk_mom = now_mom () + repeated_music_l_->body ()->length_mom ();
116
117   SCM novolta = get_property ("noVoltaBraces");
118   bool create_volta = !to_boolean (novolta);
119
120   Cons_list<Bar_create_event> becel;
121   becel.append (new Bar_create_event (now_mom (), "|:"));
122
123   if (!alt)
124     {
125       becel.append  (new Bar_create_event (walk_mom, ":|"));
126       becel.append  (new Bar_create_event (walk_mom, "stop"));
127    }
128   else
129     {
130       int last_number = 0;
131       int volta_number = repeated_music_l_->repeats_i_ - alt->length_i () + 1;
132
133       /*
134         all repeat alternatives, and generate events with
135         appropriate timestamps. The volta spanner event (a number string)
136         happens at the begin of the alt. The :| bar event at the ending.
137       */
138
139   for (SCM s = repeated_music_l_->alternatives ()->music_list ();
140        gh_pair_p (s);  s = gh_cdr (s))
141     {
142       Music *mus =unsmob_music (gh_car (s));
143
144           /*
145             some idiot might typeset a repeat not starting on a
146             barline.  Make sure there is one.
147
148             (todo: should try to avoid line breaks?)
149           */
150           if (last_number == 0)
151             {
152               becel.append (new Bar_create_event (walk_mom, ""));
153             }
154
155           
156           if (create_volta)
157             {
158               Bar_create_event * c = new Bar_create_event (walk_mom, last_number+ 1,
159                                                            volta_number);
160               
161               if (!gh_pair_p (gh_cdr (s)))
162                 c->last_b_ = true;
163               
164               becel.append (c);
165               last_number = volta_number;
166               volta_number ++;
167               SCM l (get_property ("voltaSpannerDuration"));
168               if (unsmob_moment(l))
169                 {
170                   Moment vSD_mom = *unsmob_moment (l);
171                   if ( vSD_mom < mus->length_mom() ) // terminate volta early ?
172                     {
173                       vSD_mom += walk_mom;
174                       c->last_b_ = true;
175                       becel.append (new Bar_create_event (vSD_mom, "stop"));
176                     }
177                 }
178             }
179           walk_mom += mus->length_mom();
180
181           if (gh_pair_p (gh_cdr (s)))
182             becel.append (new Bar_create_event (walk_mom, ":|"));
183           else
184             becel.append (new Bar_create_event (walk_mom, "stop"));
185         }
186     }
187
188   Cons<Bar_create_event> *&tail = create_barmoments_queue_
189     ? last_cons (create_barmoments_queue_)->next_
190     : create_barmoments_queue_;
191
192   tail = becel.head_ ;
193   becel.head_ = 0;
194 }
195
196 void
197 Repeat_engraver::do_process_music ()
198 {
199   if (repeated_music_l_ && !done_this_one_b_)
200     { 
201       queue_events ();
202       done_this_one_b_ = true;
203     }
204   
205   
206   Cons<Bar_create_event> * head =   create_barmoments_queue_;
207   if (!head)
208     return;
209
210   Bar_engraver* bar_engraver_l = dynamic_cast <Bar_engraver*>
211     (daddy_grav_l ()->get_simple_translator ("Bar_engraver")); // UGH
212
213   /*
214     Do all the events that need to be done now.
215   */
216   while (head && now_mom () == head->car_->when_)
217     {
218       create_barmoments_queue_ = create_barmoments_queue_->next_;
219       head->next_ =0;
220       if (bar_engraver_l)
221         {
222           String t = head->car_->type_;
223           if (head->car_->bar_b_)
224             {
225               if (t == "stop" || t == ":|")
226                 {
227                   end_volta_span_p_ = volta_span_p_;
228                   volta_span_p_ =0;
229                 }
230
231               if (t != "stop")
232                 bar_engraver_l->request_bar (t);
233               else
234                 bar_engraver_l->request_bar (""); 
235             }
236           else
237             {
238               assert (!volta_span_p_);
239               volta_span_p_ = new Spanner (get_property ("basicVoltaSpannerProperties"));
240               Volta_spanner::set_interface (volta_span_p_);
241               announce_element (volta_span_p_,0);
242               volta_span_p_->set_elt_property ("text",
243                                                ly_str02scm (t.ch_C()));
244               volta_span_p_->set_elt_property ("last-volta",
245                                                gh_bool2scm (head->car_->last_b_));
246               // voltaSpannerDuration stuff here.
247               // other property stuff here.
248             }
249           
250         }
251       else
252         {
253           warning (_ ("No bar engraver found.  Ignoring repeats."));
254         }
255
256       delete head->car_;
257       delete head;
258
259       head = create_barmoments_queue_;
260     }
261
262   assert (!head || head->car_->when_ > now_mom ());
263 }  
264
265
266 void
267 Repeat_engraver::acknowledge_element (Score_element_info i)
268 {
269   if (Item* item = dynamic_cast<Item*> (i.elem_l_))
270     {
271       if (Note_column::has_interface (item))
272         {
273           if (volta_span_p_)
274             Volta_spanner::add_column (volta_span_p_,item);
275           if (end_volta_span_p_)
276             Volta_spanner::add_column (end_volta_span_p_,item);      
277         }
278       if (Bar::has_interface (item))
279         {
280           if (volta_span_p_)
281             Volta_spanner::add_bar (volta_span_p_, item);
282           if (end_volta_span_p_)
283             Volta_spanner::add_bar(end_volta_span_p_ , item);
284         }
285     }
286 }
287
288 void
289 Repeat_engraver::do_removal_processing ()
290 {
291   if (volta_span_p_)
292     {
293       typeset_element(volta_span_p_);
294     }
295   if (end_volta_span_p_)
296     {
297       typeset_element (end_volta_span_p_);
298     }
299   // todo: the paranoid may also delete create_barmoments_queue_
300 }
301
302 void
303 Repeat_engraver::do_post_move_processing ()
304 {
305   for (Cons<Bar_create_event> *p = create_barmoments_queue_;
306        p && p->car_->when_ == now_mom (); p = p->next_)
307     if (p->car_->type_ == "stop")
308       {
309         repeated_music_l_ = 0;
310         done_this_one_b_ = false;
311       }
312 }
313
314 void 
315 Repeat_engraver::do_pre_move_processing ()
316 {
317   if (end_volta_span_p_)
318     {
319       Side_position::add_staff_support (end_volta_span_p_);
320       
321       typeset_element (end_volta_span_p_ );
322       end_volta_span_p_ =0;
323     }
324     
325 }
326
327
328 Repeat_engraver::Repeat_engraver()
329 {
330   repeated_music_l_ =0;
331   end_volta_span_p_ =0;
332   volta_span_p_ =0;
333   done_this_one_b_ = false;
334   create_barmoments_queue_ =0;
335 }
336                                  
337 /* ************** */
338 Bar_create_event::Bar_create_event()
339 {
340   last_b_ =false;
341   bar_b_ = true;
342 }
343
344 Bar_create_event::Bar_create_event (Moment w, String s)
345 {
346   last_b_ =false;
347   when_ = w;
348   type_ = s;
349   bar_b_ = true;
350 }
351
352 Bar_create_event::Bar_create_event (Moment w, int i, int j)
353 {
354   last_b_ =false;
355   when_ = w ;
356   bar_b_ = false;
357
358   if (i!=j)
359     type_ = to_str (i) + ".-" ;
360
361   type_ += to_str(j) + ".";
362 }