131 lines
3.9 KiB
Rust
131 lines
3.9 KiB
Rust
use crate::*;
|
|
|
|
#[derive(Clone, Debug, PartialEq, strum::Display, strum::EnumString)]
|
|
pub enum TrackState {
|
|
Empty,
|
|
Idle,
|
|
Playing,
|
|
Recording,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Track {
|
|
pub state: TrackState,
|
|
pub volume: f32,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct State {
|
|
pub selected_column: usize, // 0-based (converted to 1-based for OSC)
|
|
pub selected_row: usize, // 0-based (converted to 1-based for OSC)
|
|
pub cells: Vec<Vec<Track>>,
|
|
pub columns: usize,
|
|
pub rows: usize,
|
|
pub metronome_position: f32, // 0.0 - 1.0 position within current beat
|
|
pub metronome_timestamp: std::time::Instant, // When position was last updated
|
|
}
|
|
|
|
impl State {
|
|
pub fn new(columns: usize, rows: usize) -> Self {
|
|
let cells = (0..columns)
|
|
.map(|_| vec![Track { state: TrackState::Empty, volume: 1.0 }; rows])
|
|
.collect();
|
|
|
|
Self {
|
|
selected_column: 0,
|
|
selected_row: 0,
|
|
cells,
|
|
columns,
|
|
rows,
|
|
metronome_position: 0.0,
|
|
metronome_timestamp: std::time::Instant::now(),
|
|
}
|
|
}
|
|
|
|
pub fn update(&mut self, message: &Message) {
|
|
match message {
|
|
Message::TrackStateChanged { column, row, state } => {
|
|
if *column < self.columns && *row < self.rows {
|
|
self.cells[*column][*row].state = state.clone();
|
|
}
|
|
}
|
|
Message::TrackVolumeChanged { column, row, volume } => {
|
|
if *column < self.columns && *row < self.rows {
|
|
self.cells[*column][*row].volume = *volume;
|
|
}
|
|
}
|
|
Message::SelectedColumnChanged { column } => {
|
|
if *column < self.columns {
|
|
self.selected_column = *column;
|
|
}
|
|
}
|
|
Message::SelectedRowChanged { row } => {
|
|
if *row < self.rows {
|
|
self.selected_row = *row;
|
|
}
|
|
}
|
|
Message::MetronomePosition { position } => {
|
|
self.set_metronome_position(*position);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn create_state_dump(&self) -> Vec<Message> {
|
|
let mut messages = Vec::new();
|
|
|
|
// Send current selections
|
|
messages.push(Message::SelectedColumnChanged {
|
|
column: self.selected_column,
|
|
});
|
|
messages.push(Message::SelectedRowChanged {
|
|
row: self.selected_row,
|
|
});
|
|
|
|
// Send all cell states and volumes
|
|
for (column, column_cells) in self.cells.iter().enumerate() {
|
|
for (row, track) in column_cells.iter().enumerate() {
|
|
messages.push(Message::TrackStateChanged {
|
|
column,
|
|
row,
|
|
state: track.state.clone(),
|
|
});
|
|
messages.push(Message::TrackVolumeChanged {
|
|
column,
|
|
row,
|
|
volume: track.volume,
|
|
});
|
|
}
|
|
}
|
|
|
|
messages
|
|
}
|
|
|
|
pub fn set_track_state(&mut self, column: usize, row: usize, state: TrackState) {
|
|
if column < self.columns && row < self.rows {
|
|
self.cells[column][row].state = state;
|
|
}
|
|
}
|
|
|
|
pub fn set_selected_column(&mut self, column: usize) {
|
|
if column < self.columns {
|
|
self.selected_column = column;
|
|
}
|
|
}
|
|
|
|
pub fn set_selected_row(&mut self, row: usize) {
|
|
if row < self.rows {
|
|
self.selected_row = row;
|
|
}
|
|
}
|
|
|
|
pub fn set_track_volume(&mut self, column: usize, row: usize, volume: f32) {
|
|
if column < self.columns && row < self.rows {
|
|
self.cells[column][row].volume = volume;
|
|
}
|
|
}
|
|
|
|
pub fn set_metronome_position(&mut self, position: f32) {
|
|
self.metronome_position = position;
|
|
self.metronome_timestamp = std::time::Instant::now();
|
|
}
|
|
} |