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
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/callback.h"
59 #include "ardour/profile.h"
60 #include "ardour/session_directory.h"
61 #include "ardour/session_route.h"
62 #include "ardour/session_state_utils.h"
63 #include "ardour/session_utils.h"
64 #include "ardour/port.h"
65 #include "ardour/audioengine.h"
66 #include "ardour/playlist.h"
67 #include "ardour/utils.h"
68 #include "ardour/audio_diskstream.h"
69 #include "ardour/audiofilesource.h"
70 #include "ardour/recent_sessions.h"
71 #include "ardour/port.h"
72 #include "ardour/audio_track.h"
73 #include "ardour/midi_track.h"
74 #include "ardour/filesystem_paths.h"
75 #include "ardour/filename_extensions.h"
77 typedef uint64_t microseconds_t;
80 #include "ardour_ui.h"
81 #include "public_editor.h"
82 #include "audio_clock.h"
87 #include "add_route_dialog.h"
91 #include "gui_thread.h"
92 #include "theme_manager.h"
93 #include "bundle_manager.h"
94 #include "session_metadata_dialog.h"
95 #include "gain_meter.h"
96 #include "route_time_axis.h"
98 #include "engine_dialog.h"
99 #include "processor_box.h"
100 #include "time_axis_view_item.h"
104 using namespace ARDOUR;
106 using namespace Gtkmm2ext;
109 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
110 UIConfiguration *ARDOUR_UI::ui_config = 0;
112 sigc::signal<void,bool> ARDOUR_UI::Blink;
113 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
114 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
115 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
117 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
119 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
121 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
122 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
123 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
124 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
128 preroll_button (_("pre\nroll")),
129 postroll_button (_("post\nroll")),
133 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
137 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
138 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
139 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
140 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
141 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
142 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
143 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
144 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
145 shuttle_controller_binding_proxy (shuttle_controllable),
147 roll_button (roll_controllable),
148 stop_button (stop_controllable),
149 goto_start_button (goto_start_controllable),
150 goto_end_button (goto_end_controllable),
151 auto_loop_button (auto_loop_controllable),
152 play_selection_button (play_selection_controllable),
153 rec_button (rec_controllable),
155 shuttle_units_button (_("% ")),
157 punch_in_button (_("Punch In")),
158 punch_out_button (_("Punch Out")),
159 auto_return_button (_("Auto Return")),
160 auto_play_button (_("Auto Play")),
161 auto_input_button (_("Auto Input")),
162 click_button (_("Click")),
163 time_master_button (_("time\nmaster")),
165 auditioning_alert_button (_("AUDITION")),
166 solo_alert_button (_("SOLO")),
168 error_log_button (_("Errors"))
171 using namespace Gtk::Menu_Helpers;
177 // _auto_display_errors = false;
179 * This was commented out as it wasn't defined
180 * in A3 IIRC. If this is not needed it should
181 * be completely removed.
189 if (theArdourUI == 0) {
193 ui_config = new UIConfiguration();
194 theme_manager = new ThemeManager();
200 _session_is_new = false;
201 big_clock_window = 0;
202 big_clock_height = 0;
203 big_clock_resize_in_progress = false;
204 session_selector_window = 0;
205 last_key_press_time = 0;
206 _will_create_new_session_automatically = false;
207 add_route_dialog = 0;
209 rc_option_editor = 0;
210 session_option_editor = 0;
212 open_session_selector = 0;
213 have_configure_timeout = false;
214 have_disk_speed_dialog_displayed = false;
215 session_loaded = false;
216 last_speed_displayed = -1.0f;
217 ignore_dual_punch = false;
218 _mixer_on_top = false;
219 original_big_clock_width = -1;
220 original_big_clock_height = -1;
221 original_big_clock_font_size = 0;
223 roll_button.unset_flags (Gtk::CAN_FOCUS);
224 stop_button.unset_flags (Gtk::CAN_FOCUS);
225 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
226 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
227 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
228 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
229 rec_button.unset_flags (Gtk::CAN_FOCUS);
231 last_configure_time= 0;
233 shuttle_grabbed = false;
235 shuttle_max_speed = 8.0f;
237 shuttle_style_menu = 0;
238 shuttle_unit_menu = 0;
240 // We do not have jack linked in yet so;
242 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
244 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
245 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
247 /* handle dialog requests */
249 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
251 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
253 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
255 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
257 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
259 /* lets get this party started */
262 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
263 throw failed_constructor ();
266 setup_gtk_ardour_enums ();
269 GainMeter::setup_slider_pix ();
270 RouteTimeAxisView::setup_slider_pix ();
271 SendProcessorEntry::setup_slider_pix ();
272 SessionEvent::create_per_thread_pool ("GUI", 512);
274 } catch (failed_constructor& err) {
275 error << _("could not initialize Ardour.") << endmsg;
280 /* we like keyboards */
282 keyboard = new ArdourKeyboard(*this);
284 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
286 keyboard->set_state (*node, Stateful::loading_state_version);
291 TimeAxisViewItem::set_constant_heights ();
293 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
294 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
299 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
301 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
304 _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 ();
322 switch (_startup->response()) {
331 ARDOUR_UI::create_engine ()
333 // this gets called every time by new_session()
339 loading_message (_("Starting audio engine"));
342 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
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);
363 ARDOUR_UI::post_engine ()
365 /* Things to be done once we create the AudioEngine
368 ARDOUR::init_post_engine ();
370 ActionManager::init ();
373 if (setup_windows ()) {
374 throw failed_constructor ();
377 check_memory_locking();
379 /* this is the first point at which all the keybindings are available */
381 if (ARDOUR_COMMAND_LINE::show_key_actions) {
382 vector<string> names;
383 vector<string> paths;
385 vector<AccelKey> bindings;
387 ActionManager::get_all_actions (names, paths, keys, bindings);
389 vector<string>::iterator n;
390 vector<string>::iterator k;
391 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
392 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
398 blink_timeout_tag = -1;
400 /* this being a GUI and all, we want peakfiles */
402 AudioFileSource::set_build_peakfiles (true);
403 AudioFileSource::set_build_missing_peakfiles (true);
405 /* set default clock modes */
407 if (Profile->get_sae()) {
408 primary_clock.set_mode (AudioClock::BBT);
409 secondary_clock.set_mode (AudioClock::MinSec);
411 primary_clock.set_mode (AudioClock::Timecode);
412 secondary_clock.set_mode (AudioClock::BBT);
415 /* start the time-of-day-clock */
418 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
419 update_wall_clock ();
420 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
423 update_disk_space ();
425 update_sample_rate (engine->frame_rate());
427 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
428 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
429 Config->map_parameters (pc);
431 /* now start and maybe save state */
433 if (do_engine_start () == 0) {
434 if (_session && _session_is_new) {
435 /* we need to retain initial visual
436 settings for a new session
438 _session->save_state ("");
443 ARDOUR_UI::~ARDOUR_UI ()
448 delete add_route_dialog;
452 ARDOUR_UI::pop_back_splash ()
454 if (Splash::instance()) {
455 // Splash::instance()->pop_back();
456 Splash::instance()->hide ();
461 ARDOUR_UI::configure_timeout ()
463 if (last_configure_time == 0) {
464 /* no configure events yet */
468 /* force a gap of 0.5 seconds since the last configure event
471 if (get_microseconds() - last_configure_time < 500000) {
474 have_configure_timeout = false;
475 cerr << "config event-driven save\n";
476 save_ardour_state ();
482 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
484 if (have_configure_timeout) {
485 last_configure_time = get_microseconds();
487 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
488 have_configure_timeout = true;
495 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
497 const XMLProperty* prop;
499 if ((prop = node.property ("roll")) != 0) {
500 roll_controllable->set_id (prop->value());
502 if ((prop = node.property ("stop")) != 0) {
503 stop_controllable->set_id (prop->value());
505 if ((prop = node.property ("goto-start")) != 0) {
506 goto_start_controllable->set_id (prop->value());
508 if ((prop = node.property ("goto-end")) != 0) {
509 goto_end_controllable->set_id (prop->value());
511 if ((prop = node.property ("auto-loop")) != 0) {
512 auto_loop_controllable->set_id (prop->value());
514 if ((prop = node.property ("play-selection")) != 0) {
515 play_selection_controllable->set_id (prop->value());
517 if ((prop = node.property ("rec")) != 0) {
518 rec_controllable->set_id (prop->value());
520 if ((prop = node.property ("shuttle")) != 0) {
521 shuttle_controllable->set_id (prop->value());
526 ARDOUR_UI::get_transport_controllable_state ()
528 XMLNode* node = new XMLNode(X_("TransportControllables"));
531 roll_controllable->id().print (buf, sizeof (buf));
532 node->add_property (X_("roll"), buf);
533 stop_controllable->id().print (buf, sizeof (buf));
534 node->add_property (X_("stop"), buf);
535 goto_start_controllable->id().print (buf, sizeof (buf));
536 node->add_property (X_("goto_start"), buf);
537 goto_end_controllable->id().print (buf, sizeof (buf));
538 node->add_property (X_("goto_end"), buf);
539 auto_loop_controllable->id().print (buf, sizeof (buf));
540 node->add_property (X_("auto_loop"), buf);
541 play_selection_controllable->id().print (buf, sizeof (buf));
542 node->add_property (X_("play_selection"), buf);
543 rec_controllable->id().print (buf, sizeof (buf));
544 node->add_property (X_("rec"), buf);
545 shuttle_controllable->id().print (buf, sizeof (buf));
546 node->add_property (X_("shuttle"), buf);
553 ARDOUR_UI::autosave_session ()
555 if (g_main_depth() > 1) {
556 /* inside a recursive main loop,
557 give up because we may not be able to
563 if (!Config->get_periodic_safety_backups()) {
568 _session->maybe_write_autosave();
575 ARDOUR_UI::update_autosave ()
577 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
579 if (_session && _session->dirty()) {
580 if (_autosave_connection.connected()) {
581 _autosave_connection.disconnect();
584 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
585 Config->get_periodic_safety_backup_interval() * 1000);
588 if (_autosave_connection.connected()) {
589 _autosave_connection.disconnect();
595 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
599 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
601 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
604 MessageDialog win (title,
610 win.set_secondary_text(_("There are several possible reasons:\n\
612 1) You requested audio parameters that are not supported..\n\
613 2) JACK is running as another user.\n\
615 Please consider the possibilities, and perhaps try different parameters."));
617 win.set_secondary_text(_("There are several possible reasons:\n\
619 1) JACK is not running.\n\
620 2) JACK is running as another user, perhaps root.\n\
621 3) There is already another client called \"ardour\".\n\
623 Please consider the possibilities, and perhaps (re)start JACK."));
627 win.set_transient_for (*toplevel);
631 win.add_button (Stock::OK, RESPONSE_CLOSE);
633 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
636 win.set_default_response (RESPONSE_CLOSE);
639 win.set_position (Gtk::WIN_POS_CENTER);
642 /* we just don't care about the result, but we want to block */
648 ARDOUR_UI::startup ()
652 call_the_mothership (VERSIONSTRING);
655 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
661 goto_editor_window ();
663 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
668 ARDOUR_UI::no_memory_warning ()
670 XMLNode node (X_("no-memory-warning"));
671 Config->add_instant_xml (node);
675 ARDOUR_UI::check_memory_locking ()
678 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
682 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
684 if (engine->is_realtime() && memory_warning_node == 0) {
686 struct rlimit limits;
688 long pages, page_size;
690 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
693 ram = (int64_t) pages * (int64_t) page_size;
696 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
700 if (limits.rlim_cur != RLIM_INFINITY) {
702 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
705 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
706 "This might cause %1 to run out of memory before your system "
707 "runs out of memory. \n\n"
708 "You can view the memory limit with 'ulimit -l', "
709 "and it is normally controlled by /etc/security/limits.conf"),
710 PROGRAM_NAME).c_str());
712 VBox* vbox = msg.get_vbox();
714 CheckButton cb (_("Do not show this window again"));
716 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
718 hbox.pack_start (cb, true, false);
719 vbox->pack_start (hbox);
726 editor->ensure_float (msg);
736 ARDOUR_UI::queue_finish ()
738 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
742 ARDOUR_UI::idle_finish ()
745 return false; /* do not call again */
754 if (_session->transport_rolling() && (++tries < 8)) {
755 _session->request_stop (false, true);
759 if (_session->dirty()) {
760 switch (ask_about_saving_session(_("quit"))) {
765 /* use the default name */
766 if (save_state_canfail ("")) {
767 /* failed - don't quit */
768 MessageDialog msg (*editor,
770 Ardour was unable to save your session.\n\n\
771 If you still wish to quit, please use the\n\n\
772 \"Just quit\" option."));
783 second_connection.disconnect ();
784 point_one_second_connection.disconnect ();
785 point_oh_five_second_connection.disconnect ();
786 point_zero_one_second_connection.disconnect();
788 _session->set_clean ();
789 // _session->set_deletion_in_progress ();
790 _session->remove_pending_capture_state ();
795 cerr << "Save before quit\n";
796 save_ardour_state ();
798 ArdourDialog::close_all_dialogs ();
804 ARDOUR_UI::ask_about_saving_session (const string & what)
806 ArdourDialog window (_("Unsaved Session"));
807 Gtk::HBox dhbox; // the hbox for the image and text
808 Gtk::Label prompt_label;
809 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
813 msg = string_compose(_("Don't %1"), what);
814 window.add_button (msg, RESPONSE_REJECT);
815 msg = string_compose(_("Just %1"), what);
816 window.add_button (msg, RESPONSE_APPLY);
817 msg = string_compose(_("Save and %1"), what);
818 window.add_button (msg, RESPONSE_ACCEPT);
820 window.set_default_response (RESPONSE_ACCEPT);
822 Gtk::Button noquit_button (msg);
823 noquit_button.set_name ("EditorGTKButton");
828 if (_session->snap_name() == _session->name()) {
831 type = _("snapshot");
833 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?"),
834 type, _session->snap_name());
836 prompt_label.set_text (prompt);
837 prompt_label.set_name (X_("PrompterLabel"));
838 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
840 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
841 dhbox.set_homogeneous (false);
842 dhbox.pack_start (*dimage, false, false, 5);
843 dhbox.pack_start (prompt_label, true, false, 5);
844 window.get_vbox()->pack_start (dhbox);
846 window.set_name (_("Prompter"));
847 window.set_position (Gtk::WIN_POS_MOUSE);
848 window.set_modal (true);
849 window.set_resizable (false);
855 window.set_keep_above (true);
858 ResponseType r = (ResponseType) window.run();
863 case RESPONSE_ACCEPT: // save and get out of here
865 case RESPONSE_APPLY: // get out of here
875 ARDOUR_UI::every_second ()
878 update_buffer_load ();
879 update_disk_space ();
884 ARDOUR_UI::every_point_one_seconds ()
886 update_speed_display ();
887 RapidScreenUpdate(); /* EMIT_SIGNAL */
892 ARDOUR_UI::every_point_zero_one_seconds ()
894 // august 2007: actual update frequency: 40Hz, not 100Hz
896 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
901 ARDOUR_UI::update_sample_rate (nframes_t)
905 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
907 if (!engine->connected()) {
909 snprintf (buf, sizeof (buf), _("disconnected"));
913 nframes_t rate = engine->frame_rate();
915 if (fmod (rate, 1000.0) != 0.0) {
916 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
917 (float) rate/1000.0f,
918 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
920 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
922 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
926 sample_rate_label.set_text (buf);
930 ARDOUR_UI::update_cpu_load ()
933 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
934 cpu_load_label.set_text (buf);
938 ARDOUR_UI::update_buffer_load ()
944 c = _session->capture_load ();
945 p = _session->playback_load ();
947 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
948 _session->playback_load(), _session->capture_load());
949 buffer_load_label.set_text (buf);
951 buffer_load_label.set_text ("");
956 ARDOUR_UI::count_recenabled_streams (Route& route)
958 Track* track = dynamic_cast<Track*>(&route);
959 if (track && track->record_enabled()) {
960 rec_enabled_streams += track->n_inputs().n_total();
965 ARDOUR_UI::update_disk_space()
971 nframes_t frames = _session->available_capture_duration();
973 nframes_t fr = _session->frame_rate();
975 if (frames == max_frames) {
976 strcpy (buf, _("Disk: 24hrs+"));
978 rec_enabled_streams = 0;
979 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
981 if (rec_enabled_streams) {
982 frames /= rec_enabled_streams;
989 hrs = frames / (fr * 3600);
990 frames -= hrs * fr * 3600;
991 mins = frames / (fr * 60);
992 frames -= mins * fr * 60;
995 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
998 disk_space_label.set_text (buf);
1000 // An attempt to make the disk space label flash red when space has run out.
1002 if (frames < fr * 60 * 5) {
1003 /* disk_space_box.style ("disk_space_label_empty"); */
1005 /* disk_space_box.style ("disk_space_label"); */
1011 ARDOUR_UI::update_wall_clock ()
1018 tm_now = localtime (&now);
1020 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1021 wall_clock_label.set_text (buf);
1027 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1029 session_popup_menu->popup (0, 0);
1034 ARDOUR_UI::redisplay_recent_sessions ()
1036 std::vector<sys::path> session_directories;
1037 RecentSessionsSorter cmp;
1039 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1040 recent_session_model->clear ();
1042 ARDOUR::RecentSessions rs;
1043 ARDOUR::read_recent_sessions (rs);
1046 recent_session_display.set_model (recent_session_model);
1050 // sort them alphabetically
1051 sort (rs.begin(), rs.end(), cmp);
1053 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1054 session_directories.push_back ((*i).second);
1057 for (vector<sys::path>::const_iterator i = session_directories.begin();
1058 i != session_directories.end(); ++i)
1060 std::vector<sys::path> state_file_paths;
1062 // now get available states for this session
1064 get_state_files_in_directory (*i, state_file_paths);
1066 vector<string*>* states;
1067 vector<const gchar*> item;
1068 string fullpath = (*i).to_string();
1070 /* remove any trailing / */
1072 if (fullpath[fullpath.length()-1] == '/') {
1073 fullpath = fullpath.substr (0, fullpath.length()-1);
1076 /* check whether session still exists */
1077 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1078 /* session doesn't exist */
1079 cerr << "skipping non-existent session " << fullpath << endl;
1083 /* now get available states for this session */
1085 if ((states = Session::possible_states (fullpath)) == 0) {
1086 /* no state file? */
1090 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1092 Gtk::TreeModel::Row row = *(recent_session_model->append());
1094 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1095 row[recent_session_columns.fullpath] = fullpath;
1097 if (state_file_names.size() > 1) {
1101 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1102 i2 != state_file_names.end(); ++i2)
1105 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1107 child_row[recent_session_columns.visible_name] = *i2;
1108 child_row[recent_session_columns.fullpath] = fullpath;
1113 recent_session_display.set_model (recent_session_model);
1117 ARDOUR_UI::build_session_selector ()
1119 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1121 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1123 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1124 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1125 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1126 recent_session_model = TreeStore::create (recent_session_columns);
1127 recent_session_display.set_model (recent_session_model);
1128 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1129 recent_session_display.set_headers_visible (false);
1130 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1131 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1133 scroller->add (recent_session_display);
1134 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1136 session_selector_window->set_name ("SessionSelectorWindow");
1137 session_selector_window->set_size_request (200, 400);
1138 session_selector_window->get_vbox()->pack_start (*scroller);
1140 recent_session_display.show();
1142 //session_selector_window->get_vbox()->show();
1146 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1148 session_selector_window->response (RESPONSE_ACCEPT);
1152 ARDOUR_UI::open_recent_session ()
1154 bool can_return = (_session != 0);
1156 if (session_selector_window == 0) {
1157 build_session_selector ();
1160 redisplay_recent_sessions ();
1164 session_selector_window->set_position (WIN_POS_MOUSE);
1166 ResponseType r = (ResponseType) session_selector_window->run ();
1169 case RESPONSE_ACCEPT:
1173 session_selector_window->hide();
1180 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1184 session_selector_window->hide();
1186 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1188 if (i == recent_session_model->children().end()) {
1192 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1193 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1195 _session_is_new = false;
1197 if (load_session (path, state) == 0) {
1206 ARDOUR_UI::check_audioengine ()
1209 if (!engine->connected()) {
1210 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1211 "You cannot open or close sessions in this condition"),
1224 ARDOUR_UI::open_session ()
1226 if (!check_audioengine()) {
1231 /* popup selector window */
1233 if (open_session_selector == 0) {
1235 /* ardour sessions are folders */
1237 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1238 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1239 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1240 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1242 FileFilter session_filter;
1243 session_filter.add_pattern ("*.ardour");
1244 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1245 open_session_selector->add_filter (session_filter);
1246 open_session_selector->set_filter (session_filter);
1249 int response = open_session_selector->run();
1250 open_session_selector->hide ();
1253 case RESPONSE_ACCEPT:
1256 open_session_selector->hide();
1260 open_session_selector->hide();
1261 string session_path = open_session_selector->get_filename();
1265 if (session_path.length() > 0) {
1266 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1267 _session_is_new = isnew;
1268 load_session (path, name);
1275 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1277 list<boost::shared_ptr<MidiTrack> > tracks;
1279 if (_session == 0) {
1280 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1287 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1289 if (tracks.size() != how_many) {
1290 if (how_many == 1) {
1291 error << _("could not create a new midi track") << endmsg;
1293 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1297 if ((route = _session->new_midi_route ()) == 0) {
1298 error << _("could not create new midi bus") << endmsg;
1304 MessageDialog msg (*editor,
1305 _("There are insufficient JACK ports available\n\
1306 to create a new track or bus.\n\
1307 You should save Ardour, exit and\n\
1308 restart JACK with more ports."));
1315 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)
1317 list<boost::shared_ptr<AudioTrack> > tracks;
1320 if (_session == 0) {
1321 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1327 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1329 if (tracks.size() != how_many) {
1330 if (how_many == 1) {
1331 error << _("could not create a new audio track") << endmsg;
1333 error << string_compose (_("could only create %1 of %2 new audio %3"),
1334 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1340 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1342 if (routes.size() != how_many) {
1343 if (how_many == 1) {
1344 error << _("could not create a new audio track") << endmsg;
1346 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1353 MessageDialog msg (*editor,
1354 _("There are insufficient JACK ports available\n\
1355 to create a new track or bus.\n\
1356 You should save Ardour, exit and\n\
1357 restart JACK with more ports."));
1364 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1366 nframes_t _preroll = 0;
1369 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1370 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1372 if (new_position > _preroll) {
1373 new_position -= _preroll;
1378 _session->request_locate (new_position);
1383 ARDOUR_UI::transport_goto_start ()
1386 _session->goto_start();
1388 /* force displayed area in editor to start no matter
1389 what "follow playhead" setting is.
1393 editor->center_screen (_session->current_start_frame ());
1399 ARDOUR_UI::transport_goto_zero ()
1402 _session->request_locate (0);
1404 /* force displayed area in editor to start no matter
1405 what "follow playhead" setting is.
1409 editor->reset_x_origin (0);
1415 ARDOUR_UI::transport_goto_wallclock ()
1417 if (_session && editor) {
1424 localtime_r (&now, &tmnow);
1426 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1427 frames += tmnow.tm_min * (60 * _session->frame_rate());
1428 frames += tmnow.tm_sec * _session->frame_rate();
1430 _session->request_locate (frames);
1432 /* force displayed area in editor to start no matter
1433 what "follow playhead" setting is.
1437 editor->center_screen (frames);
1443 ARDOUR_UI::transport_goto_end ()
1446 nframes_t const frame = _session->current_end_frame();
1447 _session->request_locate (frame);
1449 /* force displayed area in editor to start no matter
1450 what "follow playhead" setting is.
1454 editor->center_screen (frame);
1460 ARDOUR_UI::transport_stop ()
1466 if (_session->is_auditioning()) {
1467 _session->cancel_audition ();
1471 _session->request_stop (false, true);
1475 ARDOUR_UI::transport_stop_and_forget_capture ()
1478 _session->request_stop (true, true);
1483 ARDOUR_UI::remove_last_capture()
1486 editor->remove_last_capture();
1491 ARDOUR_UI::transport_record (bool roll)
1495 switch (_session->record_status()) {
1496 case Session::Disabled:
1497 if (_session->ntracks() == 0) {
1498 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1502 _session->maybe_enable_record ();
1507 case Session::Recording:
1509 _session->request_stop();
1511 _session->disable_record (false, true);
1515 case Session::Enabled:
1516 _session->disable_record (false, true);
1519 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1523 ARDOUR_UI::transport_roll ()
1529 if (_session->is_auditioning()) {
1533 if (_session->config.get_external_sync()) {
1534 switch (_session->config.get_sync_source()) {
1538 /* transport controlled by the master */
1543 bool rolling = _session->transport_rolling();
1545 if (_session->get_play_loop()) {
1546 /* XXX it is not possible to just leave seamless loop and keep
1547 playing at present (nov 4th 2009)
1549 if (!Config->get_seamless_loop()) {
1550 _session->request_play_loop (false, true);
1552 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1553 /* stop playing a range if we currently are */
1554 _session->request_play_range (0, true);
1557 if (join_play_range_button.get_active()) {
1558 _session->request_play_range (&editor->get_selection().time, true);
1562 _session->request_transport_speed (1.0f);
1567 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1574 if (_session->is_auditioning()) {
1575 _session->cancel_audition ();
1579 if (_session->config.get_external_sync()) {
1580 switch (_session->config.get_sync_source()) {
1584 /* transport controlled by the master */
1589 bool rolling = _session->transport_rolling();
1590 bool affect_transport = true;
1592 if (rolling && roll_out_of_bounded_mode) {
1593 /* drop out of loop/range playback but leave transport rolling */
1594 if (_session->get_play_loop()) {
1595 if (Config->get_seamless_loop()) {
1596 /* the disk buffers contain copies of the loop - we can't
1597 just keep playing, so stop the transport. the user
1598 can restart as they wish.
1600 affect_transport = true;
1602 /* disk buffers are normal, so we can keep playing */
1603 affect_transport = false;
1605 _session->request_play_loop (false, true);
1606 } else if (_session->get_play_range ()) {
1607 affect_transport = false;
1608 _session->request_play_range (0, true);
1612 if (affect_transport) {
1614 _session->request_stop (with_abort, true);
1616 if (join_play_range_button.get_active()) {
1617 _session->request_play_range (&editor->get_selection().time, true);
1620 _session->request_transport_speed (1.0f);
1626 ARDOUR_UI::toggle_session_auto_loop ()
1629 if (_session->get_play_loop()) {
1630 if (_session->transport_rolling()) {
1631 Location * looploc = _session->locations()->auto_loop_location();
1633 _session->request_locate (looploc->start(), true);
1636 _session->request_play_loop (false);
1639 Location * looploc = _session->locations()->auto_loop_location();
1641 _session->request_play_loop (true);
1648 ARDOUR_UI::transport_play_selection ()
1654 editor->play_selection ();
1658 ARDOUR_UI::transport_rewind (int option)
1660 float current_transport_speed;
1663 current_transport_speed = _session->transport_speed();
1665 if (current_transport_speed >= 0.0f) {
1668 _session->request_transport_speed (-1.0f);
1671 _session->request_transport_speed (-4.0f);
1674 _session->request_transport_speed (-0.5f);
1679 _session->request_transport_speed (current_transport_speed * 1.5f);
1685 ARDOUR_UI::transport_forward (int option)
1687 float current_transport_speed;
1690 current_transport_speed = _session->transport_speed();
1692 if (current_transport_speed <= 0.0f) {
1695 _session->request_transport_speed (1.0f);
1698 _session->request_transport_speed (4.0f);
1701 _session->request_transport_speed (0.5f);
1706 _session->request_transport_speed (current_transport_speed * 1.5f);
1713 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1715 if (_session == 0) {
1719 boost::shared_ptr<Route> r;
1721 if ((r = _session->route_by_remote_id (rid)) != 0) {
1725 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1726 t->set_record_enabled (!t->record_enabled(), this);
1729 if (_session == 0) {
1735 ARDOUR_UI::map_transport_state ()
1737 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1740 auto_loop_button.set_visual_state (0);
1741 play_selection_button.set_visual_state (0);
1742 roll_button.set_visual_state (0);
1743 stop_button.set_visual_state (1);
1747 float sp = _session->transport_speed();
1750 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1751 shuttle_box.queue_draw ();
1752 } else if (sp == 0.0f) {
1754 shuttle_box.queue_draw ();
1755 update_disk_space ();
1762 if (_session->get_play_range()) {
1764 play_selection_button.set_visual_state (1);
1765 roll_button.set_visual_state (0);
1766 auto_loop_button.set_visual_state (0);
1768 } else if (_session->get_play_loop ()) {
1770 auto_loop_button.set_visual_state (1);
1771 play_selection_button.set_visual_state (0);
1772 roll_button.set_visual_state (0);
1776 roll_button.set_visual_state (1);
1777 play_selection_button.set_visual_state (0);
1778 auto_loop_button.set_visual_state (0);
1781 if (join_play_range_button.get_active()) {
1782 /* light up both roll and play-selection if they are joined */
1783 roll_button.set_visual_state (1);
1784 play_selection_button.set_visual_state (1);
1787 stop_button.set_visual_state (0);
1791 stop_button.set_visual_state (1);
1792 roll_button.set_visual_state (0);
1793 play_selection_button.set_visual_state (0);
1794 auto_loop_button.set_visual_state (0);
1799 ARDOUR_UI::engine_stopped ()
1801 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1802 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1803 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1807 ARDOUR_UI::engine_running ()
1809 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1810 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1811 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1813 Glib::RefPtr<Action> action;
1814 const char* action_name = 0;
1816 switch (engine->frames_per_cycle()) {
1818 action_name = X_("JACKLatency32");
1821 action_name = X_("JACKLatency64");
1824 action_name = X_("JACKLatency128");
1827 action_name = X_("JACKLatency512");
1830 action_name = X_("JACKLatency1024");
1833 action_name = X_("JACKLatency2048");
1836 action_name = X_("JACKLatency4096");
1839 action_name = X_("JACKLatency8192");
1842 /* XXX can we do anything useful ? */
1848 action = ActionManager::get_action (X_("JACK"), action_name);
1851 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1852 ract->set_active ();
1858 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1860 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1861 /* we can't rely on the original string continuing to exist when we are called
1862 again in the GUI thread, so make a copy and note that we need to
1865 char *copy = strdup (reason);
1866 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1870 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1871 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1873 update_sample_rate (0);
1877 /* if the reason is a non-empty string, it means that the backend was shutdown
1878 rather than just Ardour.
1881 if (strlen (reason)) {
1882 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1885 JACK has either been shutdown or it\n\
1886 disconnected Ardour because Ardour\n\
1887 was not fast enough. Try to restart\n\
1888 JACK, reconnect and save the session.");
1891 MessageDialog msg (*editor, msgstr);
1896 free ((char*) reason);
1901 ARDOUR_UI::do_engine_start ()
1909 error << _("Unable to start the session running")
1919 ARDOUR_UI::setup_theme ()
1921 theme_manager->setup_theme();
1925 ARDOUR_UI::update_clocks ()
1927 if (!editor || !editor->dragging_playhead()) {
1928 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1933 ARDOUR_UI::start_clocking ()
1935 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1939 ARDOUR_UI::stop_clocking ()
1941 clock_signal_connection.disconnect ();
1945 ARDOUR_UI::toggle_clocking ()
1948 if (clock_button.get_active()) {
1957 ARDOUR_UI::_blink (void *arg)
1960 ((ARDOUR_UI *) arg)->blink ();
1967 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1971 ARDOUR_UI::start_blinking ()
1973 /* Start the blink signal. Everybody with a blinking widget
1974 uses Blink to drive the widget's state.
1977 if (blink_timeout_tag < 0) {
1979 blink_timeout_tag = g_timeout_add (240, _blink, this);
1984 ARDOUR_UI::stop_blinking ()
1986 if (blink_timeout_tag >= 0) {
1987 g_source_remove (blink_timeout_tag);
1988 blink_timeout_tag = -1;
1993 /** Ask the user for the name of a new shapshot and then take it.
1997 ARDOUR_UI::snapshot_session (bool switch_to_it)
1999 ArdourPrompter prompter (true);
2002 prompter.set_name ("Prompter");
2003 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2004 prompter.set_title (_("Take Snapshot"));
2005 prompter.set_title (_("Take Snapshot"));
2006 prompter.set_prompt (_("Name of new snapshot"));
2008 if (!switch_to_it) {
2011 struct tm local_time;
2014 localtime_r (&n, &local_time);
2015 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2016 prompter.set_initial_text (timebuf);
2020 switch (prompter.run()) {
2021 case RESPONSE_ACCEPT:
2023 prompter.get_result (snapname);
2025 bool do_save = (snapname.length() != 0);
2028 if (snapname.find ('/') != string::npos) {
2029 MessageDialog msg (_("To ensure compatibility with various systems\n"
2030 "snapshot names may not contain a '/' character"));
2034 if (snapname.find ('\\') != string::npos) {
2035 MessageDialog msg (_("To ensure compatibility with various systems\n"
2036 "snapshot names may not contain a '\\' character"));
2042 vector<sys::path> p;
2043 get_state_files_in_directory (_session->session_directory().root_path(), p);
2044 vector<string> n = get_file_names_no_extension (p);
2045 if (find (n.begin(), n.end(), snapname) != n.end()) {
2047 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2048 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2049 confirm.get_vbox()->pack_start (m, true, true);
2050 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2051 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2052 confirm.show_all ();
2053 switch (confirm.run()) {
2054 case RESPONSE_CANCEL:
2060 save_state (snapname, switch_to_it);
2071 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2073 save_state_canfail (name, switch_to_it);
2077 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2082 if (name.length() == 0) {
2083 name = _session->snap_name();
2086 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2090 cerr << "SS canfail\n";
2091 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2096 ARDOUR_UI::primary_clock_value_changed ()
2099 _session->request_locate (primary_clock.current_time ());
2104 ARDOUR_UI::big_clock_value_changed ()
2107 _session->request_locate (big_clock.current_time ());
2112 ARDOUR_UI::secondary_clock_value_changed ()
2115 _session->request_locate (secondary_clock.current_time ());
2120 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2122 if (_session == 0) {
2126 if (_session->step_editing()) {
2130 Session::RecordState const r = _session->record_status ();
2131 bool const h = _session->have_rec_enabled_track ();
2133 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2135 rec_button.set_visual_state (2);
2137 rec_button.set_visual_state (0);
2139 } else if (r == Session::Recording && h) {
2140 rec_button.set_visual_state (1);
2142 rec_button.set_visual_state (0);
2147 ARDOUR_UI::save_template ()
2149 ArdourPrompter prompter (true);
2152 if (!check_audioengine()) {
2156 prompter.set_name (X_("Prompter"));
2157 prompter.set_title (_("Save Mix Template"));
2158 prompter.set_prompt (_("Name for mix template:"));
2159 prompter.set_initial_text(_session->name() + _("-template"));
2160 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2162 switch (prompter.run()) {
2163 case RESPONSE_ACCEPT:
2164 prompter.get_result (name);
2166 if (name.length()) {
2167 _session->save_template (name);
2177 ARDOUR_UI::edit_metadata ()
2179 SessionMetadataEditor dialog;
2180 dialog.set_session (_session);
2181 editor->ensure_float (dialog);
2186 ARDOUR_UI::import_metadata ()
2188 SessionMetadataImporter dialog;
2189 dialog.set_session (_session);
2190 editor->ensure_float (dialog);
2195 ARDOUR_UI::fontconfig_dialog ()
2198 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2199 may not and it can take a while to build it. Warn them.
2202 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2204 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2205 MessageDialog msg (*_startup,
2206 _("Welcome to Ardour.\n\n"
2207 "The program will take a bit longer to start up\n"
2208 "while the system fonts are checked.\n\n"
2209 "This will only be done once, and you will\n"
2210 "not see this message again\n"),
2223 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2225 existing_session = false;
2227 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2228 session_path = cmdline_path;
2229 existing_session = true;
2230 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2231 session_path = Glib::path_get_dirname (string (cmdline_path));
2232 existing_session = true;
2234 /* it doesn't exist, assume the best */
2235 session_path = Glib::path_get_dirname (string (cmdline_path));
2238 session_name = basename_nosuffix (string (cmdline_path));
2242 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2244 /* when this is called, the backend audio system must be running */
2246 /* the main idea here is to deal with the fact that a cmdline argument for the session
2247 can be interpreted in different ways - it could be a directory or a file, and before
2248 we load, we need to know both the session directory and the snapshot (statefile) within it
2249 that we are supposed to use.
2252 if (session_name.length() == 0 || session_path.length() == 0) {
2256 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2258 Glib::ustring predicted_session_file;
2260 predicted_session_file = session_path;
2261 predicted_session_file += '/';
2262 predicted_session_file += session_name;
2263 predicted_session_file += ARDOUR::statefile_suffix;
2265 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2266 existing_session = true;
2269 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2271 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2272 /* existing .ardour file */
2273 existing_session = true;
2277 existing_session = false;
2280 /* lets just try to load it */
2282 if (create_engine ()) {
2283 backend_audio_error (false, _startup);
2287 return load_session (session_path, session_name);
2291 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2293 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2295 MessageDialog msg (str,
2297 Gtk::MESSAGE_WARNING,
2298 Gtk::BUTTONS_YES_NO,
2302 msg.set_name (X_("OpenExistingDialog"));
2303 msg.set_title (_("Open Existing Session"));
2304 msg.set_wmclass (X_("existing_session"), "Ardour");
2305 msg.set_position (Gtk::WIN_POS_MOUSE);
2308 switch (msg.run()) {
2317 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2319 BusProfile bus_profile;
2321 if (Profile->get_sae()) {
2323 bus_profile.master_out_channels = 2;
2324 bus_profile.input_ac = AutoConnectPhysical;
2325 bus_profile.output_ac = AutoConnectMaster;
2326 bus_profile.requested_physical_in = 0; // use all available
2327 bus_profile.requested_physical_out = 0; // use all available
2331 /* get settings from advanced section of NSD */
2333 if (_startup->create_master_bus()) {
2334 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2336 bus_profile.master_out_channels = 0;
2339 if (_startup->connect_inputs()) {
2340 bus_profile.input_ac = AutoConnectPhysical;
2342 bus_profile.input_ac = AutoConnectOption (0);
2345 /// @todo some minor tweaks.
2347 bus_profile.output_ac = AutoConnectOption (0);
2349 if (_startup->connect_outputs ()) {
2350 if (_startup->connect_outs_to_master()) {
2351 bus_profile.output_ac = AutoConnectMaster;
2352 } else if (_startup->connect_outs_to_physical()) {
2353 bus_profile.output_ac = AutoConnectPhysical;
2357 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2358 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2361 if (build_session (session_path, session_name, bus_profile)) {
2369 ARDOUR_UI::idle_load (const Glib::ustring& path)
2372 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2373 /* /path/to/foo => /path/to/foo, foo */
2374 load_session (path, basename_nosuffix (path));
2376 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2377 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2381 ARDOUR_COMMAND_LINE::session_name = path;
2384 * new_session_dialog doens't exist in A3
2385 * Try to remove all references to it to
2386 * see if it will compile. NOTE: this will
2387 * likely cause a runtime issue is my somewhat
2391 //if (new_session_dialog) {
2394 /* make it break out of Dialog::run() and
2398 //new_session_dialog->response (1);
2404 ARDOUR_UI::end_loading_messages ()
2410 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2413 // splash->message (msg);
2417 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2419 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2421 Glib::ustring session_name;
2422 Glib::ustring session_path;
2423 Glib::ustring template_name;
2425 bool likely_new = false;
2427 if (! load_template.empty()) {
2428 should_be_new = true;
2429 template_name = load_template;
2434 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2436 /* if they named a specific statefile, use it, otherwise they are
2437 just giving a session folder, and we want to use it as is
2438 to find the session.
2441 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2442 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2444 session_path = ARDOUR_COMMAND_LINE::session_name;
2447 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2451 bool const apply = run_startup (should_be_new, load_template);
2453 if (quit_on_cancel) {
2460 /* if we run the startup dialog again, offer more than just "new session" */
2462 should_be_new = false;
2464 session_name = _startup->session_name (likely_new);
2466 /* this shouldn't happen, but we catch it just in case it does */
2468 if (session_name.empty()) {
2471 if (_startup->use_session_template()) {
2472 template_name = _startup->session_template_name();
2473 _session_is_new = true;
2476 if (session_name[0] == '/' ||
2477 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2478 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2480 /* absolute path or cwd-relative path specified for session name: infer session folder
2481 from what was given.
2484 session_path = Glib::path_get_dirname (session_name);
2485 session_name = Glib::path_get_basename (session_name);
2489 session_path = _startup->session_folder();
2493 if (create_engine ()) {
2497 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2501 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2503 if (!ask_about_loading_existing_session (existing)) {
2504 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2509 _session_is_new = false;
2514 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2516 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2520 if (session_name.find ('/') != Glib::ustring::npos) {
2521 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2522 "session names may not contain a '/' character"));
2524 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2528 if (session_name.find ('\\') != Glib::ustring::npos) {
2529 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2530 "session names may not contain a '\\' character"));
2532 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2536 _session_is_new = true;
2539 if (likely_new && template_name.empty()) {
2541 ret = build_session_from_nsd (session_path, session_name);
2545 ret = load_session (session_path, session_name, template_name);
2546 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2547 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2557 ARDOUR_UI::close_session()
2559 if (!check_audioengine()) {
2563 if (unload_session (true)) {
2567 ARDOUR_COMMAND_LINE::session_name = "";
2569 if (get_session_parameters (true, false)) {
2573 goto_editor_window ();
2578 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2580 Session *new_session;
2584 session_loaded = false;
2586 if (!check_audioengine()) {
2590 unload_status = unload_session ();
2592 if (unload_status < 0) {
2594 } else if (unload_status > 0) {
2599 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2602 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2605 /* this one is special */
2607 catch (AudioEngine::PortRegistrationFailure& err) {
2609 MessageDialog msg (err.what(),
2612 Gtk::BUTTONS_CLOSE);
2614 msg.set_title (_("Port Registration Error"));
2615 msg.set_secondary_text (_("Click the Close button to try again."));
2616 msg.set_position (Gtk::WIN_POS_CENTER);
2620 int response = msg.run ();
2625 case RESPONSE_CANCEL:
2635 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2638 Gtk::BUTTONS_CLOSE);
2640 msg.set_title (_("Loading Error"));
2641 msg.set_secondary_text (_("Click the Close button to try again."));
2642 msg.set_position (Gtk::WIN_POS_CENTER);
2646 int response = msg.run ();
2651 case RESPONSE_CANCEL:
2659 set_session (new_session);
2661 session_loaded = true;
2663 goto_editor_window ();
2666 _session->set_clean ();
2677 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2679 Session *new_session;
2682 if (!check_audioengine()) {
2686 session_loaded = false;
2688 x = unload_session ();
2696 _session_is_new = true;
2699 new_session = new Session (*engine, path, snap_name, &bus_profile);
2704 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2710 set_session (new_session);
2712 session_loaded = true;
2714 new_session->save_state(new_session->name());
2723 editor->show_window ();
2734 ARDOUR_UI::launch_chat ()
2737 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2739 open_uri("http://webchat.freenode.net/?channels=ardour");
2744 ARDOUR_UI::show_about ()
2748 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2751 about->set_transient_for(*editor);
2756 ARDOUR_UI::hide_about ()
2759 about->get_window()->set_cursor ();
2765 ARDOUR_UI::about_signal_response (int /*response*/)
2771 ARDOUR_UI::show_splash ()
2775 splash = new Splash;
2783 splash->queue_draw ();
2784 splash->get_window()->process_updates (true);
2789 ARDOUR_UI::hide_splash ()
2797 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2798 const string& plural_msg, const string& singular_msg)
2802 removed = rep.paths.size();
2805 MessageDialog msgd (*editor,
2806 _("No audio files were ready for cleanup"),
2809 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2810 msgd.set_secondary_text (_("If this seems suprising, \n\
2811 check for any existing snapshots.\n\
2812 These may still include regions that\n\
2813 require some unused files to continue to exist."));
2819 ArdourDialog results (_("Clean-up"), true, false);
2821 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2822 CleanupResultsModelColumns() {
2826 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2827 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2831 CleanupResultsModelColumns results_columns;
2832 Glib::RefPtr<Gtk::ListStore> results_model;
2833 Gtk::TreeView results_display;
2835 results_model = ListStore::create (results_columns);
2836 results_display.set_model (results_model);
2837 results_display.append_column (list_title, results_columns.visible_name);
2839 results_display.set_name ("CleanupResultsList");
2840 results_display.set_headers_visible (true);
2841 results_display.set_headers_clickable (false);
2842 results_display.set_reorderable (false);
2844 Gtk::ScrolledWindow list_scroller;
2847 Gtk::HBox dhbox; // the hbox for the image and text
2848 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2849 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2851 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2853 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2856 %1 - number of files removed
2857 %2 - location of "dead_sounds"
2858 %3 - size of files affected
2859 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2862 const char* bprefix;
2863 double space_adjusted = 0;
2865 if (rep.space < 100000.0f) {
2866 bprefix = X_("kilo");
2867 } else if (rep.space < 1000000.0f * 1000) {
2868 bprefix = X_("mega");
2869 space_adjusted = truncf((float)rep.space / 1000.0);
2871 bprefix = X_("giga");
2872 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2876 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2878 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2881 dhbox.pack_start (*dimage, true, false, 5);
2882 dhbox.pack_start (txt, true, false, 5);
2884 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2885 TreeModel::Row row = *(results_model->append());
2886 row[results_columns.visible_name] = *i;
2887 row[results_columns.fullpath] = *i;
2890 list_scroller.add (results_display);
2891 list_scroller.set_size_request (-1, 150);
2892 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2894 dvbox.pack_start (dhbox, true, false, 5);
2895 dvbox.pack_start (list_scroller, true, false, 5);
2896 ddhbox.pack_start (dvbox, true, false, 5);
2898 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2899 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2900 results.set_default_response (RESPONSE_CLOSE);
2901 results.set_position (Gtk::WIN_POS_MOUSE);
2903 results_display.show();
2904 list_scroller.show();
2911 //results.get_vbox()->show();
2912 results.set_resizable (false);
2919 ARDOUR_UI::cleanup ()
2921 if (_session == 0) {
2922 /* shouldn't happen: menu item is insensitive */
2927 MessageDialog checker (_("Are you sure you want to cleanup?"),
2929 Gtk::MESSAGE_QUESTION,
2930 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2932 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2933 ALL undo/redo information will be lost if you cleanup.\n\
2934 After cleanup, unused audio files will be moved to a \
2935 \"dead sounds\" location."));
2937 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2938 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2939 checker.set_default_response (RESPONSE_CANCEL);
2941 checker.set_name (_("CleanupDialog"));
2942 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2943 checker.set_position (Gtk::WIN_POS_MOUSE);
2945 switch (checker.run()) {
2946 case RESPONSE_ACCEPT:
2952 ARDOUR::CleanupReport rep;
2954 editor->prepare_for_cleanup ();
2956 /* do not allow flush until a session is reloaded */
2958 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2960 act->set_sensitive (false);
2963 if (_session->cleanup_sources (rep)) {
2964 editor->finish_cleanup ();
2968 editor->finish_cleanup ();
2971 display_cleanup_results (rep,
2974 The following %1 files were not in use and \n\
2975 have been moved to:\n\
2977 Flushing the wastebasket will \n\
2978 release an additional\n\
2979 %3 %4bytes of disk space.\n"),
2981 The following file was not in use and \n \
2982 has been moved to:\n \
2984 Flushing the wastebasket will \n\
2985 release an additional\n\
2986 %3 %4bytes of disk space.\n"
2992 ARDOUR_UI::flush_trash ()
2994 if (_session == 0) {
2995 /* shouldn't happen: menu item is insensitive */
2999 ARDOUR::CleanupReport rep;
3001 if (_session->cleanup_trash_sources (rep)) {
3005 display_cleanup_results (rep,
3007 _("The following %1 files were deleted from\n\
3009 releasing %3 %4bytes of disk space"),
3010 _("The following file was deleted from\n\
3012 releasing %3 %4bytes of disk space"));
3016 ARDOUR_UI::add_route (Gtk::Window* float_window)
3024 if (add_route_dialog == 0) {
3025 add_route_dialog = new AddRouteDialog (_session);
3027 add_route_dialog->set_transient_for (*float_window);
3031 if (add_route_dialog->is_visible()) {
3032 /* we're already doing this */
3036 ResponseType r = (ResponseType) add_route_dialog->run ();
3038 add_route_dialog->hide();
3041 case RESPONSE_ACCEPT:
3048 if ((count = add_route_dialog->count()) <= 0) {
3052 string template_path = add_route_dialog->track_template();
3054 if (!template_path.empty()) {
3055 _session->new_route_from_template (count, template_path);
3059 uint32_t input_chan = add_route_dialog->channels ();
3060 uint32_t output_chan;
3061 string name_template = add_route_dialog->name_template ();
3062 bool track = add_route_dialog->track ();
3063 bool aux = !track && add_route_dialog->aux();
3064 RouteGroup* route_group = add_route_dialog->route_group ();
3066 AutoConnectOption oac = Config->get_output_auto_connect();
3068 if (oac & AutoConnectMaster) {
3069 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3071 output_chan = input_chan;
3074 /* XXX do something with name template */
3076 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3078 session_add_midi_track (route_group, count);
3080 MessageDialog msg (*editor,
3081 _("Sorry, MIDI Busses are not supported at this time."));
3083 //session_add_midi_bus();
3087 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3089 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3095 ARDOUR_UI::mixer_settings () const
3100 node = _session->instant_xml(X_("Mixer"));
3102 node = Config->instant_xml(X_("Mixer"));
3106 node = new XMLNode (X_("Mixer"));
3113 ARDOUR_UI::editor_settings () const
3118 node = _session->instant_xml(X_("Editor"));
3120 node = Config->instant_xml(X_("Editor"));
3124 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3125 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3130 node = new XMLNode (X_("Editor"));
3137 ARDOUR_UI::keyboard_settings () const
3141 node = Config->extra_xml(X_("Keyboard"));
3144 node = new XMLNode (X_("Keyboard"));
3150 ARDOUR_UI::create_xrun_marker(nframes_t where)
3152 editor->mouse_add_new_marker (where, false, true);
3156 ARDOUR_UI::halt_on_xrun_message ()
3158 MessageDialog msg (*editor,
3159 _("Recording was stopped because your system could not keep up."));
3164 ARDOUR_UI::xrun_handler(nframes_t where)
3170 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3172 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3173 create_xrun_marker(where);
3176 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3177 halt_on_xrun_message ();
3182 ARDOUR_UI::disk_overrun_handler ()
3184 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3186 if (!have_disk_speed_dialog_displayed) {
3187 have_disk_speed_dialog_displayed = true;
3188 MessageDialog* msg = new MessageDialog (*editor, _("\
3189 The disk system on your computer\n\
3190 was not able to keep up with Ardour.\n\
3192 Specifically, it failed to write data to disk\n\
3193 quickly enough to keep up with recording.\n"));
3194 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3200 ARDOUR_UI::disk_underrun_handler ()
3202 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3204 if (!have_disk_speed_dialog_displayed) {
3205 have_disk_speed_dialog_displayed = true;
3206 MessageDialog* msg = new MessageDialog (*editor,
3207 _("The disk system on your computer\n\
3208 was not able to keep up with Ardour.\n\
3210 Specifically, it failed to read data from disk\n\
3211 quickly enough to keep up with playback.\n"));
3212 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3218 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3220 have_disk_speed_dialog_displayed = false;
3225 ARDOUR_UI::session_dialog (std::string msg)
3227 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3232 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3234 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3243 ARDOUR_UI::pending_state_dialog ()
3245 HBox* hbox = new HBox();
3246 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3247 ArdourDialog dialog (_("Crash Recovery"), true);
3249 This session appears to have been in\n\
3250 middle of recording when ardour or\n\
3251 the computer was shutdown.\n\
3253 Ardour can recover any captured audio for\n\
3254 you, or it can ignore it. Please decide\n\
3255 what you would like to do.\n"));
3256 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3257 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3258 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3259 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3260 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3261 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3262 dialog.set_default_response (RESPONSE_ACCEPT);
3263 dialog.set_position (WIN_POS_CENTER);
3268 switch (dialog.run ()) {
3269 case RESPONSE_ACCEPT:
3277 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3279 HBox* hbox = new HBox();
3280 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3281 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3282 Label message (string_compose (_("\
3283 This session was created with a sample rate of %1 Hz\n\
3285 The audioengine is currently running at %2 Hz\n"), desired, actual));
3287 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3288 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3289 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3290 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3291 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3292 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3293 dialog.set_default_response (RESPONSE_ACCEPT);
3294 dialog.set_position (WIN_POS_CENTER);
3299 switch (dialog.run ()) {
3300 case RESPONSE_ACCEPT:
3309 ARDOUR_UI::disconnect_from_jack ()
3312 if( engine->disconnect_from_jack ()) {
3313 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3317 update_sample_rate (0);
3322 ARDOUR_UI::reconnect_to_jack ()
3325 if (engine->reconnect_to_jack ()) {
3326 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3330 update_sample_rate (0);
3335 ARDOUR_UI::use_config ()
3338 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3340 set_transport_controllable_state (*node);
3343 node = Config->extra_xml (X_("UI"));
3346 const XMLProperty* prop = node->property (X_("show-big-clock"));
3347 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
3349 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
3350 tact->set_active (string_is_affirmative (prop->value()));
3356 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3358 if (Config->get_primary_clock_delta_edit_cursor()) {
3359 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3361 primary_clock.set (pos, 0, true);
3364 if (Config->get_secondary_clock_delta_edit_cursor()) {
3365 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3367 secondary_clock.set (pos);
3370 if (big_clock_window) {
3371 big_clock.set (pos);
3377 ARDOUR_UI::step_edit_status_change (bool yn)
3379 // XXX should really store pre-step edit status of things
3380 // we make insensitive
3383 rec_button.set_visual_state (3);
3384 rec_button.set_sensitive (false);
3386 rec_button.set_visual_state (0);
3387 rec_button.set_sensitive (true);
3392 ARDOUR_UI::record_state_changed ()
3394 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3396 if (!_session || !big_clock_window) {
3397 /* why bother - the clock isn't visible */
3401 Session::RecordState const r = _session->record_status ();
3402 bool const h = _session->have_rec_enabled_track ();
3404 if (r == Session::Recording && h) {
3405 big_clock.set_widget_name ("BigClockRecording");
3407 big_clock.set_widget_name ("BigClockNonRecording");
3412 ARDOUR_UI::first_idle ()
3415 _session->allow_auto_play (true);
3419 editor->first_idle();
3422 Keyboard::set_can_save_keybindings (true);
3427 ARDOUR_UI::store_clock_modes ()
3429 XMLNode* node = new XMLNode(X_("ClockModes"));
3431 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3432 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3435 _session->add_extra_xml (*node);
3436 _session->set_dirty ();
3441 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3442 : Controllable (name), ui (u), type(tp)
3448 ARDOUR_UI::TransportControllable::set_value (double val)
3450 if (type == ShuttleControl) {
3457 fract = -((0.5 - val)/0.5);
3459 fract = ((val - 0.5)/0.5);
3463 ui.set_shuttle_fract (fract);
3468 /* do nothing: these are radio-style actions */
3472 const char *action = 0;
3476 action = X_("Roll");
3479 action = X_("Stop");
3482 action = X_("Goto Start");
3485 action = X_("Goto End");
3488 action = X_("Loop");
3491 action = X_("Play Selection");
3494 action = X_("Record");
3504 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3512 ARDOUR_UI::TransportControllable::get_value (void) const
3531 case ShuttleControl:
3541 ARDOUR_UI::TransportControllable::set_id (const string& str)
3547 ARDOUR_UI::setup_profile ()
3549 if (gdk_screen_width() < 1200) {
3550 Profile->set_small_screen ();
3554 if (getenv ("ARDOUR_SAE")) {
3555 Profile->set_sae ();
3556 Profile->set_single_package ();