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; }
112 Glib::Threads::Mutex& request_invalidation_mutex() { return request_invalidation_lock; }
115 Glib::Threads::Thread* run_loop_thread;
116 Glib::Threads::Mutex request_buffer_map_lock;
117 Glib::Threads::Mutex request_invalidation_lock;
120 static MyEventLoop *event_loop = NULL;
122 /* ****************************************************************************/
123 /* internal helper fn and callbacks */
125 static int do_audio_midi_setup (uint32_t desired_sample_rate)
127 return AudioEngine::instance ()->start ();
132 if (!ARDOUR::init (false, true, localedir)) {
133 cerr << "Ardour failed to initialize\n" << endl;
134 ::exit (EXIT_FAILURE);
137 assert (!event_loop);
138 event_loop = new MyEventLoop ("lua");
139 EventLoop::set_event_loop_for_thread (event_loop);
140 SessionEvent::create_per_thread_pool ("lua", 4096);
142 static LuaReceiver lua_receiver;
144 lua_receiver.listen_to (error);
145 lua_receiver.listen_to (info);
146 lua_receiver.listen_to (fatal);
147 lua_receiver.listen_to (warning);
149 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (engine_connections, &do_audio_midi_setup);
152 static void set_session (ARDOUR::Session *s)
156 lua_State* L = lua->getState ();
157 LuaBindings::set_session (L, session);
158 lua->collect_garbage (); // drop references
161 static void unset_session ()
163 session_connections.drop_connections ();
167 static int prepare_engine ()
169 AudioEngine* engine = AudioEngine::instance ();
171 if (!engine->current_backend ()) {
172 if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) {
173 std::cerr << "Cannot create Audio/MIDI engine\n";
178 if (!engine->current_backend ()) {
179 std::cerr << "Cannot create Audio/MIDI engine\n";
183 if (engine->running ()) {
189 static int start_engine (uint32_t rate)
191 AudioEngine* engine = AudioEngine::instance ();
193 if (engine->set_sample_rate (rate)) {
194 std::cerr << "Cannot set session's samplerate.\n";
198 if (engine->start () != 0) {
199 std::cerr << "Cannot start Audio/MIDI engine\n";
207 static Session * _create_session (string dir, string state, uint32_t rate) // throws
209 if (prepare_engine ()) {
213 std::string s = Glib::build_filename (dir, state + statefile_suffix);
214 if (Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
215 std::cerr << "Session already exists: " << s << "\n";
219 if (start_engine (rate)) {
223 // TODO add option/bindings for this
224 BusProfile bus_profile;
225 bus_profile.master_out_channels = 2;
226 bus_profile.input_ac = AutoConnectPhysical;
227 bus_profile.output_ac = AutoConnectMaster;
228 bus_profile.requested_physical_in = 0; // use all available
229 bus_profile.requested_physical_out = 0; // use all available
231 AudioEngine* engine = AudioEngine::instance ();
232 Session* session = new Session (*engine, dir, state, &bus_profile);
236 static Session * _load_session (string dir, string state) // throws
238 if (prepare_engine ()) {
244 std::string s = Glib::build_filename (dir, state + statefile_suffix);
245 if (!Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) {
246 std::cerr << "Cannot find session: " << s << "\n";
250 if (Session::get_info_from_path (s, sr, sf) != 0) {
251 std::cerr << "Cannot get samplerate from session.\n";
255 if (start_engine (sr)) {
259 AudioEngine* engine = AudioEngine::instance ();
260 Session* session = new Session (*engine, dir, state);
264 /* ****************************************************************************/
265 /* lua bound functions */
267 static Session* create_session (string dir, string state, uint32_t rate)
271 cerr << "Session already open" << "\n";
275 s = _create_session (dir, state, rate);
276 } catch (failed_constructor& e) {
277 cerr << "failed_constructor: " << e.what () << "\n";
279 } catch (AudioEngine::PortRegistrationFailure& e) {
280 cerr << "PortRegistrationFailure: " << e.what () << "\n";
282 } catch (exception& e) {
283 cerr << "exception: " << e.what () << "\n";
286 cerr << "unknown exception.\n";
289 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
294 s->DropReferences.connect_same_thread (session_connections, &unset_session);
298 static Session* load_session (string dir, string state)
302 cerr << "Session already open" << "\n";
306 s = _load_session (dir, state);
307 } catch (failed_constructor& e) {
308 cerr << "failed_constructor: " << e.what () << "\n";
310 } catch (AudioEngine::PortRegistrationFailure& e) {
311 cerr << "PortRegistrationFailure: " << e.what () << "\n";
313 } catch (exception& e) {
314 cerr << "exception: " << e.what () << "\n";
317 cerr << "unknown exception.\n";
320 Glib::usleep (1000000); // allow signal propagation, callback/thread-pool setup
325 s->DropReferences.connect_same_thread (session_connections, &unset_session);
329 static int set_debug_options (const char *opts)
331 return PBD::parse_debug_options (opts);
334 static void close_session ()
340 static int close_session_lua (lua_State *L)
343 cerr << "No open session" << "\n";
350 static void delay (float d) {
352 Glib::usleep (d * 1000000);
356 static int do_quit (lua_State *L)
358 keep_running = false;
362 /* ****************************************************************************/
364 static void my_lua_print (std::string s) {
365 std::cout << s << "\n";
368 static void setup_lua ()
372 lua = new LuaState ();
373 lua->Print.connect (&my_lua_print);
374 lua_State* L = lua->getState ();
376 LuaBindings::stddef (L);
377 LuaBindings::common (L);
378 LuaBindings::session (L);
379 LuaBindings::osc (L);
381 luabridge::getGlobalNamespace (L)
382 .beginNamespace ("_G")
383 .addFunction ("create_session", &create_session)
384 .addFunction ("load_session", &load_session)
385 .addFunction ("close_session", &close_session)
386 .addFunction ("sleep", &delay)
387 .addFunction ("quit", &do_quit)
388 .addFunction ("set_debug_options", &set_debug_options)
391 // add a Session::close() method
392 luabridge::getGlobalNamespace (L)
393 .beginNamespace ("ARDOUR")
394 .beginClass <Session> ("Session")
395 .addExtCFunction ("close", &close_session_lua)
399 // push instance to global namespace (C++ lifetime)
400 luabridge::push <AudioEngine *> (L, AudioEngine::create ());
401 lua_setglobal (L, "AudioEngine");
403 AudioEngine::instance ()->stop ();
406 int main (int argc, char **argv)
412 std::string histfile = Glib::build_filename (user_config_directory(), "/luahist");
414 read_history (histfile.c_str());
417 while (keep_running && (line = readline ("> "))) {
419 if (!strcmp (line, "quit")) {
420 free (line); line = NULL;
424 if (strlen (line) == 0) {
425 free (line); line = NULL;
429 if (lua->do_command (line)) {
435 free (line); line = NULL;
444 engine_connections.drop_connections ();
449 write_history (histfile.c_str());
451 AudioEngine::instance ()->stop ();
452 AudioEngine::destroy ();
457 pthread_cancel_all ();