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