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