use crate::event::NoteEvent;
use crate::tree::Tree;
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Grid {
pub rows: u32,
pub columns: u32,
pub cells: Vec<Option<NoteEvent>>,
}
impl Grid {
pub fn new(rows: u32, columns: u32) -> Self {
let size = (rows * columns) as usize;
Self {
rows,
columns,
cells: vec![None; size],
}
}
fn idx(&self, row: u32, col: u32) -> usize {
(row * self.columns + col) as usize
}
pub fn get(&self, row: u32, col: u32) -> Option<&NoteEvent> {
self.cells[self.idx(row, col)].as_ref()
}
pub fn set(&mut self, row: u32, col: u32, event: Option<NoteEvent>) {
let idx = self.idx(row, col);
self.cells[idx] = event;
}
pub fn to_tree(&self) -> Tree<NoteEvent> {
let row_trees: Vec<Tree<NoteEvent>> = (0..self.rows)
.map(|row| {
let events: Vec<Tree<NoteEvent>> = (0..self.columns)
.filter_map(|col| self.get(row, col).map(|e| Tree::leaf(e.clone())))
.collect();
match events.len() {
0 => Tree::rest(),
1 => events.into_iter().next().unwrap(),
_ => Tree::par(events),
}
})
.collect();
Tree::seq(row_trees)
}
pub fn from_tree(tree: &Tree<NoteEvent>, rows: u32, columns: u32) -> Self {
let mut grid = Self::new(rows, columns);
let flat = tree.flatten();
for fe in &flat {
let row_f = fe.start.to_f64() * rows as f64;
let row = (row_f.round() as u32).min(rows - 1);
for col in 0..columns {
if grid.get(row, col).is_none() {
grid.set(row, col, Some(fe.event.clone()));
break;
}
}
}
grid
}
pub fn count_events(&self) -> usize {
self.cells.iter().filter(|c| c.is_some()).count()
}
pub fn row_has_events(&self, row: u32) -> bool {
(0..self.columns).any(|col| self.get(row, col).is_some())
}
pub fn shift_voice(&mut self, col: u32, offset: i32) {
let n = self.rows as i32;
if n == 0 {
return;
}
let old: Vec<Option<NoteEvent>> =
(0..self.rows).map(|r| self.get(r, col).cloned()).collect();
for row in 0..self.rows {
let src = (row as i32 - offset).rem_euclid(n) as u32;
self.set(row, col, old[src as usize].clone());
}
}
pub fn reverse_voice(&mut self, col: u32) {
let n = self.rows;
for i in 0..n / 2 {
let j = n - 1 - i;
let a = self.get(i, col).cloned();
let b = self.get(j, col).cloned();
self.set(i, col, b);
self.set(j, col, a);
}
}
pub fn clear_voice(&mut self, col: u32) {
for row in 0..self.rows {
self.set(row, col, None);
}
}
pub fn fill_euclidean(&mut self, col: u32, pattern: &[bool], template: NoteEvent) {
for (i, &hit) in pattern.iter().enumerate().take(self.rows as usize) {
self.set(
i as u32,
col,
if hit { Some(template.clone()) } else { None },
);
}
}
pub fn column_tree(&self, col: u32) -> Tree<NoteEvent> {
let rows: Vec<Tree<NoteEvent>> = (0..self.rows)
.map(|row| match self.get(row, col) {
Some(e) => Tree::leaf(e.clone()),
None => Tree::rest(),
})
.collect();
Tree::seq(rows)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::math::Rational;
#[test]
fn roundtrip_simple() {
let mut grid = Grid::new(4, 1);
grid.set(0, 0, Some(NoteEvent::simple(0)));
grid.set(2, 0, Some(NoteEvent::simple(4)));
let tree = grid.to_tree();
assert_eq!(tree.count_leaves(), 2);
let grid2 = Grid::from_tree(&tree, 4, 1);
assert_eq!(grid2.count_events(), 2);
assert!(grid2.get(0, 0).is_some());
assert!(grid2.get(2, 0).is_some());
}
#[test]
fn polyphony() {
let mut grid = Grid::new(4, 2);
grid.set(0, 0, Some(NoteEvent::simple(0)));
grid.set(0, 1, Some(NoteEvent::simple(4)));
let tree = grid.to_tree();
let flat = tree.flatten();
let row0_events: Vec<_> = flat
.iter()
.filter(|fe| fe.start == Rational::zero())
.collect();
assert_eq!(row0_events.len(), 2);
}
}