subsequence.voicings

Chord inversions and voice leading.

Provides functions for rotating chord intervals into different inversions and choosing the smoothest voicing between consecutive chords. Voice leading minimises the total semitone movement so that chord pads sound connected rather than jumping around the keyboard.

Example

# Manual inversion
from subsequence.voicings import invert_chord
first_inv = invert_chord([0, 4, 7], inversion=1)  # [4, 7, 12]

# Automatic voice leading across a pattern
@composition.pattern(channel=0, length=4, voice_leading=True)
def chords (p, chord):
        p.chord(chord, root=52, velocity=90, sustain=True)

Module Contents

class subsequence.voicings.VoiceLeadingState[source]

Track the previous voicing across chord changes.

Each pattern that uses voice leading gets its own instance so that a bass line and a pad can voice-lead independently.

Example

state = VoiceLeadingState()
voicing1 = state.next([0, 4, 7], 60)   # root position (no previous)
voicing2 = state.next([0, 3, 7], 60)    # picks closest inversion to voicing1

Start with no previous voicing.

next(intervals: List[int], root_midi: int) List[int][source]

Choose the smoothest voicing and update state.

Parameters:
  • intervals – Chord intervals in semitones from root

  • root_midi – MIDI note number for the chord root

Returns:

MIDI note numbers for the chosen voicing

subsequence.voicings.invert_chord(intervals: List[int], inversion: int) List[int][source]

Rotate chord intervals to produce an inversion.

Inversion 0 is root position. Inversion 1 raises the bottom note by an octave (first inversion). Wraps around for inversions >= the number of notes.

Parameters:
  • intervals – Chord intervals in semitones from root (e.g., [0, 4, 7])

  • inversion – Which inversion to produce (0 = root position)

Returns:

Rotated interval list, still measured from the original chord root, so adding any root yields the same chord with a different bass note.

Example

invert_chord([0, 4, 7], 0)  # [0, 4, 7]   - root position
invert_chord([0, 4, 7], 1)  # [4, 7, 12]  - first inversion (E-G-C)
invert_chord([0, 4, 7], 2)  # [7, 12, 16] - second inversion (G-C-E)
subsequence.voicings.voice_lead(intervals: List[int], root_midi: int, previous_voicing: List[int] | None) List[int][source]

Find the inversion closest to a previous voicing.

Tries every inversion, in the nearest octaves, and picks the candidate with the smallest total semitone movement from previous_voicing. Voices are compared positionally (voice i to voice i), so this picks the best inversion rather than the globally optimal voice reassignment. If previous_voicing is None or the chord sizes differ, returns root position.

Parameters:
  • intervals – Chord intervals in semitones from root (e.g., [0, 4, 7])

  • root_midi – MIDI note number for the chord root

  • previous_voicing – MIDI note numbers of the previous chord, or None

Returns:

MIDI note numbers for the best voicing