]> git.donarmstrong.com Git - lilypond.git/blob - lily/chord-tremolo-engraver.cc
d3ff4fa6929b0b546b5054d586048a57b1dddc04
[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--2001 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_);
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               Stem_tremolo::set_interface (stem_tremolo_);
124
125               announce_grob (stem_tremolo_, repeat_);
126               stem_tremolo_->set_grob_property ("tremolo-flags",
127                                                 gh_int2scm (flags));
128
129             }
130         }
131     }
132 }
133 void
134 Chord_tremolo_engraver::finalize ()
135 {
136   typeset_beam ();
137   if (beam_p_)
138     {
139       repeat_->origin ()->warning (_ ("unterminated chord tremolo"));
140       beam_p_->suicide ();
141     }
142 }
143
144 void
145 Chord_tremolo_engraver::typeset_beam ()
146 {
147   if (finished_beam_p_)
148     {
149       typeset_grob (finished_beam_p_);
150       finished_beam_p_ = 0;
151     }
152 }
153
154
155 void
156 Chord_tremolo_engraver::acknowledge_grob (Grob_info info)
157 {
158   if (beam_p_)
159     {
160       if (Stem::has_interface (info.grob_l_))
161         {
162           Grob * s = info.grob_l_;
163           int f = Stem::flag_i (s);
164           f = (f > 2) ? f - 2 : 1;
165           Stem::set_beaming (s, f, LEFT);
166           Stem::set_beaming (s, f, RIGHT);
167           
168           /*
169             URG: this sets the direction of the Stem s.
170             It's amazing Mike:
171             
172               Stem:: type_i () ->first_head ()->get_direction () ->
173                       Directional_element_interface::set (me, d);
174
175
176               don't understand this comment.
177                       --hwn.
178            */
179           SCM d = s->get_grob_property ("direction");
180           if (Stem::type_i (s) != 1)
181             {
182               int gap_i =Stem::flag_i (s) - ((Stem::type_i (s) >? 2) - 2);
183               beam_p_->set_grob_property ("gap", gh_int2scm (gap_i));
184             }
185           s->set_grob_property ("direction", d);
186
187           if (dynamic_cast <Rhythmic_req *> (info.music_cause ()))
188             {
189               Beam::add_stem (beam_p_, s);
190             }
191           else
192             {
193               String s = _ ("stem must have Rhythmic structure");
194               if (info.music_cause ())
195                 info.music_cause ()->origin ()->warning (s);
196               else
197                 ::warning (s);
198             }
199         }
200     }
201   else if (stem_tremolo_ && Stem::has_interface (info.grob_l_))
202     {
203        Stem_tremolo::set_stem (stem_tremolo_, info.grob_l_);
204
205        info.grob_l_->set_grob_property ("duration-log", gh_int2scm (intlog2 (note_head_i_)));
206     }
207
208   
209   if (repeat_ && Note_head::has_interface (info.grob_l_))
210     {
211       info.grob_l_->set_grob_property ("duration-log", gh_int2scm (intlog2 (note_head_i_)));
212     }
213 }
214
215
216 void
217 Chord_tremolo_engraver::start_translation_timestep ()
218 {
219   if (beam_p_ && stop_mom_ == now_mom ())
220     {
221       finished_beam_p_ = beam_p_;
222
223       repeat_ = 0;
224       beam_p_ = 0;
225     }
226 }
227
228
229 void
230 Chord_tremolo_engraver::stop_translation_timestep ()
231 {
232   typeset_beam ();
233
234   if (stem_tremolo_)
235     {
236       typeset_grob (stem_tremolo_);
237       stem_tremolo_ = 0;
238     }
239   
240 }
241
242
243
244 ENTER_DESCRIPTION(Chord_tremolo_engraver,
245 /* descr */       "Generates beams for  tremolo repeats.",
246 /* creats*/       "Beam",
247 /* acks  */       "stem-interface note-head-interface",
248 /* reads */       "",
249 /* write */       "");