fix math bug with numthreads computation
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blob10fdeb991e7510aab145a71973605b542640854d
1 /*
2 Copyright (C) 1999-2007 Paul Davis
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.
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.
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.
20 #define __STDC_FORMAT_MACROS 1
21 #include <stdint.h>
23 #include <algorithm>
24 #include <cmath>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <time.h>
29 #include <cerrno>
30 #include <fstream>
32 #include <iostream>
34 #include <sys/resource.h>
36 #include <gtkmm/messagedialog.h>
37 #include <gtkmm/accelmap.h>
39 #include "pbd/error.h"
40 #include "pbd/basename.h"
41 #include "pbd/compose.h"
42 #include "pbd/failed_constructor.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/openuri.h"
46 #include "pbd/file_utils.h"
48 #include "gtkmm2ext/gtk_ui.h"
49 #include "gtkmm2ext/utils.h"
50 #include "gtkmm2ext/click_box.h"
51 #include "gtkmm2ext/fastmeter.h"
52 #include "gtkmm2ext/popup.h"
53 #include "gtkmm2ext/window_title.h"
55 #include "midi++/manager.h"
57 #include "ardour/ardour.h"
58 #include "ardour/profile.h"
59 #include "ardour/session_directory.h"
60 #include "ardour/session_route.h"
61 #include "ardour/session_state_utils.h"
62 #include "ardour/session_utils.h"
63 #include "ardour/port.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/playlist.h"
66 #include "ardour/utils.h"
67 #include "ardour/audio_diskstream.h"
68 #include "ardour/audiofilesource.h"
69 #include "ardour/recent_sessions.h"
70 #include "ardour/port.h"
71 #include "ardour/audio_track.h"
72 #include "ardour/midi_track.h"
73 #include "ardour/filesystem_paths.h"
74 #include "ardour/filename_extensions.h"
76 typedef uint64_t microseconds_t;
78 #include "actions.h"
79 #include "ardour_ui.h"
80 #include "public_editor.h"
81 #include "audio_clock.h"
82 #include "keyboard.h"
83 #include "mixer_ui.h"
84 #include "prompter.h"
85 #include "opts.h"
86 #include "add_route_dialog.h"
87 #include "about.h"
88 #include "splash.h"
89 #include "utils.h"
90 #include "gui_thread.h"
91 #include "theme_manager.h"
92 #include "bundle_manager.h"
93 #include "session_metadata_dialog.h"
94 #include "gain_meter.h"
95 #include "route_time_axis.h"
96 #include "startup.h"
97 #include "engine_dialog.h"
98 #include "processor_box.h"
99 #include "time_axis_view_item.h"
101 #include "i18n.h"
103 using namespace ARDOUR;
104 using namespace PBD;
105 using namespace Gtkmm2ext;
106 using namespace Gtk;
108 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
109 UIConfiguration *ARDOUR_UI::ui_config = 0;
111 sigc::signal<void,bool> ARDOUR_UI::Blink;
112 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
113 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
114 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
116 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
118 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
120 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
121 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
122 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
123 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
125 /* preroll stuff */
127 preroll_button (_("pre\nroll")),
128 postroll_button (_("post\nroll")),
130 /* big clock */
132 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
134 /* transport */
136 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
137 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
138 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
139 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
140 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
141 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
142 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
143 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
144 shuttle_controller_binding_proxy (shuttle_controllable),
146 roll_button (roll_controllable),
147 stop_button (stop_controllable),
148 goto_start_button (goto_start_controllable),
149 goto_end_button (goto_end_controllable),
150 auto_loop_button (auto_loop_controllable),
151 play_selection_button (play_selection_controllable),
152 rec_button (rec_controllable),
154 shuttle_units_button (_("% ")),
156 punch_in_button (_("Punch In")),
157 punch_out_button (_("Punch Out")),
158 auto_return_button (_("Auto Return")),
159 auto_play_button (_("Auto Play")),
160 auto_input_button (_("Auto Input")),
161 click_button (_("Click")),
162 time_master_button (_("time\nmaster")),
164 auditioning_alert_button (_("AUDITION")),
165 solo_alert_button (_("SOLO")),
166 shown_flag (false),
167 error_log_button (_("Errors"))
170 using namespace Gtk::Menu_Helpers;
172 Gtkmm2ext::init();
175 #ifdef TOP_MENUBAR
176 // _auto_display_errors = false;
178 * This was commented out as it wasn't defined
179 * in A3 IIRC. If this is not needed it should
180 * be completely removed.
182 #endif
184 about = 0;
185 splash = 0;
186 _startup = 0;
188 if (theArdourUI == 0) {
189 theArdourUI = this;
192 ui_config = new UIConfiguration();
193 theme_manager = new ThemeManager();
195 editor = 0;
196 mixer = 0;
197 editor = 0;
198 engine = 0;
199 _session_is_new = false;
200 big_clock_window = 0;
201 big_clock_height = 0;
202 big_clock_resize_in_progress = false;
203 session_selector_window = 0;
204 last_key_press_time = 0;
205 _will_create_new_session_automatically = false;
206 add_route_dialog = 0;
207 route_params = 0;
208 rc_option_editor = 0;
209 session_option_editor = 0;
210 location_ui = 0;
211 open_session_selector = 0;
212 have_configure_timeout = false;
213 have_disk_speed_dialog_displayed = false;
214 session_loaded = false;
215 last_speed_displayed = -1.0f;
216 ignore_dual_punch = false;
217 _mixer_on_top = false;
218 original_big_clock_width = -1;
219 original_big_clock_height = -1;
220 original_big_clock_font_size = 0;
222 roll_button.unset_flags (Gtk::CAN_FOCUS);
223 stop_button.unset_flags (Gtk::CAN_FOCUS);
224 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
225 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
226 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
227 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
228 rec_button.unset_flags (Gtk::CAN_FOCUS);
230 last_configure_time= 0;
232 shuttle_grabbed = false;
233 shuttle_fract = 0.0;
234 shuttle_max_speed = 8.0f;
236 shuttle_style_menu = 0;
237 shuttle_unit_menu = 0;
239 // We do not have jack linked in yet so;
241 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
243 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
244 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
246 /* handle dialog requests */
248 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
250 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
252 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
254 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
256 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
258 /* lets get this party started */
260 try {
261 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
262 throw failed_constructor ();
265 setup_gtk_ardour_enums ();
266 setup_profile ();
268 GainMeter::setup_slider_pix ();
269 RouteTimeAxisView::setup_slider_pix ();
270 SendProcessorEntry::setup_slider_pix ();
271 SessionEvent::create_per_thread_pool ("GUI", 512);
273 } catch (failed_constructor& err) {
274 error << _("could not initialize Ardour.") << endmsg;
275 // pass it on up
276 throw;
279 /* we like keyboards */
281 keyboard = new ArdourKeyboard(*this);
283 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
284 if (node) {
285 keyboard->set_state (*node, Stateful::loading_state_version);
288 reset_dpi();
290 TimeAxisViewItem::set_constant_heights ();
292 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
293 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
295 platform_setup ();
298 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
299 bool
300 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
302 if (_startup == 0) {
303 _startup = new ArdourStartup ();
306 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
308 if (audio_setup && _startup->engine_control()) {
309 _startup->engine_control()->set_state (*audio_setup);
312 _startup->set_new_only (should_be_new);
313 if (!load_template.empty()) {
314 _startup->set_load_template( load_template );
316 _startup->present ();
318 main().run();
320 _startup->hide ();
322 switch (_startup->response()) {
323 case RESPONSE_OK:
324 return true;
325 default:
326 return false;
331 ARDOUR_UI::create_engine ()
333 // this gets called every time by new_session()
335 if (engine) {
336 return 0;
339 loading_message (_("Starting audio engine"));
341 try {
342 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
344 } catch (...) {
346 return -1;
349 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
350 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
351 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
353 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
355 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
357 post_engine ();
359 return 0;
362 void
363 ARDOUR_UI::post_engine ()
365 /* Things to be done once we create the AudioEngine
368 MIDI::Manager::instance()->set_api_data (engine->jack());
369 setup_midi ();
371 ARDOUR::init_post_engine ();
373 ActionManager::init ();
374 _tooltips.enable();
376 if (setup_windows ()) {
377 throw failed_constructor ();
380 check_memory_locking();
382 /* this is the first point at which all the keybindings are available */
384 if (ARDOUR_COMMAND_LINE::show_key_actions) {
385 vector<string> names;
386 vector<string> paths;
387 vector<string> keys;
388 vector<AccelKey> bindings;
390 ActionManager::get_all_actions (names, paths, keys, bindings);
392 vector<string>::iterator n;
393 vector<string>::iterator k;
394 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
395 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
398 exit (0);
401 blink_timeout_tag = -1;
403 /* this being a GUI and all, we want peakfiles */
405 AudioFileSource::set_build_peakfiles (true);
406 AudioFileSource::set_build_missing_peakfiles (true);
408 /* set default clock modes */
410 if (Profile->get_sae()) {
411 primary_clock.set_mode (AudioClock::BBT);
412 secondary_clock.set_mode (AudioClock::MinSec);
413 } else {
414 primary_clock.set_mode (AudioClock::Timecode);
415 secondary_clock.set_mode (AudioClock::BBT);
418 /* start the time-of-day-clock */
420 #ifndef GTKOSX
421 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
422 update_wall_clock ();
423 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
424 #endif
426 update_disk_space ();
427 update_cpu_load ();
428 update_sample_rate (engine->frame_rate());
430 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
431 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
432 Config->map_parameters (pc);
434 /* now start and maybe save state */
436 if (do_engine_start () == 0) {
437 if (_session && _session_is_new) {
438 /* we need to retain initial visual
439 settings for a new session
441 _session->save_state ("");
446 ARDOUR_UI::~ARDOUR_UI ()
448 delete keyboard;
449 delete editor;
450 delete mixer;
451 delete add_route_dialog;
454 void
455 ARDOUR_UI::pop_back_splash ()
457 if (Splash::instance()) {
458 // Splash::instance()->pop_back();
459 Splash::instance()->hide ();
463 gint
464 ARDOUR_UI::configure_timeout ()
466 if (last_configure_time == 0) {
467 /* no configure events yet */
468 return true;
471 /* force a gap of 0.5 seconds since the last configure event
474 if (get_microseconds() - last_configure_time < 500000) {
475 return true;
476 } else {
477 have_configure_timeout = false;
478 cerr << "config event-driven save\n";
479 save_ardour_state ();
480 return false;
484 gboolean
485 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
487 if (have_configure_timeout) {
488 last_configure_time = get_microseconds();
489 } else {
490 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
491 have_configure_timeout = true;
494 return FALSE;
497 void
498 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
500 const XMLProperty* prop;
502 if ((prop = node.property ("roll")) != 0) {
503 roll_controllable->set_id (prop->value());
505 if ((prop = node.property ("stop")) != 0) {
506 stop_controllable->set_id (prop->value());
508 if ((prop = node.property ("goto-start")) != 0) {
509 goto_start_controllable->set_id (prop->value());
511 if ((prop = node.property ("goto-end")) != 0) {
512 goto_end_controllable->set_id (prop->value());
514 if ((prop = node.property ("auto-loop")) != 0) {
515 auto_loop_controllable->set_id (prop->value());
517 if ((prop = node.property ("play-selection")) != 0) {
518 play_selection_controllable->set_id (prop->value());
520 if ((prop = node.property ("rec")) != 0) {
521 rec_controllable->set_id (prop->value());
523 if ((prop = node.property ("shuttle")) != 0) {
524 shuttle_controllable->set_id (prop->value());
528 XMLNode&
529 ARDOUR_UI::get_transport_controllable_state ()
531 XMLNode* node = new XMLNode(X_("TransportControllables"));
532 char buf[64];
534 roll_controllable->id().print (buf, sizeof (buf));
535 node->add_property (X_("roll"), buf);
536 stop_controllable->id().print (buf, sizeof (buf));
537 node->add_property (X_("stop"), buf);
538 goto_start_controllable->id().print (buf, sizeof (buf));
539 node->add_property (X_("goto_start"), buf);
540 goto_end_controllable->id().print (buf, sizeof (buf));
541 node->add_property (X_("goto_end"), buf);
542 auto_loop_controllable->id().print (buf, sizeof (buf));
543 node->add_property (X_("auto_loop"), buf);
544 play_selection_controllable->id().print (buf, sizeof (buf));
545 node->add_property (X_("play_selection"), buf);
546 rec_controllable->id().print (buf, sizeof (buf));
547 node->add_property (X_("rec"), buf);
548 shuttle_controllable->id().print (buf, sizeof (buf));
549 node->add_property (X_("shuttle"), buf);
551 return *node;
555 gint
556 ARDOUR_UI::autosave_session ()
558 if (g_main_depth() > 1) {
559 /* inside a recursive main loop,
560 give up because we may not be able to
561 take a lock.
563 return 1;
566 if (!Config->get_periodic_safety_backups()) {
567 return 1;
570 if (_session) {
571 _session->maybe_write_autosave();
574 return 1;
577 void
578 ARDOUR_UI::update_autosave ()
580 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
582 if (_session && _session->dirty()) {
583 if (_autosave_connection.connected()) {
584 _autosave_connection.disconnect();
587 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
588 Config->get_periodic_safety_backup_interval() * 1000);
590 } else {
591 if (_autosave_connection.connected()) {
592 _autosave_connection.disconnect();
597 void
598 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
600 string title;
601 if (we_set_params) {
602 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
603 } else {
604 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
607 MessageDialog win (title,
608 false,
609 Gtk::MESSAGE_INFO,
610 Gtk::BUTTONS_NONE);
612 if (we_set_params) {
613 win.set_secondary_text(_("There are several possible reasons:\n\
615 1) You requested audio parameters that are not supported..\n\
616 2) JACK is running as another user.\n\
618 Please consider the possibilities, and perhaps try different parameters."));
619 } else {
620 win.set_secondary_text(_("There are several possible reasons:\n\
622 1) JACK is not running.\n\
623 2) JACK is running as another user, perhaps root.\n\
624 3) There is already another client called \"ardour\".\n\
626 Please consider the possibilities, and perhaps (re)start JACK."));
629 if (toplevel) {
630 win.set_transient_for (*toplevel);
633 if (we_set_params) {
634 win.add_button (Stock::OK, RESPONSE_CLOSE);
635 } else {
636 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
639 win.set_default_response (RESPONSE_CLOSE);
641 win.show_all ();
642 win.set_position (Gtk::WIN_POS_CENTER);
643 pop_back_splash ();
645 /* we just don't care about the result, but we want to block */
647 win.run ();
650 void
651 ARDOUR_UI::startup ()
653 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
654 exit (1);
657 use_config ();
659 goto_editor_window ();
661 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
662 show ();
665 void
666 ARDOUR_UI::no_memory_warning ()
668 XMLNode node (X_("no-memory-warning"));
669 Config->add_instant_xml (node);
672 void
673 ARDOUR_UI::check_memory_locking ()
675 #ifdef __APPLE__
676 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
677 return;
678 #else // !__APPLE__
680 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
682 if (engine->is_realtime() && memory_warning_node == 0) {
684 struct rlimit limits;
685 int64_t ram;
686 long pages, page_size;
688 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
689 ram = 0;
690 } else {
691 ram = (int64_t) pages * (int64_t) page_size;
694 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
695 return;
698 if (limits.rlim_cur != RLIM_INFINITY) {
700 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
703 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
704 "This might cause %1 to run out of memory before your system "
705 "runs out of memory. \n\n"
706 "You can view the memory limit with 'ulimit -l', "
707 "and it is normally controlled by /etc/security/limits.conf"),
708 PROGRAM_NAME).c_str());
710 VBox* vbox = msg.get_vbox();
711 HBox hbox;
712 CheckButton cb (_("Do not show this window again"));
714 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
716 hbox.pack_start (cb, true, false);
717 vbox->pack_start (hbox);
718 cb.show();
719 vbox->show();
720 hbox.show ();
722 pop_back_splash ();
724 editor->ensure_float (msg);
725 msg.run ();
729 #endif // !__APPLE__
733 void
734 ARDOUR_UI::finish()
736 if (_session) {
737 int tries = 0;
739 if (_session->transport_rolling() && (++tries < 8)) {
740 _session->request_stop (false, true);
741 usleep (10000);
744 if (_session->dirty()) {
745 switch (ask_about_saving_session(_("quit"))) {
746 case -1:
747 return;
748 break;
749 case 1:
750 /* use the default name */
751 if (save_state_canfail ("")) {
752 /* failed - don't quit */
753 MessageDialog msg (*editor,
754 _("\
755 Ardour was unable to save your session.\n\n\
756 If you still wish to quit, please use the\n\n\
757 \"Just quit\" option."));
758 pop_back_splash();
759 msg.run ();
760 return;
762 break;
763 case 0:
764 break;
768 second_connection.disconnect ();
769 point_one_second_connection.disconnect ();
770 point_oh_five_second_connection.disconnect ();
771 point_zero_one_second_connection.disconnect();
773 // _session->set_deletion_in_progress ();
774 _session->remove_pending_capture_state ();
775 delete _session;
776 _session = 0;
779 cerr << "Save before quit\n";
780 save_ardour_state ();
782 ArdourDialog::close_all_dialogs ();
783 engine->stop (true);
784 quit ();
788 ARDOUR_UI::ask_about_saving_session (const string & what)
790 ArdourDialog window (_("Unsaved Session"));
791 Gtk::HBox dhbox; // the hbox for the image and text
792 Gtk::Label prompt_label;
793 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
795 string msg;
797 msg = string_compose(_("Don't %1"), what);
798 window.add_button (msg, RESPONSE_REJECT);
799 msg = string_compose(_("Just %1"), what);
800 window.add_button (msg, RESPONSE_APPLY);
801 msg = string_compose(_("Save and %1"), what);
802 window.add_button (msg, RESPONSE_ACCEPT);
804 window.set_default_response (RESPONSE_ACCEPT);
806 Gtk::Button noquit_button (msg);
807 noquit_button.set_name ("EditorGTKButton");
809 string prompt;
810 string type;
812 if (_session->snap_name() == _session->name()) {
813 type = _("session");
814 } else {
815 type = _("snapshot");
817 prompt = string_compose(_("The %1 \"%2\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
818 type, _session->snap_name());
820 prompt_label.set_text (prompt);
821 prompt_label.set_name (X_("PrompterLabel"));
822 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
824 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
825 dhbox.set_homogeneous (false);
826 dhbox.pack_start (*dimage, false, false, 5);
827 dhbox.pack_start (prompt_label, true, false, 5);
828 window.get_vbox()->pack_start (dhbox);
830 window.set_name (_("Prompter"));
831 window.set_position (Gtk::WIN_POS_MOUSE);
832 window.set_modal (true);
833 window.set_resizable (false);
835 dhbox.show();
836 prompt_label.show();
837 dimage->show();
838 window.show();
839 window.set_keep_above (true);
840 window.present ();
842 ResponseType r = (ResponseType) window.run();
844 window.hide ();
846 switch (r) {
847 case RESPONSE_ACCEPT: // save and get out of here
848 return 1;
849 case RESPONSE_APPLY: // get out of here
850 return 0;
851 default:
852 break;
855 return -1;
858 gint
859 ARDOUR_UI::every_second ()
861 update_cpu_load ();
862 update_buffer_load ();
863 update_disk_space ();
864 return TRUE;
867 gint
868 ARDOUR_UI::every_point_one_seconds ()
870 update_speed_display ();
871 RapidScreenUpdate(); /* EMIT_SIGNAL */
872 return TRUE;
875 gint
876 ARDOUR_UI::every_point_zero_one_seconds ()
878 // august 2007: actual update frequency: 40Hz, not 100Hz
880 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
881 return TRUE;
884 void
885 ARDOUR_UI::update_sample_rate (nframes_t)
887 char buf[32];
889 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
891 if (!engine->connected()) {
893 snprintf (buf, sizeof (buf), _("disconnected"));
895 } else {
897 nframes_t rate = engine->frame_rate();
899 if (fmod (rate, 1000.0) != 0.0) {
900 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
901 (float) rate/1000.0f,
902 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
903 } else {
904 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
905 rate/1000,
906 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
910 sample_rate_label.set_text (buf);
913 void
914 ARDOUR_UI::update_cpu_load ()
916 char buf[32];
917 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
918 cpu_load_label.set_text (buf);
921 void
922 ARDOUR_UI::update_buffer_load ()
924 char buf[64];
925 uint32_t c, p;
927 if (_session) {
928 c = _session->capture_load ();
929 p = _session->playback_load ();
931 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
932 _session->playback_load(), _session->capture_load());
933 buffer_load_label.set_text (buf);
934 } else {
935 buffer_load_label.set_text ("");
939 void
940 ARDOUR_UI::count_recenabled_streams (Route& route)
942 Track* track = dynamic_cast<Track*>(&route);
943 if (track && track->record_enabled()) {
944 rec_enabled_streams += track->n_inputs().n_total();
948 void
949 ARDOUR_UI::update_disk_space()
951 if (_session == 0) {
952 return;
955 nframes_t frames = _session->available_capture_duration();
956 char buf[64];
957 nframes_t fr = _session->frame_rate();
959 if (frames == max_frames) {
960 strcpy (buf, _("Disk: 24hrs+"));
961 } else {
962 rec_enabled_streams = 0;
963 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
965 if (rec_enabled_streams) {
966 frames /= rec_enabled_streams;
969 int hrs;
970 int mins;
971 int secs;
973 hrs = frames / (fr * 3600);
974 frames -= hrs * fr * 3600;
975 mins = frames / (fr * 60);
976 frames -= mins * fr * 60;
977 secs = frames / fr;
979 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
982 disk_space_label.set_text (buf);
984 // An attempt to make the disk space label flash red when space has run out.
986 if (frames < fr * 60 * 5) {
987 /* disk_space_box.style ("disk_space_label_empty"); */
988 } else {
989 /* disk_space_box.style ("disk_space_label"); */
994 gint
995 ARDOUR_UI::update_wall_clock ()
997 time_t now;
998 struct tm *tm_now;
999 char buf[16];
1001 time (&now);
1002 tm_now = localtime (&now);
1004 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1005 wall_clock_label.set_text (buf);
1007 return TRUE;
1010 gint
1011 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1013 session_popup_menu->popup (0, 0);
1014 return TRUE;
1017 void
1018 ARDOUR_UI::redisplay_recent_sessions ()
1020 std::vector<sys::path> session_directories;
1021 RecentSessionsSorter cmp;
1023 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1024 recent_session_model->clear ();
1026 ARDOUR::RecentSessions rs;
1027 ARDOUR::read_recent_sessions (rs);
1029 if (rs.empty()) {
1030 recent_session_display.set_model (recent_session_model);
1031 return;
1034 // sort them alphabetically
1035 sort (rs.begin(), rs.end(), cmp);
1037 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1038 session_directories.push_back ((*i).second);
1041 for (vector<sys::path>::const_iterator i = session_directories.begin();
1042 i != session_directories.end(); ++i)
1044 std::vector<sys::path> state_file_paths;
1046 // now get available states for this session
1048 get_state_files_in_directory (*i, state_file_paths);
1050 vector<string*>* states;
1051 vector<const gchar*> item;
1052 string fullpath = (*i).to_string();
1054 /* remove any trailing / */
1056 if (fullpath[fullpath.length()-1] == '/') {
1057 fullpath = fullpath.substr (0, fullpath.length()-1);
1060 /* check whether session still exists */
1061 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1062 /* session doesn't exist */
1063 cerr << "skipping non-existent session " << fullpath << endl;
1064 continue;
1067 /* now get available states for this session */
1069 if ((states = Session::possible_states (fullpath)) == 0) {
1070 /* no state file? */
1071 continue;
1074 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1076 Gtk::TreeModel::Row row = *(recent_session_model->append());
1078 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1079 row[recent_session_columns.fullpath] = fullpath;
1081 if (state_file_names.size() > 1) {
1083 // add the children
1085 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1086 i2 != state_file_names.end(); ++i2)
1089 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1091 child_row[recent_session_columns.visible_name] = *i2;
1092 child_row[recent_session_columns.fullpath] = fullpath;
1097 recent_session_display.set_model (recent_session_model);
1100 void
1101 ARDOUR_UI::build_session_selector ()
1103 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1105 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1107 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1108 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1109 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1110 recent_session_model = TreeStore::create (recent_session_columns);
1111 recent_session_display.set_model (recent_session_model);
1112 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1113 recent_session_display.set_headers_visible (false);
1114 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1115 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1117 scroller->add (recent_session_display);
1118 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1120 session_selector_window->set_name ("SessionSelectorWindow");
1121 session_selector_window->set_size_request (200, 400);
1122 session_selector_window->get_vbox()->pack_start (*scroller);
1124 recent_session_display.show();
1125 scroller->show();
1126 //session_selector_window->get_vbox()->show();
1129 void
1130 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1132 session_selector_window->response (RESPONSE_ACCEPT);
1135 void
1136 ARDOUR_UI::open_recent_session ()
1138 bool can_return = (_session != 0);
1140 if (session_selector_window == 0) {
1141 build_session_selector ();
1144 redisplay_recent_sessions ();
1146 while (true) {
1148 session_selector_window->set_position (WIN_POS_MOUSE);
1150 ResponseType r = (ResponseType) session_selector_window->run ();
1152 switch (r) {
1153 case RESPONSE_ACCEPT:
1154 break;
1155 default:
1156 if (can_return) {
1157 session_selector_window->hide();
1158 return;
1159 } else {
1160 exit (1);
1164 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1165 continue;
1168 session_selector_window->hide();
1170 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1172 if (i == recent_session_model->children().end()) {
1173 return;
1176 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1177 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1179 _session_is_new = false;
1181 if (load_session (path, state) == 0) {
1182 break;
1185 can_return = false;
1189 bool
1190 ARDOUR_UI::check_audioengine ()
1192 if (engine) {
1193 if (!engine->connected()) {
1194 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1195 "You cannot open or close sessions in this condition"),
1196 PROGRAM_NAME));
1197 pop_back_splash ();
1198 msg.run ();
1199 return false;
1201 return true;
1202 } else {
1203 return false;
1207 void
1208 ARDOUR_UI::open_session ()
1210 if (!check_audioengine()) {
1211 return;
1215 /* popup selector window */
1217 if (open_session_selector == 0) {
1219 /* ardour sessions are folders */
1221 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1222 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1223 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1224 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1226 FileFilter session_filter;
1227 session_filter.add_pattern ("*.ardour");
1228 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1229 open_session_selector->add_filter (session_filter);
1230 open_session_selector->set_filter (session_filter);
1233 int response = open_session_selector->run();
1234 open_session_selector->hide ();
1236 switch (response) {
1237 case RESPONSE_ACCEPT:
1238 break;
1239 default:
1240 open_session_selector->hide();
1241 return;
1244 open_session_selector->hide();
1245 string session_path = open_session_selector->get_filename();
1246 string path, name;
1247 bool isnew;
1249 if (session_path.length() > 0) {
1250 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1251 _session_is_new = isnew;
1252 load_session (path, name);
1258 void
1259 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1261 list<boost::shared_ptr<MidiTrack> > tracks;
1263 if (_session == 0) {
1264 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1265 return;
1268 try {
1269 if (disk) {
1271 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1273 if (tracks.size() != how_many) {
1274 if (how_many == 1) {
1275 error << _("could not create a new midi track") << endmsg;
1276 } else {
1277 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1280 } /*else {
1281 if ((route = _session->new_midi_route ()) == 0) {
1282 error << _("could not create new midi bus") << endmsg;
1287 catch (...) {
1288 MessageDialog msg (*editor,
1289 _("There are insufficient JACK ports available\n\
1290 to create a new track or bus.\n\
1291 You should save Ardour, exit and\n\
1292 restart JACK with more ports."));
1293 msg.run ();
1298 void
1299 ARDOUR_UI::session_add_audio_route (bool track, bool aux, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1301 list<boost::shared_ptr<AudioTrack> > tracks;
1302 RouteList routes;
1304 if (_session == 0) {
1305 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1306 return;
1309 try {
1310 if (track) {
1311 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1313 if (tracks.size() != how_many) {
1314 if (how_many == 1) {
1315 error << _("could not create a new audio track") << endmsg;
1316 } else {
1317 error << string_compose (_("could only create %1 of %2 new audio %3"),
1318 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1322 } else {
1324 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1326 if (routes.size() != how_many) {
1327 if (how_many == 1) {
1328 error << _("could not create a new audio track") << endmsg;
1329 } else {
1330 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1336 catch (...) {
1337 MessageDialog msg (*editor,
1338 _("There are insufficient JACK ports available\n\
1339 to create a new track or bus.\n\
1340 You should save Ardour, exit and\n\
1341 restart JACK with more ports."));
1342 pop_back_splash ();
1343 msg.run ();
1347 void
1348 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1350 nframes_t _preroll = 0;
1352 if (_session) {
1353 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1354 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1356 if (new_position > _preroll) {
1357 new_position -= _preroll;
1358 } else {
1359 new_position = 0;
1362 _session->request_locate (new_position);
1366 void
1367 ARDOUR_UI::transport_goto_start ()
1369 if (_session) {
1370 _session->goto_start();
1372 /* force displayed area in editor to start no matter
1373 what "follow playhead" setting is.
1376 if (editor) {
1377 editor->center_screen (_session->current_start_frame ());
1382 void
1383 ARDOUR_UI::transport_goto_zero ()
1385 if (_session) {
1386 _session->request_locate (0);
1388 /* force displayed area in editor to start no matter
1389 what "follow playhead" setting is.
1392 if (editor) {
1393 editor->reset_x_origin (0);
1398 void
1399 ARDOUR_UI::transport_goto_wallclock ()
1401 if (_session && editor) {
1403 time_t now;
1404 struct tm tmnow;
1405 nframes64_t frames;
1407 time (&now);
1408 localtime_r (&now, &tmnow);
1410 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1411 frames += tmnow.tm_min * (60 * _session->frame_rate());
1412 frames += tmnow.tm_sec * _session->frame_rate();
1414 _session->request_locate (frames);
1416 /* force displayed area in editor to start no matter
1417 what "follow playhead" setting is.
1420 if (editor) {
1421 editor->center_screen (frames);
1426 void
1427 ARDOUR_UI::transport_goto_end ()
1429 if (_session) {
1430 nframes_t const frame = _session->current_end_frame();
1431 _session->request_locate (frame);
1433 /* force displayed area in editor to start no matter
1434 what "follow playhead" setting is.
1437 if (editor) {
1438 editor->center_screen (frame);
1443 void
1444 ARDOUR_UI::transport_stop ()
1446 if (!_session) {
1447 return;
1450 if (_session->is_auditioning()) {
1451 _session->cancel_audition ();
1452 return;
1455 _session->request_stop (false, true);
1458 void
1459 ARDOUR_UI::transport_stop_and_forget_capture ()
1461 if (_session) {
1462 _session->request_stop (true, true);
1466 void
1467 ARDOUR_UI::remove_last_capture()
1469 if (editor) {
1470 editor->remove_last_capture();
1474 void
1475 ARDOUR_UI::transport_record (bool roll)
1478 if (_session) {
1479 switch (_session->record_status()) {
1480 case Session::Disabled:
1481 if (_session->ntracks() == 0) {
1482 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1483 msg.run ();
1484 return;
1486 _session->maybe_enable_record ();
1487 if (roll) {
1488 transport_roll ();
1490 break;
1491 case Session::Recording:
1492 if (roll) {
1493 _session->request_stop();
1494 } else {
1495 _session->disable_record (false, true);
1497 break;
1499 case Session::Enabled:
1500 _session->disable_record (false, true);
1503 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1506 void
1507 ARDOUR_UI::transport_roll ()
1509 if (!_session) {
1510 return;
1513 if (_session->is_auditioning()) {
1514 return;
1517 if (_session->config.get_external_sync()) {
1518 switch (_session->config.get_sync_source()) {
1519 case JACK:
1520 break;
1521 default:
1522 /* transport controlled by the master */
1523 return;
1527 bool rolling = _session->transport_rolling();
1529 if (_session->get_play_loop()) {
1530 /* XXX it is not possible to just leave seamless loop and keep
1531 playing at present (nov 4th 2009)
1533 if (!Config->get_seamless_loop()) {
1534 _session->request_play_loop (false, true);
1536 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1537 /* stop playing a range if we currently are */
1538 _session->request_play_range (0, true);
1541 if (join_play_range_button.get_active()) {
1542 _session->request_play_range (&editor->get_selection().time, true);
1545 if (!rolling) {
1546 _session->request_transport_speed (1.0f);
1550 void
1551 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1554 if (!_session) {
1555 return;
1558 if (_session->is_auditioning()) {
1559 _session->cancel_audition ();
1560 return;
1563 if (_session->config.get_external_sync()) {
1564 switch (_session->config.get_sync_source()) {
1565 case JACK:
1566 break;
1567 default:
1568 /* transport controlled by the master */
1569 return;
1573 bool rolling = _session->transport_rolling();
1574 bool affect_transport = true;
1576 if (rolling && roll_out_of_bounded_mode) {
1577 /* drop out of loop/range playback but leave transport rolling */
1578 if (_session->get_play_loop()) {
1579 if (Config->get_seamless_loop()) {
1580 /* the disk buffers contain copies of the loop - we can't
1581 just keep playing, so stop the transport. the user
1582 can restart as they wish.
1584 affect_transport = true;
1585 } else {
1586 /* disk buffers are normal, so we can keep playing */
1587 affect_transport = false;
1589 _session->request_play_loop (false, true);
1590 } else if (_session->get_play_range ()) {
1591 affect_transport = false;
1592 _session->request_play_range (0, true);
1596 if (affect_transport) {
1597 if (rolling) {
1598 _session->request_stop (with_abort, true);
1599 } else {
1600 if (join_play_range_button.get_active()) {
1601 _session->request_play_range (&editor->get_selection().time, true);
1604 _session->request_transport_speed (1.0f);
1609 void
1610 ARDOUR_UI::toggle_session_auto_loop ()
1612 if (_session) {
1613 if (_session->get_play_loop()) {
1614 if (_session->transport_rolling()) {
1615 Location * looploc = _session->locations()->auto_loop_location();
1616 if (looploc) {
1617 _session->request_locate (looploc->start(), true);
1619 } else {
1620 _session->request_play_loop (false);
1622 } else {
1623 Location * looploc = _session->locations()->auto_loop_location();
1624 if (looploc) {
1625 _session->request_play_loop (true);
1631 void
1632 ARDOUR_UI::transport_play_selection ()
1634 if (!_session) {
1635 return;
1638 editor->play_selection ();
1641 void
1642 ARDOUR_UI::transport_rewind (int option)
1644 float current_transport_speed;
1646 if (_session) {
1647 current_transport_speed = _session->transport_speed();
1649 if (current_transport_speed >= 0.0f) {
1650 switch (option) {
1651 case 0:
1652 _session->request_transport_speed (-1.0f);
1653 break;
1654 case 1:
1655 _session->request_transport_speed (-4.0f);
1656 break;
1657 case -1:
1658 _session->request_transport_speed (-0.5f);
1659 break;
1661 } else {
1662 /* speed up */
1663 _session->request_transport_speed (current_transport_speed * 1.5f);
1668 void
1669 ARDOUR_UI::transport_forward (int option)
1671 float current_transport_speed;
1673 if (_session) {
1674 current_transport_speed = _session->transport_speed();
1676 if (current_transport_speed <= 0.0f) {
1677 switch (option) {
1678 case 0:
1679 _session->request_transport_speed (1.0f);
1680 break;
1681 case 1:
1682 _session->request_transport_speed (4.0f);
1683 break;
1684 case -1:
1685 _session->request_transport_speed (0.5f);
1686 break;
1688 } else {
1689 /* speed up */
1690 _session->request_transport_speed (current_transport_speed * 1.5f);
1696 void
1697 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1699 if (_session == 0) {
1700 return;
1703 boost::shared_ptr<Route> r;
1705 if ((r = _session->route_by_remote_id (dstream)) != 0) {
1707 Track* t;
1709 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1710 t->set_record_enabled (!t->record_enabled());
1713 if (_session == 0) {
1714 return;
1718 void
1719 ARDOUR_UI::map_transport_state ()
1721 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1723 if (!_session) {
1724 auto_loop_button.set_visual_state (0);
1725 play_selection_button.set_visual_state (0);
1726 roll_button.set_visual_state (0);
1727 stop_button.set_visual_state (1);
1728 return;
1731 float sp = _session->transport_speed();
1733 if (sp == 1.0f) {
1734 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1735 shuttle_box.queue_draw ();
1736 } else if (sp == 0.0f) {
1737 shuttle_fract = 0;
1738 shuttle_box.queue_draw ();
1739 update_disk_space ();
1742 if (sp != 0.0) {
1744 /* we're rolling */
1746 if (_session->get_play_range()) {
1748 play_selection_button.set_visual_state (1);
1749 roll_button.set_visual_state (0);
1750 auto_loop_button.set_visual_state (0);
1752 } else if (_session->get_play_loop ()) {
1754 auto_loop_button.set_visual_state (1);
1755 play_selection_button.set_visual_state (0);
1756 roll_button.set_visual_state (0);
1758 } else {
1760 roll_button.set_visual_state (1);
1761 play_selection_button.set_visual_state (0);
1762 auto_loop_button.set_visual_state (0);
1765 if (join_play_range_button.get_active()) {
1766 /* light up both roll and play-selection if they are joined */
1767 roll_button.set_visual_state (1);
1768 play_selection_button.set_visual_state (1);
1771 stop_button.set_visual_state (0);
1773 } else {
1775 stop_button.set_visual_state (1);
1776 roll_button.set_visual_state (0);
1777 play_selection_button.set_visual_state (0);
1778 auto_loop_button.set_visual_state (0);
1782 void
1783 ARDOUR_UI::engine_stopped ()
1785 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1786 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1787 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1790 void
1791 ARDOUR_UI::engine_running ()
1793 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1794 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1795 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1797 Glib::RefPtr<Action> action;
1798 const char* action_name = 0;
1800 switch (engine->frames_per_cycle()) {
1801 case 32:
1802 action_name = X_("JACKLatency32");
1803 break;
1804 case 64:
1805 action_name = X_("JACKLatency64");
1806 break;
1807 case 128:
1808 action_name = X_("JACKLatency128");
1809 break;
1810 case 512:
1811 action_name = X_("JACKLatency512");
1812 break;
1813 case 1024:
1814 action_name = X_("JACKLatency1024");
1815 break;
1816 case 2048:
1817 action_name = X_("JACKLatency2048");
1818 break;
1819 case 4096:
1820 action_name = X_("JACKLatency4096");
1821 break;
1822 case 8192:
1823 action_name = X_("JACKLatency8192");
1824 break;
1825 default:
1826 /* XXX can we do anything useful ? */
1827 break;
1830 if (action_name) {
1832 action = ActionManager::get_action (X_("JACK"), action_name);
1834 if (action) {
1835 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1836 ract->set_active ();
1841 void
1842 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1844 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1845 /* we can't rely on the original string continuing to exist when we are called
1846 again in the GUI thread, so make a copy and note that we need to
1847 free it later.
1849 char *copy = strdup (reason);
1850 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1851 return;
1854 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1855 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1857 update_sample_rate (0);
1859 string msgstr;
1861 /* if the reason is a non-empty string, it means that the backend was shutdown
1862 rather than just Ardour.
1865 if (strlen (reason)) {
1866 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1867 } else {
1868 msgstr = _("\
1869 JACK has either been shutdown or it\n\
1870 disconnected Ardour because Ardour\n\
1871 was not fast enough. Try to restart\n\
1872 JACK, reconnect and save the session.");
1875 MessageDialog msg (*editor, msgstr);
1876 pop_back_splash ();
1877 msg.run ();
1879 if (free_reason) {
1880 free ((char*) reason);
1884 int32_t
1885 ARDOUR_UI::do_engine_start ()
1887 try {
1888 engine->start();
1891 catch (...) {
1892 engine->stop ();
1893 error << _("Unable to start the session running")
1894 << endmsg;
1895 unload_session ();
1896 return -2;
1899 return 0;
1902 void
1903 ARDOUR_UI::setup_theme ()
1905 theme_manager->setup_theme();
1908 void
1909 ARDOUR_UI::update_clocks ()
1911 if (!editor || !editor->dragging_playhead()) {
1912 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1916 void
1917 ARDOUR_UI::start_clocking ()
1919 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1922 void
1923 ARDOUR_UI::stop_clocking ()
1925 clock_signal_connection.disconnect ();
1928 void
1929 ARDOUR_UI::toggle_clocking ()
1931 #if 0
1932 if (clock_button.get_active()) {
1933 start_clocking ();
1934 } else {
1935 stop_clocking ();
1937 #endif
1940 gint
1941 ARDOUR_UI::_blink (void *arg)
1944 ((ARDOUR_UI *) arg)->blink ();
1945 return TRUE;
1948 void
1949 ARDOUR_UI::blink ()
1951 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1954 void
1955 ARDOUR_UI::start_blinking ()
1957 /* Start the blink signal. Everybody with a blinking widget
1958 uses Blink to drive the widget's state.
1961 if (blink_timeout_tag < 0) {
1962 blink_on = false;
1963 blink_timeout_tag = g_timeout_add (240, _blink, this);
1967 void
1968 ARDOUR_UI::stop_blinking ()
1970 if (blink_timeout_tag >= 0) {
1971 g_source_remove (blink_timeout_tag);
1972 blink_timeout_tag = -1;
1977 /** Ask the user for the name of a new shapshot and then take it.
1980 void
1981 ARDOUR_UI::snapshot_session (bool switch_to_it)
1983 ArdourPrompter prompter (true);
1984 string snapname;
1986 prompter.set_name ("Prompter");
1987 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1988 prompter.set_title (_("Take Snapshot"));
1989 prompter.set_title (_("Take Snapshot"));
1990 prompter.set_prompt (_("Name of new snapshot"));
1992 if (!switch_to_it) {
1993 char timebuf[128];
1994 time_t n;
1995 struct tm local_time;
1997 time (&n);
1998 localtime_r (&n, &local_time);
1999 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2000 prompter.set_initial_text (timebuf);
2003 again:
2004 switch (prompter.run()) {
2005 case RESPONSE_ACCEPT:
2007 prompter.get_result (snapname);
2009 bool do_save = (snapname.length() != 0);
2011 if (do_save) {
2012 if (snapname.find ('/') != string::npos) {
2013 MessageDialog msg (_("To ensure compatibility with various systems\n"
2014 "snapshot names may not contain a '/' character"));
2015 msg.run ();
2016 goto again;
2018 if (snapname.find ('\\') != string::npos) {
2019 MessageDialog msg (_("To ensure compatibility with various systems\n"
2020 "snapshot names may not contain a '\\' character"));
2021 msg.run ();
2022 goto again;
2026 vector<sys::path> p;
2027 get_state_files_in_directory (_session->session_directory().root_path(), p);
2028 vector<string> n = get_file_names_no_extension (p);
2029 if (find (n.begin(), n.end(), snapname) != n.end()) {
2031 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2032 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2033 confirm.get_vbox()->pack_start (m, true, true);
2034 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2035 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2036 confirm.show_all ();
2037 switch (confirm.run()) {
2038 case RESPONSE_CANCEL:
2039 do_save = false;
2043 if (do_save) {
2044 save_state (snapname, switch_to_it);
2046 break;
2049 default:
2050 break;
2054 void
2055 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2057 save_state_canfail (name, switch_to_it);
2061 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2063 if (_session) {
2064 int ret;
2066 if (name.length() == 0) {
2067 name = _session->snap_name();
2070 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2071 return ret;
2074 cerr << "SS canfail\n";
2075 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2076 return 0;
2079 void
2080 ARDOUR_UI::primary_clock_value_changed ()
2082 if (_session) {
2083 _session->request_locate (primary_clock.current_time ());
2087 void
2088 ARDOUR_UI::big_clock_value_changed ()
2090 if (_session) {
2091 _session->request_locate (big_clock.current_time ());
2095 void
2096 ARDOUR_UI::secondary_clock_value_changed ()
2098 if (_session) {
2099 _session->request_locate (secondary_clock.current_time ());
2103 void
2104 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2106 if (_session == 0) {
2107 return;
2110 Session::RecordState const r = _session->record_status ();
2111 bool const h = _session->have_rec_enabled_track ();
2113 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2114 if (onoff) {
2115 rec_button.set_visual_state (2);
2116 } else {
2117 rec_button.set_visual_state (0);
2119 } else if (r == Session::Recording && h) {
2120 rec_button.set_visual_state (1);
2121 } else {
2122 rec_button.set_visual_state (0);
2126 void
2127 ARDOUR_UI::save_template ()
2129 ArdourPrompter prompter (true);
2130 string name;
2132 if (!check_audioengine()) {
2133 return;
2136 prompter.set_name (X_("Prompter"));
2137 prompter.set_title (_("Save Mix Template"));
2138 prompter.set_prompt (_("Name for mix template:"));
2139 prompter.set_initial_text(_session->name() + _("-template"));
2140 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2142 switch (prompter.run()) {
2143 case RESPONSE_ACCEPT:
2144 prompter.get_result (name);
2146 if (name.length()) {
2147 _session->save_template (name);
2149 break;
2151 default:
2152 break;
2156 void
2157 ARDOUR_UI::edit_metadata ()
2159 SessionMetadataEditor dialog;
2160 dialog.set_session (_session);
2161 editor->ensure_float (dialog);
2162 dialog.run ();
2165 void
2166 ARDOUR_UI::import_metadata ()
2168 SessionMetadataImporter dialog;
2169 dialog.set_session (_session);
2170 editor->ensure_float (dialog);
2171 dialog.run ();
2174 void
2175 ARDOUR_UI::fontconfig_dialog ()
2177 #ifdef GTKOSX
2178 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2179 may not and it can take a while to build it. Warn them.
2182 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2184 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2185 MessageDialog msg (*_startup,
2186 _("Welcome to Ardour.\n\n"
2187 "The program will take a bit longer to start up\n"
2188 "while the system fonts are checked.\n\n"
2189 "This will only be done once, and you will\n"
2190 "not see this message again\n"),
2191 true,
2192 Gtk::MESSAGE_INFO,
2193 Gtk::BUTTONS_OK);
2194 pop_back_splash ();
2195 msg.show_all ();
2196 msg.present ();
2197 msg.run ();
2199 #endif
2202 void
2203 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2205 existing_session = false;
2207 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2208 session_path = cmdline_path;
2209 existing_session = true;
2210 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2211 session_path = Glib::path_get_dirname (string (cmdline_path));
2212 existing_session = true;
2213 } else {
2214 /* it doesn't exist, assume the best */
2215 session_path = Glib::path_get_dirname (string (cmdline_path));
2218 session_name = basename_nosuffix (string (cmdline_path));
2222 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2224 /* when this is called, the backend audio system must be running */
2226 /* the main idea here is to deal with the fact that a cmdline argument for the session
2227 can be interpreted in different ways - it could be a directory or a file, and before
2228 we load, we need to know both the session directory and the snapshot (statefile) within it
2229 that we are supposed to use.
2232 if (session_name.length() == 0 || session_path.length() == 0) {
2233 return false;
2236 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2238 Glib::ustring predicted_session_file;
2240 predicted_session_file = session_path;
2241 predicted_session_file += '/';
2242 predicted_session_file += session_name;
2243 predicted_session_file += ARDOUR::statefile_suffix;
2245 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2246 existing_session = true;
2249 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2251 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2252 /* existing .ardour file */
2253 existing_session = true;
2256 } else {
2257 existing_session = false;
2260 /* lets just try to load it */
2262 if (create_engine ()) {
2263 backend_audio_error (false, _startup);
2264 return -1;
2267 return load_session (session_path, session_name);
2270 bool
2271 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2273 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2275 MessageDialog msg (str,
2276 false,
2277 Gtk::MESSAGE_WARNING,
2278 Gtk::BUTTONS_YES_NO,
2279 true);
2282 msg.set_name (X_("OpenExistingDialog"));
2283 msg.set_title (_("Open Existing Session"));
2284 msg.set_wmclass (X_("existing_session"), "Ardour");
2285 msg.set_position (Gtk::WIN_POS_MOUSE);
2286 pop_back_splash ();
2288 switch (msg.run()) {
2289 case RESPONSE_YES:
2290 return true;
2291 break;
2293 return false;
2297 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2299 BusProfile bus_profile;
2301 if (Profile->get_sae()) {
2303 bus_profile.master_out_channels = 2;
2304 bus_profile.input_ac = AutoConnectPhysical;
2305 bus_profile.output_ac = AutoConnectMaster;
2306 bus_profile.requested_physical_in = 0; // use all available
2307 bus_profile.requested_physical_out = 0; // use all available
2309 } else {
2311 /* get settings from advanced section of NSD */
2313 if (_startup->create_master_bus()) {
2314 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2315 } else {
2316 bus_profile.master_out_channels = 0;
2319 if (_startup->connect_inputs()) {
2320 bus_profile.input_ac = AutoConnectPhysical;
2321 } else {
2322 bus_profile.input_ac = AutoConnectOption (0);
2325 /// @todo some minor tweaks.
2327 bus_profile.output_ac = AutoConnectOption (0);
2329 if (_startup->connect_outputs ()) {
2330 if (_startup->connect_outs_to_master()) {
2331 bus_profile.output_ac = AutoConnectMaster;
2332 } else if (_startup->connect_outs_to_physical()) {
2333 bus_profile.output_ac = AutoConnectPhysical;
2337 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2338 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2341 if (build_session (session_path, session_name, bus_profile)) {
2342 return -1;
2345 return 0;
2348 void
2349 ARDOUR_UI::idle_load (const Glib::ustring& path)
2351 if (_session) {
2352 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2353 /* /path/to/foo => /path/to/foo, foo */
2354 load_session (path, basename_nosuffix (path));
2355 } else {
2356 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2357 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2359 } else {
2361 ARDOUR_COMMAND_LINE::session_name = path;
2364 * new_session_dialog doens't exist in A3
2365 * Try to remove all references to it to
2366 * see if it will compile. NOTE: this will
2367 * likely cause a runtime issue is my somewhat
2368 * uneducated guess.
2371 //if (new_session_dialog) {
2374 /* make it break out of Dialog::run() and
2375 start again.
2378 //new_session_dialog->response (1);
2383 void
2384 ARDOUR_UI::end_loading_messages ()
2386 // hide_splash ();
2389 void
2390 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2392 // show_splash ();
2393 // splash->message (msg);
2394 flush_pending ();
2397 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2399 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2401 Glib::ustring session_name;
2402 Glib::ustring session_path;
2403 Glib::ustring template_name;
2404 int ret = -1;
2405 bool likely_new = false;
2407 if (! load_template.empty()) {
2408 should_be_new = true;
2409 template_name = load_template;
2412 while (ret != 0) {
2414 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2416 /* if they named a specific statefile, use it, otherwise they are
2417 just giving a session folder, and we want to use it as is
2418 to find the session.
2421 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2422 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2423 } else {
2424 session_path = ARDOUR_COMMAND_LINE::session_name;
2427 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2429 } else {
2431 bool const apply = run_startup (should_be_new, load_template);
2432 if (!apply) {
2433 if (quit_on_cancel) {
2434 exit (1);
2435 } else {
2436 return ret;
2440 /* if we run the startup dialog again, offer more than just "new session" */
2442 should_be_new = false;
2444 session_name = _startup->session_name (likely_new);
2446 /* this shouldn't happen, but we catch it just in case it does */
2448 if (session_name.empty()) {
2449 break;
2451 if (_startup->use_session_template()) {
2452 template_name = _startup->session_template_name();
2453 _session_is_new = true;
2456 if (session_name[0] == '/' ||
2457 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2458 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2460 /* absolute path or cwd-relative path specified for session name: infer session folder
2461 from what was given.
2464 session_path = Glib::path_get_dirname (session_name);
2465 session_name = Glib::path_get_basename (session_name);
2467 } else {
2469 session_path = _startup->session_folder();
2473 if (create_engine ()) {
2474 break;
2477 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2479 if (likely_new) {
2481 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2483 if (!ask_about_loading_existing_session (existing)) {
2484 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2485 continue;
2489 _session_is_new = false;
2491 } else {
2493 if (!likely_new) {
2494 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2495 msg.run ();
2496 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2497 continue;
2500 if (session_name.find ('/') != Glib::ustring::npos) {
2501 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2502 "session names may not contain a '/' character"));
2503 msg.run ();
2504 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2505 continue;
2508 if (session_name.find ('\\') != Glib::ustring::npos) {
2509 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2510 "session names may not contain a '\\' character"));
2511 msg.run ();
2512 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2513 continue;
2516 _session_is_new = true;
2519 if (likely_new && template_name.empty()) {
2521 ret = build_session_from_nsd (session_path, session_name);
2523 } else {
2525 ret = load_session (session_path, session_name, template_name);
2526 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2527 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2528 exit (1);
2533 return ret;
2536 void
2537 ARDOUR_UI::close_session()
2539 if (!check_audioengine()) {
2540 return;
2543 if (unload_session (true)) {
2544 return;
2547 ARDOUR_COMMAND_LINE::session_name = "";
2548 get_session_parameters (true, false);
2552 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2554 Session *new_session;
2555 int unload_status;
2556 int retval = -1;
2558 session_loaded = false;
2560 if (!check_audioengine()) {
2561 return -1;
2564 unload_status = unload_session ();
2566 if (unload_status < 0) {
2567 goto out;
2568 } else if (unload_status > 0) {
2569 retval = 0;
2570 goto out;
2573 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2575 try {
2576 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2579 /* this one is special */
2581 catch (AudioEngine::PortRegistrationFailure& err) {
2583 MessageDialog msg (err.what(),
2584 true,
2585 Gtk::MESSAGE_INFO,
2586 Gtk::BUTTONS_CLOSE);
2588 msg.set_title (_("Port Registration Error"));
2589 msg.set_secondary_text (_("Click the Close button to try again."));
2590 msg.set_position (Gtk::WIN_POS_CENTER);
2591 pop_back_splash ();
2592 msg.present ();
2594 int response = msg.run ();
2596 msg.hide ();
2598 switch (response) {
2599 case RESPONSE_CANCEL:
2600 exit (1);
2601 default:
2602 break;
2604 goto out;
2607 catch (...) {
2609 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2610 true,
2611 Gtk::MESSAGE_INFO,
2612 Gtk::BUTTONS_CLOSE);
2614 msg.set_title (_("Loading Error"));
2615 msg.set_secondary_text (_("Click the Close button to try again."));
2616 msg.set_position (Gtk::WIN_POS_CENTER);
2617 pop_back_splash ();
2618 msg.present ();
2620 int response = msg.run ();
2622 msg.hide ();
2624 switch (response) {
2625 case RESPONSE_CANCEL:
2626 exit (1);
2627 default:
2628 break;
2630 goto out;
2633 set_session (new_session);
2635 session_loaded = true;
2637 goto_editor_window ();
2639 if (_session) {
2640 _session->set_clean ();
2643 flush_pending ();
2644 retval = 0;
2646 out:
2647 return retval;
2651 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2653 Session *new_session;
2654 int x;
2656 if (!check_audioengine()) {
2657 return -1;
2660 session_loaded = false;
2662 x = unload_session ();
2664 if (x < 0) {
2665 return -1;
2666 } else if (x > 0) {
2667 return 0;
2670 _session_is_new = true;
2672 try {
2673 new_session = new Session (*engine, path, snap_name, &bus_profile);
2676 catch (...) {
2678 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2679 pop_back_splash ();
2680 msg.run ();
2681 return -1;
2684 set_session (new_session);
2686 session_loaded = true;
2688 new_session->save_state(new_session->name());
2690 return 0;
2693 void
2694 ARDOUR_UI::show ()
2696 if (editor) {
2697 editor->show_window ();
2699 if (!shown_flag) {
2700 editor->present ();
2703 shown_flag = true;
2707 void
2708 ARDOUR_UI::launch_chat ()
2710 #ifdef __APPLE__
2711 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2712 #else
2713 open_uri("http://webchat.freenode.net/?channels=ardour");
2714 #endif
2717 void
2718 ARDOUR_UI::show_about ()
2720 if (about == 0) {
2721 about = new About;
2722 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2725 about->set_transient_for(*editor);
2726 about->show_all ();
2729 void
2730 ARDOUR_UI::hide_about ()
2732 if (about) {
2733 about->get_window()->set_cursor ();
2734 about->hide ();
2738 void
2739 ARDOUR_UI::about_signal_response (int /*response*/)
2741 hide_about();
2744 void
2745 ARDOUR_UI::show_splash ()
2747 if (splash == 0) {
2748 try {
2749 splash = new Splash;
2750 } catch (...) {
2751 return;
2755 splash->show ();
2756 splash->present ();
2757 splash->queue_draw ();
2758 splash->get_window()->process_updates (true);
2759 flush_pending ();
2762 void
2763 ARDOUR_UI::hide_splash ()
2765 if (splash) {
2766 splash->hide();
2770 void
2771 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2772 const string& plural_msg, const string& singular_msg)
2774 size_t removed;
2776 removed = rep.paths.size();
2778 if (removed == 0) {
2779 MessageDialog msgd (*editor,
2780 _("No audio files were ready for cleanup"),
2781 true,
2782 Gtk::MESSAGE_INFO,
2783 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2784 msgd.set_secondary_text (_("If this seems suprising, \n\
2785 check for any existing snapshots.\n\
2786 These may still include regions that\n\
2787 require some unused files to continue to exist."));
2789 msgd.run ();
2790 return;
2793 ArdourDialog results (_("Clean-up"), true, false);
2795 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2796 CleanupResultsModelColumns() {
2797 add (visible_name);
2798 add (fullpath);
2800 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2801 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2805 CleanupResultsModelColumns results_columns;
2806 Glib::RefPtr<Gtk::ListStore> results_model;
2807 Gtk::TreeView results_display;
2809 results_model = ListStore::create (results_columns);
2810 results_display.set_model (results_model);
2811 results_display.append_column (list_title, results_columns.visible_name);
2813 results_display.set_name ("CleanupResultsList");
2814 results_display.set_headers_visible (true);
2815 results_display.set_headers_clickable (false);
2816 results_display.set_reorderable (false);
2818 Gtk::ScrolledWindow list_scroller;
2819 Gtk::Label txt;
2820 Gtk::VBox dvbox;
2821 Gtk::HBox dhbox; // the hbox for the image and text
2822 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2823 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2825 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2827 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2829 /* subst:
2830 %1 - number of files removed
2831 %2 - location of "dead_sounds"
2832 %3 - size of files affected
2833 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2836 const char* bprefix;
2837 double space_adjusted = 0;
2839 if (rep.space < 100000.0f) {
2840 bprefix = X_("kilo");
2841 } else if (rep.space < 1000000.0f * 1000) {
2842 bprefix = X_("mega");
2843 space_adjusted = truncf((float)rep.space / 1000.0);
2844 } else {
2845 bprefix = X_("giga");
2846 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2849 if (removed > 1) {
2850 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2851 } else {
2852 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2855 dhbox.pack_start (*dimage, true, false, 5);
2856 dhbox.pack_start (txt, true, false, 5);
2858 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2859 TreeModel::Row row = *(results_model->append());
2860 row[results_columns.visible_name] = *i;
2861 row[results_columns.fullpath] = *i;
2864 list_scroller.add (results_display);
2865 list_scroller.set_size_request (-1, 150);
2866 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2868 dvbox.pack_start (dhbox, true, false, 5);
2869 dvbox.pack_start (list_scroller, true, false, 5);
2870 ddhbox.pack_start (dvbox, true, false, 5);
2872 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2873 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2874 results.set_default_response (RESPONSE_CLOSE);
2875 results.set_position (Gtk::WIN_POS_MOUSE);
2877 results_display.show();
2878 list_scroller.show();
2879 txt.show();
2880 dvbox.show();
2881 dhbox.show();
2882 ddhbox.show();
2883 dimage->show();
2885 //results.get_vbox()->show();
2886 results.set_resizable (false);
2888 results.run ();
2892 void
2893 ARDOUR_UI::cleanup ()
2895 if (_session == 0) {
2896 /* shouldn't happen: menu item is insensitive */
2897 return;
2901 MessageDialog checker (_("Are you sure you want to cleanup?"),
2902 true,
2903 Gtk::MESSAGE_QUESTION,
2904 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2906 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2907 ALL undo/redo information will be lost if you cleanup.\n\
2908 After cleanup, unused audio files will be moved to a \
2909 \"dead sounds\" location."));
2911 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2912 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2913 checker.set_default_response (RESPONSE_CANCEL);
2915 checker.set_name (_("CleanupDialog"));
2916 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2917 checker.set_position (Gtk::WIN_POS_MOUSE);
2919 switch (checker.run()) {
2920 case RESPONSE_ACCEPT:
2921 break;
2922 default:
2923 return;
2926 ARDOUR::CleanupReport rep;
2928 editor->prepare_for_cleanup ();
2930 /* do not allow flush until a session is reloaded */
2932 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2933 if (act) {
2934 act->set_sensitive (false);
2937 if (_session->cleanup_sources (rep)) {
2938 editor->finish_cleanup ();
2939 return;
2942 editor->finish_cleanup ();
2944 checker.hide();
2945 display_cleanup_results (rep,
2946 _("cleaned files"),
2947 _("\
2948 The following %1 files were not in use and \n\
2949 have been moved to:\n\
2950 %2. \n\n\
2951 Flushing the wastebasket will \n\
2952 release an additional\n\
2953 %3 %4bytes of disk space.\n"),
2954 _("\
2955 The following file was not in use and \n \
2956 has been moved to:\n \
2957 %2. \n\n\
2958 Flushing the wastebasket will \n\
2959 release an additional\n\
2960 %3 %4bytes of disk space.\n"
2965 void
2966 ARDOUR_UI::flush_trash ()
2968 if (_session == 0) {
2969 /* shouldn't happen: menu item is insensitive */
2970 return;
2973 ARDOUR::CleanupReport rep;
2975 if (_session->cleanup_trash_sources (rep)) {
2976 return;
2979 display_cleanup_results (rep,
2980 _("deleted file"),
2981 _("The following %1 files were deleted from\n\
2982 %2,\n\
2983 releasing %3 %4bytes of disk space"),
2984 _("The following file was deleted from\n\
2985 %2,\n\
2986 releasing %3 %4bytes of disk space"));
2989 void
2990 ARDOUR_UI::add_route (Gtk::Window* float_window)
2992 int count;
2994 if (!_session) {
2995 return;
2998 if (add_route_dialog == 0) {
2999 add_route_dialog = new AddRouteDialog (_session);
3000 if (float_window) {
3001 add_route_dialog->set_transient_for (*float_window);
3005 if (add_route_dialog->is_visible()) {
3006 /* we're already doing this */
3007 return;
3010 ResponseType r = (ResponseType) add_route_dialog->run ();
3012 add_route_dialog->hide();
3014 switch (r) {
3015 case RESPONSE_ACCEPT:
3016 break;
3017 default:
3018 return;
3019 break;
3022 if ((count = add_route_dialog->count()) <= 0) {
3023 return;
3026 string template_path = add_route_dialog->track_template();
3028 if (!template_path.empty()) {
3029 _session->new_route_from_template (count, template_path);
3030 return;
3033 uint32_t input_chan = add_route_dialog->channels ();
3034 uint32_t output_chan;
3035 string name_template = add_route_dialog->name_template ();
3036 bool track = add_route_dialog->track ();
3037 bool aux = !track && add_route_dialog->aux();
3038 RouteGroup* route_group = add_route_dialog->route_group ();
3040 AutoConnectOption oac = Config->get_output_auto_connect();
3042 if (oac & AutoConnectMaster) {
3043 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3044 } else {
3045 output_chan = input_chan;
3048 /* XXX do something with name template */
3050 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3051 if (track) {
3052 session_add_midi_track (route_group, count);
3053 } else {
3054 MessageDialog msg (*editor,
3055 _("Sorry, MIDI Busses are not supported at this time."));
3056 msg.run ();
3057 //session_add_midi_bus();
3059 } else {
3060 if (track) {
3061 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3062 } else {
3063 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3068 XMLNode*
3069 ARDOUR_UI::mixer_settings () const
3071 XMLNode* node = 0;
3073 if (_session) {
3074 node = _session->instant_xml(X_("Mixer"));
3075 } else {
3076 node = Config->instant_xml(X_("Mixer"));
3079 if (!node) {
3080 node = new XMLNode (X_("Mixer"));
3083 return node;
3086 XMLNode*
3087 ARDOUR_UI::editor_settings () const
3089 XMLNode* node = 0;
3091 if (_session) {
3092 node = _session->instant_xml(X_("Editor"));
3093 } else {
3094 node = Config->instant_xml(X_("Editor"));
3097 if (!node) {
3098 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3099 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3103 if (!node) {
3104 node = new XMLNode (X_("Editor"));
3107 return node;
3110 XMLNode*
3111 ARDOUR_UI::keyboard_settings () const
3113 XMLNode* node = 0;
3115 node = Config->extra_xml(X_("Keyboard"));
3117 if (!node) {
3118 node = new XMLNode (X_("Keyboard"));
3120 return node;
3123 void
3124 ARDOUR_UI::create_xrun_marker(nframes_t where)
3126 editor->mouse_add_new_marker (where, false, true);
3129 void
3130 ARDOUR_UI::halt_on_xrun_message ()
3132 MessageDialog msg (*editor,
3133 _("Recording was stopped because your system could not keep up."));
3134 msg.run ();
3137 void
3138 ARDOUR_UI::xrun_handler(nframes_t where)
3140 if (!_session) {
3141 return;
3144 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3146 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3147 create_xrun_marker(where);
3150 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3151 halt_on_xrun_message ();
3155 void
3156 ARDOUR_UI::disk_overrun_handler ()
3158 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3160 if (!have_disk_speed_dialog_displayed) {
3161 have_disk_speed_dialog_displayed = true;
3162 MessageDialog* msg = new MessageDialog (*editor, _("\
3163 The disk system on your computer\n\
3164 was not able to keep up with Ardour.\n\
3166 Specifically, it failed to write data to disk\n\
3167 quickly enough to keep up with recording.\n"));
3168 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3169 msg->show ();
3173 void
3174 ARDOUR_UI::disk_underrun_handler ()
3176 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3178 if (!have_disk_speed_dialog_displayed) {
3179 have_disk_speed_dialog_displayed = true;
3180 MessageDialog* msg = new MessageDialog (*editor,
3181 _("The disk system on your computer\n\
3182 was not able to keep up with Ardour.\n\
3184 Specifically, it failed to read data from disk\n\
3185 quickly enough to keep up with playback.\n"));
3186 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3187 msg->show ();
3191 void
3192 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3194 have_disk_speed_dialog_displayed = false;
3195 delete msg;
3198 void
3199 ARDOUR_UI::session_dialog (std::string msg)
3201 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3203 MessageDialog* d;
3205 if (editor) {
3206 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3207 } else {
3208 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3211 d->show_all ();
3212 d->run ();
3213 delete d;
3217 ARDOUR_UI::pending_state_dialog ()
3219 HBox* hbox = new HBox();
3220 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3221 ArdourDialog dialog (_("Crash Recovery"), true);
3222 Label message (_("\
3223 This session appears to have been in\n\
3224 middle of recording when ardour or\n\
3225 the computer was shutdown.\n\
3227 Ardour can recover any captured audio for\n\
3228 you, or it can ignore it. Please decide\n\
3229 what you would like to do.\n"));
3230 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3231 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3232 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3233 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3234 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3235 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3236 dialog.set_default_response (RESPONSE_ACCEPT);
3237 dialog.set_position (WIN_POS_CENTER);
3238 message.show();
3239 image->show();
3240 hbox->show();
3242 switch (dialog.run ()) {
3243 case RESPONSE_ACCEPT:
3244 return 1;
3245 default:
3246 return 0;
3251 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3253 HBox* hbox = new HBox();
3254 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3255 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3256 Label message (string_compose (_("\
3257 This session was created with a sample rate of %1 Hz\n\
3259 The audioengine is currently running at %2 Hz\n"), desired, actual));
3261 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3262 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3263 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3264 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3265 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3266 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3267 dialog.set_default_response (RESPONSE_ACCEPT);
3268 dialog.set_position (WIN_POS_CENTER);
3269 message.show();
3270 image->show();
3271 hbox->show();
3273 switch (dialog.run ()) {
3274 case RESPONSE_ACCEPT:
3275 return 0;
3276 default:
3277 return 1;
3282 void
3283 ARDOUR_UI::disconnect_from_jack ()
3285 if (engine) {
3286 if( engine->disconnect_from_jack ()) {
3287 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3288 msg.run ();
3291 update_sample_rate (0);
3295 void
3296 ARDOUR_UI::reconnect_to_jack ()
3298 if (engine) {
3299 if (engine->reconnect_to_jack ()) {
3300 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3301 msg.run ();
3304 update_sample_rate (0);
3308 void
3309 ARDOUR_UI::use_config ()
3312 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3313 if (node) {
3314 set_transport_controllable_state (*node);
3317 node = Config->extra_xml (X_("UI"));
3319 if (node) {
3320 const XMLProperty* prop = node->property (X_("show-big-clock"));
3321 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
3322 if (act) {
3323 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
3324 tact->set_active (string_is_affirmative (prop->value()));
3329 void
3330 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3332 if (Config->get_primary_clock_delta_edit_cursor()) {
3333 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3334 } else {
3335 primary_clock.set (pos, 0, true);
3338 if (Config->get_secondary_clock_delta_edit_cursor()) {
3339 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3340 } else {
3341 secondary_clock.set (pos);
3344 if (big_clock_window) {
3345 big_clock.set (pos);
3349 void
3350 ARDOUR_UI::record_state_changed ()
3352 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3354 if (!_session || !big_clock_window) {
3355 /* why bother - the clock isn't visible */
3356 return;
3359 Session::RecordState const r = _session->record_status ();
3360 bool const h = _session->have_rec_enabled_track ();
3362 if (r == Session::Recording && h) {
3363 big_clock.set_widget_name ("BigClockRecording");
3364 } else {
3365 big_clock.set_widget_name ("BigClockNonRecording");
3369 bool
3370 ARDOUR_UI::first_idle ()
3372 if (_session) {
3373 _session->allow_auto_play (true);
3376 if (editor) {
3377 editor->first_idle();
3380 Keyboard::set_can_save_keybindings (true);
3381 return false;
3384 void
3385 ARDOUR_UI::store_clock_modes ()
3387 XMLNode* node = new XMLNode(X_("ClockModes"));
3389 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3390 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3393 _session->add_extra_xml (*node);
3394 _session->set_dirty ();
3399 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3400 : Controllable (name), ui (u), type(tp)
3405 void
3406 ARDOUR_UI::TransportControllable::set_value (float val)
3408 if (type == ShuttleControl) {
3409 double fract;
3411 if (val == 0.5f) {
3412 fract = 0.0;
3413 } else {
3414 if (val < 0.5f) {
3415 fract = -((0.5f - val)/0.5f);
3416 } else {
3417 fract = ((val - 0.5f)/0.5f);
3421 ui.set_shuttle_fract (fract);
3422 return;
3425 if (val < 0.5f) {
3426 /* do nothing: these are radio-style actions */
3427 return;
3430 const char *action = 0;
3432 switch (type) {
3433 case Roll:
3434 action = X_("Roll");
3435 break;
3436 case Stop:
3437 action = X_("Stop");
3438 break;
3439 case GotoStart:
3440 action = X_("Goto Start");
3441 break;
3442 case GotoEnd:
3443 action = X_("Goto End");
3444 break;
3445 case AutoLoop:
3446 action = X_("Loop");
3447 break;
3448 case PlaySelection:
3449 action = X_("Play Selection");
3450 break;
3451 case RecordEnable:
3452 action = X_("Record");
3453 break;
3454 default:
3455 break;
3458 if (action == 0) {
3459 return;
3462 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3464 if (act) {
3465 act->activate ();
3469 float
3470 ARDOUR_UI::TransportControllable::get_value (void) const
3472 float val = 0.0f;
3474 switch (type) {
3475 case Roll:
3476 break;
3477 case Stop:
3478 break;
3479 case GotoStart:
3480 break;
3481 case GotoEnd:
3482 break;
3483 case AutoLoop:
3484 break;
3485 case PlaySelection:
3486 break;
3487 case RecordEnable:
3488 break;
3489 case ShuttleControl:
3490 break;
3491 default:
3492 break;
3495 return val;
3498 void
3499 ARDOUR_UI::TransportControllable::set_id (const string& str)
3501 _id = str;
3504 void
3505 ARDOUR_UI::setup_profile ()
3507 if (gdk_screen_width() < 1200) {
3508 Profile->set_small_screen ();
3512 if (getenv ("ARDOUR_SAE")) {
3513 Profile->set_sae ();
3514 Profile->set_single_package ();