subsequence.intervals
The API reference for register_scale and scale_notes.
register_scale
register_scale(
name: str,
intervals: typing.List[int],
qualities: typing.Optional[typing.List[str]] = None,
) -> None
Register a custom scale for use with p.snap_to_scale() and
scale_pitch_classes().
Built-in scale names (e.g. "minor", "hirajoshi") cannot be
overwritten. Custom names may be re-registered freely — live reload
re-runs registration on every save, so this must not raise.
Parameters
name: Scale name (used inp.snap_to_scale(key, name)). Must not be the name of a built-in scale.intervals: Semitone offsets from the root (e.g.[0, 2, 3, 7, 8]for Hirajōshi). Must be whole numbers, start with 0, ascend strictly, and stay within 0–11.qualities: Optional chord quality per scale degree (e.g.["minor", "major", "minor", "major", "diminished"]). Required only if you want to use the scale withdiatonic_chords()ordiatonic_chord_sequence().
Raises
ValueError: If name is a built-in scale, or intervals / qualities fail the rules above.
Example:
import subsequence
subsequence.register_scale("raga_bhairav", [0, 1, 4, 5, 7, 8, 11])
@comp.pattern(channel=0, length=4)
def melody (p):
p.note(60, beat=0)
p.snap_to_scale("C", "raga_bhairav")
scale_notes
scale_notes(
key: str,
mode: str = 'ionian',
low: int = 60,
high: int = 72,
count: typing.Optional[int] = None,
) -> typing.List[int]
Return MIDI note numbers for a scale within a pitch range.
Parameters
key: Scale root as a note name ("C","F#","Bb", etc.). This acts as a pitch-class filter only — it determines which semitone positions (0–11) are valid members of the scale, but does not affect which octave notes are drawn from. Notes are selected starting fromlowupward;keycontrols which notes are kept, not where the sequence starts. To guarantee the first returned note is the root,lowmust be a MIDI number whose pitch class matcheskey. When starting from an arbitrary MIDI number, derive the key name withsubsequence.chords.PC_TO_NOTE_NAME[root_pitch % 12].mode: Scale mode name. Supports all keys ofSCALE_MODE_MAP(e.g."ionian","dorian","natural_minor","major_pentatonic"). Useregister_scalefor custom scales.low: Lowest MIDI note (inclusive). Whencountis set, this is the starting note from which the scale ascends. Iflowis not a member of the scale defined bykey, it is silently skipped and the first returned note will be the next in-scale pitch abovelow.high: Highest MIDI note (inclusive). Ignored whencountis set.count: Exact number of notes to return. Notes ascend fromlowthrough successive scale degrees, cycling into higher octaves as needed. WhenNone(default), all scale tones betweenlowandhighare returned.
Returns
typing.List[int]: Sorted list of MIDI note numbers.
Examples
import subsequence
import subsequence.constants.midi_notes as notes
# C major: all tones from middle C to C5
subsequence.scale_notes("C", "ionian", low=notes.C4, high=notes.C5)
# → [60, 62, 64, 65, 67, 69, 71, 72]
# E natural minor (aeolian) across one octave
subsequence.scale_notes("E", "aeolian", low=notes.E2, high=notes.E3)
# → [40, 42, 43, 45, 47, 48, 50, 52]
# 15 notes of A minor pentatonic ascending from A3
subsequence.scale_notes("A", "minor_pentatonic", low=notes.A3, count=15)
# → [57, 60, 62, 64, 67, 69, 72, 74, 76, 79, 81, 84, 86, 88, 91]
# Misalignment: key="E" but low=C4 — first note is C, not E
subsequence.scale_notes("E", "minor", low=60, count=4)
# → [60, 62, 64, 66] (C D E F# — all in E natural minor, but starts on C)
# Fix: derive key name from root_pitch so low is always in the scale
root_pitch = 64 # E4
key = subsequence.chords.PC_TO_NOTE_NAME[root_pitch % 12] # → "E"
subsequence.scale_notes(key, "minor", low=root_pitch, count=4)
# → [64, 66, 67, 69] (E F# G A — starts on the root)