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/application.h"
49 #include "gtkmm2ext/gtk_ui.h"
50 #include "gtkmm2ext/utils.h"
51 #include "gtkmm2ext/click_box.h"
52 #include "gtkmm2ext/fastmeter.h"
53 #include "gtkmm2ext/popup.h"
54 #include "gtkmm2ext/window_title.h"
56 #include "midi++/manager.h"
58 #include "ardour/ardour.h"
59 #include "ardour/callback.h"
60 #include "ardour/profile.h"
61 #include "ardour/session_directory.h"
62 #include "ardour/session_route.h"
63 #include "ardour/session_state_utils.h"
64 #include "ardour/session_utils.h"
65 #include "ardour/port.h"
66 #include "ardour/audioengine.h"
67 #include "ardour/playlist.h"
68 #include "ardour/utils.h"
69 #include "ardour/audio_diskstream.h"
70 #include "ardour/audiofilesource.h"
71 #include "ardour/recent_sessions.h"
72 #include "ardour/port.h"
73 #include "ardour/audio_track.h"
74 #include "ardour/midi_track.h"
75 #include "ardour/filesystem_paths.h"
76 #include "ardour/filename_extensions.h"
78 typedef uint64_t microseconds_t;
81 #include "ardour_ui.h"
82 #include "public_editor.h"
83 #include "audio_clock.h"
88 #include "add_route_dialog.h"
92 #include "gui_thread.h"
93 #include "theme_manager.h"
94 #include "bundle_manager.h"
95 #include "session_metadata_dialog.h"
96 #include "gain_meter.h"
97 #include "route_time_axis.h"
99 #include "engine_dialog.h"
100 #include "processor_box.h"
101 #include "time_axis_view_item.h"
102 #include "window_proxy.h"
103 #include "global_port_matrix.h"
104 #include "location_ui.h"
108 using namespace ARDOUR;
110 using namespace Gtkmm2ext;
113 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
114 UIConfiguration *ARDOUR_UI::ui_config = 0;
116 sigc::signal<void,bool> ARDOUR_UI::Blink;
117 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
118 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
119 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
121 bool could_be_a_valid_path (const string& path);
123 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
125 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
127 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
128 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
129 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
130 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
134 preroll_button (_("pre\nroll")),
135 postroll_button (_("post\nroll")),
139 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
143 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
144 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
145 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
146 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
147 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
148 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
149 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
150 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
151 shuttle_controller_binding_proxy (shuttle_controllable),
153 roll_button (roll_controllable),
154 stop_button (stop_controllable),
155 goto_start_button (goto_start_controllable),
156 goto_end_button (goto_end_controllable),
157 auto_loop_button (auto_loop_controllable),
158 play_selection_button (play_selection_controllable),
159 rec_button (rec_controllable),
161 shuttle_units_button (_("% ")),
163 punch_in_button (_("Punch In")),
164 punch_out_button (_("Punch Out")),
165 auto_return_button (_("Auto Return")),
166 auto_play_button (_("Auto Play")),
167 auto_input_button (_("Auto Input")),
168 click_button (_("Click")),
169 time_master_button (_("time\nmaster")),
171 auditioning_alert_button (_("AUDITION")),
172 solo_alert_button (_("SOLO")),
173 error_log_button (_("Errors"))
176 using namespace Gtk::Menu_Helpers;
182 // _auto_display_errors = false;
184 * This was commented out as it wasn't defined
185 * in A3 IIRC. If this is not needed it should
186 * be completely removed.
194 if (theArdourUI == 0) {
198 ui_config = new UIConfiguration();
199 theme_manager = new ThemeManager();
205 _session_is_new = false;
206 big_clock_window = 0;
207 big_clock_height = 0;
208 big_clock_resize_in_progress = false;
209 session_selector_window = 0;
210 last_key_press_time = 0;
211 _will_create_new_session_automatically = false;
212 add_route_dialog = 0;
214 rc_option_editor = 0;
215 session_option_editor = 0;
217 open_session_selector = 0;
218 have_configure_timeout = false;
219 have_disk_speed_dialog_displayed = false;
220 session_loaded = false;
221 last_speed_displayed = -1.0f;
222 ignore_dual_punch = false;
223 _mixer_on_top = false;
224 original_big_clock_width = -1;
225 original_big_clock_height = -1;
226 original_big_clock_font_size = 0;
228 roll_button.unset_flags (Gtk::CAN_FOCUS);
229 stop_button.unset_flags (Gtk::CAN_FOCUS);
230 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
231 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
232 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
233 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
234 rec_button.unset_flags (Gtk::CAN_FOCUS);
236 last_configure_time= 0;
238 shuttle_grabbed = false;
240 shuttle_max_speed = 8.0f;
242 shuttle_style_menu = 0;
243 shuttle_unit_menu = 0;
245 // We do not have jack linked in yet so;
247 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
249 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
250 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
252 /* handle dialog requests */
254 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
256 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
258 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
260 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
262 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
264 /* lets get this party started */
267 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
268 throw failed_constructor ();
271 setup_gtk_ardour_enums ();
274 GainMeter::setup_slider_pix ();
275 RouteTimeAxisView::setup_slider_pix ();
276 SendProcessorEntry::setup_slider_pix ();
277 SessionEvent::create_per_thread_pool ("GUI", 512);
279 } catch (failed_constructor& err) {
280 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
285 /* we like keyboards */
287 keyboard = new ArdourKeyboard(*this);
289 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
291 keyboard->set_state (*node, Stateful::loading_state_version);
296 TimeAxisViewItem::set_constant_heights ();
298 /* The following must happen after ARDOUR::init() so that Config is set up */
300 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
301 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
303 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
304 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
305 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
306 Config->extra_xml (X_("UI")),
307 string_compose ("toggle-%1-connection-manager", (*i).to_string())
313 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
314 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
319 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
321 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
324 _startup = new ArdourStartup ();
326 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
328 if (audio_setup && _startup->engine_control()) {
329 _startup->engine_control()->set_state (*audio_setup);
332 _startup->set_new_only (should_be_new);
333 if (!load_template.empty()) {
334 _startup->set_load_template( load_template );
336 _startup->present ();
342 switch (_startup->response()) {
351 ARDOUR_UI::create_engine ()
353 // this gets called every time by new_session()
359 loading_message (_("Starting audio engine"));
362 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
369 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
370 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
371 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
373 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
375 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
383 ARDOUR_UI::post_engine ()
385 /* Things to be done once we create the AudioEngine
388 ARDOUR::init_post_engine ();
390 ActionManager::init ();
393 if (setup_windows ()) {
394 throw failed_constructor ();
397 check_memory_locking();
399 /* this is the first point at which all the keybindings are available */
401 if (ARDOUR_COMMAND_LINE::show_key_actions) {
402 vector<string> names;
403 vector<string> paths;
405 vector<AccelKey> bindings;
407 ActionManager::get_all_actions (names, paths, keys, bindings);
409 vector<string>::iterator n;
410 vector<string>::iterator k;
411 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
412 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
418 blink_timeout_tag = -1;
420 /* this being a GUI and all, we want peakfiles */
422 AudioFileSource::set_build_peakfiles (true);
423 AudioFileSource::set_build_missing_peakfiles (true);
425 /* set default clock modes */
427 if (Profile->get_sae()) {
428 primary_clock.set_mode (AudioClock::BBT);
429 secondary_clock.set_mode (AudioClock::MinSec);
431 primary_clock.set_mode (AudioClock::Timecode);
432 secondary_clock.set_mode (AudioClock::BBT);
435 /* start the time-of-day-clock */
438 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
439 update_wall_clock ();
440 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
443 update_disk_space ();
445 update_sample_rate (engine->frame_rate());
447 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
448 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
449 Config->map_parameters (pc);
451 /* now start and maybe save state */
453 if (do_engine_start () == 0) {
454 if (_session && _session_is_new) {
455 /* we need to retain initial visual
456 settings for a new session
458 _session->save_state ("");
463 ARDOUR_UI::~ARDOUR_UI ()
468 delete add_route_dialog;
472 ARDOUR_UI::pop_back_splash ()
474 if (Splash::instance()) {
475 // Splash::instance()->pop_back();
476 Splash::instance()->hide ();
481 ARDOUR_UI::configure_timeout ()
483 if (last_configure_time == 0) {
484 /* no configure events yet */
488 /* force a gap of 0.5 seconds since the last configure event
491 if (get_microseconds() - last_configure_time < 500000) {
494 have_configure_timeout = false;
495 cerr << "config event-driven save\n";
496 save_ardour_state ();
502 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
504 if (have_configure_timeout) {
505 last_configure_time = get_microseconds();
507 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
508 have_configure_timeout = true;
515 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
517 const XMLProperty* prop;
519 if ((prop = node.property ("roll")) != 0) {
520 roll_controllable->set_id (prop->value());
522 if ((prop = node.property ("stop")) != 0) {
523 stop_controllable->set_id (prop->value());
525 if ((prop = node.property ("goto-start")) != 0) {
526 goto_start_controllable->set_id (prop->value());
528 if ((prop = node.property ("goto-end")) != 0) {
529 goto_end_controllable->set_id (prop->value());
531 if ((prop = node.property ("auto-loop")) != 0) {
532 auto_loop_controllable->set_id (prop->value());
534 if ((prop = node.property ("play-selection")) != 0) {
535 play_selection_controllable->set_id (prop->value());
537 if ((prop = node.property ("rec")) != 0) {
538 rec_controllable->set_id (prop->value());
540 if ((prop = node.property ("shuttle")) != 0) {
541 shuttle_controllable->set_id (prop->value());
546 ARDOUR_UI::get_transport_controllable_state ()
548 XMLNode* node = new XMLNode(X_("TransportControllables"));
551 roll_controllable->id().print (buf, sizeof (buf));
552 node->add_property (X_("roll"), buf);
553 stop_controllable->id().print (buf, sizeof (buf));
554 node->add_property (X_("stop"), buf);
555 goto_start_controllable->id().print (buf, sizeof (buf));
556 node->add_property (X_("goto_start"), buf);
557 goto_end_controllable->id().print (buf, sizeof (buf));
558 node->add_property (X_("goto_end"), buf);
559 auto_loop_controllable->id().print (buf, sizeof (buf));
560 node->add_property (X_("auto_loop"), buf);
561 play_selection_controllable->id().print (buf, sizeof (buf));
562 node->add_property (X_("play_selection"), buf);
563 rec_controllable->id().print (buf, sizeof (buf));
564 node->add_property (X_("rec"), buf);
565 shuttle_controllable->id().print (buf, sizeof (buf));
566 node->add_property (X_("shuttle"), buf);
573 ARDOUR_UI::autosave_session ()
575 if (g_main_depth() > 1) {
576 /* inside a recursive main loop,
577 give up because we may not be able to
583 if (!Config->get_periodic_safety_backups()) {
588 _session->maybe_write_autosave();
595 ARDOUR_UI::update_autosave ()
597 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
599 if (_session && _session->dirty()) {
600 if (_autosave_connection.connected()) {
601 _autosave_connection.disconnect();
604 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
605 Config->get_periodic_safety_backup_interval() * 1000);
608 if (_autosave_connection.connected()) {
609 _autosave_connection.disconnect();
615 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
619 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
621 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
624 MessageDialog win (title,
630 win.set_secondary_text(_("There are several possible reasons:\n\
632 1) You requested audio parameters that are not supported..\n\
633 2) JACK is running as another user.\n\
635 Please consider the possibilities, and perhaps try different parameters."));
637 win.set_secondary_text(_("There are several possible reasons:\n\
639 1) JACK is not running.\n\
640 2) JACK is running as another user, perhaps root.\n\
641 3) There is already another client called \"ardour\".\n\
643 Please consider the possibilities, and perhaps (re)start JACK."));
647 win.set_transient_for (*toplevel);
651 win.add_button (Stock::OK, RESPONSE_CLOSE);
653 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
656 win.set_default_response (RESPONSE_CLOSE);
659 win.set_position (Gtk::WIN_POS_CENTER);
662 /* we just don't care about the result, but we want to block */
668 ARDOUR_UI::startup ()
670 Application* app = Application::instance ();
672 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
673 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
676 call_the_mothership (VERSIONSTRING);
681 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
687 goto_editor_window ();
689 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
690 to be opened on top of the editor window that goto_editor_window() just opened.
692 add_window_proxy (location_ui);
693 add_window_proxy (big_clock_window);
694 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
695 add_window_proxy (_global_port_matrix[*i]);
698 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
702 ARDOUR_UI::no_memory_warning ()
704 XMLNode node (X_("no-memory-warning"));
705 Config->add_instant_xml (node);
709 ARDOUR_UI::check_memory_locking ()
712 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
716 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
718 if (engine->is_realtime() && memory_warning_node == 0) {
720 struct rlimit limits;
722 long pages, page_size;
724 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
727 ram = (int64_t) pages * (int64_t) page_size;
730 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
734 if (limits.rlim_cur != RLIM_INFINITY) {
736 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
739 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
740 "This might cause %1 to run out of memory before your system "
741 "runs out of memory. \n\n"
742 "You can view the memory limit with 'ulimit -l', "
743 "and it is normally controlled by /etc/security/limits.conf"),
744 PROGRAM_NAME).c_str());
746 VBox* vbox = msg.get_vbox();
748 CheckButton cb (_("Do not show this window again"));
750 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
752 hbox.pack_start (cb, true, false);
753 vbox->pack_start (hbox);
760 editor->ensure_float (msg);
770 ARDOUR_UI::queue_finish ()
772 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
776 ARDOUR_UI::idle_finish ()
779 return false; /* do not call again */
788 if (_session->transport_rolling() && (++tries < 8)) {
789 _session->request_stop (false, true);
793 if (_session->dirty()) {
794 switch (ask_about_saving_session(_("quit"))) {
799 /* use the default name */
800 if (save_state_canfail ("")) {
801 /* failed - don't quit */
802 MessageDialog msg (*editor,
804 Ardour was unable to save your session.\n\n\
805 If you still wish to quit, please use the\n\n\
806 \"Just quit\" option."));
817 second_connection.disconnect ();
818 point_one_second_connection.disconnect ();
819 point_oh_five_second_connection.disconnect ();
820 point_zero_one_second_connection.disconnect();
823 /* Save state before deleting the session, as that causes some
824 windows to be destroyed before their visible state can be
827 save_ardour_state ();
830 // _session->set_deletion_in_progress ();
831 _session->set_clean ();
832 _session->remove_pending_capture_state ();
837 ArdourDialog::close_all_dialogs ();
843 ARDOUR_UI::ask_about_saving_session (const string & what)
845 ArdourDialog window (_("Unsaved Session"));
846 Gtk::HBox dhbox; // the hbox for the image and text
847 Gtk::Label prompt_label;
848 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
852 msg = string_compose(_("Don't %1"), what);
853 window.add_button (msg, RESPONSE_REJECT);
854 msg = string_compose(_("Just %1"), what);
855 window.add_button (msg, RESPONSE_APPLY);
856 msg = string_compose(_("Save and %1"), what);
857 window.add_button (msg, RESPONSE_ACCEPT);
859 window.set_default_response (RESPONSE_ACCEPT);
861 Gtk::Button noquit_button (msg);
862 noquit_button.set_name ("EditorGTKButton");
867 if (_session->snap_name() == _session->name()) {
870 type = _("snapshot");
872 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?"),
873 type, _session->snap_name());
875 prompt_label.set_text (prompt);
876 prompt_label.set_name (X_("PrompterLabel"));
877 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
879 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
880 dhbox.set_homogeneous (false);
881 dhbox.pack_start (*dimage, false, false, 5);
882 dhbox.pack_start (prompt_label, true, false, 5);
883 window.get_vbox()->pack_start (dhbox);
885 window.set_name (_("Prompter"));
886 window.set_position (Gtk::WIN_POS_MOUSE);
887 window.set_modal (true);
888 window.set_resizable (false);
894 window.set_keep_above (true);
897 ResponseType r = (ResponseType) window.run();
902 case RESPONSE_ACCEPT: // save and get out of here
904 case RESPONSE_APPLY: // get out of here
914 ARDOUR_UI::every_second ()
917 update_buffer_load ();
918 update_disk_space ();
923 ARDOUR_UI::every_point_one_seconds ()
925 update_speed_display ();
926 RapidScreenUpdate(); /* EMIT_SIGNAL */
931 ARDOUR_UI::every_point_zero_one_seconds ()
933 // august 2007: actual update frequency: 40Hz, not 100Hz
935 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
940 ARDOUR_UI::update_sample_rate (nframes_t)
944 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
946 if (!engine->connected()) {
948 snprintf (buf, sizeof (buf), _("disconnected"));
952 nframes_t rate = engine->frame_rate();
954 if (fmod (rate, 1000.0) != 0.0) {
955 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
956 (float) rate/1000.0f,
957 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
959 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
961 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
965 sample_rate_label.set_text (buf);
969 ARDOUR_UI::update_cpu_load ()
972 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
973 cpu_load_label.set_text (buf);
977 ARDOUR_UI::update_buffer_load ()
983 c = _session->capture_load ();
984 p = _session->playback_load ();
986 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
987 _session->playback_load(), _session->capture_load());
988 buffer_load_label.set_text (buf);
990 buffer_load_label.set_text ("");
995 ARDOUR_UI::count_recenabled_streams (Route& route)
997 Track* track = dynamic_cast<Track*>(&route);
998 if (track && track->record_enabled()) {
999 rec_enabled_streams += track->n_inputs().n_total();
1004 ARDOUR_UI::update_disk_space()
1006 if (_session == 0) {
1010 nframes_t frames = _session->available_capture_duration();
1012 nframes_t fr = _session->frame_rate();
1014 if (frames == max_frames) {
1015 strcpy (buf, _("Disk: 24hrs+"));
1017 rec_enabled_streams = 0;
1018 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1020 if (rec_enabled_streams) {
1021 frames /= rec_enabled_streams;
1028 hrs = frames / (fr * 3600);
1029 frames -= hrs * fr * 3600;
1030 mins = frames / (fr * 60);
1031 frames -= mins * fr * 60;
1034 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1037 disk_space_label.set_text (buf);
1039 // An attempt to make the disk space label flash red when space has run out.
1041 if (frames < fr * 60 * 5) {
1042 /* disk_space_box.style ("disk_space_label_empty"); */
1044 /* disk_space_box.style ("disk_space_label"); */
1050 ARDOUR_UI::update_wall_clock ()
1057 tm_now = localtime (&now);
1059 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1060 wall_clock_label.set_text (buf);
1066 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1068 session_popup_menu->popup (0, 0);
1073 ARDOUR_UI::redisplay_recent_sessions ()
1075 std::vector<sys::path> session_directories;
1076 RecentSessionsSorter cmp;
1078 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1079 recent_session_model->clear ();
1081 ARDOUR::RecentSessions rs;
1082 ARDOUR::read_recent_sessions (rs);
1085 recent_session_display.set_model (recent_session_model);
1089 // sort them alphabetically
1090 sort (rs.begin(), rs.end(), cmp);
1092 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1093 session_directories.push_back ((*i).second);
1096 for (vector<sys::path>::const_iterator i = session_directories.begin();
1097 i != session_directories.end(); ++i)
1099 std::vector<sys::path> state_file_paths;
1101 // now get available states for this session
1103 get_state_files_in_directory (*i, state_file_paths);
1105 vector<string*>* states;
1106 vector<const gchar*> item;
1107 string fullpath = (*i).to_string();
1109 /* remove any trailing / */
1111 if (fullpath[fullpath.length()-1] == '/') {
1112 fullpath = fullpath.substr (0, fullpath.length()-1);
1115 /* check whether session still exists */
1116 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1117 /* session doesn't exist */
1118 cerr << "skipping non-existent session " << fullpath << endl;
1122 /* now get available states for this session */
1124 if ((states = Session::possible_states (fullpath)) == 0) {
1125 /* no state file? */
1129 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1131 Gtk::TreeModel::Row row = *(recent_session_model->append());
1133 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1134 row[recent_session_columns.fullpath] = fullpath;
1136 if (state_file_names.size() > 1) {
1140 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1141 i2 != state_file_names.end(); ++i2)
1144 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1146 child_row[recent_session_columns.visible_name] = *i2;
1147 child_row[recent_session_columns.fullpath] = fullpath;
1152 recent_session_display.set_model (recent_session_model);
1156 ARDOUR_UI::build_session_selector ()
1158 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1160 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1162 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1163 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1164 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1165 recent_session_model = TreeStore::create (recent_session_columns);
1166 recent_session_display.set_model (recent_session_model);
1167 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1168 recent_session_display.set_headers_visible (false);
1169 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1170 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1172 scroller->add (recent_session_display);
1173 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1175 session_selector_window->set_name ("SessionSelectorWindow");
1176 session_selector_window->set_size_request (200, 400);
1177 session_selector_window->get_vbox()->pack_start (*scroller);
1179 recent_session_display.show();
1181 //session_selector_window->get_vbox()->show();
1185 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1187 session_selector_window->response (RESPONSE_ACCEPT);
1191 ARDOUR_UI::open_recent_session ()
1193 bool can_return = (_session != 0);
1195 if (session_selector_window == 0) {
1196 build_session_selector ();
1199 redisplay_recent_sessions ();
1203 session_selector_window->set_position (WIN_POS_MOUSE);
1205 ResponseType r = (ResponseType) session_selector_window->run ();
1208 case RESPONSE_ACCEPT:
1212 session_selector_window->hide();
1219 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1223 session_selector_window->hide();
1225 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1227 if (i == recent_session_model->children().end()) {
1231 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1232 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1234 _session_is_new = false;
1236 if (load_session (path, state) == 0) {
1245 ARDOUR_UI::check_audioengine ()
1248 if (!engine->connected()) {
1249 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1250 "You cannot open or close sessions in this condition"),
1263 ARDOUR_UI::open_session ()
1265 if (!check_audioengine()) {
1270 /* popup selector window */
1272 if (open_session_selector == 0) {
1274 /* ardour sessions are folders */
1276 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1277 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1278 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1279 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1281 FileFilter session_filter;
1282 session_filter.add_pattern ("*.ardour");
1283 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1284 open_session_selector->add_filter (session_filter);
1285 open_session_selector->set_filter (session_filter);
1288 int response = open_session_selector->run();
1289 open_session_selector->hide ();
1292 case RESPONSE_ACCEPT:
1295 open_session_selector->hide();
1299 open_session_selector->hide();
1300 string session_path = open_session_selector->get_filename();
1304 if (session_path.length() > 0) {
1305 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1306 _session_is_new = isnew;
1307 load_session (path, name);
1314 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1316 list<boost::shared_ptr<MidiTrack> > tracks;
1318 if (_session == 0) {
1319 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1326 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1328 if (tracks.size() != how_many) {
1329 if (how_many == 1) {
1330 error << _("could not create a new midi track") << endmsg;
1332 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1336 if ((route = _session->new_midi_route ()) == 0) {
1337 error << _("could not create new midi bus") << endmsg;
1343 MessageDialog msg (*editor,
1344 string_compose (_("There are insufficient JACK ports available\n\
1345 to create a new track or bus.\n\
1346 You should save %1, exit and\n\
1347 restart JACK with more ports."), PROGRAM_NAME));
1354 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)
1356 list<boost::shared_ptr<AudioTrack> > tracks;
1359 if (_session == 0) {
1360 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1366 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1368 if (tracks.size() != how_many) {
1369 if (how_many == 1) {
1370 error << _("could not create a new audio track") << endmsg;
1372 error << string_compose (_("could only create %1 of %2 new audio %3"),
1373 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1379 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1381 if (routes.size() != how_many) {
1382 if (how_many == 1) {
1383 error << _("could not create a new audio track") << endmsg;
1385 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1392 MessageDialog msg (*editor,
1393 string_compose (_("There are insufficient JACK ports available\n\
1394 to create a new track or bus.\n\
1395 You should save %1, exit and\n\
1396 restart JACK with more ports."), PROGRAM_NAME));
1403 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1405 nframes_t _preroll = 0;
1408 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1409 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1411 if (new_position > _preroll) {
1412 new_position -= _preroll;
1417 _session->request_locate (new_position);
1422 ARDOUR_UI::transport_goto_start ()
1425 _session->goto_start();
1427 /* force displayed area in editor to start no matter
1428 what "follow playhead" setting is.
1432 editor->center_screen (_session->current_start_frame ());
1438 ARDOUR_UI::transport_goto_zero ()
1441 _session->request_locate (0);
1443 /* force displayed area in editor to start no matter
1444 what "follow playhead" setting is.
1448 editor->reset_x_origin (0);
1454 ARDOUR_UI::transport_goto_wallclock ()
1456 if (_session && editor) {
1463 localtime_r (&now, &tmnow);
1465 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1466 frames += tmnow.tm_min * (60 * _session->frame_rate());
1467 frames += tmnow.tm_sec * _session->frame_rate();
1469 _session->request_locate (frames, _session->transport_rolling ());
1471 /* force displayed area in editor to start no matter
1472 what "follow playhead" setting is.
1476 editor->center_screen (frames);
1482 ARDOUR_UI::transport_goto_end ()
1485 nframes_t const frame = _session->current_end_frame();
1486 _session->request_locate (frame);
1488 /* force displayed area in editor to start no matter
1489 what "follow playhead" setting is.
1493 editor->center_screen (frame);
1499 ARDOUR_UI::transport_stop ()
1505 if (_session->is_auditioning()) {
1506 _session->cancel_audition ();
1510 _session->request_stop (false, true);
1514 ARDOUR_UI::transport_stop_and_forget_capture ()
1517 _session->request_stop (true, true);
1522 ARDOUR_UI::remove_last_capture()
1525 editor->remove_last_capture();
1530 ARDOUR_UI::transport_record (bool roll)
1534 switch (_session->record_status()) {
1535 case Session::Disabled:
1536 if (_session->ntracks() == 0) {
1537 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1541 _session->maybe_enable_record ();
1546 case Session::Recording:
1548 _session->request_stop();
1550 _session->disable_record (false, true);
1554 case Session::Enabled:
1555 _session->disable_record (false, true);
1558 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1562 ARDOUR_UI::transport_roll ()
1568 if (_session->is_auditioning()) {
1572 if (_session->config.get_external_sync()) {
1573 switch (_session->config.get_sync_source()) {
1577 /* transport controlled by the master */
1582 bool rolling = _session->transport_rolling();
1584 if (_session->get_play_loop()) {
1585 /* XXX it is not possible to just leave seamless loop and keep
1586 playing at present (nov 4th 2009)
1588 if (!Config->get_seamless_loop()) {
1589 _session->request_play_loop (false, true);
1591 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1592 /* stop playing a range if we currently are */
1593 _session->request_play_range (0, true);
1596 if (join_play_range_button.get_active()) {
1597 _session->request_play_range (&editor->get_selection().time, true);
1601 _session->request_transport_speed (1.0f);
1606 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1613 if (_session->is_auditioning()) {
1614 _session->cancel_audition ();
1618 if (_session->config.get_external_sync()) {
1619 switch (_session->config.get_sync_source()) {
1623 /* transport controlled by the master */
1628 bool rolling = _session->transport_rolling();
1629 bool affect_transport = true;
1631 if (rolling && roll_out_of_bounded_mode) {
1632 /* drop out of loop/range playback but leave transport rolling */
1633 if (_session->get_play_loop()) {
1634 if (Config->get_seamless_loop()) {
1635 /* the disk buffers contain copies of the loop - we can't
1636 just keep playing, so stop the transport. the user
1637 can restart as they wish.
1639 affect_transport = true;
1641 /* disk buffers are normal, so we can keep playing */
1642 affect_transport = false;
1644 _session->request_play_loop (false, true);
1645 } else if (_session->get_play_range ()) {
1646 affect_transport = false;
1647 _session->request_play_range (0, true);
1651 if (affect_transport) {
1653 _session->request_stop (with_abort, true);
1655 if (join_play_range_button.get_active()) {
1656 _session->request_play_range (&editor->get_selection().time, true);
1659 _session->request_transport_speed (1.0f);
1665 ARDOUR_UI::toggle_session_auto_loop ()
1668 if (_session->get_play_loop()) {
1669 if (_session->transport_rolling()) {
1670 Location * looploc = _session->locations()->auto_loop_location();
1672 _session->request_locate (looploc->start(), true);
1675 _session->request_play_loop (false);
1678 Location * looploc = _session->locations()->auto_loop_location();
1680 _session->request_play_loop (true);
1687 ARDOUR_UI::transport_play_selection ()
1693 editor->play_selection ();
1697 ARDOUR_UI::transport_rewind (int option)
1699 float current_transport_speed;
1702 current_transport_speed = _session->transport_speed();
1704 if (current_transport_speed >= 0.0f) {
1707 _session->request_transport_speed (-1.0f);
1710 _session->request_transport_speed (-4.0f);
1713 _session->request_transport_speed (-0.5f);
1718 _session->request_transport_speed (current_transport_speed * 1.5f);
1724 ARDOUR_UI::transport_forward (int option)
1726 float current_transport_speed;
1729 current_transport_speed = _session->transport_speed();
1731 if (current_transport_speed <= 0.0f) {
1734 _session->request_transport_speed (1.0f);
1737 _session->request_transport_speed (4.0f);
1740 _session->request_transport_speed (0.5f);
1745 _session->request_transport_speed (current_transport_speed * 1.5f);
1752 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1754 if (_session == 0) {
1758 boost::shared_ptr<Route> r;
1760 if ((r = _session->route_by_remote_id (rid)) != 0) {
1764 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1765 t->set_record_enabled (!t->record_enabled(), this);
1768 if (_session == 0) {
1774 ARDOUR_UI::map_transport_state ()
1776 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1779 auto_loop_button.set_visual_state (0);
1780 play_selection_button.set_visual_state (0);
1781 roll_button.set_visual_state (0);
1782 stop_button.set_visual_state (1);
1786 float sp = _session->transport_speed();
1789 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1790 shuttle_box.queue_draw ();
1791 } else if (sp == 0.0f) {
1793 shuttle_box.queue_draw ();
1794 update_disk_space ();
1801 if (_session->get_play_range()) {
1803 play_selection_button.set_visual_state (1);
1804 roll_button.set_visual_state (0);
1805 auto_loop_button.set_visual_state (0);
1807 } else if (_session->get_play_loop ()) {
1809 auto_loop_button.set_visual_state (1);
1810 play_selection_button.set_visual_state (0);
1811 roll_button.set_visual_state (0);
1815 roll_button.set_visual_state (1);
1816 play_selection_button.set_visual_state (0);
1817 auto_loop_button.set_visual_state (0);
1820 if (join_play_range_button.get_active()) {
1821 /* light up both roll and play-selection if they are joined */
1822 roll_button.set_visual_state (1);
1823 play_selection_button.set_visual_state (1);
1826 stop_button.set_visual_state (0);
1830 stop_button.set_visual_state (1);
1831 roll_button.set_visual_state (0);
1832 play_selection_button.set_visual_state (0);
1833 auto_loop_button.set_visual_state (0);
1838 ARDOUR_UI::engine_stopped ()
1840 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1841 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1842 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1846 ARDOUR_UI::engine_running ()
1848 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1849 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1850 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1852 Glib::RefPtr<Action> action;
1853 const char* action_name = 0;
1855 switch (engine->frames_per_cycle()) {
1857 action_name = X_("JACKLatency32");
1860 action_name = X_("JACKLatency64");
1863 action_name = X_("JACKLatency128");
1866 action_name = X_("JACKLatency512");
1869 action_name = X_("JACKLatency1024");
1872 action_name = X_("JACKLatency2048");
1875 action_name = X_("JACKLatency4096");
1878 action_name = X_("JACKLatency8192");
1881 /* XXX can we do anything useful ? */
1887 action = ActionManager::get_action (X_("JACK"), action_name);
1890 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1891 ract->set_active ();
1897 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1899 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1900 /* we can't rely on the original string continuing to exist when we are called
1901 again in the GUI thread, so make a copy and note that we need to
1904 char *copy = strdup (reason);
1905 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1909 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1910 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1912 update_sample_rate (0);
1916 /* if the reason is a non-empty string, it means that the backend was shutdown
1917 rather than just Ardour.
1920 if (strlen (reason)) {
1921 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1923 msgstr = string_compose (_("\
1924 JACK has either been shutdown or it\n\
1925 disconnected %1 because %1\n\
1926 was not fast enough. Try to restart\n\
1927 JACK, reconnect and save the session."), PROGRAM_NAME);
1930 MessageDialog msg (*editor, msgstr);
1935 free ((char*) reason);
1940 ARDOUR_UI::do_engine_start ()
1948 error << _("Unable to start the session running")
1958 ARDOUR_UI::setup_theme ()
1960 theme_manager->setup_theme();
1964 ARDOUR_UI::update_clocks ()
1966 if (!editor || !editor->dragging_playhead()) {
1967 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1972 ARDOUR_UI::start_clocking ()
1974 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1978 ARDOUR_UI::stop_clocking ()
1980 clock_signal_connection.disconnect ();
1984 ARDOUR_UI::toggle_clocking ()
1987 if (clock_button.get_active()) {
1996 ARDOUR_UI::_blink (void *arg)
1999 ((ARDOUR_UI *) arg)->blink ();
2006 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2010 ARDOUR_UI::start_blinking ()
2012 /* Start the blink signal. Everybody with a blinking widget
2013 uses Blink to drive the widget's state.
2016 if (blink_timeout_tag < 0) {
2018 blink_timeout_tag = g_timeout_add (240, _blink, this);
2023 ARDOUR_UI::stop_blinking ()
2025 if (blink_timeout_tag >= 0) {
2026 g_source_remove (blink_timeout_tag);
2027 blink_timeout_tag = -1;
2032 /** Ask the user for the name of a new shapshot and then take it.
2036 ARDOUR_UI::snapshot_session (bool switch_to_it)
2038 ArdourPrompter prompter (true);
2041 prompter.set_name ("Prompter");
2042 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2043 prompter.set_title (_("Take Snapshot"));
2044 prompter.set_title (_("Take Snapshot"));
2045 prompter.set_prompt (_("Name of new snapshot"));
2047 if (!switch_to_it) {
2050 struct tm local_time;
2053 localtime_r (&n, &local_time);
2054 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2055 prompter.set_initial_text (timebuf);
2059 switch (prompter.run()) {
2060 case RESPONSE_ACCEPT:
2062 prompter.get_result (snapname);
2064 bool do_save = (snapname.length() != 0);
2067 if (snapname.find ('/') != string::npos) {
2068 MessageDialog msg (_("To ensure compatibility with various systems\n"
2069 "snapshot names may not contain a '/' character"));
2073 if (snapname.find ('\\') != string::npos) {
2074 MessageDialog msg (_("To ensure compatibility with various systems\n"
2075 "snapshot names may not contain a '\\' character"));
2081 vector<sys::path> p;
2082 get_state_files_in_directory (_session->session_directory().root_path(), p);
2083 vector<string> n = get_file_names_no_extension (p);
2084 if (find (n.begin(), n.end(), snapname) != n.end()) {
2086 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2087 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2088 confirm.get_vbox()->pack_start (m, true, true);
2089 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2090 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2091 confirm.show_all ();
2092 switch (confirm.run()) {
2093 case RESPONSE_CANCEL:
2099 save_state (snapname, switch_to_it);
2110 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2112 XMLNode* node = new XMLNode (X_("UI"));
2114 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2115 if (!(*i)->rc_configured()) {
2116 node->add_child_nocopy (*((*i)->get_state ()));
2120 _session->add_extra_xml (*node);
2122 save_state_canfail (name, switch_to_it);
2126 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2131 if (name.length() == 0) {
2132 name = _session->snap_name();
2135 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2139 cerr << "SS canfail\n";
2140 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2145 ARDOUR_UI::primary_clock_value_changed ()
2148 _session->request_locate (primary_clock.current_time ());
2153 ARDOUR_UI::big_clock_value_changed ()
2156 _session->request_locate (big_clock.current_time ());
2161 ARDOUR_UI::secondary_clock_value_changed ()
2164 _session->request_locate (secondary_clock.current_time ());
2169 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2171 if (_session == 0) {
2175 if (_session->step_editing()) {
2179 Session::RecordState const r = _session->record_status ();
2180 bool const h = _session->have_rec_enabled_track ();
2182 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2184 rec_button.set_visual_state (2);
2186 rec_button.set_visual_state (0);
2188 } else if (r == Session::Recording && h) {
2189 rec_button.set_visual_state (1);
2191 rec_button.set_visual_state (0);
2196 ARDOUR_UI::save_template ()
2198 ArdourPrompter prompter (true);
2201 if (!check_audioengine()) {
2205 prompter.set_name (X_("Prompter"));
2206 prompter.set_title (_("Save Mix Template"));
2207 prompter.set_prompt (_("Name for mix template:"));
2208 prompter.set_initial_text(_session->name() + _("-template"));
2209 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2211 switch (prompter.run()) {
2212 case RESPONSE_ACCEPT:
2213 prompter.get_result (name);
2215 if (name.length()) {
2216 _session->save_template (name);
2226 ARDOUR_UI::edit_metadata ()
2228 SessionMetadataEditor dialog;
2229 dialog.set_session (_session);
2230 editor->ensure_float (dialog);
2235 ARDOUR_UI::import_metadata ()
2237 SessionMetadataImporter dialog;
2238 dialog.set_session (_session);
2239 editor->ensure_float (dialog);
2244 ARDOUR_UI::fontconfig_dialog ()
2247 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2248 may not and it can take a while to build it. Warn them.
2251 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2253 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2254 MessageDialog msg (*_startup,
2255 string_compose (_("Welcome to %1.\n\n"
2256 "The program will take a bit longer to start up\n"
2257 "while the system fonts are checked.\n\n"
2258 "This will only be done once, and you will\n"
2259 "not see this message again\n"), PROGRAM_NAME),
2272 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2274 existing_session = false;
2276 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2277 session_path = cmdline_path;
2278 existing_session = true;
2279 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2280 session_path = Glib::path_get_dirname (string (cmdline_path));
2281 existing_session = true;
2283 /* it doesn't exist, assume the best */
2284 session_path = Glib::path_get_dirname (string (cmdline_path));
2287 session_name = basename_nosuffix (string (cmdline_path));
2291 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2293 /* when this is called, the backend audio system must be running */
2295 /* the main idea here is to deal with the fact that a cmdline argument for the session
2296 can be interpreted in different ways - it could be a directory or a file, and before
2297 we load, we need to know both the session directory and the snapshot (statefile) within it
2298 that we are supposed to use.
2301 if (session_name.length() == 0 || session_path.length() == 0) {
2305 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2307 Glib::ustring predicted_session_file;
2309 predicted_session_file = session_path;
2310 predicted_session_file += '/';
2311 predicted_session_file += session_name;
2312 predicted_session_file += ARDOUR::statefile_suffix;
2314 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2315 existing_session = true;
2318 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2320 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2321 /* existing .ardour file */
2322 existing_session = true;
2326 existing_session = false;
2329 /* lets just try to load it */
2331 if (create_engine ()) {
2332 backend_audio_error (false, _startup);
2336 return load_session (session_path, session_name);
2340 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2342 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2344 MessageDialog msg (str,
2346 Gtk::MESSAGE_WARNING,
2347 Gtk::BUTTONS_YES_NO,
2351 msg.set_name (X_("OpenExistingDialog"));
2352 msg.set_title (_("Open Existing Session"));
2353 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2354 msg.set_position (Gtk::WIN_POS_MOUSE);
2357 switch (msg.run()) {
2366 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2368 BusProfile bus_profile;
2370 if (Profile->get_sae()) {
2372 bus_profile.master_out_channels = 2;
2373 bus_profile.input_ac = AutoConnectPhysical;
2374 bus_profile.output_ac = AutoConnectMaster;
2375 bus_profile.requested_physical_in = 0; // use all available
2376 bus_profile.requested_physical_out = 0; // use all available
2380 /* get settings from advanced section of NSD */
2382 if (_startup->create_master_bus()) {
2383 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2385 bus_profile.master_out_channels = 0;
2388 if (_startup->connect_inputs()) {
2389 bus_profile.input_ac = AutoConnectPhysical;
2391 bus_profile.input_ac = AutoConnectOption (0);
2394 /// @todo some minor tweaks.
2396 bus_profile.output_ac = AutoConnectOption (0);
2398 if (_startup->connect_outputs ()) {
2399 if (_startup->connect_outs_to_master()) {
2400 bus_profile.output_ac = AutoConnectMaster;
2401 } else if (_startup->connect_outs_to_physical()) {
2402 bus_profile.output_ac = AutoConnectPhysical;
2406 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2407 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2410 if (build_session (session_path, session_name, bus_profile)) {
2418 ARDOUR_UI::idle_load (const Glib::ustring& path)
2421 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2422 /* /path/to/foo => /path/to/foo, foo */
2423 load_session (path, basename_nosuffix (path));
2425 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2426 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2430 ARDOUR_COMMAND_LINE::session_name = path;
2433 * new_session_dialog doens't exist in A3
2434 * Try to remove all references to it to
2435 * see if it will compile. NOTE: this will
2436 * likely cause a runtime issue is my somewhat
2440 //if (new_session_dialog) {
2443 /* make it break out of Dialog::run() and
2447 //new_session_dialog->response (1);
2453 ARDOUR_UI::end_loading_messages ()
2459 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2462 // splash->message (msg);
2466 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2468 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2470 string session_name;
2471 string session_path;
2472 string template_name;
2474 bool likely_new = false;
2476 if (! load_template.empty()) {
2477 should_be_new = true;
2478 template_name = load_template;
2483 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2485 /* if they named a specific statefile, use it, otherwise they are
2486 just giving a session folder, and we want to use it as is
2487 to find the session.
2490 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2491 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2493 session_path = ARDOUR_COMMAND_LINE::session_name;
2496 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2500 bool const apply = run_startup (should_be_new, load_template);
2503 if (quit_on_cancel) {
2510 /* if we run the startup dialog again, offer more than just "new session" */
2512 should_be_new = false;
2514 session_name = _startup->session_name (likely_new);
2516 /* this shouldn't happen, but we catch it just in case it does */
2518 if (session_name.empty()) {
2522 if (_startup->use_session_template()) {
2523 template_name = _startup->session_template_name();
2524 _session_is_new = true;
2527 if (session_name[0] == G_DIR_SEPARATOR ||
2528 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2529 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2531 /* absolute path or cwd-relative path specified for session name: infer session folder
2532 from what was given.
2535 session_path = Glib::path_get_dirname (session_name);
2536 session_name = Glib::path_get_basename (session_name);
2540 session_path = _startup->session_folder();
2542 if (session_name.find ('/') != string::npos) {
2543 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2544 "session names may not contain a '/' character"));
2546 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2550 if (session_name.find ('\\') != string::npos) {
2551 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2552 "session names may not contain a '\\' character"));
2554 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2560 if (create_engine ()) {
2564 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2568 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2570 if (!ask_about_loading_existing_session (existing)) {
2571 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2576 _session_is_new = false;
2581 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2583 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2587 if (session_name.find ('/') != Glib::ustring::npos) {
2588 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2589 "session names may not contain a '/' character"));
2591 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2595 if (session_name.find ('\\') != Glib::ustring::npos) {
2596 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2597 "session names may not contain a '\\' character"));
2599 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2603 _session_is_new = true;
2606 if (likely_new && template_name.empty()) {
2608 ret = build_session_from_nsd (session_path, session_name);
2612 ret = load_session (session_path, session_name, template_name);
2613 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2614 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2624 ARDOUR_UI::close_session()
2626 if (!check_audioengine()) {
2630 if (unload_session (true)) {
2634 ARDOUR_COMMAND_LINE::session_name = "";
2636 if (get_session_parameters (true, false)) {
2640 goto_editor_window ();
2644 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2646 Session *new_session;
2650 session_loaded = false;
2652 if (!check_audioengine()) {
2656 unload_status = unload_session ();
2658 if (unload_status < 0) {
2660 } else if (unload_status > 0) {
2665 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2668 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2671 /* this one is special */
2673 catch (AudioEngine::PortRegistrationFailure& err) {
2675 MessageDialog msg (err.what(),
2678 Gtk::BUTTONS_CLOSE);
2680 msg.set_title (_("Port Registration Error"));
2681 msg.set_secondary_text (_("Click the Close button to try again."));
2682 msg.set_position (Gtk::WIN_POS_CENTER);
2686 int response = msg.run ();
2691 case RESPONSE_CANCEL:
2701 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2704 Gtk::BUTTONS_CLOSE);
2706 msg.set_title (_("Loading Error"));
2707 msg.set_secondary_text (_("Click the Close button to try again."));
2708 msg.set_position (Gtk::WIN_POS_CENTER);
2712 int response = msg.run ();
2717 case RESPONSE_CANCEL:
2725 /* Now the session been created, add the transport controls */
2726 new_session->add_controllable(roll_controllable);
2727 new_session->add_controllable(stop_controllable);
2728 new_session->add_controllable(goto_start_controllable);
2729 new_session->add_controllable(goto_end_controllable);
2730 new_session->add_controllable(auto_loop_controllable);
2731 new_session->add_controllable(play_selection_controllable);
2732 new_session->add_controllable(rec_controllable);
2734 set_session (new_session);
2736 session_loaded = true;
2738 goto_editor_window ();
2741 _session->set_clean ();
2752 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2754 Session *new_session;
2757 if (!check_audioengine()) {
2761 session_loaded = false;
2763 x = unload_session ();
2771 _session_is_new = true;
2774 new_session = new Session (*engine, path, snap_name, &bus_profile);
2779 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2785 /* Give the new session the default GUI state */
2786 new_session->add_instant_xml (*Config->instant_xml (X_("Editor")), false);
2787 new_session->add_instant_xml (*Config->instant_xml (X_("Mixer")), false);
2789 set_session (new_session);
2791 session_loaded = true;
2793 new_session->save_state(new_session->name());
2799 ARDOUR_UI::launch_chat ()
2802 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2804 open_uri("http://webchat.freenode.net/?channels=ardour");
2809 ARDOUR_UI::show_about ()
2813 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2816 about->set_transient_for(*editor);
2821 ARDOUR_UI::launch_manual ()
2823 PBD::open_uri("http://ardour.org/flossmanual");
2827 ARDOUR_UI::launch_reference ()
2829 PBD::open_uri("http://ardour.org/refmanual");
2833 ARDOUR_UI::hide_about ()
2836 about->get_window()->set_cursor ();
2842 ARDOUR_UI::about_signal_response (int /*response*/)
2848 ARDOUR_UI::show_splash ()
2852 splash = new Splash;
2860 splash->queue_draw ();
2861 splash->get_window()->process_updates (true);
2866 ARDOUR_UI::hide_splash ()
2874 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2875 const string& plural_msg, const string& singular_msg)
2879 removed = rep.paths.size();
2882 MessageDialog msgd (*editor,
2883 _("No audio files were ready for cleanup"),
2886 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2887 msgd.set_secondary_text (_("If this seems suprising, \n\
2888 check for any existing snapshots.\n\
2889 These may still include regions that\n\
2890 require some unused files to continue to exist."));
2896 ArdourDialog results (_("Clean-up"), true, false);
2898 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2899 CleanupResultsModelColumns() {
2903 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2904 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2908 CleanupResultsModelColumns results_columns;
2909 Glib::RefPtr<Gtk::ListStore> results_model;
2910 Gtk::TreeView results_display;
2912 results_model = ListStore::create (results_columns);
2913 results_display.set_model (results_model);
2914 results_display.append_column (list_title, results_columns.visible_name);
2916 results_display.set_name ("CleanupResultsList");
2917 results_display.set_headers_visible (true);
2918 results_display.set_headers_clickable (false);
2919 results_display.set_reorderable (false);
2921 Gtk::ScrolledWindow list_scroller;
2924 Gtk::HBox dhbox; // the hbox for the image and text
2925 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2926 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2928 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2930 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2933 %1 - number of files removed
2934 %2 - location of "dead_sounds"
2935 %3 - size of files affected
2936 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2939 const char* bprefix;
2940 double space_adjusted = 0;
2942 if (rep.space < 100000.0f) {
2943 bprefix = X_("kilo");
2944 } else if (rep.space < 1000000.0f * 1000) {
2945 bprefix = X_("mega");
2946 space_adjusted = truncf((float)rep.space / 1000.0);
2948 bprefix = X_("giga");
2949 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2953 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2955 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2958 dhbox.pack_start (*dimage, true, false, 5);
2959 dhbox.pack_start (txt, true, false, 5);
2961 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2962 TreeModel::Row row = *(results_model->append());
2963 row[results_columns.visible_name] = *i;
2964 row[results_columns.fullpath] = *i;
2967 list_scroller.add (results_display);
2968 list_scroller.set_size_request (-1, 150);
2969 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2971 dvbox.pack_start (dhbox, true, false, 5);
2972 dvbox.pack_start (list_scroller, true, false, 5);
2973 ddhbox.pack_start (dvbox, true, false, 5);
2975 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2976 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2977 results.set_default_response (RESPONSE_CLOSE);
2978 results.set_position (Gtk::WIN_POS_MOUSE);
2980 results_display.show();
2981 list_scroller.show();
2988 //results.get_vbox()->show();
2989 results.set_resizable (false);
2996 ARDOUR_UI::cleanup ()
2998 if (_session == 0) {
2999 /* shouldn't happen: menu item is insensitive */
3004 MessageDialog checker (_("Are you sure you want to cleanup?"),
3006 Gtk::MESSAGE_QUESTION,
3007 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3009 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3010 ALL undo/redo information will be lost if you cleanup.\n\
3011 After cleanup, unused audio files will be moved to a \
3012 \"dead sounds\" location."));
3014 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3015 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3016 checker.set_default_response (RESPONSE_CANCEL);
3018 checker.set_name (_("CleanupDialog"));
3019 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3020 checker.set_position (Gtk::WIN_POS_MOUSE);
3022 switch (checker.run()) {
3023 case RESPONSE_ACCEPT:
3029 ARDOUR::CleanupReport rep;
3031 editor->prepare_for_cleanup ();
3033 /* do not allow flush until a session is reloaded */
3035 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3037 act->set_sensitive (false);
3040 if (_session->cleanup_sources (rep)) {
3041 editor->finish_cleanup ();
3045 editor->finish_cleanup ();
3048 display_cleanup_results (rep,
3051 The following %1 files were not in use and \n\
3052 have been moved to:\n\
3054 Flushing the wastebasket will \n\
3055 release an additional\n\
3056 %3 %4bytes of disk space.\n"),
3058 The following file was not in use and \n \
3059 has been moved to:\n \
3061 Flushing the wastebasket will \n\
3062 release an additional\n\
3063 %3 %4bytes of disk space.\n"
3069 ARDOUR_UI::flush_trash ()
3071 if (_session == 0) {
3072 /* shouldn't happen: menu item is insensitive */
3076 ARDOUR::CleanupReport rep;
3078 if (_session->cleanup_trash_sources (rep)) {
3082 display_cleanup_results (rep,
3084 _("The following %1 files were deleted from\n\
3086 releasing %3 %4bytes of disk space"),
3087 _("The following file was deleted from\n\
3089 releasing %3 %4bytes of disk space"));
3093 ARDOUR_UI::add_route (Gtk::Window* float_window)
3101 if (add_route_dialog == 0) {
3102 add_route_dialog = new AddRouteDialog (_session);
3104 add_route_dialog->set_transient_for (*float_window);
3108 if (add_route_dialog->is_visible()) {
3109 /* we're already doing this */
3113 ResponseType r = (ResponseType) add_route_dialog->run ();
3115 add_route_dialog->hide();
3118 case RESPONSE_ACCEPT:
3125 if ((count = add_route_dialog->count()) <= 0) {
3129 string template_path = add_route_dialog->track_template();
3131 if (!template_path.empty()) {
3132 _session->new_route_from_template (count, template_path);
3136 uint32_t input_chan = add_route_dialog->channels ();
3137 uint32_t output_chan;
3138 string name_template = add_route_dialog->name_template ();
3139 bool track = add_route_dialog->track ();
3140 bool aux = !track && add_route_dialog->aux();
3141 RouteGroup* route_group = add_route_dialog->route_group ();
3143 AutoConnectOption oac = Config->get_output_auto_connect();
3145 if (oac & AutoConnectMaster) {
3146 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3148 output_chan = input_chan;
3151 /* XXX do something with name template */
3153 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3155 session_add_midi_track (route_group, count);
3157 MessageDialog msg (*editor,
3158 _("Sorry, MIDI Busses are not supported at this time."));
3160 //session_add_midi_bus();
3164 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3166 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3172 ARDOUR_UI::mixer_settings () const
3177 node = _session->instant_xml(X_("Mixer"));
3179 node = Config->instant_xml(X_("Mixer"));
3183 node = new XMLNode (X_("Mixer"));
3190 ARDOUR_UI::editor_settings () const
3195 node = _session->instant_xml(X_("Editor"));
3197 node = Config->instant_xml(X_("Editor"));
3201 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3202 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3207 node = new XMLNode (X_("Editor"));
3214 ARDOUR_UI::keyboard_settings () const
3218 node = Config->extra_xml(X_("Keyboard"));
3221 node = new XMLNode (X_("Keyboard"));
3227 ARDOUR_UI::create_xrun_marker(nframes_t where)
3229 editor->mouse_add_new_marker (where, false, true);
3233 ARDOUR_UI::halt_on_xrun_message ()
3235 MessageDialog msg (*editor,
3236 _("Recording was stopped because your system could not keep up."));
3241 ARDOUR_UI::xrun_handler(nframes_t where)
3247 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3249 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3250 create_xrun_marker(where);
3253 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3254 halt_on_xrun_message ();
3259 ARDOUR_UI::disk_overrun_handler ()
3261 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3263 if (!have_disk_speed_dialog_displayed) {
3264 have_disk_speed_dialog_displayed = true;
3265 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3266 The disk system on your computer\n\
3267 was not able to keep up with %1.\n\
3269 Specifically, it failed to write data to disk\n\
3270 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3271 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3277 ARDOUR_UI::disk_underrun_handler ()
3279 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3281 if (!have_disk_speed_dialog_displayed) {
3282 have_disk_speed_dialog_displayed = true;
3283 MessageDialog* msg = new MessageDialog (*editor,
3284 string_compose (_("The disk system on your computer\n\
3285 was not able to keep up with %1.\n\
3287 Specifically, it failed to read data from disk\n\
3288 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3289 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3295 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3297 have_disk_speed_dialog_displayed = false;
3302 ARDOUR_UI::session_dialog (std::string msg)
3304 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3309 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3311 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3320 ARDOUR_UI::pending_state_dialog ()
3322 HBox* hbox = new HBox();
3323 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3324 ArdourDialog dialog (_("Crash Recovery"), true);
3326 This session appears to have been in\n\
3327 middle of recording when ardour or\n\
3328 the computer was shutdown.\n\
3330 Ardour can recover any captured audio for\n\
3331 you, or it can ignore it. Please decide\n\
3332 what you would like to do.\n"));
3333 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3334 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3335 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3336 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3337 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3338 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3339 dialog.set_default_response (RESPONSE_ACCEPT);
3340 dialog.set_position (WIN_POS_CENTER);
3345 switch (dialog.run ()) {
3346 case RESPONSE_ACCEPT:
3354 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3356 HBox* hbox = new HBox();
3357 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3358 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3359 Label message (string_compose (_("\
3360 This session was created with a sample rate of %1 Hz\n\
3362 The audioengine is currently running at %2 Hz\n"), desired, actual));
3364 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3365 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3366 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3367 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3368 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3369 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3370 dialog.set_default_response (RESPONSE_ACCEPT);
3371 dialog.set_position (WIN_POS_CENTER);
3376 switch (dialog.run ()) {
3377 case RESPONSE_ACCEPT:
3386 ARDOUR_UI::disconnect_from_jack ()
3389 if( engine->disconnect_from_jack ()) {
3390 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3394 update_sample_rate (0);
3399 ARDOUR_UI::reconnect_to_jack ()
3402 if (engine->reconnect_to_jack ()) {
3403 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3407 update_sample_rate (0);
3412 ARDOUR_UI::use_config ()
3414 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3416 set_transport_controllable_state (*node);
3421 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3423 if (Config->get_primary_clock_delta_edit_cursor()) {
3424 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3426 primary_clock.set (pos, 0, true);
3429 if (Config->get_secondary_clock_delta_edit_cursor()) {
3430 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3432 secondary_clock.set (pos);
3435 if (big_clock_window->get()) {
3436 big_clock.set (pos);
3442 ARDOUR_UI::step_edit_status_change (bool yn)
3444 // XXX should really store pre-step edit status of things
3445 // we make insensitive
3448 rec_button.set_visual_state (3);
3449 rec_button.set_sensitive (false);
3451 rec_button.set_visual_state (0);
3452 rec_button.set_sensitive (true);
3457 ARDOUR_UI::record_state_changed ()
3459 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3461 if (!_session || !big_clock_window->get()) {
3462 /* why bother - the clock isn't visible */
3466 Session::RecordState const r = _session->record_status ();
3467 bool const h = _session->have_rec_enabled_track ();
3469 if (r == Session::Recording && h) {
3470 big_clock.set_widget_name ("BigClockRecording");
3472 big_clock.set_widget_name ("BigClockNonRecording");
3477 ARDOUR_UI::first_idle ()
3480 _session->allow_auto_play (true);
3484 editor->first_idle();
3487 Keyboard::set_can_save_keybindings (true);
3492 ARDOUR_UI::store_clock_modes ()
3494 XMLNode* node = new XMLNode(X_("ClockModes"));
3496 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3497 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3500 _session->add_extra_xml (*node);
3501 _session->set_dirty ();
3506 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3507 : Controllable (name), ui (u), type(tp)
3513 ARDOUR_UI::TransportControllable::set_value (double val)
3515 if (type == ShuttleControl) {
3522 fract = -((0.5 - val)/0.5);
3524 fract = ((val - 0.5)/0.5);
3528 ui.set_shuttle_fract (fract);
3533 /* do nothing: these are radio-style actions */
3537 const char *action = 0;
3541 action = X_("Roll");
3544 action = X_("Stop");
3547 action = X_("Goto Start");
3550 action = X_("Goto End");
3553 action = X_("Loop");
3556 action = X_("Play Selection");
3559 action = X_("Record");
3569 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3577 ARDOUR_UI::TransportControllable::get_value (void) const
3596 case ShuttleControl:
3606 ARDOUR_UI::TransportControllable::set_id (const string& str)
3612 ARDOUR_UI::setup_profile ()
3614 if (gdk_screen_width() < 1200) {
3615 Profile->set_small_screen ();
3619 if (getenv ("ARDOUR_SAE")) {
3620 Profile->set_sae ();
3621 Profile->set_single_package ();
3626 ARDOUR_UI::toggle_translations ()
3628 using namespace Glib;
3630 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3632 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3635 string i18n_killer = ARDOUR::translation_kill_path();
3637 bool already_enabled = !ARDOUR::translations_are_disabled ();
3639 if (ract->get_active ()) {
3640 /* we don't care about errors */
3641 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3644 /* we don't care about errors */
3645 unlink (i18n_killer.c_str());
3648 if (already_enabled != ract->get_active()) {
3649 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3651 Gtk::MESSAGE_WARNING,
3653 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3654 win.set_position (Gtk::WIN_POS_CENTER);
3662 /** Add a window proxy to our list, so that its state will be saved.
3663 * This call also causes the window to be created and opened if its
3664 * state was saved as `visible'.
3667 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3669 _window_proxies.push_back (p);
3673 /** Remove a window proxy from our list. Must be called if a WindowProxy
3674 * is deleted, to prevent hanging pointers.
3677 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3679 _window_proxies.remove (p);