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;
46 class LuaReceiver : public Receiver
49 void receive (Transmitter::Channel chn, const char * str)
51 const char *prefix = "";
54 case Transmitter::Error:
57 case Transmitter::Info:
60 case Transmitter::Warning:
61 prefix = "[WARNING]: ";
63 case Transmitter::Fatal:
66 case Transmitter::Throw:
67 /* this isn't supposed to happen */
71 /* note: iostreams are already thread-safe: no external
75 std::cout << prefix << str << std::endl;
77 if (chn == Transmitter::Fatal) {
83 class MyEventLoop : public sigc::trackable, public EventLoop
86 MyEventLoop (std::string const& name) : EventLoop (name) {
87 run_loop_thread = Glib::Threads::Thread::self ();
90 void call_slot (InvalidationRecord* ir, const boost::function<void()>& f) {
91 if (Glib::Threads::Thread::self () == run_loop_thread) {
92 //cout << string_compose ("%1/%2 direct dispatch of call slot via functor @ %3, invalidation %4\n", event_loop_name(), pthread_name(), &f, ir);
95 //cout << string_compose ("%1/%2 queue call-slot using functor @ %3, invalidation %4\n", event_loop_name(), pthread_name(), &f, ir);
97 f (); // XXX TODO, queue and process during run ()
102 ; // TODO process Events, if any
105 Glib::Threads::Mutex& slot_invalidation_mutex () { return request_buffer_map_lock; }
108 Glib::Threads::Thread* run_loop_thread;
109 Glib::Threads::Mutex request_buffer_map_lock;
112 static int do_audio_midi_setup (uint32_t desired_sample_rate)
114 return AudioEngine::instance ()->start ();
117 static MyEventLoop *event_loop = NULL;
121 if (!ARDOUR::init (false, true, localedir)) {
122 cerr << "Ardour failed to initialize\n" << endl;
123 ::exit (EXIT_FAILURE);
126 assert (!event_loop);
127 event_loop = new MyEventLoop ("lua");
128 EventLoop::set_event_loop_for_thread (event_loop);
129 SessionEvent::create_per_thread_pool ("lua", 4096);
131 static LuaReceiver lua_receiver;
133 lua_receiver.listen_to (error);
134 lua_receiver.listen_to (info);
135 lua_receiver.listen_to (fatal);
136 lua_receiver.listen_to (warning);
138 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (engine_connections, &do_audio_midi_setup);
141 static void set_session (ARDOUR::Session *s)
145 lua_State* L = lua->getState ();
146 LuaBindings::set_session (L, _session);
147 lua->collect_garbage (); // drop references
150 static void unset_session ()
152 session_connections.drop_connections ();
156 static Session * _create_session (string dir, string state, uint32_t rate)
158 AudioEngine* engine = AudioEngine::instance ();
160 if (!engine->current_backend ()) {
161 if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) {
162 std::cerr << "Cannot create Audio/MIDI engine\n";
167 if (!engine->current_backend ()) {
168 std::cerr << "Cannot create Audio/MIDI engine\n";
172 if (engine->running ()) {
176 std::string s = Glib::build_filename (dir, state + statefile_suffix);
177 if (Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
178 std::cerr << "Session already exists: " << s << "\n";
182 engine->set_sample_rate (rate);
186 if (engine->start () != 0) {
187 std::cerr << "Cannot start Audio/MIDI engine\n";
191 Session* session = new Session (*engine, dir, state);
195 static Session * _load_session (string dir, string state)
197 AudioEngine* engine = AudioEngine::instance ();
199 if (!engine->current_backend ()) {
200 if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) {
201 std::cerr << "Cannot create Audio/MIDI engine\n";
206 if (!engine->current_backend ()) {
207 std::cerr << "Cannot create Audio/MIDI engine\n";
211 if (engine->running ()) {
218 std::string s = Glib::build_filename (dir, state + statefile_suffix);
219 if (!Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
220 std::cerr << "Cannot find session: " << s << "\n";
224 if (Session::get_info_from_path (s, sr, sf) == 0) {
225 if (engine->set_sample_rate (sr)) {
226 std::cerr << "Cannot set session's samplerate.\n";
230 std::cerr << "Cannot get samplerate from session.\n";
236 if (engine->start () != 0) {
237 std::cerr << "Cannot start Audio/MIDI engine\n";
241 Session* session = new Session (*engine, dir, state);
245 static Session* create_session (string dir, string state, uint32_t rate)
249 cerr << "Session already open" << "\n";
253 s = _create_session (dir, state, rate);
254 } catch (failed_constructor& e) {
255 cerr << "failed_constructor: " << e.what () << "\n";
257 } catch (AudioEngine::PortRegistrationFailure& e) {
258 cerr << "PortRegistrationFailure: " << e.what () << "\n";
260 } catch (exception& e) {
261 cerr << "exception: " << e.what () << "\n";
264 cerr << "unknown exception.\n";
267 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
272 s->DropReferences.connect_same_thread (session_connections, &unset_session);
276 static Session* load_session (string dir, string state)
280 cerr << "Session already open" << "\n";
284 s = _load_session (dir, state);
285 } catch (failed_constructor& e) {
286 cerr << "failed_constructor: " << e.what () << "\n";
288 } catch (AudioEngine::PortRegistrationFailure& e) {
289 cerr << "PortRegistrationFailure: " << e.what () << "\n";
291 } catch (exception& e) {
292 cerr << "exception: " << e.what () << "\n";
295 cerr << "unknown exception.\n";
298 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
303 s->DropReferences.connect_same_thread (session_connections, &unset_session);
307 static void close_session ()
313 static int close_session_lua (lua_State *L)
316 cerr << "No open session" << "\n";
323 /* extern VST functions */
324 int vstfx_init (void*) { return 0; }
325 void vstfx_exit () {}
326 void vstfx_destroy_editor (VSTState*) {}
328 static void my_lua_print (std::string s) {
329 std::cout << s << "\n";
332 static void delay (float d) {
334 Glib::usleep (d * 1000000);
338 static void setup_lua ()
342 lua = new LuaState ();
343 lua->Print.connect (&my_lua_print);
344 lua_State* L = lua->getState ();
346 LuaBindings::stddef (L);
347 LuaBindings::common (L);
348 LuaBindings::session (L);
349 LuaBindings::osc (L);
351 luabridge::getGlobalNamespace (L)
352 .beginNamespace ("_G")
353 .addFunction ("create_session", &create_session)
354 .addFunction ("load_session", &load_session)
355 .addFunction ("close_session", &close_session)
356 .addFunction ("sleep", &delay)
359 luabridge::getGlobalNamespace (L)
360 .beginNamespace ("ARDOUR")
361 .beginClass <Session> ("Session")
362 .addExtCFunction ("close", &close_session_lua)
366 // push instance to global namespace (C++ lifetime)
367 luabridge::push <AudioEngine *> (L, AudioEngine::create ());
368 lua_setglobal (L, "AudioEngine");
371 int main (int argc, char **argv)
377 std::string histfile = Glib::build_filename (user_config_directory(), "/luahist");
379 read_history (histfile.c_str());
382 while ((line = readline ("> "))) {
384 if (!strcmp (line, "quit")) {
387 if (strlen (line) == 0) {
390 if (!lua->do_command (line)) {
391 add_history (line); // OK
393 add_history (line); // :)
405 engine_connections.drop_connections ();
410 write_history (histfile.c_str());
412 AudioEngine::instance ()->stop ();
413 AudioEngine::destroy ();
418 pthread_cancel_all ();