mutex 'er up
[ardour.git] / session_utils / common.cc
1 #include <iostream>
2 #include <cstdlib>
3 #include <glibmm.h>
4
5 #include "pbd/debug.h"
6 #include "pbd/event_loop.h"
7 #include "pbd/error.h"
8 #include "pbd/failed_constructor.h"
9 #include "pbd/pthread_utils.h"
10
11 #include "ardour/audioengine.h"
12 #include "ardour/filename_extensions.h"
13 #include "ardour/types.h"
14
15 #include "common.h"
16
17 using namespace std;
18 using namespace ARDOUR;
19 using namespace PBD;
20
21 static const char* localedir = LOCALEDIR;
22 TestReceiver test_receiver;
23
24 void
25 TestReceiver::receive (Transmitter::Channel chn, const char * str)
26 {
27         const char *prefix = "";
28
29         switch (chn) {
30         case Transmitter::Error:
31                 prefix = ": [ERROR]: ";
32                 break;
33         case Transmitter::Info:
34                 /* ignore */
35                 return;
36         case Transmitter::Warning:
37                 prefix = ": [WARNING]: ";
38                 break;
39         case Transmitter::Fatal:
40                 prefix = ": [FATAL]: ";
41                 break;
42         case Transmitter::Throw:
43                 /* this isn't supposed to happen */
44                 abort ();
45         }
46
47         /* note: iostreams are already thread-safe: no external
48            lock required.
49         */
50
51         std::cout << prefix << str << std::endl;
52
53         if (chn == Transmitter::Fatal) {
54                 ::exit (9);
55         }
56 }
57
58 /* temporarily required due to some code design confusion (Feb 2014) */
59
60 #include "ardour/vst_types.h"
61
62 int vstfx_init (void*) { return 0; }
63 void vstfx_exit () {}
64 void vstfx_destroy_editor (VSTState*) {}
65
66 class MyEventLoop : public sigc::trackable, public EventLoop
67 {
68         public:
69                 MyEventLoop (std::string const& name) : EventLoop (name) {
70                         run_loop_thread = Glib::Threads::Thread::self();
71                 }
72
73                 void call_slot (InvalidationRecord*, const boost::function<void()>& f) {
74                         if (Glib::Threads::Thread::self() == run_loop_thread) {
75                                 f ();
76                         }
77                 }
78
79                 Glib::Threads::Mutex& slot_invalidation_mutex() { return request_buffer_map_lock; }
80                 Glib::Threads::Mutex& request_invalidation_mutex() { return request_invalidation_lock; }
81
82         private:
83                 Glib::Threads::Thread* run_loop_thread;
84                 Glib::Threads::Mutex   request_buffer_map_lock;
85                 Glib::Threads::Mutex   request_invalidation_lock;
86 };
87
88 static MyEventLoop *event_loop;
89
90 void
91 SessionUtils::init (bool print_log)
92 {
93         if (!ARDOUR::init (false, true, localedir)) {
94                 cerr << "Ardour failed to initialize\n" << endl;
95                 ::exit (EXIT_FAILURE);
96         }
97
98         event_loop = new MyEventLoop ("util");
99         EventLoop::set_event_loop_for_thread (event_loop);
100         SessionEvent::create_per_thread_pool ("util", 512);
101
102         if (print_log) {
103                 test_receiver.listen_to (error);
104                 test_receiver.listen_to (info);
105                 test_receiver.listen_to (fatal);
106                 test_receiver.listen_to (warning);
107         }
108 }
109
110 // TODO return NULL, rather than exit() ?!
111 static Session * _load_session (string dir, string state)
112 {
113         AudioEngine* engine = AudioEngine::create ();
114
115         if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) {
116                 std::cerr << "Cannot create Audio/MIDI engine\n";
117                 ::exit (EXIT_FAILURE);
118         }
119
120         engine->set_input_channels (256);
121         engine->set_output_channels (256);
122
123         float sr;
124         SampleFormat sf;
125
126         std::string s = Glib::build_filename (dir, state + statefile_suffix);
127         if (Session::get_info_from_path (s, sr, sf) == 0) {
128                 if (engine->set_sample_rate (sr)) {
129                         std::cerr << "Cannot set session's samplerate.\n";
130                         return 0;
131                 }
132         } else {
133                 std::cerr << "Cannot get samplerate from session.\n";
134                 return 0;
135         }
136
137         init_post_engine ();
138
139         if (engine->start () != 0) {
140                 std::cerr << "Cannot start Audio/MIDI engine\n";
141                 return 0;
142         }
143
144         Session* session = new Session (*engine, dir, state);
145         engine->set_session (session);
146         return session;
147 }
148
149 Session *
150 SessionUtils::load_session (string dir, string state, bool exit_at_failure)
151 {
152         Session* s = 0;
153         try {
154                 s = _load_session (dir, state);
155         } catch (failed_constructor& e) {
156                 cerr << "failed_constructor: " << e.what() << "\n";
157                 ::exit (EXIT_FAILURE);
158         } catch (AudioEngine::PortRegistrationFailure& e) {
159                 cerr << "PortRegistrationFailure: " << e.what() << "\n";
160                 ::exit (EXIT_FAILURE);
161         } catch (exception& e) {
162                 cerr << "exception: " << e.what() << "\n";
163                 ::exit (EXIT_FAILURE);
164         } catch (...) {
165                 cerr << "unknown exception.\n";
166                 ::exit (EXIT_FAILURE);
167         }
168         if (!s && exit_at_failure) {
169                 ::exit (EXIT_FAILURE);
170         }
171         return s;
172 }
173
174 void
175 SessionUtils::unload_session (Session *s)
176 {
177         delete s;
178         AudioEngine::instance()->stop ();
179         AudioEngine::destroy ();
180 }
181
182 void
183 SessionUtils::cleanup ()
184 {
185         ARDOUR::cleanup ();
186         delete event_loop;
187         pthread_cancel_all ();
188 }