From 6cf07c3c5de258b96d89482cd13458944461190b Mon Sep 17 00:00:00 2001 From: Charlotte McElwain Date: Sun, 4 Feb 2024 08:59:29 -0800 Subject: [PATCH] Add monome grid chop. --- Cargo.lock | 9 +++ Cargo.toml | 1 + plugins/chop/monome-grid/Cargo.toml | 16 ++++ plugins/chop/monome-grid/src/lib.rs | 118 ++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 plugins/chop/monome-grid/Cargo.toml create mode 100644 plugins/chop/monome-grid/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 7d08ed5..5bc4c86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2230,6 +2230,15 @@ dependencies = [ "ws2_32-sys", ] +[[package]] +name = "monome-grid" +version = "0.1.0" +dependencies = [ + "monome-rs", + "td-rs-chop", + "td-rs-derive", +] + [[package]] name = "monome-rs" version = "1.1.3" diff --git a/Cargo.toml b/Cargo.toml index 314e365..401acdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "plugins/chop/euro-filter", "plugins/chop/filter", "plugins/chop/generator", + "plugins/chop/monome-grid", "plugins/chop/python", "plugins/chop/wasm", "plugins/dat/filter", diff --git a/plugins/chop/monome-grid/Cargo.toml b/plugins/chop/monome-grid/Cargo.toml new file mode 100644 index 0000000..2785081 --- /dev/null +++ b/plugins/chop/monome-grid/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "monome-grid" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "chop" + +[lib] +name = "monome_grid" +crate-type = ["staticlib"] + +[dependencies] +td-rs-chop = { path = "../../../td-rs-chop" } +td-rs-derive = { path = "../../../td-rs-derive" } +monome-rs = "1.1.3" \ No newline at end of file diff --git a/plugins/chop/monome-grid/src/lib.rs b/plugins/chop/monome-grid/src/lib.rs new file mode 100644 index 0000000..17513c6 --- /dev/null +++ b/plugins/chop/monome-grid/src/lib.rs @@ -0,0 +1,118 @@ +use monome::{KeyDirection, Monome, MonomeDevice, MonomeEvent}; +use td_rs_chop::*; +use td_rs_derive::{Param, Params}; + +#[derive(Param, Default, Clone, Debug)] +enum Operation { + #[default] + Add, + Multiply, + Power, +} + +#[derive(Params, Default, Clone, Debug, Eq, PartialEq)] +struct MonomeGridParams { + #[param(label = "Prefix", page = "Grid", default = "/touchdesigner")] + prefix: String, + #[param(label = "Hold", page = "Grid")] + hold: bool, +} + +/// Struct representing our CHOP's state +#[derive(Debug)] +pub struct MonomeGrid { + params: MonomeGridParams, + prev_params: MonomeGridParams, + device: Option, + grid: [bool; 128], +} + +/// Impl block providing default constructor for plugin +impl OpNew for MonomeGrid { + fn new(_info: NodeInfo) -> Self { + Self { + params: MonomeGridParams { + prefix: "/touchdesigner".to_string(), + hold: false, + }, + prev_params: Default::default(), + device: None, + grid: [false; 128], + } + } +} + +impl OpInfo for MonomeGrid { + const OPERATOR_LABEL: &'static str = "Monome Grid"; + const OPERATOR_TYPE: &'static str = "Monomegrid"; +} + +impl Op for MonomeGrid { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } +} + +impl Chop for MonomeGrid { + fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { + if self.params != self.prev_params || self.device.is_none() { + self.prev_params = self.params.clone(); + let device = match Monome::new(&self.params.prefix) { + Ok(device) => device, + Err(err) => { + self.set_error(&format!("Error connecting to monome: {}", err)); + return; + } + }; + self.device = Some(device); + } + + if let Some(ref mut device) = &mut self.device { + while let Some(event) = device.poll() { + match event { + MonomeEvent::GridKey { x, y, direction, } => { + let index = (y * 16 + x) as usize; + if self.params.hold { + if matches!(direction, KeyDirection::Down) { + self.grid[index] = !self.grid[index]; + } + } else { + self.grid[index] = !self.grid[index]; + } + } + _ => {} + } + } + + device.set_all(&self.grid); + } + + for i in 0..output.num_channels() { + output[i][0] = if self.grid[i] { 1.0 } else { 0.0 }; + } + } + + fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { + ChopGeneralInfo { + cook_every_frame: true, + cook_every_frame_if_asked: true, + timeslice: false, + input_match_index: 0, + } + } + + fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { + format!("grid{}", index) + } + + fn output_info(&self, _inputs: &OperatorInputs) -> Option { + Some(ChopOutputInfo { + num_channels: 128, + num_samples: 1, + start_index: 0, + ..Default::default() + }) + } +} + +chop_plugin!(MonomeGrid);