]> git.donarmstrong.com Git - lilypond.git/blob - lily/stem-engraver.cc
Run `make grand-replace'.
[lilypond.git] / lily / stem-engraver.cc
1 /*
2   stem-engraver.cc -- implement Stem_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "engraver.hh"
10
11 #include "context.hh"
12 #include "directional-element-interface.hh"
13 #include "duration.hh"
14 #include "international.hh"
15 #include "item.hh"
16 #include "misc.hh"
17 #include "rhythmic-head.hh"
18 #include "script-interface.hh"
19 #include "staff-symbol-referencer.hh"
20 #include "stem-tremolo.hh"
21 #include "stem.hh"
22 #include "stream-event.hh"
23
24 #include "translator.icc"
25
26 class Stem_engraver : public Engraver
27 {
28   Grob *stem_;
29   Grob *tremolo_;
30   Stream_event *rhythmic_ev_;
31   Stream_event *tremolo_ev_;
32
33   TRANSLATOR_DECLARATIONS (Stem_engraver);
34
35 protected:
36   void make_stem (Grob_info);
37
38   DECLARE_TRANSLATOR_LISTENER (tremolo);
39   DECLARE_ACKNOWLEDGER (rhythmic_head);
40   void stop_translation_timestep ();
41 };
42
43 Stem_engraver::Stem_engraver ()
44 {
45   tremolo_ev_ = 0;
46   stem_ = 0;
47   tremolo_ = 0;
48   rhythmic_ev_ = 0;
49 }
50
51 void
52 Stem_engraver::make_stem (Grob_info gi)
53 {
54   /* Announce the cause of the head as cause of the stem.  The
55      stem needs a rhythmic structure to fit it into a beam.  */
56   stem_ = make_item ("Stem", gi.grob ()->self_scm ());
57
58   if (tremolo_ev_)
59     {
60       /* Stem tremolo is never applied to a note by default,
61          is must me requested.  But there is a default for the
62          tremolo value:
63
64          c4:8 c c:
65
66          the first and last (quarter) note bothe get one tremolo flag.  */
67       int requested_type
68         = scm_to_int (tremolo_ev_->get_property ("tremolo-type"));
69       SCM f = get_property ("tremoloFlags");
70       if (!requested_type)
71         {
72           if (scm_is_number (f))
73             requested_type = scm_to_int (f);
74           else
75             requested_type = 8;
76         }
77       else
78         context ()->set_property ("tremoloFlags", scm_from_int (requested_type));
79
80
81       /*
82         we take the duration log from the Event, since the duration-log
83         for a note head is always <= 2.
84       */
85       Stream_event *ev = gi.event_cause ();
86       Duration *dur = unsmob_duration (ev->get_property ("duration"));
87       
88       int tremolo_flags = intlog2 (requested_type) - 2
89         - (dur->duration_log () > 2 ? dur->duration_log () - 2 : 0);
90       if (tremolo_flags <= 0)
91         {
92           tremolo_ev_->origin ()->warning (_ ("tremolo duration is too long"));
93           tremolo_flags = 0;
94         }
95
96       if (tremolo_flags)
97         {
98           tremolo_ = make_item ("StemTremolo", tremolo_ev_->self_scm ());
99
100           /* The number of tremolo flags is the number of flags of the
101              tremolo-type minus the number of flags of the note itself.  */
102           tremolo_->set_property ("flag-count", scm_from_int (tremolo_flags));
103           tremolo_->set_parent (stem_, X_AXIS);
104           stem_->set_object ("tremolo-flag", tremolo_->self_scm ());
105           tremolo_->set_object ("stem", stem_->self_scm ());
106         }
107     }
108 }
109
110 void
111 Stem_engraver::acknowledge_rhythmic_head (Grob_info gi)
112 {
113   if (Rhythmic_head::get_stem (gi.grob ()))
114     return;
115
116   Stream_event *cause = gi.event_cause ();
117   if (!cause)
118     return;
119   Duration *d = unsmob_duration (cause->get_property ("duration"));
120   if (!d)
121     return;
122
123   if (!stem_)
124     make_stem (gi);
125
126   if (Stem::duration_log (stem_) != d->duration_log ())
127     {
128       // FIXME: 
129       gi.event_cause ()->origin ()->warning (_f ("adding note head to incompatible stem (type = %d)",
130                                                  1 << Stem::duration_log (stem_)));
131       gi.event_cause ()->origin ()->warning (_ ("maybe input should specify polyphonic voices"));
132     }
133
134   Stem::add_head (stem_, gi.grob ());
135 }
136
137 void
138 Stem_engraver::stop_translation_timestep ()
139 {
140   tremolo_ = 0;
141   if (stem_)
142     {
143       /* FIXME: junk these properties.  */
144       SCM prop = get_property ("stemLeftBeamCount");
145       if (scm_is_number (prop))
146         {
147           Stem::set_beaming (stem_, scm_to_int (prop), LEFT);
148           context ()->unset_property (ly_symbol2scm ("stemLeftBeamCount"));
149         }
150       prop = get_property ("stemRightBeamCount");
151       if (scm_is_number (prop))
152         {
153           Stem::set_beaming (stem_, scm_to_int (prop), RIGHT);
154           context ()->unset_property (ly_symbol2scm ("stemRightBeamCount"));
155         }
156       stem_ = 0;
157     }
158   tremolo_ev_ = 0;
159 }
160
161 IMPLEMENT_TRANSLATOR_LISTENER (Stem_engraver, tremolo);
162 void
163 Stem_engraver::listen_tremolo (Stream_event *ev)
164 {
165   ASSIGN_EVENT_ONCE (tremolo_ev_, ev);
166 }
167
168 ADD_ACKNOWLEDGER (Stem_engraver, rhythmic_head);
169
170 ADD_TRANSLATOR (Stem_engraver,
171                 /* doc */
172                 "Create stems and single-stem tremolos.  It also works"
173                 " together with the beam engraver for overriding beaming.",
174
175                 /* create */
176                 "Stem "
177                 "StemTremolo ",
178
179                 /* read */
180                 "tremoloFlags "
181                 "stemLeftBeamCount "
182                 "stemRightBeamCount ",
183
184                 /* write */
185                 ""
186                 );