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