once the user has explicitly set the session range end, playlist/range changes do...
[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
81         private:
82                 Glib::Threads::Thread* run_loop_thread;
83                 Glib::Threads::Mutex   request_buffer_map_lock;
84 };
85
86 static MyEventLoop *event_loop;
87
88 void
89 SessionUtils::init (bool print_log)
90 {
91         if (!ARDOUR::init (false, true, localedir)) {
92                 cerr << "Ardour failed to initialize\n" << endl;
93                 ::exit (EXIT_FAILURE);
94         }
95
96         event_loop = new MyEventLoop ("util");
97         EventLoop::set_event_loop_for_thread (event_loop);
98         SessionEvent::create_per_thread_pool ("util", 512);
99
100         if (print_log) {
101                 test_receiver.listen_to (error);
102                 test_receiver.listen_to (info);
103                 test_receiver.listen_to (fatal);
104                 test_receiver.listen_to (warning);
105         }
106 }
107
108 // TODO return NULL, rather than exit() ?!
109 static Session * _load_session (string dir, string state)
110 {
111         AudioEngine* engine = AudioEngine::create ();
112
113         if (!engine->set_backend ("None (Dummy)", "Unit-Test", "")) {
114                 std::cerr << "Cannot create Audio/MIDI engine\n";
115                 ::exit (EXIT_FAILURE);
116         }
117
118         engine->set_input_channels (256);
119         engine->set_output_channels (256);
120
121         float sr;
122         SampleFormat sf;
123
124         std::string s = Glib::build_filename (dir, state + statefile_suffix);
125         if (Session::get_info_from_path (s, sr, sf) == 0) {
126                 if (engine->set_sample_rate (sr)) {
127                         std::cerr << "Cannot set session's samplerate.\n";
128                         return 0;
129                 }
130         } else {
131                 std::cerr << "Cannot get samplerate from session.\n";
132                 return 0;
133         }
134
135         init_post_engine ();
136
137         if (engine->start () != 0) {
138                 std::cerr << "Cannot start Audio/MIDI engine\n";
139                 return 0;
140         }
141
142         Session* session = new Session (*engine, dir, state);
143         engine->set_session (session);
144         return session;
145 }
146
147 Session *
148 SessionUtils::load_session (string dir, string state, bool exit_at_failure)
149 {
150         Session* s = 0;
151         try {
152                 s = _load_session (dir, state);
153         } catch (failed_constructor& e) {
154                 cerr << "failed_constructor: " << e.what() << "\n";
155                 ::exit (EXIT_FAILURE);
156         } catch (AudioEngine::PortRegistrationFailure& e) {
157                 cerr << "PortRegistrationFailure: " << e.what() << "\n";
158                 ::exit (EXIT_FAILURE);
159         } catch (exception& e) {
160                 cerr << "exception: " << e.what() << "\n";
161                 ::exit (EXIT_FAILURE);
162         } catch (...) {
163                 cerr << "unknown exception.\n";
164                 ::exit (EXIT_FAILURE);
165         }
166         if (!s && exit_at_failure) {
167                 ::exit (EXIT_FAILURE);
168         }
169         return s;
170 }
171
172 void
173 SessionUtils::unload_session (Session *s)
174 {
175         delete s;
176         AudioEngine::instance()->stop ();
177         AudioEngine::destroy ();
178 }
179
180 void
181 SessionUtils::cleanup ()
182 {
183         ARDOUR::cleanup ();
184         delete event_loop;
185         pthread_cancel_all ();
186 }