1 /*
2 This file is part of LilyPond, the GNU music typesetter.
3
4 Copyright (C) 1997--2020 Han-Wen Nienhuys <hanwen@xs4all.nl>
5 Mats Bengtsson <matsb@s3.kth.se>
6 Copyright (C) 2010--2020 Reinhold Kainhofer <reinhold@kainhofer.com>
7
8 LilyPond is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 LilyPond is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "item.hh"
23 #include "context.hh"
24 #include "staff-symbol-referencer.hh"
25 #include "engraver.hh"
26 #include "direction.hh"
27 #include "side-position-interface.hh"
28 #include "warn.hh"
29 #include "international.hh"
30
31 #include "translator.icc"
32
33 #include <cctype>
34
35 class Cue_clef_engraver : public Engraver
36 {
37 public:
38 TRANSLATOR_DECLARATIONS (Cue_clef_engraver);
39
40 protected:
41 void stop_translation_timestep ();
42 void process_music ();
43 void acknowledge_bar_line (Grob_info);
44
45 void derived_mark () const override;
46 private:
47 Item *clef_;
48 Item *modifier_;
49
50 SCM prev_glyph_;
51 SCM prev_cpos_;
52 SCM prev_transposition_;
53 void create_clef ();
54 void create_end_clef ();
55 void set_glyph ();
56 void inspect_clef_properties ();
57 void create_clef_modifier (SCM transp, SCM style, SCM formatter);
58 };
59
60 void
derived_mark() const61 Cue_clef_engraver::derived_mark () const
62 {
63 scm_gc_mark (prev_transposition_);
64 scm_gc_mark (prev_cpos_);
65 scm_gc_mark (prev_glyph_);
66 }
67
Cue_clef_engraver(Context * c)68 Cue_clef_engraver::Cue_clef_engraver (Context *c)
69 : Engraver (c)
70 {
71 clef_ = 0;
72 modifier_ = 0;
73
74 prev_transposition_ = prev_cpos_ = prev_glyph_ = SCM_EOL;
75 }
76
77 void
set_glyph()78 Cue_clef_engraver::set_glyph ()
79 {
80 SCM glyph_sym = ly_symbol2scm ("glyph");
81 SCM basic = ly_symbol2scm ("CueClef");
82 execute_pushpop_property (context (), basic, glyph_sym, SCM_UNDEFINED);
83 execute_pushpop_property (context (), basic, glyph_sym, get_property (this, "cueClefGlyph"));
84
85 basic = ly_symbol2scm ("CueEndClef");
86 execute_pushpop_property (context (), basic, glyph_sym, SCM_UNDEFINED);
87 execute_pushpop_property (context (), basic, glyph_sym, get_property (this, "clefGlyph"));
88 }
89
90 /**
91 Generate a clef at the start of a measure. (when you see a Bar,
92 ie. a breakpoint)
93 */
94 void
acknowledge_bar_line(Grob_info info)95 Cue_clef_engraver::acknowledge_bar_line (Grob_info info)
96 {
97 Item *item = dynamic_cast<Item *> (info.grob ());
98 if (item && scm_is_string (get_property (this, "cueClefGlyph")))
99 create_clef ();
100 }
101
102 void
create_clef_modifier(SCM transp,SCM style,SCM formatter)103 Cue_clef_engraver::create_clef_modifier (SCM transp, SCM style, SCM formatter)
104 {
105 if (scm_is_number (transp) && scm_to_int (transp))
106 {
107 Item *g = make_item ("ClefModifier", SCM_EOL);
108
109 int abs_transp = scm_to_int (transp);
110 int dir = sign (abs_transp);
111 abs_transp = abs (abs_transp) + 1;
112
113 SCM txt = scm_number_to_string (to_scm (abs_transp),
114 to_scm (10));
115
116 if (ly_is_procedure (formatter))
117 set_property (g, "text", scm_call_2 (formatter, txt, style));
118
119 Side_position_interface::add_support (g, clef_);
120
121 g->set_y_parent (clef_);
122 g->set_x_parent (clef_);
123 set_property (g, "direction", to_scm (dir));
124 modifier_ = g;
125 }
126 }
127
128 void
create_clef()129 Cue_clef_engraver::create_clef ()
130 {
131 if (!clef_)
132 {
133 Item *c = make_item ("CueClef", SCM_EOL);
134
135 clef_ = c;
136 SCM cpos = get_property (this, "cueClefPosition");
137 if (scm_is_number (cpos))
138 set_property (clef_, "staff-position", cpos);
139
140 create_clef_modifier (get_property (this, "cueClefTransposition"),
141 get_property (this, "cueClefTranspositionStyle"),
142 get_property (this, "cueClefTranspositionFormatter"));
143 }
144 }
145
146 void
create_end_clef()147 Cue_clef_engraver::create_end_clef ()
148 {
149 if (!clef_)
150 {
151 clef_ = make_item ("CueEndClef", SCM_EOL);
152 SCM cpos = get_property (this, "clefPosition");
153 if (scm_is_number (cpos))
154 set_property (clef_, "staff-position", cpos);
155
156 create_clef_modifier (get_property (this, "clefTransposition"),
157 get_property (this, "clefTranspositionStyle"),
158 get_property (this, "clefTranspositionFormatter"));
159 }
160 }
161
162 void
process_music()163 Cue_clef_engraver::process_music ()
164 {
165 inspect_clef_properties ();
166 }
167
168 void
inspect_clef_properties()169 Cue_clef_engraver::inspect_clef_properties ()
170 {
171 SCM glyph = get_property (this, "cueClefGlyph");
172 SCM clefpos = get_property (this, "cueClefPosition");
173 SCM transposition = get_property (this, "cueClefTransposition");
174
175 if (!ly_is_equal (glyph, prev_glyph_)
176 || !ly_is_equal (clefpos, prev_cpos_)
177 || !ly_is_equal (transposition, prev_transposition_))
178 {
179 set_glyph ();
180 if (scm_is_string (glyph))
181 {
182 create_clef ();
183 if (clef_)
184 set_property (clef_, "non-default", SCM_BOOL_T);
185 }
186 else
187 create_end_clef ();
188
189 prev_cpos_ = clefpos;
190 prev_glyph_ = glyph;
191 prev_transposition_ = transposition;
192 }
193
194 }
195
196 void
stop_translation_timestep()197 Cue_clef_engraver::stop_translation_timestep ()
198 {
199 if (clef_)
200 {
201 if (from_scm<bool> (get_property (clef_, "non-default")))
202 {
203 SCM vis = get_property (this, "explicitCueClefVisibility");
204
205 if (scm_is_vector (vis))
206 set_property (clef_, "break-visibility", vis);
207 }
208
209 clef_ = 0;
210 modifier_ = 0;
211 }
212 }
213
214 void
boot()215 Cue_clef_engraver::boot ()
216 {
217 ADD_ACKNOWLEDGER (Cue_clef_engraver, bar_line);
218 }
219
220 ADD_TRANSLATOR (Cue_clef_engraver,
221 /* doc */
222 "Determine and set reference point for pitches in cued voices.",
223
224 /* create */
225 "CueClef "
226 "CueEndClef "
227 "ClefModifier ",
228
229 /* read */
230 "cueClefGlyph "
231 "cueClefTransposition "
232 "cueClefTranspositionStyle "
233 "cueClefPosition "
234 "explicitCueClefVisibility "
235 "middleCCuePosition "
236 "clefTransposition ",
237
238 /* write */
239 ""
240 );
241