]> git.donarmstrong.com Git - lilypond.git/blob - lily/repeat-engraver.cc
patch::: 1.3.91.jcn1
[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   /*
189     ugh, should merge :| and |: here.
190    */
191   Cons<Bar_create_event> * last = last_cons (create_barmoments_queue_);
192   Cons<Bar_create_event> **tail = last?  & last->next_
193     : & create_barmoments_queue_;
194
195   *tail = becel.head_ ;
196   
197   becel.head_ = 0;
198 }
199
200 void
201 Repeat_engraver::do_process_music ()
202 {
203   if (repeated_music_l_ && !done_this_one_b_)
204     { 
205       queue_events ();
206       done_this_one_b_ = true;
207     }
208   
209   
210   Cons<Bar_create_event> * head = create_barmoments_queue_;
211   if (!head)
212     return;
213
214   /*
215     Do all the events that need to be done now.
216   */
217   while (head && now_mom () == head->car_->when_)
218     {
219       create_barmoments_queue_ = create_barmoments_queue_->next_;
220       head->next_ =0;
221       String t = head->car_->type_;
222       if (head->car_->bar_b_)
223         {
224           if (t == "stop" || t == ":|")
225             {
226               end_volta_span_p_ = volta_span_p_;
227               volta_span_p_ =0;
228             }
229
230           SCM whsym = ly_symbol2scm ("whichBar");
231           Translator_group* where = daddy_trans_l_->where_defined (whsym);
232           SCM which = where->get_property (whsym);
233
234           /*
235             Should use symbols for bar glyphs.
236           */
237           if (t == "stop" && which == SCM_UNDEFINED)
238             which = ly_str02scm ("");
239           else if (t != "stop")
240             {
241               SCM l = ly_str02scm (":|");
242               SCM r = ly_str02scm ("|:");                 
243                   
244               if ( (t == "|:" && scm_equal_p (which, l) == SCM_BOOL_T)
245                    || (t == ":|" && scm_equal_p (which, r)== SCM_BOOL_T))
246                 t = ":|:";
247
248               if (t != "" || !gh_string_p (which))
249                 which = ly_str02scm (t.ch_C());
250             }
251           where->set_property (whsym, which);
252         }
253       else
254         {
255           assert (!volta_span_p_);
256           volta_span_p_ = new Spanner (get_property ("basicVoltaSpannerProperties"));
257           Volta_spanner::set_interface (volta_span_p_);
258           announce_element (volta_span_p_,0);
259           volta_span_p_->set_elt_property ("text",
260                                            ly_str02scm (t.ch_C()));
261           volta_span_p_->set_elt_property ("last-volta",
262                                            gh_bool2scm (head->car_->last_b_));
263           // voltaSpannerDuration stuff here.
264           // other property stuff here.
265         }
266           
267
268       delete head->car_;
269       delete head;
270
271       head = create_barmoments_queue_;
272     }
273
274   assert (!head || head->car_->when_ > now_mom ());
275 }  
276
277
278 void
279 Repeat_engraver::acknowledge_element (Score_element_info i)
280 {
281   if (Item* item = dynamic_cast<Item*> (i.elem_l_))
282     {
283       if (Note_column::has_interface (item))
284         {
285           if (volta_span_p_)
286             Volta_spanner::add_column (volta_span_p_,item);
287           if (end_volta_span_p_)
288             Volta_spanner::add_column (end_volta_span_p_,item);      
289         }
290       if (Bar::has_interface (item))
291         {
292           if (volta_span_p_)
293             Volta_spanner::add_bar (volta_span_p_, item);
294           if (end_volta_span_p_)
295             Volta_spanner::add_bar(end_volta_span_p_ , item);
296         }
297     }
298 }
299
300 void
301 Repeat_engraver::do_removal_processing ()
302 {
303   if (volta_span_p_)
304     {
305       typeset_element(volta_span_p_);
306     }
307   if (end_volta_span_p_)
308     {
309       typeset_element (end_volta_span_p_);
310     }
311   // todo: the paranoid may also delete create_barmoments_queue_
312 }
313
314 void
315 Repeat_engraver::do_post_move_processing ()
316 {
317   for (Cons<Bar_create_event> *p = create_barmoments_queue_;
318        p && p->car_->when_ == now_mom (); p = p->next_)
319     if (p->car_->type_ == "stop")
320       {
321         repeated_music_l_ = 0;
322         done_this_one_b_ = false;
323       }
324 }
325
326 void 
327 Repeat_engraver::do_pre_move_processing ()
328 {
329   if (end_volta_span_p_)
330     {
331       Side_position::add_staff_support (end_volta_span_p_);
332       
333       typeset_element (end_volta_span_p_ );
334       end_volta_span_p_ =0;
335     }
336     
337 }
338
339
340 Repeat_engraver::Repeat_engraver()
341 {
342   repeated_music_l_ =0;
343   end_volta_span_p_ =0;
344   volta_span_p_ =0;
345   done_this_one_b_ = false;
346   create_barmoments_queue_ =0;
347 }
348                                  
349 /* ************** */
350 Bar_create_event::Bar_create_event()
351 {
352   last_b_ =false;
353   bar_b_ = true;
354 }
355
356 Bar_create_event::Bar_create_event (Moment w, String s)
357 {
358   last_b_ =false;
359   when_ = w;
360   type_ = s;
361   bar_b_ = true;
362 }
363
364 Bar_create_event::Bar_create_event (Moment w, int i, int j)
365 {
366   last_b_ =false;
367   when_ = w ;
368   bar_b_ = false;
369
370   if (i!=j)
371     type_ = to_str (i) + ".-" ;
372
373   type_ += to_str(j) + ".";
374 }