aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2020-08-08 09:58:44 +0200
committercbdev <cb@cbcdn.com>2020-08-08 09:58:44 +0200
commitb6ea5bbddf9db836ba206127b6eb77ca21cb8fa4 (patch)
treefc1afa3461531ce6def3712c93047c8cb68f05b1
parent39dfd02d5daa8ce7cf749f6235cf6450b2171214 (diff)
downloadmidimonster-b6ea5bbddf9db836ba206127b6eb77ca21cb8fa4.tar.gz
midimonster-b6ea5bbddf9db836ba206127b6eb77ca21cb8fa4.tar.bz2
midimonster-b6ea5bbddf9db836ba206127b6eb77ca21cb8fa4.zip
Lua channel introspection (#68)
-rw-r--r--backends/lua.c40
-rw-r--r--backends/lua.md5
2 files changed, 41 insertions, 4 deletions
diff --git a/backends/lua.c b/backends/lua.c
index 98ce369..cf59f8f 100644
--- a/backends/lua.c
+++ b/backends/lua.c
@@ -137,6 +137,8 @@ static int lua_update_timerfd(){
}
static void lua_thread_resume(size_t current_thread){
+ int thread_status = 0;
+
//push coroutine reference
lua_pushstring(thread[current_thread].thread, LUA_REGISTRY_CURRENT_THREAD);
lua_pushnumber(thread[current_thread].thread, current_thread);
@@ -144,9 +146,17 @@ static void lua_thread_resume(size_t current_thread){
//call thread main
DBGPF("Resuming thread %" PRIsize_t " on %s", current_thread, thread[current_thread].instance->name);
- if(lua_resume(thread[current_thread].thread, NULL, 0) != LUA_YIELD){
- DBGPF("Thread %" PRIsize_t " on %s terminated", current_thread, thread[current_thread].instance->name);
+ thread_status = lua_resume(thread[current_thread].thread, NULL, 0);
+
+ if(thread_status == LUA_YIELD){
+ DBGPF("Thread %" PRIsize_t " on %s yielded execution", current_thread, thread[current_thread].instance->name);
+ }
+ else{
thread[current_thread].timeout = 0;
+ LOGPF("Thread %" PRIsize_t " on %s terminated", current_thread, thread[current_thread].instance->name);
+ if(thread_status){
+ LOGPF("Last error message: %s", lua_tostring(thread[current_thread].thread, -1));
+ }
}
//remove coroutine reference
@@ -166,6 +176,30 @@ static instance* lua_fetch_instance(lua_State* interpreter){
return inst;
}
+static int lua_callback_channels(lua_State* interpreter){
+ size_t u;
+ instance* inst = lua_fetch_instance(interpreter);
+ lua_instance_data* data = (lua_instance_data*) inst->impl;
+
+ if(!last_timestamp){
+ LOG("The channels() API will not return usable results before the configuration has been read completely");
+ }
+
+ //create a table for the return array
+ lua_createtable(interpreter, data->channels, 0);
+
+ for(u = 0; u < data->channels; u++){
+ //push the key
+ lua_pushnumber(interpreter, u + 1);
+ //push the value
+ lua_pushstring(interpreter, data->channel[u].name);
+ //settable pops key and value, leaving the table
+ lua_settable(interpreter, -3);
+ }
+
+ return 1;
+}
+
static int lua_callback_thread(lua_State* interpreter){
instance* inst = lua_fetch_instance(interpreter);
size_t u = threads;
@@ -467,6 +501,7 @@ static int lua_instance(instance* inst){
lua_register(data->interpreter, "thread", lua_callback_thread);
lua_register(data->interpreter, "sleep", lua_callback_sleep);
lua_register(data->interpreter, "cleanup_handler", lua_callback_cleanup_handler);
+ lua_register(data->interpreter, "channels", lua_callback_channels);
//store instance pointer to the lua state
lua_pushstring(data->interpreter, LUA_REGISTRY_KEY);
@@ -604,6 +639,7 @@ static int lua_resolve_symbol(lua_State* interpreter, char* symbol){
|| !strcmp(symbol, "input_channel")
|| !strcmp(symbol, "timestamp")
|| !strcmp(symbol, "cleanup_handler")
+ || !strcmp(symbol, "channels")
|| !strcmp(symbol, "interval")){
return LUA_NOREF;
}
diff --git a/backends/lua.md b/backends/lua.md
index b2f40e0..026c945 100644
--- a/backends/lua.md
+++ b/backends/lua.md
@@ -6,8 +6,8 @@ and manipulate events using the Lua scripting language.
Every instance has its own interpreter state which can be loaded with custom scripts.
To process incoming channel events, the MIDIMonster calls corresponding Lua functions (if they exist)
-with the value (as a Lua `number` type) as parameter. Alternatively, a designated default channel handler
-which will receive events for all incoming channels may be supplied in the configuration.
+with the normalized event value (as a Lua `number` type) as parameter. Alternatively, a designated
+default channel handler which will receive events for all incoming channels may be set in the configuration.
The backend can also call Lua functions repeatedly using a timer, allowing users to implement time-based
functionality (such as evaluating a fixed mathematical function or outputting periodic updates).
@@ -25,6 +25,7 @@ The following functions are provided within the Lua interpreter for interaction
| `timestamp()` | `print(timestamp())` | Returns the core timestamp for this iteration with millisecond resolution. This is not a performance timer, but intended for timeouting, etc |
| `thread(function)` | `thread(run_show)` | Run a function as a Lua thread (see below) |
| `sleep(number)` | `sleep(100)` | Suspend current thread for time specified in milliseconds |
+| `channels()` | `chans = channels()` | Fetch an array of all currently known channels on the instance. Note that this function only works properly after the configuration has been read completely, i.e. any time after startup |
While a channel handler executes, calling `input_value` for that channel returns the previous value.
The stored value is updated once the handler returns.