relic_keymanager
Tools to manage notes in musical applications. Includes note priority, arpeggiation, and sequencing.
Author(s): Cooper Dalrymple
Implementation Notes
Software and Dependencies:
Adafruit CircuitPython firmware for the supported boards: https://circuitpython.org/downloads
Adafruit’s SimpleMath library: https://github.com/adafruit/Adafruit_CircuitPython_SimpleMath
- class relic_keymanager.Arpeggiator(bpm: float = 120.0, steps: float = TimerStep.EIGHTH, mode: int = ArpeggiatorMode.UP)
Use this class to iterate over notes based on time parameters. Note press and release timing is managed by bpm (beats per minute), steps (divisions of a beat), and gate (note duration during step).
- Parameters:
bpm – The beats per minute of timer.
steps – The number of steps to divide a single beat. The minimum value allowed is 0.25, or a whole note.
gate – The duration of each pressed note per step to play before releasing as a ratio from 0.0 to 1.0.
mode – The method of stepping through notes as specified by
ArpeggiatorModeconstants.
- property mode: int
The method of stepping through notes. See
ArpeggiatorModefor options.
- class relic_keymanager.ArpeggiatorMode
An enum-like class containing constaints for the possible modes of the
Arpeggiatorclass.
- class relic_keymanager.Keyboard(keys: <module 'keypad' from '/home/docs/checkouts/readthedocs.org/user_builds/circuitpython-keymanager/envs/latest/lib/python3.14/site-packages/keypad.py'> = None, max_voices: int = 1, root: int = 48, mode: int = KeyboardMode.HIGH)
Manage notes, voice allocation, arpeggiator assignment, sustain, and relevant callbacks using this class.
- Parameters:
keys – A list of
Keyobjects which will be used to update the keyboard state.max_voices – The maximum number of voices/notes to be played at once.
root – Set the base note number of the physical key inputs.
- property active_voices: list[Voice]
All keyboard voices that are “active”, have been assigned a note. The voices will automatically be sorted by the time they were last assigned a note from oldest to newest.
- append(notenum: int | Note, velocity: float = 1.0, keynum: int = None)
Add a note to the keyboard buffer. Useful when working with MIDI input or another note source. Any previous notes with the same notenum value will be removed automatically.
- Parameters:
notenum – The number of the note. Can be defined by MIDI notes, a designated sample index, etc. When using MODE_HIGH or MODE_LOW, the value of this parameter will affect the order. A
Noteobject can be used instead of providing notenum, velocity, and keynum parameters directly.velocity – The velocity of the note from 0.0 through 1.0.
keynum – An additional index reference typically used to associate the note with a physical
Keyobject. Not required for use of the keyboard.
- property arpeggiator: Arpeggiator
The
Arpeggiatorobject assigned to the keyboard.
- property inactive_voices: list[Voice]
All keyboard voices that are “inactive”, do not currently have a note assigned. The voices will automatically be sorted by the time they were last assigned a note from oldest to newest.
- property keys: <module 'keypad' from '/home/docs/checkouts/readthedocs.org/user_builds/circuitpython-keymanager/envs/latest/lib/python3.14/site-packages/keypad.py'>
The
keypad.Keysobject which will be used to update the keyboard state.
- property max_voices: int
The maximum number of voices used by this keyboard to allocate notes. Must be greater than 1. When this property is set, it will automatically release and delete any voices or add new voice objects depending on the previous number of voices. Any voice related callbacks may be triggered during this process.
- property mode: int
The note allocation mode. Use one of the mode constants of
KeyboardMode. Note allocation won’t be updated until the next update call.
- property notes: list[Note]
Active
Notesobjects according to the currentKeyboardMode.
- on_key_press: Callable[[int, int, float], None] = None
The callback method to be called when a
Keyobject is pressed. Must have 3 parameters for keynum, note value, velocity (0.0-1.0), and keynum. Ie:def press(keynum, notenum, velocity):.
- on_key_release: Callable[[int, int], None] = None
The callback method to be called when a
Keyobject is released. Must have 2 parameters for keynum and note value. Velocity is always assumed to be 0.0. Ie:def release(keynum, notenum):.
- on_voice_press: Callable[[Voice], None] = None
The callback method to be called when a voice is pressed. Must have 1 parameter for the
Voiceobject. Ie:def press(voice):.
- on_voice_release: Callable[[Voice], None] = None
The callback method to be called when a voice is released. Must have 1 parameter for the
Voiceobject. Velocity is always assumed to be 0.0. Ie:def release(voice):.
- remove(notenum: int | Note, remove_sustained: bool = False)
Remove a note from the keyboard buffer. Useful when working with MIDI input or another note source. If the note is found (and the keyboard isn’t being sustained or remove_sustained is set as
True), the release callback will trigger automatically regardless of theupdateparameter.- Parameters:
notenum – The value of the note that you would like to be removed. All notes in the buffer with this value will be removed. Can be defined by MIDI note value, a designated sample index, etc. Can also use a
Noteobject instead.remove_sustained – Whether or not you would like to override the current sustained state of the keyboard and release any notes that are being sustained.
- property sustain: bool
Whether or not the notes pressed are sustained after being released until this property is set to
False.
- update() None
Update
keysobjects if they were provided during initialization. For best performance, call frequently!- Parameters:
delay – The amount of time to sleep between polling in seconds.
- class relic_keymanager.KeyboardMode
An enum-like class representing Keyboard note handling modes.
- class relic_keymanager.LoopType
An enum-like class representing sequencer looping methods.
- class relic_keymanager.Note(notenum: int, velocity: float = 1.0, keynum: int = None)
Object which represents the parameters of a note. Contains note number, velocity, key number (if evoked by a
Keyobject), and timestamp of when the note was created.- Parameters:
notenum – The MIDI note number representing the frequency of a note.
velocity – The strength of which a note was pressed from 0.0 to 1.0.
keynum – The index number of the
Keyobject which created thisNoteobject.
- class relic_keymanager.Sequencer(length: int = 16, tracks: int = 1, bpm: float = 120.0)
Sequence notes using the
Timerclass to create a multi-track note sequencer. By default, the Sequencer is set up for a single 4/4 measure of 16 notes with one track. Each note of each track can be assigned any note value and velocity. The length and number of tracks can be reassigned during runtime.- Parameters:
length – The number of steps of each track. The minimum value allowed is 1.
tracks – The number of tracks to create and sequence. The minimum value allowed is 1.
bpm – The beats per minute of the timer.
- get_note(position: int, track: int = 0) tuple[int, int]
Get the note data for a specified track and step position. If a note isn’t defined at specific index, a value of
Nonewill be returned.- Parameters:
position – Index of the step (0-based). Will be limited to the track length.
track – Index of the track (0-based). Will be limited to the track count.
- Returns:
note data (notenum, velocity)
- get_track(track=0) list[tuple[int, int]]
Get list of note data for a specified track index (0-based). If the track isn’t available, a value of
Nonewill be returned.- Returns:
track data list of note tuples as (notenum, velocity)
- has_note(position: int, track: int = 0) bool
Check whether or note a specific step within a track has been set with note data.
- Parameters:
position – Index of the step (0-based). Will be limited to the track length.
track – Index of the track (0-based). Will be limited to the track count.
- Returns:
if the track step has a note
- property length: int
The number of steps for each track. If the length is shortened, all of the step data beyond the new length will be deleted and the
loop_startandloop_endproperties may be altered. If the sequencer is currently running, it should loop back around automatically to the start of the track data ifpositionis beyond the new value. The minimum length allowed is 1.
- property loop_end: int | None
The index of the sequence of which to loop back from when
positionreaches it. Should be a value betweenloop_start+ 1 andlength. If set asNone, this value will be ignored andlengthwill be used instead.
- property loop_start: int
The index of the sequence of which to begin at when looping back. This occurs when
positionreachesloop_end. Should be a value between 0 andloop_end- 1.
- on_loop: Callable[[int], None] = None
The callback method that is called when a the sequencer
positionreachesloop_endand begins back atloop_start. Must have 1 parameter for sequencer position index, typicallyloop_start. Ie:def loop(pos):.
- on_step: Callable[[int], None] = None
The callback method that is called when a step is triggered. This callback will fire whether or not the step has any notes. However, any pressed notes will occur before this callback is called. Must have 1 parameter for sequencer position index. Ie:
def step(pos):.
- remove_note(position: int, track: int = 0) None
Remove the note data as a specific step within a track.
- Parameters:
position – Index of the step (0-based). Will be limited to the track length.
track – Index of the track (0-based). Will be limited to the track count.
- set_note(position: int, notenum: int, velocity: float = 1.0, track: int = 0) None
Set the note value and velocity of a track at a specific step index.
- Parameters:
position – Index of the step (0-based). Will be limited to the track length.
notenum – Value of the note.
velocity – Velocity of the note (0.0-1.0).
track – Index of the track (0-based). Will be limited to the track count.
- class relic_keymanager.Timer(bpm: float = 120.0, steps: float = TimerStep.EIGHTH, gate: float = 0.5)
An abstract class to help handle timing functionality of the
ArpeggiatorandSequencerclasses. Note press and release timing is managed by bpm (beats per minute), steps (divisions of a beat), and gate (note duration during step).- Parameters:
bpm – The beats per minute of timer.
steps – The number of steps to divide a single beat. The minimum value allowed is 0.25, or a whole note.
gate – The duration of each pressed note per step to play before releasing as a ratio from 0.0 to 1.0.
- property gate: float
The duration each pressed note per step will play before releasing within a step of a beat as a ratio of that step from 0.0 to 1.0.
- on_enabled: Callable[[bool], None] = None
The callback method that is called when
activeis changed. Must have 1 parameter for the current active state. Ie:def enabled(active):
- on_press: Callable[[int, float], None] = None
The callback method that is called when a timed step note is pressed. Must have 2 parameters for note value and velocity (0.0-1.0). Ie:
def press(notenum, velocity):.
- on_release: Callable[[int], None] = None
The callback method that is called when a timed step note is released. Must have 1 parameter for note value. Velocity is always assumed to be 0.0. Ie:
def release(notenum):.
- on_step: Callable[[], None] = None
The callback method that is called when a step is triggered. This callback will fire whether or not the step has pressed any notes. However, any pressed notes will occur before this callback is called.
- property steps: float
The number of steps per beat (or the beat division). The minimum value allowed is 0.25, or a whole note. The pre-defined
TimerStepconstants can be used here.
- class relic_keymanager.TimerStep
An enum-like class representing common step divisions.
- class relic_keymanager.Voice(index: int)
Object which represents the parameters of a
Keyboardvoice. Used to allocateNoteobjects to a pre-defined number of available slots in a logical manner based on timing and keyboard mode.- Parameters:
index – The position of the voice in the pre-defined set of keyboard voices.
- property active: bool
The active state of the voice. Will return
Trueif a note has been assigned to this voice.