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 */
123 static int do_audio_midi_setup (uint32_t desired_sample_rate)
125 return AudioEngine::instance ()->start ();
130 if (!ARDOUR::init (false, true, localedir)) {
131 cerr << "Ardour failed to initialize\n" << endl;
132 ::exit (EXIT_FAILURE);
135 assert (!event_loop);
136 event_loop = new MyEventLoop ("lua");
137 EventLoop::set_event_loop_for_thread (event_loop);
138 SessionEvent::create_per_thread_pool ("lua", 4096);
140 static LuaReceiver lua_receiver;
142 lua_receiver.listen_to (error);
143 lua_receiver.listen_to (info);
144 lua_receiver.listen_to (fatal);
145 lua_receiver.listen_to (warning);
147 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (engine_connections, &do_audio_midi_setup);
150 static void set_session (ARDOUR::Session *s)
154 lua_State* L = lua->getState ();
155 LuaBindings::set_session (L, session);
156 lua->collect_garbage (); // drop references
159 static void unset_session ()
161 session_connections.drop_connections ();
165 static int prepare_engine ()
167 AudioEngine* engine = AudioEngine::instance ();
169 if (!engine->current_backend ()) {
170 if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) {
171 std::cerr << "Cannot create Audio/MIDI engine\n";
176 if (!engine->current_backend ()) {
177 std::cerr << "Cannot create Audio/MIDI engine\n";
181 if (engine->running ()) {
187 static int start_engine (uint32_t rate)
189 AudioEngine* engine = AudioEngine::instance ();
191 if (engine->set_sample_rate (rate)) {
192 std::cerr << "Cannot set session's samplerate.\n";
196 if (engine->start () != 0) {
197 std::cerr << "Cannot start Audio/MIDI engine\n";
204 static Session * _create_session (string dir, string state, uint32_t rate) // throws
206 if (prepare_engine ()) {
210 std::string s = Glib::build_filename (dir, state + statefile_suffix);
211 if (Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
212 std::cerr << "Session already exists: " << s << "\n";
216 if (start_engine (rate)) {
220 // TODO add option/bindings for this
221 BusProfile bus_profile;
222 bus_profile.master_out_channels = 2;
224 AudioEngine* engine = AudioEngine::instance ();
225 Session* session = new Session (*engine, dir, state, &bus_profile);
229 static Session * _load_session (string dir, string state) // throws
231 if (prepare_engine ()) {
238 std::string s = Glib::build_filename (dir, state + statefile_suffix);
239 if (!Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
240 std::cerr << "Cannot find session: " << s << "\n";
244 if (Session::get_info_from_path (s, sr, sf, v) != 0) {
245 std::cerr << "Cannot get samplerate from session.\n";
249 if (start_engine (sr)) {
253 AudioEngine* engine = AudioEngine::instance ();
254 Session* session = new Session (*engine, dir, state);
258 /* ****************************************************************************/
259 /* lua bound functions */
261 static Session* create_session (string dir, string state, uint32_t rate)
265 cerr << "Session already open" << "\n";
269 s = _create_session (dir, state, rate);
270 } catch (failed_constructor& e) {
271 cerr << "failed_constructor: " << e.what () << "\n";
273 } catch (AudioEngine::PortRegistrationFailure& e) {
274 cerr << "PortRegistrationFailure: " << e.what () << "\n";
276 } catch (exception& e) {
277 cerr << "exception: " << e.what () << "\n";
280 cerr << "unknown exception.\n";
283 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
288 s->DropReferences.connect_same_thread (session_connections, &unset_session);
292 static Session* load_session (string dir, string state)
296 cerr << "Session already open" << "\n";
300 s = _load_session (dir, state);
301 } catch (failed_constructor& e) {
302 cerr << "failed_constructor: " << e.what () << "\n";
304 } catch (AudioEngine::PortRegistrationFailure& e) {
305 cerr << "PortRegistrationFailure: " << e.what () << "\n";
307 } catch (exception& e) {
308 cerr << "exception: " << e.what () << "\n";
311 cerr << "unknown exception.\n";
314 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
319 s->DropReferences.connect_same_thread (session_connections, &unset_session);
323 static int set_debug_options (const char *opts)
325 return PBD::parse_debug_options (opts);
328 static void close_session ()
334 static int close_session_lua (lua_State *L)
337 cerr << "No open session" << "\n";
344 static void delay (float d) {
346 Glib::usleep (d * 1000000);
350 static int do_quit (lua_State *L)
352 keep_running = false;
356 /* ****************************************************************************/
358 static void my_lua_print (std::string s) {
359 std::cout << s << "\n";
362 static void setup_lua ()
366 lua = new LuaState ();
367 lua->Print.connect (&my_lua_print);
368 lua_State* L = lua->getState ();
370 LuaBindings::stddef (L);
371 LuaBindings::common (L);
372 LuaBindings::session (L);
373 LuaBindings::osc (L);
375 luabridge::getGlobalNamespace (L)
376 .beginNamespace ("_G")
377 .addFunction ("create_session", &create_session)
378 .addFunction ("load_session", &load_session)
379 .addFunction ("close_session", &close_session)
380 .addFunction ("sleep", &delay)
381 .addFunction ("quit", &do_quit)
382 .addFunction ("set_debug_options", &set_debug_options)
385 // add a Session::close() method
386 luabridge::getGlobalNamespace (L)
387 .beginNamespace ("ARDOUR")
388 .beginClass <Session> ("Session")
389 .addExtCFunction ("close", &close_session_lua)
393 // push instance to global namespace (C++ lifetime)
394 luabridge::push <AudioEngine *> (L, AudioEngine::create ());
395 lua_setglobal (L, "AudioEngine");
397 AudioEngine::instance ()->stop ();
401 incomplete (lua_State* L, int status) {
402 if (status == LUA_ERRSYNTAX) {
404 const char *msg = lua_tolstring (L, -1, &lmsg);
405 if (lmsg >= 5 && strcmp(msg + lmsg - 5, "<eof>") == 0) {
413 int main (int argc, char **argv)
419 std::string histfile = Glib::build_filename (user_config_directory(), "/luahist");
421 rl_bind_key ('\t', rl_insert); // disable completion
422 read_history (histfile.c_str());
425 while (keep_running && (line = readline ("> "))) {
427 if (!strcmp (line, "quit")) {
428 free (line); line = NULL;
432 if (strlen (line) == 0) {
433 free (line); line = NULL;
439 lua_State* L = lt.getState ();
440 int status = luaL_loadbuffer (L, line, strlen(line), "=stdin");
441 if (!incomplete (L, status)) {
444 char *l2 = readline (">> ");
448 if (strlen (l2) == 0) {
451 line = (char*) realloc ((void*)line, (strlen(line) + strlen (l2) + 2) * sizeof(char));
457 if (lua->do_command (line)) {
459 free (line); line = NULL;
465 free (line); line = NULL;
474 engine_connections.drop_connections ();
479 write_history (histfile.c_str());
481 AudioEngine::instance ()->stop ();
482 AudioEngine::destroy ();
487 pthread_cancel_all ();