Linux vessel [was: L Re: [Lua-av] Hi there]
Graham Wakefield
lists at grahamwakefield.net
Mon Dec 17 08:15:21 PST 2007
On Dec 17, 2007, at 4:42 AM, Frank Barknecht wrote:
>>
>
> Okay, I now have vessel running in Pd!
Alright!
> I took the naive approach and basically just used a Vessel object
> inside the Pd class struct, without even thinking about threading nor
> clocks for now. I called the object [vessel~] for now. Attached is the
> code, with a SConstruct for building it also on Win/OS-X (untested)
> and an example Pd patch.
>
> So far the object is hardcoded to one signal inlet and one signal
> outlet. I copied some stuff from the Max object, the code should be
> easy to follow.
>
> There is no message interface so far: All you can do is give a
> lua/vessel-script as argument, and then it runs that. There is code to
> change that script at runtime with an "open x" message, but that
> doesn't work. Probably a silly bug. Am I right to assume, that once I
> have a Vessel-instance, I can just call Vessel->dofile(...) again to
> load a new script, overwriting the old one?
Well, if you want to keep the same messaging interface as the Max
object, this is what it responds to:
file [filename]
loads a new file, or reloads the same file if the argument is omitted.
In the Max object, I read the file contents into a char * array, and
store it in the Max struct as 'script'. When the audio DSP function
is called, I check if the script pointer is not NULL, and call the
script into Vessel accordingly:
// check if there's a new file to load:
if (script != NULL)
{
vessel->doscript(script);
script = NULL;
}
That's the thread-safe version. The non-thread-safe version would
just call vessel->dofile() on the filename (with a unix style path).
[the max object also has an editor window that can open, and write
changes to the script, so it has additional messages for autosave,
fontsize etc., and the 'open' message opens the editor window. I
guess that's not doable in PD? There's also an autowatch option,
which is really handy - it reloads the file whenever it is modified
by an external editor. I'm not sure how this is done, I'm just using
some Max library routines, but if anything this would be the best
thing to support]
enable 0/1
turns processing of vessel on or off. pretty simple flag as to
whether to call vessel->execute() or not.
call [func args...], bang
calls the global function func in the script, passing it args
(coerced to Lua types). Also bang just calls the global 'bang'
function if defined. Something like this should work (not sure if
t_atom is right for PD):
lua_getglobal(L, func); // get the function name
if (lua_type(L, -1) == LUA_TFUNCTION) {
for (i=0; i<argc; i++) { // push the arguments
t_atom a = argv[i];
switch (a->a_type) {
case A_SYM:
lua_pushstring(L, a->a_w.w_sym->s_name);
break;
case A_LONG:
lua_pushinteger(L, a->a_w.w_long);
break;
case A_FLOAT:
lua_pushnumber(L, a->a_w.w_float);
break;
default:
lua_pushnil(L);
}
}
} else {
error("function %s not defined", a->a_w.w_sym->s_name);
lua_pop(L, 1); // remove function
}
vessel->go(L, vessel->now); // launch the function as a new coroutine-
task
dostring [symbol]
loads the message symbol into the Lua state as Lua code and calls it.
// convert string to function:
if (luaL_loadstring(L, string) {
error("Lua dostring parsing error: %s", lua_tostring(L, -1));
} if (lua_type(L, 1) == LUA_TFUNCTION) {
vessel->go(L, vessel->now);
} else {
error("dostring compile failed on %s", string);
}
set [foo arg]
sets the global variable foo to the value arg (coerced to a Lua type)
switch (arg->a_type) {
case A_SYM:
lua_pushstring(L, a->a_w.w_sym->s_name); break;
case A_LONG:
lua_pushinteger(L, a->a_w.w_long); break;
case A_FLOAT:
lua_pushnumber(L, a->a_w.w_float); break;
default:
lua_pushnil(L);
}
lua_setglobal(L, foo);
get [foo]
sends the message [foo x] out of the message outlet, where x is
coerced from Lua to Max types.
lua_getglobal(L, foo);
t_atom v;
switch (lua_type(L, -1)) {
case LUA_TNUMBER:
SETFLOAT(&v, lua_tonumber(L, -1)); break;
case LUA_TSTRING:
SETSYM(&v, gensym((char *)lua_tostring(L, -1))); break;
default:
SETSYM(&v, gensym((char *)lua_typename(L, lua_type(L, -1))));
}
outlet_anything(msgoutlet, gensym(name), 1, &v); // this is probably
different in PD
lua_pop(L, 1); // pop the value off the stack
Also, in the Lua state I push a few functions that are specific to
Max, and these would need the equivalent in PD:
outlet(msg, ...) -> sends messages out of the lua~ object
print(...), -> prints to the max window
error(msg) -> prints errors to the max window
Here are their equivalents in Max:
static int max_print(lua_State *L) {
int i, t = lua_gettop(L);
if (t) {
char msg[32];
for (i=1; i <= t; i++) {
switch (lua_type(L, i)) {
case LUA_TNIL:
post("nil"); break;
case LUA_TBOOLEAN:
post(lua_toboolean(L, i) ? "true" : "false"); break;
case LUA_TSTRING:
post(lua_tostring(L, i)); break;
case LUA_TNUMBER:
sprintf(msg, "%f", lua_tonumber(L, i));
post(msg); break;
case LUA_TUSERDATA:
lua_getglobal(L, "tostring");
lua_pushvalue(L, i);
lua_pcall(L, 1, 1, 0);
post(lua_tostring(L, -1));
lua_pop(L, 1); break;
default:
sprintf(msg, "%s (%p)", lua_typename(L, lua_type(L, i)),
lua_topointer(L, i));
post(msg);
}
}
} else {
post(NULL);
}
return 0;
}
static int max_error(lua_State * L) {
error(lua_tostring(L, -1));
return 0;
}
static int max_outlet(lua_State * L)
{
const char * msg = 0;
int i = 0;
short argc = 0;
int t = lua_gettop(L);
if (t > 0) {
if (lua_type(L, i+1) == LUA_TSTRING) {
msg = lua_tostring(L, i+1);
i++;
}
}
if (!msg) msg = "outlet";
t_vessel_tilde * x = (t_vessel_tilde *)lua_touserdata(L,
lua_upvalueindex(1));
while (i < t)
{
switch (lua_type(L, i+1)) {
case LUA_TNUMBER:
SETFLOAT(x->outlet_argv+argc, lua_tonumber(L, i+1));
break;
case LUA_TSTRING:
SETSYM(x->outlet_argv+argc, gensym((char *)lua_tostring(L, i+1)));
break;
default:
SETSYM(x->outlet_argv+argc, gensym((char *)lua_typename(L,
lua_type(L, i+1))));
}
argc++;
i++;
}
outlet_anything(x->msgoutlet, gensym((char *)msg), argc, x-
>outlet_argv);
return 0;
}
And to register these functions with the Lua state, call these in
vessel_tilde_dsp after the line x->vessel = new Vessel(1, 1, sys_getsr
()); (line 83):
lua_State * L = vessel->getLUA();
lua_pushlightuserdata(L, x);
lua_pushcclosure(L, max_outlet, 1);
lua_setglobal(L, "outlet");
lua_pushcfunction(L, max_print);
lua_setglobal(L, "print");
lua_pushcfunction(L, max_error);
lua_setfield(L, LUA_REGISTRYINDEX, "error");
I'll see if I can get it to build on OSX here - do I need to build
all of PD, or is there a binary lib I can link to?
>
> Have fun.
>
> Ciao
> --
> Frank Barknecht _
> ______footils.org__<vessel~.tgz>______________________________________
> _________
> Lua-av mailing list
> Lua-av at mat.ucsb.edu
> http://zydeco.mat.ucsb.edu/mailman/listinfo/lua-av
Be seeing you
grrr waaa
www.grahamwakefield.net
More information about the Lua-av
mailing list