]> git.donarmstrong.com Git - lilypond.git/blob - lily/note-head.cc
``slikken kreng''
[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 "warn.hh"
15 #include "font-interface.hh"
16 #include "molecule.hh"
17 #include "musical-request.hh"
18 #include "rhythmic-head.hh"
19 #include "staff-symbol-referencer.hh"
20 #include "lookup.hh"
21 #include "paper-def.hh"
22
23 /*
24   Note_head contains the code for printing note heads.
25
26   Ledger lines:
27
28   It also contains the ledger lines, for historical reasons.  Ledger
29   lines are somewhat of a PITA. In some cases, they take up no space, in
30   some cases they don't:
31
32   DO take space:
33
34   - when ledgered notes are juxtaposed: there should be some white
35    space between the ledger lines.
36
37   - when accidentals are near: the accidentals should not be on the
38   ledger lines
39
40   [both tips by Heinz Stolba from Universal Edition].
41
42   DO NOT take space into account:
43
44   - for basically everything else, e.g. swapping ledgered notes on
45    clustered chords, spacing between ledgered and unledgered notes.
46   
47   TODO: fix this. It is not feasible to have a special grob for
48   ledgers, since you basically don't know if there will be ledgers,
49   unless you know at interpretation phase already 1. the Y-position,
50   2. the number of staff lines. It's not yet specced when both pieces
51   of information are there, so for now, it is probably better to build
52   special support for ledgers into the accidental and separation-item
53   code.
54
55   (Besides a separate ledger seems overkill. For what else would
56   it be useful?)
57
58 */
59
60 Molecule
61 Note_head::brew_ledger_lines (Grob *me,
62                               int pos,
63                               int interspaces,
64                               Interval x_extent,
65                               bool take_space)
66 {
67   Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
68   int lines_i = abs (pos) < interspaces
69     ? 0
70     : (abs (pos) - interspaces) / 2;
71   Molecule molecule = Molecule();
72
73   if (lines_i)
74     {
75       Real ledgerlinethickness =
76         (me->get_paper ()->get_var ("ledgerlinethickness"));
77       Real blotdiameter = ledgerlinethickness;
78       //        (me->get_paper ()->get_var ("blotdiameter"));
79       Interval y_extent =
80         Interval (-0.5*(ledgerlinethickness),
81                   +0.5*(ledgerlinethickness));
82       Box ledger_line (x_extent, y_extent);
83
84       Molecule proto_ledger_line =
85         Lookup::roundfilledbox (ledger_line, blotdiameter);
86       
87       if (!take_space)
88         proto_ledger_line.set_empty (true);
89
90       Direction dir = (Direction)sign (pos);
91       Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
92         ? 0.0
93         : -dir * inter_f;
94       for (int i = 0; i < lines_i; i++)
95         {
96           Molecule ledger_line (proto_ledger_line);
97           ledger_line.translate_axis (-dir * inter_f * i * 2 + offs, Y_AXIS);
98           molecule.add_molecule (ledger_line);
99         }
100     }
101
102   return molecule;
103 }
104
105 Molecule
106 internal_brew_molecule (Grob *me,  bool ledger_take_space)
107 {
108   SCM style  = me->get_grob_property ("style");
109   if (!gh_symbol_p (style))
110     {
111       return Molecule();
112     }
113
114   /*
115     ugh: use gh_call () / scm_apply ().
116
117     UGH: use grob-property.
118   */
119   SCM log = gh_int2scm (Note_head::get_balltype (me));
120   SCM exp = scm_list_n (ly_symbol2scm ("find-notehead-symbol"), log,
121                         ly_quote_scm (style),
122                         SCM_UNDEFINED);
123   String name = "noteheads-" + ly_scm2string (scm_primitive_eval (exp));
124   Molecule out = Font_interface::get_default_font (me)->find_by_name (name);
125   if (out.empty_b())
126     {
127       warning (_f("Symbol not found, ", name.to_str0 ()));
128     }
129   
130   int interspaces = Staff_symbol_referencer::line_count (me)-1;
131   int pos = (int)rint (Staff_symbol_referencer::get_position (me));
132   if (abs (pos) - interspaces > 1)
133     {
134       Interval hd = out.extent (X_AXIS);
135       Real left_ledger_protusion = hd.length ()/4;
136       Real right_ledger_protusion = left_ledger_protusion;
137
138       if (unsmob_grob(me->get_grob_property ("accidental-grob")))
139         {
140           /*
141             make a little room for accidentals.
142           
143             TODO: this will look silly if a chord has ledger lines,
144             and only the bottom note has an accidental.
145           */
146           
147           left_ledger_protusion *= 0.66;
148           right_ledger_protusion *= 0.9; 
149         }
150
151       Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
152                                      hd[RIGHT] + right_ledger_protusion);
153       out.add_molecule (Note_head::brew_ledger_lines (me, pos, interspaces,
154                                                       l_extents,
155                                                       ledger_take_space));
156     }
157   return out;
158 }
159
160
161 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
162 SCM
163 Note_head::brew_molecule (SCM smob)  
164 {
165   Grob *me = unsmob_grob (smob);
166
167   /*
168     ledgers don't take space. See top of file.
169    */
170   return internal_brew_molecule (me, false).smobbed_copy ();
171 }
172
173 /*
174   Compute the width the head without ledgers.
175
176   -- there used to be some code from the time that ledgers
177   did take space. Nowadays, we can simply take the standard extent.
178  */
179 Interval
180 Note_head::head_extent (Grob *me, Axis a)
181 {
182   return me->get_molecule()->extent (a);
183 }
184
185
186
187 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
188
189 SCM
190 Note_head::brew_ez_molecule (SCM smob)
191 {
192   Grob *me = unsmob_grob (smob);
193   int l = Note_head::get_balltype (me);
194
195   int b = (l >= 2);
196
197   SCM cause = me->get_grob_property ("cause");
198   SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
199   Pitch* pit =  unsmob_pitch (spitch);
200
201   char s[2] = "a";
202   s[0] = (pit->notename_ + 2)%7 + 'a';
203   s[0] = toupper (s[0]);
204   
205   SCM charstr = ly_str02scm (s);
206   
207   SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
208                        charstr,
209                        gh_int2scm (b),
210                        gh_int2scm (1-b),
211                        SCM_UNDEFINED);
212   Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
213   Molecule m (bx, at);
214
215   int pos = (int)rint (Staff_symbol_referencer::get_position (me));
216   int interspaces = Staff_symbol_referencer::line_count (me)-1;
217   if (abs (pos) - interspaces > 1)
218     {
219       Interval hd = m.extent (X_AXIS);
220       Real hw = hd.length ()/4;
221       Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
222       m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
223     }
224
225   return m.smobbed_copy ();
226 }
227
228
229 Real
230 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
231 {
232   SCM v = me->get_grob_property ("stem-attachment-function");
233
234   if (!gh_procedure_p (v))
235     return 0.0;
236
237   SCM st = me->get_grob_property ("style");
238   SCM result = gh_apply (v, scm_list_n (st, SCM_UNDEFINED));
239
240   if (!gh_pair_p (result))
241     return 0.0;
242
243   result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
244   
245   return gh_number_p (result) ?  gh_scm2double (result) : 0.0;
246 }
247
248
249 int
250 Note_head::get_balltype (Grob*me) 
251 {
252   SCM s = me->get_grob_property ("duration-log");
253   return gh_number_p (s) ? gh_scm2int (s) <? 2 : 0;
254 }
255
256 ADD_INTERFACE (Note_head,"note-head-interface",
257   "Note head",
258   "accidental-grob style stem-attachment-function");
259