Provide SignalProcessing methods to the Lua script

This is accomplished by providing a wrapped reference to the
SignalProcessing instance of the Rust program as a global Lua variable.
The wrapper class implements mlua::UserData, wraps the relevant
SignalProcessing methods and provides them as Lua methods.

So far, this is implemented for get_energy_in_band() only.
This commit is contained in:
Thomas Kolb 2021-02-20 21:47:30 +01:00
parent 62bbff481c
commit 864add8403
2 changed files with 62 additions and 17 deletions

View file

@ -12,25 +12,29 @@ mod userscript;
use crate::signal_processing::SignalProcessing; use crate::signal_processing::SignalProcessing;
use crate::userscript::UserScript; use crate::userscript::UserScript;
use std::rc::Rc;
use std::cell::RefCell;
fn main() fn main()
{ {
let mut stdin = std::io::stdin(); let mut stdin = std::io::stdin();
// set up Lua environment
println!("Loading user script...");
let script = UserScript::new("test.lua").unwrap();
println!("Calling init()...");
script.init().unwrap();
// set up signal processing // set up signal processing
println!("Initializing signal processing..."); println!("Initializing signal processing...");
let mut sigproc = SignalProcessing::new(config::BLOCK_LEN, config::SAMP_RATE).unwrap(); let sigproc = Rc::new(RefCell::new(
SignalProcessing::new(config::BLOCK_LEN, config::SAMP_RATE).unwrap()));
// set up Lua environment
println!("Loading user script...");
let script = UserScript::new(sigproc.clone(), "test.lua").unwrap();
println!("Calling init()...");
script.init().unwrap();
println!("Done! Starting main loop…"); println!("Done! Starting main loop…");
@ -67,12 +71,15 @@ fn main()
} }
sigproc.import_i16_mono_from_iter(samples.iter()).unwrap(); {
sigproc.update_fft().unwrap(); let mut s = sigproc.borrow_mut();
s.import_i16_mono_from_iter(samples.iter()).unwrap();
s.update_fft().unwrap();
}
let energy_bass = sigproc.get_energy_in_band( 0.0, 400.0); let energy_bass = sigproc.borrow().get_energy_in_band( 0.0, 400.0);
let energy_mid = sigproc.get_energy_in_band( 400.0, 4000.0); let energy_mid = sigproc.borrow().get_energy_in_band( 400.0, 4000.0);
let energy_treble = sigproc.get_energy_in_band(4000.0, config::SAMP_RATE/2.0); let energy_treble = sigproc.borrow().get_energy_in_band(4000.0, config::SAMP_RATE/2.0);
// dump the output // dump the output
println!("Bass: {:11.2} Mid: {:11.2} Treble: {:11.2}", energy_bass, energy_mid, energy_treble); println!("Bass: {:11.2} Mid: {:11.2} Treble: {:11.2}", energy_bass, energy_mid, energy_treble);

View file

@ -21,11 +21,15 @@
*/ */
use crate::config; use crate::config;
use crate::signal_processing::SignalProcessing;
use mlua::Lua; use mlua::Lua;
use mlua::FromLua; use mlua::FromLua;
use mlua::Error; use mlua::Error;
use std::rc::Rc;
use std::cell::RefCell;
pub struct UserScript pub struct UserScript
{ {
lua_state: Lua, lua_state: Lua,
@ -33,12 +37,26 @@ pub struct UserScript
impl UserScript impl UserScript
{ {
pub fn new(user_script_path: &str) -> std::result::Result<UserScript, mlua::Error> pub fn new(sigproc: Rc<RefCell<SignalProcessing>>, user_script_path: &str) -> std::result::Result<UserScript, mlua::Error>
{ {
let s = UserScript { let s = UserScript {
lua_state: Lua::new(), lua_state: Lua::new(),
}; };
// provide some configuration constants to Lua via a table
let config_table = s.lua_state.create_table()?;
config_table.set("sampling_rate", config::SAMP_RATE)?;
config_table.set("block_length", config::BLOCK_LEN)?;
config_table.set("samples_per_update", config::SAMPLES_PER_UPDATE)?;
s.lua_state.globals().set("CONFIG", config_table)?;
// register the signal processing reference as Lua user data
s.lua_state.globals().set("sigproc", SignalProcessingWrapper{
signal_processing: sigproc
})?;
// load the user script and execute it to make variables and functions available // load the user script and execute it to make variables and functions available
let user_script = std::fs::read_to_string(user_script_path)?; let user_script = std::fs::read_to_string(user_script_path)?;
s.lua_state.load(&user_script).exec()?; s.lua_state.load(&user_script).exec()?;
@ -93,3 +111,23 @@ impl UserScript
Ok(()) Ok(())
} }
} }
/*
* Wrap a SignalProcessing instance and provide a Lua interface for some of its methods.
*/
struct SignalProcessingWrapper
{
signal_processing: Rc<RefCell<SignalProcessing>>,
}
impl mlua::UserData for SignalProcessingWrapper
{
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M)
{
methods.add_method("get_energy_in_band", |_, this, (start_freq, end_freq): (f32, f32)| {
Ok(this.signal_processing.borrow().get_energy_in_band(start_freq, end_freq))
});
}
}