pm-grid Ticker: top-row beat strip + shift name down a row

Free the top row for a beat indicator: faint ticks at each beat (every sub steps)
across cols 0-10 with a bright playhead at the master lane's current step. The
scrolling name moves down to rows 2-6 (row 1 = separator). BPM block unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Me Here 2026-06-03 14:57:45 -05:00
parent e46ff02c0c
commit 512890baa2
2 changed files with 26 additions and 10 deletions

View file

@ -160,11 +160,12 @@ CircuitPython `Matrix`; per-pixel I²C is too slow to animate), the **polymeter
`track-format::schedule::lane_durs` (the cross-impl contract) with per-lane step clocks + ramp + `track-format::schedule::lane_durs` (the cross-impl contract) with per-lane step clocks + ramp +
gap-trainer, **4-button input** (A tap=play/stop, hold=cycle view; B tap=next track, hold=next set gap-trainer, **4-button input** (A tap=play/stop, hold=cycle view; B tap=next track, hold=next set
list; X/Y=tempo ∓ with auto-repeat), the **built-in set lists**, and three LED views: list; X/Y=tempo ∓ with auto-repeat), the **built-in set lists**, and three LED views:
- **Ticker** (default): track name infinite-scrolls across the left (cols 010, full height); BPM is - **Ticker** (default): a **beat strip** on the top row (cols 010) — faint ticks at each beat + a
pinned right, **rotated 90° CCW** — a vertical hundreds **dot-bar** in col 11 (one dot per 100) + bright playhead at the master lane's current step; the track name infinite-scrolls below it (cols
the last two digits rotated into cols 1216 (tens bottom, units top). So `130` → 1 dot + rotated 010, rows 26); BPM is pinned right, **rotated 90° CCW** — a vertical hundreds **dot-bar** in col
"30". This is the user-designed landscape readout. Rotation/geometry verified off-bench with an 11 (one dot per 100) + the last two digits rotated into cols 1216 (tens bottom, units top). So
ASCII replica of `draw_ticker`. `130` → 1 dot + rotated "30". This is the user-designed landscape readout. Layout/rotation verified
off-bench with an ASCII replica of `draw_ticker`. Whole matrix strobes white on the downbeat.
- **Grid** (lanes×steps + playhead) and **Pendulum** (bouncing arm + beat ticks) — ports of - **Grid** (lanes×steps + playhead) and **Pendulum** (bouncing arm + beat ticks) — ports of
`_render_grid` / `_render_pendulum`. `_render_grid` / `_render_pendulum`.
Boot splash scrolls "PM-G1 GRID" (liveness + pixel-map check). Boot splash scrolls "PM-G1 GRID" (liveness + pixel-map check).

View file

@ -491,11 +491,26 @@ fn render<I: I2c>(m: &mut Matrix<I>, app: &App, now_ns: i64) {
m.show(); m.show();
} }
/// Ticker: track name infinite-scrolls across the left (cols 0..=10, full height), BPM is pinned to /// Ticker: a beat strip runs along the top row (cols 0..=10); the track name infinite-scrolls below
/// the right rotated 90° CCW — a vertical "hundreds dot-bar" in col 11 (one dot per 100) plus the /// it (cols 0..=10, rows 2..=6); BPM is pinned to the right rotated 90° CCW — a vertical "hundreds
/// last two digits rotated into cols 12..=16 (tens at the bottom, units on top; reads bottom→top). /// dot-bar" in col 11 (one dot per 100) plus the last two digits rotated into cols 12..=16 (tens at
/// the bottom, units on top; reads bottom→top).
fn draw_ticker<I: I2c>(m: &mut Matrix<I>, app: &App) { fn draw_ticker<I: I2c>(m: &mut Matrix<I>, app: &App) {
// scrolling name on rows 1..=5 // top-row beat strip (cols 0..=10): faint marks at each beat (every `sub` steps), a bright
// playhead at the master lane's current step — spread across the full name-region width.
if let Some(master) = app.track.lanes.first() {
let steps = master.levels.len().max(1) as i32;
let sub = master.sub.max(1) as i32;
for s in 0..steps {
if s % sub == 0 {
m.set_max(s * 11 / steps, 0, 24); // beat tick
}
}
if app.playing && app.step[0] >= 0 {
m.set(app.step[0] * 11 / steps, 0, 255); // live playhead
}
}
// scrolling name on rows 2..=6 (shifted down one to clear the beat strip)
let total = app.scroll_total.max(1); let total = app.scroll_total.max(1);
for sx in 0..=10i32 { for sx in 0..=10i32 {
let i = ((app.scroll_off + sx) % total + total) % total; let i = ((app.scroll_off + sx) % total + total) % total;
@ -506,7 +521,7 @@ fn draw_ticker<I: I2c>(m: &mut Matrix<I>, app: &App) {
}; };
for r in 0..5i32 { for r in 0..5i32 {
if colbits & (1 << r) != 0 { if colbits & (1 << r) != 0 {
m.set(sx, 1 + r, NAME_BRIGHT); m.set(sx, 2 + r, NAME_BRIGHT);
} }
} }
} }