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