]> git.donarmstrong.com Git - lilypond.git/blob - lily/repeat-engraver.cc
release: 1.3.69
[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_p_;
115   Moment walk_mom = now_mom () + repeated_music_l_->repeat_body_p_->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       for (Cons<Music> *i = alt->music_p_list_p_->head_; i; i = i->next_)
139         {
140
141           /*
142             some idiot might typeset a repeat not starting on a
143             barline.  Make sure there is one.
144
145             (todo: should try to avoid line breaks?)
146           */
147           if (last_number == 0)
148             {
149               becel.append (new Bar_create_event (walk_mom, ""));
150             }
151
152           
153           if (create_volta)
154             {
155               Bar_create_event * c = new Bar_create_event (walk_mom, last_number+ 1,
156                                                            volta_number);
157               
158               if (!i->next_)
159                 c->last_b_ = true;
160               
161               becel.append (c);
162               last_number = volta_number;
163               volta_number ++;
164               SCM l (get_property ("voltaSpannerDuration"));
165               if (SMOB_IS_TYPE_B (Moment, l))
166                 {
167                   Moment vSD_mom = *SMOB_TO_TYPE (Moment,l);
168                   if ( vSD_mom < i->car_->length_mom() ) // terminate volta early ?
169                     {
170                       vSD_mom += walk_mom;
171                       c->last_b_ = true;
172                       becel.append (new Bar_create_event (vSD_mom, "stop"));
173                     }
174                 }
175             }
176           walk_mom += i->car_->length_mom();
177
178           if (i->next_)
179             becel.append (new Bar_create_event (walk_mom, ":|"));
180           else
181             becel.append (new Bar_create_event (walk_mom, "stop"));
182         }
183     }
184
185   Cons<Bar_create_event> *&tail = create_barmoments_queue_
186     ? last_cons (create_barmoments_queue_)->next_
187     : create_barmoments_queue_;
188
189   tail = becel.head_ ;
190   becel.head_ = 0;
191 }
192
193 void
194 Repeat_engraver::do_process_music ()
195 {
196   if (repeated_music_l_ && !done_this_one_b_)
197     { 
198       queue_events ();
199       done_this_one_b_ = true;
200     }
201   
202   
203   Cons<Bar_create_event> * head =   create_barmoments_queue_;
204   if (!head)
205     return;
206
207   Bar_engraver* bar_engraver_l = dynamic_cast <Bar_engraver*>
208     (daddy_grav_l ()->get_simple_translator ("Bar_engraver"));
209
210   /*
211     Do all the events that need to be done now.
212   */
213   while (head && now_mom () == head->car_->when_)
214     {
215       create_barmoments_queue_ = create_barmoments_queue_->next_;
216       head->next_ =0;
217       if (bar_engraver_l)
218         {
219           String t = head->car_->type_;
220           if (head->car_->bar_b_)
221             {
222               if (t == "stop" || t == ":|")
223                 {
224                   end_volta_span_p_ = volta_span_p_;
225                   volta_span_p_ =0;
226                 }
227
228               if (t != "stop")
229                 bar_engraver_l->request_bar (t);
230               else
231                 bar_engraver_l->request_bar (""); 
232             }
233           else
234             {
235               assert (!volta_span_p_);
236               volta_span_p_ = new Spanner (get_property ("basicVoltaSpannerProperties"));
237               Volta_spanner::set_interface (volta_span_p_);
238               announce_element (Score_element_info (volta_span_p_,0));
239               volta_span_p_->set_elt_property ("text",
240                                                ly_str02scm (t.ch_C()));
241               volta_span_p_->set_elt_property ("last-volta",
242                                                gh_bool2scm (head->car_->last_b_));
243               // voltaSpannerDuration stuff here.
244               // other property stuff here.
245             }
246           
247         }
248       else
249         {
250           warning (_ ("No bar engraver found.  Ignoring repeats."));
251         }
252
253       delete head->car_;
254       delete head;
255
256       head = create_barmoments_queue_;
257     }
258
259   assert (!head || head->car_->when_ > now_mom ());
260 }  
261
262
263 void
264 Repeat_engraver::acknowledge_element (Score_element_info i)
265 {
266   if (Item* item = dynamic_cast<Item*> (i.elem_l_))
267     {
268       if (Note_column::has_interface (item))
269         {
270           if (volta_span_p_)
271             Volta_spanner::add_column (volta_span_p_,item);
272           if (end_volta_span_p_)
273             Volta_spanner::add_column (end_volta_span_p_,item);      
274         }
275       if (Bar::has_interface (item))
276         {
277           if (volta_span_p_)
278             Volta_spanner::add_bar (volta_span_p_, item);
279           if (end_volta_span_p_)
280             Volta_spanner::add_bar(end_volta_span_p_ , item);
281         }
282     }
283 }
284
285 void
286 Repeat_engraver::do_removal_processing ()
287 {
288   if (volta_span_p_)
289     {
290       typeset_element(volta_span_p_);
291     }
292   if (end_volta_span_p_)
293     {
294       typeset_element (end_volta_span_p_);
295     }
296   // todo: the paranoid may also delete create_barmoments_queue_
297 }
298
299 void
300 Repeat_engraver::do_post_move_processing ()
301 {
302   for (Cons<Bar_create_event> *p = create_barmoments_queue_;
303        p && p->car_->when_ == now_mom (); p = p->next_)
304     if (p->car_->type_ == "stop")
305       {
306         repeated_music_l_ = 0;
307         done_this_one_b_ = false;
308       }
309 }
310
311 void 
312 Repeat_engraver::do_pre_move_processing ()
313 {
314   if (end_volta_span_p_)
315     {
316       Side_position::add_staff_support (end_volta_span_p_);
317       
318       typeset_element (end_volta_span_p_ );
319       end_volta_span_p_ =0;
320     }
321     
322 }
323
324
325 Repeat_engraver::Repeat_engraver()
326 {
327   repeated_music_l_ =0;
328   end_volta_span_p_ =0;
329   volta_span_p_ =0;
330   done_this_one_b_ = false;
331   create_barmoments_queue_ =0;
332 }
333                                  
334 /* ************** */
335 Bar_create_event::Bar_create_event()
336 {
337   last_b_ =false;
338   bar_b_ = true;
339 }
340
341 Bar_create_event::Bar_create_event (Moment w, String s)
342 {
343   last_b_ =false;
344   when_ = w;
345   type_ = s;
346   bar_b_ = true;
347 }
348
349 Bar_create_event::Bar_create_event (Moment w, int i, int j)
350 {
351   last_b_ =false;
352   when_ = w ;
353   bar_b_ = false;
354
355   if (i!=j)
356     type_ = to_str (i) + ".-" ;
357
358   type_ += to_str(j) + ".";
359 }