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 original_big_clock_width = -1;
224 original_big_clock_height = -1;
225 original_big_clock_font_size = 0;
227 roll_button.unset_flags (Gtk::CAN_FOCUS);
228 stop_button.unset_flags (Gtk::CAN_FOCUS);
229 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
230 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
231 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
232 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
233 rec_button.unset_flags (Gtk::CAN_FOCUS);
235 last_configure_time= 0;
237 shuttle_grabbed = false;
239 shuttle_max_speed = 8.0f;
241 shuttle_style_menu = 0;
242 shuttle_unit_menu = 0;
244 // We do not have jack linked in yet so;
246 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
248 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
249 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
251 /* handle dialog requests */
253 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
255 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
257 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
259 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
261 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
263 /* handle requests to quit (coming from JACK session) */
265 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
267 /* lets get this party started */
270 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
271 throw failed_constructor ();
274 setup_gtk_ardour_enums ();
277 GainMeter::setup_slider_pix ();
278 RouteTimeAxisView::setup_slider_pix ();
279 SendProcessorEntry::setup_slider_pix ();
280 SessionEvent::create_per_thread_pool ("GUI", 512);
282 } catch (failed_constructor& err) {
283 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
288 /* we like keyboards */
290 keyboard = new ArdourKeyboard(*this);
292 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
294 keyboard->set_state (*node, Stateful::loading_state_version);
299 TimeAxisViewItem::set_constant_heights ();
301 /* The following must happen after ARDOUR::init() so that Config is set up */
303 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
304 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
306 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
307 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
308 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
309 Config->extra_xml (X_("UI")),
310 string_compose ("toggle-%1-connection-manager", (*i).to_string())
316 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
317 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
322 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
324 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
327 _startup = new ArdourStartup ();
329 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
331 if (audio_setup && _startup->engine_control()) {
332 _startup->engine_control()->set_state (*audio_setup);
335 _startup->set_new_only (should_be_new);
336 if (!load_template.empty()) {
337 _startup->set_load_template( load_template );
339 _startup->present ();
345 switch (_startup->response()) {
354 ARDOUR_UI::create_engine ()
356 // this gets called every time by new_session()
362 loading_message (_("Starting audio engine"));
365 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
372 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
373 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
374 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
376 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
378 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
386 ARDOUR_UI::post_engine ()
388 /* Things to be done once we create the AudioEngine
391 ARDOUR::init_post_engine ();
393 ActionManager::init ();
396 if (setup_windows ()) {
397 throw failed_constructor ();
400 check_memory_locking();
402 /* this is the first point at which all the keybindings are available */
404 if (ARDOUR_COMMAND_LINE::show_key_actions) {
405 vector<string> names;
406 vector<string> paths;
408 vector<AccelKey> bindings;
410 ActionManager::get_all_actions (names, paths, keys, bindings);
412 vector<string>::iterator n;
413 vector<string>::iterator k;
414 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
415 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
421 blink_timeout_tag = -1;
423 /* this being a GUI and all, we want peakfiles */
425 AudioFileSource::set_build_peakfiles (true);
426 AudioFileSource::set_build_missing_peakfiles (true);
428 /* set default clock modes */
430 if (Profile->get_sae()) {
431 primary_clock.set_mode (AudioClock::BBT);
432 secondary_clock.set_mode (AudioClock::MinSec);
434 primary_clock.set_mode (AudioClock::Timecode);
435 secondary_clock.set_mode (AudioClock::BBT);
438 /* start the time-of-day-clock */
441 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
442 update_wall_clock ();
443 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
446 update_disk_space ();
448 update_sample_rate (engine->frame_rate());
450 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
451 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
452 Config->map_parameters (pc);
454 /* now start and maybe save state */
456 if (do_engine_start () == 0) {
457 if (_session && _session_is_new) {
458 /* we need to retain initial visual
459 settings for a new session
461 _session->save_state ("");
466 ARDOUR_UI::~ARDOUR_UI ()
471 delete add_route_dialog;
475 ARDOUR_UI::pop_back_splash ()
477 if (Splash::instance()) {
478 // Splash::instance()->pop_back();
479 Splash::instance()->hide ();
484 ARDOUR_UI::configure_timeout ()
486 if (last_configure_time == 0) {
487 /* no configure events yet */
491 /* force a gap of 0.5 seconds since the last configure event
494 if (get_microseconds() - last_configure_time < 500000) {
497 have_configure_timeout = false;
498 cerr << "config event-driven save\n";
499 save_ardour_state ();
505 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
507 if (have_configure_timeout) {
508 last_configure_time = get_microseconds();
510 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
511 have_configure_timeout = true;
518 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
520 const XMLProperty* prop;
522 if ((prop = node.property ("roll")) != 0) {
523 roll_controllable->set_id (prop->value());
525 if ((prop = node.property ("stop")) != 0) {
526 stop_controllable->set_id (prop->value());
528 if ((prop = node.property ("goto-start")) != 0) {
529 goto_start_controllable->set_id (prop->value());
531 if ((prop = node.property ("goto-end")) != 0) {
532 goto_end_controllable->set_id (prop->value());
534 if ((prop = node.property ("auto-loop")) != 0) {
535 auto_loop_controllable->set_id (prop->value());
537 if ((prop = node.property ("play-selection")) != 0) {
538 play_selection_controllable->set_id (prop->value());
540 if ((prop = node.property ("rec")) != 0) {
541 rec_controllable->set_id (prop->value());
543 if ((prop = node.property ("shuttle")) != 0) {
544 shuttle_controllable->set_id (prop->value());
549 ARDOUR_UI::get_transport_controllable_state ()
551 XMLNode* node = new XMLNode(X_("TransportControllables"));
554 roll_controllable->id().print (buf, sizeof (buf));
555 node->add_property (X_("roll"), buf);
556 stop_controllable->id().print (buf, sizeof (buf));
557 node->add_property (X_("stop"), buf);
558 goto_start_controllable->id().print (buf, sizeof (buf));
559 node->add_property (X_("goto_start"), buf);
560 goto_end_controllable->id().print (buf, sizeof (buf));
561 node->add_property (X_("goto_end"), buf);
562 auto_loop_controllable->id().print (buf, sizeof (buf));
563 node->add_property (X_("auto_loop"), buf);
564 play_selection_controllable->id().print (buf, sizeof (buf));
565 node->add_property (X_("play_selection"), buf);
566 rec_controllable->id().print (buf, sizeof (buf));
567 node->add_property (X_("rec"), buf);
568 shuttle_controllable->id().print (buf, sizeof (buf));
569 node->add_property (X_("shuttle"), buf);
576 ARDOUR_UI::autosave_session ()
578 if (g_main_depth() > 1) {
579 /* inside a recursive main loop,
580 give up because we may not be able to
586 if (!Config->get_periodic_safety_backups()) {
591 _session->maybe_write_autosave();
598 ARDOUR_UI::update_autosave ()
600 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
602 if (_session && _session->dirty()) {
603 if (_autosave_connection.connected()) {
604 _autosave_connection.disconnect();
607 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
608 Config->get_periodic_safety_backup_interval() * 1000);
611 if (_autosave_connection.connected()) {
612 _autosave_connection.disconnect();
618 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
622 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
624 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
627 MessageDialog win (title,
633 win.set_secondary_text(_("There are several possible reasons:\n\
635 1) You requested audio parameters that are not supported..\n\
636 2) JACK is running as another user.\n\
638 Please consider the possibilities, and perhaps try different parameters."));
640 win.set_secondary_text(_("There are several possible reasons:\n\
642 1) JACK is not running.\n\
643 2) JACK is running as another user, perhaps root.\n\
644 3) There is already another client called \"ardour\".\n\
646 Please consider the possibilities, and perhaps (re)start JACK."));
650 win.set_transient_for (*toplevel);
654 win.add_button (Stock::OK, RESPONSE_CLOSE);
656 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
659 win.set_default_response (RESPONSE_CLOSE);
662 win.set_position (Gtk::WIN_POS_CENTER);
665 /* we just don't care about the result, but we want to block */
671 ARDOUR_UI::startup ()
673 Application* app = Application::instance ();
675 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
676 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
679 call_the_mothership (VERSIONSTRING);
684 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
690 goto_editor_window ();
692 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
693 to be opened on top of the editor window that goto_editor_window() just opened.
695 add_window_proxy (location_ui);
696 add_window_proxy (big_clock_window);
697 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
698 add_window_proxy (_global_port_matrix[*i]);
701 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
705 ARDOUR_UI::no_memory_warning ()
707 XMLNode node (X_("no-memory-warning"));
708 Config->add_instant_xml (node);
712 ARDOUR_UI::check_memory_locking ()
715 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
719 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
721 if (engine->is_realtime() && memory_warning_node == 0) {
723 struct rlimit limits;
725 long pages, page_size;
727 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
730 ram = (int64_t) pages * (int64_t) page_size;
733 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
737 if (limits.rlim_cur != RLIM_INFINITY) {
739 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
742 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
743 "This might cause %1 to run out of memory before your system "
744 "runs out of memory. \n\n"
745 "You can view the memory limit with 'ulimit -l', "
746 "and it is normally controlled by /etc/security/limits.conf"),
747 PROGRAM_NAME).c_str());
749 VBox* vbox = msg.get_vbox();
751 CheckButton cb (_("Do not show this window again"));
753 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
755 hbox.pack_start (cb, true, false);
756 vbox->pack_start (hbox);
763 editor->ensure_float (msg);
773 ARDOUR_UI::queue_finish ()
775 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
779 ARDOUR_UI::idle_finish ()
782 return false; /* do not call again */
791 if (_session->transport_rolling() && (++tries < 8)) {
792 _session->request_stop (false, true);
796 if (_session->dirty()) {
797 switch (ask_about_saving_session(_("quit"))) {
802 /* use the default name */
803 if (save_state_canfail ("")) {
804 /* failed - don't quit */
805 MessageDialog msg (*editor,
807 Ardour was unable to save your session.\n\n\
808 If you still wish to quit, please use the\n\n\
809 \"Just quit\" option."));
820 second_connection.disconnect ();
821 point_one_second_connection.disconnect ();
822 point_oh_five_second_connection.disconnect ();
823 point_zero_one_second_connection.disconnect();
826 /* Save state before deleting the session, as that causes some
827 windows to be destroyed before their visible state can be
830 save_ardour_state ();
833 // _session->set_deletion_in_progress ();
834 _session->set_clean ();
835 _session->remove_pending_capture_state ();
840 ArdourDialog::close_all_dialogs ();
846 ARDOUR_UI::ask_about_saving_session (const string & what)
848 ArdourDialog window (_("Unsaved Session"));
849 Gtk::HBox dhbox; // the hbox for the image and text
850 Gtk::Label prompt_label;
851 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
855 msg = string_compose(_("Don't %1"), what);
856 window.add_button (msg, RESPONSE_REJECT);
857 msg = string_compose(_("Just %1"), what);
858 window.add_button (msg, RESPONSE_APPLY);
859 msg = string_compose(_("Save and %1"), what);
860 window.add_button (msg, RESPONSE_ACCEPT);
862 window.set_default_response (RESPONSE_ACCEPT);
864 Gtk::Button noquit_button (msg);
865 noquit_button.set_name ("EditorGTKButton");
870 if (_session->snap_name() == _session->name()) {
873 type = _("snapshot");
875 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?"),
876 type, _session->snap_name());
878 prompt_label.set_text (prompt);
879 prompt_label.set_name (X_("PrompterLabel"));
880 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
882 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
883 dhbox.set_homogeneous (false);
884 dhbox.pack_start (*dimage, false, false, 5);
885 dhbox.pack_start (prompt_label, true, false, 5);
886 window.get_vbox()->pack_start (dhbox);
888 window.set_name (_("Prompter"));
889 window.set_position (Gtk::WIN_POS_MOUSE);
890 window.set_modal (true);
891 window.set_resizable (false);
897 window.set_keep_above (true);
900 ResponseType r = (ResponseType) window.run();
905 case RESPONSE_ACCEPT: // save and get out of here
907 case RESPONSE_APPLY: // get out of here
917 ARDOUR_UI::every_second ()
920 update_buffer_load ();
921 update_disk_space ();
926 ARDOUR_UI::every_point_one_seconds ()
928 update_speed_display ();
929 RapidScreenUpdate(); /* EMIT_SIGNAL */
934 ARDOUR_UI::every_point_zero_one_seconds ()
936 // august 2007: actual update frequency: 40Hz, not 100Hz
938 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
943 ARDOUR_UI::update_sample_rate (nframes_t)
947 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
949 if (!engine->connected()) {
951 snprintf (buf, sizeof (buf), _("disconnected"));
955 nframes_t rate = engine->frame_rate();
957 if (fmod (rate, 1000.0) != 0.0) {
958 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
959 (float) rate/1000.0f,
960 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
962 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
964 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
968 sample_rate_label.set_text (buf);
972 ARDOUR_UI::update_cpu_load ()
975 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
976 cpu_load_label.set_text (buf);
980 ARDOUR_UI::update_buffer_load ()
986 c = _session->capture_load ();
987 p = _session->playback_load ();
989 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
990 _session->playback_load(), _session->capture_load());
991 buffer_load_label.set_text (buf);
993 buffer_load_label.set_text ("");
998 ARDOUR_UI::count_recenabled_streams (Route& route)
1000 Track* track = dynamic_cast<Track*>(&route);
1001 if (track && track->record_enabled()) {
1002 rec_enabled_streams += track->n_inputs().n_total();
1007 ARDOUR_UI::update_disk_space()
1009 if (_session == 0) {
1013 framecnt_t frames = _session->available_capture_duration();
1015 nframes_t fr = _session->frame_rate();
1017 if (frames == max_framecnt) {
1018 strcpy (buf, _("Disk: 24hrs+"));
1020 rec_enabled_streams = 0;
1021 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1023 if (rec_enabled_streams) {
1024 frames /= rec_enabled_streams;
1031 hrs = frames / (fr * 3600);
1032 frames -= hrs * fr * 3600;
1033 mins = frames / (fr * 60);
1034 frames -= mins * fr * 60;
1037 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1040 disk_space_label.set_text (buf);
1042 // An attempt to make the disk space label flash red when space has run out.
1044 if (frames < fr * 60 * 5) {
1045 /* disk_space_box.style ("disk_space_label_empty"); */
1047 /* disk_space_box.style ("disk_space_label"); */
1053 ARDOUR_UI::update_wall_clock ()
1060 tm_now = localtime (&now);
1062 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1063 wall_clock_label.set_text (buf);
1069 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1071 session_popup_menu->popup (0, 0);
1076 ARDOUR_UI::redisplay_recent_sessions ()
1078 std::vector<sys::path> session_directories;
1079 RecentSessionsSorter cmp;
1081 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1082 recent_session_model->clear ();
1084 ARDOUR::RecentSessions rs;
1085 ARDOUR::read_recent_sessions (rs);
1088 recent_session_display.set_model (recent_session_model);
1092 // sort them alphabetically
1093 sort (rs.begin(), rs.end(), cmp);
1095 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1096 session_directories.push_back ((*i).second);
1099 for (vector<sys::path>::const_iterator i = session_directories.begin();
1100 i != session_directories.end(); ++i)
1102 std::vector<sys::path> state_file_paths;
1104 // now get available states for this session
1106 get_state_files_in_directory (*i, state_file_paths);
1108 vector<string*>* states;
1109 vector<const gchar*> item;
1110 string fullpath = (*i).to_string();
1112 /* remove any trailing / */
1114 if (fullpath[fullpath.length()-1] == '/') {
1115 fullpath = fullpath.substr (0, fullpath.length()-1);
1118 /* check whether session still exists */
1119 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1120 /* session doesn't exist */
1121 cerr << "skipping non-existent session " << fullpath << endl;
1125 /* now get available states for this session */
1127 if ((states = Session::possible_states (fullpath)) == 0) {
1128 /* no state file? */
1132 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1134 Gtk::TreeModel::Row row = *(recent_session_model->append());
1136 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1137 row[recent_session_columns.fullpath] = fullpath;
1139 if (state_file_names.size() > 1) {
1143 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1144 i2 != state_file_names.end(); ++i2)
1147 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1149 child_row[recent_session_columns.visible_name] = *i2;
1150 child_row[recent_session_columns.fullpath] = fullpath;
1155 recent_session_display.set_model (recent_session_model);
1159 ARDOUR_UI::build_session_selector ()
1161 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1163 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1165 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1166 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1167 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1168 recent_session_model = TreeStore::create (recent_session_columns);
1169 recent_session_display.set_model (recent_session_model);
1170 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1171 recent_session_display.set_headers_visible (false);
1172 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1173 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1175 scroller->add (recent_session_display);
1176 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1178 session_selector_window->set_name ("SessionSelectorWindow");
1179 session_selector_window->set_size_request (200, 400);
1180 session_selector_window->get_vbox()->pack_start (*scroller);
1182 recent_session_display.show();
1184 //session_selector_window->get_vbox()->show();
1188 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1190 session_selector_window->response (RESPONSE_ACCEPT);
1194 ARDOUR_UI::open_recent_session ()
1196 bool can_return = (_session != 0);
1198 if (session_selector_window == 0) {
1199 build_session_selector ();
1202 redisplay_recent_sessions ();
1206 session_selector_window->set_position (WIN_POS_MOUSE);
1208 ResponseType r = (ResponseType) session_selector_window->run ();
1211 case RESPONSE_ACCEPT:
1215 session_selector_window->hide();
1222 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1226 session_selector_window->hide();
1228 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1230 if (i == recent_session_model->children().end()) {
1234 std::string path = (*i)[recent_session_columns.fullpath];
1235 std::string state = (*i)[recent_session_columns.visible_name];
1237 _session_is_new = false;
1239 if (load_session (path, state) == 0) {
1248 ARDOUR_UI::check_audioengine ()
1251 if (!engine->connected()) {
1252 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1253 "You cannot open or close sessions in this condition"),
1266 ARDOUR_UI::open_session ()
1268 if (!check_audioengine()) {
1273 /* popup selector window */
1275 if (open_session_selector == 0) {
1277 /* ardour sessions are folders */
1279 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1280 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1281 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1282 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1284 FileFilter session_filter;
1285 session_filter.add_pattern ("*.ardour");
1286 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1287 open_session_selector->add_filter (session_filter);
1288 open_session_selector->set_filter (session_filter);
1291 int response = open_session_selector->run();
1292 open_session_selector->hide ();
1295 case RESPONSE_ACCEPT:
1298 open_session_selector->hide();
1302 open_session_selector->hide();
1303 string session_path = open_session_selector->get_filename();
1307 if (session_path.length() > 0) {
1308 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1309 _session_is_new = isnew;
1310 load_session (path, name);
1317 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1319 list<boost::shared_ptr<MidiTrack> > tracks;
1321 if (_session == 0) {
1322 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1329 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1331 if (tracks.size() != how_many) {
1332 if (how_many == 1) {
1333 error << _("could not create a new midi track") << endmsg;
1335 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1339 if ((route = _session->new_midi_route ()) == 0) {
1340 error << _("could not create new midi bus") << endmsg;
1346 MessageDialog msg (*editor,
1347 string_compose (_("There are insufficient JACK ports available\n\
1348 to create a new track or bus.\n\
1349 You should save %1, exit and\n\
1350 restart JACK with more ports."), PROGRAM_NAME));
1357 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)
1359 list<boost::shared_ptr<AudioTrack> > tracks;
1362 if (_session == 0) {
1363 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1369 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1371 if (tracks.size() != how_many) {
1372 if (how_many == 1) {
1373 error << _("could not create a new audio track") << endmsg;
1375 error << string_compose (_("could only create %1 of %2 new audio %3"),
1376 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1382 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1384 if (routes.size() != how_many) {
1385 if (how_many == 1) {
1386 error << _("could not create a new audio track") << endmsg;
1388 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1395 MessageDialog msg (*editor,
1396 string_compose (_("There are insufficient JACK ports available\n\
1397 to create a new track or bus.\n\
1398 You should save %1, exit and\n\
1399 restart JACK with more ports."), PROGRAM_NAME));
1406 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1408 nframes_t _preroll = 0;
1411 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1412 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1414 if (new_position > _preroll) {
1415 new_position -= _preroll;
1420 _session->request_locate (new_position);
1425 ARDOUR_UI::transport_goto_start ()
1428 _session->goto_start();
1430 /* force displayed area in editor to start no matter
1431 what "follow playhead" setting is.
1435 editor->center_screen (_session->current_start_frame ());
1441 ARDOUR_UI::transport_goto_zero ()
1444 _session->request_locate (0);
1446 /* force displayed area in editor to start no matter
1447 what "follow playhead" setting is.
1451 editor->reset_x_origin (0);
1457 ARDOUR_UI::transport_goto_wallclock ()
1459 if (_session && editor) {
1466 localtime_r (&now, &tmnow);
1468 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1469 frames += tmnow.tm_min * (60 * _session->frame_rate());
1470 frames += tmnow.tm_sec * _session->frame_rate();
1472 _session->request_locate (frames, _session->transport_rolling ());
1474 /* force displayed area in editor to start no matter
1475 what "follow playhead" setting is.
1479 editor->center_screen (frames);
1485 ARDOUR_UI::transport_goto_end ()
1488 nframes_t const frame = _session->current_end_frame();
1489 _session->request_locate (frame);
1491 /* force displayed area in editor to start no matter
1492 what "follow playhead" setting is.
1496 editor->center_screen (frame);
1502 ARDOUR_UI::transport_stop ()
1508 if (_session->is_auditioning()) {
1509 _session->cancel_audition ();
1513 _session->request_stop (false, true);
1517 ARDOUR_UI::transport_stop_and_forget_capture ()
1520 _session->request_stop (true, true);
1525 ARDOUR_UI::remove_last_capture()
1528 editor->remove_last_capture();
1533 ARDOUR_UI::transport_record (bool roll)
1537 switch (_session->record_status()) {
1538 case Session::Disabled:
1539 if (_session->ntracks() == 0) {
1540 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1544 _session->maybe_enable_record ();
1549 case Session::Recording:
1551 _session->request_stop();
1553 _session->disable_record (false, true);
1557 case Session::Enabled:
1558 _session->disable_record (false, true);
1561 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1565 ARDOUR_UI::transport_roll ()
1571 if (_session->is_auditioning()) {
1575 if (_session->config.get_external_sync()) {
1576 switch (_session->config.get_sync_source()) {
1580 /* transport controlled by the master */
1585 bool rolling = _session->transport_rolling();
1587 if (_session->get_play_loop()) {
1588 /* XXX it is not possible to just leave seamless loop and keep
1589 playing at present (nov 4th 2009)
1591 if (!Config->get_seamless_loop()) {
1592 _session->request_play_loop (false, true);
1594 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1595 /* stop playing a range if we currently are */
1596 _session->request_play_range (0, true);
1599 if (join_play_range_button.get_active()) {
1600 _session->request_play_range (&editor->get_selection().time, true);
1604 _session->request_transport_speed (1.0f);
1609 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1616 if (_session->is_auditioning()) {
1617 _session->cancel_audition ();
1621 if (_session->config.get_external_sync()) {
1622 switch (_session->config.get_sync_source()) {
1626 /* transport controlled by the master */
1631 bool rolling = _session->transport_rolling();
1632 bool affect_transport = true;
1634 if (rolling && roll_out_of_bounded_mode) {
1635 /* drop out of loop/range playback but leave transport rolling */
1636 if (_session->get_play_loop()) {
1637 if (Config->get_seamless_loop()) {
1638 /* the disk buffers contain copies of the loop - we can't
1639 just keep playing, so stop the transport. the user
1640 can restart as they wish.
1642 affect_transport = true;
1644 /* disk buffers are normal, so we can keep playing */
1645 affect_transport = false;
1647 _session->request_play_loop (false, true);
1648 } else if (_session->get_play_range ()) {
1649 affect_transport = false;
1650 _session->request_play_range (0, true);
1654 if (affect_transport) {
1656 _session->request_stop (with_abort, true);
1658 if (join_play_range_button.get_active()) {
1659 _session->request_play_range (&editor->get_selection().time, true);
1662 _session->request_transport_speed (1.0f);
1668 ARDOUR_UI::toggle_session_auto_loop ()
1671 if (_session->get_play_loop()) {
1672 if (_session->transport_rolling()) {
1673 Location * looploc = _session->locations()->auto_loop_location();
1675 _session->request_locate (looploc->start(), true);
1678 _session->request_play_loop (false);
1681 Location * looploc = _session->locations()->auto_loop_location();
1683 _session->request_play_loop (true);
1690 ARDOUR_UI::transport_play_selection ()
1696 editor->play_selection ();
1700 ARDOUR_UI::transport_rewind (int option)
1702 float current_transport_speed;
1705 current_transport_speed = _session->transport_speed();
1707 if (current_transport_speed >= 0.0f) {
1710 _session->request_transport_speed (-1.0f);
1713 _session->request_transport_speed (-4.0f);
1716 _session->request_transport_speed (-0.5f);
1721 _session->request_transport_speed (current_transport_speed * 1.5f);
1727 ARDOUR_UI::transport_forward (int option)
1729 float current_transport_speed;
1732 current_transport_speed = _session->transport_speed();
1734 if (current_transport_speed <= 0.0f) {
1737 _session->request_transport_speed (1.0f);
1740 _session->request_transport_speed (4.0f);
1743 _session->request_transport_speed (0.5f);
1748 _session->request_transport_speed (current_transport_speed * 1.5f);
1755 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1757 if (_session == 0) {
1761 boost::shared_ptr<Route> r;
1763 if ((r = _session->route_by_remote_id (rid)) != 0) {
1767 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1768 t->set_record_enabled (!t->record_enabled(), this);
1771 if (_session == 0) {
1777 ARDOUR_UI::map_transport_state ()
1779 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1782 auto_loop_button.set_visual_state (0);
1783 play_selection_button.set_visual_state (0);
1784 roll_button.set_visual_state (0);
1785 stop_button.set_visual_state (1);
1789 float sp = _session->transport_speed();
1792 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1793 shuttle_box.queue_draw ();
1794 } else if (sp == 0.0f) {
1796 shuttle_box.queue_draw ();
1797 update_disk_space ();
1804 if (_session->get_play_range()) {
1806 play_selection_button.set_visual_state (1);
1807 roll_button.set_visual_state (0);
1808 auto_loop_button.set_visual_state (0);
1810 } else if (_session->get_play_loop ()) {
1812 auto_loop_button.set_visual_state (1);
1813 play_selection_button.set_visual_state (0);
1814 roll_button.set_visual_state (0);
1818 roll_button.set_visual_state (1);
1819 play_selection_button.set_visual_state (0);
1820 auto_loop_button.set_visual_state (0);
1823 if (join_play_range_button.get_active()) {
1824 /* light up both roll and play-selection if they are joined */
1825 roll_button.set_visual_state (1);
1826 play_selection_button.set_visual_state (1);
1829 stop_button.set_visual_state (0);
1833 stop_button.set_visual_state (1);
1834 roll_button.set_visual_state (0);
1835 play_selection_button.set_visual_state (0);
1836 auto_loop_button.set_visual_state (0);
1841 ARDOUR_UI::engine_stopped ()
1843 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1844 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1845 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1849 ARDOUR_UI::engine_running ()
1851 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1852 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1853 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1855 Glib::RefPtr<Action> action;
1856 const char* action_name = 0;
1858 switch (engine->frames_per_cycle()) {
1860 action_name = X_("JACKLatency32");
1863 action_name = X_("JACKLatency64");
1866 action_name = X_("JACKLatency128");
1869 action_name = X_("JACKLatency512");
1872 action_name = X_("JACKLatency1024");
1875 action_name = X_("JACKLatency2048");
1878 action_name = X_("JACKLatency4096");
1881 action_name = X_("JACKLatency8192");
1884 /* XXX can we do anything useful ? */
1890 action = ActionManager::get_action (X_("JACK"), action_name);
1893 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1894 ract->set_active ();
1900 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1902 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1903 /* we can't rely on the original string continuing to exist when we are called
1904 again in the GUI thread, so make a copy and note that we need to
1907 char *copy = strdup (reason);
1908 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1912 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1913 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1915 update_sample_rate (0);
1919 /* if the reason is a non-empty string, it means that the backend was shutdown
1920 rather than just Ardour.
1923 if (strlen (reason)) {
1924 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1926 msgstr = string_compose (_("\
1927 JACK has either been shutdown or it\n\
1928 disconnected %1 because %1\n\
1929 was not fast enough. Try to restart\n\
1930 JACK, reconnect and save the session."), PROGRAM_NAME);
1933 MessageDialog msg (*editor, msgstr);
1938 free ((char*) reason);
1943 ARDOUR_UI::do_engine_start ()
1951 error << _("Unable to start the session running")
1961 ARDOUR_UI::setup_theme ()
1963 theme_manager->setup_theme();
1967 ARDOUR_UI::update_clocks ()
1969 if (!editor || !editor->dragging_playhead()) {
1970 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1975 ARDOUR_UI::start_clocking ()
1977 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1981 ARDOUR_UI::stop_clocking ()
1983 clock_signal_connection.disconnect ();
1987 ARDOUR_UI::toggle_clocking ()
1990 if (clock_button.get_active()) {
1999 ARDOUR_UI::_blink (void *arg)
2002 ((ARDOUR_UI *) arg)->blink ();
2009 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2013 ARDOUR_UI::start_blinking ()
2015 /* Start the blink signal. Everybody with a blinking widget
2016 uses Blink to drive the widget's state.
2019 if (blink_timeout_tag < 0) {
2021 blink_timeout_tag = g_timeout_add (240, _blink, this);
2026 ARDOUR_UI::stop_blinking ()
2028 if (blink_timeout_tag >= 0) {
2029 g_source_remove (blink_timeout_tag);
2030 blink_timeout_tag = -1;
2035 /** Ask the user for the name of a new shapshot and then take it.
2039 ARDOUR_UI::snapshot_session (bool switch_to_it)
2041 ArdourPrompter prompter (true);
2044 prompter.set_name ("Prompter");
2045 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2046 prompter.set_title (_("Take Snapshot"));
2047 prompter.set_title (_("Take Snapshot"));
2048 prompter.set_prompt (_("Name of new snapshot"));
2050 if (!switch_to_it) {
2053 struct tm local_time;
2056 localtime_r (&n, &local_time);
2057 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2058 prompter.set_initial_text (timebuf);
2062 switch (prompter.run()) {
2063 case RESPONSE_ACCEPT:
2065 prompter.get_result (snapname);
2067 bool do_save = (snapname.length() != 0);
2070 if (snapname.find ('/') != string::npos) {
2071 MessageDialog msg (_("To ensure compatibility with various systems\n"
2072 "snapshot names may not contain a '/' character"));
2076 if (snapname.find ('\\') != string::npos) {
2077 MessageDialog msg (_("To ensure compatibility with various systems\n"
2078 "snapshot names may not contain a '\\' character"));
2084 vector<sys::path> p;
2085 get_state_files_in_directory (_session->session_directory().root_path(), p);
2086 vector<string> n = get_file_names_no_extension (p);
2087 if (find (n.begin(), n.end(), snapname) != n.end()) {
2089 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2090 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2091 confirm.get_vbox()->pack_start (m, true, true);
2092 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2093 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2094 confirm.show_all ();
2095 switch (confirm.run()) {
2096 case RESPONSE_CANCEL:
2102 save_state (snapname, switch_to_it);
2113 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2115 XMLNode* node = new XMLNode (X_("UI"));
2117 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2118 if (!(*i)->rc_configured()) {
2119 node->add_child_nocopy (*((*i)->get_state ()));
2123 _session->add_extra_xml (*node);
2125 save_state_canfail (name, switch_to_it);
2129 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2134 if (name.length() == 0) {
2135 name = _session->snap_name();
2138 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2142 cerr << "SS canfail\n";
2143 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2148 ARDOUR_UI::primary_clock_value_changed ()
2151 _session->request_locate (primary_clock.current_time ());
2156 ARDOUR_UI::big_clock_value_changed ()
2159 _session->request_locate (big_clock.current_time ());
2164 ARDOUR_UI::secondary_clock_value_changed ()
2167 _session->request_locate (secondary_clock.current_time ());
2172 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2174 if (_session == 0) {
2178 if (_session->step_editing()) {
2182 Session::RecordState const r = _session->record_status ();
2183 bool const h = _session->have_rec_enabled_track ();
2185 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2187 rec_button.set_visual_state (2);
2189 rec_button.set_visual_state (0);
2191 } else if (r == Session::Recording && h) {
2192 rec_button.set_visual_state (1);
2194 rec_button.set_visual_state (0);
2199 ARDOUR_UI::save_template ()
2201 ArdourPrompter prompter (true);
2204 if (!check_audioengine()) {
2208 prompter.set_name (X_("Prompter"));
2209 prompter.set_title (_("Save Mix Template"));
2210 prompter.set_prompt (_("Name for mix template:"));
2211 prompter.set_initial_text(_session->name() + _("-template"));
2212 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2214 switch (prompter.run()) {
2215 case RESPONSE_ACCEPT:
2216 prompter.get_result (name);
2218 if (name.length()) {
2219 _session->save_template (name);
2229 ARDOUR_UI::edit_metadata ()
2231 SessionMetadataEditor dialog;
2232 dialog.set_session (_session);
2233 editor->ensure_float (dialog);
2238 ARDOUR_UI::import_metadata ()
2240 SessionMetadataImporter dialog;
2241 dialog.set_session (_session);
2242 editor->ensure_float (dialog);
2247 ARDOUR_UI::fontconfig_dialog ()
2250 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2251 may not and it can take a while to build it. Warn them.
2254 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2256 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2257 MessageDialog msg (*_startup,
2258 string_compose (_("Welcome to %1.\n\n"
2259 "The program will take a bit longer to start up\n"
2260 "while the system fonts are checked.\n\n"
2261 "This will only be done once, and you will\n"
2262 "not see this message again\n"), PROGRAM_NAME),
2275 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2277 existing_session = false;
2279 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2280 session_path = cmdline_path;
2281 existing_session = true;
2282 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2283 session_path = Glib::path_get_dirname (string (cmdline_path));
2284 existing_session = true;
2286 /* it doesn't exist, assume the best */
2287 session_path = Glib::path_get_dirname (string (cmdline_path));
2290 session_name = basename_nosuffix (string (cmdline_path));
2294 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2296 /* when this is called, the backend audio system must be running */
2298 /* the main idea here is to deal with the fact that a cmdline argument for the session
2299 can be interpreted in different ways - it could be a directory or a file, and before
2300 we load, we need to know both the session directory and the snapshot (statefile) within it
2301 that we are supposed to use.
2304 if (session_name.length() == 0 || session_path.length() == 0) {
2308 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2310 std::string predicted_session_file;
2312 predicted_session_file = session_path;
2313 predicted_session_file += '/';
2314 predicted_session_file += session_name;
2315 predicted_session_file += ARDOUR::statefile_suffix;
2317 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2318 existing_session = true;
2321 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2323 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2324 /* existing .ardour file */
2325 existing_session = true;
2329 existing_session = false;
2332 /* lets just try to load it */
2334 if (create_engine ()) {
2335 backend_audio_error (false, _startup);
2339 return load_session (session_path, session_name);
2343 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2345 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2347 MessageDialog msg (str,
2349 Gtk::MESSAGE_WARNING,
2350 Gtk::BUTTONS_YES_NO,
2354 msg.set_name (X_("OpenExistingDialog"));
2355 msg.set_title (_("Open Existing Session"));
2356 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2357 msg.set_position (Gtk::WIN_POS_MOUSE);
2360 switch (msg.run()) {
2369 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2371 BusProfile bus_profile;
2373 if (Profile->get_sae()) {
2375 bus_profile.master_out_channels = 2;
2376 bus_profile.input_ac = AutoConnectPhysical;
2377 bus_profile.output_ac = AutoConnectMaster;
2378 bus_profile.requested_physical_in = 0; // use all available
2379 bus_profile.requested_physical_out = 0; // use all available
2383 /* get settings from advanced section of NSD */
2385 if (_startup->create_master_bus()) {
2386 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2388 bus_profile.master_out_channels = 0;
2391 if (_startup->connect_inputs()) {
2392 bus_profile.input_ac = AutoConnectPhysical;
2394 bus_profile.input_ac = AutoConnectOption (0);
2397 /// @todo some minor tweaks.
2399 bus_profile.output_ac = AutoConnectOption (0);
2401 if (_startup->connect_outputs ()) {
2402 if (_startup->connect_outs_to_master()) {
2403 bus_profile.output_ac = AutoConnectMaster;
2404 } else if (_startup->connect_outs_to_physical()) {
2405 bus_profile.output_ac = AutoConnectPhysical;
2409 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2410 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2413 if (build_session (session_path, session_name, bus_profile)) {
2421 ARDOUR_UI::idle_load (const std::string& path)
2424 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2425 /* /path/to/foo => /path/to/foo, foo */
2426 load_session (path, basename_nosuffix (path));
2428 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2429 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2433 ARDOUR_COMMAND_LINE::session_name = path;
2436 * new_session_dialog doens't exist in A3
2437 * Try to remove all references to it to
2438 * see if it will compile. NOTE: this will
2439 * likely cause a runtime issue is my somewhat
2443 //if (new_session_dialog) {
2446 /* make it break out of Dialog::run() and
2450 //new_session_dialog->response (1);
2456 ARDOUR_UI::end_loading_messages ()
2462 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2465 // splash->message (msg);
2469 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2471 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2473 string session_name;
2474 string session_path;
2475 string template_name;
2477 bool likely_new = false;
2479 if (! load_template.empty()) {
2480 should_be_new = true;
2481 template_name = load_template;
2486 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2488 /* if they named a specific statefile, use it, otherwise they are
2489 just giving a session folder, and we want to use it as is
2490 to find the session.
2493 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2494 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2496 session_path = ARDOUR_COMMAND_LINE::session_name;
2499 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2503 bool const apply = run_startup (should_be_new, load_template);
2506 if (quit_on_cancel) {
2513 /* if we run the startup dialog again, offer more than just "new session" */
2515 should_be_new = false;
2517 session_name = _startup->session_name (likely_new);
2519 /* this shouldn't happen, but we catch it just in case it does */
2521 if (session_name.empty()) {
2525 if (_startup->use_session_template()) {
2526 template_name = _startup->session_template_name();
2527 _session_is_new = true;
2530 if (session_name[0] == G_DIR_SEPARATOR ||
2531 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2532 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2534 /* absolute path or cwd-relative path specified for session name: infer session folder
2535 from what was given.
2538 session_path = Glib::path_get_dirname (session_name);
2539 session_name = Glib::path_get_basename (session_name);
2543 session_path = _startup->session_folder();
2545 if (session_name.find ('/') != string::npos) {
2546 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2547 "session names may not contain a '/' character"));
2549 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2553 if (session_name.find ('\\') != string::npos) {
2554 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2555 "session names may not contain a '\\' character"));
2557 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2563 if (create_engine ()) {
2567 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2571 std::string existing = Glib::build_filename (session_path, session_name);
2573 if (!ask_about_loading_existing_session (existing)) {
2574 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2579 _session_is_new = false;
2584 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2586 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2590 if (session_name.find ('/') != std::string::npos) {
2591 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2592 "session names may not contain a '/' character"));
2594 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2598 if (session_name.find ('\\') != std::string::npos) {
2599 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2600 "session names may not contain a '\\' character"));
2602 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2606 _session_is_new = true;
2609 if (likely_new && template_name.empty()) {
2611 ret = build_session_from_nsd (session_path, session_name);
2615 ret = load_session (session_path, session_name, template_name);
2616 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2617 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2627 ARDOUR_UI::close_session()
2629 if (!check_audioengine()) {
2633 if (unload_session (true)) {
2637 ARDOUR_COMMAND_LINE::session_name = "";
2639 if (get_session_parameters (true, false)) {
2643 goto_editor_window ();
2647 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2649 Session *new_session;
2653 session_loaded = false;
2655 if (!check_audioengine()) {
2659 unload_status = unload_session ();
2661 if (unload_status < 0) {
2663 } else if (unload_status > 0) {
2668 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2671 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2674 /* this one is special */
2676 catch (AudioEngine::PortRegistrationFailure& err) {
2678 MessageDialog msg (err.what(),
2681 Gtk::BUTTONS_CLOSE);
2683 msg.set_title (_("Port Registration Error"));
2684 msg.set_secondary_text (_("Click the Close button to try again."));
2685 msg.set_position (Gtk::WIN_POS_CENTER);
2689 int response = msg.run ();
2694 case RESPONSE_CANCEL:
2704 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2707 Gtk::BUTTONS_CLOSE);
2709 msg.set_title (_("Loading Error"));
2710 msg.set_secondary_text (_("Click the Close button to try again."));
2711 msg.set_position (Gtk::WIN_POS_CENTER);
2715 int response = msg.run ();
2720 case RESPONSE_CANCEL:
2728 /* Now the session been created, add the transport controls */
2729 new_session->add_controllable(roll_controllable);
2730 new_session->add_controllable(stop_controllable);
2731 new_session->add_controllable(goto_start_controllable);
2732 new_session->add_controllable(goto_end_controllable);
2733 new_session->add_controllable(auto_loop_controllable);
2734 new_session->add_controllable(play_selection_controllable);
2735 new_session->add_controllable(rec_controllable);
2737 set_session (new_session);
2739 session_loaded = true;
2741 goto_editor_window ();
2744 _session->set_clean ();
2755 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2757 Session *new_session;
2760 if (!check_audioengine()) {
2764 session_loaded = false;
2766 x = unload_session ();
2774 _session_is_new = true;
2777 new_session = new Session (*engine, path, snap_name, &bus_profile);
2782 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2788 /* Give the new session the default GUI state, if such things exist */
2791 n = Config->instant_xml (X_("Editor"));
2793 new_session->add_instant_xml (*n, false);
2795 n = Config->instant_xml (X_("Mixer"));
2797 new_session->add_instant_xml (*n, false);
2800 set_session (new_session);
2802 session_loaded = true;
2804 new_session->save_state(new_session->name());
2810 ARDOUR_UI::launch_chat ()
2813 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2815 open_uri("http://webchat.freenode.net/?channels=ardour");
2820 ARDOUR_UI::show_about ()
2824 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2827 about->set_transient_for(*editor);
2832 ARDOUR_UI::launch_manual ()
2834 PBD::open_uri("http://ardour.org/flossmanual");
2838 ARDOUR_UI::launch_reference ()
2840 PBD::open_uri("http://ardour.org/refmanual");
2844 ARDOUR_UI::hide_about ()
2847 about->get_window()->set_cursor ();
2853 ARDOUR_UI::about_signal_response (int /*response*/)
2859 ARDOUR_UI::show_splash ()
2863 splash = new Splash;
2871 splash->queue_draw ();
2872 splash->get_window()->process_updates (true);
2877 ARDOUR_UI::hide_splash ()
2885 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2886 const string& plural_msg, const string& singular_msg)
2890 removed = rep.paths.size();
2893 MessageDialog msgd (*editor,
2894 _("No audio files were ready for cleanup"),
2897 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2898 msgd.set_secondary_text (_("If this seems suprising, \n\
2899 check for any existing snapshots.\n\
2900 These may still include regions that\n\
2901 require some unused files to continue to exist."));
2907 ArdourDialog results (_("Clean-up"), true, false);
2909 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2910 CleanupResultsModelColumns() {
2914 Gtk::TreeModelColumn<std::string> visible_name;
2915 Gtk::TreeModelColumn<std::string> fullpath;
2919 CleanupResultsModelColumns results_columns;
2920 Glib::RefPtr<Gtk::ListStore> results_model;
2921 Gtk::TreeView results_display;
2923 results_model = ListStore::create (results_columns);
2924 results_display.set_model (results_model);
2925 results_display.append_column (list_title, results_columns.visible_name);
2927 results_display.set_name ("CleanupResultsList");
2928 results_display.set_headers_visible (true);
2929 results_display.set_headers_clickable (false);
2930 results_display.set_reorderable (false);
2932 Gtk::ScrolledWindow list_scroller;
2935 Gtk::HBox dhbox; // the hbox for the image and text
2936 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2937 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2939 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2941 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2944 %1 - number of files removed
2945 %2 - location of "dead_sounds"
2946 %3 - size of files affected
2947 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2950 const char* bprefix;
2951 double space_adjusted = 0;
2953 if (rep.space < 100000.0f) {
2954 bprefix = X_("kilo");
2955 } else if (rep.space < 1000000.0f * 1000) {
2956 bprefix = X_("mega");
2957 space_adjusted = truncf((float)rep.space / 1000.0);
2959 bprefix = X_("giga");
2960 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2964 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2966 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2969 dhbox.pack_start (*dimage, true, false, 5);
2970 dhbox.pack_start (txt, true, false, 5);
2972 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2973 TreeModel::Row row = *(results_model->append());
2974 row[results_columns.visible_name] = *i;
2975 row[results_columns.fullpath] = *i;
2978 list_scroller.add (results_display);
2979 list_scroller.set_size_request (-1, 150);
2980 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2982 dvbox.pack_start (dhbox, true, false, 5);
2983 dvbox.pack_start (list_scroller, true, false, 5);
2984 ddhbox.pack_start (dvbox, true, false, 5);
2986 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2987 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2988 results.set_default_response (RESPONSE_CLOSE);
2989 results.set_position (Gtk::WIN_POS_MOUSE);
2991 results_display.show();
2992 list_scroller.show();
2999 //results.get_vbox()->show();
3000 results.set_resizable (false);
3007 ARDOUR_UI::cleanup ()
3009 if (_session == 0) {
3010 /* shouldn't happen: menu item is insensitive */
3015 MessageDialog checker (_("Are you sure you want to cleanup?"),
3017 Gtk::MESSAGE_QUESTION,
3018 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3020 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3021 ALL undo/redo information will be lost if you cleanup.\n\
3022 After cleanup, unused audio files will be moved to a \
3023 \"dead sounds\" location."));
3025 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3026 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3027 checker.set_default_response (RESPONSE_CANCEL);
3029 checker.set_name (_("CleanupDialog"));
3030 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3031 checker.set_position (Gtk::WIN_POS_MOUSE);
3033 switch (checker.run()) {
3034 case RESPONSE_ACCEPT:
3040 ARDOUR::CleanupReport rep;
3042 editor->prepare_for_cleanup ();
3044 /* do not allow flush until a session is reloaded */
3046 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3048 act->set_sensitive (false);
3051 if (_session->cleanup_sources (rep)) {
3052 editor->finish_cleanup ();
3056 editor->finish_cleanup ();
3059 display_cleanup_results (rep,
3062 The following %1 files were not in use and \n\
3063 have been moved to:\n\
3065 Flushing the wastebasket will \n\
3066 release an additional\n\
3067 %3 %4bytes of disk space.\n"),
3069 The following file was not in use and \n \
3070 has been moved to:\n \
3072 Flushing the wastebasket will \n\
3073 release an additional\n\
3074 %3 %4bytes of disk space.\n"
3080 ARDOUR_UI::flush_trash ()
3082 if (_session == 0) {
3083 /* shouldn't happen: menu item is insensitive */
3087 ARDOUR::CleanupReport rep;
3089 if (_session->cleanup_trash_sources (rep)) {
3093 display_cleanup_results (rep,
3095 _("The following %1 files were deleted from\n\
3097 releasing %3 %4bytes of disk space"),
3098 _("The following file was deleted from\n\
3100 releasing %3 %4bytes of disk space"));
3104 ARDOUR_UI::add_route (Gtk::Window* float_window)
3112 if (add_route_dialog == 0) {
3113 add_route_dialog = new AddRouteDialog (_session);
3115 add_route_dialog->set_transient_for (*float_window);
3119 if (add_route_dialog->is_visible()) {
3120 /* we're already doing this */
3124 ResponseType r = (ResponseType) add_route_dialog->run ();
3126 add_route_dialog->hide();
3129 case RESPONSE_ACCEPT:
3136 if ((count = add_route_dialog->count()) <= 0) {
3140 string template_path = add_route_dialog->track_template();
3142 if (!template_path.empty()) {
3143 _session->new_route_from_template (count, template_path);
3147 uint32_t input_chan = add_route_dialog->channels ();
3148 uint32_t output_chan;
3149 string name_template = add_route_dialog->name_template ();
3150 bool track = add_route_dialog->track ();
3151 bool aux = !track && add_route_dialog->aux();
3152 RouteGroup* route_group = add_route_dialog->route_group ();
3154 AutoConnectOption oac = Config->get_output_auto_connect();
3156 if (oac & AutoConnectMaster) {
3157 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3159 output_chan = input_chan;
3162 /* XXX do something with name template */
3164 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3166 session_add_midi_track (route_group, count);
3168 MessageDialog msg (*editor,
3169 _("Sorry, MIDI Busses are not supported at this time."));
3171 //session_add_midi_bus();
3175 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3177 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3183 ARDOUR_UI::mixer_settings () const
3188 node = _session->instant_xml(X_("Mixer"));
3190 node = Config->instant_xml(X_("Mixer"));
3194 node = new XMLNode (X_("Mixer"));
3201 ARDOUR_UI::editor_settings () const
3206 node = _session->instant_xml(X_("Editor"));
3208 node = Config->instant_xml(X_("Editor"));
3212 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3213 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3218 node = new XMLNode (X_("Editor"));
3225 ARDOUR_UI::keyboard_settings () const
3229 node = Config->extra_xml(X_("Keyboard"));
3232 node = new XMLNode (X_("Keyboard"));
3238 ARDOUR_UI::create_xrun_marker(nframes_t where)
3240 editor->mouse_add_new_marker (where, false, true);
3244 ARDOUR_UI::halt_on_xrun_message ()
3246 MessageDialog msg (*editor,
3247 _("Recording was stopped because your system could not keep up."));
3252 ARDOUR_UI::xrun_handler(nframes_t where)
3258 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3260 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3261 create_xrun_marker(where);
3264 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3265 halt_on_xrun_message ();
3270 ARDOUR_UI::disk_overrun_handler ()
3272 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3274 if (!have_disk_speed_dialog_displayed) {
3275 have_disk_speed_dialog_displayed = true;
3276 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3277 The disk system on your computer\n\
3278 was not able to keep up with %1.\n\
3280 Specifically, it failed to write data to disk\n\
3281 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3282 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3288 ARDOUR_UI::disk_underrun_handler ()
3290 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3292 if (!have_disk_speed_dialog_displayed) {
3293 have_disk_speed_dialog_displayed = true;
3294 MessageDialog* msg = new MessageDialog (*editor,
3295 string_compose (_("The disk system on your computer\n\
3296 was not able to keep up with %1.\n\
3298 Specifically, it failed to read data from disk\n\
3299 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3300 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3306 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3308 have_disk_speed_dialog_displayed = false;
3313 ARDOUR_UI::session_dialog (std::string msg)
3315 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3320 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3322 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3331 ARDOUR_UI::pending_state_dialog ()
3333 HBox* hbox = new HBox();
3334 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3335 ArdourDialog dialog (_("Crash Recovery"), true);
3337 This session appears to have been in\n\
3338 middle of recording when ardour or\n\
3339 the computer was shutdown.\n\
3341 Ardour can recover any captured audio for\n\
3342 you, or it can ignore it. Please decide\n\
3343 what you would like to do.\n"));
3344 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3345 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3346 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3347 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3348 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3349 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3350 dialog.set_default_response (RESPONSE_ACCEPT);
3351 dialog.set_position (WIN_POS_CENTER);
3356 switch (dialog.run ()) {
3357 case RESPONSE_ACCEPT:
3365 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3367 HBox* hbox = new HBox();
3368 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3369 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3370 Label message (string_compose (_("\
3371 This session was created with a sample rate of %1 Hz\n\
3373 The audioengine is currently running at %2 Hz\n"), desired, actual));
3375 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3376 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3377 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3378 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3379 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3380 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3381 dialog.set_default_response (RESPONSE_ACCEPT);
3382 dialog.set_position (WIN_POS_CENTER);
3387 switch (dialog.run ()) {
3388 case RESPONSE_ACCEPT:
3397 ARDOUR_UI::disconnect_from_jack ()
3400 if( engine->disconnect_from_jack ()) {
3401 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3405 update_sample_rate (0);
3410 ARDOUR_UI::reconnect_to_jack ()
3413 if (engine->reconnect_to_jack ()) {
3414 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3418 update_sample_rate (0);
3423 ARDOUR_UI::use_config ()
3425 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3427 set_transport_controllable_state (*node);
3432 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3434 if (Config->get_primary_clock_delta_edit_cursor()) {
3435 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3437 primary_clock.set (pos, 0, true);
3440 if (Config->get_secondary_clock_delta_edit_cursor()) {
3441 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3443 secondary_clock.set (pos);
3446 if (big_clock_window->get()) {
3447 big_clock.set (pos);
3453 ARDOUR_UI::step_edit_status_change (bool yn)
3455 // XXX should really store pre-step edit status of things
3456 // we make insensitive
3459 rec_button.set_visual_state (3);
3460 rec_button.set_sensitive (false);
3462 rec_button.set_visual_state (0);
3463 rec_button.set_sensitive (true);
3468 ARDOUR_UI::record_state_changed ()
3470 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3472 if (!_session || !big_clock_window->get()) {
3473 /* why bother - the clock isn't visible */
3477 Session::RecordState const r = _session->record_status ();
3478 bool const h = _session->have_rec_enabled_track ();
3480 if (r == Session::Recording && h) {
3481 big_clock.set_widget_name ("BigClockRecording");
3483 big_clock.set_widget_name ("BigClockNonRecording");
3488 ARDOUR_UI::first_idle ()
3491 _session->allow_auto_play (true);
3495 editor->first_idle();
3498 Keyboard::set_can_save_keybindings (true);
3503 ARDOUR_UI::store_clock_modes ()
3505 XMLNode* node = new XMLNode(X_("ClockModes"));
3507 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3508 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3511 _session->add_extra_xml (*node);
3512 _session->set_dirty ();
3517 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3518 : Controllable (name), ui (u), type(tp)
3524 ARDOUR_UI::TransportControllable::set_value (double val)
3526 if (type == ShuttleControl) {
3533 fract = -((0.5 - val)/0.5);
3535 fract = ((val - 0.5)/0.5);
3539 ui.set_shuttle_fract (fract);
3544 /* do nothing: these are radio-style actions */
3548 const char *action = 0;
3552 action = X_("Roll");
3555 action = X_("Stop");
3558 action = X_("Goto Start");
3561 action = X_("Goto End");
3564 action = X_("Loop");
3567 action = X_("Play Selection");
3570 action = X_("Record");
3580 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3588 ARDOUR_UI::TransportControllable::get_value (void) const
3607 case ShuttleControl:
3617 ARDOUR_UI::TransportControllable::set_id (const string& str)
3623 ARDOUR_UI::setup_profile ()
3625 if (gdk_screen_width() < 1200) {
3626 Profile->set_small_screen ();
3630 if (getenv ("ARDOUR_SAE")) {
3631 Profile->set_sae ();
3632 Profile->set_single_package ();
3637 ARDOUR_UI::toggle_translations ()
3639 using namespace Glib;
3641 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3643 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3646 string i18n_killer = ARDOUR::translation_kill_path();
3648 bool already_enabled = !ARDOUR::translations_are_disabled ();
3650 if (ract->get_active ()) {
3651 /* we don't care about errors */
3652 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3655 /* we don't care about errors */
3656 unlink (i18n_killer.c_str());
3659 if (already_enabled != ract->get_active()) {
3660 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3662 Gtk::MESSAGE_WARNING,
3664 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3665 win.set_position (Gtk::WIN_POS_CENTER);
3673 /** Add a window proxy to our list, so that its state will be saved.
3674 * This call also causes the window to be created and opened if its
3675 * state was saved as `visible'.
3678 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3680 _window_proxies.push_back (p);
3684 /** Remove a window proxy from our list. Must be called if a WindowProxy
3685 * is deleted, to prevent hanging pointers.
3688 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3690 _window_proxies.remove (p);