"""
Metric modulation.
"""
import abjad
import quicktions
[docs]def mixed_number(fraction_pair=(288, 5)):
fraction_pair = quicktions.Fraction(fraction_pair)
q = fraction_pair.numerator // fraction_pair.denominator
r = quicktions.Fraction(
(fraction_pair.numerator % fraction_pair.denominator)
/ fraction_pair.denominator
).limit_denominator()
return (q, (r.numerator, r.denominator))
[docs]def compare_speed(l_note=None, r_note=None):
left_dur = abjad.get.duration(l_note)
right_dur = abjad.get.duration(r_note)
multiplier = left_dur / right_dur
return multiplier
[docs]def calculate_metric_modulation(l_tempo=60, l_note=None, r_note=None):
left_dur = abjad.get.duration(l_note)
right_dur = abjad.get.duration(r_note)
multiplier = right_dur / left_dur
new_tempo = l_tempo * multiplier
return new_tempo
[docs]def metric_modulation(
metronome_mark=((1, 4), 60),
left_note=(abjad.Note("c'8")),
right_note=(abjad.Note("c'8.")),
modulated_beat=(abjad.Note("c'4")),
):
r"""
Makes metric modulation markup.
.. container:: example
>>> m = evans.metric_modulation(
... metronome_mark=((1, 4), 96),
... left_note=(abjad.Tuplet(multiplier=(5, 3), components=[abjad.Note()])),
... right_note=(abjad.Note("c'4")),
... modulated_beat=(abjad.Note("c'4")),
... )
...
>>> staff = abjad.Staff("c'1")
>>> abjad.attach(m, staff[0])
>>> score = abjad.Score([staff])
>>> moment = "#(ly:make-moment 1 25)"
>>> abjad.setting(score).proportional_notation_duration = moment
>>> file = abjad.LilyPondFile(
... items=[score],
... includes=[
... "/Users/evansdsg2/abjad/docs/source/_stylesheets/abjad.ily"
... ],
... global_staff_size=16,
... )
>>> abjad.show(file) # doctest: +SKIP
.. docs::
>>> print(abjad.lilypond(staff))
\new Staff
{
c'1
^ \markup {
\huge
\concat {
\abjad-metronome-mark-mixed-number-markup #2 #0 #1 #"57" #"3" #"5"
\hspace #1
\upright [
\abjad-metric-modulation-tuplet-lhs #2 #0 #5 #3 #2 #0 #'(0.6 . 0.6)
\hspace #0.5
\upright ]
}
}
}
.. container:: example
>>> m = evans.metric_modulation(
... metronome_mark=((1, 4), 96),
... left_note=(abjad.Note("c'4.")),
... right_note=(abjad.Note("c'4")),
... modulated_beat=(abjad.Note("c'4")),
... )
...
>>> staff = abjad.Staff("c'1")
>>> abjad.attach(m, staff[0])
>>> score = abjad.Score([staff])
>>> moment = "#(ly:make-moment 1 25)"
>>> abjad.setting(score).proportional_notation_duration = moment
>>> file = abjad.LilyPondFile(
... items=[score],
... includes=[
... "/Users/evansdsg2/abjad/docs/source/_stylesheets/abjad.ily"
... ],
... global_staff_size=16,
... )
>>> abjad.show(file) # doctest: +SKIP
.. docs::
>>> print(abjad.lilypond(staff))
\new Staff
{
c'1
^ \markup {
\huge
\concat {
\abjad-metronome-mark-markup #2 #0 #1 #"64"
\hspace #1
\upright [
\abjad-metric-modulation #2 #1 #2 #0 #'(0.6 . 0.6)
\hspace #0.5
\upright ]
}
}
}
.. container:: example
>>> m = evans.metric_modulation(
... metronome_mark=((1, 4), 71),
... left_note=(abjad.Tuplet(multiplier=(10, 9), components=[abjad.Note("c'16")])),
... right_note=(abjad.Note("c'16")),
... modulated_beat=(abjad.Note("c'4")),
... )
...
>>> staff = abjad.Staff("c'1")
>>> abjad.attach(m, staff[0])
>>> score = abjad.Score([staff])
>>> moment = "#(ly:make-moment 1 25)"
>>> abjad.setting(score).proportional_notation_duration = moment
>>> file = abjad.LilyPondFile(
... items=[score],
... includes=[
... "/Users/evansdsg2/abjad/docs/source/_stylesheets/abjad.ily"
... ],
... global_staff_size=16,
... )
>>> abjad.show(file) # doctest: +SKIP
.. docs::
>>> print(abjad.lilypond(staff))
\new Staff
{
c'1
^ \markup {
\huge
\concat {
\abjad-metronome-mark-mixed-number-markup #2 #0 #1 #"63" #"9" #"10"
\hspace #1
\upright [
\abjad-metric-modulation-tuplet-lhs #4 #0 #10 #9 #4 #0 #'(0.6 . 0.6)
\hspace #0.5
\upright ]
}
}
}
.. container:: example
>>> m = evans.metric_modulation(
... metronome_mark=((1, 4), 40),
... left_note=(abjad.Tuplet(multiplier=(2, 3), components=[abjad.Note("c'2")])),
... right_note=(abjad.Note("c'2")),
... modulated_beat=(abjad.Note("c'4")),
... )
...
>>> staff = abjad.Staff("c'1")
>>> abjad.attach(m, staff[0])
>>> score = abjad.Score([staff])
>>> moment = "#(ly:make-moment 1 25)"
>>> abjad.setting(score).proportional_notation_duration = moment
>>> file = abjad.LilyPondFile(
... items=[score],
... includes=[
... "/Users/evansdsg2/abjad/docs/source/_stylesheets/abjad.ily"
... ],
... global_staff_size=16,
... )
>>> abjad.show(file) # doctest: +SKIP
.. docs::
>>> print(abjad.lilypond(staff))
\new Staff
{
c'1
^ \markup {
\huge
\concat {
\abjad-metronome-mark-markup #2 #0 #1 #"60"
\hspace #1
\upright [
\abjad-metric-modulation-tuplet-lhs #1 #0 #2 #3 #1 #0 #'(0.6 . 0.6)
\hspace #0.5
\upright ]
}
}
}
"""
tempo_note = abjad.Note()
tempo_note.written_duration = metronome_mark[0]
left_speed_multiplier = compare_speed(l_note=tempo_note, r_note=left_note)
left_speed = metronome_mark[1] * left_speed_multiplier
modulation_speed = calculate_metric_modulation(
l_tempo=left_speed, l_note=left_note, r_note=right_note
)
returned_speed = float(modulation_speed * compare_speed(left_note, modulated_beat))
if returned_speed % 1 == 0.0:
met = abjad.MetronomeMark.make_tempo_equation_markup(
abjad.get.duration(modulated_beat), int(returned_speed)
)
mod = abjad.MetricModulation(
left_rhythm=left_note, right_rhythm=right_note, scale=(0.6, 0.6)
)
mark = abjad.LilyPondLiteral(
[
r"^ \markup {",
r" \huge",
r" \concat {",
f" {str(met)[8:]}",
r" \hspace #1",
r" \upright [",
f" {str(mod)[8:]}",
r" \hspace #0.5",
r" \upright ]",
r" }",
r"}",
],
format_slot="after",
)
return mark
else:
met = abjad.MetronomeMark.make_tempo_equation_markup(
abjad.get.duration(modulated_beat),
quicktions.Fraction(returned_speed).limit_denominator(),
)
mod = abjad.MetricModulation(
left_rhythm=left_note, right_rhythm=right_note, scale=(0.6, 0.6)
)
mark = abjad.LilyPondLiteral(
[
r"^ \markup {",
r" \huge",
r" \concat {",
f" {str(met)[8:]}",
r" \hspace #1",
r" \upright [",
f" {str(mod)[8:]}",
r" \hspace #0.5",
r" \upright ]",
r" }",
r"}",
],
format_slot="after",
)
return mark
[docs]def calculate_tempo_modulated_duration(
original_tempo=((1, 4), 60),
new_tempo=((1, 4), 120),
duration=abjad.Duration((1, 1)),
):
"""
.. container:: example
>>> evans.calculate_tempo_modulated_duration(
... original_tempo=((1, 4), 60),
... new_tempo=((1, 4), 120),
... duration=abjad.Duration((1, 1)),
... )
...
Duration(2, 1)
.. container:: example
>>> evans.calculate_tempo_modulated_duration(
... original_tempo=((1, 4), 72),
... new_tempo=((1, 4), 83),
... duration=abjad.Duration((23, 8)),
... )
...
Duration(1909, 576)
"""
def convert_to_quarter(tempo):
notehead_string = f"{tempo[0][0]}/{tempo[0][1]}"
beat_change = quicktions.Fraction("1/4") / quicktions.Fraction(notehead_string)
new_speed = tempo[1] * beat_change
return ((1, 4), new_speed)
original_tempo = convert_to_quarter(original_tempo)
new_tempo = convert_to_quarter(new_tempo)
multiplier = original_tempo[1] / new_tempo[1]
timed_duration = duration / multiplier
return timed_duration