add lua-session commandline tool
authorRobin Gareus <robin@gareus.org>
Sat, 30 Jan 2016 16:26:14 +0000 (17:26 +0100)
committerRobin Gareus <robin@gareus.org>
Tue, 23 Feb 2016 14:43:03 +0000 (15:43 +0100)
gtk2_ardour/arlua [new file with mode: 0755]
tools/luadevel/ardour-lua.sh.in [new file with mode: 0644]
tools/luadevel/devel.cc [new file with mode: 0644]
tools/luadevel/luasession.cc [new file with mode: 0644]
tools/luadevel/wscript [new file with mode: 0755]
wscript

diff --git a/gtk2_ardour/arlua b/gtk2_ardour/arlua
new file mode 100755 (executable)
index 0000000..d8cec78
--- /dev/null
@@ -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
diff --git a/tools/luadevel/ardour-lua.sh.in b/tools/luadevel/ardour-lua.sh.in
new file mode 100644 (file)
index 0000000..50d6e6e
--- /dev/null
@@ -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 "$@"
diff --git a/tools/luadevel/devel.cc b/tools/luadevel/devel.cc
new file mode 100644 (file)
index 0000000..3caa051
--- /dev/null
@@ -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;
+}
diff --git a/tools/luadevel/luasession.cc b/tools/luadevel/luasession.cc
new file mode 100644 (file)
index 0000000..5ddea90
--- /dev/null
@@ -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;
+}
diff --git a/tools/luadevel/wscript b/tools/luadevel/wscript
new file mode 100755 (executable)
index 0000000..730f08a
--- /dev/null
@@ -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']
diff --git a/wscript b/wscript
index 69ea9b3220e37eb2673cf68d20c340df5ce3c858..30a710afe6ec86bccb3c3a67a77b65a68bb657a5 100644 (file)
--- a/wscript
+++ b/wscript
@@ -230,6 +230,7 @@ children = [
         'libs/vfork',
         'libs/ardouralsautil',
         'cfgtool',
+        'tools/luadevel',
 ]
 
 i18n_children = [