subsequence.display¶
Live terminal dashboard for composition playback.
Provides a persistent status line showing the current bar, section, chord, BPM, and key. Optionally renders an ASCII grid visualisation of all running patterns above the status line, showing which steps have notes and at what velocity.
Log messages scroll above the dashboard without disruption.
Enable it with a single call before play():
composition.display() # status line only
composition.display(grid=True) # status line + pattern grid
composition.play()
The status line updates every beat and looks like:
125 BPM Key: E Bar: 17 [chorus 1/8] Chord: Em7
The grid (when enabled) updates every bar and looks like:
kick_2 |X . . . X . . . X . . . X . . .|
snare_1 |. . . . X . . . . . . . X . . .|
bass |X . . X . . X . X . . . X . . .|
Module Contents¶
- class subsequence.display.Display(composition: subsequence.composition.Composition, grid: bool = False, grid_scale: float = 1.0)[source]¶
Live-updating terminal dashboard showing composition state.
Reads bar, section, chord, BPM, and key from the
Compositionand renders a persistent region to stderr. Whengrid=Truean ASCII pattern grid is rendered above the status line. A customDisplayLogHandlerensures log messages scroll cleanly above the dashboard.Example
composition.display(grid=True) composition.play()
Store composition reference for reading playback state.
- Parameters:
composition – The
Compositioninstance to read state from.grid – When True, render an ASCII grid of running patterns above the status line.
grid_scale – Horizontal zoom factor for the grid (default
1.0). Snapped internally to the nearest integercols_per_stepfor uniform marker spacing.
- start() None[source]¶
Install the log handler and activate the display.
Saves existing root logger handlers and replaces them with a
DisplayLogHandlerthat clears/redraws the status line around each log message. Original handlers are restored bystop().
- update(_: int = 0) None[source]¶
Rebuild and redraw the dashboard; called on
"bar"and"beat"events.The integer argument (bar or beat number) is ignored — state is read directly from the composition.
Note: “bar” and “beat” events are emitted as
asyncio.create_taskat the start of each pulse, but the tasks only execute after_advance_pulse()completes (which includes sending MIDI via_process_pulse()). The display therefore always trails the audio slightly — this is inherent to the architecture and cannot be avoided without restructuring the sequencer loop.
- class subsequence.display.DisplayLogHandler(display: Display)[source]¶
Bases:
logging.HandlerLogging handler that clears and redraws the status line around log output.
Installed by
Display.start()and removed byDisplay.stop(). Ensures log messages do not overwrite or corrupt the persistent status line.Store reference to the display for clear/redraw calls.
- emit(record: logging.LogRecord) None[source]¶
Clear the status line, write the log message, then redraw.
- class subsequence.display.GridDisplay(composition: subsequence.composition.Composition, scale: float = 1.0)[source]¶
Multi-line ASCII grid visualisation of running pattern steps.
Renders one block per pattern showing which grid steps have notes and at what velocity. Drum patterns (those with a
drum_note_map) show one row per drum sound; pitched patterns show a single summary row.Not used directly — instantiated by
Displaywhengrid=True.Store composition reference for reading pattern state.
- Parameters:
composition – The
Compositioninstance to read running patterns from.scale – Horizontal zoom factor. Snapped to the nearest integer
cols_per_stepso that all on-grid markers are uniformly spaced. Default1.0= one visual column per grid step (current behaviour).