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", 512);
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 * _load_session (string dir, string state)
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 ()) {
179 std::string s = Glib::build_filename (dir, state + statefile_suffix);
180 if (!Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
181 std::cerr << "Cannot find session: " << s << "\n";
185 if (Session::get_info_from_path (s, sr, sf) == 0) {
186 if (engine->set_sample_rate (sr)) {
187 std::cerr << "Cannot set session's samplerate.\n";
191 std::cerr << "Cannot get samplerate from session.\n";
197 if (engine->start () != 0) {
198 std::cerr << "Cannot start Audio/MIDI engine\n";
202 Session* session = new Session (*engine, dir, state);
206 static Session* load_session (string dir, string state)
210 cerr << "Session already open" << "\n";
214 s = _load_session (dir, state);
215 } catch (failed_constructor& e) {
216 cerr << "failed_constructor: " << e.what () << "\n";
218 } catch (AudioEngine::PortRegistrationFailure& e) {
219 cerr << "PortRegistrationFailure: " << e.what () << "\n";
221 } catch (exception& e) {
222 cerr << "exception: " << e.what () << "\n";
225 cerr << "unknown exception.\n";
228 Glib::usleep (1000000); // allo signal propagation, callback/thread-pool setup
231 s->DropReferences.connect_same_thread (session_connections, &unset_session);
235 static void close_session ()
241 static int close_session_lua (lua_State *L)
244 cerr << "No open session" << "\n";
251 /* extern VST functions */
252 int vstfx_init (void*) { return 0; }
253 void vstfx_exit () {}
254 void vstfx_destroy_editor (VSTState*) {}
256 static void my_lua_print (std::string s) {
257 std::cout << s << "\n";
260 static void delay (float d) {
262 Glib::usleep (d * 1000000);
266 static void setup_lua ()
270 lua = new LuaState ();
271 lua->Print.connect (&my_lua_print);
272 lua_State* L = lua->getState ();
274 LuaBindings::stddef (L);
275 LuaBindings::common (L);
276 LuaBindings::session (L);
277 LuaBindings::osc (L);
279 luabridge::getGlobalNamespace (L)
280 .beginNamespace ("_G")
281 .addFunction ("load_session", &load_session)
282 .addFunction ("close_session", &close_session)
283 .addFunction ("sleep", &delay)
286 luabridge::getGlobalNamespace (L)
287 .beginNamespace ("ARDOUR")
288 .beginClass <Session> ("Session")
289 .addExtCFunction ("close", &close_session_lua)
293 // push instance to global namespace (C++ lifetime)
294 luabridge::push <AudioEngine *> (L, AudioEngine::create ());
295 lua_setglobal (L, "AudioEngine");
298 int main (int argc, char **argv)
304 std::string histfile = Glib::build_filename (user_config_directory(), "/luahist");
306 read_history (histfile.c_str());
309 while ((line = readline ("> "))) {
311 if (!strcmp (line, "quit")) {
314 if (strlen (line) == 0) {
317 if (!lua->do_command (line)) {
318 add_history (line); // OK
320 add_history (line); // :)
331 engine_connections.drop_connections ();
336 write_history (histfile.c_str());
338 AudioEngine::instance ()->stop ();
339 AudioEngine::destroy ();
344 pthread_cancel_all ();