]> git.donarmstrong.com Git - lilypond.git/blob - lily/note-head.cc
*** empty log message ***
[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--2003 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 "event.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   SCM log = gh_int2scm (Note_head::get_balltype (me));
115   SCM proc = me->get_grob_property ("glyph-name-procedure");
116   SCM scm_font_char = scm_call_2 (proc, log, style);
117   String font_char = "noteheads-" + ly_scm2string (scm_font_char);
118
119   Font_metric * fm = Font_interface::get_default_font (me);
120   Molecule out = fm->find_by_name (font_char);
121   if (out.empty_b())
122     {
123       me->warning (_f ("note head `%s' not found", font_char.to_str0 ()));
124     }
125
126   int interspaces = Staff_symbol_referencer::line_count (me)-1;
127   int pos = (int)rint (Staff_symbol_referencer::get_position (me));
128   if (abs (pos) - interspaces > 1)
129     {
130       Interval hd = out.extent (X_AXIS);
131       Real left_ledger_protusion = hd.length ()/4;
132       Real right_ledger_protusion = left_ledger_protusion;
133
134       if (unsmob_grob(me->get_grob_property ("accidental-grob")))
135         {
136           /*
137             make a little room for accidentals.
138           
139             TODO: this will look silly if a chord has ledger lines,
140             and only the bottom note has an accidental.
141           */
142           
143           left_ledger_protusion *= 0.66;
144           right_ledger_protusion *= 0.9; 
145         }
146
147       Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
148                                      hd[RIGHT] + right_ledger_protusion);
149       out.add_molecule (Note_head::brew_ledger_lines (me, pos, interspaces,
150                                                       l_extents,
151                                                       ledger_take_space));
152     }
153   return out;
154 }
155
156
157 MAKE_SCHEME_CALLBACK (Note_head,brew_molecule,1);
158 SCM
159 Note_head::brew_molecule (SCM smob)  
160 {
161   Grob *me = unsmob_grob (smob);
162
163   /*
164     ledgers don't take space. See top of file.
165    */
166   return internal_brew_molecule (me, false).smobbed_copy ();
167 }
168
169 /*
170   Compute the width the head without ledgers.
171
172   -- there used to be some code from the time that ledgers
173   did take space. Nowadays, we can simply take the standard extent.
174  */
175 Interval
176 Note_head::head_extent (Grob *me, Axis a)
177 {
178   Molecule * mol = me->get_molecule();
179   return mol ? mol ->extent (a) : Interval(0,0);
180 }
181
182
183
184 MAKE_SCHEME_CALLBACK (Note_head,brew_ez_molecule,1);
185
186 SCM
187 Note_head::brew_ez_molecule (SCM smob)
188 {
189   Grob *me = unsmob_grob (smob);
190   int l = Note_head::get_balltype (me);
191
192   int b = (l >= 2);
193
194   SCM cause = me->get_grob_property ("cause");
195   SCM spitch = unsmob_music (cause)->get_mus_property ("pitch");
196   Pitch* pit =  unsmob_pitch (spitch);
197
198   char s[2] = "a";
199   s[0] = (pit->notename_ + 2)%7 + 'a';
200   s[0] = toupper (s[0]);
201   
202   SCM charstr = scm_makfrom0str (s);
203   
204   SCM at = scm_list_n (ly_symbol2scm ("ez-ball"),
205                        charstr,
206                        gh_int2scm (b),
207                        gh_int2scm (1-b),
208                        SCM_UNDEFINED);
209   Box bx (Interval (0, 1.0), Interval (-0.5, 0.5));
210   Molecule m (bx, at);
211
212   int pos = (int)rint (Staff_symbol_referencer::get_position (me));
213   int interspaces = Staff_symbol_referencer::line_count (me)-1;
214   if (abs (pos) - interspaces > 1)
215     {
216       Interval hd = m.extent (X_AXIS);
217       Real hw = hd.length ()/4;
218       Interval extent = Interval (hd[LEFT] - hw, hd[RIGHT] + hw);
219       m.add_molecule (brew_ledger_lines (me, pos, interspaces, extent, false));
220     }
221
222   return m.smobbed_copy ();
223 }
224
225
226 Real
227 Note_head::stem_attachment_coordinate (Grob *me, Axis a)
228 {
229   SCM v = me->get_grob_property ("stem-attachment-function");
230
231   if (!gh_procedure_p (v))
232     return 0.0;
233
234   SCM st = me->get_grob_property ("style");
235   SCM log = gh_int2scm (get_balltype (me));
236   SCM result = gh_apply (v, scm_list_n (st, log, SCM_UNDEFINED));
237
238   if (!gh_pair_p (result))
239     return 0.0;
240
241   result = (a == X_AXIS) ? ly_car (result) : ly_cdr (result);
242   
243   return gh_number_p (result) ?  gh_scm2double (result) : 0.0;
244 }
245
246 int
247 Note_head::get_balltype (Grob*me) 
248 {
249   SCM s = me->get_grob_property ("duration-log");
250   return gh_number_p (s) ? gh_scm2int (s) <? 2 : 0;
251 }
252
253 ADD_INTERFACE (Note_head,"note-head-interface",
254   "Note head",
255   "glyph-name-procedure accidental-grob style stem-attachment-function");
256