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