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