]> git.donarmstrong.com Git - lilypond.git/blob - lily/repeat-engraver.cc
release: 1.1.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--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   create_barmoments_queue_ = becel.head_ ;
109   becel.head_ = 0;
110 }
111
112 void
113 Repeat_engraver::do_process_requests ()
114 {
115   if (repeated_music_l_ && !done_this_one_b_)
116     { 
117       queue_events ();
118       done_this_one_b_ = true;
119     }
120   
121   
122   Cons<Bar_create_event> * head =   create_barmoments_queue_;
123   if (!head)
124     return;
125
126   Bar_engraver* bar_engraver_l = dynamic_cast <Bar_engraver*>
127     (daddy_grav_l ()->get_simple_translator ("Bar_engraver"));
128
129   /*
130     Do all the events that need to be done now.
131   */
132   bool stop = false;
133   while (head && now_mom () == head->car_->when_)
134     {
135       create_barmoments_queue_ = create_barmoments_queue_->next_;
136       head->next_ =0;
137       if (bar_engraver_l)
138         {
139           String t = head->car_->type_;
140           if (head->car_->bar_b_)
141             {
142               if (t == "stop" || t == ":|")
143                 {
144                   end_volta_span_p_ = volta_span_p_;
145                   volta_span_p_ =0;
146                 }
147
148               if (t != "stop")
149                 bar_engraver_l->request_bar (t);
150               else
151                 bar_engraver_l->request_bar (""); 
152             }
153           else
154             {
155               assert (!volta_span_p_);
156               volta_span_p_ = new Volta_spanner;
157               announce_element (Score_element_info (volta_span_p_,0));
158               volta_span_p_->number_str_ = t;
159               volta_span_p_->last_b_ = head->car_->last_b_;
160               // voltaSpannerDuration stuff here.
161               // other property stuff here.
162             }
163           
164         }
165       else
166         {
167           warning ("No bar engraver found. Ignoring repeats.");
168         }
169
170       delete head->car_;
171       delete head;
172
173       head = create_barmoments_queue_;
174     }
175
176   assert (!head || head->car_->when_ > now_mom ());
177 }  
178
179
180 void
181 Repeat_engraver::acknowledge_element (Score_element_info i)
182 {
183   if (Note_column *c = dynamic_cast<Note_column *> (i.elem_l_))
184     {
185       if (volta_span_p_)
186         volta_span_p_->add_column (c);
187       if (end_volta_span_p_)
188         end_volta_span_p_->add_column (c);      
189     }
190   if (Bar *c = dynamic_cast<Bar*> (i.elem_l_))
191     {
192       if (volta_span_p_)
193         volta_span_p_->add_bar (c);
194       if (end_volta_span_p_)
195         end_volta_span_p_ ->add_bar(c);
196     }
197 }
198
199
200 void
201 Repeat_engraver::do_removal_processing ()
202 {
203   if (volta_span_p_)
204     {
205       typeset_element(volta_span_p_);
206     }
207   if (end_volta_span_p_)
208     {
209       typeset_element (end_volta_span_p_);
210     }
211   // todo: the paranoid may also delete create_barmoments_queue_
212 }
213
214 void
215 Repeat_engraver::do_post_move_processing ()
216 {
217   for (Cons<Bar_create_event> *p = create_barmoments_queue_;
218        p && p->car_->when_ == now_mom (); p = p->next_)
219     if (p->car_->type_ == "stop")
220       {
221         repeated_music_l_ = 0;
222         done_this_one_b_ = false;
223       }
224 }
225
226 void 
227 Repeat_engraver::do_pre_move_processing ()
228 {
229   if (end_volta_span_p_)
230     {
231       typeset_element (end_volta_span_p_ );
232       end_volta_span_p_ =0;
233     }
234     
235 }
236
237
238 Repeat_engraver::Repeat_engraver()
239 {
240   repeated_music_l_ =0;
241   end_volta_span_p_ =0;
242   volta_span_p_ =0;
243   done_this_one_b_ = false;
244   create_barmoments_queue_ =0;
245 }
246                                  
247 /* ************** */
248 Bar_create_event::Bar_create_event()
249 {
250   last_b_ =false;
251   bar_b_ = true;
252 }
253
254 Bar_create_event::Bar_create_event (Moment w, String s)
255 {
256   last_b_ =false;
257   when_ = w;
258   type_ = s;
259   bar_b_ = true;
260 }
261
262 Bar_create_event::Bar_create_event (Moment w, int i, int j)
263 {
264   last_b_ =false;
265   when_ = w ;
266   bar_b_ = false;
267
268   if (i!=j)
269     type_ = to_str (i) + ".-" ;
270
271   type_ += to_str(j) + ".";
272 }