]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
58063603084d279ae2c6630d2381c8d15bc99679
[lilypond.git] / lily / percent-repeat-engraver.cc
1 /*   
2   new-chord-tremolo-engraver.cc --  implement Chord_tremolo_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2000--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "repeated-music.hh"
11 #include "global-context.hh"
12 #include "warn.hh"
13 #include "misc.hh"
14 #include "spanner.hh"
15 #include "item.hh"
16 #include "percent-repeat-iterator.hh"
17 #include "bar-line.hh"
18 #include "score-engraver.hh"
19
20 /**
21   This acknowledges repeated music with "percent" style.  It typesets
22   a % sign.  
23
24   TODO:
25
26   - BEAT case: Create items for single beat repeats, i.e. c4 / / /
27
28   - DOUBLE_MEASURE case: attach a % to an appropriate barline.
29   
30 */
31 class Percent_repeat_engraver : public Engraver
32 {
33   void typeset_perc ();
34 public:
35   TRANSLATOR_DECLARATIONS (Percent_repeat_engraver);
36 protected:
37   Music *repeat_;
38
39   /// moment (global time) where beam started.
40   Moment start_mom_;
41   Moment stop_mom_;
42
43   /// location  within measure where beam started.
44   Moment beam_start_location_;
45   Moment next_moment_;
46   Moment body_length_;
47
48   enum {
49     UNKNOWN,
50     MEASURE,
51     DOUBLE_MEASURE,
52   } repeat_sign_type_ ;
53
54   Item * double_percent_;
55   Spanner * perc_;
56   Spanner * finished_perc_;
57 protected:
58   virtual void finalize ();
59   virtual bool try_music (Music*);
60   virtual void stop_translation_timestep ();
61   virtual void start_translation_timestep ();
62   virtual void process_music ();
63 };
64
65 Percent_repeat_engraver::Percent_repeat_engraver ()
66 {
67   perc_  = 0;
68   finished_perc_ = 0;
69   repeat_ = 0;
70
71   double_percent_ = 0;
72 }
73
74 bool
75 Percent_repeat_engraver::try_music (Music * m)
76 {
77   if (m->is_mus_type ("repeated-music")
78       && m->get_property ("iterator-ctor")
79          == Percent_repeat_iterator::constructor_proc
80       && !repeat_)
81     {
82       body_length_ = Repeated_music::body_get_length (m);
83       int count = Repeated_music::repeat_count (m);
84       
85       Moment now = now_mom ();
86       start_mom_ = now;
87       stop_mom_ = start_mom_ + Moment (count) * body_length_;
88       next_moment_ = start_mom_ + body_length_;
89
90       Moment meas_len (robust_scm2moment (get_property ("measureLength"), Moment (1)));
91       if (meas_len == body_length_)
92         repeat_sign_type_ = MEASURE;
93       else if (Moment (2)* meas_len == body_length_)
94         {
95           repeat_sign_type_ = DOUBLE_MEASURE;
96           next_moment_ += meas_len ;
97         }
98       else
99         {
100           warning (_ ("Don't know how to handle a percent repeat of this length."));
101           return false;
102         }
103
104       repeat_ = m;
105
106       
107       Global_context *global = get_global_context ();
108       for (int i = 0; i < count; i++)  
109         {
110           global->add_moment_to_process (next_moment_ + Moment (i) * body_length_);
111
112           /*
113             bars between % too.
114            */
115           if (repeat_sign_type_ == DOUBLE_MEASURE)
116             global->add_moment_to_process (next_moment_ + meas_len + Moment (i) * body_length_);
117           
118         }
119   
120       return true;
121     }
122
123   return false;
124 }
125
126 void
127 Percent_repeat_engraver::process_music ()
128 {
129   if (repeat_ && now_mom () == next_moment_)
130     {
131       if (repeat_sign_type_ == MEASURE)
132         {
133           finished_perc_ = perc_;
134           typeset_perc ();
135           perc_ = make_spanner ("PercentRepeat", repeat_->self_scm ());
136           SCM col = get_property ("currentCommandColumn");
137           perc_->set_bound (LEFT, unsmob_grob (col));
138         }
139       else if (repeat_sign_type_ == DOUBLE_MEASURE)
140         {
141           double_percent_ = make_item ("DoublePercentRepeat", repeat_->self_scm ());
142       /*
143         forbid breaks on a % line. Should forbid all breaks, really.
144        */
145
146           get_score_engraver ()->forbid_breaks ();      // guh. Use properties!      
147         }
148       next_moment_ = next_moment_ + body_length_;
149
150       get_global_context ()->add_moment_to_process (next_moment_);
151     }
152 }
153
154 void
155 Percent_repeat_engraver::finalize ()
156 {
157   typeset_perc ();
158   if (perc_)
159     {
160       repeat_->origin ()->warning (_ ("unterminated percent repeat"));
161       perc_->suicide ();
162     }
163 }
164
165 void
166 Percent_repeat_engraver::typeset_perc ()
167 {
168   if (finished_perc_)
169     {
170       SCM col = get_property ("currentCommandColumn");
171       finished_perc_->set_bound (RIGHT, unsmob_grob (col));
172       finished_perc_ = 0;
173     }
174
175   double_percent_ = 0;
176 }
177
178
179
180
181 void
182 Percent_repeat_engraver::start_translation_timestep ()
183 {
184   if (stop_mom_ == now_mom ())
185     {
186       if (perc_)
187         {
188           finished_perc_ = perc_;
189           typeset_perc ();
190         }
191       repeat_ = 0;
192       perc_ = 0;
193       repeat_sign_type_ = UNKNOWN;
194     }
195 }
196
197
198 void
199 Percent_repeat_engraver::stop_translation_timestep ()
200 {
201   typeset_perc ();
202 }
203
204
205
206
207 ADD_TRANSLATOR (Percent_repeat_engraver,
208 /* descr */       "Make whole bar and double bar repeats.",
209 /* creats*/       "PercentRepeat DoublePercentRepeat",
210 /* accepts */     "repeated-music",
211 /* acks  */      "",
212 /* reads */       "measureLength currentCommandColumn",
213 /* write */       "");