13
0

add lua-session commandline tool

This commit is contained in:
Robin Gareus 2016-01-30 17:26:14 +01:00
parent 44ce56a9e1
commit 942471d21f
6 changed files with 764 additions and 0 deletions

21
gtk2_ardour/arlua Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh
TOP=`dirname "$0"`/..
. $TOP/build/gtk2_ardour/ardev_common_waf.sh
export UBUNTU_MENUPROXY=""
if [ $# -gt 0 ] ; then
case $1 in
-g|--gdb) GDB=gdb; shift ;;
esac
fi
if test -z "$GDB"; then
exec $TOP/build/tools/luadevel/luasession "$@"
fi
if test -n "`which gdb`"; then
exec gdb --args $TOP/build/tools/luadevel/luasession "$@"
fi
if test -n "`which lldb`"; then
exec lldb -- $TOP/build/tools/luadevel/luasession "$@"
fi

View File

@ -0,0 +1,9 @@
#!/bin/sh
export LD_LIBRARY_PATH=@LIBDIR@${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
export ARDOUR_DATA_PATH=@DATADIR@
export ARDOUR_CONFIG_PATH=@CONFDIR@
export ARDOUR_DLL_PATH=@LIBDIR@
export VAMP_PATH=@LIBDIR@/vamp
exec @LIBDIR@/luasession "$@"

296
tools/luadevel/devel.cc Normal file
View File

@ -0,0 +1,296 @@
#include <stdint.h>
#include <cstdio>
#include <iostream>
#include <string>
#include <list>
#include <vector>
#define LIBPBD_API
#include "../../libs/pbd/pbd/reallocpool.h"
#include "../../libs/pbd/reallocpool.cc"
#include <readline/readline.h>
#include <readline/history.h>
#include "lua/luastate.h"
#include "LuaBridge/LuaBridge.h"
static void my_lua_print (std::string s) {
std::cout << s << "\n";
}
class A {
public:
A() { printf ("CTOR\n"); _int = 4; for (int i = 0; i < 256; ++i) {arr[i] = i; ar2[i] = i/256.0; ar3[i] = i;} }
~A() { printf ("DTOR\n"); }
void set_int (int a) { _int = a; }
int get_int () const { return _int; }
int& get_ref () { return _int; }
int get_arg (int &a) { printf ("a = %d\n", a); a = _int; printf ("a = %d\n", a); return 1; }
void get_arg2 (int &a, int& b) { a = _int; b = 100; }
void get_args (std::string &a) { a = "hello"; }
void set_ref (int const &a) { _int = a; }
float * get_arr () { return arr; }
float * get_ar2 () { return ar2; }
int * get_ar3 () { return ar3; }
void set_list (std::list<std::string> sl) { _sl = sl; }
std::list<std::string>& get_list () { return _sl; }
uint32_t minone() { return -1; }
enum EN {
RV1 = 1, RV2, RV3
};
enum EN ret_enum () { return _en;}
void set_enum (enum EN en) { _en = en; }
private:
std::list<std::string> _sl;
int _int;
enum EN _en;
float arr[256];
float ar2[256];
int ar3[256];
};
int main (int argc, char **argv)
{
#if 0
LuaState lua;
#else
PBD::ReallocPool _mempool ("Devel", 1048576);
LuaState lua (lua_newstate (&PBD::ReallocPool::lalloc, &_mempool));
#endif
lua.Print.connect (&my_lua_print);
lua_State* L = lua.getState();
#if 1
luabridge::getGlobalNamespace (L)
.beginNamespace ("Test")
.beginStdList <std::string> ("StringList")
.endClass ()
.endNamespace ();
luabridge::getGlobalNamespace (L)
.beginNamespace ("Test")
.beginStdVector <std::string> ("StringVector")
.endClass ()
.endNamespace ();
luabridge::getGlobalNamespace (L)
.beginNamespace ("Test")
.beginStdMap <std::string,std::string> ("StringStringMap")
.endClass ()
.endNamespace ();
luabridge::getGlobalNamespace (L)
.beginNamespace ("Test")
.beginStdSet <std::string> ("StringSet")
.endClass ()
.endNamespace ();
luabridge::getGlobalNamespace (L)
.beginNamespace ("Test")
.registerArray <float> ("FloatArray")
.registerArray <int> ("IntArray")
.beginClass <A> ("A")
.addConstructor <void (*) ()> ()
.addFunction ("set_int", &A::set_int)
.addFunction ("get_int", &A::get_int)
.addRefFunction ("get_arg", &A::get_arg)
.addRefFunction ("get_arg2", &A::get_arg2)
.addRefFunction ("get_args", &A::get_args)
.addFunction ("set_ref", &A::set_ref)
.addFunction ("get_list", &A::get_list)
.addFunction ("set_list", &A::set_list)
.addFunction ("ret_enum", &A::ret_enum)
.addFunction ("set_enum", &A::set_enum)
.addFunction ("get_arr", &A::get_arr)
.addFunction ("get_ar2", &A::get_ar2)
.addFunction ("get_ar3", &A::get_ar3)
.endClass ()
.endNamespace ();
luabridge::getGlobalNamespace (L)
.beginNamespace ("Test")
.beginClass <A> ("A")
.addFunction ("minone", &A::minone)
.addConst ("cologne", 4711)
.endClass ()
.addConst ("koln", 4711)
.endNamespace ();
#endif
#if 0 // session script test
lua.do_command (
"function ArdourSession ()"
" local self = { scripts = {}, instances = {} }"
""
" local foreach = function (fn)"
" for n, s in pairs (self.scripts) do"
" fn (n, s)"
" end"
" end"
""
" local run = function ()"
" for n, s in pairs (self.instances) do"
" local status, err = pcall (s)"
" if not status then print ('fn \"'.. n .. '\": ', err) end"
" end"
" collectgarbage()"
" end"
""
" local add = function (n, f, a)"
" assert(type(n) == 'string', 'function-name must be string')"
" assert(type(f) == 'function', 'Given script is a not a function')"
" assert(type(a) == 'table' or type(a) == 'nil', 'Given argument is invalid')"
" assert(self.scripts[n] == nil, 'Callback \"'.. n ..'\" already exists.')"
" self.scripts[n] = { ['f'] = f, ['a'] = a }"
" local env = { print = print, Session = Session, tostring = tostring, assert = assert, ipairs = ipairs, error = error, string = string, type = type, tonumber = tonumber, collectgarbage = collectgarbage, pairs = pairs, math = math, table = table, pcall = pcall }"
" self.instances[n] = load (string.dump(f), nil, nil, env)(a)"
" end"
""
" local remove = function (n)"
" self.scripts[n] = nil"
" end"
""
" local list = function ()"
" local rv = {}"
" foreach (function (n) rv[n] = true end)"
" return rv"
" end"
""
" local function basic_serialize (o)"
" if type(o) == \"number\" then"
" return tostring(o)"
" else"
" return string.format(\"%q\", o)"
" end"
" end"
""
" local function serialize (name, value)"
" local rv = name .. ' = '"
" if type(value) == \"number\" or type(value) == \"string\" or type(value) == \"nil\" then"
" return rv .. basic_serialize(value) .. ' '"
" elseif type(value) == \"table\" then"
" rv = rv .. '{} '"
" for k,v in pairs(value) do"
" local fieldname = string.format(\"%s[%s]\", name, basic_serialize(k))"
" rv = rv .. serialize(fieldname, v) .. ' '"
" end"
" return rv;"
" elseif type(value) == \"function\" then"
" return rv .. string.format(\"%q\", string.dump(value))"
" else"
" error('cannot save a ' .. type(value))"
" end"
" end"
""
""
" local save = function ()"
" return (serialize('scripts', self.scripts))"
" end"
""
" local restore = function (state)"
" self.scripts = {}"
" load (state)()"
" print (scripts)"
" for n, s in pairs (scripts) do"
" add (n, load(s['f']), s['a'])"
" end"
" end"
""
" return { run = run, add = add, remove = remove,"
" list = list, foreach = foreach,"
" restore = restore, save = save}"
" end"
" "
" sess = ArdourSession ()"
" ArdourSession = nil"
);
luabridge::LuaRef *lua_run;
luabridge::LuaRef *lua_add;
luabridge::LuaRef *lua_del;
luabridge::LuaRef *lua_save;
luabridge::LuaRef *lua_load;
{
luabridge::LuaRef lua_sess = luabridge::getGlobal (L, "sess");
lua.do_command ("sess = nil"); // hide it.
lua.do_command ("collectgarbage()");
lua_run = new luabridge::LuaRef(lua_sess["run"]);
lua_add = new luabridge::LuaRef(lua_sess["add"]);
lua_del = new luabridge::LuaRef(lua_sess["remove"]);
lua_save = new luabridge::LuaRef(lua_sess["save"]);
lua_load = new luabridge::LuaRef(lua_sess["restore"]);
}
lua.do_command ("collectgarbage()");
#if 1
lua.do_command ("function factory (t) return function () local p = t or { } local a = t[1] or 'Nibor' print ('Hello ' .. a) end end");
luabridge::LuaRef lua_fact = luabridge::getGlobal (L, "factory");
luabridge::LuaRef tbl_arg (luabridge::newTable(L));
//tbl_arg[1] = "Robin";
(*lua_add)("t2", lua_fact, tbl_arg);
#else
lua.do_command ("function factory (t) return function () print ('Boo') end end");
luabridge::LuaRef lua_fact = luabridge::getGlobal (L, "factory");
(*lua_add)("t2", lua_fact());
#endif
lua.do_command ("function factory (t) return function () print ('Ahoy') end end");
luabridge::LuaRef lua_fact2 = luabridge::getGlobal (L, "factory");
(*lua_add)("t1", lua_fact2);
luabridge::LuaRef savedstate ((*lua_save)());
std::string saved = savedstate.cast<std::string>();
(*lua_del)("t2");
try {
(*lua_run)();
} catch (luabridge::LuaException const& e) { printf ("LuaException: %s\n", e.what ()); }
(*lua_load)(saved);
for (int i = 0; i < 2; ++i) {
lua.do_command ("collectgarbage()");
lua.collect_garbage ();
try {
(*lua_run)();
} catch (luabridge::LuaException const& e) { printf ("LuaException: %s\n", e.what ()); }
}
#endif
add_history("a = Test:A() b = 2 c = 3 d = 'a'");
add_history("x = a:get_arg(b) y = a:get_arg2(b, c) z = a:get_args(d) ");
add_history("for i,n in ipairs(y) do print (i, n); end");
/////////////////////////////////////////////////////////////////////////////
char *line;
while ((line = readline ("> "))) {
if (!strcmp (line, "quit")) {
break;
}
if (strlen(line) == 0) {
//lua.do_command("collectgarbage();");
continue;
}
if (!lua.do_command (line)) {
add_history(line); // OK
} else {
add_history(line); // :)
}
}
printf("\n");
return 0;
}

View File

@ -0,0 +1,345 @@
#include <stdint.h>
#include <assert.h>
#include <cstdio>
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <glibmm.h>
#include "pbd/debug.h"
#include "pbd/event_loop.h"
#include "pbd/error.h"
#include "pbd/failed_constructor.h"
#include "pbd/pthread_utils.h"
#include "pbd/reallocpool.h"
#include "pbd/receiver.h"
#include "pbd/transmitter.h"
#include "ardour/ardour.h"
#include "ardour/audioengine.h"
#include "ardour/filename_extensions.h"
#include "ardour/filesystem_paths.h"
#include "ardour/luabindings.h"
#include "ardour/session.h"
#include "ardour/types.h"
#include "ardour/vst_types.h"
#include <readline/readline.h>
#include <readline/history.h>
#include "lua/luastate.h"
#include "LuaBridge/LuaBridge.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
static const char* localedir = LOCALEDIR;
static PBD::ScopedConnectionList engine_connections;
static PBD::ScopedConnectionList session_connections;
static Session *_session = NULL;
static LuaState *lua;
class LuaReceiver : public Receiver
{
protected:
void receive (Transmitter::Channel chn, const char * str)
{
const char *prefix = "";
switch (chn) {
case Transmitter::Error:
prefix = "[ERROR]: ";
break;
case Transmitter::Info:
/* ignore */
return;
case Transmitter::Warning:
prefix = "[WARNING]: ";
break;
case Transmitter::Fatal:
prefix = "[FATAL]: ";
break;
case Transmitter::Throw:
/* this isn't supposed to happen */
abort ();
}
/* note: iostreams are already thread-safe: no external
lock required.
*/
std::cout << prefix << str << std::endl;
if (chn == Transmitter::Fatal) {
::exit (9);
}
}
};
class MyEventLoop : public sigc::trackable, public EventLoop
{
public:
MyEventLoop (std::string const& name) : EventLoop (name) {
run_loop_thread = Glib::Threads::Thread::self ();
}
void call_slot (InvalidationRecord* ir, const boost::function<void()>& f) {
if (Glib::Threads::Thread::self () == run_loop_thread) {
//cout << string_compose ("%1/%2 direct dispatch of call slot via functor @ %3, invalidation %4\n", event_loop_name(), pthread_name(), &f, ir);
f ();
} else {
//cout << string_compose ("%1/%2 queue call-slot using functor @ %3, invalidation %4\n", event_loop_name(), pthread_name(), &f, ir);
assert (!ir);
f (); // XXX TODO, queue and process during run ()
}
}
void run () {
; // TODO process Events, if any
}
Glib::Threads::Mutex& slot_invalidation_mutex () { return request_buffer_map_lock; }
private:
Glib::Threads::Thread* run_loop_thread;
Glib::Threads::Mutex request_buffer_map_lock;
};
static int do_audio_midi_setup (uint32_t desired_sample_rate)
{
return AudioEngine::instance ()->start ();
}
static MyEventLoop *event_loop = NULL;
static void init ()
{
if (!ARDOUR::init (false, true, localedir)) {
cerr << "Ardour failed to initialize\n" << endl;
::exit (EXIT_FAILURE);
}
assert (!event_loop);
event_loop = new MyEventLoop ("lua");
EventLoop::set_event_loop_for_thread (event_loop);
SessionEvent::create_per_thread_pool ("lua", 512);
static LuaReceiver lua_receiver;
lua_receiver.listen_to (error);
lua_receiver.listen_to (info);
lua_receiver.listen_to (fatal);
lua_receiver.listen_to (warning);
ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (engine_connections, &do_audio_midi_setup);
}
static void set_session (ARDOUR::Session *s)
{
_session = s;
assert (lua);
lua_State* L = lua->getState ();
LuaBindings::set_session (L, _session);
lua->collect_garbage (); // drop references
}
static void unset_session ()
{
session_connections.drop_connections ();
set_session (NULL);
}
static Session * _load_session (string dir, string state)
{
AudioEngine* engine = AudioEngine::instance ();
if (!engine->current_backend ()) {
if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) {
std::cerr << "Cannot create Audio/MIDI engine\n";
return 0;
}
}
if (!engine->current_backend ()) {
std::cerr << "Cannot create Audio/MIDI engine\n";
return 0;
}
if (engine->running ()) {
engine->stop ();
}
float sr;
SampleFormat sf;
std::string s = Glib::build_filename (dir, state + statefile_suffix);
if (!Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
std::cerr << "Cannot find session: " << s << "\n";
return 0;
}
if (Session::get_info_from_path (s, sr, sf) == 0) {
if (engine->set_sample_rate (sr)) {
std::cerr << "Cannot set session's samplerate.\n";
return 0;
}
} else {
std::cerr << "Cannot get samplerate from session.\n";
return 0;
}
init_post_engine ();
if (engine->start () != 0) {
std::cerr << "Cannot start Audio/MIDI engine\n";
return 0;
}
Session* session = new Session (*engine, dir, state);
return session;
}
static Session* load_session (string dir, string state)
{
Session* s = 0;
if (_session) {
cerr << "Session already open" << "\n";
return 0;
}
try {
s = _load_session (dir, state);
} catch (failed_constructor& e) {
cerr << "failed_constructor: " << e.what () << "\n";
return 0;
} catch (AudioEngine::PortRegistrationFailure& e) {
cerr << "PortRegistrationFailure: " << e.what () << "\n";
return 0;
} catch (exception& e) {
cerr << "exception: " << e.what () << "\n";
return 0;
} catch (...) {
cerr << "unknown exception.\n";
return 0;
}
Glib::usleep (1000000); // allo signal propagation, callback/thread-pool setup
assert (s);
set_session (s);
s->DropReferences.connect_same_thread (session_connections, &unset_session);
return s;
}
static void close_session ()
{
delete _session;
assert (!_session);
}
static int close_session_lua (lua_State *L)
{
if (!_session) {
cerr << "No open session" << "\n";
return 0;
}
close_session ();
return 0;
}
/* extern VST functions */
int vstfx_init (void*) { return 0; }
void vstfx_exit () {}
void vstfx_destroy_editor (VSTState*) {}
static void my_lua_print (std::string s) {
std::cout << s << "\n";
}
static void delay (float d) {
if (d > 0) {
Glib::usleep (d * 1000000);
}
}
static void setup_lua ()
{
assert (!lua);
lua = new LuaState ();
lua->Print.connect (&my_lua_print);
lua_State* L = lua->getState ();
LuaBindings::stddef (L);
LuaBindings::common (L);
LuaBindings::session (L);
luabridge::getGlobalNamespace (L)
.beginNamespace ("_G")
.addFunction ("load_session", &load_session)
.addFunction ("close_session", &close_session)
.addFunction ("sleep", &delay)
.endNamespace ();
luabridge::getGlobalNamespace (L)
.beginNamespace ("ARDOUR")
.beginClass <Session> ("Session")
.addExtCFunction ("close", &close_session_lua)
.endClass ()
.endNamespace ();
// push instance to global namespace (C++ lifetime)
luabridge::push <AudioEngine *> (L, AudioEngine::create ());
lua_setglobal (L, "AudioEngine");
}
int main (int argc, char **argv)
{
init ();
setup_lua ();
using_history ();
std::string histfile = Glib::build_filename (user_config_directory(), "/luahist");
read_history (histfile.c_str());
char *line;
while ((line = readline ("> "))) {
event_loop->run();
if (!strcmp (line, "quit")) {
break;
}
if (strlen (line) == 0) {
continue;
}
if (!lua->do_command (line)) {
add_history (line); // OK
} else {
add_history (line); // :)
}
event_loop->run();
free (line);
}
printf ("\n");
if (_session) {
close_session ();
}
engine_connections.drop_connections ();
delete lua;
lua = NULL;
write_history (histfile.c_str());
AudioEngine::instance ()->stop ();
AudioEngine::destroy ();
// cleanup
ARDOUR::cleanup ();
delete event_loop;
pthread_cancel_all ();
return 0;
}

92
tools/luadevel/wscript Executable file
View File

@ -0,0 +1,92 @@
#!/usr/bin/env python
from waflib.extras import autowaf as autowaf
from waflib import Options, TaskGen
import waflib.Logs as Logs, waflib.Utils as Utils
import os
import shutil
import sys
import re
import time
from waflib.Task import Task
top = '.'
out = 'build'
def options(opt):
autowaf.set_options(opt)
def configure(conf):
conf.load('misc')
conf.load('compiler_cxx')
conf.check_cc(function_name='readline',
header_name='stdio.h readline/readline.h',
lib='readline',
uselib_store='READLINE',
mandatory=False)
autowaf.configure(conf)
def build(bld):
VERSION = "%s.%s" % (bld.env['MAJOR'], bld.env['MINOR'])
if not bld.is_defined('HAVE_READLINE'):
return;
# no wine
if bld.is_defined('WINDOWS_VST_SUPPORT') and bld.env['build_target'] != 'mingw':
return
# TEST/DEVEL TOOL #######################
obj = bld (features = 'cxx c cxxprogram')
obj.source = 'devel.cc'
obj.target = 'devel'
obj.uselib = ['SIGCPP', 'READLINE']
obj.use = ['liblua']
obj.install_path = None
#########################################
# commandline luasession wrapper
obj = bld(features = 'subst')
obj.source = 'ardour-lua.sh.in'
obj.target = 'ardour' + str (bld.env['MAJOR']) + '-lua'
obj.chmod = Utils.O755
obj.install_path = bld.env['BINDIR']
obj.LIBDIR = os.path.normpath(bld.env['DLLDIR'])
obj.DATADIR = os.path.normpath(bld.env['DATADIR'])
obj.CONFDIR = os.path.normpath(bld.env['CONFDIR'])
# commandline luasession
obj = bld (features = 'cxx c cxxprogram')
obj.source = 'luasession.cc'
obj.target = 'luasession'
obj.includes = ['../libs']
obj.use = ['liblua'
'libpbd',
'libardour',
'libardour_cp',
'libtimecode',
'libmidipp',
]
obj.defines = [
'VERSIONSTRING="' + str(bld.env['VERSION']) + '"',
'DATA_DIR="' + os.path.normpath(bld.env['DATADIR']) + '"',
'CONFIG_DIR="' + os.path.normpath(bld.env['SYSCONFDIR']) + '"',
'LOCALEDIR="' + os.path.join(os.path.normpath(bld.env['DATADIR']), 'locale') + '"',
'PACKAGE="' + "ARDOURUTILS" + '"',
]
obj.uselib = 'UUID FLAC FONTCONFIG GLIBMM GTHREAD OGG CURL DL'
obj.uselib += ' FFTW3F'
obj.uselib += ' AUDIOUNITS OSX LO '
obj.uselib += ' TAGLIB '
obj.uselib += ' READLINE '
if sys.platform == 'darwin':
obj.uselib += ' AUDIOUNITS OSX'
obj.use += ' libappleutility'
#if bld.env['build_target'] == 'mingw':
# if bld.env['DEBUG'] == False:
# obj.linkflags = ['-mwindows']
if bld.is_defined('NEED_INTL'):
obj.linkflags = ' -lintl'
obj.install_path = bld.env['DLLDIR']

View File

@ -230,6 +230,7 @@ children = [
'libs/vfork',
'libs/ardouralsautil',
'cfgtool',
'tools/luadevel',
]
i18n_children = [