import math
from . import duration as _duration
from . import iterate as _iterate
from . import math as _math
from . import overrides as _overrides
from . import pitch as _pitch
from . import score as _score
from . import sequence as _sequence
from . import spanners as _spanners
from . import tag as _tag
from . import tweaks as _tweaks
def _group_by_implied_prolation(pairs):
assert all(isinstance(_, tuple) for _ in pairs), repr(pairs)
assert 0 < len(pairs)
pair_list = [pairs[0]]
pair_lists = [pair_list]
for pair in pairs[1:]:
pair_denominator_factors = set(_math.factors(pair[1]))
pair_denominator_factors.discard(2)
group_zero_denominator_factors = set(_math.factors(pair_list[0][1]))
group_zero_denominator_factors.discard(2)
if pair_denominator_factors == group_zero_denominator_factors:
pair_list.append(pair)
else:
pair_list = [pair]
pair_lists.append(pair_list)
return pair_lists
def _make_leaf_on_pitch(
pitch_list,
duration,
*,
increase_monotonic=False,
forbidden_note_duration=None,
forbidden_rest_duration=None,
skips_instead_of_rests=False,
tag=None,
use_multimeasure_rests=False,
):
assert isinstance(pitch_list, list), repr(pitch_list)
assert all(isinstance(_, _pitch.NamedPitch) for _ in pitch_list), repr(pitch_list)
assert isinstance(duration, _duration.Duration), repr(duration)
if pitch_list == []:
if skips_instead_of_rests is True:
leaves = _make_tied_leaf(
_score.Skip,
duration,
increase_monotonic=increase_monotonic,
forbidden_duration=forbidden_rest_duration,
pitches=None,
tag=tag,
)
elif use_multimeasure_rests is True:
multimeasure_rest = _score.MultimeasureRest((1), tag=tag)
multimeasure_rest.multiplier = duration.pair
leaves = [multimeasure_rest]
else:
leaves = _make_tied_leaf(
_score.Rest,
duration,
increase_monotonic=increase_monotonic,
forbidden_duration=forbidden_rest_duration,
pitches=None,
tag=tag,
)
elif len(pitch_list) == 1:
pitch = pitch_list[0]
leaves = _make_tied_leaf(
_score.Note,
duration,
increase_monotonic=increase_monotonic,
forbidden_duration=forbidden_note_duration,
pitches=pitch,
tag=tag,
)
else:
leaves = _make_tied_leaf(
_score.Chord,
duration,
increase_monotonic=increase_monotonic,
forbidden_duration=forbidden_note_duration,
pitches=pitch_list,
tag=tag,
)
assert isinstance(leaves, list), repr(leaves)
assert all(isinstance(_, _score.Leaf) for _ in leaves), repr(leaves)
return leaves
def _make_tied_leaf(
class_,
duration,
increase_monotonic=False,
forbidden_duration=None,
multiplier=None,
pitches=None,
tag=None,
):
assert isinstance(duration, _duration.Duration), repr(duration)
if multiplier is not None:
assert isinstance(multiplier, tuple), repr(multiplier)
duration_pair = duration.pair
if forbidden_duration is not None:
assert forbidden_duration.is_assignable
assert forbidden_duration.numerator == 1
if forbidden_duration is not None and forbidden_duration <= duration:
denominators = [2 * forbidden_duration.denominator, duration.denominator]
denominator = _math.least_common_multiple(*denominators)
forbidden_pair = _duration.with_denominator(forbidden_duration, denominator)
forbidden_numerator = forbidden_pair[0]
assert forbidden_numerator % 2 == 0
preferred_numerator = forbidden_numerator / 2
duration_pair = _duration.with_denominator(duration_pair, denominator)
parts = _math.partition_integer_into_canonic_parts(duration_pair[0])
if forbidden_duration is not None and forbidden_duration <= duration:
numerators = []
for part in parts:
if forbidden_numerator <= part:
better_parts = _partition_less_than_double(part, preferred_numerator)
numerators.extend(better_parts)
else:
numerators.append(part)
else:
numerators = parts
if increase_monotonic:
numerators = list(reversed(numerators))
leaves = []
for numerator in numerators:
written_duration = _duration.Duration(numerator, duration_pair[1])
if pitches is not None:
arguments = (pitches, written_duration)
else:
arguments = (written_duration,)
leaf = class_(*arguments, multiplier=multiplier, tag=tag)
leaves.append(leaf)
if 1 < len(leaves):
if not issubclass(class_, _score.Rest | _score.Skip):
_spanners.tie(leaves)
assert isinstance(leaves, list), repr(leaves)
assert all(isinstance(_, _score.Leaf) for _ in leaves), repr(leaves)
return leaves
def _make_unprolated_notes(pitches, durations, *, increase_monotonic=None, tag=None):
assert all(isinstance(_, _duration.Duration) for _ in durations), repr(durations)
notes = []
for pitch, duration in zip(pitches, durations, strict=True):
notes_ = _make_tied_leaf(
_score.Note,
duration,
pitches=pitch,
increase_monotonic=increase_monotonic,
tag=tag,
)
notes.extend(notes_)
assert all(isinstance(_, _score.Note) for _ in notes), repr(notes)
return notes
def _partition_less_than_double(n, m):
assert _math.is_positive_integer_equivalent_number(n)
assert _math.is_positive_integer_equivalent_number(m)
n, m = int(n), int(m)
result = []
current_value = n
double_m = 2 * m
while double_m <= current_value:
result.append(m)
current_value -= m
result.append(current_value)
return tuple(result)
[docs]
def make_durations(items: list) -> list[_duration.Duration]:
"""
Changes list of arbitrary ``items`` to list of durations.
.. container:: example
>>> abjad.makers.make_durations([(1, 8), (1, 2), (1, 16)])
[Duration(1, 8), Duration(1, 2), Duration(1, 16)]
"""
durations = [_duration.Duration(_) for _ in items]
return durations
[docs]
def make_leaves(
pitch_lists: list[list[_pitch.NamedPitch]],
durations: list[_duration.Duration],
*,
forbidden_note_duration: _duration.Duration | None = None,
forbidden_rest_duration: _duration.Duration | None = None,
increase_monotonic: bool = False,
skips_instead_of_rests: bool = False,
tag: _tag.Tag | None = None,
use_multimeasure_rests: bool = False,
):
r"""
Makes leaves from ``pitch_lists`` and ``durations``.
.. container:: example
Interprets empty pitch lists as rests:
>>> items = [[], [], [], []]
>>> pitch_lists = abjad.makers.make_pitch_lists(items)
>>> leaves = abjad.makers.make_leaves(pitch_lists, [abjad.Duration(1, 4)])
>>> staff = abjad.Staff(leaves)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
r4
r4
r4
r4
}
Interprets length-1 pitch lists as notes:
>>> items = [2, 4, "F#5", "G#5"]
>>> pitch_lists = abjad.makers.make_pitch_lists(items)
>>> leaves = abjad.makers.make_leaves(pitch_lists, [abjad.Duration(1, 4)])
>>> staff = abjad.Staff(leaves)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
d'4
e'4
fs''4
gs''4
}
Interprets pitch lists with length greater than 1 as chords:
>>> items = [[0, 2, 4], ["F#5", "G#5", "A#5"]]
>>> pitch_lists = abjad.makers.make_pitch_lists(items)
>>> leaves = abjad.makers.make_leaves(pitch_lists, [abjad.Duration(1, 4)])
>>> staff = abjad.Staff(leaves)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
<c' d' e'>4
<fs'' gs'' as''>4
}
Interprets mixed types of pitch list like this:
>>> items = [[0, 2, 4], [], "C#5", "D#5"]
>>> pitch_lists = abjad.makers.make_pitch_lists(items)
>>> leaves = abjad.makers.make_leaves(pitch_lists, [abjad.Duration(1, 4)])
>>> staff = abjad.Staff(leaves)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
<c' d' e'>4
r4
cs''4
ds''4
}
.. container:: example
Interprets nondyadic durations as (possibly incomplete) tuplets:
>>> pitch_list = [abjad.NamedPitch("d''")]
>>> durations = [abjad.Duration(1, 3)]
>>> leaves = abjad.makers.make_leaves([pitch_list], durations)
>>> abjad.makers.tweak_tuplet_bracket_edge_height(leaves)
>>> staff = abjad.Staff(leaves)
>>> score = abjad.Score([staff])
>>> abjad.override(score).TupletBracket.bracket_visibility = True
>>> abjad.setting(score).tupletFullLength = True
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(score)
>>> print(string)
\new Score
\with
{
\override TupletBracket.bracket-visibility = ##t
tupletFullLength = ##t
}
<<
\new Staff
{
\tweak edge-height #'(0.7 . 0)
\tuplet 3/2
{
d''2
}
}
>>
>>> pitch_list = [abjad.NamedPitch("d''")]
>>> durations = 2 * [abjad.Duration(1, 3)]
>>> leaves = abjad.makers.make_leaves([pitch_list], durations)
>>> abjad.makers.tweak_tuplet_bracket_edge_height(leaves)
>>> staff = abjad.Staff(leaves)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
\tweak edge-height #'(0.7 . 0)
\tuplet 3/2
{
d''2
d''2
}
}
>>> pitch_list = [abjad.NamedPitch("d''")]
>>> durations = 3 * [abjad.Duration(1, 3)]
>>> leaves = abjad.makers.make_leaves([pitch_list], durations)
>>> staff = abjad.Staff(leaves)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
\tuplet 3/2
{
d''2
d''2
d''2
}
}
>>> pitch_list = [abjad.NamedPitch("d''")]
>>> leaves = abjad.makers.make_leaves([pitch_list], [abjad.Duration(5, 14)])
>>> abjad.makers.tweak_tuplet_bracket_edge_height(leaves)
>>> staff = abjad.Staff(leaves)
>>> time_signature = abjad.TimeSignature((5, 14))
>>> leaf = abjad.get.leaf(staff, 0)
>>> abjad.attach(time_signature, leaf)
>>> score = abjad.Score([staff], name="Score")
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(score)
>>> print(string)
\context Score = "Score"
<<
\new Staff
{
\tweak edge-height #'(0.7 . 0)
\tuplet 14/8
{
#(ly:expect-warning "strange time signature found")
\time 5/14
d''2
~
d''8
}
}
>>
.. container:: example
Reads ``pitch_lists`` cyclically when the length of ``pitch_lists`` is less
than the length of ``durations``:
>>> pitch_lists = abjad.makers.make_pitch_lists([[12, 14], []])
>>> pairs = [(1, 16), (1, 16), (1, 8), (1, 8), (1, 8)]
>>> durations = abjad.makers.make_durations(pairs)
>>> leaves = abjad.makers.make_leaves(pitch_lists, durations)
>>> staff = abjad.Staff(leaves)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
<c'' d''>16
r16
<c'' d''>8
r8
<c'' d''>8
}
Reads ``durations`` cyclically when the length of ``durations`` is less
than the length of ``pitch_lists``:
>>> pitch_lists = abjad.makers.make_pitch_lists([[12, 14], [], 10, 9, 7])
>>> durations = [abjad.Duration(1, 16), abjad.Duration(1, 8)]
>>> leaves = abjad.makers.make_leaves(pitch_lists, durations)
>>> staff = abjad.Staff(leaves)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
<c'' d''>16
r8
bf'16
a'8
g'16
}
.. container:: example
Avoids durations greater than or equal to ``forbidden_note_duration``:
>>> pitch_lists = abjad.makers.make_pitch_lists("f' g'")
>>> durations = [abjad.Duration(5, 8)]
>>> leaves = abjad.makers.make_leaves(pitch_lists, durations)
>>> staff = abjad.Staff(leaves)
>>> score = abjad.Score([staff], name="Score")
>>> time_signature = abjad.TimeSignature((5, 4))
>>> abjad.attach(time_signature, staff[0])
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
\time 5/4
f'2
~
f'8
g'2
~
g'8
}
>>> leaves = abjad.makers.make_leaves(
... pitch_lists,
... durations,
... forbidden_note_duration=abjad.Duration(1, 2),
... )
>>> staff = abjad.Staff(leaves)
>>> score = abjad.Score([staff], name="Score")
>>> time_signature = abjad.TimeSignature((5, 4))
>>> abjad.attach(time_signature, staff[0])
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
\time 5/4
f'4
~
f'4
~
f'8
g'4
~
g'4
~
g'8
}
.. container:: example
Writes tied durations in monotonically decreasing order by default:
>>> pitch_list = [abjad.NamedPitch("ds''")]
>>> durations = [abjad.Duration(13, 16)]
>>> leaves = abjad.makers.make_leaves([pitch_list], durations)
>>> staff = abjad.Staff(leaves)
>>> score = abjad.Score([staff], name="Score")
>>> time_signature = abjad.TimeSignature((13, 16))
>>> abjad.attach(time_signature, staff[0])
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
\time 13/16
ds''2.
~
ds''16
}
Writes tied durations in monotonically increasing order when
``increase_monotonic`` is true:
>>> leaves = abjad.makers.make_leaves(
... [[abjad.NamedPitch("e''")]],
... [abjad.Duration(13, 16)],
... increase_monotonic=True,
... )
>>> staff = abjad.Staff(leaves)
>>> score = abjad.Score([staff], name="Score")
>>> time_signature = abjad.TimeSignature((13, 16))
>>> abjad.attach(time_signature, staff[0])
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
\time 13/16
e''16
~
e''2.
}
.. container:: example
Interprets empty pitch lists as skips when ``skips_instead_of_rests``
is true:
>>> durations = [abjad.Duration(13, 16)]
>>> abjad.makers.make_leaves([[]], durations, skips_instead_of_rests=True)
[Skip('s2.'), Skip('s16')]
.. container:: example
Interprets empty pitch lists as multimeasure rests when
``use_multimeasure_rests`` is true:
>>> durations = [abjad.Duration(3, 8), abjad.Duration(5, 8)]
>>> leaves = abjad.makers.make_leaves(
... [[]],
... durations,
... use_multimeasure_rests=True,
... )
>>> staff = abjad.Staff(leaves)
>>> abjad.attach(abjad.TimeSignature((3, 8)), leaves[0])
>>> abjad.attach(abjad.TimeSignature((5, 8)), leaves[1])
>>> score = abjad.Score([staff], name="Score")
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(score)
>>> print(string)
\context Score = "Score"
<<
\new Staff
{
\time 3/8
R1 * 3/8
\time 5/8
R1 * 5/8
}
>>
"""
assert isinstance(pitch_lists, list), repr(pitch_lists)
for pitch_list in pitch_lists:
assert isinstance(pitch_list, list), repr(pitch_lists)
assert all(isinstance(_, _pitch.NamedPitch) for _ in pitch_list), repr(
pitch_lists
)
assert all(isinstance(_, _duration.Duration) for _ in durations), repr(durations)
if forbidden_note_duration is not None:
assert isinstance(forbidden_note_duration, _duration.Duration)
if forbidden_rest_duration is not None:
assert isinstance(forbidden_rest_duration, _duration.Duration)
maximum_length = max(len(durations), len(pitch_lists))
durations = _sequence.repeat_to_length(durations, maximum_length)
pitch_lists = _sequence.repeat_to_length(pitch_lists, maximum_length)
pairs = [_.pair for _ in durations]
pair_lists = _group_by_implied_prolation(pairs)
result: list[_score.Tuplet | _score.Leaf] = []
for pair_list in pair_lists:
factors_ = _math.factors(pair_list[0][1])
factors = set(factors_)
factors.discard(1)
factors.discard(2)
current_pitch_lists = pitch_lists[0 : len(pair_list)]
pitch_lists = pitch_lists[len(pair_list) :]
if len(factors) == 0:
pair_list = [_duration.Duration(_) for _ in pair_list]
for pitch_list, duration in zip(current_pitch_lists, pair_list):
leaves = _make_leaf_on_pitch(
pitch_list,
duration,
increase_monotonic=increase_monotonic,
forbidden_note_duration=forbidden_note_duration,
forbidden_rest_duration=forbidden_rest_duration,
skips_instead_of_rests=skips_instead_of_rests,
tag=tag,
use_multimeasure_rests=use_multimeasure_rests,
)
result.extend(leaves)
else:
denominator = pair_list[0][1]
numerator = _math.greatest_power_of_two_less_equal(denominator)
multiplier = (numerator, denominator)
ratio = 1 / _duration.Duration(*multiplier)
pair_list = [ratio * _duration.Duration(duration) for duration in pair_list]
tuplet_leaves: list[_score.Leaf] = []
for pitch_list, duration in zip(current_pitch_lists, pair_list):
leaves = _make_leaf_on_pitch(
pitch_list,
duration,
increase_monotonic=increase_monotonic,
skips_instead_of_rests=skips_instead_of_rests,
tag=tag,
use_multimeasure_rests=use_multimeasure_rests,
)
tuplet_leaves.extend(leaves)
tuplet = _score.Tuplet(multiplier, tuplet_leaves)
result.append(tuplet)
return result
[docs]
def make_notes(
pitches: list[_pitch.NamedPitch],
durations: list[_duration.Duration],
*,
increase_monotonic: bool = False,
tag: _tag.Tag | None = None,
) -> list[_score.Note | _score.Tuplet]:
r"""
Makes notes from ``pitches`` and ``durations``.
.. container:: example
Cycles through ``pitches`` when the length of ``pitches`` is less than
the length of ``durations``:
>>> pitches = abjad.makers.make_pitches("c' d'")
>>> pairs = [(1, 16), (1, 16), (1, 8), (1, 8), (1, 8)]
>>> durations = abjad.makers.make_durations(pairs)
>>> notes = abjad.makers.make_notes(pitches, durations)
>>> staff = abjad.Staff(notes)
>>> score = abjad.Score([staff], name="Score")
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
c'16
d'16
c'8
d'8
c'8
}
Cycles through ``durations`` when the length of ``durations`` is less
than the length of ``pitches``:
>>> pitches = abjad.makers.make_pitches("c' d' e' f' g'")
>>> durations = abjad.makers.make_durations([(1, 16), (1, 8)])
>>> notes = abjad.makers.make_notes(pitches, durations)
>>> staff = abjad.Staff(notes)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
c'16
d'8
e'16
f'8
g'16
}
.. container:: example
Interprets nondyadic durations as (possibly incomplete) tuplets:
>>> pitches = abjad.makers.make_pitches([0])
>>> durations = abjad.makers.make_durations([(1, 16), (1, 12), (1, 8)])
>>> components = abjad.makers.make_notes(pitches, durations)
>>> abjad.makers.tweak_tuplet_bracket_edge_height(components)
>>> staff = abjad.Staff(components)
>>> score = abjad.Score([staff])
>>> abjad.override(score).TupletBracket.bracket_visibility = True
>>> abjad.setting(score).proportionalNotationDuration = "#1/24"
>>> abjad.setting(score).tupletFullLength = True
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(score)
>>> print(string)
\new Score
\with
{
\override TupletBracket.bracket-visibility = ##t
proportionalNotationDuration = #1/24
tupletFullLength = ##t
}
<<
\new Staff
{
c'16
\tweak edge-height #'(0.7 . 0)
\tuplet 3/2
{
c'8
}
c'8
}
>>
.. container:: example
Writes tied durations in monotonically decreasing order by default:
>>> pitches = abjad.makers.make_pitches([0])
>>> durations = [abjad.Duration(13, 16)]
>>> notes = abjad.makers.make_notes(pitches, durations)
>>> staff = abjad.Staff(notes)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
c'2.
~
c'16
}
Writes tied durations in monotonically increasing order when
``increase_monotonic`` is true:
>>> pitches = abjad.makers.make_pitches([0])
>>> durations = [abjad.Duration(13, 16)]
>>> notes = abjad.makers.make_notes(pitches, durations, increase_monotonic=True)
>>> staff = abjad.Staff(notes)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
c'16
~
c'2.
}
"""
assert isinstance(pitches, list), repr(pitches)
prototype = _pitch.NamedPitch | _pitch.NumberedPitch
assert all(isinstance(_, prototype) for _ in pitches), repr(pitches)
assert all(isinstance(_, _duration.Duration) for _ in durations), repr(durations)
maximum_length = max(len(pitches), len(durations))
pitches = _sequence.repeat_to_length(pitches, maximum_length)
pairs = [_.pair for _ in durations]
pairs = _sequence.repeat_to_length(pairs, maximum_length)
pair_lists = _group_by_implied_prolation(pairs)
result: list[_score.Note | _score.Tuplet] = []
for pair_list in pair_lists:
factors = set(_math.factors(pair_list[0][1]))
factors.discard(1)
factors.discard(2)
pitches_ = pitches[0 : len(pair_list)]
pitches = pitches[len(pair_list) :]
if len(factors) == 0:
duration_list = [_duration.Duration(_) for _ in pair_list]
notes = _make_unprolated_notes(
pitches_,
duration_list,
increase_monotonic=increase_monotonic,
tag=tag,
)
result.extend(notes)
else:
denominator = pair_list[0][1]
numerator = _math.greatest_power_of_two_less_equal(denominator)
duration = _duration.Duration(numerator, denominator)
duration_list = [_duration.Duration(_) for _ in pair_list]
duration_list = [duration.reciprocal * _ for _ in duration_list]
notes = _make_unprolated_notes(
pitches_,
duration_list,
increase_monotonic=increase_monotonic,
tag=tag,
)
tuplet = _score.Tuplet(duration.pair, notes)
result.append(tuplet)
assert isinstance(result, list), repr(list)
assert all(isinstance(_, _score.Note | _score.Tuplet) for _ in result), repr(result)
return result
[docs]
def make_pitch_lists(argument: list | str) -> list[list[_pitch.NamedPitch]]:
"""
Changes list or string ``argument`` to list of pitch lists.
.. container:: example
>>> abjad.makers.make_pitch_lists([3, None, [4, 5]])
[[NamedPitch("ef'")], [], [NamedPitch("e'"), NamedPitch("f'")]]
>>> abjad.makers.make_pitch_lists([3, [], [4, 5]])
[[NamedPitch("ef'")], [], [NamedPitch("e'"), NamedPitch("f'")]]
>>> abjad.makers.make_pitch_lists("e'' ef'' d''")
[[NamedPitch("e''")], [NamedPitch("ef''")], [NamedPitch("d''")]]
Use this function to format input for ``abjad.makers.make_leaves()``.
"""
pitch_lists = []
if isinstance(argument, str):
argument = argument.split()
for item in argument:
if isinstance(item, list | tuple):
pitch_list = [_pitch.NamedPitch(_) for _ in item]
elif item is None:
pitch_list = []
else:
pitch_list = [_pitch.NamedPitch(item)]
pitch_lists.append(pitch_list)
return pitch_lists
[docs]
def make_pitches(argument: list | str) -> list[_pitch.NamedPitch]:
"""
Changes list or string ``argument`` to list of named pitches.
.. container:: example
>>> abjad.makers.make_pitches([3, 16, 16.5])
[NamedPitch("ef'"), NamedPitch("e''"), NamedPitch("eqs''")]
>>> abjad.makers.make_pitches("ef' e'' eqs''")
[NamedPitch("ef'"), NamedPitch("e''"), NamedPitch("eqs''")]
>>> abjad.makers.make_pitches(["ef'", "e''", "eqs''"])
[NamedPitch("ef'"), NamedPitch("e''"), NamedPitch("eqs''")]
>>> abjad.makers.make_pitches([3, "e''", abjad.NamedPitch("eqs''")])
[NamedPitch("ef'"), NamedPitch("e''"), NamedPitch("eqs''")]
Use this function to format input for ``abjad.makers.make_notes()``.
"""
if isinstance(argument, str):
argument = argument.split()
assert not any(_ is None for _ in argument), repr(argument)
pitches = [_pitch.NamedPitch(_) for _ in argument]
return pitches
[docs]
def tuplet_from_ratio_and_pair(
ratio: tuple[int, ...],
pair: tuple[int, int],
*,
tag: _tag.Tag | None = None,
) -> _score.Tuplet:
r"""
Makes tuplet from ``ratio`` and ``pair``.
.. container:: example
Helper function:
>>> def make_score(ratio, pair):
... tuplet = abjad.makers.tuplet_from_ratio_and_pair(ratio, pair)
... abjad.makers.tweak_tuplet_number_text(tuplet)
... staff = abjad.Staff([tuplet], lilypond_type="RhythmicStaff")
... score = abjad.Score([staff], name="Score")
... time_signature = abjad.TimeSignature(pair)
... leaf = abjad.select.leaf(staff, 0)
... abjad.attach(time_signature, leaf)
... return score
.. container:: example
Divides duration of 3/16 into increasing number of parts:
>>> score = make_score((1, 2, 2), (3, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tweak text #tuplet-number::calc-fraction-text
\tuplet 5/3
{
\time 3/16
c'16
c'8
c'8
}
>>> score = make_score((1, 2, 2, 3), (3, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tweak text #tuplet-number::calc-fraction-text
\tuplet 4/3
{
\time 3/16
c'32
c'16
c'16
c'16.
}
>>> score = make_score((1, 2, 2, 3, 3), (3, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tweak text #tuplet-number::calc-fraction-text
\tuplet 11/6
{
\time 3/16
c'32
c'16
c'16
c'16.
c'16.
}
>>> score = make_score((1, 2, 2, 3, 3, 4), (3, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tuplet 5/4
{
\time 3/16
c'64
c'32
c'32
c'32.
c'32.
c'16
}
.. container:: example
Divides duration of 7/16 into increasing number of parts:
>>> score = make_score((1,), (7, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tweak text #tuplet-number::calc-fraction-text
\tuplet 1/1
{
\time 7/16
c'4..
}
>>> score = make_score((1, 2), (7, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tweak text #tuplet-number::calc-fraction-text
\tuplet 6/7
{
\time 7/16
c'8
c'4
}
>>> score = make_score((1, 2, 4), (7, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tweak text #tuplet-number::calc-fraction-text
\tuplet 1/1
{
\time 7/16
c'16
c'8
c'4
}
>>> score = make_score((1, 2, 4, 1), (7, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tweak text #tuplet-number::calc-fraction-text
\tuplet 8/7
{
\time 7/16
c'16
c'8
c'4
c'16
}
>>> score = make_score((1, 2, 4, 1, 2), (7, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tweak text #tuplet-number::calc-fraction-text
\tuplet 10/7
{
\time 7/16
c'16
c'8
c'4
c'16
c'8
}
>>> score = make_score((1, 2, 4, 1, 2, 4), (7, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tuplet 2/1
{
\time 7/16
c'16
c'8
c'4
c'16
c'8
c'4
}
.. container:: example
Interprets negative integers in ``ratio`` as rests:
>>> score = make_score((1, 1, 1, -1, 1), (1, 4))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tuplet 5/4
{
\time 1/4
c'16
c'16
c'16
r16
c'16
}
>>> score = make_score((3, -2, 2), (1, 4))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tuplet 7/4
{
\time 1/4
c'8.
r8
c'8
}
.. container:: example
Works with nonassignable rests:
>>> score = make_score((11, -5), (7, 16))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tweak text #tuplet-number::calc-fraction-text
\tuplet 8/7
{
\time 7/16
c'4
~
c'16.
r8
r32
}
.. container:: example
Reduces integers in ``ratio`` relative to each other:
>>> score = make_score((1, 1, 1), (1, 4))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tuplet 3/2
{
\time 1/4
c'8
c'8
c'8
}
>>> score = make_score((4, 4, 4), (1, 4))
>>> abjad.show(score) # doctest: +SKIP
.. docs::
>>> tuplet = score[0][0]
>>> string = abjad.lilypond(tuplet)
>>> print(string)
\tuplet 3/2
{
\time 1/4
c'8
c'8
c'8
}
"""
assert isinstance(ratio, tuple), repr(ratio)
assert all(isinstance(_, int) for _ in ratio), repr(ratio)
assert not any(_ == 0 for _ in ratio), repr(ratio)
assert isinstance(pair, tuple), repr(pair)
assert all(isinstance(_, int) for _ in pair), repr(pair)
duration = _duration.Duration(pair)
if len(ratio) == 1:
if 0 < ratio[0]:
pitch_list = [_pitch.NamedPitch("c'")]
else:
assert ratio[0] < 0, repr(ratio)
pitch_list = []
leaves = make_leaves([pitch_list], [duration], tag=tag)
tuplet = _score.Tuplet.from_duration(duration, leaves, tag=tag)
else:
numerator, denominator = pair
exponent = int(math.log(_math.weight(ratio), 2) - math.log(numerator, 2))
denominator = int(denominator * 2**exponent)
components: list[_score.Leaf | _score.Tuplet] = []
for item in ratio:
if 0 < item:
pitch_list = [_pitch.NamedPitch("c'")]
else:
assert item < 0, repr(item)
pitch_list = []
duration_ = _duration.Duration(abs(item), denominator)
leaves = make_leaves([pitch_list], [duration_], tag=tag)
components.extend(leaves)
tuplet = _score.Tuplet.from_duration(duration, components, tag=tag)
return tuplet
[docs]
def tweak_tuplet_bracket_edge_height(argument) -> None:
r"""
Tweaks tuplet bracket edge height of incomplete tuplets in ``argument``.
A tuplet is defined as incomplete when the denominator ``d`` of the
tuplet's duration ``n/d`` is nondyadic. For example, the duration of
``\tuplet 3/2 { c'4 d'4 }`` is nondyadic because the denominator of ``2/3 *
2/4 = 1/3`` is 3. But the duration of ``\tuplet 3/2 { c'4 d'4 e'4 }`` is
dyadic because the denominator of ``2/3 * 3/4 = 1/2`` is 2.
.. container:: example
By default, LilyPond engraves all tuplets with a complete bracket,
even those that are incomplete, like the first tuplet below:
>>> string = r"\tuplet 3/2 { c'4 d'4 } \tuplet 3/2 { c'4 d'4 e'4 }"
>>> staff = abjad.Staff(string)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
\tuplet 3/2
{
c'4
d'4
}
\tuplet 3/2
{
c'4
d'4
e'4
}
}
Call ``abjad.makers.tweak_tuplet_bracket_edge_height()`` to adjust
the right edge of incomplete tuplets:
>>> abjad.makers.tweak_tuplet_bracket_edge_height(staff)
>>> abjad.show(staff) # doctest: +SKIP
.. docs::
>>> string = abjad.lilypond(staff)
>>> print(string)
\new Staff
{
\tweak edge-height #'(0.7 . 0)
\tuplet 3/2
{
c'4
d'4
}
\tuplet 3/2
{
c'4
d'4
e'4
}
}
"""
for tuplet in _iterate.components(argument, _score.Tuplet):
duration = tuplet._get_preprolated_duration()
denominator = duration.denominator
if not _math.is_nonnegative_integer_power_of_two(denominator):
_tweaks.tweak(tuplet, tuplet.edge_height_tweak_string)
[docs]
def tweak_tuplet_number_text(argument) -> None:
r"""
Tweaks tuplet number text for tuplets in ``argument``. Sets tuplet
number text equal to ``#tuplet-number::calc-fraction-text`` when
any of these conditions is true:
* tuplet is an augmentation (like 3:4), or
* tuplet is nondyadic (like 4:3), or
* denominator of tuplet multiplier is 1
Does not tweak tuplets for which none of these conditions holds.
"""
for tuplet in _iterate.components(argument, _score.Tuplet):
if "text" in vars(_overrides.override(tuplet).TupletNumber):
continue
if tuplet.augmentation() or not tuplet.dyadic() or tuplet.multiplier[1] == 1:
_tweaks.tweak(tuplet, tuplet.tuplet_number_calc_fraction_text_tweak_string)