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";
205 static Session * _create_session (string dir, string state, uint32_t rate) // throws
207 if (prepare_engine ()) {
211 std::string s = Glib::build_filename (dir, state + statefile_suffix);
212 if (Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
213 std::cerr << "Session already exists: " << s << "\n";
217 if (start_engine (rate)) {
221 // TODO add option/bindings for this
222 BusProfile bus_profile;
223 bus_profile.master_out_channels = 2;
224 bus_profile.input_ac = AutoConnectPhysical;
225 bus_profile.output_ac = AutoConnectMaster;
226 bus_profile.requested_physical_in = 0; // use all available
227 bus_profile.requested_physical_out = 0; // use all available
229 AudioEngine* engine = AudioEngine::instance ();
230 Session* session = new Session (*engine, dir, state, &bus_profile);
234 static Session * _load_session (string dir, string state) // throws
236 if (prepare_engine ()) {
243 std::string s = Glib::build_filename (dir, state + statefile_suffix);
244 if (!Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
245 std::cerr << "Cannot find session: " << s << "\n";
249 if (Session::get_info_from_path (s, sr, sf, v) != 0) {
250 std::cerr << "Cannot get samplerate from session.\n";
254 if (start_engine (sr)) {
258 AudioEngine* engine = AudioEngine::instance ();
259 Session* session = new Session (*engine, dir, state);
263 /* ****************************************************************************/
264 /* lua bound functions */
266 static Session* create_session (string dir, string state, uint32_t rate)
270 cerr << "Session already open" << "\n";
274 s = _create_session (dir, state, rate);
275 } catch (failed_constructor& e) {
276 cerr << "failed_constructor: " << e.what () << "\n";
278 } catch (AudioEngine::PortRegistrationFailure& e) {
279 cerr << "PortRegistrationFailure: " << e.what () << "\n";
281 } catch (exception& e) {
282 cerr << "exception: " << e.what () << "\n";
285 cerr << "unknown exception.\n";
288 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
293 s->DropReferences.connect_same_thread (session_connections, &unset_session);
297 static Session* load_session (string dir, string state)
301 cerr << "Session already open" << "\n";
305 s = _load_session (dir, state);
306 } catch (failed_constructor& e) {
307 cerr << "failed_constructor: " << e.what () << "\n";
309 } catch (AudioEngine::PortRegistrationFailure& e) {
310 cerr << "PortRegistrationFailure: " << e.what () << "\n";
312 } catch (exception& e) {
313 cerr << "exception: " << e.what () << "\n";
316 cerr << "unknown exception.\n";
319 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
324 s->DropReferences.connect_same_thread (session_connections, &unset_session);
328 static int set_debug_options (const char *opts)
330 return PBD::parse_debug_options (opts);
333 static void close_session ()
339 static int close_session_lua (lua_State *L)
342 cerr << "No open session" << "\n";
349 static void delay (float d) {
351 Glib::usleep (d * 1000000);
355 static int do_quit (lua_State *L)
357 keep_running = false;
361 /* ****************************************************************************/
363 static void my_lua_print (std::string s) {
364 std::cout << s << "\n";
367 static void setup_lua ()
371 lua = new LuaState ();
372 lua->Print.connect (&my_lua_print);
373 lua_State* L = lua->getState ();
375 LuaBindings::stddef (L);
376 LuaBindings::common (L);
377 LuaBindings::session (L);
378 LuaBindings::osc (L);
380 luabridge::getGlobalNamespace (L)
381 .beginNamespace ("_G")
382 .addFunction ("create_session", &create_session)
383 .addFunction ("load_session", &load_session)
384 .addFunction ("close_session", &close_session)
385 .addFunction ("sleep", &delay)
386 .addFunction ("quit", &do_quit)
387 .addFunction ("set_debug_options", &set_debug_options)
390 // add a Session::close() method
391 luabridge::getGlobalNamespace (L)
392 .beginNamespace ("ARDOUR")
393 .beginClass <Session> ("Session")
394 .addExtCFunction ("close", &close_session_lua)
398 // push instance to global namespace (C++ lifetime)
399 luabridge::push <AudioEngine *> (L, AudioEngine::create ());
400 lua_setglobal (L, "AudioEngine");
402 AudioEngine::instance ()->stop ();
405 int main (int argc, char **argv)
411 std::string histfile = Glib::build_filename (user_config_directory(), "/luahist");
413 read_history (histfile.c_str());
416 while (keep_running && (line = readline ("> "))) {
418 if (!strcmp (line, "quit")) {
419 free (line); line = NULL;
423 if (strlen (line) == 0) {
424 free (line); line = NULL;
428 if (lua->do_command (line)) {
434 free (line); line = NULL;
443 engine_connections.drop_connections ();
448 write_history (histfile.c_str());
450 AudioEngine::instance ()->stop ();
451 AudioEngine::destroy ();
456 pthread_cancel_all ();