]> git.donarmstrong.com Git - lilypond.git/blob - lily/note-head.cc
release: 1.5.31
[lilypond.git] / lily / note-head.cc
1 /*
2   notehead.cc -- implement Note_head
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8 #include <math.h>
9
10 #include "misc.hh"
11 #include "dots.hh"
12 #include "note-head.hh"
13 #include "debug.hh"
14 #include "font-interface.hh"
15 #include "molecule.hh"
16 #include "musical-request.hh"
17 #include "rhythmic-head.hh"
18
19 /*
20   Note_head contains the code for printing note heads.
21
22
23
24   Ledger lines:
25
26   It also contains the ledger lines, for historical reasons.  Ledger
27   lines are somewhat of a PITA. In some cases, they take up no space, in
28   some cases they don't:
29
30   DO take space:
31
32   - when ledgered notes are juxtaposed: there should be some white
33    space between the ledger lines.
34
35   - when accidentals are near: the accidentals should not be on the ledger lines
36
37   [both tips by Heinz Stolba from Universal Edition].
38
39   DO NOT take space into account:
40
41   - for basically everything else, e.g. swapping ledgered notes on
42    clustered chords, spacing between ledgered and unledgered notes.
43
44   
45   TODO: fix this. It is not feasible to have a special grob for
46   ledgers, since you basically don't know if there will be ledgers,
47   unless you know at interpretation phase already 1. the Y-position,
48   2. the number of staff lines. It's not yet specced when both pieces
49   of information are there, so for now, it is probably better to build
50   special support for ledgers into the accidental and separation-item
51   code.
52
53   (Besides a separate ledger seems overkill. For what else would
54   it be useful?)
55   
56
57
58 */
59
60 #include "staff-symbol-referencer.hh"
61
62 /*
63   build a ledger line for small pieces.
64  */
65 Molecule
66 Note_head::ledger_line (Interval xwid, Grob *me) 
67 {
68   Drul_array<Molecule> endings;
69   endings[LEFT] = Font_interface::get_default_font (me)->find_by_name ("noteheads-ledgerending");
70   Molecule *e = &endings[LEFT];
71   endings[RIGHT] = *e;
72   
73   Real thick = e->extent (Y_AXIS).length ();
74   Real len = e->extent (X_AXIS).length () - thick;
75
76   Molecule total;
77   Direction d = LEFT;
78   do {
79     endings[d].translate_axis (xwid[d] - endings[d].extent (X_AXIS)[d], X_AXIS);
80     total.add_molecule (endings[d]);    
81   } while ((flip (&d)) != LEFT);
82
83   Real xpos = xwid [LEFT] + len;
84
85   while (xpos + len + thick /2 <= xwid[RIGHT])
86     {
87       e->translate_axis (len, X_AXIS);
88       total.add_molecule (*e);
89       xpos += len;
90     }
91
92   return total;
93 }
94
95
96 Molecule
97 Note_head::ledger_lines (Grob*me,
98                          bool take_space,
99                          int count, Direction dir, Interval idw)
100 {
101   Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
102
103   /*
104     idw ?
105
106     (who's that ?  :-)
107
108
109     --hwn 
110    */
111   Molecule ledger (ledger_line (idw, me));
112
113   if (!take_space)
114     ledger.set_empty (true);
115   
116   Real offs = (Staff_symbol_referencer::on_staffline (me))
117     ? 0.0
118     : -dir * inter_f;
119
120   Molecule legs;
121   for (int i=0; i < count; i++)
122     {
123       Molecule s (ledger);
124       s.translate_axis (-dir * inter_f * i*2 + offs,
125                         Y_AXIS);
126       legs.add_molecule (s);
127     }
128
129   return legs;
130 }
131
132 Molecule
133 internal_brew_molecule (Grob *me,  bool ledger_take_space)
134 {
135   int sz = Staff_symbol_referencer::line_count (me)-1;
136   int p = (int)  rint (Staff_symbol_referencer::position_f (me));
137   int streepjes_i = abs (p) < sz 
138     ? 0
139     : (abs (p) - sz) /2;
140
141   SCM style  = me->get_grob_property ("style");
142   if (!gh_symbol_p (style))
143     {
144       return Molecule();
145     }
146
147   /*
148     ugh: use gh_call () / scm_apply ().
149
150     UGH: use grob-property.
151   */
152   SCM log = gh_int2scm (Rhythmic_head::balltype_i (me));
153   SCM exp = scm_list_n (ly_symbol2scm ("find-notehead-symbol"), log,
154                         ly_quote_scm (style),
155                         SCM_UNDEFINED);
156   String name = "noteheads-" + ly_scm2string (scm_primitive_eval (exp));
157   Molecule out = Font_interface::get_default_font (me)->find_by_name (name);
158
159   if (streepjes_i) 
160     {
161       Direction dir = (Direction)sign (p);
162       Interval hd = out.extent (X_AXIS);
163       Real hw = hd.length ()/4;
164       out.add_molecule (Note_head::ledger_lines (me, ledger_take_space, streepjes_i, dir,
165                                       Interval (hd[LEFT] - hw,
166                                                 hd[RIGHT] + hw)));
167     }
168   return out;
169 }
170
171
172 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
173 SCM
174 Note_head::brew_molecule (SCM smob)  
175 {
176   Grob *me = unsmob_grob (smob);
177
178   /*
179     ledgers don't take space. See top of file.
180    */
181   return internal_brew_molecule (me, false).smobbed_copy ();
182 }
183
184 /*
185   Compute the width the head without ledgers.
186  */
187 Interval
188 Note_head::head_extent (Grob *me, Axis a)
189 {
190   return  internal_brew_molecule (me, false).extent (a);
191 }
192
193 bool
194 Note_head::has_interface (Grob*m)
195 {
196   return m&& m->has_interface (ly_symbol2scm ("note-head-interface"));
197 }
198
199
200 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
201
202 /*
203   TODO: ledger lines are causing  a mess again, now with accidentals and
204   ez-note heads.
205  */ 
206 SCM
207 Note_head::brew_ez_molecule (SCM smob)
208 {
209   Grob *me = unsmob_grob (smob);
210   int l = Rhythmic_head::balltype_i (me);
211
212   int b = (l >= 2);
213   SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
214                     me->get_grob_property ("note-character"),
215                     gh_int2scm (b),
216                     gh_int2scm (1-b),
217                     SCM_UNDEFINED);
218   Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
219   Molecule m (bx, at);
220   int p = (int)  rint (Staff_symbol_referencer::position_f (me));
221
222   int sz = Staff_symbol_referencer::line_count (me)-1;
223   int streepjes_i = abs (p) < sz 
224     ? 0
225     : (abs (p) - sz) /2;
226
227  if (streepjes_i)
228    {
229       Direction dir = (Direction)sign (p);
230       Interval hd = m.extent (X_AXIS);
231       Real hw = hd.length ()/4;
232       m.add_molecule (ledger_lines (me, false, streepjes_i, dir,
233                                     Interval (hd[LEFT] - hw,
234                                                 hd[RIGHT] + hw)));
235     }
236   
237   return m.smobbed_copy ();
238 }
239
240
241 Real
242 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
243 {
244   SCM v = me->get_grob_property ("stem-attachment-function");
245
246   if (!gh_procedure_p (v))
247     return 0.0;
248
249   SCM st = me->get_grob_property ("style");
250   SCM result = gh_apply (v, scm_list_n (st, SCM_UNDEFINED));
251
252   if (!gh_pair_p (result))
253     return 0.0;
254
255   result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
256   
257   return gh_number_p (result) ?  gh_scm2double (result) : 0.0;
258 }