]> git.donarmstrong.com Git - lilypond.git/blob - lily/chord-tremolo-engraver.cc
stem tremolo fix
[lilypond.git] / lily / chord-tremolo-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--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 #include "engraver.hh"
11 #include "beam.hh"
12 #include "repeated-music.hh"
13 #include "stem.hh"
14 #include "rhythmic-head.hh"
15 #include "engraver-group-engraver.hh"
16 #include "musical-request.hh"
17 #include "warn.hh"
18 #include "misc.hh"
19 #include "note-head.hh"
20 #include "spanner.hh"
21 #include "item.hh"
22 #include "chord-tremolo-iterator.hh"
23 #include "stem-tremolo.hh"
24 #include "music-list.hh"
25 #include "math.h"           // ceil
26
27 /**
28   This acknowledges repeated music with "tremolo" style.  It typesets
29   a beam.
30
31   TODO:
32
33   - perhaps use engraver this to steer other engravers? That would
34   create dependencies between engravers, which is bad.
35
36   - create dots if appropriate.
37
38   - create  TremoloBeam iso Beam?
39  */
40
41 class Chord_tremolo_engraver : public Engraver
42 {
43   void typeset_beam ();
44 TRANSLATOR_DECLARATIONS(Chord_tremolo_engraver);
45 protected:
46   Repeated_music * repeat_;
47
48   /// moment (global time) where beam started.
49   Moment start_mom_;
50   Moment stop_mom_;
51
52   /// location  within measure where beam started.
53   Moment beam_start_location_;
54
55   int note_head_i_;
56   int dots_i_;
57
58   bool sequential_body_b_;
59   Spanner * beam_p_;
60   Spanner * finished_beam_p_;
61   Item * stem_tremolo_;
62 protected:
63   virtual void finalize ();
64   virtual bool try_music (Music*);
65   virtual void acknowledge_grob (Grob_info);
66   virtual void stop_translation_timestep ();
67   virtual void start_translation_timestep ();
68   virtual void process_music ();
69 };
70
71 Chord_tremolo_engraver::Chord_tremolo_engraver ()
72 {
73   beam_p_  = finished_beam_p_ = 0;
74   repeat_ =0;
75   note_head_i_ = 0;
76   dots_i_ = 0;
77   stem_tremolo_ = 0;
78   sequential_body_b_ = false;
79 }
80
81 bool
82 Chord_tremolo_engraver::try_music (Music * m)
83 {
84   Repeated_music * rp = dynamic_cast<Repeated_music*> (m);
85   if (rp
86       && rp->get_mus_property ("iterator-ctor") == Chord_tremolo_iterator::constructor_cxx_function
87       && !repeat_) 
88     {
89       Moment l = rp->length_mom ();
90       repeat_ = rp;
91       start_mom_ = now_mom ();
92       stop_mom_ = start_mom_ + l;
93       sequential_body_b_ = dynamic_cast<Sequential_music*> (rp->body ());
94
95       // ugh. should generate triplet beams.
96       note_head_i_ = int (ceil (double(l.den ()) / l.num ()));
97       dots_i_ = intlog2 (1+l.num ()) -1 ; // 1->0, 3->1, 7->2
98       note_head_i_ = note_head_i_ <? 4; 
99       return true;
100     }
101
102   return false;
103 }
104
105 void
106 Chord_tremolo_engraver::process_music ()
107 {
108   if (repeat_)
109     {
110       if (sequential_body_b_ && !beam_p_)
111         {
112           beam_p_ = new Spanner (get_property ("Beam"));
113           beam_p_->set_grob_property ("chord-tremolo", SCM_BOOL_T);
114
115
116           SCM smp = get_property ("measurePosition");
117           Moment mp
118             = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
119           beam_start_location_ = mp;
120           announce_grob(beam_p_, repeat_->self_scm());
121         }
122       else if (!sequential_body_b_ && !stem_tremolo_)
123         {
124           int flags = intlog2 (note_head_i_ * repeat_->repeat_count ()) -2;
125           if (flags)
126             {
127               stem_tremolo_ = new Item (get_property ("StemTremolo"));
128               announce_grob(stem_tremolo_, repeat_->self_scm());
129               stem_tremolo_->set_grob_property ("flag-count",
130                                                 gh_int2scm (flags));
131
132             }
133         }
134     }
135 }
136 void
137 Chord_tremolo_engraver::finalize ()
138 {
139   typeset_beam ();
140   if (beam_p_)
141     {
142       repeat_->origin ()->warning (_ ("unterminated chord tremolo"));
143       beam_p_->suicide ();
144     }
145 }
146
147 void
148 Chord_tremolo_engraver::typeset_beam ()
149 {
150   if (finished_beam_p_)
151     {
152       typeset_grob (finished_beam_p_);
153       finished_beam_p_ = 0;
154     }
155 }
156
157
158 void
159 Chord_tremolo_engraver::acknowledge_grob (Grob_info info)
160 {
161   if (beam_p_)
162     {
163       if (Stem::has_interface (info.grob_l_))
164         {
165           Grob * s = info.grob_l_;
166           int f = Stem::duration_log (s);
167           f = (f > 2) ? f - 2 : 1;
168           Stem::set_beaming (s, f, LEFT);
169           Stem::set_beaming (s, f, RIGHT);
170           
171           SCM d = s->get_grob_property ("direction");
172           if (Stem::duration_log (s) != 1)
173             {
174               int gap_i =Stem::duration_log (s) - ((Stem::duration_log (s) >? 2) - 2);
175               beam_p_->set_grob_property ("gap", gh_int2scm (gap_i));
176             }
177           s->set_grob_property ("direction", d);
178
179           if (dynamic_cast <Rhythmic_req *> (info.music_cause ()))
180             {
181               Beam::add_stem (beam_p_, s);
182             }
183           else
184             {
185               String s = _ ("stem must have Rhythmic structure");
186               if (info.music_cause ())
187                 info.music_cause ()->origin ()->warning (s);
188               else
189                 ::warning (s);
190             }
191         }
192     }
193   else if (stem_tremolo_ && Stem::has_interface (info.grob_l_))
194     {
195        Stem_tremolo::set_stem (stem_tremolo_, info.grob_l_);
196
197        info.grob_l_->set_grob_property ("duration-log", gh_int2scm (intlog2 (note_head_i_)));
198     }
199
200   
201   if (repeat_ && Note_head::has_interface (info.grob_l_))
202     {
203       info.grob_l_->set_grob_property ("duration-log", gh_int2scm (intlog2 (note_head_i_)));
204       if (dots_i_ > 0) 
205         {
206           Item * d = new Item (get_property ("Dots"));
207           Rhythmic_head::set_dots (info.grob_l_, d);
208           
209           d->set_grob_property ("dot-count", gh_int2scm (dots_i_));
210
211           d->set_parent (info.grob_l_, Y_AXIS);
212           announce_grob (d, SCM_EOL);
213         }
214     }
215 }
216
217
218 void
219 Chord_tremolo_engraver::start_translation_timestep ()
220 {
221   if (beam_p_ && stop_mom_ == now_mom ())
222     {
223       finished_beam_p_ = beam_p_;
224
225       repeat_ = 0;
226       beam_p_ = 0;
227     }
228 }
229
230
231 void
232 Chord_tremolo_engraver::stop_translation_timestep ()
233 {
234   typeset_beam ();
235
236   if (stem_tremolo_)
237     {
238       typeset_grob (stem_tremolo_);
239       stem_tremolo_ = 0;
240     }
241   
242 }
243
244
245
246 ENTER_DESCRIPTION(Chord_tremolo_engraver,
247 /* descr */       "Generates beams for  tremolo repeats.",
248 /* creats*/       "Beam",
249 /* acks  */       "stem-interface note-head-interface",
250 /* reads */       "",
251 /* write */       "");