]> git.donarmstrong.com Git - lilypond.git/blob - lily/piano-pedal-engraver.cc
0a7bf172c2634d28f5bf6163f0fd657f4e9f9aa0
[lilypond.git] / lily / piano-pedal-engraver.cc
1 /*   
2   piano-pedal-engraver.cc --  implement Piano_pedal_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2000 Jan Nieuwenhuizen <janneke@gnu.org>
7  */
8
9 #include "engraver.hh"
10 #include "musical-request.hh"
11 #include "score-element.hh"
12 #include "item.hh"
13 #include "lookup.hh"
14 #include "lily-guile.hh"
15 #include "note-head.hh"
16 #include "stem.hh"
17 #include "side-position-interface.hh"
18 #include "staff-symbol-referencer.hh"
19 #include "dictionary.hh"
20 #include "dictionary-iter.hh"
21 #include "text-item.hh"
22
23 /*
24   Urg.
25   This is almost text
26   Problem is:
27     * we have no kerning
28     * symbols are at wrong place in font
29 */
30
31 class Sustain_pedal : public Item
32 {
33 public:
34   VIRTUAL_COPY_CONS (Score_element);
35
36 protected:
37   virtual Molecule do_brew_molecule () const;
38   virtual void after_line_breaking ();
39 };
40
41 void
42 Sustain_pedal::after_line_breaking ()
43 {
44   Side_position_interface i (this);
45   Direction d =  i.get_direction ();
46   i.set_direction (d);
47 }
48
49 Molecule
50 Sustain_pedal::do_brew_molecule () const
51 {
52   Molecule mol;
53   SCM glyph = get_elt_property ("glyph");
54   if (glyph == SCM_UNDEFINED)
55     return mol;
56   String text = ly_scm2string (glyph);
57
58   for (int i = 0; i < text.length_i (); i++)
59     {
60       // leuke koor dump door tiepo, snapnie helemaal:
61       //String idx = ("pedal-") + text[i];
62       // urg, Byte* ??
63       // braak: waarom vindt String het zo moeilijk om
64       // String + char te doen?
65       //String idx = "pedal-" + String (&text.byte_C ()[i], 1);
66       String idx = String ("pedal-") + String (&text.byte_C ()[i], 1);
67       Molecule m = lookup_l ()->afm_find (idx);
68       if (m.empty_b ())
69         continue;
70       Real kern = 0;
71       if (i)
72         {
73           SCM s = scm_eval (gh_list (ly_symbol2scm ("pedal-kerning"),
74                                      ly_str02scm (String (&text.byte_C ()[i - 1], 1).ch_C ()),
75                                      ly_str02scm (String (&text.byte_C ()[i], 1).ch_C ()),
76                                      SCM_UNDEFINED));
77           if (gh_number_p (s))
78             {
79               Staff_symbol_referencer_interface st (this);
80               Real staff_space = st.staff_space ();
81               kern = gh_scm2double (s) * staff_space;
82             }
83         }
84       mol.add_at_edge (X_AXIS, RIGHT, m, kern);
85     }
86     
87   return mol;
88 }
89
90
91
92 /*
93    TODO:
94      * it would be real cool if an engraver could be initialised with a
95        string, ie:
96
97           Piano_pedal_engraver::"sostenuto"
98           Piano_pedal_engraver::"sustain"
99           Piano_pedal_engraver::"una-chorda"
100  */
101
102 /**
103    engrave Piano pedals
104  */
105 class Piano_pedal_engraver : public Engraver
106 {
107   struct Pedal_info
108   {
109     Span_req* start_req_l_;
110     Drul_array<Span_req*> req_l_drul_;
111     Item* item_p_;
112   };
113
114 public:
115   VIRTUAL_COPY_CONS (Translator);
116   Piano_pedal_engraver ();
117
118 protected:
119   virtual bool do_try_music (Music*);
120   virtual void do_process_music ();
121   virtual void do_pre_move_processing ();
122   virtual void do_post_move_processing ();
123   virtual void acknowledge_element (Score_element_info);
124
125 private:
126   Dictionary<Pedal_info> info_dict_;
127 };
128
129 ADD_THIS_TRANSLATOR (Piano_pedal_engraver);
130
131 Piano_pedal_engraver::Piano_pedal_engraver ()
132 {
133   (void)info_dict_["Sostenuto"];
134   (void)info_dict_["Sustain"];
135   (void)info_dict_["UnaChorda"];
136   for (Dictionary_iter <Pedal_info> i (info_dict_); i.ok (); i++)
137     {
138       Pedal_info& p = i.val_ref ();
139       p.item_p_ = 0;
140       p.req_l_drul_[START] = 0;
141       p.req_l_drul_[STOP] = 0;
142       p.start_req_l_ = 0;
143     }
144 }
145
146 /*
147   Urg: Code dup
148   I'm a script
149  */
150 void
151 Piano_pedal_engraver::acknowledge_element (Score_element_info info)
152 {
153   for (Dictionary_iter <Pedal_info> i (info_dict_); i.ok (); i++)
154     {
155       Pedal_info& p = i.val_ref ();
156       if (p.item_p_)
157         {
158           if (Note_head* n = dynamic_cast<Note_head*> (info.elem_l_))
159             {
160               Side_position_interface st (p.item_p_);
161               st.add_support (n);
162               if (st.get_axis( ) == X_AXIS
163                   && !p.item_p_->parent_l (Y_AXIS))
164                 p.item_p_->set_parent (n, Y_AXIS);
165             }
166           if (Stem* s = dynamic_cast<Stem*> (info.elem_l_))
167             {
168               Side_position_interface st (p.item_p_);
169               st.add_support (s);
170             }
171         }
172     }
173 }
174
175 bool
176 Piano_pedal_engraver::do_try_music (Music *m)
177 {
178   for (Dictionary_iter <Pedal_info> i (info_dict_); i.ok (); i++)
179     {
180       Pedal_info& p = i.val_ref ();
181       if (Span_req * s = dynamic_cast<Span_req*>(m))
182         {
183           if (s->span_type_str_ == i.key ())
184             {
185               p.req_l_drul_[s->span_dir_] = s;
186               return true;
187             }
188         }
189     }
190   return false;
191 }
192
193 void
194 Piano_pedal_engraver::do_process_music ()
195 {
196   for (Dictionary_iter <Pedal_info> i (info_dict_); i.ok (); i++)
197     {
198       Pedal_info& p = i.val_ref ();
199       SCM s = SCM_UNDEFINED;
200       if (p.req_l_drul_[STOP] && p.req_l_drul_[START])
201         {
202           if (!p.start_req_l_)
203             {
204               p.req_l_drul_[STOP]->warning (_f ("can't find start of piano pedal: %s", i.key ()));
205             }
206           else
207             {
208               s = get_property ("stopStart" + i.key ());
209             }
210           p.start_req_l_ = p.req_l_drul_[START];
211         }
212       else if (p.req_l_drul_[STOP])
213         {
214           if (!p.start_req_l_)
215             {
216               p.req_l_drul_[STOP]->warning (_f ("can't find start of piano pedal: %s", i.key ()));
217             }
218           else
219             {
220               s = get_property ("stop" + i.key ());
221             }
222           p.start_req_l_ = 0;
223         }
224       else if (p.req_l_drul_[START])
225         {
226           p.start_req_l_ = p.req_l_drul_[START];
227           s = get_property ("start" + i.key ());
228         }
229
230       if (s != SCM_UNDEFINED)
231         {
232           if (i.key () == "Sustain")
233             {
234               p.item_p_ = new Sustain_pedal;
235               p.item_p_->set_elt_property ("glyph", s);
236             }
237           else
238             {
239               p.item_p_ = new Text_item;
240               p.item_p_->set_elt_property ("text", s);
241               // guh
242               p.item_p_->set_elt_property ("style", ly_str02scm ("italic"));
243             }
244
245           Side_position_interface si (p.item_p_);
246           si.set_axis (Y_AXIS);
247
248           /* Hmm,
249              If set to empty, it can't be centred
250              Howto centre non-fat text?
251              p.item_p_->set_empty (X_AXIS);
252           */
253           p.item_p_->set_elt_property ("self-alignment-X", gh_int2scm (0));
254           p.item_p_->add_offset_callback (Side_position_interface::aligned_on_self, X_AXIS);
255           p.item_p_->add_offset_callback (Side_position_interface::centered_on_parent, X_AXIS);
256           announce_element (Score_element_info (p.item_p_,
257                                                 p.req_l_drul_[START]
258                                                 ? p.req_l_drul_[START]
259                                                 : p.req_l_drul_[STOP]));
260         }
261     }
262 }
263
264 void
265 Piano_pedal_engraver::do_pre_move_processing ()
266 {
267   for (Dictionary_iter <Pedal_info> i (info_dict_); i.ok (); i++)
268     {
269       Pedal_info& p = i.val_ref ();
270       if (p.item_p_)
271         {
272           side_position (p.item_p_).add_staff_support ();
273           typeset_element (p.item_p_);
274         }
275       p.item_p_ = 0;
276     }
277 }
278
279 void
280 Piano_pedal_engraver::do_post_move_processing ()
281 {
282   for (Dictionary_iter <Pedal_info> i (info_dict_); i.ok (); i++)
283     {
284       Pedal_info& p = i.val_ref ();
285       p.req_l_drul_[STOP] = 0;
286       p.req_l_drul_[START] = 0;
287     }
288 }