]> git.donarmstrong.com Git - lilypond.git/blob - lily/stem-engraver.cc
* lily/new-slur.cc: Resolve conflicts.
[lilypond.git] / lily / stem-engraver.cc
1 /*
2   stem-grav.cc -- implement Stem_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "context.hh"
10 #include "directional-element-interface.hh"
11 #include "engraver.hh"
12 #include "event.hh"
13 #include "item.hh"
14 #include "misc.hh"
15 #include "rhythmic-head.hh"
16 #include "script-interface.hh"
17 #include "staff-symbol-referencer.hh"
18 #include "stem-tremolo.hh"
19 #include "stem.hh"
20
21
22 /**
23   Make stems upon receiving noteheads.
24  */
25 class Stem_engraver : public Engraver
26 {
27   Grob  *stem_;
28   Grob *tremolo_;
29   Music *rhythmic_ev_;
30   Music* tremolo_ev_;
31   TRANSLATOR_DECLARATIONS (Stem_engraver);
32
33 protected:
34   void add_script (Grob *);
35   void make_stem (Grob_info);
36   virtual void acknowledge_grob (Grob_info);
37   virtual void stop_translation_timestep ();
38   virtual bool try_music (Music *);
39 };
40
41 Stem_engraver::Stem_engraver ()
42 {
43   tremolo_ev_ = 0;
44   stem_ = 0;
45   tremolo_ = 0;
46   rhythmic_ev_ =0;
47 }
48
49 void
50 Stem_engraver::make_stem (Grob_info gi)
51 {
52   /* Announce the cause of the head as cause of the stem.  The
53      stem needs a rhythmic structure to fit it into a beam.  */
54   stem_ = make_item ("Stem", gi.music_cause ()->self_scm ());
55
56   int duration_log = gi.music_cause ()->duration_log ();
57   stem_->set_property ("duration-log", scm_int2num (duration_log));
58
59   if (tremolo_ev_)
60     {
61       /* Stem tremolo is never applied to a note by default,
62          is must me requested.  But there is a default for the
63          tremolo value:
64
65          c4:8 c c:
66
67          the first and last (quarter) note bothe get one tremolo flag.  */
68       int requested_type
69         = ly_scm2int (tremolo_ev_->get_property ("tremolo-type"));
70       SCM f = get_property ("tremoloFlags");
71       if (!requested_type)
72         {
73           if (ly_c_number_p (f))
74             requested_type = ly_scm2int (f);
75           else
76             requested_type = 8;
77         }
78       else
79         context ()->set_property ("tremoloFlags", scm_int2num (requested_type));
80
81       int tremolo_flags = intlog2 (requested_type) - 2
82         - (duration_log > 2 ? duration_log - 2 : 0);
83       if (tremolo_flags <= 0)
84         {
85           tremolo_ev_->origin ()->warning (_("tremolo duration is too long"));
86           tremolo_flags = 0;
87         }
88
89       if (tremolo_flags)
90         {
91           tremolo_ = make_item ("StemTremolo", tremolo_ev_->self_scm ());
92
93           /* The number of tremolo flags is the number of flags of the
94             tremolo-type minus the number of flags of the note itself.  */
95           tremolo_->set_property ("flag-count", scm_int2num (tremolo_flags));
96           tremolo_->set_parent (stem_, X_AXIS);
97           stem_->set_property ("tremolo-flag", tremolo_->self_scm ());
98           tremolo_->set_property ("stem", stem_->self_scm ());
99         }
100     }
101 }
102
103 void
104 Stem_engraver::add_script (Grob *script)
105 {
106   Direction d = get_grob_direction (script);
107   if (d == UP || d == DOWN)
108     {
109       char const *property = d == UP ? "script-up" : "script-down";
110       stem_->set_property (property,
111                            scm_cons (script->self_scm (),
112                                      stem_->get_property (property)));
113     }
114 }
115
116 void
117 Stem_engraver::acknowledge_grob (Grob_info gi)
118 {
119   if (Rhythmic_head::has_interface (gi.grob_))
120     {
121       if (Rhythmic_head::get_stem (gi.grob_))
122         return;
123       
124       if (!stem_)
125         make_stem (gi);
126       
127       int duration_log = gi.music_cause ()->duration_log ();
128       if (Stem::duration_log (stem_) != duration_log)
129         {
130           // FIXME: 
131           gi.music_cause ()->origin ()->warning (_f ("Adding note head to incompatible stem (type = %d)", 1 << Stem::duration_log (stem_)));
132           
133           gi.music_cause ()->origin ()->warning (_f ("Don't you want polyphonic voices instead?"));
134         }
135
136       Stem::add_head (stem_, gi.grob_);
137     }
138   else if (Script_interface::has_interface (gi.grob_))
139     add_script (gi.grob_);
140 }
141
142 void
143 Stem_engraver::stop_translation_timestep ()
144 {
145   tremolo_ = 0;
146   if (stem_)
147     {
148       /* FIXME: junk these properties.  */
149       SCM prop = get_property ("stemLeftBeamCount");
150       if (ly_c_number_p (prop))
151         {
152           Stem::set_beaming (stem_,ly_scm2int (prop),LEFT);
153           context ()->unset_property (ly_symbol2scm ("stemLeftBeamCount"));
154         }
155       prop = get_property ("stemRightBeamCount");
156       if (ly_c_number_p (prop))
157         {
158           Stem::set_beaming (stem_,ly_scm2int (prop), RIGHT);
159           context ()->unset_property (ly_symbol2scm ("stemRightBeamCount"));
160         }
161       stem_ = 0;
162     }
163   tremolo_ev_ = 0;
164 }
165
166 bool
167 Stem_engraver::try_music (Music *m)
168 {
169   if (m->is_mus_type ("tremolo-event"))
170     {
171       tremolo_ev_ = m;
172       return true;
173     }
174   return false;
175 }
176
177 ENTER_DESCRIPTION (Stem_engraver,
178 /* descr */       "Create stems and single-stem tremolos.  It also works together with "
179 "the beam engraver for overriding beaming.",
180 /* creats*/       "Stem StemTremolo",
181 /* accepts */     "tremolo-event",
182 /* acks  */      "rhythmic-head-interface",
183 /* reads */       "tremoloFlags stemLeftBeamCount stemRightBeamCount",
184 /* write */       "");