]> git.donarmstrong.com Git - lilypond.git/blob - lily/percent-repeat-engraver.cc
(try_music): add measure before
[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--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "repeated-music.hh"
10 #include "global-context.hh"
11 #include "warn.hh"
12 #include "misc.hh"
13 #include "spanner.hh"
14 #include "item.hh"
15 #include "percent-repeat-iterator.hh"
16 #include "bar-line.hh"
17 #include "score-engraver.hh"
18
19 /**
20    This acknowledges repeated music with "percent" style.  It typesets
21    a % sign.
22
23    TODO:
24
25    - BEAT case: Create items for single beat repeats, i.e. c4 / / /
26
27    - DOUBLE_MEASURE case: attach a % to an appropriate barline.
28 */
29 class Percent_repeat_engraver : public Engraver
30 {
31   void typeset_perc ();
32 public:
33   TRANSLATOR_DECLARATIONS (Percent_repeat_engraver);
34 protected:
35   Music *repeat_;
36
37   /// moment (global time) where beam started.
38   Moment start_mom_;
39   Moment stop_mom_;
40
41   /// location  within measure where beam started.
42   Moment beam_start_location_;
43   Moment next_moment_;
44   Moment body_length_;
45
46   enum
47     {
48       UNKNOWN,
49       MEASURE,
50       DOUBLE_MEASURE,
51     }
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         }
97       else
98         {
99           warning (_f ("can't handle a percent repeat of length: %s",
100                        body_length_.to_string ()));
101           return false;
102         }
103
104       repeat_ = m;
105
106       Global_context *global = get_global_context ();
107       for (int i = 1; i < count; i++)
108         {
109           Moment m = next_moment_ + Moment (i) * body_length_;
110           global->add_moment_to_process (m);
111
112           /* bars between % too.  */
113           if (repeat_sign_type_ == DOUBLE_MEASURE)
114             global->add_moment_to_process (m - meas_len);
115         }
116
117       if (repeat_sign_type_ == DOUBLE_MEASURE)
118         next_moment_ += meas_len;
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           /*
144             forbid breaks on a % line. Should forbid all breaks, really.
145
146             Ugh. Why can't this be regular communication between
147             contexts?
148           */
149           get_score_engraver ()->forbid_breaks ();
150         }
151       next_moment_ = next_moment_ + body_length_;
152     }
153 }
154
155 void
156 Percent_repeat_engraver::finalize ()
157 {
158   typeset_perc ();
159   if (perc_)
160     {
161       repeat_->origin ()->warning (_ ("unterminated percent repeat"));
162       perc_->suicide ();
163     }
164 }
165
166 void
167 Percent_repeat_engraver::typeset_perc ()
168 {
169   if (finished_perc_)
170     {
171       SCM col = get_property ("currentCommandColumn");
172       finished_perc_->set_bound (RIGHT, unsmob_grob (col));
173       finished_perc_ = 0;
174     }
175
176   double_percent_ = 0;
177 }
178
179 void
180 Percent_repeat_engraver::start_translation_timestep ()
181 {
182   if (stop_mom_ == now_mom ())
183     {
184       if (perc_)
185         {
186           finished_perc_ = perc_;
187           typeset_perc ();
188         }
189       repeat_ = 0;
190       perc_ = 0;
191       repeat_sign_type_ = UNKNOWN;
192     }
193 }
194
195 void
196 Percent_repeat_engraver::stop_translation_timestep ()
197 {
198   typeset_perc ();
199 }
200
201 ADD_TRANSLATOR (Percent_repeat_engraver,
202                 /* descr */ "Make whole bar and double bar repeats.",
203                 /* creats*/ "PercentRepeat DoublePercentRepeat",
204                 /* accepts */ "repeated-music",
205                 /* acks  */ "",
206                 /* reads */ "measureLength currentCommandColumn",
207                 /* write */ "");