Composition tools

General-purpose composition tools.

paeonia.tools.note_repeat(bar, repeats, *, frames=None)[source]

Yield notes indefinitely using a cycling repeat-count pattern.

The notes in bar and the values in repeats advance together and cycle independently. For example, a bar containing a, b, c and repeat counts 1, 2 produces a, b, b, c, a, a, b, c, c, a, .... Emitted values are the original Note objects, so their pitches, duration, velocity, and tie metadata are retained.

Parameters:
  • bar (Bar) – Non-empty bar whose notes are cycled indefinitely.

  • repeats (Iterable[int]) – Finite, non-empty pattern of positive repeat counts. The iterable is materialized once so that it can be validated and cycled.

  • frames (int | None, default=None) – Number of note/count pairs to consume. The default yields indefinitely; a finite value makes the stream stop after that many pairs.

Yields:

Note – Each note from bar, repeated by its corresponding count.

Raises:
  • ValueError – If the bar or repeat pattern is empty, or a repeat count is not positive, or frames is negative.

  • TypeError – If a repeat count is not an integer or frames has the wrong type.

Return type:

Iterator[Note]

paeonia.tools.gate_notes(bar, pattern, *, extend_previous=False, frames=None)[source]

Yield a note stream controlled by a cycling gate pattern.

The notes in bar and switches in pattern advance together and cycle independently. A true switch opens the gate and yields the original event unchanged; a false switch closes it and normally yields an untied rest with the same duration and velocity. With extend_previous=True, closed frames following an active event are instead absorbed into that event’s duration. Chords are treated as single events. Existing rests remain rests.

Parameters:
  • bar (Bar) – Non-empty bar whose events are cycled indefinitely.

  • pattern (Iterable[bool | int] | str) – Finite, non-empty pattern containing Boolean values or the equivalent integers 0 and 1. A string may use "x" for an open gate and "." for a closed gate. The pattern is materialized once so generator patterns can be validated and cycled.

  • extend_previous (bool, default=False) – Merge the durations of muted events into the preceding active event. Muted events before the first active event remain rests.

  • frames (int | None, default=None) – Number of source frames to consume. The default yields indefinitely; a finite value stops after that many frames and flushes a final extended event.

Yields:

Note – An active event, an extended active event, or a rest that occurs before any active event.

Raises:
  • ValueError – If the bar or switch pattern is empty, a string pattern contains characters other than "x" and ".", or frames is negative.

  • TypeError – If a switch is not Boolean, 0, or 1, or an option has the wrong type.

Return type:

Iterator[Note]

Notes

Muted events have both tie flags cleared because rests cannot form valid ties. Active events are yielded unchanged, so callers masking tied material are responsible for ensuring adjacent tie chains remain valid.

paeonia.tools.pulses_to_durations(bar, pulses, legato=True, unit=Fraction(1, 16), offset=0, emit_ties=False)[source]

Apply an onset pattern to a bar’s events.

Each "x" starts the next source event, cycling through bar when necessary. Each "." is either a unit rest or, in legato mode, a continuation of the preceding onset. Dots before the first onset remain rests.

In the default legato representation, an onset and its continuation frames become one longer event. With emit_ties=True, sounding continuations are instead emitted as separate unit events joined by ties. Rest spans are never tied. Pitch spelling, velocity, outer tie flags, and bar tonality are retained, and the source bar is not modified.

Parameters:
  • bar (Bar) – Non-empty source of events when pulses contains an onset.

  • pulses (str) – Pattern whose onsets are "x" and whose rests or continuations are ".".

  • legato (bool, default=True) – Merge onsets with their following dot frames. When false, every frame produces one unit-length event.

  • unit (Fraction, default=Fraction(1, 16)) – Positive duration of one pattern frame.

  • offset (int, default=0) – Number of frames by which to rotate the pattern to the left.

  • emit_ties (bool, default=False) – In legato mode, emit separate tied sounding frames instead of one merged event. This has no effect when legato is false.

Returns:

A new rhythmically transformed bar with the source tonality.

Return type:

Bar

Raises:
  • TypeError – If bar is not a bar, pulses is not a string, or offset is not an integer.

  • ValueError – If the pattern contains unsupported characters, unit is not positive, or an onset is requested from an empty bar.

paeonia.tools.euclidean_rhythm(bar, n, k, legato=True, unit=Fraction(1, 16), offset=0, emit_ties=False)[source]

Distribute k source onsets evenly over n frames.

Source events are selected cyclically at generated onsets. Rhythm realization is delegated to pulses_to_durations(), so legato durations, explicit ties, metadata, rotation, and tonality behave identically in both functions.

Parameters:
  • bar (Bar) – Source events cycled at generated onsets.

  • n (int) – Positive number of frames in the generated rhythm.

  • k (int) – Number of onsets between zero and n, inclusive.

  • legato (bool, default=True) – Merge each onset with its following continuation frames.

  • unit (Fraction, default=Fraction(1, 16)) – Duration of one frame.

  • offset (int, default=0) – Number of frames by which to rotate the pattern to the left.

  • emit_ties (bool, default=False) – In legato mode, emit tied unit events instead of merged durations.

Returns:

A new bar containing the generated rhythm and source tonality.

Return type:

Bar

Raises:
  • TypeError – If bar is not a bar or n and k are not integers.

  • ValueError – If n is not positive or k lies outside 0 <= k <= n.

paeonia.tools.fill_bars(bars, notes)[source]

Fill template bars with events from a note source.

The function consumes events in order and returns one new bar for every template bar. Each result has exactly the template’s span and tonality. Events that cross a bar boundary are split; sounding notes and chords are tied across the boundary, while rests are split without ties. Consecutive rests within one result bar are combined into a single rest, retaining the first rest’s velocity. Existing tie flags are retained at the outer ends of a split sounding event.

The finite bar input is consumed eagerly and the result is a concrete Voice. If bars is a voice, its default tonality, tonality plan, and name are inherited by the result. The note source is consumed only as far as needed. Source events that fit without splitting are reused unchanged except when rest normalization requires a new event; split segments are created with Note.with_duration() and Note.with_ties().

Parameters:
  • bars (Iterable[Bar]) – Finite collection of bars whose spans and tonalities define the output structure. A Voice can be passed directly.

  • notes (Iterable[Note]) – Finite or infinite source of notes, chords, and rests.

Returns:

A new voice containing the filled bars. Voice-level tonal context and name are inherited when the templates are supplied as a voice.

Return type:

Voice

Raises:
  • TypeError – If either input produces an object of the wrong type.

  • ValueError – If the note source ends before a template bar can be filled.