]> git.donarmstrong.com Git - lilypond.git/blob - lily/pitched-trill-engraver.cc
Issue 4997/3: Use Preinit in Music
[lilypond.git] / lily / pitched-trill-engraver.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 2005--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "engraver.hh"
21
22 #include "axis-group-interface.hh"
23 #include "context.hh"
24 #include "dots.hh"
25 #include "item.hh"
26 #include "note-head.hh"
27 #include "pitch.hh"
28 #include "pointer-group-interface.hh"
29 #include "side-position-interface.hh"
30 #include "stream-event.hh"
31 #include "warn.hh"
32
33 #include "translator.icc"
34
35 class Pitched_trill_engraver : public Engraver
36 {
37 public:
38   TRANSLATOR_DECLARATIONS (Pitched_trill_engraver);
39
40 protected:
41   void acknowledge_note_head (Grob_info);
42   void acknowledge_dots (Grob_info);
43   void acknowledge_stem (Grob_info);
44   void acknowledge_flag (Grob_info);
45   void acknowledge_trill_spanner (Grob_info);
46   void stop_translation_timestep ();
47
48 private:
49   Item *trill_head_;
50   Item *trill_group_;
51   Item *trill_accidental_;
52
53   vector<Grob *> heads_;
54
55   void make_trill (Stream_event *);
56 };
57
58 Pitched_trill_engraver::Pitched_trill_engraver ()
59 {
60   trill_head_ = 0;
61   trill_group_ = 0;
62   trill_accidental_ = 0;
63 }
64
65 void
66 Pitched_trill_engraver::acknowledge_dots (Grob_info info)
67 {
68   heads_.push_back (info.grob ());
69 }
70 void
71 Pitched_trill_engraver::acknowledge_stem (Grob_info info)
72 {
73   heads_.push_back (info.grob ());
74 }
75 void
76 Pitched_trill_engraver::acknowledge_flag (Grob_info info)
77 {
78   heads_.push_back (info.grob ());
79 }
80 void
81 Pitched_trill_engraver::acknowledge_note_head (Grob_info info)
82 {
83   heads_.push_back (info.grob ());
84 }
85
86 void
87 Pitched_trill_engraver::acknowledge_trill_spanner (Grob_info info)
88 {
89   Stream_event *ev = info.event_cause ();
90   if (ev
91       && ev->in_event_class ("trill-span-event")
92       && to_dir (ev->get_property ("span-direction")) == START
93       && unsmob<Pitch> (ev->get_property ("pitch")))
94     make_trill (ev);
95 }
96
97 void
98 Pitched_trill_engraver::make_trill (Stream_event *ev)
99 {
100   SCM scm_pitch = ev->get_property ("pitch");
101   Pitch *p = unsmob<Pitch> (scm_pitch);
102
103   SCM keysig = get_property ("localAlterations");
104
105   SCM key = scm_cons (scm_from_int (p->get_octave ()),
106                       scm_from_int (p->get_notename ()));
107
108   int bn = measure_number (context ());
109
110   SCM handle = scm_assoc (key, keysig);
111   if (scm_is_true (handle))
112     {
113       bool same_bar = (bn == robust_scm2int (scm_caddr (handle), 0));
114       bool same_alt
115         = (p->get_alteration () == robust_scm2rational (scm_cadr (handle), 0));
116
117       if (!same_bar || (same_bar && !same_alt))
118         handle = SCM_BOOL_F;
119     }
120
121   bool print_acc = scm_is_false (handle)
122                    || p->get_alteration () == Rational (0)
123                    || to_boolean (ev->get_property ("force-accidental"));
124
125   if (trill_head_)
126     {
127       programming_error ("already have a trill head.");
128       trill_head_ = 0;
129     }
130
131   trill_head_ = make_item ("TrillPitchHead", ev->self_scm ());
132   SCM c0scm = get_property ("middleCPosition");
133
134   int c0 = scm_is_number (c0scm) ? scm_to_int (c0scm) : 0;
135
136   trill_head_->set_property ("staff-position",
137                              scm_from_int (unsmob<Pitch> (scm_pitch)->steps ()
138                                            + c0));
139
140   trill_group_ = make_item ("TrillPitchGroup", ev->self_scm ());
141   trill_group_->set_parent (trill_head_, Y_AXIS);
142
143   Axis_group_interface::add_element (trill_group_, trill_head_);
144
145   if (print_acc)
146     {
147       trill_accidental_ = make_item ("TrillPitchAccidental", ev->self_scm ());
148
149       // fixme: naming -> alterations
150       trill_accidental_->set_property ("alteration", ly_rational2scm (p->get_alteration ()));
151       Side_position_interface::add_support (trill_accidental_, trill_head_);
152
153       trill_head_->set_object ("accidental-grob", trill_accidental_->self_scm ());
154       trill_accidental_->set_parent (trill_head_, Y_AXIS);
155       Axis_group_interface::add_element (trill_group_, trill_accidental_);
156     }
157 }
158
159 void
160 Pitched_trill_engraver::stop_translation_timestep ()
161 {
162   if (trill_group_)
163     for (vsize i = 0; i < heads_.size (); i++)
164       Side_position_interface::add_support (trill_group_, heads_[i]);
165
166   heads_.clear ();
167   trill_head_ = 0;
168   trill_group_ = 0;
169   trill_accidental_ = 0;
170 }
171
172
173 void
174 Pitched_trill_engraver::boot ()
175 {
176   ADD_ACKNOWLEDGER (Pitched_trill_engraver, note_head);
177   ADD_ACKNOWLEDGER (Pitched_trill_engraver, dots);
178   ADD_ACKNOWLEDGER (Pitched_trill_engraver, stem);
179   ADD_ACKNOWLEDGER (Pitched_trill_engraver, flag);
180   ADD_ACKNOWLEDGER (Pitched_trill_engraver, trill_spanner);
181 }
182
183 ADD_TRANSLATOR (Pitched_trill_engraver,
184                 /* doc */
185                 "Print the bracketed note head after a note head with trill.",
186
187                 /* create */
188                 "TrillPitchHead "
189                 "TrillPitchAccidental "
190                 "TrillPitchGroup ",
191
192                 /* read */
193                 "",
194
195                 /* write */
196                 ""
197                );