+LY_DEFINE (ly_make_music_relative_x, "ly:make-music-relative!",
+ 2, 0, 0, (SCM music, SCM pitch),
+ "Make @var{music} relative to @var{pitch},"
+ " return final pitch.")
+{
+ LY_ASSERT_TYPE (unsmob_music, music, 1);
+ LY_ASSERT_TYPE (unsmob_pitch, pitch, 2);
+
+ Pitch start = *unsmob_pitch (pitch);
+ Music *m = unsmob_music (music);
+ Pitch last = m->to_relative_octave (start);
+
+ return last.smobbed_copy ();
+}
+
+LY_DEFINE (ly_music_duration_length, "ly:music-duration-length", 1, 0, 0,
+ (SCM mus),
+ "Extract the duration field from @var{mus} and return the"
+ " length.")
+{
+ LY_ASSERT_TYPE (unsmob_music, mus, 1);
+ Music *m = unsmob_music (mus);
+
+ Duration *d = unsmob_duration (m->get_property ("duration"));
+ Moment len;
+
+ if (d)
+ len = d->get_length ();
+ else
+ programming_error ("music has no duration");
+ return len.smobbed_copy ();
+}
+
+LY_DEFINE (ly_music_duration_compress, "ly:music-duration-compress", 2, 0, 0,
+ (SCM mus, SCM fact),
+ "Compress @var{mus} by factor @var{fact}, which is a"
+ " @code{Moment}.")
+{
+ LY_ASSERT_TYPE (unsmob_music, mus, 1);
+ LY_ASSERT_SMOB (Moment, fact, 2);
+
+ Music *m = unsmob_music (mus);
+ Moment *f = unsmob_moment (fact);
+
+ Duration *d = unsmob_duration (m->get_property ("duration"));
+ if (d)
+ m->set_property ("duration", d->compressed (f->main_part_).smobbed_copy ());
+ return SCM_UNSPECIFIED;
+}
+
+/*
+ This is hairy, since the scale in a key-change event may contain
+ octaveless notes.
+
+
+ TODO: this should use ly:pitch.
+*/
+LY_DEFINE (ly_transpose_key_alist, "ly:transpose-key-alist",
+ 2, 0, 0, (SCM l, SCM pit),
+ "Make a new key alist of@tie{}@var{l} transposed by"
+ " pitch @var{pit}.")
+{
+ SCM newlist = SCM_EOL;
+ Pitch *p = unsmob_pitch (pit);
+
+ for (SCM s = l; scm_is_pair (s); s = scm_cdr (s))
+ {
+ SCM key = scm_caar (s);
+ SCM alter = scm_cdar (s);
+ if (scm_is_pair (key))
+ {
+ Pitch orig (scm_to_int (scm_car (key)),
+ scm_to_int (scm_cdr (key)),
+ ly_scm2rational (alter));
+
+ orig = orig.transposed (*p);
+
+ SCM key = scm_cons (scm_from_int (orig.get_octave ()),
+ scm_from_int (orig.get_notename ()));
+
+ newlist = scm_cons (scm_cons (key, ly_rational2scm (orig.get_alteration ())),
+ newlist);
+ }
+ else if (scm_is_number (key))
+ {
+ Pitch orig (0, scm_to_int (key), ly_scm2rational (alter));
+ orig = orig.transposed (*p);
+
+ key = scm_from_int (orig.get_notename ());
+ alter = ly_rational2scm (orig.get_alteration ());
+ newlist = scm_cons (scm_cons (key, alter), newlist);
+ }
+ }
+ return scm_reverse_x (newlist, SCM_EOL);
+}
+