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