subsequence.pattern_algorithmic =============================== .. py:module:: subsequence.pattern_algorithmic .. autoapi-nested-parse:: Mixin class providing algorithmic and generative pattern-building methods. This module is not intended to be used directly. ``PatternAlgorithmicMixin`` is inherited by ``PatternBuilder`` in ``pattern_builder.py``. Module Contents --------------- .. py:class:: PatternAlgorithmicMixin Algorithmic and generative note-placement methods for PatternBuilder. All methods here operate on ``self._pattern`` (a ``Pattern`` instance) and ``self.rng`` (a ``random.Random`` instance), both of which are set by ``PatternBuilder.__init__``. .. py:method:: branch(pitches: List[Union[int, str]], depth: int = 2, path: int = 0, mutation: float = 0.0, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.2, spacing: float = 0.25, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate a melodic variation by navigating a fractal tree of transforms. The ``pitches`` sequence is the "trunk". At each branch level, two musical transforms are assigned deterministically (derived from the original sequence), and the ``path`` index selects left or right at each level. After ``depth`` levels the result is a variation that is always structurally related to the input ``pitches``. Use ``path=p.cycle`` to step through all ``2 ** depth`` variations in order; the index wraps automatically. **Transforms** (assigned deterministically per level): - *Retrograde* — reverse the sequence. - *Invert* — mirror each pitch around the first note. - *Transpose* — shift all pitches by the interval between the first two notes. - *Rotate* — shift the starting position by one step. - *Scale intervals* — multiply intervals from the first note by 0.5 (compress) or 2.0 (expand), rounded to the nearest semitone. An optional ``mutation`` layer randomly substitutes individual notes with other input pitches on top of the deterministic branching. :param pitches: Original pitch sequence. All variations are derived from this. :param depth: Branching levels. ``2 ** depth`` unique variations are available before the path wraps. :param path: Which variation to play (0-based). ``path=p.cycle`` advances automatically. Values wrap modulo ``2 ** depth``. :param mutation: Probability that any step is replaced by a random input pitch after branching (0.0 = none, 1.0 = fully random). :param velocity: MIDI velocity. An ``(low, high)`` tuple randomises per step. :param duration: Note duration in beats. :param spacing: Beat interval between steps. :param seed: Fix the mutation substitutions and velocity draws for this call (an int) — the variation tree itself is deterministic; omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python # Cycle through 8 variations (depth=3) of a 4-note motif p.branch([60, 64, 67, 72], depth=3, path=p.cycle, velocity=85, spacing=0.5) p.snap_to_scale("C", "minor") .. py:method:: bresenham(pitch: Union[int, str], pulses: int, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_VELOCITY, duration: float = 0.1, probability: float = 1.0, no_overlap: bool = False, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate a rhythm using the Bresenham line algorithm. This is an alternative to Euclidean rhythms that often results in slightly different (but still mathematically even) distributions. :param pitch: MIDI note or drum name. :param pulses: Total number of notes to place. :param velocity: MIDI velocity, or a ``(low, high)`` tuple for a fresh random draw per hit. :param duration: Note duration. :param probability: Chance (0.0–1.0) that each pulse plays — 1.0 places them all, lower thins the rhythm. :param seed: Fix the thinning for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). :param no_overlap: If True, skip steps where a note of the same pitch already exists. Useful for layering ghost notes around hand-placed anchors. .. py:method:: bresenham_poly(parts: Dict[Union[int, str], float], velocity: Union[int, Dict[Union[int, str], int]] = subsequence.constants.velocity.DEFAULT_VELOCITY, duration: float = 0.1, grid: Optional[int] = None, probability: float = 1.0, no_overlap: bool = False, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Distribute multiple drum voices across the pattern using weighted Bresenham. Each step is assigned to exactly one voice - voices never overlap, producing interlocking rhythmic patterns. Density weights control how frequently each voice fires. If the weights sum to less than 1.0, the remainder becomes evenly-distributed rests (silent steps). Because notes are placed via ``self.note()``, all post-placement transforms (``groove``, ``randomize``, ``velocity_shape``, ``rotate``, etc.) work normally. :param parts: Mapping of pitch (MIDI note or drum name) to density weight. Higher weight means more hits per bar. Weights in the range (0, 1] are typical; a weight of 0.5 targets roughly one hit every two steps. :param velocity: Either a single MIDI velocity applied to all voices, or a dict mapping each pitch to its own velocity. Pitches absent from the dict fall back to the default velocity (100). :param duration: Note duration in beats (default 0.1). :param grid: Number of steps to divide the pattern into. Defaults to the pattern's ``default_grid``. :param probability: Chance (0.0–1.0) that each hit plays — 1.0 places them all, lower thins. :param seed: Fix the thinning for this call (an int); omit to use the pattern's RNG. :param no_overlap: If True, skip steps where a note of the same pitch already exists. Useful for layering ghost notes around hand-placed anchors. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python p.bresenham_poly( parts={"kick_1": 0.25, "snare_1": 0.125, "hi_hat_closed": 0.5}, velocity={"kick_1": 100, "snare_1": 90, "hi_hat_closed": 70}, ) Layering with hand-placed hits: .. code-block:: python # Algorithmic base - interlocking texture, no overlaps within this layer p.bresenham_poly( parts={"hi_hat_closed": 0.5, "snare_2": 0.1}, velocity={"hi_hat_closed": 65, "snare_2": 40}, ) # Hand-placed anchors on top - these CAN overlap the algorithmic layer p.hit_steps("kick_1", [0, 8], velocity=110) p.hit_steps("snare_1", [4, 12], velocity=100) Stable vs shifting patterns: Because the algorithm redistributes all positions when weights change, a single voice with a continuously ramping density will shift positions every bar. This is great for background texture (hats, shakers) but can sound jarring for prominent, distinctive sounds (claps, cowbells). **For stable patterns** - use ``bresenham()`` with integer pulses. Positions stay fixed until the pulse count steps up:: pulses = max(1, round(density * 16)) p.bresenham("hand_clap", pulses=pulses, velocity=95) **For shifting texture** - use ``bresenham_poly()`` with continuous density. Positions evolve every bar:: p.bresenham_poly(parts={"hi_hat_closed": density}, velocity=70) **To stabilise a solo voice** - pair it with a second voice. More voices in a single call means less positional shift per voice:: p.bresenham_poly( parts={"hand_clap": 0.12, "snare_2": 0.08}, velocity={"hand_clap": 95, "snare_2": 40}, ) .. py:method:: build_ghost_bias(grid: int, bias: str) -> List[float] :staticmethod: Build probability weights for ghost notes or other generative functions. Generates a list of probability weights (values between 0.0 and 1.0) spanning a given grid size. These curves shape probability over a beat, assigning higher or lower chances of an event occurring based on the rhythmic position within the beat (downbeat, offbeat, syncopated 16th note, etc). This is a public escape hatch: call it yourself, manipulate the returned list, then pass the result as ``bias=`` to :meth:`ghost_fill()`. This lets you pin specific steps, boost a weak position, or combine two named curves. :param grid: The total number of steps in the sequence (usually 16 or 32). :param bias: The probability distribution shape to generate: - ``"uniform"`` - 1.0 everywhere. - ``"offbeat"`` - 1.0 on 8th note off-beats (&), 0.3 on 16ths (e/a), 0.05 on downbeats. - ``"sixteenths"`` - 1.0 on 16th notes (e/a), 0.3 on 8th off-beats (&), 0.05 on downbeats. - ``"before"`` - 1.0 preceding a beat, 0.25 on other 16ths, 0.05 on beats. - ``"after"`` - 1.0 following a beat, 0.25 on other 16ths, 0.05 on beats. - ``"downbeat"`` - 1.0 on downbeats, 0.15 on 8th off-beats, 0.05 on other 16ths. - ``"upbeat"`` - 1.0 on 8th note off-beats only, 0.05 everywhere else. - ``"e_and_a"`` - 1.0 on all non-downbeat 16th positions, 0.05 on downbeats. :returns: A ``List[float]`` of length ``grid`` where each value is a probability multiplier from 0.0 to 1.0. The list is a plain Python list — modify it freely before passing to ``ghost_fill(bias=...)``. .. rubric:: Example .. code-block:: python # Start from a named curve, then zero out beat 3 (step 8) entirely # and give the step before the snare (step 11) maximum weight. weights = p.build_ghost_bias(16, "sixteenths") weights[8] = 0.0 # silence around beat 3 weights[11] = 1.0 # boost the "and" before beat 4 p.ghost_fill("snare_1", density=0.25, velocity=(25, 45), bias=weights, no_overlap=True) .. py:method:: cellular_1d(pitch: Union[int, str], rule: int = 30, generation: Optional[int] = None, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_CA_VELOCITY, duration: float = 0.1, no_overlap: bool = False, probability: float = 1.0, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate an evolving rhythm using a 1D cellular automaton. Uses an elementary CA (1D binary cellular automaton) to produce rhythmic patterns that change organically each bar. The CA state evolves by one generation per cycle, creating patterns that are deterministic yet surprising - structured chaos. Rule 30 is the default: it produces quasi-random patterns with hidden self-similarity. Rule 90 produces fractal patterns. Rule 110 is Turing-complete. :param pitch: MIDI note number or drum name. :param rule: Wolfram rule number (0–255). Default 30. :param generation: CA generation to render. Defaults to ``self.cycle`` so the pattern evolves each bar automatically. :param velocity: MIDI velocity, or a ``(low, high)`` tuple for a fresh random draw per hit. :param duration: Note duration in beats. :param no_overlap: If True, skip where same pitch already exists. :param probability: Chance (0.0–1.0) that each hit plays — 1.0 places them all, lower thins. :param seed: Fix the thinning for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python p.hit_steps("kick_1", [0, 8], velocity=100) p.cellular_1d("kick_1", rule=30, velocity=40, no_overlap=True) .. py:method:: cellular_2d(pitches: List[Union[int, str]], rule: str = 'B368/S245', generation: Optional[int] = None, velocity: Union[int, Tuple[int, int], List[int]] = subsequence.constants.velocity.DEFAULT_CA_VELOCITY, duration: float = 0.1, no_overlap: bool = False, probability: float = 1.0, initial_state: Union[str, List[List[int]]] = 'center', density: float = 0.5, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate polyphonic patterns using a 2D Life-like cellular automaton. Evolves a 2D grid where rows map to pitches or instruments and columns map to time steps. Live cells in the final generation become note onsets, producing patterns with spatial structure that evolves each bar. The default rule B368/S245 (Morley/"Move") produces chaotic, active patterns. B3/S23 is Conway's Life; B36/S23 is HighLife. :param pitches: MIDI note numbers or drum names, one per row. Row 0 maps to the first pitch. :param rule: Birth/Survival notation, e.g. ``"B3/S23"`` for Conway's Life, ``"B368/S245"`` for Morley. :param generation: CA generation to render. Defaults to ``self.cycle`` so the grid evolves each bar automatically. :param velocity: Single MIDI velocity for all rows, or a list with one value per row. :param duration: Note duration in beats. :param no_overlap: If True, skip notes where same pitch already exists. :param probability: Chance (0.0–1.0) that each live cell plays — 1.0 places them all, lower thins. :param initial_state: The generation-0 grid. ``"center"`` (default) lights a single cell at the centre; ``"random"`` fills cells with probability *density* (seed it with *seed* for a reproducible fill); or pass an explicit ``list[list[int]]`` (rows × cols) for a custom start. :param density: Fill probability for ``initial_state="random"`` (0.0–1.0). :param seed: RNG seed (an int) for the ``"random"`` initial grid, so it reproduces. Ignored for ``"center"`` or an explicit grid (a warning is emitted if passed there). :param rng: Random generator for the probability thinning. Defaults to ``self.rng``. .. rubric:: Example .. code-block:: python pitches = [36, 38, 42, 46] # kick, snare, hihat, open hihat p.cellular_2d(pitches, rule="B3/S23", initial_state="random", seed=7, density=0.3) .. py:method:: de_bruijn(pitches: List[Union[int, str]], window: int = 2, spacing: Optional[float] = None, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.2, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate a melody that exhaustively traverses all pitch subsequences. A de Bruijn sequence B(k, n) over an alphabet of size ``k`` with window ``n`` contains every possible subsequence of length ``n`` exactly once (cyclically). Mapping each symbol to a pitch produces a melody that systematically explores all possible ``n``-gram transitions - every permutation of ``window`` consecutive pitches appears exactly once. With ``spacing=None`` (default) the full sequence is auto-fitted into the bar, matching the behaviour of :meth:`lsystem`. With a fixed ``spacing`` the sequence is truncated to fill the available beats. :param pitches: List of MIDI note numbers or note strings. The alphabet size ``k`` is ``len(pitches)``. :param window: Subsequence length ``n``. The output has ``len(pitches) ** window`` notes. Keep small (2–4) for practical bar lengths. :param spacing: Time between notes in beats. ``None`` auto-fits the sequence into the bar; a float uses fixed spacing and truncates. :param velocity: MIDI velocity. An ``(low, high)`` tuple randomises per note. :param duration: Note duration in beats. :param seed: Fix the velocity draws for this call (an int) — the note order itself is deterministic; omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python # All 2-note combinations of a pentatonic scale p.de_bruijn([60, 62, 64, 67, 69], window=2, velocity=(60, 100)) .. py:method:: euclidean(pitch: Union[int, str], pulses: int, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_VELOCITY, duration: float = 0.1, probability: float = 1.0, no_overlap: bool = False, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate a Euclidean rhythm. This distributes a fixed number of 'pulses' as evenly as possible across the pattern. This produces many of the world's most common musical rhythms. :param pitch: MIDI note or drum name. :param pulses: Total number of notes to place. :param velocity: MIDI velocity, or a ``(low, high)`` tuple for a fresh random draw per hit. :param duration: Note duration. :param probability: Chance (0.0–1.0) that each pulse plays — 1.0 places them all, lower thins the rhythm. :param seed: Fix the thinning for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). :param no_overlap: If True, skip steps where a note of the same pitch already exists. Useful for layering ghost notes around hand-placed anchors. .. rubric:: Example .. code-block:: python # A classic 3-against-16 rhythm p.euclidean("kick", pulses=3) .. py:method:: evolve(pitches: List[Union[int, str]], length: Optional[int] = None, drift: float = 0.0, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.2, spacing: float = 0.25, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Loop a pitch sequence that gradually mutates each cycle. On cycle 0, the sequence is locked to the initial ``pitches`` (truncated to ``length`` if provided). Each subsequent cycle, every step has a ``drift`` probability of being replaced by a randomly-chosen value from the pool. When ``drift=0.0`` the loop never changes; when ``drift=1.0`` every step is redrawn every cycle. State is stored in ``p.data`` under a key derived from the pitch content, so the buffer persists across pattern rebuilds. The buffer is reset whenever ``cycle == 0`` so restarts produce deterministic output. Combine with ``p.snap_to_scale()`` to keep drifted pitches in key: .. code-block:: python p.evolve([60, 64, 67, 72], length=8, drift=0.12) p.snap_to_scale("C", "minor") :param pitches: Initial pitch pool. The initial buffer is built from the first ``length`` values (cycling if shorter than ``length``). Mutation also draws replacements from this pool. :param length: Number of steps in the loop. Defaults to ``len(pitches)``. :param drift: Per-step mutation probability each cycle (0.0–1.0). ``0.0`` = locked loop, ``1.0`` = fully random each cycle. :param velocity: MIDI velocity. An ``(low, high)`` tuple randomises per step. :param duration: Note duration in beats. :param spacing: Beat interval between steps. :param seed: Fix the drift mutations and velocity draws for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python # 8-step loop that slowly diverges from its seed p.evolve([60, 62, 64, 65, 67, 69], length=8, drift=0.1, velocity=(70, 100), spacing=0.5) p.snap_to_scale("C", "dorian") .. py:method:: fibonacci(pitches: List[Union[int, str]], modulus: Optional[int] = None, count: Optional[int] = None, spacing: Optional[float] = None, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.2, a: int = 1, b: int = 1, mapping: Optional[Callable[[int, int], Optional[Tuple[Union[int, str], int, float]]]] = None, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Play the Fibonacci sequence as a repeating melodic cycle. Each number is the sum of the previous two, folded into your pitch pool. The musical trick is that folding makes the sequence *repeat*, and the length it repeats after is decided by the size of the pool — so the number of notes you hand it chooses the phrase length: a triad gives 8 steps, a pentatonic 20, a seven-note scale 16, an octatonic 12, the full chromatic 24. Called bare, it plays exactly one complete cycle, so the phrase closes on itself. Unlike :meth:`recaman`, which wanders off and never comes back, this always returns home — pair them when you want one voice looping against one that doesn't. For golden-ratio *timing* (which has no Fibonacci numbers in it at all), see :meth:`golden`. :param pitches: Pitch pool. Values index into it, so its size sets the cycle length. Ordered low-to-high it reads as a scale. :param modulus: Fold values into ``[0, modulus)``. Defaults to the pool size, which is almost always what you want; set it larger than the pool to make the line wrap through the pool more than once per cycle. :param count: How many notes to place. Omit for one complete cycle. :param spacing: Beats between notes. Omit to spread the whole cycle across the bar, however long it is. Setting a spacing fixes the note length instead, so a cycle longer than the bar is cut off where the bar ends — a 20-step cycle at ``spacing=0.25`` gets its first 16 notes. :param velocity: MIDI velocity. An ``(low, high)`` tuple randomises per note. :param duration: Note duration in beats. :param a: The first number. Defaults to 1. :param b: The second number. Defaults to 1. ``(2, 1)`` gives the Lucas numbers, a different cycle through the same pool. Note many pairs are that same cycle started elsewhere — ``(1, 3)`` is Lucas one step along. :param mapping: ``f(value, index)`` returning ``(pitch, velocity, duration)`` to place, or None for a rest — full control over how numbers become notes. :param seed: Fix the velocity draws for this call (an int) — the pitches and timing are deterministic; omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). :raises ValueError: If ``pitches`` is empty, or ``spacing`` is not positive. .. rubric:: Example .. code-block:: python # One full 16-step cycle over a minor scale, spread across the bar. p.fibonacci(subsequence.intervals.scale_notes("C", "minor", low=60, high=71)) # The Lucas variant, as steady eighth notes. p.fibonacci([60, 62, 63, 65, 67], a=2, b=1, spacing=0.5) .. py:method:: ghost_fill(pitch: Union[int, str], density: float = 0.3, velocity: Union[int, Tuple[int, int], Sequence[Union[int, float]], Callable[[int], Union[int, float]]] = subsequence.constants.velocity.GHOST_FILL_VELOCITY, bias: Union[str, List[float]] = 'uniform', no_overlap: bool = True, grid: Optional[int] = None, duration: float = 0.1, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Fill the pattern with probability-biased ghost notes. A single method for generating musically-aware ghost note layers. Combines density control, velocity randomisation, and rhythmic bias to produce the micro-detail layering heard in dense electronic music production. :param pitch: MIDI note number or drum name. :param density: Overall density (0.0–1.0). How many available steps receive ghost notes. 0.3 = roughly 30% of steps at peak bias. :param velocity: Single velocity, ``(low, high)`` tuple for random range, a list/sequence of values (indexed by step), or a callable that takes the step index ``i`` and returns a velocity. Allows dynamic values like Perlin noise curves. :param bias: Probability distribution shape: - ``"uniform"`` - equal probability everywhere - ``"offbeat"`` - prefer 8th-note off-beats (&) - ``"sixteenths"`` - prefer 16th-note subdivisions (e/a) - ``"before"`` - cluster just before beat positions - ``"after"`` - cluster just after beat positions - ``"downbeat"`` - reinforce the beat (inverse of offbeat) - ``"upbeat"`` - strictly 8th-note off-beats only - ``"e_and_a"`` - all non-downbeat 16th positions - Or: a list of floats (one per grid step) for a custom field. Use :meth:`build_ghost_bias` to generate a named curve and then modify specific steps before passing it here. :param no_overlap: If True (default), skip where same pitch already exists. Essential for layering ghosts around hand-placed anchors. :param grid: Grid resolution. Defaults to the pattern's default grid. :param duration: Note duration in beats (default 0.1). :param seed: Fix the ghost layer for this call (an int); omit to use the pattern's RNG. **Tip — freeze the layer each cycle:** ``seed=`` starts a fresh random stream on every rebuild, so the same steps — and the same ``(low, high)`` velocity draws — are chosen on every cycle: the ghost layer is locked in place. The default ``self.rng`` advances state across rebuilds, so placement differs every cycle. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python p.hit_steps("kick_1", [0, 4, 8, 12], velocity=100) p.hit_steps("snare_1", [4, 12], velocity=95) # Different ghost placement each cycle (default) p.ghost_fill("kick_1", density=0.2, velocity=(30, 45), bias="sixteenths", no_overlap=True) # The same ghost layer every cycle — placement frozen p.ghost_fill("snare_1", density=0.15, velocity=(25, 40), bias="before", seed=42) .. py:method:: golden(pitches: Union[int, str, List[Union[int, str]]], count: int, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.2, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Place notes at golden-ratio-spaced beat positions. Uses the golden angle method - ``position_i = frac(i × φ) × bar_length``, where ``frac`` keeps only the fractional part - to distribute ``count`` events across the bar as a low-discrepancy (sunflower-seed) spread. The result is sorted into ascending time order. Unlike a Euclidean rhythm (maximally even spacing on a fixed grid), golden-ratio timing is irrational and places events off-grid in a way that sounds organic and avoids metronomic repetition. Give a single pitch (or drum name) for one voice, or a list to cycle a pool through the placed notes in time order — the first note takes the first pitch, and the pool repeats once exhausted. The positions themselves never change, so swapping one pitch for a pool re-voices a rhythm without moving it. This shapes *time* only — the pool is walked in order, not chosen by the golden ratio. For the Fibonacci integer sequence as pitch material, see :meth:`fibonacci`. :param pitches: A MIDI note number or drum name, or a list of them to cycle. :param count: Number of notes to place. :param velocity: MIDI velocity. An ``(low, high)`` tuple randomises per note. :param duration: Note duration in beats. :param seed: Fix the velocity draws for this call (an int) — the timing itself is deterministic; omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). :raises ValueError: If ``pitches`` is an empty list. .. rubric:: Example .. code-block:: python # 11 hi-hat hits with golden-ratio spacing p.golden("hi_hat_closed", count=11, velocity=(60, 90)) # The same spread, cycling a pentatonic pool p.golden([60, 62, 65, 67, 70], count=11) .. py:method:: lorenz(pitches: List[Union[int, str]], spacing: float = 0.25, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.2, dt: float = 0.01, sigma: float = 10.0, rho: float = 28.0, beta: float = 8.0 / 3.0, x0: float = 0.1, y0: float = 0.0, z0: float = 0.0, mapping: Optional[Callable[[float, float, float], Optional[Tuple[Union[int, str], int, float]]]] = None) -> subsequence.pattern_builder.PatternBuilder Generate a note sequence driven by the Lorenz strange attractor. Integrates the Lorenz system to produce a trajectory of (x, y, z) points, each normalised to [0, 1]. The three axes provide correlated but independent modulation sources: by default x drives pitch selection, y drives velocity, and z drives duration. The Lorenz attractor is deterministic but extremely sensitive to initial conditions: changing ``x0`` by even 0.001 produces a divergent trajectory over time. This makes it ideal for cycle-by-cycle variation - pass ``x0=p.cycle * 0.001`` to generate a unique but slowly evolving phrase each bar. A custom ``mapping`` callable can override the default x/y/z → pitch/vel/dur assignment, or return ``None`` for a rest. :param pitches: Pitch pool. The x-axis selects an index: ``int(x * len(pitches)) % len(pitches)``. :param spacing: Time between notes in beats. Default 0.25 (16th note). :param velocity: Fixed velocity or ``(low, high)`` tuple. Overridden by ``mapping``. :param duration: Maximum note duration. z is scaled to ``[0.05, duration]``. Overridden by ``mapping``. :param dt: Integration time step. Default 0.01. :param sigma: Lorenz parameters. Defaults produce the classic butterfly attractor (chaotic regime). :param rho: Lorenz parameters. Defaults produce the classic butterfly attractor (chaotic regime). :param beta: Lorenz parameters. Defaults produce the classic butterfly attractor (chaotic regime). :param x0: Initial conditions. Use ``x0=p.cycle * small_delta`` for slowly evolving variation. :param y0: Initial conditions. Use ``x0=p.cycle * small_delta`` for slowly evolving variation. :param z0: Initial conditions. Use ``x0=p.cycle * small_delta`` for slowly evolving variation. :param mapping: Optional callable ``(x, y, z) -> (pitch, velocity, duration)`` or ``None`` for rest. .. rubric:: Example .. code-block:: python scale = [60, 62, 64, 65, 67, 69, 71, 72] p.lorenz(scale, spacing=0.25, velocity=(50, 110), x0=p.cycle * 0.002) .. py:method:: lsystem(pitch_map: Dict[str, Union[int, str]], axiom: str, rules: Dict[str, Union[str, List[Tuple[str, float]]]], generations: int = 3, spacing: Optional[float] = None, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.2, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate a note sequence using L-system string rewriting. Expands ``axiom`` by applying ``rules`` for ``generations`` iterations, then walks the resulting string placing a note for each character found in ``pitch_map``. Unmapped characters are silent rests - they advance time but produce no note. The defining musical property is self-similarity: patterns repeat at different time scales. The Fibonacci-word rule (``A → AB``, ``B → A``) spaces hits evenly but never quite repeats, so the pattern keeps shifting against the bar. Koch and dragon curve rules produce fractal melodic contours. (Hits land on the grid here — for events placed *off* the grid by the golden ratio, see :meth:`golden`.) With ``spacing=None`` (default) the entire expanded string is fitted into the bar: each generation makes notes twice as dense while preserving the overall shape. With a fixed ``spacing`` the string is truncated to fit and the density stays constant. :param pitch_map: Maps single characters to MIDI notes or drum names. Characters absent from the map produce rests. :param axiom: Starting string (e.g. ``"A"``). :param rules: Production rules. Deterministic: ``{"A": "AB"}``. Stochastic: ``{"A": [("AB", 3), ("BA", 1)]}``. :param generations: Rewriting iterations. String length grows exponentially - keep this to 3–8 for practical use. :param spacing: Time between symbols in beats. ``None`` (default) auto-fits the full expanded string into the bar. A float uses fixed spacing and truncates excess symbols. :param velocity: MIDI velocity. An ``(low, high)`` tuple randomises per note. :param duration: Note duration in beats. :param seed: Fix the stochastic-rule choices and velocity draws for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python # Fibonacci-word kick rhythm - self-similar hit spacing p.lsystem( pitch_map={"A": "kick_1"}, axiom="A", rules={"A": "AB", "B": "A"}, generations=6, velocity=80, ) # Fractal melody over scale notes p.lsystem( pitch_map={"F": 60, "G": 62, "+": 64, "-": 67}, axiom="F", rules={"F": "F+G", "G": "-F"}, generations=4, spacing=0.25, velocity=(70, 100), ) .. py:method:: markov(transitions: Dict[str, List[Tuple[str, int]]], pitch_map: Dict[str, int], velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_VELOCITY, duration: float = 0.1, spacing: float = 0.25, start: Optional[str] = None, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate a sequence by walking a first-order Markov chain. Builds a :class:`~subsequence.weighted_graph.WeightedGraph` from ``transitions`` and walks it, placing one note per ``spacing`` beats. The probability of each next state depends only on the current one - use this to generate basslines, melodies, or rhythm motifs that have stylistic coherence without being perfectly repetitive. The transition dict uses the same ``(target, weight)`` pair format as :meth:`Composition.form`, so the idiom is already familiar. :param transitions: Mapping of state name to a list of ``(next_state, weight)`` tuples. Higher weight means higher probability of that transition. :param pitch_map: Mapping of state name to absolute MIDI note number. States absent from this dict are walked but produce no note. :param velocity: MIDI velocity for all placed notes (default 100), or a ``(low, high)`` tuple for a fresh random draw per step. :param duration: Note duration in beats (default 0.1). :param spacing: Time between note onsets in beats (default 0.25 = 16th note). :param start: Name of the starting state. Defaults to the first key in ``transitions`` when not provided. :param seed: Fix the walk for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). :raises ValueError: If ``transitions`` or ``pitch_map`` is empty. .. rubric:: Example .. code-block:: python # Walking bassline: root anchors, 3rd and 5th passing tones p.markov( transitions={ "root": [("3rd", 3), ("5th", 2), ("root", 1)], "3rd": [("5th", 3), ("root", 2)], "5th": [("root", 3), ("3rd", 1)], }, pitch_map={"root": 52, "3rd": 56, "5th": 59}, velocity=80, spacing=0.5, ) .. py:method:: melody(state: subsequence.melodic_state.MelodicState, spacing: float = 0.25, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_CHORD_VELOCITY, duration: float = 0.2, chord_tones: Optional[List[int]] = None, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate a melodic line by querying a persistent :class:`~subsequence.melodic_state.MelodicState`. Places one note (or rest) per ``spacing`` beats for the full pattern length. Pitch selection is guided by the NIR cognitive model inside ``state``: after a large leap the model expects a direction reversal; after a small step it expects continuation. Chord tones, range gravity, and a pitch-diversity penalty further shape the output. Because ``state`` lives outside the pattern builder and persists across bar rebuilds, melodic continuity is maintained automatically - no manual history management is required. :param state: Persistent :class:`~subsequence.melodic_state.MelodicState` instance created once at module level. :param spacing: Time between note onsets in beats (default 0.25 = 16th note). :param velocity: MIDI velocity. An ``int`` applies a fixed level; a ``(low, high)`` tuple draws uniformly from that range each spacing. :param duration: Note duration in beats (default 0.2 - slightly shorter than a 16th note, giving a crisp attack). :param chord_tones: Optional list of MIDI note numbers that are chord tones this bar (e.g. from ``chord.tones(root)``). Chord-tone pitch classes receive a ``chord_weight`` bonus inside ``state``. :param seed: Fix the walk for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python melody_state = subsequence.MelodicState( key="A", mode="aeolian", low=60, high=84, nir_strength=0.6, chord_weight=0.4, ) @composition.pattern(channel=4, beats=4) def lead (p, chord): tones = chord.tones(72) if chord else None p.melody(melody_state, spacing=0.5, velocity=(70, 100), chord_tones=tones) .. py:method:: ratchet(subdivisions: int = 2, pitch: Optional[Union[int, str]] = None, probability: float = 1.0, velocity_start: float = 1.0, velocity_end: float = 1.0, shape: Union[str, Callable[[float], float]] = 'linear', gate: float = 0.5, steps: Optional[List[int]] = None, grid: Optional[int] = None, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Subdivide existing notes into rapid repeated hits (rolls/ratchets). A post-placement transform: takes notes already in the pattern and replaces each one with ``subdivisions`` evenly-spaced sub-hits within the original note's duration window. The velocity of each sub-hit is interpolated from ``velocity_start`` to ``velocity_end`` (as multipliers on the original velocity) using the ``shape`` easing curve, so crescendo rolls, decrescendo buzzes, and flat repeats are all one parameter apart. Call ``ratchet()`` after note-placement methods (``euclidean``, ``hit_steps``, ``arpeggio``, etc.) and before ``swing`` or ``groove`` so that the subdivisions sit inside the original note slot and swing displacement still affects the parent position. :param subdivisions: Number of sub-hits replacing each note (default 2). If the note's duration is shorter than ``subdivisions`` pulses, subdivisions are clamped to ``note.duration`` so they never stack on the same pulse. :param pitch: Only ratchet notes matching this pitch (MIDI number or drum name). ``None`` (default) ratchets all notes regardless of pitch — useful for melodic patterns such as arpeggios. :param probability: Chance (0.0–1.0) that each note gets ratcheted. Notes that fail the check are left completely unchanged. Default 1.0 (every note is ratcheted). :param velocity_start: Velocity multiplier for the first sub-hit (0.0–2.0). Default 1.0 (same as the original). :param velocity_end: Velocity multiplier for the last sub-hit (0.0–2.0). Default 1.0. Set ``velocity_start=0.3, velocity_end=1.0`` for a crescendo roll; ``1.0, 0.2`` for a decrescendo buzz. :param shape: Easing curve applied to the velocity interpolation across sub-hits. Accepts any name from ``subsequence.easing`` (e.g. ``"ease_in"``, ``"ease_out"``, ``"s_curve"``) or a custom callable ``f(t) → t`` for t ∈ [0, 1]. Default ``"linear"``. :param gate: Sub-note duration as a fraction of each subdivision slot (0.0–1.0). ``1.0`` = legato (sub-hits touch), ``0.5`` = staccato (half the slot). Default 0.5. :param steps: Grid positions to ratchet (e.g. ``[0, 4, 12]``). Notes are classified to grid zones the same way ``thin()`` works — swing- shifted notes remain in their original zone. ``None`` (default) applies ratchet to all eligible notes. :param grid: Grid resolution used for ``steps`` zone classification. Defaults to the pattern's ``default_grid``. :param seed: Fix the probability gating for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Examples .. code-block:: python # Subdivide every hi-hat into a triplet roll p.euclidean("hi_hat_closed", 8).ratchet(3, pitch="hi_hat_closed") # Crescendo roll into a snare p.hit_steps("snare", [12]).ratchet(4, velocity_start=0.3, velocity_end=1.0, shape="ease_in") # Probabilistic 2× ratchet on hi-hats only p.euclidean("hi_hat_closed", 12).ratchet(2, pitch="hi_hat_closed", probability=0.4, gate=0.3) # Ratchet only steps 0 and 8 (downbeats) p.euclidean("kick_1", 6).ratchet(2, pitch="kick_1", steps=[0, 8]) .. py:method:: reaction_diffusion(pitch: Union[int, str], threshold: float = 0.5, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.1, feed_rate: float = 0.055, kill_rate: float = 0.062, steps: int = 1000, no_overlap: bool = False, probability: float = 1.0, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate a rhythm from a 1D Gray-Scott reaction-diffusion simulation. Simulates the Gray-Scott model on a ring of ``_default_grid`` cells, then thresholds the final V-concentration to produce a binary hit pattern. Cells where concentration exceeds ``threshold`` become note events. Unlike cellular automata - where rules are discrete and the state is binary - reaction-diffusion evolves a continuous concentration field governed by diffusion rates and chemical reactions. The resulting spatial patterns (spots, stripes, travelling waves) have an organic, biological character that maps naturally to rhythm. The ``feed_rate`` and ``kill_rate`` parameters control pattern type: typical values that produce spots (useful rhythms) range from 0.020–0.062 for feed and 0.045–0.069 for kill. The defaults (F=0.055, k=0.062) produce a stable spotted pattern. :param pitch: MIDI note number or drum name. :param threshold: V-concentration threshold for note placement (0.0–1.0). Lower values produce denser patterns. :param velocity: MIDI velocity. An ``(low, high)`` tuple is NOT random: each step's local V-concentration is mapped into the range deterministically, so notes are louder where the pattern is denser. :param duration: Note duration in beats. :param feed_rate: Rate of U replenishment. Default 0.055. :param kill_rate: Rate of V removal. Default 0.062. :param steps: Number of simulation iterations. More = more developed pattern. Default 1000. :param no_overlap: Skip steps where ``pitch`` is already sounding. :param probability: Chance (0.0–1.0) that each active step plays — 1.0 places them all, lower thins. :param seed: Fix the thinning for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python # Organic kick pattern from reaction-diffusion p.reaction_diffusion("kick_1", threshold=0.4, feed_rate=0.037, kill_rate=0.060) .. py:method:: recaman(pitches: List[Union[int, str]], count: Optional[int] = None, spacing: Optional[float] = None, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.2, start: int = 0, skip: int = 0, octave_span: int = 2, mapping: Optional[Callable[[int, int], Optional[Tuple[Union[int, str], int, float]]]] = None, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Play Recamán's sequence — a melody that wanders off and never repeats. The rule is *step back if you can, otherwise step forward*, by one at the first note, two at the second, and so on. Because the steps keep growing, the line lurches ever wider, and the back-and-forth splits into **two voices**: alternate notes sink while the ones between them climb, so a single line is heard as two moving apart. That wedge is the reason to reach for this — nothing else here produces it, and it is deterministic, so the same call always gives it back. It is at its best over one or two bars. Left running much longer the sequence spreads out and starts to sound like a random walk. Because the numbers grow without limit, they are read as *scale degrees plus register*: each value picks a note from the pool and how many octaves up to put it, which is what turns the widening into an audible opening-out. Give a pool of **one octave** — the degrees of your scale. A multi-octave pool works, but it stacks octaves on octaves and the wedge gets very wide very fast. The sister generator :meth:`fibonacci` always returns home; this one never does. :param pitches: One octave of pitches — the degrees values are drawn from. :param count: How many notes to place. Defaults to the pattern's grid. :param spacing: Beats between notes. Omit to spread them across the bar. :param velocity: MIDI velocity. An ``(low, high)`` tuple randomises per note. :param duration: Note duration in beats. :param start: The first value. From 2 upward this is genuinely new material, and the higher it is the longer the melody's opening descent. ``0`` and ``1`` give the same shape, so step by more than one to hear a change — ``start=2 + p.cycle * 3`` evolves the line every cycle. :param skip: Start further along the sequence, discarding this many values. :param octave_span: How many octaves the line may climb before it turns back. Set to 0 to keep everything in one octave. :param mapping: ``f(value, index)`` returning ``(pitch, velocity, duration)`` to place, or None for a rest — full control over how numbers become notes. :param seed: Fix the velocity draws for this call (an int) — the pitches and timing are deterministic; omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). :raises ValueError: If ``pitches`` is empty, ``spacing`` is not positive, or ``skip`` is negative. .. rubric:: Example .. code-block:: python # The wedge, over one octave of C minor. p.recaman(subsequence.intervals.scale_notes("C", "minor", low=60, high=71)) # A line that reinvents itself every cycle. p.recaman([60, 62, 63, 65, 67, 68, 71], start=2 + p.cycle * 3) .. py:method:: self_avoiding_walk(pitches: List[Union[int, str]], spacing: float = 0.25, velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_GENERATIVE_VELOCITY, duration: float = 0.2, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Generate a melody using a self-avoiding random walk. A self-avoiding walk moves ±1 step through a pitch index space, tracking visited positions and refusing to revisit them. When the walk is trapped (all neighbours visited), the visited set resets and the walk continues from the current position - creating natural phrase boundaries. Compared to :func:`random_walk`, the self-avoiding variant guarantees pitch diversity within each phrase: no pitch repeats until the walk resets. The contiguous step motion (never skipping pitches) gives melodies a smooth, step-wise quality with occasional direction reversals. :param pitches: Ordered list of MIDI note numbers or note strings. The walk moves through indices ``[0, len(pitches) - 1]``, mapping each to the corresponding pitch. :param spacing: Time between notes in beats. Default 0.25 (16th note). :param velocity: MIDI velocity. An ``(low, high)`` tuple randomises per note. :param duration: Note duration in beats. :param seed: Fix the walk for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python scale = subsequence.scale_notes("C", "ionian", low=60, high=72) p.self_avoiding_walk(scale, spacing=0.25, velocity=(60, 100)) .. py:method:: thin(pitch: Optional[Union[int, str]] = None, strategy: Union[str, List[float]] = 'strength', amount: float = 0.5, grid: Optional[int] = None, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Remove notes from the pattern based on their rhythmic position. This is the musical inverse of :meth:`ghost_fill()`. Where ``ghost_fill`` uses bias weights to decide where to *add* ghost notes, ``thin`` uses the same position vocabulary to decide where to *remove* notes. A high strategy weight on a position means that position is dropped first. The strategy names match those in :meth:`build_ghost_bias()` and carry the same rhythmic meaning: - ``"sixteenths"`` - removes 16th-note subdivisions (e/a), keeps beats and &. - ``"offbeat"`` - removes the & position, straightens the groove. - ``"e_and_a"`` - removes all non-downbeat positions, keeps only beats. - ``"downbeat"`` - removes beat positions (floating/displaced effect). - ``"upbeat"`` - removes only the & position. - ``"uniform"`` - removes from all positions equally (per-instrument dropout). - ``"strength"`` - progressive thinning: weakest positions (e/a) drop first, strongest (downbeat) last. Useful for Perlin-driven density control. When ``pitch`` is given, only notes of that instrument are affected - useful for drum layers. When ``pitch`` is ``None`` (the default), all notes regardless of pitch are candidates. This makes ``thin`` a rhythm-aware generalisation of :meth:`dropout()`, and is ideal for tonal patterns such as arpeggios where each step carries a different pitch. Position classification is **zone-based**: each grid step owns the pulse range ``[N * step_pulses, (N + 1) * step_pulses)``, so notes shifted by swing or groove are still classified correctly regardless of call order. :param pitch: Drum name or MIDI note number to target, or ``None`` to thin all notes regardless of pitch. Defaults to ``None``. :param strategy: Named strategy string or a list of per-step drop-priority floats (0.0 = never drop, 1.0 = highest drop priority). Must have length equal to ``grid`` when a list is provided. :param amount: Overall thinning depth (0.0 = remove nothing, 1.0 = remove all qualifying). Effective drop probability = ``priority * amount``. Drive this with a Perlin field or section progress for smooth, organic thinning over time. :param grid: Step grid size. Defaults to the pattern's ``default_grid``. :param seed: Fix the thinning for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). Example:: # Thin 16th ghost notes from the kick, keep anchors and off-beats p.hit_steps("kick_1", [0, 4, 8, 12], velocity=100) p.ghost_fill("kick_1", density=0.3, velocity=(25, 40), bias="sixteenths") p.thin("kick_1", "sixteenths", amount=0.8) # Perlin-driven progressive thinning of hi-hats sparseness = perlin_1d(p.cycle * 0.07, seed=42) p.thin("hi_hat_closed", "strength", amount=sparseness) # Thin an arpeggio (all pitches) - no pitch loop needed p.thin(strategy="strength", amount=sparseness) .. py:method:: thue_morse(pitch: Union[int, str], velocity: Union[int, Tuple[int, int]] = subsequence.constants.velocity.DEFAULT_VELOCITY, duration: float = 0.1, pitch_b: Optional[Union[int, str]] = None, velocity_b: Optional[Union[int, Tuple[int, int]]] = None, no_overlap: bool = False, probability: float = 1.0, seed: Optional[int] = None, rng: Optional[random.Random] = None) -> subsequence.pattern_builder.PatternBuilder Place notes using the Thue-Morse aperiodic binary sequence. The Thue-Morse sequence (0 1 1 0 1 0 0 1 1 0 0 1 0 1 1 0 …) is perfectly balanced, overlap-free, and self-similar but never periodic. It produces rhythmic patterns that feel structured yet never settle into a simple repeating loop - a quality distinct from Euclidean rhythms (evenly spaced) and cellular automata (rule-driven evolution). In **single-pitch mode** (default), notes are placed at positions where the sequence is 1. In **two-pitch mode** (``pitch_b`` given), ``pitch`` flips to the 0-positions and ``pitch_b`` takes the 1-positions - useful for alternating two drums or two chord tones. :param pitch: Pitch (MIDI note number or drum name). Placed at the sequence's 1-positions in single-pitch mode; at the 0-positions when ``pitch_b`` takes over the 1s. :param velocity: MIDI velocity for ``pitch``, or a ``(low, high)`` tuple for a fresh random draw per hit. :param duration: Note duration in beats. :param pitch_b: Optional second pitch placed at sequence-1 positions. When set, all steps produce a note (no rests). :param velocity_b: Velocity for ``pitch_b`` (int or ``(low, high)`` tuple). Defaults to ``velocity``. :param no_overlap: Skip steps where ``pitch`` is already sounding. :param probability: Chance (0.0–1.0) that each active step plays — 1.0 places them all, lower thins. :param seed: Fix the thinning for this call (an int); omit to use the pattern's RNG. :param rng: Advanced determinism form — a ``random.Random`` (wins over ``seed=``). .. rubric:: Example .. code-block:: python # Single-pitch Thue-Morse kick p.thue_morse("kick_1", velocity=100) # Two-pitch mode: alternate kick and snare p.thue_morse("kick_1", pitch_b="snare_1", velocity=100)