pm-grid: swap X/Y tempo buttons + full-screen strobe on the downbeat

- Swap X/Y: X now tempo-up, Y tempo-down (match the physical Scroll Pack layout).
- On the master lane's step 0 (the '1'), flash the entire 17x7 matrix at full
  brightness for 80ms — a visual downbeat strobe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Me Here 2026-06-03 14:52:04 -05:00
parent 86cd4a0242
commit e46ff02c0c

View file

@ -145,6 +145,12 @@ impl<I: I2c> Matrix<I> {
} }
} }
fn fill(&mut self, v: u8) {
for b in self.fb[1..].iter_mut() {
*b = v;
}
}
fn get(&self, x: i32, y: i32) -> u8 { fn get(&self, x: i32, y: i32) -> u8 {
if (0..17).contains(&x) && (0..7).contains(&y) { if (0..17).contains(&x) && (0..7).contains(&y) {
self.fb[1 + pixel_addr(x, y)] self.fb[1 + pixel_addr(x, y)]
@ -238,7 +244,8 @@ struct App {
scroll_total: i32, scroll_total: i32,
beatflash: u8, beatflash: u8,
beatflash_off: i64, beatflash_off: i64,
bpm_flash_off: i64, // while >0 and active, Grid/Pendulum briefly show the Ticker so nudges are visible bpm_flash_off: i64, // while >0 and active, Grid/Pendulum briefly show the Ticker so nudges are visible
full_flash_off: i64, // strobe the WHOLE matrix bright on the downbeat ("the 1")
} }
fn master_bar_ns(track: &track_format::Track, tempo: i64) -> i64 { fn master_bar_ns(track: &track_format::Track, tempo: i64) -> i64 {
@ -294,6 +301,7 @@ impl App {
beatflash: 0, beatflash: 0,
beatflash_off: 0, beatflash_off: 0,
bpm_flash_off: 0, bpm_flash_off: 0,
full_flash_off: 0,
}; };
app.load(0, 0, now_ns); app.load(0, 0, now_ns);
app app
@ -405,6 +413,10 @@ impl App {
while now_ns >= self.next[li] { while now_ns >= self.next[li] {
self.step[li] = (self.step[li] + 1) % steps; self.step[li] = (self.step[li] + 1) % steps;
if li == 0 { if li == 0 {
if self.step[li] == 0 {
// the downbeat — strobe the entire matrix bright
self.full_flash_off = now_ns + 80_000_000;
}
self.m_steps += 1; self.m_steps += 1;
let bar = (self.m_steps - 1) / steps as i64; let bar = (self.m_steps - 1) / steps as i64;
if bar != self.lastbar { if bar != self.lastbar {
@ -458,6 +470,12 @@ fn lvl_bright(lvl: u8) -> u8 {
// ============================== RENDERING ============================== // ============================== RENDERING ==============================
fn render<I: I2c>(m: &mut Matrix<I>, app: &App, now_ns: i64) { fn render<I: I2c>(m: &mut Matrix<I>, app: &App, now_ns: i64) {
// downbeat strobe: the whole matrix at full brightness on "the 1"
if now_ns < app.full_flash_off {
m.fill(255);
m.show();
return;
}
m.clear(); m.clear();
// a tempo nudge briefly forces the Ticker (so X/Y is visible from Grid/Pendulum) // a tempo nudge briefly forces the Ticker (so X/Y is visible from Grid/Pendulum)
let view = if app.view != View::Ticker && now_ns < app.bpm_flash_off { let view = if app.view != View::Ticker && now_ns < app.bpm_flash_off {
@ -708,24 +726,24 @@ fn main() -> ! {
app.next_track(now_ns); app.next_track(now_ns);
} }
} }
// X: tempo down (tap -1, auto-repeat; -5 after 1.5s held) // X: tempo up (tap +1, auto-repeat; +5 after 1.5s held) [X/Y swapped per hardware layout]
if x && !px { if x && !px {
held_x = us; held_x = us;
nextrep_x = us + 350_000; nextrep_x = us + 350_000;
app.set_bpm(app.tempo - 1, now_ns); app.set_bpm(app.tempo + 1, now_ns);
} else if x && px && us >= nextrep_x { } else if x && px && us >= nextrep_x {
nextrep_x = us + 120_000; nextrep_x = us + 120_000;
let d = if us - held_x > 1_500_000 { -5 } else { -1 }; let d = if us - held_x > 1_500_000 { 5 } else { 1 };
app.set_bpm(app.tempo + d, now_ns); app.set_bpm(app.tempo + d, now_ns);
} }
// Y: tempo up // Y: tempo down
if y && !py { if y && !py {
held_y = us; held_y = us;
nextrep_y = us + 350_000; nextrep_y = us + 350_000;
app.set_bpm(app.tempo + 1, now_ns); app.set_bpm(app.tempo - 1, now_ns);
} else if y && py && us >= nextrep_y { } else if y && py && us >= nextrep_y {
nextrep_y = us + 120_000; nextrep_y = us + 120_000;
let d = if us - held_y > 1_500_000 { 5 } else { 1 }; let d = if us - held_y > 1_500_000 { -5 } else { -1 };
app.set_bpm(app.tempo + d, now_ns); app.set_bpm(app.tempo + d, now_ns);
} }
pa = a; pa = a;