fixes for libsndfile conversion issues, tape track waveform display and overloaded...
[ardour.git] / gtk2_ardour / main.cc
1 /*
2     Copyright (C) 2001-2006 Paul Davis
3     
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <sys/types.h>
22 #include <sys/mman.h>
23 #include <sys/wait.h>
24 #include <cerrno>
25 #include <cstdlib>
26 #include <signal.h>
27 #include <unistd.h>
28
29 #include <sigc++/bind.h>
30 #include <gtkmm/settings.h>
31
32 #include <pbd/error.h>
33 #include <pbd/textreceiver.h>
34 #include <pbd/failed_constructor.h>
35 #include <pbd/pthread_utils.h>
36
37 #include <jack/jack.h>
38
39 #include <ardour/version.h>
40 #include <ardour/ardour.h>
41 #include <ardour/audioengine.h>
42
43 #include <gtkmm/main.h>
44 #include <gtkmm2ext/popup.h>
45 #include <gtkmm2ext/utils.h>
46
47 #include "version.h"
48 #include "ardour_ui.h"
49 #include "opts.h"
50
51 #include "i18n.h"
52
53 using namespace Gtk;
54 using namespace GTK_ARDOUR;
55 using namespace ARDOUR;
56 using namespace sigc;
57
58 TextReceiver text_receiver ("ardour");
59
60 extern int curvetest (string);
61
62 static ARDOUR_UI  *ui = 0;
63
64 static void
65 shutdown (int status)
66 {
67         char* msg;
68
69         if (status) {
70
71                 msg = _("ardour is killing itself for a clean exit\n");
72                 write (1, msg, strlen (msg));
73                 /* drastic, but perhaps necessary */
74                 kill (-getpgrp(), SIGKILL);     
75                 /*NOTREACHED*/
76
77         } else {
78
79                 if (ui) {
80                         msg = _("stopping user interface\n");
81                         write (1, msg, strlen (msg));
82                         ui->kill();
83                 }
84                 
85                 pthread_cancel_all ();
86         }
87
88         exit (status);
89 }
90
91
92 static void 
93 handler (int sig)
94 {
95         char buf[64];
96         int n;
97
98         /* XXX its doubtful that snprintf() is async-safe */
99         n = snprintf (buf, sizeof(buf), _("%d(%d): received signal %d\n"), getpid(), (int) pthread_self(), sig);
100         write (1, buf, n);
101
102         shutdown (1);
103 }
104
105 static void 
106 handler2 (int sig, siginfo_t* ctxt, void* ignored)
107 {
108         handler (sig);
109 }       
110
111 static void *
112 signal_thread (void *arg)
113 {
114         int sig;
115         sigset_t blocked;
116
117         PBD::ThreadCreated (pthread_self(), X_("Signal"));
118
119         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
120         
121         /* find out what's blocked right now */
122
123         //sigprocmask (SIG_SETMASK, 0, &blocked);
124         if (pthread_sigmask (SIG_SETMASK, 0, &blocked)) {
125                 cerr << "getting blocked signals failed\n";
126         }
127         
128         /* wait for any of the currently blocked signals.
129            
130            According to the man page found in linux 2.6 and 2.4, sigwait() 
131            never returns an error. This is incorrect. Checking the man
132            pages for some other *nix systems makes it clear that
133            sigwait() can return several error codes, one of which 
134            is EINTR. This happens if the thread receives a signal
135            which is not in the blocked set. 
136
137            We do not expect that to happen, and if it did we should generally
138            exit as planned. However, under 2.6, the ptrace facility used 
139            by gdb seems to also cause sigwait() to return with EINTR
140            but with a signal that sigwait cannot understand. As a result, 
141            "sig" is set to zero, an impossible signal number.
142
143            Handling the EINTR code makes it possible to debug 
144            ardour on a 2.6 kernel.
145
146         */
147
148         int swerr;
149
150   again:
151         if ((swerr = sigwait (&blocked, &sig))) {
152                 if (swerr == EINTR) {
153                         goto again;
154                 } else {
155                         cerr << "sigwait failed with " << swerr << endl;
156                 }
157         }
158
159         cerr << "Signal " << sig << " received\n";
160
161         if (sig != SIGSEGV) {
162
163                 /* unblock signals so we can see them during shutdown.
164                    this will help prod developers not to lose sight
165                    of bugs that cause segfaults etc. during shutdown.
166                 */
167
168                 sigprocmask (SIG_UNBLOCK, &blocked, 0);
169         }
170
171         shutdown (1);
172         /*NOTREACHED*/
173         return 0;
174 }
175
176 int
177 catch_signals (void)
178 {
179         struct sigaction action;
180         pthread_t signal_thread_id;
181         sigset_t signals;
182
183 //      if (setpgid (0,0)) {
184         if (setsid ()) {
185                 warning << string_compose (_("cannot become new process group leader (%1)"), 
186                                     strerror (errno))
187                         << endmsg;
188         }
189
190         sigemptyset (&signals);
191         sigaddset(&signals, SIGHUP);
192         sigaddset(&signals, SIGINT);
193         sigaddset(&signals, SIGQUIT);
194         sigaddset(&signals, SIGPIPE);
195         sigaddset(&signals, SIGTERM);
196         sigaddset(&signals, SIGUSR1);
197         sigaddset(&signals, SIGUSR2);
198
199
200         /* install a handler because otherwise
201            pthreads behaviour is undefined when we enter
202            sigwait.
203         */
204         
205         action.sa_handler = handler;
206         action.sa_mask = signals;
207         action.sa_flags = SA_RESTART|SA_RESETHAND;
208
209         for (int i = 1; i < 32; i++) {
210                 if (sigismember (&signals, i)) {
211                         if (sigaction (i, &action, 0)) {
212                                 cerr << string_compose (_("cannot setup signal handling for %1"), i) << endl;
213                                 return -1;
214                         }
215                 }
216         } 
217
218         /* this sets the signal mask for this and all 
219            subsequent threads that do not reset it.
220         */
221         
222         if (pthread_sigmask (SIG_SETMASK, &signals, 0)) {
223                 cerr << string_compose (_("cannot set default signal mask (%1)"), strerror (errno)) << endl;
224                 return -1;
225         }
226
227         /* start a thread to wait for signals */
228
229         if (pthread_create_and_store ("signal", &signal_thread_id, 0, signal_thread, 0)) {
230                 cerr << "cannot create signal catching thread" << endl;
231                 return -1;
232         }
233
234         pthread_detach (signal_thread_id);
235         return 0;
236 }
237
238 string
239 which_ui_rcfile ()
240 {
241         string rcfile;
242         char* env;
243
244         if ((env = getenv ("ARDOUR2_UI_RC")) != 0 && strlen (env)) {
245                 rcfile = env;
246         } else {
247                 rcfile = "ardour2_ui.rc";
248         }
249
250         rcfile = find_config_file (rcfile);
251         
252         if (rcfile.empty()) {
253                 warning << _("Without a UI style file, ardour will look strange.\n Please set ARDOUR2_UI_RC to point to a valid UI style file") << endmsg;
254         } else {
255                 cerr << "Loading ui configuration file " << rcfile << endl;
256         }
257         
258         return rcfile;
259 }
260
261 gint
262 show_ui_callback (void *arg)
263 {
264         ARDOUR_UI * ui = (ARDOUR_UI *) arg;
265
266         ui->hide_splash();
267         ui->show ();
268         
269         return FALSE;
270 }
271
272 void
273 gui_jack_error ()
274 {
275   MessageDialog win (_("Ardour could not connect to JACK."),
276                      false,
277                      Gtk::MESSAGE_INFO,
278                      (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
279 win.set_secondary_text(_("There are several possible reasons:\n\
280 \n\
281 1) JACK is not running.\n\
282 2) JACK is running as another user, perhaps root.\n\
283 3) There is already another client called \"ardour\".\n\
284 \n\
285 Please consider the possibilities, and perhaps (re)start JACK."));
286
287         win.add_button (Stock::QUIT, RESPONSE_CLOSE);
288         win.set_default_response (RESPONSE_CLOSE);
289         
290         win.show_all ();
291         win.set_position (Gtk::WIN_POS_CENTER);
292
293         /* we just don't care about the result */
294
295         win.run ();
296 }
297
298 static bool
299 maybe_load_session ()
300 {
301
302         /* load session, if given */
303         string name, path;
304
305         if (session_name.length()){
306                 bool isnew;
307
308                 if (Session::find_session (session_name, path, name, isnew)) {
309                         error << string_compose(_("could not load command line session \"%1\""), session_name) << endmsg;
310                 } else {
311
312                         if (new_session) {
313
314                                 /* command line required that the session be new */
315
316                                 if (isnew) {
317                                         
318                                         /* popup the new session dialog
319                                            once everything else is OK.
320                                         */
321
322                                         Glib::signal_idle().connect (bind (mem_fun (*ui, &ARDOUR_UI::cmdline_new_session), path));
323                                         ui->set_will_create_new_session_automatically (true);
324
325                                 } else {
326
327                                         /* it wasn't new, but we require a new session */
328
329                                         error << string_compose (_("\n\nA session named \"%1\" already exists.\n\
330 To avoid this message, start ardour as \"ardour %1"), path)
331                                               << endmsg;
332                                         return false;
333                                 }
334
335                         } else {
336
337                                 /* command line didn't require a new session */
338                                 
339                                 if (isnew) {
340                                         error << string_compose (_("\n\nNo session named \"%1\" exists.\n\
341 To create it from the command line, start ardour as \"ardour --new %1"), path) 
342                                               << endmsg;
343                                         return false;
344                                 }
345
346                                 ui->load_session (path, name);
347                         }
348                 }
349
350                 if (no_splash) {
351                         ui->show();
352                 }
353
354         } else {
355                 ui->hide_splash ();
356                 if (!Config->get_no_new_session_dialog()) {
357                        ui->new_session (true);
358                 }
359         }
360
361         return true;
362 }
363
364
365 int
366 main (int argc, char *argv[])
367 {
368         ARDOUR::AudioEngine *engine;
369         vector<Glib::ustring> null_file_list;
370
371         // needs a better home.
372         Glib::thread_init();
373         
374         gtk_set_locale ();
375
376         (void)   bindtextdomain (PACKAGE, LOCALEDIR);
377         (void) textdomain (PACKAGE);
378
379         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
380
381         // catch_signals ();
382
383         text_receiver.listen_to (error);
384         text_receiver.listen_to (info);
385         text_receiver.listen_to (fatal);
386         text_receiver.listen_to (warning);
387
388         if (parse_opts (argc, argv)) {
389                 exit (1);
390         }
391
392         if (curvetest_file) {
393                 return curvetest (curvetest_file);
394         }
395         
396         cout << _("Ardour/GTK ") 
397              << VERSIONSTRING
398              << _("\n   (built using ")
399              << gtk_ardour_major_version << '.'
400              << gtk_ardour_minor_version << '.'
401              << gtk_ardour_micro_version
402              << _(" with libardour ")
403              << libardour_major_version << '.'
404              << libardour_minor_version << '.' 
405              << libardour_micro_version 
406 #ifdef __GNUC__
407              << _(" and GCC version ") << __VERSION__ 
408 #endif
409              << ')'
410              << endl;
411         
412         if (just_version) {
413                 exit (0);
414         }
415
416         if (no_splash) {
417                 cerr << _("Copyright (C) 1999-2006 Paul Davis") << endl
418                      << _("Some portions Copyright (C) Steve Harris, Ari Johnson, Brett Viren, Joel Baker") << endl
419                      << endl
420                      << _("Ardour comes with ABSOLUTELY NO WARRANTY") << endl
421                      << _("not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.") << endl
422                      << _("This is free software, and you are welcome to redistribute it ") << endl
423                      << _("under certain conditions; see the source for copying conditions.")
424                      << endl;
425         }
426
427         try { 
428                 ui = new ARDOUR_UI (&argc, &argv, which_ui_rcfile());
429         } 
430
431         catch (failed_constructor& err) {
432                 error << _("could not create ARDOUR GUI") << endmsg;
433                 exit (1);
434         }
435
436
437         if (!no_splash) {
438                 ui->show_splash ();
439                 if (session_name.length()) {  
440                         gtk_timeout_add (4000, show_ui_callback, ui);
441                 }
442         }
443         
444         try { 
445                 engine = new ARDOUR::AudioEngine (jack_client_name);
446                 ARDOUR::init (*engine, use_vst, try_hw_optimization, handler2);
447                 ui->set_engine (*engine);
448         } catch (AudioEngine::NoBackendAvailable& err) {
449                 gui_jack_error ();
450                 error << string_compose (_("Could not connect to JACK server as  \"%1\""), jack_client_name) <<  endmsg;
451                 return -1;
452         } catch (failed_constructor& err) {
453                 error << _("could not initialize Ardour.") << endmsg;
454                 return -1;
455         } 
456
457         if (maybe_load_session ()) {
458                 ui->run (text_receiver);
459                 ui = 0;
460         }
461
462         delete engine;
463         ARDOUR::cleanup ();
464         shutdown (0);
465
466         /* just another commit forcing change */
467 }
468