diff --git a/src/config.rs b/src/config.rs index bb7da1c..be9da5c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,3 +4,9 @@ pub const SAMP_RATE: f32 = 48000.0; // samples read from stdin per update pub const SAMPLES_PER_UPDATE: usize = BLOCK_LEN/2; + +// LED configuration +pub const NUM_STRIPS: usize = 8; +pub const NUM_LEDS_PER_STRIP: usize = 16; + +pub const NUM_LEDS_TOTAL: usize = NUM_STRIPS * NUM_LEDS_PER_STRIP; diff --git a/src/main.rs b/src/main.rs index 2632fd3..9772e51 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,30 +5,30 @@ use std::collections::VecDeque; use byteorder::{NativeEndian, ReadBytesExt}; -use mlua::Lua; - mod signal_processing; mod config; +mod userscript; use crate::signal_processing::SignalProcessing; +use crate::userscript::UserScript; fn main() { let mut stdin = std::io::stdin(); - // test the mlua crate - let lua_state = Lua::new(); + // set up Lua environment - lua_state.globals().set("get_rust_value", lua_state.create_function(|_, ()| { - Ok(3) - }).unwrap()).unwrap(); + println!("Loading user script..."); - let user_script = std::fs::read_to_string("test.lua").unwrap(); - lua_state.load(&user_script).exec().unwrap(); + let script = UserScript::new("test.lua").unwrap(); - let lua_func_test : mlua::Function = lua_state.globals().get("test").unwrap(); + println!("Calling init()..."); - println!("{}", lua_func_test.call::<_, u32>(123).unwrap()); + script.init().unwrap(); + + // set up signal processing + + println!("Initializing signal processing..."); let mut sigproc = SignalProcessing::new(config::BLOCK_LEN, config::SAMP_RATE).unwrap(); @@ -75,7 +75,10 @@ fn main() let energy_treble = sigproc.get_energy_in_band(4000.0, config::SAMP_RATE/2.0); // dump the output - println!("Bass: {:8.2} – Mid: {:8.2} – Treble: {:8.2}", energy_bass, energy_mid, energy_treble); + println!("Bass: {:11.2} – Mid: {:11.2} – Treble: {:11.2}", energy_bass, energy_mid, energy_treble); + + // call the periodic function in the user script + script.periodic().unwrap(); } } diff --git a/src/userscript.rs b/src/userscript.rs new file mode 100644 index 0000000..7603b8b --- /dev/null +++ b/src/userscript.rs @@ -0,0 +1,95 @@ +// vim: noet + +/* + * Module for the Lua scripting interface of Musiclight. + */ + +/* Test code for reference + // test the mlua crate + let lua_state = Lua::new(); + + lua_state.globals().set("get_rust_value", lua_state.create_function(|_, ()| { + Ok(3) + }).unwrap()).unwrap(); + + let user_script = std::fs::read_to_string("test.lua").unwrap(); + lua_state.load(&user_script).exec().unwrap(); + + let lua_func_test : mlua::Function = lua_state.globals().get("test").unwrap(); + + println!("{}", lua_func_test.call::<_, u32>(123).unwrap()); +*/ + +use crate::config; + +use mlua::Lua; +use mlua::FromLua; +use mlua::Error; + +pub struct UserScript +{ + lua_state: Lua, +} + +impl UserScript +{ + pub fn new(user_script_path: &str) -> std::result::Result + { + let s = UserScript { + lua_state: Lua::new(), + }; + + // load the user script and execute it to make variables and functions available + let user_script = std::fs::read_to_string(user_script_path)?; + s.lua_state.load(&user_script).exec()?; + + Ok(s) + } + + pub fn init(&self) -> std::result::Result<(), mlua::Error> + { + // find the init functions + let lua_init_func: mlua::Function = self.lua_state.globals().get("init")?; + + lua_init_func.call( (config::NUM_STRIPS, config::NUM_LEDS_PER_STRIP) )?; + + Ok(()) + } + + pub fn periodic(&self) -> std::result::Result<(), mlua::Error> + { + // find the init functions + let lua_periodic_func: mlua::Function = self.lua_state.globals().get("periodic")?; + + // call the script's periodic() function, which (hopefully) returns four Tables with color + // values + let rvals = lua_periodic_func.call::<_, mlua::MultiValue>( () )?; + + // check the number of returned values + if rvals.len() != 4 { + return Err(Error::RuntimeError("Wrong number of return values from 'periodic'. Expected 4.".to_string())); + } + + // convert the Lua Tables to normal vectors + let mut colorlists = Vec::>::new(); + + for rval in rvals { + let table = mlua::Table::from_lua(rval, &self.lua_state)?; + + let v = table.sequence_values() + .map(|x| x.unwrap()) + .collect::>(); + + // check the length of the color array + if v.len() != config::NUM_LEDS_TOTAL { + return Err(Error::RuntimeError("Number of color values returned from 'periodic' must match number of LEDs given in 'init'.".to_string())); + } + + colorlists.push(v); + } + + println!("{:?}", colorlists[0][0]); + + Ok(()) + } +} diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..c486336 --- /dev/null +++ b/test.lua @@ -0,0 +1,25 @@ +function init(nstrip, nmod) + print("Initializing with "..nstrip.." strips with "..nmod.." modules each.") + + local nled = nstrip * nmod + + red = {} + green = {} + blue = {} + white = {} + + + for i = 1,nled do + red[i] = 0.8 + green[i] = 0.1 + blue[i] = 0.2 + white[i] = 0.1 + end + + return 0 +end + +function periodic() + print("Going round and round...") + return red, green, blue, white +end