]> git.donarmstrong.com Git - lilypond.git/blob - lily/note-head.cc
release: 1.5.32
[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 (Interval xwid, Grob *me) 
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 (idw, me));
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 hw = hd.length ()/4;
161       out.add_molecule (Note_head::ledger_lines (me, ledger_take_space, streepjes_i, dir,
162                                       Interval (hd[LEFT] - hw,
163                                                 hd[RIGHT] + hw)));
164     }
165   return out;
166 }
167
168
169 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
170 SCM
171 Note_head::brew_molecule (SCM smob)  
172 {
173   Grob *me = unsmob_grob (smob);
174
175   /*
176     ledgers don't take space. See top of file.
177    */
178   return internal_brew_molecule (me, false).smobbed_copy ();
179 }
180
181 /*
182   Compute the width the head without ledgers.
183  */
184 Interval
185 Note_head::head_extent (Grob *me, Axis a)
186 {
187   return  internal_brew_molecule (me, false).extent (a);
188 }
189
190 bool
191 Note_head::has_interface (Grob*m)
192 {
193   return m&& m->has_interface (ly_symbol2scm ("note-head-interface"));
194 }
195
196
197 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
198
199 SCM
200 Note_head::brew_ez_molecule (SCM smob)
201 {
202   Grob *me = unsmob_grob (smob);
203   int l = Rhythmic_head::balltype_i (me);
204
205   int b = (l >= 2);
206
207   SCM cause = me->get_grob_property ("cause");
208   SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
209   Pitch* pit =  unsmob_pitch (spitch);
210
211   char s[2] = "a";
212   s[0] = (pit->notename_i_ + 2)%7 + 'a';
213   s[0] = toupper (s[0]);
214   
215   SCM charstr = ly_str02scm (s);
216   
217   SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
218                        charstr,
219                        gh_int2scm (b),
220                        gh_int2scm (1-b),
221                        SCM_UNDEFINED);
222   Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
223   Molecule m (bx, at);
224   int p = (int)  rint (Staff_symbol_referencer::position_f (me));
225
226   int sz = Staff_symbol_referencer::line_count (me)-1;
227   int streepjes_i = abs (p) < sz 
228     ? 0
229     : (abs (p) - sz) /2;
230
231  if (streepjes_i)
232    {
233       Direction dir = (Direction)sign (p);
234       Interval hd = m.extent (X_AXIS);
235       Real hw = hd.length ()/4;
236       m.add_molecule (ledger_lines (me, false, streepjes_i, dir,
237                                     Interval (hd[LEFT] - hw,
238                                                 hd[RIGHT] + hw)));
239     }
240   
241   return m.smobbed_copy ();
242 }
243
244
245 Real
246 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
247 {
248   SCM v = me->get_grob_property ("stem-attachment-function");
249
250   if (!gh_procedure_p (v))
251     return 0.0;
252
253   SCM st = me->get_grob_property ("style");
254   SCM result = gh_apply (v, scm_list_n (st, SCM_UNDEFINED));
255
256   if (!gh_pair_p (result))
257     return 0.0;
258
259   result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
260   
261   return gh_number_p (result) ?  gh_scm2double (result) : 0.0;
262 }