12 #include "pbd/debug.h"
13 #include "pbd/event_loop.h"
14 #include "pbd/error.h"
15 #include "pbd/failed_constructor.h"
16 #include "pbd/pthread_utils.h"
17 #include "pbd/reallocpool.h"
18 #include "pbd/receiver.h"
19 #include "pbd/transmitter.h"
21 #include "ardour/ardour.h"
22 #include "ardour/audioengine.h"
23 #include "ardour/filename_extensions.h"
24 #include "ardour/filesystem_paths.h"
25 #include "ardour/luabindings.h"
26 #include "ardour/session.h"
27 #include "ardour/types.h"
28 #include "ardour/vst_types.h"
30 #include <readline/readline.h>
31 #include <readline/history.h>
33 #include "lua/luastate.h"
34 #include "LuaBridge/LuaBridge.h"
37 using namespace ARDOUR;
40 static const char* localedir = LOCALEDIR;
41 static PBD::ScopedConnectionList engine_connections;
42 static PBD::ScopedConnectionList session_connections;
43 static Session* session = NULL;
45 static bool keep_running = true;
47 /* extern VST functions */
48 int vstfx_init (void*) { return 0; }
50 void vstfx_destroy_editor (VSTState*) {}
52 class LuaReceiver : public Receiver
55 void receive (Transmitter::Channel chn, const char * str)
57 const char *prefix = "";
60 case Transmitter::Error:
63 case Transmitter::Info:
66 case Transmitter::Warning:
67 prefix = "[WARNING]: ";
69 case Transmitter::Fatal:
72 case Transmitter::Throw:
73 /* this isn't supposed to happen */
77 /* note: iostreams are already thread-safe: no external
81 std::cout << prefix << str << std::endl;
83 if (chn == Transmitter::Fatal) {
89 class MyEventLoop : public sigc::trackable, public EventLoop
92 MyEventLoop (std::string const& name) : EventLoop (name) {
93 run_loop_thread = Glib::Threads::Thread::self ();
96 void call_slot (InvalidationRecord* ir, const boost::function<void()>& f) {
97 if (Glib::Threads::Thread::self () == run_loop_thread) {
98 cout << string_compose ("%1/%2 direct dispatch of call slot via functor @ %3, invalidation %4\n", event_loop_name(), pthread_name(), &f, ir);
101 cout << string_compose ("%1/%2 queue call-slot using functor @ %3, invalidation %4\n", event_loop_name(), pthread_name(), &f, ir);
103 f (); // XXX TODO, queue and process during run ()
108 ; // TODO process Events, if any
111 Glib::Threads::Mutex& slot_invalidation_mutex () { return request_buffer_map_lock; }
114 Glib::Threads::Thread* run_loop_thread;
115 Glib::Threads::Mutex request_buffer_map_lock;
118 static MyEventLoop *event_loop = NULL;
120 /* ****************************************************************************/
121 /* internal helper fn and callbacks */
125 if (!ARDOUR::init (false, true, localedir)) {
126 cerr << "Ardour failed to initialize\n" << endl;
127 ::exit (EXIT_FAILURE);
130 assert (!event_loop);
131 event_loop = new MyEventLoop ("lua");
132 EventLoop::set_event_loop_for_thread (event_loop);
133 SessionEvent::create_per_thread_pool ("lua", 4096);
135 static LuaReceiver lua_receiver;
137 lua_receiver.listen_to (error);
138 lua_receiver.listen_to (info);
139 lua_receiver.listen_to (fatal);
140 lua_receiver.listen_to (warning);
143 static void set_session (ARDOUR::Session *s)
147 lua_State* L = lua->getState ();
148 LuaBindings::set_session (L, session);
149 lua->collect_garbage (); // drop references
152 static void unset_session ()
154 session_connections.drop_connections ();
158 static int prepare_engine ()
160 AudioEngine* engine = AudioEngine::instance ();
162 if (!engine->current_backend ()) {
163 if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) {
164 std::cerr << "Cannot create Audio/MIDI engine\n";
169 if (!engine->current_backend ()) {
170 std::cerr << "Cannot create Audio/MIDI engine\n";
174 if (engine->running ()) {
180 static int start_engine (uint32_t rate)
182 AudioEngine* engine = AudioEngine::instance ();
184 if (engine->set_sample_rate (rate)) {
185 std::cerr << "Cannot set session's samplerate.\n";
189 if (engine->start () != 0) {
190 std::cerr << "Cannot start Audio/MIDI engine\n";
197 static Session * _create_session (string dir, string state, uint32_t rate) // throws
199 if (prepare_engine ()) {
203 std::string s = Glib::build_filename (dir, state + statefile_suffix);
204 if (Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
205 std::cerr << "Session already exists: " << s << "\n";
209 if (start_engine (rate)) {
213 // TODO add option/bindings for this
214 BusProfile bus_profile;
215 bus_profile.master_out_channels = 2;
217 AudioEngine* engine = AudioEngine::instance ();
218 Session* session = new Session (*engine, dir, state, &bus_profile);
222 static Session * _load_session (string dir, string state) // throws
224 if (prepare_engine ()) {
231 std::string s = Glib::build_filename (dir, state + statefile_suffix);
232 if (!Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
233 std::cerr << "Cannot find session: " << s << "\n";
237 if (Session::get_info_from_path (s, sr, sf, v) != 0) {
238 std::cerr << "Cannot get samplerate from session.\n";
242 if (start_engine (sr)) {
246 AudioEngine* engine = AudioEngine::instance ();
247 Session* session = new Session (*engine, dir, state);
251 /* ****************************************************************************/
252 /* lua bound functions */
254 static Session* create_session (string dir, string state, uint32_t rate)
258 cerr << "Session already open" << "\n";
262 s = _create_session (dir, state, rate);
263 } catch (failed_constructor& e) {
264 cerr << "failed_constructor: " << e.what () << "\n";
266 } catch (AudioEngine::PortRegistrationFailure& e) {
267 cerr << "PortRegistrationFailure: " << e.what () << "\n";
269 } catch (exception& e) {
270 cerr << "exception: " << e.what () << "\n";
273 cerr << "unknown exception.\n";
276 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
281 s->DropReferences.connect_same_thread (session_connections, &unset_session);
285 static Session* load_session (string dir, string state)
289 cerr << "Session already open" << "\n";
293 s = _load_session (dir, state);
294 } catch (failed_constructor& e) {
295 cerr << "failed_constructor: " << e.what () << "\n";
297 } catch (AudioEngine::PortRegistrationFailure& e) {
298 cerr << "PortRegistrationFailure: " << e.what () << "\n";
300 } catch (exception& e) {
301 cerr << "exception: " << e.what () << "\n";
304 cerr << "unknown exception.\n";
307 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
312 s->DropReferences.connect_same_thread (session_connections, &unset_session);
316 static int set_debug_options (const char *opts)
318 return PBD::parse_debug_options (opts);
321 static void close_session ()
327 static int close_session_lua (lua_State *L)
330 cerr << "No open session" << "\n";
337 static void delay (float d) {
339 Glib::usleep (d * 1000000);
343 static int do_quit (lua_State *L)
345 keep_running = false;
349 /* ****************************************************************************/
351 static void my_lua_print (std::string s) {
352 std::cout << s << "\n";
355 static void setup_lua ()
359 lua = new LuaState ();
360 lua->Print.connect (&my_lua_print);
361 lua_State* L = lua->getState ();
363 LuaBindings::stddef (L);
364 LuaBindings::common (L);
365 LuaBindings::session (L);
366 LuaBindings::osc (L);
368 luabridge::getGlobalNamespace (L)
369 .beginNamespace ("_G")
370 .addFunction ("create_session", &create_session)
371 .addFunction ("load_session", &load_session)
372 .addFunction ("close_session", &close_session)
373 .addFunction ("sleep", &delay)
374 .addFunction ("quit", &do_quit)
375 .addFunction ("set_debug_options", &set_debug_options)
378 // add a Session::close() method
379 luabridge::getGlobalNamespace (L)
380 .beginNamespace ("ARDOUR")
381 .beginClass <Session> ("Session")
382 .addExtCFunction ("close", &close_session_lua)
386 // push instance to global namespace (C++ lifetime)
387 luabridge::push <AudioEngine *> (L, AudioEngine::create ());
388 lua_setglobal (L, "AudioEngine");
390 AudioEngine::instance ()->stop ();
394 incomplete (lua_State* L, int status) {
395 if (status == LUA_ERRSYNTAX) {
397 const char *msg = lua_tolstring (L, -1, &lmsg);
398 if (lmsg >= 5 && strcmp(msg + lmsg - 5, "<eof>") == 0) {
406 int main (int argc, char **argv)
412 std::string histfile = Glib::build_filename (user_config_directory(), "/luahist");
414 rl_bind_key ('\t', rl_insert); // disable completion
415 read_history (histfile.c_str());
418 while (keep_running && (line = readline ("> "))) {
420 if (!strcmp (line, "quit")) {
421 free (line); line = NULL;
425 if (strlen (line) == 0) {
426 free (line); line = NULL;
432 lua_State* L = lt.getState ();
433 int status = luaL_loadbuffer (L, line, strlen(line), "=stdin");
434 if (!incomplete (L, status)) {
437 char *l2 = readline (">> ");
441 if (strlen (l2) == 0) {
444 line = (char*) realloc ((void*)line, (strlen(line) + strlen (l2) + 2) * sizeof(char));
450 if (lua->do_command (line)) {
452 free (line); line = NULL;
458 free (line); line = NULL;
467 engine_connections.drop_connections ();
472 write_history (histfile.c_str());
474 AudioEngine::instance ()->stop ();
475 AudioEngine::destroy ();
480 pthread_cancel_all ();