]> git.donarmstrong.com Git - lilypond.git/blob - lily/repeat-engraver.cc
c716bb1243136106ff84e3cb6fa652a7374899d6
[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--1999 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 "time-description.hh"
16 #include "engraver-group-engraver.hh"
17 #include "repeated-music.hh"
18 #include "time-description.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 void
53 Repeat_engraver::queue_events ()
54 {
55   Music_sequence* alt = repeated_music_l_->alternatives_p_;
56   Moment walk_mom = now_mom () + repeated_music_l_->repeat_body_p_->length_mom ();
57
58   bool create_volta = ! get_property ("noVoltaBraces",0).to_bool ();
59
60   Cons_list<Bar_create_event> becel;
61   becel.append (new Bar_create_event (now_mom (), "|:"));
62
63   if (!alt)
64     {
65       becel.append  (new Bar_create_event (walk_mom, ":|"));
66       becel.append  (new Bar_create_event (walk_mom, "stop"));
67    }
68   else
69     {
70       int last_number = 0;
71       int volta_number = repeated_music_l_->repeats_i_ - alt->length_i () + 1;
72
73       /*
74         all repeat alternatives, and generate events with
75         appropriate timestamps. The volta spanner event (a number string)
76         happens at the begin of the alt. The :| bar event at the ending.
77       */
78       for (Cons<Music> *i = alt->music_p_list_p_->head_; i; i = i->next_)
79         {
80
81           /*
82             some idiot might typeset a repeat not starting on a
83             barline.  Make sure there is one.
84
85             (todo: should try to avoid line breaks?)
86           */
87           if (last_number == 0)
88             {
89               becel.append (new Bar_create_event (walk_mom, ""));
90             }
91
92           
93           if (create_volta)
94             {
95               Bar_create_event * c = new Bar_create_event (walk_mom, last_number+ 1,
96                                                            volta_number);
97               
98               if (!i->next_)
99                 c->last_b_ = true;
100               
101               becel.append (c);
102               last_number = volta_number;
103               volta_number ++;
104               Scalar l (get_property ("voltaSpannerDuration", 0));
105               if (l.length_i ()) // voltaSpannerDuration OK?
106               {
107  
108                 Moment vSD_mom = l.to_rat();
109                 if ( vSD_mom < i->car_->length_mom() ) // terminate volta early ?
110                 {
111                         vSD_mom += walk_mom;
112                    c->last_b_ = true;
113                    becel.append (new Bar_create_event (vSD_mom, "stop"));
114                 }
115               }
116             }
117           walk_mom += i->car_->length_mom();
118
119           if (i->next_)
120             becel.append (new Bar_create_event (walk_mom, ":|"));
121           else
122             becel.append (new Bar_create_event (walk_mom, "stop"));
123         }
124     }
125
126   Cons<Bar_create_event> *&tail = create_barmoments_queue_
127     ? last_cons (create_barmoments_queue_)->next_
128     : create_barmoments_queue_;
129
130   tail = becel.head_ ;
131   becel.head_ = 0;
132 }
133
134 void
135 Repeat_engraver::do_process_requests ()
136 {
137   if (repeated_music_l_ && !done_this_one_b_)
138     { 
139       queue_events ();
140       done_this_one_b_ = true;
141     }
142   
143   
144   Cons<Bar_create_event> * head =   create_barmoments_queue_;
145   if (!head)
146     return;
147
148   Bar_engraver* bar_engraver_l = dynamic_cast <Bar_engraver*>
149     (daddy_grav_l ()->get_simple_translator ("Bar_engraver"));
150
151   /*
152     Do all the events that need to be done now.
153   */
154   while (head && now_mom () == head->car_->when_)
155     {
156       create_barmoments_queue_ = create_barmoments_queue_->next_;
157       head->next_ =0;
158       if (bar_engraver_l)
159         {
160           String t = head->car_->type_;
161           if (head->car_->bar_b_)
162             {
163               if (t == "stop" || t == ":|")
164                 {
165                   end_volta_span_p_ = volta_span_p_;
166                   volta_span_p_ =0;
167                 }
168
169               if (t != "stop")
170                 bar_engraver_l->request_bar (t);
171               else
172                 bar_engraver_l->request_bar (""); 
173             }
174           else
175             {
176               assert (!volta_span_p_);
177               volta_span_p_ = new Volta_spanner;
178               announce_element (Score_element_info (volta_span_p_,0));
179               volta_span_p_->number_str_ = t;
180               volta_span_p_->last_b_ = head->car_->last_b_;
181               // voltaSpannerDuration stuff here.
182               // other property stuff here.
183             }
184           
185         }
186       else
187         {
188           warning (_ ("No bar engraver found.  Ignoring repeats."));
189         }
190
191       delete head->car_;
192       delete head;
193
194       head = create_barmoments_queue_;
195     }
196
197   assert (!head || head->car_->when_ > now_mom ());
198 }  
199
200
201 void
202 Repeat_engraver::acknowledge_element (Score_element_info i)
203 {
204   if (Note_column *c = dynamic_cast<Note_column *> (i.elem_l_))
205     {
206       if (volta_span_p_)
207         volta_span_p_->add_column (c);
208       if (end_volta_span_p_)
209         end_volta_span_p_->add_column (c);      
210     }
211   if (Bar *c = dynamic_cast<Bar*> (i.elem_l_))
212     {
213       if (volta_span_p_)
214         volta_span_p_->add_bar (c);
215       if (end_volta_span_p_)
216         end_volta_span_p_ ->add_bar(c);
217     }
218 }
219
220
221 void
222 Repeat_engraver::do_removal_processing ()
223 {
224   if (volta_span_p_)
225     {
226       typeset_element(volta_span_p_);
227     }
228   if (end_volta_span_p_)
229     {
230       typeset_element (end_volta_span_p_);
231     }
232   // todo: the paranoid may also delete create_barmoments_queue_
233 }
234
235 void
236 Repeat_engraver::do_post_move_processing ()
237 {
238   for (Cons<Bar_create_event> *p = create_barmoments_queue_;
239        p && p->car_->when_ == now_mom (); p = p->next_)
240     if (p->car_->type_ == "stop")
241       {
242         repeated_music_l_ = 0;
243         done_this_one_b_ = false;
244       }
245 }
246
247 void 
248 Repeat_engraver::do_pre_move_processing ()
249 {
250   if (end_volta_span_p_)
251     {
252       typeset_element (end_volta_span_p_ );
253       end_volta_span_p_ =0;
254     }
255     
256 }
257
258
259 Repeat_engraver::Repeat_engraver()
260 {
261   repeated_music_l_ =0;
262   end_volta_span_p_ =0;
263   volta_span_p_ =0;
264   done_this_one_b_ = false;
265   create_barmoments_queue_ =0;
266 }
267                                  
268 /* ************** */
269 Bar_create_event::Bar_create_event()
270 {
271   last_b_ =false;
272   bar_b_ = true;
273 }
274
275 Bar_create_event::Bar_create_event (Moment w, String s)
276 {
277   last_b_ =false;
278   when_ = w;
279   type_ = s;
280   bar_b_ = true;
281 }
282
283 Bar_create_event::Bar_create_event (Moment w, int i, int j)
284 {
285   last_b_ =false;
286   when_ = w ;
287   bar_b_ = false;
288
289   if (i!=j)
290     type_ = to_str (i) + ".-" ;
291
292   type_ += to_str(j) + ".";
293 }