]> git.donarmstrong.com Git - lilypond.git/blob - lily/pitch.cc
* lily/global-context.cc (run_iterator_on_me): fix grace note
[lilypond.git] / lily / pitch.cc
1 /*
2   musical-pitch.cc --  implement Pitch
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "pitch.hh"
10 #include "warn.hh"
11 #include "main.hh"
12 #include "ly-smobs.icc"
13
14
15 Pitch::Pitch (int o, int n, int a)
16 {
17   notename_ = n;
18   alteration_ = a;
19   octave_ = o;
20   normalise ();
21 }
22
23 Pitch::Pitch ()
24 {
25   notename_ = 0;
26   alteration_ = 0;
27   octave_ = 0;
28 }
29
30 int
31 Pitch::compare (Pitch const &m1, Pitch const &m2)
32 {
33   int o=  m1.octave_ - m2.octave_;
34   int n = m1.notename_ - m2.notename_;
35   int a = m1.alteration_ - m2.alteration_;
36
37   if (o)
38     return o;
39   if (n)
40     return n;
41   if (a)
42     return a;
43   return 0;
44 }
45
46 int
47 Pitch::steps () const
48 {
49   return  notename_ + octave_*7;
50 }
51
52 /* Should be settable from input?  */
53 static Byte diatonic_scale_semitones[  ] = { 0, 2, 4, 5, 7, 9, 11 };
54
55
56 /* Calculate pitch height in 12th octave steps.  Don't assume
57    normalised pitch as this function is used to normalise the pitch.  */
58 int
59 Pitch::semitone_pitch () const
60 {
61   int o = octave_;
62   int n = notename_;
63   while (n < 0)
64     {
65       n += 7;
66       o --;
67     }
68
69   if (alteration_ % 2)
70     programming_error ("semitone_pitch () called on quarter tone alteration.");
71
72   return ((o + n / 7) * 12
73           + diatonic_scale_semitones[n % 7]
74           + (alteration_ / 2));
75 }
76
77 int
78 Pitch::quartertone_pitch () const
79 {
80   int o = octave_;
81   int n = notename_;
82   while (n < 0)
83     {
84       n += 7;
85       o --;
86     }
87
88   return ((o + n / 7) * 24
89           + 2 * diatonic_scale_semitones[n % 7]
90           + alteration_);
91 }
92
93 void
94 Pitch::normalise ()
95 {
96   int pitch = quartertone_pitch ();
97   while (notename_ >= 7)
98     {
99       notename_ -= 7;
100       octave_++;
101       alteration_ -= quartertone_pitch () - pitch;
102     }
103   while (notename_ < 0)
104     {
105       notename_ += 7;
106       octave_--;
107       alteration_ -= quartertone_pitch () - pitch;
108     }
109   while (alteration_ > DOUBLE_SHARP)
110     {
111       if (notename_ == 6)
112         {
113           notename_ = 0;
114           octave_++;
115         }
116       else
117         notename_++;
118
119       alteration_ = 0;
120       alteration_ -= quartertone_pitch () - pitch;
121     }
122
123   while (alteration_ < DOUBLE_FLAT)
124     {
125       if (notename_ == 0)
126         {
127           notename_ = 6;
128           octave_--;
129         }
130       else
131         notename_--;
132
133       alteration_ = 0;
134       alteration_ -= quartertone_pitch () - pitch;
135     }
136 }
137
138 /* WHugh, wat een intervaas */
139 void
140 Pitch::transpose (Pitch delta)
141 {
142   int new_semi = quartertone_pitch ()  +delta.quartertone_pitch ();
143   octave_ += delta.octave_;
144   notename_ += delta.notename_;
145   alteration_ += new_semi - quartertone_pitch ();
146
147   normalise ();
148 }
149
150 Pitch
151 interval (Pitch const & from , Pitch const & to )
152 {
153   int sound = to.quartertone_pitch ()  - from.quartertone_pitch ();
154   Pitch pt (to.get_octave () - from.get_octave (),
155             to.get_notename () - from.get_notename (),
156
157             to.get_alteration () - from.get_alteration ());
158
159   return pt.transposed (Pitch (0,0,sound - pt.quartertone_pitch ()));
160 }
161
162
163 /* FIXME
164    Merge with *pitch->text* funcs in chord-name.scm  */
165 char const *accname[] = {"eses", "eseh", "es", "eh", "",
166                          "ih", "is" , "isih",  "isis"};
167
168 String
169 Pitch::to_string () const
170 {
171   int n = (notename_ + 2) % 7;
172   String s = ::to_string (char (n + 'a'));
173   if (alteration_)
174     s += String (accname[alteration_ - DOUBLE_FLAT]);
175
176   if (octave_ >= 0)
177     {
178       int o = octave_ + 1;
179       while (o--)
180         s += "'";
181     }
182   else if (octave_ < 0)
183     {
184       int o = (-octave_) - 1;
185       while (o--)
186         s += ::to_string (',');
187     }
188
189   return s;
190 }
191
192 /* Change me to relative, counting from last pitch p
193    return copy of resulting pitch.  */
194 Pitch
195 Pitch::to_relative_octave (Pitch p) const
196 {
197   /* account for c' = octave 1 iso. 0 4 */
198   int oct_mod = octave_  + 1;
199   Pitch up_pitch (p);
200   Pitch down_pitch (p);
201
202   up_pitch.alteration_ = alteration_;
203   down_pitch.alteration_ = alteration_;
204
205   Pitch n = *this;
206   up_pitch.up_to (notename_);
207   down_pitch.down_to (notename_);
208
209   int h = p.steps ();
210   if (abs (up_pitch.steps () - h) < abs (down_pitch.steps () - h))
211     n = up_pitch;
212   else
213     n = down_pitch;
214
215   n.octave_ += oct_mod;
216   return n;
217 }
218
219 void
220 Pitch::up_to (int notename)
221 {
222   if (notename_ > notename)
223     octave_++;
224   notename_  = notename;
225 }
226
227 void
228 Pitch::down_to (int notename)
229 {
230   if (notename_ < notename)
231     octave_--;
232   notename_ = notename;
233 }
234
235 LY_DEFINE (ly_pitch_transpose, "ly:pitch-transpose",
236            2, 0, 0, (SCM p, SCM delta),
237            "Transpose @var{p} by the amount @var{delta}, "
238            "where @var{delta} is relative to middle C.")
239 {
240   Pitch* t = unsmob_pitch (p);
241   Pitch *d = unsmob_pitch (delta);
242   SCM_ASSERT_TYPE (t, p, SCM_ARG1, __FUNCTION__, "pitch");
243   SCM_ASSERT_TYPE (d, delta, SCM_ARG1, __FUNCTION__, "pitch");
244   return t->transposed (*d).smobbed_copy ();
245 }
246
247 IMPLEMENT_TYPE_P (Pitch, "ly:pitch?");
248
249 SCM
250 Pitch::mark_smob (SCM)
251 {
252   return SCM_EOL;
253 }
254
255 IMPLEMENT_SIMPLE_SMOBS (Pitch);
256 int
257 Pitch::print_smob (SCM s, SCM port, scm_print_state *)
258 {
259   Pitch *r = (Pitch *) ly_cdr (s);
260   scm_puts ("#<Pitch ", port);
261   scm_display (scm_makfrom0str (r->to_string ().to_str0 ()), port);
262   scm_puts (" >", port);
263   return 1;
264 }
265
266 SCM
267 Pitch::equal_p (SCM a , SCM b)
268 {
269   Pitch *p = (Pitch *) ly_cdr (a);
270   Pitch *q = (Pitch *) ly_cdr (b);
271
272   bool eq = p->notename_ == q->notename_
273     && p->octave_ == q->octave_
274     && p->alteration_ == q->alteration_;
275
276   return eq ? SCM_BOOL_T : SCM_BOOL_F;
277 }
278
279 MAKE_SCHEME_CALLBACK (Pitch, less_p, 2);
280 SCM
281 Pitch::less_p (SCM p1, SCM p2)
282 {
283   Pitch *a = unsmob_pitch (p1);
284   Pitch *b = unsmob_pitch (p2);
285
286   if (compare (*a, *b) < 0)
287     return SCM_BOOL_T;
288   else
289     return SCM_BOOL_F;
290 }
291
292 /* Should add optional args.  */
293 LY_DEFINE (make_pitch, "ly:make-pitch",
294            3, 0, 0, (SCM octave, SCM note, SCM alter),
295            "@var{octave} is specified by an integer, "
296            "zero for the octave containing middle C.  "
297            "@var{note} is a number from 0 to 6, "
298            "with 0 corresponding to C and 6 corresponding to B.  "
299            "The @var{alter} is zero for a natural, negative for "
300            "flats, or positive for sharps. ")
301 {
302   SCM_ASSERT_TYPE (scm_integer_p (octave)== SCM_BOOL_T , octave, SCM_ARG1, __FUNCTION__, "integer");
303   SCM_ASSERT_TYPE (scm_integer_p (note)== SCM_BOOL_T, note, SCM_ARG2, __FUNCTION__, "integer");
304   SCM_ASSERT_TYPE (scm_integer_p (alter)== SCM_BOOL_T, alter, SCM_ARG3, __FUNCTION__, "integer");
305
306   Pitch p (gh_scm2int (octave), gh_scm2int (note), gh_scm2int (alter));
307   return p.smobbed_copy ();
308 }
309
310 LY_DEFINE (pitch_steps, "ly:pitch-steps", 1, 0, 0,
311            (SCM p),
312            "Number of steps counted from middle C of the pitch @var{p}.")
313 {
314   Pitch *pp = unsmob_pitch (p);
315   SCM_ASSERT_TYPE (pp, p, SCM_ARG1, __FUNCTION__, "Pitch");
316   return gh_int2scm (pp->steps ());
317 }
318
319 LY_DEFINE (pitch_octave, "ly:pitch-octave",
320            1, 0, 0, (SCM pp),
321            "Extract the octave from pitch @var{p}.")
322 {
323   Pitch *p = unsmob_pitch (pp);
324   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
325   int q = p->get_octave ();
326   return gh_int2scm (q);
327 }
328
329 LY_DEFINE (pitch_alteration, "ly:pitch-alteration",
330            1, 0, 0, (SCM pp),
331            "Extract the alteration from pitch  @var{p}.")
332 {
333   Pitch *p = unsmob_pitch (pp);
334   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
335   int q = p->get_alteration ();
336
337   return gh_int2scm (q);
338 }
339
340 LY_DEFINE (pitch_notename, "ly:pitch-notename",
341            1, 0, 0, (SCM pp),
342            "Extract the note name from pitch  @var{pp}.")
343 {
344   Pitch *p = unsmob_pitch (pp);
345   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
346   int q = p->get_notename ();
347   return gh_int2scm (q);
348 }
349
350 LY_DEFINE (ly_pitch_quartertones,  "ly:pitch-quartertones",
351            1, 0, 0, (SCM pp),
352            "Calculate the number of quarter tones of @var{p} from middle C.")
353 {
354   Pitch *p = unsmob_pitch (pp);
355   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
356   int q = p->quartertone_pitch ();
357   return gh_int2scm (q);
358 }
359
360 LY_DEFINE (ly_pitch_semitones,  "ly:pitch-semitones",
361            1, 0, 0, (SCM pp),
362            "calculate the number of semitones of @var{p} from middle C.")
363 {
364   Pitch *p = unsmob_pitch (pp);
365   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
366   int q = p->semitone_pitch ();
367   return gh_int2scm (q);
368 }
369
370 LY_DEFINE (pitch_less, "ly:pitch<?",
371            2, 0, 0, (SCM p1, SCM p2),
372            "Is @var{p1} lexicographically smaller than @var{p2}?")
373 {
374   Pitch *a = unsmob_pitch (p1);
375   Pitch *b = unsmob_pitch (p2);
376
377   SCM_ASSERT_TYPE (a, p1, SCM_ARG1, __FUNCTION__, "Pitch");
378   SCM_ASSERT_TYPE (b, p2, SCM_ARG2, __FUNCTION__, "Pitch");
379
380   if (Pitch::compare (*a, *b) < 0)
381     return SCM_BOOL_T;
382   else
383     return SCM_BOOL_F;
384 }
385
386 LY_DEFINE (ly_pitch_diff, "ly:pitch-diff",
387            2 ,0, 0, (SCM pitch, SCM  root),
388            "Return pitch @var{delta} such that @code{pitch} transposed by "
389            "@var{delta} equals @var{root}" )
390 {
391   Pitch *p = unsmob_pitch (pitch);
392   Pitch *r = unsmob_pitch (root);
393   SCM_ASSERT_TYPE (p, pitch, SCM_ARG1, __FUNCTION__, "Pitch");
394   SCM_ASSERT_TYPE (r, root, SCM_ARG2, __FUNCTION__, "Pitch");
395
396   return interval (*r, *p).smobbed_copy ();
397 }
398
399
400 int
401 Pitch::get_octave ()const
402 {
403   return octave_;
404 }
405
406 int
407 Pitch::get_notename () const
408 {
409   return notename_;
410 }
411
412 int
413 Pitch::get_alteration () const
414 {
415   return alteration_;
416 }
417
418 Pitch
419 Pitch::transposed (Pitch d) const
420 {
421   Pitch p = *this;
422   p.transpose (d);
423   return p;
424 }