/* * Copyright (C) 2015-2017 Robin Gareus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include "pbd/debug.h" #include "pbd/event_loop.h" #include "pbd/error.h" #include "pbd/failed_constructor.h" #include "pbd/pthread_utils.h" #include "pbd/receiver.h" #include "pbd/transmitter.h" #include "ardour/audioengine.h" #include "ardour/filename_extensions.h" #include "ardour/types.h" #include "common.h" using namespace std; using namespace ARDOUR; using namespace PBD; static const char* localedir = LOCALEDIR; class LogReceiver : public Receiver { protected: void receive (Transmitter::Channel chn, const char * str) { const char *prefix = ""; switch (chn) { case Transmitter::Debug: /* ignore */ return; case Transmitter::Info: /* ignore */ return; case Transmitter::Warning: prefix = ": [WARNING]: "; break; case Transmitter::Error: prefix = ": [ERROR]: "; break; case Transmitter::Fatal: prefix = ": [FATAL]: "; break; case Transmitter::Throw: /* this isn't supposed to happen */ abort (); } /* note: iostreams are already thread-safe: no external lock required. */ std::cout << prefix << str << std::endl; if (chn == Transmitter::Fatal) { ::exit (9); } } }; LogReceiver log_receiver; /* temporarily required due to some code design confusion (Feb 2014) */ #include "ardour/vst_types.h" int vstfx_init (void*) { return 0; } void vstfx_exit () {} void vstfx_destroy_editor (VSTState*) {} class MyEventLoop : public sigc::trackable, public EventLoop { public: MyEventLoop (std::string const& name) : EventLoop (name) { run_loop_thread = Glib::Threads::Thread::self(); } bool call_slot (InvalidationRecord*, const std::function& f) { if (Glib::Threads::Thread::self() == run_loop_thread) { f (); } return true; } Glib::Threads::RWLock& slot_invalidation_rwlock() { return request_buffer_map_lock; } private: Glib::Threads::Thread* run_loop_thread; Glib::Threads::RWLock request_buffer_map_lock; }; static MyEventLoop *event_loop; void SessionUtils::init (bool print_log) { if (!ARDOUR::init (true, localedir)) { cerr << "Ardour failed to initialize\n" << endl; ::exit (EXIT_FAILURE); } event_loop = new MyEventLoop ("util"); EventLoop::set_event_loop_for_thread (event_loop); SessionEvent::create_per_thread_pool ("util", 512); if (print_log) { log_receiver.listen_to (warning); log_receiver.listen_to (error); log_receiver.listen_to (fatal); } } // TODO return NULL, rather than exit() ?! static Session * _load_session (string dir, string state) { AudioEngine* engine = AudioEngine::create (); if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) { std::cerr << "Cannot create Audio/MIDI engine\n"; ::exit (EXIT_FAILURE); } float sr; SampleFormat sf; std::string v; std::string s = Glib::build_filename (dir, state + statefile_suffix); if (!Glib::file_test (s, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR)) { std::cerr << "Cannot read session '"<< s << "'\n"; return 0; } if (Session::get_info_from_path (s, sr, sf, v) == 0) { if (engine->set_sample_rate (sr)) { std::cerr << "Cannot set session's samplerate.\n"; return 0; } } else { std::cerr << "Cannot get samplerate from session.\n"; return 0; } if (engine->start () != 0) { std::cerr << "Cannot start Audio/MIDI engine\n"; return 0; } Session* session = new Session (*engine, dir, state); engine->set_session (session); return session; } Session * SessionUtils::load_session (string dir, string state, bool exit_at_failure) { Session* s = 0; try { s = _load_session (dir, state); } catch (failed_constructor& e) { cerr << "failed_constructor: " << e.what() << "\n"; ::exit (EXIT_FAILURE); } catch (AudioEngine::PortRegistrationFailure& e) { cerr << "PortRegistrationFailure: " << e.what() << "\n"; ::exit (EXIT_FAILURE); } catch (exception& e) { cerr << "exception: " << e.what() << "\n"; ::exit (EXIT_FAILURE); } catch (...) { cerr << "unknown exception.\n"; ::exit (EXIT_FAILURE); } if (!s && exit_at_failure) { ::exit (EXIT_FAILURE); } return s; } Session * SessionUtils::create_session (string dir, string state, float sample_rate) { AudioEngine* engine = AudioEngine::create (); if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) { std::cerr << "Cannot create Audio/MIDI engine\n"; ::exit (EXIT_FAILURE); } if (engine->set_sample_rate (sample_rate)) { std::cerr << "Cannot set session's samplerate.\n"; return 0; } if (engine->start () != 0) { std::cerr << "Cannot start Audio/MIDI engine\n"; return 0; } std::string s = Glib::build_filename (dir, state + statefile_suffix); if (Glib::file_test (dir, Glib::FILE_TEST_EXISTS)) { std::cerr << "Session folder already exists '"<< dir << "'\n"; } if (Glib::file_test (s, Glib::FILE_TEST_EXISTS)) { std::cerr << "Session file exists '"<< s << "'\n"; return 0; } Session* session = new Session (*engine, dir, state); engine->set_session (session); return session; } void SessionUtils::unload_session (Session *s) { delete s; AudioEngine::instance()->stop (); } void SessionUtils::cleanup () { ARDOUR::cleanup (); delete event_loop; pthread_cancel_all (); }