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