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 std::string path = (*i)[recent_session_columns.fullpath];
1232 std::string 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 std::string 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 std::string& cmdline_path, std::string& session_name, std::string& 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 std::string& session_name, const std::string& 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 std::string 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 std::string& session_path)
2342 std::string 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 std::string& session_path, const std::string& 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 std::string& 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 std::string 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 ('/') != std::string::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 ('\\') != std::string::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 std::string& path, const std::string& snap_name, std::string 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 std::string& path, const std::string& 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, if such things exist */
2788 n = Config->instant_xml (X_("Editor"));
2790 new_session->add_instant_xml (*n, false);
2792 n = Config->instant_xml (X_("Mixer"));
2794 new_session->add_instant_xml (*n, false);
2797 set_session (new_session);
2799 session_loaded = true;
2801 new_session->save_state(new_session->name());
2807 ARDOUR_UI::launch_chat ()
2810 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2812 open_uri("http://webchat.freenode.net/?channels=ardour");
2817 ARDOUR_UI::show_about ()
2821 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2824 about->set_transient_for(*editor);
2829 ARDOUR_UI::launch_manual ()
2831 PBD::open_uri("http://ardour.org/flossmanual");
2835 ARDOUR_UI::launch_reference ()
2837 PBD::open_uri("http://ardour.org/refmanual");
2841 ARDOUR_UI::hide_about ()
2844 about->get_window()->set_cursor ();
2850 ARDOUR_UI::about_signal_response (int /*response*/)
2856 ARDOUR_UI::show_splash ()
2860 splash = new Splash;
2868 splash->queue_draw ();
2869 splash->get_window()->process_updates (true);
2874 ARDOUR_UI::hide_splash ()
2882 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2883 const string& plural_msg, const string& singular_msg)
2887 removed = rep.paths.size();
2890 MessageDialog msgd (*editor,
2891 _("No audio files were ready for cleanup"),
2894 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2895 msgd.set_secondary_text (_("If this seems suprising, \n\
2896 check for any existing snapshots.\n\
2897 These may still include regions that\n\
2898 require some unused files to continue to exist."));
2904 ArdourDialog results (_("Clean-up"), true, false);
2906 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2907 CleanupResultsModelColumns() {
2911 Gtk::TreeModelColumn<std::string> visible_name;
2912 Gtk::TreeModelColumn<std::string> fullpath;
2916 CleanupResultsModelColumns results_columns;
2917 Glib::RefPtr<Gtk::ListStore> results_model;
2918 Gtk::TreeView results_display;
2920 results_model = ListStore::create (results_columns);
2921 results_display.set_model (results_model);
2922 results_display.append_column (list_title, results_columns.visible_name);
2924 results_display.set_name ("CleanupResultsList");
2925 results_display.set_headers_visible (true);
2926 results_display.set_headers_clickable (false);
2927 results_display.set_reorderable (false);
2929 Gtk::ScrolledWindow list_scroller;
2932 Gtk::HBox dhbox; // the hbox for the image and text
2933 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2934 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2936 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2938 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2941 %1 - number of files removed
2942 %2 - location of "dead_sounds"
2943 %3 - size of files affected
2944 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2947 const char* bprefix;
2948 double space_adjusted = 0;
2950 if (rep.space < 100000.0f) {
2951 bprefix = X_("kilo");
2952 } else if (rep.space < 1000000.0f * 1000) {
2953 bprefix = X_("mega");
2954 space_adjusted = truncf((float)rep.space / 1000.0);
2956 bprefix = X_("giga");
2957 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2961 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2963 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2966 dhbox.pack_start (*dimage, true, false, 5);
2967 dhbox.pack_start (txt, true, false, 5);
2969 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2970 TreeModel::Row row = *(results_model->append());
2971 row[results_columns.visible_name] = *i;
2972 row[results_columns.fullpath] = *i;
2975 list_scroller.add (results_display);
2976 list_scroller.set_size_request (-1, 150);
2977 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2979 dvbox.pack_start (dhbox, true, false, 5);
2980 dvbox.pack_start (list_scroller, true, false, 5);
2981 ddhbox.pack_start (dvbox, true, false, 5);
2983 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2984 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2985 results.set_default_response (RESPONSE_CLOSE);
2986 results.set_position (Gtk::WIN_POS_MOUSE);
2988 results_display.show();
2989 list_scroller.show();
2996 //results.get_vbox()->show();
2997 results.set_resizable (false);
3004 ARDOUR_UI::cleanup ()
3006 if (_session == 0) {
3007 /* shouldn't happen: menu item is insensitive */
3012 MessageDialog checker (_("Are you sure you want to cleanup?"),
3014 Gtk::MESSAGE_QUESTION,
3015 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3017 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3018 ALL undo/redo information will be lost if you cleanup.\n\
3019 After cleanup, unused audio files will be moved to a \
3020 \"dead sounds\" location."));
3022 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3023 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3024 checker.set_default_response (RESPONSE_CANCEL);
3026 checker.set_name (_("CleanupDialog"));
3027 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3028 checker.set_position (Gtk::WIN_POS_MOUSE);
3030 switch (checker.run()) {
3031 case RESPONSE_ACCEPT:
3037 ARDOUR::CleanupReport rep;
3039 editor->prepare_for_cleanup ();
3041 /* do not allow flush until a session is reloaded */
3043 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3045 act->set_sensitive (false);
3048 if (_session->cleanup_sources (rep)) {
3049 editor->finish_cleanup ();
3053 editor->finish_cleanup ();
3056 display_cleanup_results (rep,
3059 The following %1 files were not in use and \n\
3060 have been moved to:\n\
3062 Flushing the wastebasket will \n\
3063 release an additional\n\
3064 %3 %4bytes of disk space.\n"),
3066 The following file was not in use and \n \
3067 has been moved to:\n \
3069 Flushing the wastebasket will \n\
3070 release an additional\n\
3071 %3 %4bytes of disk space.\n"
3077 ARDOUR_UI::flush_trash ()
3079 if (_session == 0) {
3080 /* shouldn't happen: menu item is insensitive */
3084 ARDOUR::CleanupReport rep;
3086 if (_session->cleanup_trash_sources (rep)) {
3090 display_cleanup_results (rep,
3092 _("The following %1 files were deleted from\n\
3094 releasing %3 %4bytes of disk space"),
3095 _("The following file was deleted from\n\
3097 releasing %3 %4bytes of disk space"));
3101 ARDOUR_UI::add_route (Gtk::Window* float_window)
3109 if (add_route_dialog == 0) {
3110 add_route_dialog = new AddRouteDialog (_session);
3112 add_route_dialog->set_transient_for (*float_window);
3116 if (add_route_dialog->is_visible()) {
3117 /* we're already doing this */
3121 ResponseType r = (ResponseType) add_route_dialog->run ();
3123 add_route_dialog->hide();
3126 case RESPONSE_ACCEPT:
3133 if ((count = add_route_dialog->count()) <= 0) {
3137 string template_path = add_route_dialog->track_template();
3139 if (!template_path.empty()) {
3140 _session->new_route_from_template (count, template_path);
3144 uint32_t input_chan = add_route_dialog->channels ();
3145 uint32_t output_chan;
3146 string name_template = add_route_dialog->name_template ();
3147 bool track = add_route_dialog->track ();
3148 bool aux = !track && add_route_dialog->aux();
3149 RouteGroup* route_group = add_route_dialog->route_group ();
3151 AutoConnectOption oac = Config->get_output_auto_connect();
3153 if (oac & AutoConnectMaster) {
3154 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3156 output_chan = input_chan;
3159 /* XXX do something with name template */
3161 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3163 session_add_midi_track (route_group, count);
3165 MessageDialog msg (*editor,
3166 _("Sorry, MIDI Busses are not supported at this time."));
3168 //session_add_midi_bus();
3172 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3174 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3180 ARDOUR_UI::mixer_settings () const
3185 node = _session->instant_xml(X_("Mixer"));
3187 node = Config->instant_xml(X_("Mixer"));
3191 node = new XMLNode (X_("Mixer"));
3198 ARDOUR_UI::editor_settings () const
3203 node = _session->instant_xml(X_("Editor"));
3205 node = Config->instant_xml(X_("Editor"));
3209 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3210 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3215 node = new XMLNode (X_("Editor"));
3222 ARDOUR_UI::keyboard_settings () const
3226 node = Config->extra_xml(X_("Keyboard"));
3229 node = new XMLNode (X_("Keyboard"));
3235 ARDOUR_UI::create_xrun_marker(nframes_t where)
3237 editor->mouse_add_new_marker (where, false, true);
3241 ARDOUR_UI::halt_on_xrun_message ()
3243 MessageDialog msg (*editor,
3244 _("Recording was stopped because your system could not keep up."));
3249 ARDOUR_UI::xrun_handler(nframes_t where)
3255 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3257 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3258 create_xrun_marker(where);
3261 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3262 halt_on_xrun_message ();
3267 ARDOUR_UI::disk_overrun_handler ()
3269 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3271 if (!have_disk_speed_dialog_displayed) {
3272 have_disk_speed_dialog_displayed = true;
3273 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3274 The disk system on your computer\n\
3275 was not able to keep up with %1.\n\
3277 Specifically, it failed to write data to disk\n\
3278 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3279 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3285 ARDOUR_UI::disk_underrun_handler ()
3287 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3289 if (!have_disk_speed_dialog_displayed) {
3290 have_disk_speed_dialog_displayed = true;
3291 MessageDialog* msg = new MessageDialog (*editor,
3292 string_compose (_("The disk system on your computer\n\
3293 was not able to keep up with %1.\n\
3295 Specifically, it failed to read data from disk\n\
3296 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3297 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3303 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3305 have_disk_speed_dialog_displayed = false;
3310 ARDOUR_UI::session_dialog (std::string msg)
3312 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3317 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3319 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3328 ARDOUR_UI::pending_state_dialog ()
3330 HBox* hbox = new HBox();
3331 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3332 ArdourDialog dialog (_("Crash Recovery"), true);
3334 This session appears to have been in\n\
3335 middle of recording when ardour or\n\
3336 the computer was shutdown.\n\
3338 Ardour can recover any captured audio for\n\
3339 you, or it can ignore it. Please decide\n\
3340 what you would like to do.\n"));
3341 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3342 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3343 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3344 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3345 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3346 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3347 dialog.set_default_response (RESPONSE_ACCEPT);
3348 dialog.set_position (WIN_POS_CENTER);
3353 switch (dialog.run ()) {
3354 case RESPONSE_ACCEPT:
3362 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3364 HBox* hbox = new HBox();
3365 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3366 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3367 Label message (string_compose (_("\
3368 This session was created with a sample rate of %1 Hz\n\
3370 The audioengine is currently running at %2 Hz\n"), desired, actual));
3372 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3373 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3374 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3375 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3376 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3377 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3378 dialog.set_default_response (RESPONSE_ACCEPT);
3379 dialog.set_position (WIN_POS_CENTER);
3384 switch (dialog.run ()) {
3385 case RESPONSE_ACCEPT:
3394 ARDOUR_UI::disconnect_from_jack ()
3397 if( engine->disconnect_from_jack ()) {
3398 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3402 update_sample_rate (0);
3407 ARDOUR_UI::reconnect_to_jack ()
3410 if (engine->reconnect_to_jack ()) {
3411 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3415 update_sample_rate (0);
3420 ARDOUR_UI::use_config ()
3422 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3424 set_transport_controllable_state (*node);
3429 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3431 if (Config->get_primary_clock_delta_edit_cursor()) {
3432 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3434 primary_clock.set (pos, 0, true);
3437 if (Config->get_secondary_clock_delta_edit_cursor()) {
3438 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3440 secondary_clock.set (pos);
3443 if (big_clock_window->get()) {
3444 big_clock.set (pos);
3450 ARDOUR_UI::step_edit_status_change (bool yn)
3452 // XXX should really store pre-step edit status of things
3453 // we make insensitive
3456 rec_button.set_visual_state (3);
3457 rec_button.set_sensitive (false);
3459 rec_button.set_visual_state (0);
3460 rec_button.set_sensitive (true);
3465 ARDOUR_UI::record_state_changed ()
3467 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3469 if (!_session || !big_clock_window->get()) {
3470 /* why bother - the clock isn't visible */
3474 Session::RecordState const r = _session->record_status ();
3475 bool const h = _session->have_rec_enabled_track ();
3477 if (r == Session::Recording && h) {
3478 big_clock.set_widget_name ("BigClockRecording");
3480 big_clock.set_widget_name ("BigClockNonRecording");
3485 ARDOUR_UI::first_idle ()
3488 _session->allow_auto_play (true);
3492 editor->first_idle();
3495 Keyboard::set_can_save_keybindings (true);
3500 ARDOUR_UI::store_clock_modes ()
3502 XMLNode* node = new XMLNode(X_("ClockModes"));
3504 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3505 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3508 _session->add_extra_xml (*node);
3509 _session->set_dirty ();
3514 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3515 : Controllable (name), ui (u), type(tp)
3521 ARDOUR_UI::TransportControllable::set_value (double val)
3523 if (type == ShuttleControl) {
3530 fract = -((0.5 - val)/0.5);
3532 fract = ((val - 0.5)/0.5);
3536 ui.set_shuttle_fract (fract);
3541 /* do nothing: these are radio-style actions */
3545 const char *action = 0;
3549 action = X_("Roll");
3552 action = X_("Stop");
3555 action = X_("Goto Start");
3558 action = X_("Goto End");
3561 action = X_("Loop");
3564 action = X_("Play Selection");
3567 action = X_("Record");
3577 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3585 ARDOUR_UI::TransportControllable::get_value (void) const
3604 case ShuttleControl:
3614 ARDOUR_UI::TransportControllable::set_id (const string& str)
3620 ARDOUR_UI::setup_profile ()
3622 if (gdk_screen_width() < 1200) {
3623 Profile->set_small_screen ();
3627 if (getenv ("ARDOUR_SAE")) {
3628 Profile->set_sae ();
3629 Profile->set_single_package ();
3634 ARDOUR_UI::toggle_translations ()
3636 using namespace Glib;
3638 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3640 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3643 string i18n_killer = ARDOUR::translation_kill_path();
3645 bool already_enabled = !ARDOUR::translations_are_disabled ();
3647 if (ract->get_active ()) {
3648 /* we don't care about errors */
3649 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3652 /* we don't care about errors */
3653 unlink (i18n_killer.c_str());
3656 if (already_enabled != ract->get_active()) {
3657 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3659 Gtk::MESSAGE_WARNING,
3661 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3662 win.set_position (Gtk::WIN_POS_CENTER);
3670 /** Add a window proxy to our list, so that its state will be saved.
3671 * This call also causes the window to be created and opened if its
3672 * state was saved as `visible'.
3675 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3677 _window_proxies.push_back (p);
3681 /** Remove a window proxy from our list. Must be called if a WindowProxy
3682 * is deleted, to prevent hanging pointers.
3685 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3687 _window_proxies.remove (p);