]> git.donarmstrong.com Git - lilypond.git/blob - lily/pitch.cc
*** empty log message ***
[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
11 #include "warn.hh"
12 #include "main.hh"
13
14 #include "ly-smobs.icc"
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 /* FIXME: why is octave == 0 and default not middleC ? */
25 Pitch::Pitch ()
26 {
27   notename_ = 0;
28   alteration_ = 0;
29   octave_ = 0;
30 }
31
32 int
33 Pitch::compare (Pitch const &m1, Pitch const &m2)
34 {
35   int o =  m1.octave_ - m2.octave_;
36   int n = m1.notename_ - m2.notename_;
37   int a = m1.alteration_ - m2.alteration_;
38
39   if (o)
40     return o;
41   if (n)
42     return n;
43   if (a)
44     return a;
45   return 0;
46 }
47
48 int
49 Pitch::steps () const
50 {
51   return  notename_ + octave_*7;
52 }
53
54 /* Should be settable from input?  */
55 static Byte diatonic_scale_semitones[  ] = { 0, 2, 4, 5, 7, 9, 11 };
56
57
58 /* Calculate pitch height in 12th octave steps.  Don't assume
59    normalised pitch as this function is used to normalise the pitch.  */
60 int
61 Pitch::semitone_pitch () const
62 {
63   int o = octave_;
64   int n = notename_;
65   while (n < 0)
66     {
67       n += 7;
68       o --;
69     }
70
71   if (alteration_ % 2)
72     programming_error ("semitone_pitch () called on quarter tone alteration.");
73
74   return ((o + n / 7) * 12
75           + diatonic_scale_semitones[n % 7]
76           + (alteration_ / 2));
77 }
78
79 int
80 Pitch::quartertone_pitch () const
81 {
82   int o = octave_;
83   int n = notename_;
84   while (n < 0)
85     {
86       n += 7;
87       o --;
88     }
89
90   return ((o + n / 7) * 24
91           + 2 * diatonic_scale_semitones[n % 7]
92           + 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 pitch_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 char const *accname[] = {"eses", "eseh", "es", "eh", "",
168                          "ih", "is" , "isih",  "isis"};
169
170 String
171 Pitch::to_string () const
172 {
173   int n = (notename_ + 2) % 7;
174   String s = ::to_string (char (n + 'a'));
175   if (alteration_)
176     s += String (accname[alteration_ - DOUBLE_FLAT]);
177
178   if (octave_ >= 0)
179     {
180       int o = octave_ + 1;
181       while (o--)
182         s += "'";
183     }
184   else if (octave_ < 0)
185     {
186       int o = (-octave_) - 1;
187       while (o--)
188         s += ::to_string (',');
189     }
190
191   return s;
192 }
193
194 /* Change me to relative, counting from last pitch p
195    return copy of resulting pitch.  */
196 Pitch
197 Pitch::to_relative_octave (Pitch p) const
198 {
199   /* account for c' = octave 1 iso. 0 4 */
200   int oct_mod = octave_  + 1;
201   Pitch up_pitch (p);
202   Pitch down_pitch (p);
203
204   up_pitch.alteration_ = alteration_;
205   down_pitch.alteration_ = alteration_;
206
207   Pitch n = *this;
208   up_pitch.up_to (notename_);
209   down_pitch.down_to (notename_);
210
211   int h = p.steps ();
212   if (abs (up_pitch.steps () - h) < abs (down_pitch.steps () - h))
213     n = up_pitch;
214   else
215     n = down_pitch;
216
217   n.octave_ += oct_mod;
218   return n;
219 }
220
221 void
222 Pitch::up_to (int notename)
223 {
224   if (notename_ > notename)
225     octave_++;
226   notename_  = notename;
227 }
228
229 void
230 Pitch::down_to (int notename)
231 {
232   if (notename_ < notename)
233     octave_--;
234   notename_ = notename;
235 }
236
237 LY_DEFINE (ly_pitch_transpose, "ly:pitch-transpose",
238            2, 0, 0, (SCM p, SCM delta),
239            "Transpose @var{p} by the amount @var{delta}, "
240            "where @var{delta} is relative to middle C.")
241 {
242   Pitch* t = unsmob_pitch (p);
243   Pitch *d = unsmob_pitch (delta);
244   SCM_ASSERT_TYPE (t, p, SCM_ARG1, __FUNCTION__, "pitch");
245   SCM_ASSERT_TYPE (d, delta, SCM_ARG1, __FUNCTION__, "pitch");
246   return t->transposed (*d).smobbed_copy ();
247 }
248
249 IMPLEMENT_TYPE_P (Pitch, "ly:pitch?");
250
251 SCM
252 Pitch::mark_smob (SCM)
253 {
254   return SCM_EOL;
255 }
256
257 IMPLEMENT_SIMPLE_SMOBS (Pitch);
258 int
259 Pitch::print_smob (SCM s, SCM port, scm_print_state *)
260 {
261   Pitch *r = (Pitch *) SCM_CELL_WORD_1 (s);
262   scm_puts ("#<Pitch ", port);
263   scm_display (scm_makfrom0str (r->to_string ().to_str0 ()), port);
264   scm_puts (" >", port);
265   return 1;
266 }
267
268 SCM
269 Pitch::equal_p (SCM a , SCM b)
270 {
271   Pitch *p = (Pitch *) SCM_CELL_WORD_1 (a);
272   Pitch *q = (Pitch *) SCM_CELL_WORD_1 (b);
273
274   bool eq = p->notename_ == q->notename_
275     && p->octave_ == q->octave_
276     && p->alteration_ == q->alteration_;
277
278   return eq ? SCM_BOOL_T : SCM_BOOL_F;
279 }
280
281 MAKE_SCHEME_CALLBACK (Pitch, less_p, 2);
282 SCM
283 Pitch::less_p (SCM p1, SCM p2)
284 {
285   Pitch *a = unsmob_pitch (p1);
286   Pitch *b = unsmob_pitch (p2);
287
288   if (compare (*a, *b) < 0)
289     return SCM_BOOL_T;
290   else
291     return SCM_BOOL_F;
292 }
293
294 /* Should add optional args.  */
295 LY_DEFINE (ly_make_pitch, "ly:make-pitch",
296            3, 0, 0, (SCM octave, SCM note, SCM alter),
297            "@var{octave} is specified by an integer, "
298            "zero for the octave containing middle C.  "
299            "@var{note} is a number from 0 to 6, "
300            "with 0 corresponding to C and 6 corresponding to B.  "
301            "The @var{alter} is zero for a natural, negative for "
302            "flats, or positive for sharps. ")
303 {
304   SCM_ASSERT_TYPE (scm_integer_p (octave)== SCM_BOOL_T , octave, SCM_ARG1, __FUNCTION__, "integer");
305   SCM_ASSERT_TYPE (scm_integer_p (note)== SCM_BOOL_T, note, SCM_ARG2, __FUNCTION__, "integer");
306   SCM_ASSERT_TYPE (scm_integer_p (alter)== SCM_BOOL_T, alter, SCM_ARG3, __FUNCTION__, "integer");
307
308   Pitch p (scm_to_int (octave), scm_to_int (note), scm_to_int (alter));
309   return p.smobbed_copy ();
310 }
311
312 LY_DEFINE (ly_pitch_steps, "ly:pitch-steps", 1, 0, 0,
313            (SCM p),
314            "Number of steps counted from middle C of the pitch @var{p}.")
315 {
316   Pitch *pp = unsmob_pitch (p);
317   SCM_ASSERT_TYPE (pp, p, SCM_ARG1, __FUNCTION__, "Pitch");
318   return scm_int2num (pp->steps ());
319 }
320
321 LY_DEFINE (ly_pitch_octave, "ly:pitch-octave",
322            1, 0, 0, (SCM pp),
323            "Extract the octave from pitch @var{p}.")
324 {
325   Pitch *p = unsmob_pitch (pp);
326   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
327   int q = p->get_octave ();
328   return scm_int2num (q);
329 }
330
331 LY_DEFINE (ly_pitch_alteration, "ly:pitch-alteration",
332            1, 0, 0, (SCM pp),
333            "Extract the alteration from pitch  @var{p}.")
334 {
335   Pitch *p = unsmob_pitch (pp);
336   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
337   int q = p->get_alteration ();
338
339   return scm_int2num (q);
340 }
341
342 LY_DEFINE (pitch_notename, "ly:pitch-notename",
343            1, 0, 0, (SCM pp),
344            "Extract the note name from pitch  @var{pp}.")
345 {
346   Pitch *p = unsmob_pitch (pp);
347   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
348   int q = p->get_notename ();
349   return scm_int2num (q);
350 }
351
352 LY_DEFINE (ly_pitch_quartertones, "ly:pitch-quartertones",
353            1, 0, 0, (SCM pp),
354            "Calculate the number of quarter tones of @var{p} from middle C.")
355 {
356   Pitch *p = unsmob_pitch (pp);
357   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
358   int q = p->quartertone_pitch ();
359   return scm_int2num (q);
360 }
361
362 LY_DEFINE (ly_pitch_semitones, "ly:pitch-semitones",
363            1, 0, 0, (SCM pp),
364            "calculate the number of semitones of @var{p} from middle C.")
365 {
366   Pitch *p = unsmob_pitch (pp);
367   SCM_ASSERT_TYPE (p, pp, SCM_ARG1, __FUNCTION__, "Pitch");
368   int q = p->semitone_pitch ();
369   return scm_int2num (q);
370 }
371
372 LY_DEFINE (ly_pitch_less_p, "ly:pitch<?",
373            2, 0, 0, (SCM p1, SCM p2),
374            "Is @var{p1} lexicographically smaller than @var{p2}?")
375 {
376   Pitch *a = unsmob_pitch (p1);
377   Pitch *b = unsmob_pitch (p2);
378
379   SCM_ASSERT_TYPE (a, p1, SCM_ARG1, __FUNCTION__, "Pitch");
380   SCM_ASSERT_TYPE (b, p2, SCM_ARG2, __FUNCTION__, "Pitch");
381
382   if (Pitch::compare (*a, *b) < 0)
383     return SCM_BOOL_T;
384   else
385     return SCM_BOOL_F;
386 }
387
388 LY_DEFINE (ly_pitch_diff, "ly:pitch-diff",
389            2 ,0, 0, (SCM pitch, SCM  root),
390            "Return pitch @var{delta} such that @code{pitch} transposed by "
391            "@var{delta} equals @var{root}" )
392 {
393   Pitch *p = unsmob_pitch (pitch);
394   Pitch *r = unsmob_pitch (root);
395   SCM_ASSERT_TYPE (p, pitch, SCM_ARG1, __FUNCTION__, "Pitch");
396   SCM_ASSERT_TYPE (r, root, SCM_ARG2, __FUNCTION__, "Pitch");
397
398   return pitch_interval (*r, *p).smobbed_copy ();
399 }
400
401 int
402 Pitch::get_octave () const
403 {
404   return octave_;
405 }
406
407 int
408 Pitch::get_notename () const
409 {
410   return notename_;
411 }
412
413 int
414 Pitch::get_alteration () const
415 {
416   return alteration_;
417 }
418
419 Pitch
420 Pitch::transposed (Pitch d) const
421 {
422   Pitch p = *this;
423   p.transpose (d);
424   return p;
425 }