Permalink
Cannot retrieve contributors at this time
| /*** | |
| * 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; | |
| } | |