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