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