2 musical-pitch.cc -- implement Pitch
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
12 #include "ly-smobs.icc"
15 Pitch::Pitch (int o
, int n
, int a
)
31 Pitch::compare (Pitch
const &m1
, Pitch
const &m2
)
33 int o
= m1
.octave_
- m2
.octave_
;
34 int n
= m1
.notename_
- m2
.notename_
;
35 int a
= m1
.alteration_
- m2
.alteration_
;
49 return notename_
+ octave_
*7;
52 /* Should be settable from input? */
53 static Byte diatonic_scale_semitones
[ ] = { 0, 2, 4, 5, 7, 9, 11 };
56 /* Calculate pitch height in 12th octave steps. Don't assume
57 normalised pitch as this function is used to normalise the pitch. */
59 Pitch::semitone_pitch () const
70 programming_error ("semitone_pitch () called on quarter tone alteration.");
72 return ((o
+ n
/ 7) * 12
73 + diatonic_scale_semitones
[n
% 7]
78 Pitch::quartertone_pitch () const
88 return ((o
+ n
/ 7) * 24
89 + 2 * diatonic_scale_semitones
[n
% 7]
96 int pitch
= quartertone_pitch ();
97 while (notename_
>= 7)
101 alteration_
-= quartertone_pitch () - pitch
;
103 while (notename_
< 0)
107 alteration_
-= quartertone_pitch () - pitch
;
109 while (alteration_
> DOUBLE_SHARP
)
120 alteration_
-= quartertone_pitch () - pitch
;
123 while (alteration_
< DOUBLE_FLAT
)
134 alteration_
-= quartertone_pitch () - pitch
;
138 /* WHugh, wat een intervaas */
140 Pitch::transpose (Pitch delta
)
142 int new_semi
= quartertone_pitch () +delta
.quartertone_pitch ();
143 octave_
+= delta
.octave_
;
144 notename_
+= delta
.notename_
;
145 alteration_
+= new_semi
- quartertone_pitch ();
151 interval (Pitch
const & from
, Pitch
const & to
)
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 (),
157 to
.get_alteration () - from
.get_alteration ());
159 return pt
.transposed (Pitch (0,0,sound
- pt
.quartertone_pitch ()));
164 Merge with *pitch->text* funcs in chord-name.scm */
165 char const *accname
[] = {"eses", "eseh", "es", "eh", "",
166 "ih", "is" , "isih", "isis"};
169 Pitch::to_string () const
171 int n
= (notename_
+ 2) % 7;
172 String s
= ::to_string (char (n
+ 'a'));
174 s
+= String (accname
[alteration_
- DOUBLE_FLAT
]);
182 else if (octave_
< 0)
184 int o
= (-octave_
) - 1;
186 s
+= ::to_string (',');
192 /* Change me to relative, counting from last pitch p
193 return copy of resulting pitch. */
195 Pitch::to_relative_octave (Pitch p
) const
197 /* account for c' = octave 1 iso. 0 4 */
198 int oct_mod
= octave_
+ 1;
200 Pitch
down_pitch (p
);
202 up_pitch
.alteration_
= alteration_
;
203 down_pitch
.alteration_
= alteration_
;
206 up_pitch
.up_to (notename_
);
207 down_pitch
.down_to (notename_
);
210 if (abs (up_pitch
.steps () - h
) < abs (down_pitch
.steps () - h
))
215 n
.octave_
+= oct_mod
;
220 Pitch::up_to (int notename
)
222 if (notename_
> notename
)
224 notename_
= notename
;
228 Pitch::down_to (int notename
)
230 if (notename_
< notename
)
232 notename_
= notename
;
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.")
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 ();
247 IMPLEMENT_TYPE_P (Pitch
, "ly:pitch?");
250 Pitch::mark_smob (SCM
)
255 IMPLEMENT_SIMPLE_SMOBS (Pitch
);
257 Pitch::print_smob (SCM s
, SCM port
, scm_print_state
*)
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
);
267 Pitch::equal_p (SCM a
, SCM b
)
269 Pitch
*p
= (Pitch
*) ly_cdr (a
);
270 Pitch
*q
= (Pitch
*) ly_cdr (b
);
272 bool eq
= p
->notename_
== q
->notename_
273 && p
->octave_
== q
->octave_
274 && p
->alteration_
== q
->alteration_
;
276 return eq
? SCM_BOOL_T
: SCM_BOOL_F
;
279 MAKE_SCHEME_CALLBACK (Pitch
, less_p
, 2);
281 Pitch::less_p (SCM p1
, SCM p2
)
283 Pitch
*a
= unsmob_pitch (p1
);
284 Pitch
*b
= unsmob_pitch (p2
);
286 if (compare (*a
, *b
) < 0)
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. ")
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");
306 Pitch
p (gh_scm2int (octave
), gh_scm2int (note
), gh_scm2int (alter
));
307 return p
.smobbed_copy ();
310 LY_DEFINE (pitch_steps
, "ly:pitch-steps", 1, 0, 0,
312 "Number of steps counted from middle C of the pitch @var{p}.")
314 Pitch
*pp
= unsmob_pitch (p
);
315 SCM_ASSERT_TYPE (pp
, p
, SCM_ARG1
, __FUNCTION__
, "Pitch");
316 return gh_int2scm (pp
->steps ());
319 LY_DEFINE (pitch_octave
, "ly:pitch-octave",
321 "Extract the octave from pitch @var{p}.")
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
);
329 LY_DEFINE (pitch_alteration
, "ly:pitch-alteration",
331 "Extract the alteration from pitch @var{p}.")
333 Pitch
*p
= unsmob_pitch (pp
);
334 SCM_ASSERT_TYPE (p
, pp
, SCM_ARG1
, __FUNCTION__
, "Pitch");
335 int q
= p
->get_alteration ();
337 return gh_int2scm (q
);
340 LY_DEFINE (pitch_notename
, "ly:pitch-notename",
342 "Extract the note name from pitch @var{pp}.")
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
);
350 LY_DEFINE (ly_pitch_quartertones
, "ly:pitch-quartertones",
352 "Calculate the number of quarter tones of @var{p} from middle C.")
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
);
360 LY_DEFINE (ly_pitch_semitones
, "ly:pitch-semitones",
362 "calculate the number of semitones of @var{p} from middle C.")
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
);
370 LY_DEFINE (pitch_less
, "ly:pitch<?",
371 2, 0, 0, (SCM p1
, SCM p2
),
372 "Is @var{p1} lexicographically smaller than @var{p2}?")
374 Pitch
*a
= unsmob_pitch (p1
);
375 Pitch
*b
= unsmob_pitch (p2
);
377 SCM_ASSERT_TYPE (a
, p1
, SCM_ARG1
, __FUNCTION__
, "Pitch");
378 SCM_ASSERT_TYPE (b
, p2
, SCM_ARG2
, __FUNCTION__
, "Pitch");
380 if (Pitch::compare (*a
, *b
) < 0)
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}" )
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");
396 return interval (*r
, *p
).smobbed_copy ();
401 Pitch::get_octave ()const
407 Pitch::get_notename () const
413 Pitch::get_alteration () const
419 Pitch::transposed (Pitch d
) const