subsequence.groove ================== .. py:module:: subsequence.groove .. autoapi-nested-parse:: Groove templates — repeating timing and velocity feels applied to quantized patterns. Exports the public Groove class: build one by hand, from a swing percentage, or from an Ableton ``.agr`` file, then apply it with ``p.groove(template)``. Module Contents --------------- .. py:class:: Groove A timing/velocity template applied to quantized grid positions. A groove is a repeating pattern of per-step timing offsets and optional velocity adjustments aligned to a rhythmic grid. Apply it as a post-build transform with ``p.groove(template)`` to give a pattern its characteristic feel — swing, shuffle, MPC-style pocket, or anything extracted from an Ableton ``.agr`` file. :param offsets: Timing offset per grid slot, in beats. Repeats cyclically. Positive values delay the note; negative values push it earlier. :param grid: Grid size in beats (0.25 = 16th notes, 0.5 = 8th notes). :param velocities: Optional velocity scale per grid slot (1.0 = unchanged). Repeats cyclically alongside offsets. Example:: # Ableton-style 57% swing on 16th notes groove = Groove.swing(percent=57) # Custom groove with timing and velocity groove = Groove( grid=0.25, offsets=[0.0, +0.02, 0.0, -0.01], velocities=[1.0, 0.7, 0.9, 0.6], ) .. py:method:: from_agr(path: str) -> Groove :staticmethod: Import timing and velocity data from an Ableton .agr groove file. An ``.agr`` file is an XML document containing a MIDI clip whose note positions encode the groove's rhythmic feel. This method reads those note start times and velocities and converts them into the ``Groove`` dataclass format (per-step offsets and velocity scales). **What is extracted:** - ``Time`` attribute of each ``MidiNoteEvent`` → timing offsets relative to ideal grid positions. - ``Velocity`` attribute of each ``MidiNoteEvent`` → velocity scaling (normalised to the highest velocity in the file). - ``TimingAmount`` from the Groove element → pre-scales the timing offsets (100 = full, 70 = 70% of the groove's timing). - ``VelocityAmount`` from the Groove element → pre-scales velocity deviation (100 = full groove velocity, 0 = no velocity changes). The resulting ``Groove`` reflects the file author's intended strength. Use ``strength=`` when applying to further adjust. **What is NOT imported:** ``RandomAmount`` (use ``p.randomize()`` separately for random jitter) and ``QuantizationAmount`` (not applicable - Subsequence notes are already grid-quantized by construction). Other ``MidiNoteEvent`` fields (``Duration``, ``VelocityDeviation``, ``OffVelocity``, ``Probability``) are also ignored. :param path: Path to the .agr file. .. py:method:: swing(percent: float = 57.0, grid: float = 0.25) -> Groove :staticmethod: Create a swing groove from a percentage. 50% is straight (no swing). 67% is approximately triplet swing. 57% is a moderate shuffle — the Ableton default. :param percent: Swing amount (50–75 is the useful range). :param grid: Grid size in beats (0.25 = 16ths, 0.5 = 8ths). .. py:function:: apply_groove(steps: Dict[int, subsequence.pattern.Step], groove: Groove, pulses_per_quarter: int = subsequence.constants.MIDI_QUARTER_NOTE, strength: float = 1.0) -> Dict[int, subsequence.pattern.Step] Apply a groove template to a step dictionary keyed by pulse positions. Notes close to a grid position are shifted by the groove's offset for that slot. Notes between grid positions are left untouched. :param steps: Step dictionary (pulse → Step). :param groove: The groove template to apply. :param pulses_per_quarter: Internal MIDI clock resolution (default 24). :param strength: How much of the groove to apply (0.0–1.0). 0.0 leaves all timing and velocity unchanged; 1.0 applies the full groove. Intermediate values blend between the two, equivalent to Ableton’s TimingAmount / VelocityAmount dials.