Skip to content
Permalink
39afbf7bd4
Go to file
 
 
Cannot retrieve contributors at this time
2011 lines (1736 sloc) 47.8 KB
/***
* weaver
* c->lua and lua->c interface
* @module system
*/
// standard
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
// linux / posix
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
// lua
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
// norns
#include "device_hid.h"
#include "device_monome.h"
#include "device_midi.h"
#include "events.h"
#include "hello.h"
#include "lua_eval.h"
#include "metro.h"
#include "screen.h"
#include "snd_file.h"
#include "i2c.h"
#include "osc.h"
#include "oracle.h"
#include "weaver.h"
//------
//---- global lua state!
lua_State *lvm;
void w_run_code(const char *code) {
l_dostring(lvm, code, "w_run_code");
fflush(stdout);
}
void w_handle_exec_code_line(char *line) {
l_handle_line(lvm, line);
}
//-------------
//--- declare lua->c glue
// NB these static functions are prefixed with '_'
// to avoid shadowing similar-named extern functions in other moduels (like
// screen)
// and also to distinguish from extern 'w_' functions.
// grid
static int _grid_set_led(lua_State *l);
static int _grid_all_led(lua_State *l);
static int _grid_rows(lua_State *l);
static int _grid_cols(lua_State *l);
static int _grid_set_rotation(lua_State *l);
static int _arc_set_led(lua_State *l);
static int _arc_all_led(lua_State *l);
static int _monome_refresh(lua_State *l);
//screen
static int _screen_update(lua_State *l);
static int _screen_save(lua_State *l);
static int _screen_restore(lua_State *l);
static int _screen_font_face(lua_State *l);
static int _screen_font_size(lua_State *l);
static int _screen_aa(lua_State *l);
static int _screen_level(lua_State *l);
static int _screen_line_width(lua_State *l);
static int _screen_line_cap(lua_State *l);
static int _screen_line_join(lua_State *l);
static int _screen_miter_limit(lua_State *l);
static int _screen_move(lua_State *l);
static int _screen_line(lua_State *l);
static int _screen_move_rel(lua_State *l);
static int _screen_line_rel(lua_State *l);
static int _screen_curve(lua_State *l);
static int _screen_curve_rel(lua_State *l);
static int _screen_arc(lua_State *l);
static int _screen_rect(lua_State *l);
static int _screen_stroke(lua_State *l);
static int _screen_fill(lua_State *l);
static int _screen_text(lua_State *l);
static int _screen_clear(lua_State *l);
static int _screen_close(lua_State *l);
static int _screen_extents(lua_State *l);
//i2c
static int _gain_hp(lua_State *l);
//osc
static int _osc_send(lua_State *l);
static int _osc_send_crone(lua_State *l);
// midi
// midi
static int _midi_send(lua_State *l);
// crone
/// engines
static int _request_engine_report(lua_State *l);
static int _load_engine(lua_State *l);
static int _free_engine(lua_State *l);
/// commands
static int _send_command(lua_State *l);
static int _start_poll(lua_State *l);
static int _stop_poll(lua_State *l);
static int _set_poll_time(lua_State *l);
static int _request_poll_value(lua_State *l);
// timing
static int _metro_start(lua_State *l);
static int _metro_stop(lua_State *l);
static int _metro_set_time(lua_State *l);
// get the current system time
static int _get_time(lua_State *l);
// usleep!
static int _micro_sleep(lua_State *l);
// audio context control
static int _set_audio_input_level(lua_State *l);
static int _set_audio_output_level(lua_State *l);
static int _set_audio_monitor_level(lua_State *l);
static int _set_audio_monitor_mono(lua_State *l);
static int _set_audio_monitor_stereo(lua_State *l);
static int _set_audio_monitor_on(lua_State *l);
static int _set_audio_monitor_off(lua_State *l);
static int _set_audio_pitch_on(lua_State *l);
static int _set_audio_pitch_off(lua_State *l);
// tape control
static int _tape_level(lua_State *l);
static int _tape_new(lua_State *l);
static int _tape_start_rec(lua_State *l);
static int _tape_pause_rec(lua_State *l);
static int _tape_stop_rec(lua_State *l);
static int _tape_open(lua_State *l);
static int _tape_play(lua_State *l);
static int _tape_pause(lua_State *l);
static int _tape_stop(lua_State *l);
// aux effects controls
static int _set_aux_fx_on(lua_State *l);
static int _set_aux_fx_off(lua_State *l);
static int _set_aux_fx_input_level(lua_State *l);
static int _set_aux_fx_input_pan(lua_State *l);
static int _set_aux_fx_output_level(lua_State *l);
static int _set_aux_fx_return_level(lua_State *l);
static int _set_aux_fx_param(lua_State *l);
// insert effects controls
static int _set_insert_fx_on(lua_State *l);
static int _set_insert_fx_off(lua_State *l);
static int _set_insert_fx_mix(lua_State *l);
static int _set_insert_fx_param(lua_State *l);
// start audio (sync with sclang startup)
static int _start_audio(lua_State *l);
// restart audio (recompile sclang)
static int _restart_audio(lua_State *l);
// soundfile inspection
static int _sound_file_inspect(lua_State *l);
// reset LVM
static int _reset_lvm(lua_State *l);
// boilerplate: push a function to the stack, from field in global 'norns'
static inline void
_push_norns_func(const char *field, const char *func) {
// fprintf(stderr, "calling norns.%s.%s\n", field, func);
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, field);
lua_remove(lvm, -2);
lua_getfield(lvm, -1, func);
lua_remove(lvm, -2);
}
////////////////////////////////
//// extern function definitions
void w_init(void) {
fprintf(stderr, "starting lua vm\n");
lvm = luaL_newstate();
luaL_openlibs(lvm);
lua_pcall(lvm, 0, 0, 0);
////////////////////////
// FIXME: document these in lua in some deliberate fashion
//////////////////
// low-level monome grid control
lua_register(lvm, "grid_set_led", &_grid_set_led);
lua_register(lvm, "grid_all_led", &_grid_all_led);
lua_register(lvm, "grid_rows", &_grid_rows);
lua_register(lvm, "grid_cols", &_grid_cols);
lua_register(lvm, "grid_set_rotation", &_grid_set_rotation);
lua_register(lvm, "arc_set_led", &_arc_set_led);
lua_register(lvm, "arc_all_led", &_arc_all_led);
lua_register(lvm, "monome_refresh", &_monome_refresh);
// register screen funcs
lua_register(lvm, "s_update", &_screen_update);
lua_register(lvm, "s_save", &_screen_save);
lua_register(lvm, "s_restore", &_screen_restore);
lua_register(lvm, "s_font_face", &_screen_font_face);
lua_register(lvm, "s_font_size", &_screen_font_size);
lua_register(lvm, "s_aa", &_screen_aa);
lua_register(lvm, "s_level", &_screen_level);
lua_register(lvm, "s_line_width", &_screen_line_width);
lua_register(lvm, "s_line_cap", &_screen_line_cap);
lua_register(lvm, "s_line_join", &_screen_line_join);
lua_register(lvm, "s_miter_limit", &_screen_miter_limit);
lua_register(lvm, "s_move", &_screen_move);
lua_register(lvm, "s_line", &_screen_line);
lua_register(lvm, "s_move_rel", &_screen_move_rel);
lua_register(lvm, "s_line_rel", &_screen_line_rel);
lua_register(lvm, "s_curve", &_screen_curve);
lua_register(lvm, "s_curve_rel", &_screen_curve_rel);
lua_register(lvm, "s_arc", &_screen_arc);
lua_register(lvm, "s_rect", &_screen_rect);
lua_register(lvm, "s_stroke", &_screen_stroke);
lua_register(lvm, "s_fill", &_screen_fill);
lua_register(lvm, "s_text", &_screen_text);
lua_register(lvm, "s_clear", &_screen_clear);
lua_register(lvm, "s_close", &_screen_close);
lua_register(lvm, "s_extents", &_screen_extents);
// analog output control
lua_register(lvm, "gain_hp", &_gain_hp);
// osc
lua_register(lvm, "osc_send", &_osc_send);
lua_register(lvm, "osc_send_crone", &_osc_send_crone);
// midi
lua_register(lvm, "midi_send", &_midi_send);
// get list of available crone engines
lua_register(lvm, "report_engines", &_request_engine_report);
// load a named engine
lua_register(lvm, "load_engine", &_load_engine);
// free engine
lua_register(lvm, "free_engine", &_free_engine);
// send an indexed command
lua_register(lvm, "send_command", &_send_command);
// start/stop an indexed metro with callback
lua_register(lvm, "metro_start", &_metro_start);
lua_register(lvm, "metro_stop", &_metro_stop);
lua_register(lvm, "metro_set_time", &_metro_set_time);
// get the current high-resolution CPU time
lua_register(lvm, "get_time", &_get_time);
// usleep!
lua_register(lvm, "usleep", &_micro_sleep);
// start / stop a poll
lua_register(lvm, "start_poll", &_start_poll);
lua_register(lvm, "stop_poll", &_stop_poll);
lua_register(lvm, "set_poll_time", &_set_poll_time);
lua_register(lvm, "request_poll_value", &_request_poll_value);
// audio context controls
lua_register(lvm, "audio_input_level", &_set_audio_input_level);
lua_register(lvm, "audio_output_level", &_set_audio_output_level);
lua_register(lvm, "audio_monitor_level", &_set_audio_monitor_level);
lua_register(lvm, "audio_monitor_mono", &_set_audio_monitor_mono);
lua_register(lvm, "audio_monitor_stereo", &_set_audio_monitor_stereo);
lua_register(lvm, "audio_monitor_on", &_set_audio_monitor_on);
lua_register(lvm, "audio_monitor_off", &_set_audio_monitor_off);
lua_register(lvm, "audio_pitch_on", &_set_audio_pitch_on);
lua_register(lvm, "audio_pitch_off", &_set_audio_pitch_off);
// tape controls
lua_register(lvm, "tape_level", &_tape_level);
lua_register(lvm, "tape_new", &_tape_new);
lua_register(lvm, "tape_start_rec", &_tape_start_rec);
lua_register(lvm, "tape_pause_rec", &_tape_pause_rec);
lua_register(lvm, "tape_stop_rec", &_tape_stop_rec);
lua_register(lvm, "tape_open", &_tape_open);
lua_register(lvm, "tape_play", &_tape_play);
lua_register(lvm, "tape_pause", &_tape_pause);
lua_register(lvm, "tape_stop", &_tape_stop);
// aux effects controls
lua_register(lvm, "set_aux_fx_on", &_set_aux_fx_on);
lua_register(lvm, "set_aux_fx_off", &_set_aux_fx_off);
lua_register(lvm, "set_aux_fx_input_level", &_set_aux_fx_input_level);
lua_register(lvm, "set_aux_fx_input_pan", &_set_aux_fx_input_pan);
lua_register(lvm, "set_aux_fx_output_level", &_set_aux_fx_output_level);
lua_register(lvm, "set_aux_fx_return_level", &_set_aux_fx_return_level);
lua_register(lvm, "set_aux_fx_param", &_set_aux_fx_param);
// insert effects controls
lua_register(lvm, "set_insert_fx_on", &_set_insert_fx_on);
lua_register(lvm, "set_insert_fx_off", &_set_insert_fx_off);
lua_register(lvm, "set_insert_fx_mix", &_set_insert_fx_mix);
lua_register(lvm, "set_insert_fx_param", &_set_insert_fx_param);
// start audio (query for sclang readiness)
lua_register(lvm, "start_audio", &_start_audio);
// restart the audio process (recompile sclang)
lua_register(lvm, "restart_audio", &_restart_audio);
// returns channels, frames, samplerate
lua_register(lvm, "sound_file_inspect", &_sound_file_inspect);
// reset LVM
lua_register(lvm, "_reset_lvm", &_reset_lvm);
// run system init code
char *config = getenv("NORNS_CONFIG");
char *home = getenv("HOME");
char cmd[256];
if (config == NULL) {
snprintf(cmd, 256, "dofile('%s/norns/lua/config.lua')\n", home);
} else {
snprintf(cmd, 256, "dofile('%s')\n", config);
}
fprintf(stderr, "running lua config file: %s", cmd);
w_run_code(cmd);
w_run_code("require('norns')");
}
// run startup code
// audio backend should be running
void w_startup(void) {
fprintf(stderr, "running startup\n");
lua_getglobal(lvm, "startup");
l_report(lvm, l_docall(lvm, 0, 0));
}
void w_deinit(void) {
fprintf(stderr, "shutting down lua vm\n");
lua_close(lvm);
}
void w_reset_lvm() {
w_deinit();
w_init();
w_startup();
}
//----------------------------------
//---- static definitions
//
int _reset_lvm(lua_State *l) {
if (lua_gettop(l) != 0) {
return luaL_error(l, "wrong number of arguments");
}
lua_settop(l, 0);
// do this through the event loop, not from inside a lua pcall
event_post( event_data_new(EVENT_RESET_LVM) );
return 0;
}
/***
* screen: update (flip buffer)
* @function s_update
*/
int _screen_update(lua_State *l) {
if (lua_gettop(l) != 0) {
return luaL_error(l, "wrong number of arguments");
}
screen_update();
lua_settop(l, 0);
return 0;
}
/***
* screen: save attributes
* @function s_save
*/
int _screen_save(lua_State *l) {
if (lua_gettop(l) != 0) {
return luaL_error(l, "wrong number of arguments");
}
screen_save();
lua_settop(l, 0);
return 0;
}
/***
* screen: restore attributes
* @function s_restore
*/
int _screen_restore(lua_State *l) {
if (lua_gettop(l) != 0) {
return luaL_error(l, "wrong number of arguments");
}
screen_restore();
lua_settop(l, 0);
return 0;
}
/***
* screen: set font face
* @function s_font_face
*/
int _screen_font_face(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
int x = (int) luaL_checkinteger(l, 1);
screen_font_face(x);
lua_settop(l, 0);
return 0;
}
/***
* screen: set font size
* @function s_font_size
*/
int _screen_font_size(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
int x = (int) luaL_checknumber(l, 1);
screen_font_size(x);
lua_settop(l, 0);
return 0;
}
/***
* screen: change antialias mode for drawing
* @function s_aa
* @tparam integer state, 0=off, 1=on
*/
int _screen_aa(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
int x = (int) luaL_checkinteger(l, 1);
screen_aa(x);
lua_settop(l, 0);
return 0;
}
/***
* screen: change level (color)
* @function s_level
* @tparam integer level, 0 (black) to 15 (white)
*/
int _screen_level(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
int x = (int) luaL_checkinteger(l, 1);
screen_level(x);
lua_settop(l, 0);
return 0;
}
/***
* screen: set line width
* @function s_line_width
* @tparam integer width line width
*/
int _screen_line_width(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
double x = luaL_checknumber(l, 1);
screen_line_width(x);
lua_settop(l, 0);
return 0;
}
/***
* screen: set line cap
* @function s_line_cap
* @tparam string line cap style ("butt", "round" or "square"). default is "butt".
*/
int _screen_line_cap(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
const char *s = luaL_checkstring(l, 1);
screen_line_cap(s);
lua_settop(l, 0);
return 0;
}
/***
* screen: set line join
* @function s_line_join
* @tparam string line join style ("miter", "round" or "bevel"). default is "miter".
*/
int _screen_line_join(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
const char *s = luaL_checkstring(l, 1);
screen_line_join(s);
lua_settop(l, 0);
return 0;
}
/***
* screen: set miter limit
* @function s_miter_limit
* @tparam double miter limit
*/
int _screen_miter_limit(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
double limit = luaL_checknumber(l, 1);
screen_miter_limit(limit);
lua_settop(l, 0);
return 0;
}
/***
* screen: move position
* @function s_move
* @param x
* @param y
*/
int _screen_move(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
double x = luaL_checknumber(l, 1);
double y = luaL_checknumber(l, 2);
screen_move(x,y);
lua_settop(l, 0);
return 0;
}
/***
* screen: draw line to position
* @function s_line
* @param x
* @param y
*/
int _screen_line(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
double x = luaL_checknumber(l, 1);
double y = luaL_checknumber(l, 2);
screen_line(x,y);
lua_settop(l, 0);
return 0;
}
/***
* screen: move position rel
* @function s_move_rel
* @param x
* @param y
*/
int _screen_move_rel(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
double x = luaL_checknumber(l, 1);
double y = luaL_checknumber(l, 2);
screen_move_rel(x,y);
lua_settop(l, 0);
return 0;
}
/***
* screen: draw line to position rel
* @function s_line_rel
* @param x
* @param y
*/
int _screen_line_rel(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
double x = (int) luaL_checknumber(l, 1);
double y = (int) luaL_checknumber(l, 2);
screen_line_rel(x,y);
lua_settop(l, 0);
return 0;
}
/***
* screen: draw curve
* @function s_curve
* @param x
* @param y
*/
int _screen_curve(lua_State *l) {
if (lua_gettop(l) != 6) {
return luaL_error(l, "wrong number of arguments");
}
double x1 = luaL_checknumber(l, 1);
double y1 = luaL_checknumber(l, 2);
double x2 = luaL_checknumber(l, 3);
double y2 = luaL_checknumber(l, 4);
double x3 = luaL_checknumber(l, 5);
double y3 = luaL_checknumber(l, 6);
screen_curve(x1, y1, x2, y2, x3, y3);
lua_settop(l, 0);
return 0;
}
/***
* screen: draw curve rel
* @function s_curve_rel
* @param x
* @param y
*/
int _screen_curve_rel(lua_State *l) {
if (lua_gettop(l) != 6) {
return luaL_error(l, "wrong number of arguments");
}
double x1 = luaL_checknumber(l, 1);
double y1 = luaL_checknumber(l, 2);
double x2 = luaL_checknumber(l, 3);
double y2 = luaL_checknumber(l, 4);
double x3 = luaL_checknumber(l, 5);
double y3 = luaL_checknumber(l, 6);
screen_curve_rel(x1, y1, x2, y2, x3, y3);
lua_settop(l, 0);
return 0;
}
/***
* screen: draw arc
* @function s_arc
* @param x
* @param y
*/
int _screen_arc(lua_State *l) {
if (lua_gettop(l) != 5) {
return luaL_error(l, "wrong number of arguments");
}
double x = luaL_checknumber(l, 1);
double y = luaL_checknumber(l, 2);
double r = luaL_checknumber(l, 3);
double a1 = luaL_checknumber(l, 4);
double a2 = luaL_checknumber(l, 5);
screen_arc(x,y,r,a1,a2);
lua_settop(l, 0);
return 0;
}
/***
* screen: draw rect
* @function s_rect
* @param x
* @param y
*/
int _screen_rect(lua_State *l) {
if (lua_gettop(l) != 4) {
return luaL_error(l, "wrong number of arguments");
}
double x = luaL_checknumber(l, 1);
double y = luaL_checknumber(l, 2);
double w = luaL_checknumber(l, 3);
double h = luaL_checknumber(l, 4);
screen_rect(x, y, w, h);
lua_settop(l, 0);
return 0;
}
/***
* screen: stroke, or apply width/color to line(s)
* @function s_stroke
*/
int _screen_stroke(lua_State *l) {
if (lua_gettop(l) != 0) {
return luaL_error(l, "wrong number of arguments");
}
screen_stroke();
lua_settop(l, 0);
return 0;
}
/***
* screen: fill path
* @function s_fill
*/
int _screen_fill(lua_State *l) {
if (lua_gettop(l) != 0) {
return luaL_error(l, "wrong number of arguments");
}
screen_fill();
lua_settop(l, 0);
return 0;
}
/***
* screen: text
* @function s_text
* @tparam string text test to print
*/
int _screen_text(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
const char *s = luaL_checkstring(l, 1);
screen_text(s);
lua_settop(l, 0);
return 0;
}
/***
* screen: clear to black
* @function s_clear
*/
int _screen_clear(lua_State *l) {
if (lua_gettop(l) != 0) {
return luaL_error(l, "wrong number of arguments");
}
screen_clear();
lua_settop(l, 0);
return 0;
}
/***
* screen: close path
* @function s_close
*/
int _screen_close(lua_State *l) {
if (lua_gettop(l) != 0) {
return luaL_error(l, "wrong number of arguments");
}
screen_close_path();
lua_settop(l, 0);
return 0;
}
/***
* screen: extents
* @function s_extents
* @tparam gets x/y displacement of a string
*/
int _screen_extents(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
const char *s = luaL_checkstring(l, 1);
double *xy = screen_extents(s);
lua_pushinteger(l, xy[0]);
lua_pushinteger(l, xy[1]);
return 2;
}
/***
* headphone: set level
* @function gain_hp
* @tparam integer level level (0-63)
*/
int _gain_hp(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
int level = (int) luaL_checkinteger(l, 1);
i2c_hp(level);
lua_settop(l, 0);
return 0;
}
/***
* osc: send to arbitrary address
* @function osc_send
*/
int _osc_send(lua_State *l) {
const char *host = NULL;
const char *port = NULL;
const char *path = NULL;
lo_message msg;
int nargs = lua_gettop(l);
// address
luaL_checktype(l, 1, LUA_TTABLE);
if (lua_rawlen(l, 1) != 2) {
luaL_argerror(l, 1, "address should be a table in the form {host, port}");
}
lua_pushnumber(l, 1);
lua_gettable(l, 1);
if (lua_isstring(l, -1)) {
host = lua_tostring(l, -1);
} else {
luaL_argerror(l, 1, "address should be a table in the form {host, port}");
}
lua_pop(l, 1);
lua_pushnumber(l, 2);
lua_gettable(l, 1);
if (lua_isstring(l, -1)) {
port = lua_tostring(l, -1);
} else {
luaL_argerror(l, 1, "address should be a table in the form {host, port}");
}
lua_pop(l, 1);
// path
luaL_checktype(l, 2, LUA_TSTRING);
path = lua_tostring(l, 2);
if ((host == NULL) || (port == NULL) || (path == NULL)) { return 1; }
msg = lo_message_new();
// add args (optional)
if (nargs > 2) {
luaL_checktype(l, 3, LUA_TTABLE);
for (size_t i = 1; i <= lua_rawlen(l, 3); i++) {
lua_pushnumber(l, i);
lua_gettable(l, 3);
int argtype = lua_type(l, -1);
switch (argtype) {
case LUA_TNIL:
lo_message_add_nil(msg);
break;
case LUA_TNUMBER:
lo_message_add_float(msg, lua_tonumber(l, -1));
break;
case LUA_TBOOLEAN:
if (lua_toboolean(l, -1)) {
lo_message_add_true(msg);
} else {
lo_message_add_false(msg);
}
break;
case LUA_TSTRING:
lo_message_add_string(msg, lua_tostring(l, -1));
break;
default:
lo_message_free(msg);
luaL_error(l, "invalid osc argument type %s",
lua_typename(l, argtype));
break;
} /* switch */
lua_pop(l, 1);
}
}
osc_send(host, port, path, msg);
lo_message_free(msg);
lua_settop(l, 0);
return 0;
}
/***
* osc: send to crone
* @function osc_send
*/
int _osc_send_crone(lua_State *l) {
const char *path = NULL;
lo_message msg;
int nargs = lua_gettop(l);
// path
luaL_checktype(l, 1, LUA_TSTRING);
path = lua_tostring(l, 1);
if (path == NULL) { return 1; }
msg = lo_message_new();
// add args (optional)
if (nargs > 2) {
luaL_checktype(l, 3, LUA_TTABLE);
for (size_t i = 1; i <= lua_rawlen(l, 3); i++) {
lua_pushnumber(l, i);
lua_gettable(l, 3);
int argtype = lua_type(l, -1);
switch (argtype) {
case LUA_TNIL:
lo_message_add_nil(msg);
break;
case LUA_TNUMBER:
lo_message_add_float(msg, lua_tonumber(l, -1));
break;
case LUA_TBOOLEAN:
if (lua_toboolean(l, -1)) {
lo_message_add_true(msg);
} else {
lo_message_add_false(msg);
}
break;
case LUA_TSTRING:
lo_message_add_string(msg, lua_tostring(l, -1));
break;
default:
lo_message_free(msg);
luaL_error(l, "invalid osc argument type %s",
lua_typename(l, argtype));
break;
} /* switch */
lua_pop(l, 1);
}
}
osc_send_crone(path, msg);
lo_message_free(msg);
lua_settop(l, 0);
return 0;
}
/***
* midi: send
* @function midi_send
*/
int _midi_send(lua_State *l) {
struct dev_midi *md;
size_t nbytes;
uint8_t *data;
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
luaL_checktype(l, 1, LUA_TLIGHTUSERDATA);
md = lua_touserdata(l, 1);
luaL_checktype(l, 2, LUA_TTABLE);
nbytes = lua_rawlen(l, 2);
data = malloc(nbytes);
for (unsigned int i = 1; i <= nbytes; i++) {
lua_pushinteger(l, i);
lua_gettable(l, 2);
// TODO: lua_isnumber
data[i - 1] = lua_tointeger(l, -1);
lua_pop(l, 1);
}
dev_midi_send(md, data, nbytes);
free(data);
return 0;
}
/***
* grid: set led
* @function grid_set_led
* @param dev grid device
* @param x x
* @param y y
* @param z level (0-15)
*/
int _grid_set_led(lua_State *l) {
if (lua_gettop(l) != 4) {
return luaL_error(l, "wrong number of arguments");
}
luaL_checktype(l, 1, LUA_TLIGHTUSERDATA);
struct dev_monome *md = lua_touserdata(l, 1);
int x = (int) luaL_checkinteger(l, 2) - 1; // convert from 1-base
int y = (int) luaL_checkinteger(l, 3) - 1; // convert from 1-base
int z = (int) luaL_checkinteger(l, 4); // don't convert value!
dev_monome_grid_set_led(md, x, y, z);
lua_settop(l, 0);
return 0;
}
int _arc_set_led(lua_State *l) {
if (lua_gettop(l) != 4) {
return luaL_error(l, "wrong number of arguments");
}
luaL_checktype(l, 1, LUA_TLIGHTUSERDATA);
struct dev_monome *md = lua_touserdata(l, 1);
int n = (int) luaL_checkinteger(l, 2) - 1; // convert from 1-base
int x = (int) luaL_checkinteger(l, 3) - 1; // convert from 1-base
int val = (int) luaL_checkinteger(l, 4); // don't convert value!
dev_monome_arc_set_led(md, n, x, val);
lua_settop(l, 0);
return 0;
}
/***
* grid: set all LEDs
* @function grid_all_led
* @param dev grid device
* @param z level (0-15)
*/
int _grid_all_led(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
luaL_checktype(l, 1, LUA_TLIGHTUSERDATA);
struct dev_monome *md = lua_touserdata(l, 1);
int z = (int) luaL_checkinteger(l, 2); // don't convert value!
dev_monome_all_led(md, z);
lua_settop(l, 0);
return 0;
}
int _arc_all_led(lua_State *l) {
return _grid_all_led(l);
}
/***
* grid: set rotation
* @param dev grid device
* @param z (rotation 0-3 - or is it 0,90,180,270?)
*/
int _grid_set_rotation(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
luaL_checktype(l, 1, LUA_TLIGHTUSERDATA);
struct dev_monome *md = lua_touserdata(l, 1);
int z = (int) luaL_checkinteger(l, 2); // don't convert value!
dev_monome_set_rotation(md, z);
lua_settop(l, 0);
return 0;
}
/***
* monome: refresh
* @function monome_refresh
* @param dev grid device
*/
int _monome_refresh(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
luaL_checktype(l, 1, LUA_TLIGHTUSERDATA);
struct dev_monome *md = lua_touserdata(l, 1);
dev_monome_refresh(md);
lua_settop(l, 0);
return 0;
}
/***
* grid: rows
* @function grid_rows
* @param dev grid device
*/
int _grid_rows(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
luaL_checktype(l, 1, LUA_TLIGHTUSERDATA);
struct dev_monome *md = lua_touserdata(l, 1);
lua_pushinteger(l, dev_monome_grid_rows(md));
return 1;
}
/***
* grid: cold
* @function grid_cols
* @param dev grid device
*/
int _grid_cols(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
luaL_checktype(l, 1, LUA_TLIGHTUSERDATA);
struct dev_monome *md = lua_touserdata(l, 1);
lua_pushinteger(l, dev_monome_grid_cols(md));
return 1;
}
//-- audio processing controls
int _load_engine(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
const char *s = luaL_checkstring(l, 1);
o_load_engine(s);
lua_settop(l, 0);
return 0;
}
int _free_engine(lua_State *l) {
if (lua_gettop(l) != 0) {
return luaL_error(l, "wrong number of arguments");
}
o_free_engine();
lua_settop(l, 0);
return 0;
}
int _send_command(lua_State *l) {
int nargs = lua_gettop(l);
if (nargs < 1) {
return luaL_error(l, "wrong number of arguments");
}
char *cmd = NULL;
char *fmt = NULL;
int idx = (int) luaL_checkinteger(l, 1) - 1; // 1-base to 0-base
// FIXME: this isn't really safe.
// to make it safe would mean locks, which is bad.
// might be better to put name/fmt on stack from lua on every call
cmd = o_get_commands()[idx].name;
fmt = o_get_commands()[idx].format;
// FIXME: refactor this, should go in oracle!
lo_message msg = lo_message_new();
const char *s;
int d;
double f;
for(int i = 2; i <= nargs; i++) {
switch(fmt[i - 2]) {
case 's':
if (lua_isstring(l, i)) {
s = lua_tostring(l, i);
lo_message_add_string(msg, s);
} else {
lo_message_free(msg);
return luaL_error(l, "failed string type check");
}
break;
case 'i':
if (lua_isnumber(l, i)) {
d = (int)lua_tonumber(l, i);
lo_message_add_int32(msg, d);
} else {
lo_message_free(msg);
return luaL_error(l, "failed int type check");
}
break;
case 'f':
if (lua_isnumber(l, i)) {
f = lua_tonumber(l, i);
lo_message_add_double(msg, f);
} else {
lo_message_free(msg);
return luaL_error(l, "failed double type check");
}
break;
default:
break;
} /* switch */
}
if ((cmd == NULL) || (fmt == NULL)) {
lo_message_free(msg);
return luaL_error(l, "null format/command string");
}
o_send_command(cmd, msg);
free(msg);
lua_settop(l, 0);
return 0;
}
int _request_engine_report(lua_State *l) {
(void)l;
o_request_engine_report();
return 0;
}
/***
* metro: start
* @function metro_start
*/
int _metro_start(lua_State *l) {
static int idx = 0;
double seconds = -1.0; // metro will re-use previous value
int count = -1; // default: infinite
int stage = 0;
int nargs = lua_gettop(l);
if (nargs > 0) {
idx = (int) luaL_checkinteger(l, 1) - 1; // convert from 1-based
}
if (nargs > 1) {
seconds = (double) luaL_checknumber(l, 2);
}
if (nargs > 2) {
count = (int) luaL_checkinteger(l, 3);
}
if (nargs > 3) {
stage = (int) luaL_checkinteger(l, 4) - 1; // convert from 1-based
}
metro_start(idx, seconds, count, stage);
lua_settop(l, 0);
return 0;
}
/***
* metro: stop
* @function metro_stop
*/
int _metro_stop(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
int idx = (int) luaL_checkinteger(l, 1) - 1;
metro_stop(idx);
lua_settop(l, 0);
return 0;
}
/***
* metro: set time
* @function metro_set_time
*/
int _metro_set_time(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
int idx = (int) luaL_checkinteger(l, 1) - 1;
float sec = (float) luaL_checknumber(l, 2);
metro_set_time(idx, sec);
lua_settop(l, 0);
return 0;
}
/***
* request current time since Epoch
* @function get_time
*/
int _get_time(lua_State *l) {
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
// returns two results: microseconds, seconds
lua_pushinteger(l, (lua_Integer)tv.tv_sec);
lua_pushinteger(l, (lua_Integer)tv.tv_usec);
return 2;
}
// usleep
int _micro_sleep(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
int usec = (float) luaL_checknumber(l, 1);
usleep(usec);
lua_settop(l, 0);
return 0;
}
//---- c -> lua glue
//--- hardware input:
// helper for calling grid handlers
static inline void
_call_grid_handler(int id, int x, int y, int state) {
_push_norns_func("grid", "key");
lua_pushinteger(lvm, id + 1); // convert to 1-base
lua_pushinteger(lvm, x + 1); // convert to 1-base
lua_pushinteger(lvm, y + 1); // convert to 1-base
lua_pushinteger(lvm, state);
l_report(lvm, l_docall(lvm, 4, 0));
}
void w_handle_monome_add(void *mdev) {
struct dev_monome *md = (struct dev_monome *)mdev;
int id = md->dev.id;
const char *serial = md->dev.serial;
const char *name = md->dev.name;
_push_norns_func("monome", "add");
lua_pushinteger(lvm, id + 1); // convert to 1-base
lua_pushstring(lvm, serial);
lua_pushstring(lvm, name);
lua_pushlightuserdata(lvm, mdev);
l_report(lvm, l_docall(lvm, 4, 0));
}
void w_handle_monome_remove(int id) {
_push_norns_func("monome", "remove");
lua_pushinteger(lvm, id + 1); // convert to 1-base
l_report(lvm, l_docall(lvm, 1, 0));
}
void w_handle_grid_key(int id, int x, int y, int state) {
_call_grid_handler(id, x, y, state > 0);
}
void w_handle_arc_encoder_delta(int id, int n, int delta) {
_push_norns_func("arc", "delta");
lua_pushinteger(lvm, id + 1); // convert to 1-base
lua_pushinteger(lvm, n + 1); // convert to 1-base
lua_pushinteger(lvm, delta);
l_report(lvm, l_docall(lvm, 3, 0));
}
void w_handle_arc_encoder_key(int id, int n, int state) {
_push_norns_func("arc", "key");
lua_pushinteger(lvm, id + 1); // convert to 1-base
lua_pushinteger(lvm, n + 1); // convert to 1-base
lua_pushinteger(lvm, state);
l_report(lvm, l_docall(lvm, 3, 0));
}
void w_handle_hid_add(void *p) {
struct dev_hid *dev = (struct dev_hid *)p;
struct dev_common *base = (struct dev_common *)p;
int id = base->id;
_push_norns_func("hid", "add");
lua_pushinteger(lvm, id + 1); // convert to 1-base
lua_pushstring(lvm, base->name);
// push table of event types
int ntypes = dev->num_types;
lua_createtable(lvm, ntypes, 0);
for(int i = 0; i < ntypes; i++) {
lua_pushinteger(lvm, dev->types[i]);
lua_rawseti(lvm, -2, i + 1);
}
// table of tables of event codes
lua_createtable(lvm, ntypes, 0);
for(int i = 0; i < ntypes; i++) {
int ncodes = dev->num_codes[i];
lua_createtable(lvm, ncodes, 0);
for(int j = 0; j < ncodes; j++) {
lua_pushinteger(lvm, dev->codes[i][j]);
lua_rawseti(lvm, -2, j + 1);
}
lua_rawseti(lvm, -2, i + 1);
}
l_report(lvm, l_docall(lvm, 4, 0));
}
void w_handle_hid_remove(int id) {
_push_norns_func("hid", "remove");
lua_pushinteger(lvm, id + 1); // convert to 1-base
l_report(lvm, l_docall(lvm, 1, 0));
}
void w_handle_hid_event(int id, uint8_t type, dev_code_t code, int value) {
_push_norns_func("hid", "event");
lua_pushinteger(lvm, id + 1); // convert to 1-base
lua_pushinteger(lvm, type);
lua_pushinteger(lvm, code);
lua_pushinteger(lvm, value);
l_report(lvm, l_docall(lvm, 4, 0));
}
void w_handle_midi_add(void *p) {
struct dev_midi *dev = (struct dev_midi *)p;
struct dev_common *base = (struct dev_common *)p;
int id = base->id;
_push_norns_func("midi", "add");
lua_pushinteger(lvm, id + 1); // convert to 1-base
lua_pushstring(lvm, base->name);
lua_pushlightuserdata(lvm, dev);
l_report(lvm, l_docall(lvm, 3, 0));
}
void w_handle_midi_remove(int id) {
_push_norns_func("midi", "remove");
lua_pushinteger(lvm, id + 1); // convert to 1-base
l_report(lvm, l_docall(lvm, 1, 0));
}
void w_handle_midi_event(int id, uint8_t *data, size_t nbytes) {
_push_norns_func("midi", "event");
lua_pushinteger(lvm, id + 1); // convert to 1-base
lua_createtable(lvm, nbytes, 0);
for (size_t i = 0; i < nbytes; i++) {
lua_pushinteger(lvm, data[i]);
lua_rawseti(lvm, -2, i + 1);
}
l_report(lvm, l_docall(lvm, 2, 0));
}
void w_handle_osc_event(char *from_host,
char *from_port,
char *path,
lo_message msg) {
const char *types = NULL;
int argc;
lo_arg **argv = NULL;
types = lo_message_get_types(msg);
argc = lo_message_get_argc(msg);
argv = lo_message_get_argv(msg);
_push_norns_func("osc", "event");
lua_pushstring(lvm, path);
lua_createtable(lvm, argc, 0);
for (int i = 0; i < argc; i++) {
switch (types[i]) {
case LO_INT32:
lua_pushinteger(lvm, argv[i]->i);
break;
case LO_FLOAT:
lua_pushnumber(lvm, argv[i]->f);
break;
case LO_STRING:
lua_pushstring(lvm, &argv[i]->s);
break;
case LO_BLOB:
lua_pushlstring(lvm,
lo_blob_dataptr((lo_blob) argv[i]),
lo_blob_datasize((lo_blob) argv[i]));
break;
case LO_INT64:
lua_pushinteger(lvm, argv[i]->h);
break;
case LO_DOUBLE:
lua_pushnumber(lvm, argv[i]->d);
break;
case LO_SYMBOL:
lua_pushstring(lvm, &argv[i]->S);
break;
case LO_CHAR:
lua_pushlstring(lvm, (const char *) &argv[i]->c, 1);
break;
case LO_MIDI:
lua_pushlstring(lvm, (const char *) &argv[i]->m, 4);
break;
case LO_TRUE:
lua_pushboolean(lvm, 1);
break;
case LO_FALSE:
lua_pushboolean(lvm, 0);
break;
case LO_NIL:
lua_pushnil(lvm);
break;
case LO_INFINITUM:
lua_pushnumber(lvm, INFINITY);
break;
default:
fprintf(stderr, "unknown osc typetag: %c\n", types[i]);
lua_pushnil(lvm);
break;
} /* switch */
lua_rawseti(lvm, -2, i + 1);
}
lua_createtable(lvm, 2, 0);
lua_pushstring(lvm, from_host);
lua_rawseti(lvm, -2, 1);
lua_pushstring(lvm, from_port);
lua_rawseti(lvm, -2, 2);
l_report(lvm, l_docall(lvm, 3, 0));
}
// helper for pushing array of c strings
static inline void
_push_string_array(const char **arr, const int n) {
// push a table of strings
lua_createtable(lvm, n, 0);
for (int i = 0; i < n; i++) {
lua_pushstring(lvm, arr[i]);
lua_rawseti(lvm, -2, i + 1);
}
// push count of entries
lua_pushinteger(lvm, n);
}
// audio engine report handlers
void w_handle_engine_report(const char **arr, const int n) {
_push_norns_func("report", "engines");
_push_string_array(arr, n);
l_report(lvm, l_docall(lvm, 2, 0));
}
void w_handle_startup_ready_ok() {
_push_norns_func("startup_status", "ok");
l_report(lvm, l_docall(lvm, 0, 0));
}
void w_handle_startup_ready_timeout() {
_push_norns_func("startup_status", "timeout");
l_report(lvm, l_docall(lvm, 0, 0));
}
// helper: push table of commands
// each entry is a subtatble: {name, format}
static void _push_commands() {
o_lock_descriptors();
const struct engine_command *p = o_get_commands();
const int n = o_get_num_commands();
lua_createtable(lvm, n, 0);
for(int i = 0; i < n; i++) {
// create subtable on stack
lua_createtable(lvm, 2, 0);
// put command string on stack; assign to subtable, pop
lua_pushstring(lvm, p[i].name);
lua_rawseti(lvm, -2, 1);
// put format string on stack; assign to subtable, pop
lua_pushstring(lvm, p[i].format);
lua_rawseti(lvm, -2, 2);
// subtable is on stack; assign to master table and pop
lua_rawseti(lvm, -2, i + 1);
}
o_unlock_descriptors();
lua_pushinteger(lvm, n);
}
// helper: push table of polls
// each entry is a subtable: { name, type }
// FIXME: this is silly, just use full format specification as for commands
static void _push_polls() {
o_lock_descriptors();
const struct engine_poll *p = o_get_polls();
const int n = o_get_num_polls();
lua_createtable(lvm, n, 0);
for(int i = 0; i < n; ++i) {
// create subtable on stack
lua_createtable(lvm, 2, 0);
// put poll index on stack; assign to subtable, pop
lua_pushinteger(lvm, i + 1); // convert to 1-base
lua_rawseti(lvm, -2, 1);
// put poll name on stack; assign to subtable, pop
lua_pushstring(lvm, p[i].name);
lua_rawseti(lvm, -2, 2);
/// FIXME: just use a format string....
if (p[i].type == POLL_TYPE_VALUE) {
lua_pushstring(lvm, "value");
} else {
lua_pushstring(lvm, "data");
}
// put type string on stack; assign to subtable, pop
lua_rawseti(lvm, -2, 3);
// subtable is on stack; assign to master table and pop
lua_rawseti(lvm, -2, i + 1); // convert to 1-base
}
o_unlock_descriptors();
lua_pushinteger(lvm, n);
}
void w_handle_engine_loaded() {
_push_norns_func("report", "commands");
_push_commands();
l_report(lvm, l_docall(lvm, 2, 0));
_push_norns_func("report", "polls");
_push_polls();
l_report(lvm, l_docall(lvm, 2, 0));
_push_norns_func("report", "did_engine_load");
l_report(lvm, l_docall(lvm, 0, 0));
// TODO
// _push_params();
}
// metro handler
void w_handle_metro(const int idx, const int stage) {
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, "metro");
lua_remove(lvm, -2);
lua_pushinteger(lvm, idx + 1); // convert to 1-based
lua_pushinteger(lvm, stage + 1); // convert to 1-based
l_report(lvm, l_docall(lvm, 2, 0));
}
// gpio handler
void w_handle_key(const int n, const int val) {
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, "key");
lua_remove(lvm, -2);
lua_pushinteger(lvm, n);
lua_pushinteger(lvm, val);
l_report(lvm, l_docall(lvm, 2, 0));
}
// gpio handler
void w_handle_enc(const int n, const int delta) {
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, "enc");
lua_remove(lvm, -2);
lua_pushinteger(lvm, n);
lua_pushinteger(lvm, delta);
l_report(lvm, l_docall(lvm, 2, 0));
}
// system/battery
void w_handle_battery(const int percent, const int current) {
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, "battery");
lua_remove(lvm, -2);
lua_pushinteger(lvm, percent);
lua_pushinteger(lvm, current);
l_report(lvm, l_docall(lvm, 2, 0));
}
// system/power
void w_handle_power(const int present) {
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, "power");
lua_remove(lvm, -2);
lua_pushinteger(lvm, present);
l_report(lvm, l_docall(lvm, 1, 0));
}
// stat
void w_handle_stat(const uint32_t disk, const uint16_t temp, const uint16_t cpu) {
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, "stat");
lua_remove(lvm, -2);
lua_pushinteger(lvm, disk);
lua_pushinteger(lvm, temp);
lua_pushinteger(lvm, cpu);
l_report(lvm, l_docall(lvm, 3, 0));
}
void w_handle_poll_value(int idx, float val) {
// fprintf(stderr, "_handle_poll_value: %d, %f\n", idx, val);
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, "poll");
lua_remove(lvm, -2);
lua_pushinteger(lvm, idx + 1); // convert to 1-base
lua_pushnumber(lvm, val);
l_report(lvm, l_docall(lvm, 2, 0));
}
void w_handle_poll_data(int idx, int size, uint8_t *data) {
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, "poll");
lua_remove(lvm, -2);
lua_pushinteger(lvm, idx + 1); // convert index to 1-based
lua_createtable(lvm, size, 0);
// FIXME: would like a better way of passing a byte array to lua!
for(int i = 0; i < size; ++i) {
lua_pushinteger(lvm, data[i]);
lua_rawseti(lvm, -2, 1);
}
lua_pushinteger(lvm, size);
l_report(lvm, l_docall(lvm, 2, 0));
}
/* void w_handle_poll_wave(int idx, uint8_t *data) { */
/* // TODO */
/* } */
// argument is an array of 4 bytes
void w_handle_poll_io_levels(uint8_t *levels) {
lua_getglobal(lvm, "norns");
lua_getfield(lvm, -1, "vu");
lua_remove(lvm, -2);
for(int i = 0; i < 4; ++i) {
lua_pushinteger(lvm, levels[i]);
}
l_report(lvm, l_docall(lvm, 4, 0));
}
// helper: set poll given by lua to given state
static int poll_set_state(lua_State *l, bool val) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
int idx = (int) luaL_checkinteger(l, 1) - 1; // convert from 1-based
o_set_poll_state(idx, val);
lua_settop(l, 0);
return 0;
}
int _start_poll(lua_State *l) {
return poll_set_state(l, true);
}
int _stop_poll(lua_State *l) {
return poll_set_state(l, false);
}
int _set_poll_time(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
int idx = (int) luaL_checkinteger(l, 1) - 1; // convert from 1-based
float val = (float) luaL_checknumber(l, 2);
o_set_poll_time(idx, val);
lua_settop(l, 0);
return 0;
}
int _request_poll_value(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
int idx = (int) luaL_checkinteger(l, 1) - 1; // convert from 1-based
o_request_poll_value(idx);
lua_settop(l, 0);
return 0;
}
// audio context control
int _set_audio_input_level(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
int idx = (int) luaL_checkinteger(l, 1) - 1; // convert from 1-based
float val = (float) luaL_checknumber(l, 2);
o_set_audio_input_level(idx, val);
lua_settop(l, 0);
return 0;
}
int _set_audio_output_level(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
float val = (float) luaL_checknumber(l, 1);
o_set_audio_output_level(val);
lua_settop(l, 0);
return 0;
}
int _set_audio_monitor_level(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
float val = (float) luaL_checknumber(l, 1);
o_set_audio_monitor_level(val);
lua_settop(l, 0);
return 0;
}
int _set_audio_monitor_mono(lua_State *l) {
(void)l;
o_set_audio_monitor_mono();
return 0;
}
int _set_audio_monitor_stereo(lua_State *l) {
(void)l;
o_set_audio_monitor_stereo();
return 0;
}
int _set_audio_monitor_on(lua_State *l) {
(void)l;
o_set_audio_monitor_on();
return 0;
}
int _set_audio_monitor_off(lua_State *l) {
(void)l;
o_set_audio_monitor_off();
return 0;
}
int _set_audio_pitch_on(lua_State *l) {
(void)l;
o_set_audio_pitch_on();
return 0;
}
int _set_audio_pitch_off(lua_State *l) {
(void)l;
o_set_audio_pitch_off();
return 0;
}
int _tape_level(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
float val = (float) luaL_checknumber(l, 1);
o_tape_level(val);
lua_settop(l, 0);
return 0;
}
int _tape_new(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
const char *s = luaL_checkstring(l, 1);
o_tape_new((char *) s);
lua_settop(l, 0);
return 0;
}
int _tape_start_rec(lua_State *l) {
(void)l;
o_tape_start_rec();
return 0;
}
int _tape_pause_rec(lua_State *l) {
(void)l;
o_tape_pause_rec();
return 0;
}
int _tape_stop_rec(lua_State *l) {
(void)l;
o_tape_stop_rec();
return 0;
}
int _tape_open(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
const char *s = luaL_checkstring(l, 1);
o_tape_open((char *) s);
lua_settop(l, 0);
return 0;
}
int _tape_play(lua_State *l) {
(void)l;
o_tape_play();
return 0;
}
int _tape_pause(lua_State *l) {
(void)l;
o_tape_pause();
return 0;
}
int _tape_stop(lua_State *l) {
(void)l;
o_tape_stop();
return 0;
}
// aux effects controls
int _set_aux_fx_on(lua_State *l) {
(void)l;
o_set_aux_fx_on();
return 0;
}
int _set_aux_fx_off(lua_State *l) {
(void)l;
o_set_aux_fx_off();
return 0;
}
int _set_aux_fx_input_level(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
int idx = (int) luaL_checkinteger(l, 1) - 1; // convert from 1-based
float val = (float) luaL_checknumber(l, 2);
o_set_aux_fx_input_level(idx, val);
return 0;
}
int _set_aux_fx_input_pan(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
int idx = (int) luaL_checkinteger(l, 1) - 1; // convert from 1-based
float val = (float) luaL_checknumber(l, 2);
o_set_aux_fx_input_pan(idx, val);
return 0;
}
int _set_aux_fx_output_level(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
float val = (float) luaL_checknumber(l, 1);
o_set_aux_fx_output_level(val);
return 0;
}
int _set_aux_fx_return_level(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
float val = (float) luaL_checknumber(l, 1);
o_set_aux_fx_return_level(val);
return 0;
}
int _set_aux_fx_param(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
const char *s = luaL_checkstring(l, 1);
float val = (float) luaL_checknumber(l, 2);
o_set_aux_fx_param(s, val);
return 0;
}
// insert effects controls
int _set_insert_fx_on(lua_State *l) {
(void)l;
o_set_insert_fx_on();
return 0;
}
int _set_insert_fx_off(lua_State *l) {
(void)l;
o_set_insert_fx_off();
return 0;
}
int _set_insert_fx_mix(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
float val = (float) luaL_checknumber(l, 1);
o_set_insert_fx_mix(val);
return 0;
}
int _set_insert_fx_param(lua_State *l) {
if (lua_gettop(l) != 2) {
return luaL_error(l, "wrong number of arguments");
}
const char *s = luaL_checkstring(l, 1);
float val = (float) luaL_checknumber(l, 2);
o_set_insert_fx_param(s, val);
return 0;
}
int _start_audio(lua_State *l) {
(void)l;
norns_hello_start();
return 0;
}
int _restart_audio(lua_State *l) {
(void)l;
o_restart_audio();
norns_hello_start();
return 0;
}
int _sound_file_inspect(lua_State *l) {
if (lua_gettop(l) != 1) {
return luaL_error(l, "wrong number of arguments");
}
const char *path = luaL_checkstring(l, 1);
struct snd_file_desc desc = snd_file_inspect(path);
lua_pushinteger(l, desc.channels);
lua_pushinteger(l, desc.frames);
lua_pushinteger(l, desc.samplerate);
return 3;
}