diff --git a/src/bin/piano_firmware.rs b/src/bin/piano_firmware.rs index 7a26ee8..472da3a 100644 --- a/src/bin/piano_firmware.rs +++ b/src/bin/piano_firmware.rs @@ -47,235 +47,400 @@ async fn piano_task(pin_driver: pins::TransparentPins) { // Notes for each key let keymap = [ [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, - ], - [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, - ], - [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, - ], - [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, + N1(GS5), + N1(AS5), + N1(C6), + NOP, + N1(F5), + NOP, + NOP, + N1(G5), + N1(A5), + N1(B5), + NOP, + NOP, + NOP, + NOP, + NOP, + N1(FS5), ], [ NOP, NOP, NOP, - N(A0, 64), + N1(F1), NOP, - N(CS1, 64), - N(B0, 64), + N1(A1), + N1(G1), NOP, NOP, NOP, - N(DS1, 64), - N(E1, 64), - N(C1, 64), - N(D1, 64), - N(AS0, 64), + N1(B1), + N1(C2), + N1(GS1), + N1(AS1), + N1(FS1), NOP, ], [ NOP, NOP, NOP, - N(F1, 64), + N1(A0), NOP, - N(A1, 64), - N(G1, 64), + N1(CS1), + N1(B0), NOP, NOP, NOP, - N(B1, 64), - N(C2, 64), - N(GS1, 64), - N(AS1, 64), - N(FS1, 64), - NOP, - ], - [ - N(GS5, 64), - N(AS5, 64), - N(C6, 64), - NOP, - N(F5, 64), - NOP, - NOP, - N(G5, 64), - N(A5, 64), - N(B5, 64), - NOP, - NOP, - NOP, - NOP, - NOP, - N(FS5, 64), - ], - [ - N(C7, 64), - N(D7, 64), - N(E7, 64), - NOP, - N(A6, 64), - NOP, - NOP, - N(B6, 64), - N(CS7, 64), - N(DS7, 64), - NOP, - NOP, - NOP, - NOP, - NOP, - N(AS6, 64), - ], - [ - N(E6, 64), - N(FS6, 64), - N(GS6, 64), - NOP, - N(CS6, 64), - NOP, - NOP, - N(DS6, 64), - N(F6, 64), - N(G6, 64), - NOP, - NOP, - NOP, - NOP, - NOP, - N(D6, 64), - ], - [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, - ], - [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, - ], - [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, - ], - [ - NOP, - NOP, - NOP, - N(A2, 64), - NOP, - N(CS3, 64), - N(B2, 64), - NOP, - NOP, - NOP, - N(DS3, 64), - N(E3, 64), - N(C3, 64), - N(D3, 64), - N(AS2, 64), - NOP, - ], - [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, - ], - [ - NOP, - NOP, - NOP, - N(A4, 64), - NOP, - N(CS5, 64), - N(B4, 64), - NOP, - NOP, - NOP, - N(DS5, 64), - N(E5, 64), - N(C5, 64), - N(D5, 64), - N(AS4, 64), + N1(DS1), + N1(E1), + N1(C1), + N1(D1), + N1(AS0), NOP, ], [ NOP, NOP, NOP, - N(F3, 64), + N1(CS2), NOP, - N(A3, 64), - N(G3, 64), + N1(F2), + N1(DS2), NOP, NOP, NOP, - N(B3, 64), - N(C4, 64), - N(GS3, 64), - N(AS3, 64), - N(FS3, 64), + N1(G2), + N1(GS2), + N1(E2), + N1(FS2), + N1(D2), NOP, ], [ NOP, NOP, NOP, - N(CS4, 64), + N2(A0), NOP, - N(F4, 64), - N(DS4, 64), + N2(CS1), + N2(B0), NOP, NOP, NOP, - N(G4, 64), - N(GS4, 64), - N(E4, 64), - N(FS4, 64), - N(D4, 64), + N2(DS1), + N2(E1), + N2(C1), + N2(D1), + N2(AS0), NOP, ], [ NOP, NOP, NOP, - N(CS2, 64), + N2(F1), NOP, - N(F2, 64), - N(DS2, 64), + N2(A1), + N2(G1), NOP, NOP, NOP, - N(G2, 64), - N(GS2, 64), - N(E2, 64), - N(FS2, 64), - N(D2, 64), + N2(B1), + N2(C2), + N2(GS1), + N2(AS1), + N2(FS1), NOP, ], [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, + N2(GS5), + N2(AS5), + N2(C6), + NOP, + N2(F5), + NOP, + NOP, + N2(G5), + N2(A5), + N2(B5), + NOP, + NOP, + NOP, + NOP, + NOP, + N2(FS5), ], [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, + N2(C7), + N2(D7), + N2(E7), + NOP, + N2(A6), + NOP, + NOP, + N2(B6), + N2(CS7), + N2(DS7), + NOP, + NOP, + NOP, + NOP, + NOP, + N2(AS6), ], [ - NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, + N2(E6), + N2(FS6), + N2(GS6), + NOP, + N2(CS6), + NOP, + NOP, + N2(DS6), + N2(F6), + N2(G6), + NOP, + NOP, + NOP, + NOP, + NOP, + N2(D6), ], [ - N(GS7, 64), - N(AS7, 64), - N(C8, 64), - NOP, - N(F7, 64), NOP, NOP, - N(G7, 64), - N(A7, 64), - N(B7, 64), + NOP, + N1(A2), + NOP, + N1(CS3), + N1(B2), + NOP, + NOP, + NOP, + N1(DS3), + N1(E3), + N1(C3), + N1(D3), + N1(AS2), + NOP, + ], + [ + NOP, + NOP, + NOP, + N1(CS4), + NOP, + N1(F4), + N1(DS4), + NOP, + NOP, + NOP, + N1(G4), + N1(GS4), + N1(E4), + N1(FS4), + N1(D4), + NOP, + ], + [ + NOP, + NOP, + NOP, + N1(F3), + NOP, + N1(A3), + N1(G3), + NOP, + NOP, + NOP, + N1(B3), + N1(C4), + N1(GS3), + N1(AS3), + N1(FS3), + NOP, + ], + [ + NOP, + NOP, + NOP, + N2(A2), + NOP, + N2(CS3), + N2(B2), + NOP, + NOP, + NOP, + N2(DS3), + N2(E3), + N2(C3), + N2(D3), + N2(AS2), + NOP, + ], + [ + NOP, + NOP, + NOP, + N1(A4), + NOP, + N1(CS5), + N1(B4), + NOP, + NOP, + NOP, + N1(DS5), + N1(E5), + N1(C5), + N1(D5), + N1(AS4), + NOP, + ], + [ + NOP, + NOP, + NOP, + N2(A4), + NOP, + N2(CS5), + N2(B4), + NOP, + NOP, + NOP, + N2(DS5), + N2(E5), + N2(C5), + N2(D5), + N2(AS4), + NOP, + ], + [ + NOP, + NOP, + NOP, + N2(F3), + NOP, + N2(A3), + N2(G3), + NOP, + NOP, + NOP, + N2(B3), + N2(C4), + N2(GS3), + N2(AS3), + N2(FS3), + NOP, + ], + [ + NOP, + NOP, + NOP, + N2(CS4), + NOP, + N2(F4), + N2(DS4), + NOP, + NOP, + NOP, + N2(G4), + N2(GS4), + N2(E4), + N2(FS4), + N2(D4), + NOP, + ], + [ + NOP, + NOP, + NOP, + N2(CS2), + NOP, + N2(F2), + N2(DS2), + NOP, + NOP, + NOP, + N2(G2), + N2(GS2), + N2(E2), + N2(FS2), + N2(D2), + NOP, + ], + [ + N1(E6), + N1(FS6), + N1(GS6), + NOP, + N1(CS6), + NOP, + NOP, + N1(DS6), + N1(F6), + N1(G6), NOP, NOP, NOP, NOP, NOP, - N(FS7, 64), + N1(D6), + ], + [ + N1(C7), + N1(D7), + N1(E7), + NOP, + N1(A6), + NOP, + NOP, + N1(B6), + N1(CS7), + N1(DS7), + NOP, + NOP, + NOP, + NOP, + NOP, + N1(AS6), + ], + [ + N1(GS7), + N1(AS7), + N1(C8), + NOP, + N1(F7), + NOP, + NOP, + N1(G7), + N1(A7), + N1(B7), + NOP, + NOP, + NOP, + NOP, + NOP, + N1(FS7), + ], + [ + N2(GS7), + N2(AS7), + N2(C8), + NOP, + N2(F7), + NOP, + NOP, + N2(G7), + N2(A7), + N2(B7), + NOP, + NOP, + NOP, + NOP, + NOP, + N2(FS7), ], ]; diff --git a/src/matrix.rs b/src/matrix.rs index 849f814..cd6c3fb 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -3,7 +3,7 @@ use crate::midi; use crate::pins; use crate::unwrap; -use core::cmp::min; +use core::cmp::{min}; use embassy_rp::gpio; use embassy_time::{Duration, Instant, Ticker}; @@ -56,7 +56,7 @@ impl KeyMatrix { // scan frequency // this might(?) panic if the scan takes longer than the tick - let mut ticker = Ticker::every(Duration::from_millis(13)); + let mut ticker = Ticker::every(Duration::from_millis(8)); let chan = midi::MidiChannel::new(0); const MAX_NOTES: usize = 128; @@ -66,7 +66,14 @@ impl KeyMatrix { // (for velocity detection) moment key is first touched let mut note_first: [Option; MAX_NOTES] = [None; MAX_NOTES]; + let mut counter = 0; + loop { + counter += 1; + counter %= 50; + let profile = counter == 0; + let prof_start = Instant::now(); + for (i, col) in self.col_pins.iter().enumerate() { unwrap(pin_driver.set_output(*col)).await; let input = unwrap(pin_driver.read_all()).await; @@ -79,11 +86,12 @@ impl KeyMatrix { let key_active = mask & (1 << row) != 0; match key_action { midi::KeyAction::N1(note) => { - if !note_on[note as usize] - && note_first[note as usize].is_none() - && key_active - { - note_first[note as usize] = Some(Instant::now()); + if key_active { + if note_first[note as usize].is_none() { + note_first[note as usize] = Some(Instant::now()); + } + } else if note_first[note as usize].is_some() { + note_first[note as usize] = None; } } midi::KeyAction::N2(note) => { @@ -92,15 +100,17 @@ impl KeyMatrix { // millisecond duration of keypress let dur = note_first[note as usize].unwrap().elapsed().as_millis(); - // 1905 millis is the minimum velocity - let velocity: u8 = 127 - min(dur / 15, 127) as u8; - note_first[note as usize] = None; + let velocity: u8 = if dur <= 80 { + (127 - dur) as u8 + } else { + (127 - min(dur, 250) / 5 - 70) as u8 + }; + log::debug!("{note:?} velocity {velocity} from dur {dur}ms"); note_on[note as usize] = true; chan.note_on(note, velocity).await; } } else if note_on[note as usize] { note_on[note as usize] = false; - note_first[note as usize] = None; chan.note_off(note, 0).await; } } @@ -114,11 +124,15 @@ impl KeyMatrix { note_on[note as usize] = false; chan.note_off(note, 0).await; } - }, - midi::KeyAction::NOP => {}, + } + midi::KeyAction::NOP => {} } } } + + if profile { + log::trace!("profile: scan took {}ms", prof_start.elapsed().as_millis()) + } ticker.next().await; } } diff --git a/src/midi/keymap.py b/src/midi/keymap.py index a48d462..f911d0c 100644 --- a/src/midi/keymap.py +++ b/src/midi/keymap.py @@ -12,6 +12,7 @@ Use cargo fmt to de-messify the output once pasted in the source. """ from dataclasses import dataclass +import sys @dataclass @@ -62,7 +63,7 @@ for col in mat: print(f"[{', '.join(col)}],") print("]") -print(f"{len(row_pins)} rows, {len(col_pins)} cols") -print(f"row pins: [{', '.join([str(i) for i in row_pins])}]") -print(f"col pins: [{', '.join([str(i) for i in col_pins])}]") -print(f"{empty_counter} empty cells") +print(f"{len(row_pins)} rows, {len(col_pins)} cols", file=sys.stderr) +print(f"row pins: [{', '.join([str(i) for i in row_pins])}]", file=sys.stderr) +print(f"col pins: [{', '.join([str(i) for i in col_pins])}]", file=sys.stderr) +print(f"{empty_counter} empty cells", file=sys.stderr) diff --git a/src/midi/mod.rs b/src/midi/mod.rs index b8acde4..f25a6d6 100644 --- a/src/midi/mod.rs +++ b/src/midi/mod.rs @@ -86,7 +86,7 @@ impl MidiMsg { /// Note identifiers /// /// See src/midi/note_def.py for how this is generated -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum Note { A0 = 21, AS0 = 22,