2 Copyright (C) 1999-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #define __STDC_FORMAT_MACROS 1
34 #include <sys/resource.h>
36 #include <gtkmm/messagedialog.h>
37 #include <gtkmm/accelmap.h>
39 #include "pbd/error.h"
40 #include "pbd/basename.h"
41 #include "pbd/compose.h"
42 #include "pbd/failed_constructor.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/openuri.h"
46 #include "pbd/file_utils.h"
48 #include "gtkmm2ext/gtk_ui.h"
49 #include "gtkmm2ext/utils.h"
50 #include "gtkmm2ext/click_box.h"
51 #include "gtkmm2ext/fastmeter.h"
52 #include "gtkmm2ext/popup.h"
53 #include "gtkmm2ext/window_title.h"
55 #include "midi++/manager.h"
57 #include "ardour/ardour.h"
58 #include "ardour/callback.h"
59 #include "ardour/profile.h"
60 #include "ardour/session_directory.h"
61 #include "ardour/session_route.h"
62 #include "ardour/session_state_utils.h"
63 #include "ardour/session_utils.h"
64 #include "ardour/port.h"
65 #include "ardour/audioengine.h"
66 #include "ardour/playlist.h"
67 #include "ardour/utils.h"
68 #include "ardour/audio_diskstream.h"
69 #include "ardour/audiofilesource.h"
70 #include "ardour/recent_sessions.h"
71 #include "ardour/port.h"
72 #include "ardour/audio_track.h"
73 #include "ardour/midi_track.h"
74 #include "ardour/filesystem_paths.h"
75 #include "ardour/filename_extensions.h"
77 typedef uint64_t microseconds_t;
80 #include "ardour_ui.h"
81 #include "public_editor.h"
82 #include "audio_clock.h"
87 #include "add_route_dialog.h"
91 #include "gui_thread.h"
92 #include "theme_manager.h"
93 #include "bundle_manager.h"
94 #include "session_metadata_dialog.h"
95 #include "gain_meter.h"
96 #include "route_time_axis.h"
98 #include "engine_dialog.h"
99 #include "processor_box.h"
100 #include "time_axis_view_item.h"
101 #include "window_proxy.h"
102 #include "global_port_matrix.h"
103 #include "location_ui.h"
107 using namespace ARDOUR;
109 using namespace Gtkmm2ext;
112 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
113 UIConfiguration *ARDOUR_UI::ui_config = 0;
115 sigc::signal<void,bool> ARDOUR_UI::Blink;
116 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
117 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
118 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
120 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
122 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
124 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
125 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
126 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
127 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
131 preroll_button (_("pre\nroll")),
132 postroll_button (_("post\nroll")),
136 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
140 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
141 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
142 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
143 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
144 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
145 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
146 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
147 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
148 shuttle_controller_binding_proxy (shuttle_controllable),
150 roll_button (roll_controllable),
151 stop_button (stop_controllable),
152 goto_start_button (goto_start_controllable),
153 goto_end_button (goto_end_controllable),
154 auto_loop_button (auto_loop_controllable),
155 play_selection_button (play_selection_controllable),
156 rec_button (rec_controllable),
158 shuttle_units_button (_("% ")),
160 punch_in_button (_("Punch In")),
161 punch_out_button (_("Punch Out")),
162 auto_return_button (_("Auto Return")),
163 auto_play_button (_("Auto Play")),
164 auto_input_button (_("Auto Input")),
165 click_button (_("Click")),
166 time_master_button (_("time\nmaster")),
168 auditioning_alert_button (_("AUDITION")),
169 solo_alert_button (_("SOLO")),
170 error_log_button (_("Errors"))
173 using namespace Gtk::Menu_Helpers;
179 // _auto_display_errors = false;
181 * This was commented out as it wasn't defined
182 * in A3 IIRC. If this is not needed it should
183 * be completely removed.
191 if (theArdourUI == 0) {
195 ui_config = new UIConfiguration();
196 theme_manager = new ThemeManager();
202 _session_is_new = false;
203 big_clock_window = 0;
204 big_clock_height = 0;
205 big_clock_resize_in_progress = false;
206 session_selector_window = 0;
207 last_key_press_time = 0;
208 _will_create_new_session_automatically = false;
209 add_route_dialog = 0;
211 rc_option_editor = 0;
212 session_option_editor = 0;
214 open_session_selector = 0;
215 have_configure_timeout = false;
216 have_disk_speed_dialog_displayed = false;
217 session_loaded = false;
218 last_speed_displayed = -1.0f;
219 ignore_dual_punch = false;
220 _mixer_on_top = false;
221 original_big_clock_width = -1;
222 original_big_clock_height = -1;
223 original_big_clock_font_size = 0;
225 roll_button.unset_flags (Gtk::CAN_FOCUS);
226 stop_button.unset_flags (Gtk::CAN_FOCUS);
227 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
228 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
229 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
230 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
231 rec_button.unset_flags (Gtk::CAN_FOCUS);
233 last_configure_time= 0;
235 shuttle_grabbed = false;
237 shuttle_max_speed = 8.0f;
239 shuttle_style_menu = 0;
240 shuttle_unit_menu = 0;
242 // We do not have jack linked in yet so;
244 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
246 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
247 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
249 /* handle dialog requests */
251 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
253 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
255 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
257 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
259 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
261 /* lets get this party started */
264 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
265 throw failed_constructor ();
268 setup_gtk_ardour_enums ();
271 GainMeter::setup_slider_pix ();
272 RouteTimeAxisView::setup_slider_pix ();
273 SendProcessorEntry::setup_slider_pix ();
274 SessionEvent::create_per_thread_pool ("GUI", 512);
276 } catch (failed_constructor& err) {
277 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
282 /* we like keyboards */
284 keyboard = new ArdourKeyboard(*this);
286 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
288 keyboard->set_state (*node, Stateful::loading_state_version);
293 TimeAxisViewItem::set_constant_heights ();
295 /* The following must happen after ARDOUR::init() so that Config is set up */
297 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
298 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
300 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
301 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
302 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
303 Config->extra_xml (X_("UI")),
304 string_compose ("toggle-%1-connection-manager", (*i).to_string())
310 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
311 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
316 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
318 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
321 _startup = new ArdourStartup ();
323 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
325 if (audio_setup && _startup->engine_control()) {
326 _startup->engine_control()->set_state (*audio_setup);
329 _startup->set_new_only (should_be_new);
330 if (!load_template.empty()) {
331 _startup->set_load_template( load_template );
333 _startup->present ();
339 switch (_startup->response()) {
348 ARDOUR_UI::create_engine ()
350 // this gets called every time by new_session()
356 loading_message (_("Starting audio engine"));
359 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
366 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
367 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
368 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
370 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
372 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
380 ARDOUR_UI::post_engine ()
382 /* Things to be done once we create the AudioEngine
385 ARDOUR::init_post_engine ();
387 ActionManager::init ();
390 if (setup_windows ()) {
391 throw failed_constructor ();
394 check_memory_locking();
396 /* this is the first point at which all the keybindings are available */
398 if (ARDOUR_COMMAND_LINE::show_key_actions) {
399 vector<string> names;
400 vector<string> paths;
402 vector<AccelKey> bindings;
404 ActionManager::get_all_actions (names, paths, keys, bindings);
406 vector<string>::iterator n;
407 vector<string>::iterator k;
408 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
409 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
415 blink_timeout_tag = -1;
417 /* this being a GUI and all, we want peakfiles */
419 AudioFileSource::set_build_peakfiles (true);
420 AudioFileSource::set_build_missing_peakfiles (true);
422 /* set default clock modes */
424 if (Profile->get_sae()) {
425 primary_clock.set_mode (AudioClock::BBT);
426 secondary_clock.set_mode (AudioClock::MinSec);
428 primary_clock.set_mode (AudioClock::Timecode);
429 secondary_clock.set_mode (AudioClock::BBT);
432 /* start the time-of-day-clock */
435 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
436 update_wall_clock ();
437 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
440 update_disk_space ();
442 update_sample_rate (engine->frame_rate());
444 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
445 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
446 Config->map_parameters (pc);
448 /* now start and maybe save state */
450 if (do_engine_start () == 0) {
451 if (_session && _session_is_new) {
452 /* we need to retain initial visual
453 settings for a new session
455 _session->save_state ("");
460 ARDOUR_UI::~ARDOUR_UI ()
465 delete add_route_dialog;
469 ARDOUR_UI::pop_back_splash ()
471 if (Splash::instance()) {
472 // Splash::instance()->pop_back();
473 Splash::instance()->hide ();
478 ARDOUR_UI::configure_timeout ()
480 if (last_configure_time == 0) {
481 /* no configure events yet */
485 /* force a gap of 0.5 seconds since the last configure event
488 if (get_microseconds() - last_configure_time < 500000) {
491 have_configure_timeout = false;
492 cerr << "config event-driven save\n";
493 save_ardour_state ();
499 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
501 if (have_configure_timeout) {
502 last_configure_time = get_microseconds();
504 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
505 have_configure_timeout = true;
512 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
514 const XMLProperty* prop;
516 if ((prop = node.property ("roll")) != 0) {
517 roll_controllable->set_id (prop->value());
519 if ((prop = node.property ("stop")) != 0) {
520 stop_controllable->set_id (prop->value());
522 if ((prop = node.property ("goto-start")) != 0) {
523 goto_start_controllable->set_id (prop->value());
525 if ((prop = node.property ("goto-end")) != 0) {
526 goto_end_controllable->set_id (prop->value());
528 if ((prop = node.property ("auto-loop")) != 0) {
529 auto_loop_controllable->set_id (prop->value());
531 if ((prop = node.property ("play-selection")) != 0) {
532 play_selection_controllable->set_id (prop->value());
534 if ((prop = node.property ("rec")) != 0) {
535 rec_controllable->set_id (prop->value());
537 if ((prop = node.property ("shuttle")) != 0) {
538 shuttle_controllable->set_id (prop->value());
543 ARDOUR_UI::get_transport_controllable_state ()
545 XMLNode* node = new XMLNode(X_("TransportControllables"));
548 roll_controllable->id().print (buf, sizeof (buf));
549 node->add_property (X_("roll"), buf);
550 stop_controllable->id().print (buf, sizeof (buf));
551 node->add_property (X_("stop"), buf);
552 goto_start_controllable->id().print (buf, sizeof (buf));
553 node->add_property (X_("goto_start"), buf);
554 goto_end_controllable->id().print (buf, sizeof (buf));
555 node->add_property (X_("goto_end"), buf);
556 auto_loop_controllable->id().print (buf, sizeof (buf));
557 node->add_property (X_("auto_loop"), buf);
558 play_selection_controllable->id().print (buf, sizeof (buf));
559 node->add_property (X_("play_selection"), buf);
560 rec_controllable->id().print (buf, sizeof (buf));
561 node->add_property (X_("rec"), buf);
562 shuttle_controllable->id().print (buf, sizeof (buf));
563 node->add_property (X_("shuttle"), buf);
570 ARDOUR_UI::autosave_session ()
572 if (g_main_depth() > 1) {
573 /* inside a recursive main loop,
574 give up because we may not be able to
580 if (!Config->get_periodic_safety_backups()) {
585 _session->maybe_write_autosave();
592 ARDOUR_UI::update_autosave ()
594 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
596 if (_session && _session->dirty()) {
597 if (_autosave_connection.connected()) {
598 _autosave_connection.disconnect();
601 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
602 Config->get_periodic_safety_backup_interval() * 1000);
605 if (_autosave_connection.connected()) {
606 _autosave_connection.disconnect();
612 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
616 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
618 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
621 MessageDialog win (title,
627 win.set_secondary_text(_("There are several possible reasons:\n\
629 1) You requested audio parameters that are not supported..\n\
630 2) JACK is running as another user.\n\
632 Please consider the possibilities, and perhaps try different parameters."));
634 win.set_secondary_text(_("There are several possible reasons:\n\
636 1) JACK is not running.\n\
637 2) JACK is running as another user, perhaps root.\n\
638 3) There is already another client called \"ardour\".\n\
640 Please consider the possibilities, and perhaps (re)start JACK."));
644 win.set_transient_for (*toplevel);
648 win.add_button (Stock::OK, RESPONSE_CLOSE);
650 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
653 win.set_default_response (RESPONSE_CLOSE);
656 win.set_position (Gtk::WIN_POS_CENTER);
659 /* we just don't care about the result, but we want to block */
665 ARDOUR_UI::startup ()
669 call_the_mothership (VERSIONSTRING);
672 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
678 goto_editor_window ();
680 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
681 to be opened on top of the editor window that goto_editor_window() just opened.
683 add_window_proxy (location_ui);
684 add_window_proxy (big_clock_window);
685 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
686 add_window_proxy (_global_port_matrix[*i]);
689 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
693 ARDOUR_UI::no_memory_warning ()
695 XMLNode node (X_("no-memory-warning"));
696 Config->add_instant_xml (node);
700 ARDOUR_UI::check_memory_locking ()
703 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
707 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
709 if (engine->is_realtime() && memory_warning_node == 0) {
711 struct rlimit limits;
713 long pages, page_size;
715 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
718 ram = (int64_t) pages * (int64_t) page_size;
721 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
725 if (limits.rlim_cur != RLIM_INFINITY) {
727 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
730 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
731 "This might cause %1 to run out of memory before your system "
732 "runs out of memory. \n\n"
733 "You can view the memory limit with 'ulimit -l', "
734 "and it is normally controlled by /etc/security/limits.conf"),
735 PROGRAM_NAME).c_str());
737 VBox* vbox = msg.get_vbox();
739 CheckButton cb (_("Do not show this window again"));
741 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
743 hbox.pack_start (cb, true, false);
744 vbox->pack_start (hbox);
751 editor->ensure_float (msg);
761 ARDOUR_UI::queue_finish ()
763 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
767 ARDOUR_UI::idle_finish ()
770 return false; /* do not call again */
779 if (_session->transport_rolling() && (++tries < 8)) {
780 _session->request_stop (false, true);
784 if (_session->dirty()) {
785 switch (ask_about_saving_session(_("quit"))) {
790 /* use the default name */
791 if (save_state_canfail ("")) {
792 /* failed - don't quit */
793 MessageDialog msg (*editor,
795 Ardour was unable to save your session.\n\n\
796 If you still wish to quit, please use the\n\n\
797 \"Just quit\" option."));
808 second_connection.disconnect ();
809 point_one_second_connection.disconnect ();
810 point_oh_five_second_connection.disconnect ();
811 point_zero_one_second_connection.disconnect();
814 /* Save state before deleting the session, as that causes some
815 windows to be destroyed before their visible state can be
818 save_ardour_state ();
821 // _session->set_deletion_in_progress ();
822 _session->set_clean ();
823 _session->remove_pending_capture_state ();
828 ArdourDialog::close_all_dialogs ();
834 ARDOUR_UI::ask_about_saving_session (const string & what)
836 ArdourDialog window (_("Unsaved Session"));
837 Gtk::HBox dhbox; // the hbox for the image and text
838 Gtk::Label prompt_label;
839 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
843 msg = string_compose(_("Don't %1"), what);
844 window.add_button (msg, RESPONSE_REJECT);
845 msg = string_compose(_("Just %1"), what);
846 window.add_button (msg, RESPONSE_APPLY);
847 msg = string_compose(_("Save and %1"), what);
848 window.add_button (msg, RESPONSE_ACCEPT);
850 window.set_default_response (RESPONSE_ACCEPT);
852 Gtk::Button noquit_button (msg);
853 noquit_button.set_name ("EditorGTKButton");
858 if (_session->snap_name() == _session->name()) {
861 type = _("snapshot");
863 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?"),
864 type, _session->snap_name());
866 prompt_label.set_text (prompt);
867 prompt_label.set_name (X_("PrompterLabel"));
868 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
870 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
871 dhbox.set_homogeneous (false);
872 dhbox.pack_start (*dimage, false, false, 5);
873 dhbox.pack_start (prompt_label, true, false, 5);
874 window.get_vbox()->pack_start (dhbox);
876 window.set_name (_("Prompter"));
877 window.set_position (Gtk::WIN_POS_MOUSE);
878 window.set_modal (true);
879 window.set_resizable (false);
885 window.set_keep_above (true);
888 ResponseType r = (ResponseType) window.run();
893 case RESPONSE_ACCEPT: // save and get out of here
895 case RESPONSE_APPLY: // get out of here
905 ARDOUR_UI::every_second ()
908 update_buffer_load ();
909 update_disk_space ();
914 ARDOUR_UI::every_point_one_seconds ()
916 update_speed_display ();
917 RapidScreenUpdate(); /* EMIT_SIGNAL */
922 ARDOUR_UI::every_point_zero_one_seconds ()
924 // august 2007: actual update frequency: 40Hz, not 100Hz
926 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
931 ARDOUR_UI::update_sample_rate (nframes_t)
935 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
937 if (!engine->connected()) {
939 snprintf (buf, sizeof (buf), _("disconnected"));
943 nframes_t rate = engine->frame_rate();
945 if (fmod (rate, 1000.0) != 0.0) {
946 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
947 (float) rate/1000.0f,
948 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
950 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
952 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
956 sample_rate_label.set_text (buf);
960 ARDOUR_UI::update_cpu_load ()
963 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
964 cpu_load_label.set_text (buf);
968 ARDOUR_UI::update_buffer_load ()
974 c = _session->capture_load ();
975 p = _session->playback_load ();
977 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
978 _session->playback_load(), _session->capture_load());
979 buffer_load_label.set_text (buf);
981 buffer_load_label.set_text ("");
986 ARDOUR_UI::count_recenabled_streams (Route& route)
988 Track* track = dynamic_cast<Track*>(&route);
989 if (track && track->record_enabled()) {
990 rec_enabled_streams += track->n_inputs().n_total();
995 ARDOUR_UI::update_disk_space()
1001 nframes_t frames = _session->available_capture_duration();
1003 nframes_t fr = _session->frame_rate();
1005 if (frames == max_frames) {
1006 strcpy (buf, _("Disk: 24hrs+"));
1008 rec_enabled_streams = 0;
1009 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1011 if (rec_enabled_streams) {
1012 frames /= rec_enabled_streams;
1019 hrs = frames / (fr * 3600);
1020 frames -= hrs * fr * 3600;
1021 mins = frames / (fr * 60);
1022 frames -= mins * fr * 60;
1025 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1028 disk_space_label.set_text (buf);
1030 // An attempt to make the disk space label flash red when space has run out.
1032 if (frames < fr * 60 * 5) {
1033 /* disk_space_box.style ("disk_space_label_empty"); */
1035 /* disk_space_box.style ("disk_space_label"); */
1041 ARDOUR_UI::update_wall_clock ()
1048 tm_now = localtime (&now);
1050 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1051 wall_clock_label.set_text (buf);
1057 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1059 session_popup_menu->popup (0, 0);
1064 ARDOUR_UI::redisplay_recent_sessions ()
1066 std::vector<sys::path> session_directories;
1067 RecentSessionsSorter cmp;
1069 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1070 recent_session_model->clear ();
1072 ARDOUR::RecentSessions rs;
1073 ARDOUR::read_recent_sessions (rs);
1076 recent_session_display.set_model (recent_session_model);
1080 // sort them alphabetically
1081 sort (rs.begin(), rs.end(), cmp);
1083 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1084 session_directories.push_back ((*i).second);
1087 for (vector<sys::path>::const_iterator i = session_directories.begin();
1088 i != session_directories.end(); ++i)
1090 std::vector<sys::path> state_file_paths;
1092 // now get available states for this session
1094 get_state_files_in_directory (*i, state_file_paths);
1096 vector<string*>* states;
1097 vector<const gchar*> item;
1098 string fullpath = (*i).to_string();
1100 /* remove any trailing / */
1102 if (fullpath[fullpath.length()-1] == '/') {
1103 fullpath = fullpath.substr (0, fullpath.length()-1);
1106 /* check whether session still exists */
1107 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1108 /* session doesn't exist */
1109 cerr << "skipping non-existent session " << fullpath << endl;
1113 /* now get available states for this session */
1115 if ((states = Session::possible_states (fullpath)) == 0) {
1116 /* no state file? */
1120 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1122 Gtk::TreeModel::Row row = *(recent_session_model->append());
1124 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1125 row[recent_session_columns.fullpath] = fullpath;
1127 if (state_file_names.size() > 1) {
1131 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1132 i2 != state_file_names.end(); ++i2)
1135 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1137 child_row[recent_session_columns.visible_name] = *i2;
1138 child_row[recent_session_columns.fullpath] = fullpath;
1143 recent_session_display.set_model (recent_session_model);
1147 ARDOUR_UI::build_session_selector ()
1149 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1151 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1153 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1154 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1155 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1156 recent_session_model = TreeStore::create (recent_session_columns);
1157 recent_session_display.set_model (recent_session_model);
1158 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1159 recent_session_display.set_headers_visible (false);
1160 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1161 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1163 scroller->add (recent_session_display);
1164 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1166 session_selector_window->set_name ("SessionSelectorWindow");
1167 session_selector_window->set_size_request (200, 400);
1168 session_selector_window->get_vbox()->pack_start (*scroller);
1170 recent_session_display.show();
1172 //session_selector_window->get_vbox()->show();
1176 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1178 session_selector_window->response (RESPONSE_ACCEPT);
1182 ARDOUR_UI::open_recent_session ()
1184 bool can_return = (_session != 0);
1186 if (session_selector_window == 0) {
1187 build_session_selector ();
1190 redisplay_recent_sessions ();
1194 session_selector_window->set_position (WIN_POS_MOUSE);
1196 ResponseType r = (ResponseType) session_selector_window->run ();
1199 case RESPONSE_ACCEPT:
1203 session_selector_window->hide();
1210 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1214 session_selector_window->hide();
1216 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1218 if (i == recent_session_model->children().end()) {
1222 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1223 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1225 _session_is_new = false;
1227 if (load_session (path, state) == 0) {
1236 ARDOUR_UI::check_audioengine ()
1239 if (!engine->connected()) {
1240 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1241 "You cannot open or close sessions in this condition"),
1254 ARDOUR_UI::open_session ()
1256 if (!check_audioengine()) {
1261 /* popup selector window */
1263 if (open_session_selector == 0) {
1265 /* ardour sessions are folders */
1267 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1268 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1269 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1270 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1272 FileFilter session_filter;
1273 session_filter.add_pattern ("*.ardour");
1274 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1275 open_session_selector->add_filter (session_filter);
1276 open_session_selector->set_filter (session_filter);
1279 int response = open_session_selector->run();
1280 open_session_selector->hide ();
1283 case RESPONSE_ACCEPT:
1286 open_session_selector->hide();
1290 open_session_selector->hide();
1291 string session_path = open_session_selector->get_filename();
1295 if (session_path.length() > 0) {
1296 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1297 _session_is_new = isnew;
1298 load_session (path, name);
1305 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1307 list<boost::shared_ptr<MidiTrack> > tracks;
1309 if (_session == 0) {
1310 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1317 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1319 if (tracks.size() != how_many) {
1320 if (how_many == 1) {
1321 error << _("could not create a new midi track") << endmsg;
1323 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1327 if ((route = _session->new_midi_route ()) == 0) {
1328 error << _("could not create new midi bus") << endmsg;
1334 MessageDialog msg (*editor,
1335 string_compose (_("There are insufficient JACK ports available\n\
1336 to create a new track or bus.\n\
1337 You should save %1, exit and\n\
1338 restart JACK with more ports."), PROGRAM_NAME));
1345 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)
1347 list<boost::shared_ptr<AudioTrack> > tracks;
1350 if (_session == 0) {
1351 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1357 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1359 if (tracks.size() != how_many) {
1360 if (how_many == 1) {
1361 error << _("could not create a new audio track") << endmsg;
1363 error << string_compose (_("could only create %1 of %2 new audio %3"),
1364 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1370 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1372 if (routes.size() != how_many) {
1373 if (how_many == 1) {
1374 error << _("could not create a new audio track") << endmsg;
1376 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1383 MessageDialog msg (*editor,
1384 string_compose (_("There are insufficient JACK ports available\n\
1385 to create a new track or bus.\n\
1386 You should save %1, exit and\n\
1387 restart JACK with more ports."), PROGRAM_NAME));
1394 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1396 nframes_t _preroll = 0;
1399 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1400 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1402 if (new_position > _preroll) {
1403 new_position -= _preroll;
1408 _session->request_locate (new_position);
1413 ARDOUR_UI::transport_goto_start ()
1416 _session->goto_start();
1418 /* force displayed area in editor to start no matter
1419 what "follow playhead" setting is.
1423 editor->center_screen (_session->current_start_frame ());
1429 ARDOUR_UI::transport_goto_zero ()
1432 _session->request_locate (0);
1434 /* force displayed area in editor to start no matter
1435 what "follow playhead" setting is.
1439 editor->reset_x_origin (0);
1445 ARDOUR_UI::transport_goto_wallclock ()
1447 if (_session && editor) {
1454 localtime_r (&now, &tmnow);
1456 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1457 frames += tmnow.tm_min * (60 * _session->frame_rate());
1458 frames += tmnow.tm_sec * _session->frame_rate();
1460 _session->request_locate (frames, _session->transport_rolling ());
1462 /* force displayed area in editor to start no matter
1463 what "follow playhead" setting is.
1467 editor->center_screen (frames);
1473 ARDOUR_UI::transport_goto_end ()
1476 nframes_t const frame = _session->current_end_frame();
1477 _session->request_locate (frame);
1479 /* force displayed area in editor to start no matter
1480 what "follow playhead" setting is.
1484 editor->center_screen (frame);
1490 ARDOUR_UI::transport_stop ()
1496 if (_session->is_auditioning()) {
1497 _session->cancel_audition ();
1501 _session->request_stop (false, true);
1505 ARDOUR_UI::transport_stop_and_forget_capture ()
1508 _session->request_stop (true, true);
1513 ARDOUR_UI::remove_last_capture()
1516 editor->remove_last_capture();
1521 ARDOUR_UI::transport_record (bool roll)
1525 switch (_session->record_status()) {
1526 case Session::Disabled:
1527 if (_session->ntracks() == 0) {
1528 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1532 _session->maybe_enable_record ();
1537 case Session::Recording:
1539 _session->request_stop();
1541 _session->disable_record (false, true);
1545 case Session::Enabled:
1546 _session->disable_record (false, true);
1549 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1553 ARDOUR_UI::transport_roll ()
1559 if (_session->is_auditioning()) {
1563 if (_session->config.get_external_sync()) {
1564 switch (_session->config.get_sync_source()) {
1568 /* transport controlled by the master */
1573 bool rolling = _session->transport_rolling();
1575 if (_session->get_play_loop()) {
1576 /* XXX it is not possible to just leave seamless loop and keep
1577 playing at present (nov 4th 2009)
1579 if (!Config->get_seamless_loop()) {
1580 _session->request_play_loop (false, true);
1582 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1583 /* stop playing a range if we currently are */
1584 _session->request_play_range (0, true);
1587 if (join_play_range_button.get_active()) {
1588 _session->request_play_range (&editor->get_selection().time, true);
1592 _session->request_transport_speed (1.0f);
1597 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1604 if (_session->is_auditioning()) {
1605 _session->cancel_audition ();
1609 if (_session->config.get_external_sync()) {
1610 switch (_session->config.get_sync_source()) {
1614 /* transport controlled by the master */
1619 bool rolling = _session->transport_rolling();
1620 bool affect_transport = true;
1622 if (rolling && roll_out_of_bounded_mode) {
1623 /* drop out of loop/range playback but leave transport rolling */
1624 if (_session->get_play_loop()) {
1625 if (Config->get_seamless_loop()) {
1626 /* the disk buffers contain copies of the loop - we can't
1627 just keep playing, so stop the transport. the user
1628 can restart as they wish.
1630 affect_transport = true;
1632 /* disk buffers are normal, so we can keep playing */
1633 affect_transport = false;
1635 _session->request_play_loop (false, true);
1636 } else if (_session->get_play_range ()) {
1637 affect_transport = false;
1638 _session->request_play_range (0, true);
1642 if (affect_transport) {
1644 _session->request_stop (with_abort, true);
1646 if (join_play_range_button.get_active()) {
1647 _session->request_play_range (&editor->get_selection().time, true);
1650 _session->request_transport_speed (1.0f);
1656 ARDOUR_UI::toggle_session_auto_loop ()
1659 if (_session->get_play_loop()) {
1660 if (_session->transport_rolling()) {
1661 Location * looploc = _session->locations()->auto_loop_location();
1663 _session->request_locate (looploc->start(), true);
1666 _session->request_play_loop (false);
1669 Location * looploc = _session->locations()->auto_loop_location();
1671 _session->request_play_loop (true);
1678 ARDOUR_UI::transport_play_selection ()
1684 editor->play_selection ();
1688 ARDOUR_UI::transport_rewind (int option)
1690 float current_transport_speed;
1693 current_transport_speed = _session->transport_speed();
1695 if (current_transport_speed >= 0.0f) {
1698 _session->request_transport_speed (-1.0f);
1701 _session->request_transport_speed (-4.0f);
1704 _session->request_transport_speed (-0.5f);
1709 _session->request_transport_speed (current_transport_speed * 1.5f);
1715 ARDOUR_UI::transport_forward (int option)
1717 float current_transport_speed;
1720 current_transport_speed = _session->transport_speed();
1722 if (current_transport_speed <= 0.0f) {
1725 _session->request_transport_speed (1.0f);
1728 _session->request_transport_speed (4.0f);
1731 _session->request_transport_speed (0.5f);
1736 _session->request_transport_speed (current_transport_speed * 1.5f);
1743 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1745 if (_session == 0) {
1749 boost::shared_ptr<Route> r;
1751 if ((r = _session->route_by_remote_id (rid)) != 0) {
1755 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1756 t->set_record_enabled (!t->record_enabled(), this);
1759 if (_session == 0) {
1765 ARDOUR_UI::map_transport_state ()
1767 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1770 auto_loop_button.set_visual_state (0);
1771 play_selection_button.set_visual_state (0);
1772 roll_button.set_visual_state (0);
1773 stop_button.set_visual_state (1);
1777 float sp = _session->transport_speed();
1780 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1781 shuttle_box.queue_draw ();
1782 } else if (sp == 0.0f) {
1784 shuttle_box.queue_draw ();
1785 update_disk_space ();
1792 if (_session->get_play_range()) {
1794 play_selection_button.set_visual_state (1);
1795 roll_button.set_visual_state (0);
1796 auto_loop_button.set_visual_state (0);
1798 } else if (_session->get_play_loop ()) {
1800 auto_loop_button.set_visual_state (1);
1801 play_selection_button.set_visual_state (0);
1802 roll_button.set_visual_state (0);
1806 roll_button.set_visual_state (1);
1807 play_selection_button.set_visual_state (0);
1808 auto_loop_button.set_visual_state (0);
1811 if (join_play_range_button.get_active()) {
1812 /* light up both roll and play-selection if they are joined */
1813 roll_button.set_visual_state (1);
1814 play_selection_button.set_visual_state (1);
1817 stop_button.set_visual_state (0);
1821 stop_button.set_visual_state (1);
1822 roll_button.set_visual_state (0);
1823 play_selection_button.set_visual_state (0);
1824 auto_loop_button.set_visual_state (0);
1829 ARDOUR_UI::engine_stopped ()
1831 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1832 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1833 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1837 ARDOUR_UI::engine_running ()
1839 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1840 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1841 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1843 Glib::RefPtr<Action> action;
1844 const char* action_name = 0;
1846 switch (engine->frames_per_cycle()) {
1848 action_name = X_("JACKLatency32");
1851 action_name = X_("JACKLatency64");
1854 action_name = X_("JACKLatency128");
1857 action_name = X_("JACKLatency512");
1860 action_name = X_("JACKLatency1024");
1863 action_name = X_("JACKLatency2048");
1866 action_name = X_("JACKLatency4096");
1869 action_name = X_("JACKLatency8192");
1872 /* XXX can we do anything useful ? */
1878 action = ActionManager::get_action (X_("JACK"), action_name);
1881 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1882 ract->set_active ();
1888 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1890 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1891 /* we can't rely on the original string continuing to exist when we are called
1892 again in the GUI thread, so make a copy and note that we need to
1895 char *copy = strdup (reason);
1896 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1900 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1901 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1903 update_sample_rate (0);
1907 /* if the reason is a non-empty string, it means that the backend was shutdown
1908 rather than just Ardour.
1911 if (strlen (reason)) {
1912 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1914 msgstr = string_compose (_("\
1915 JACK has either been shutdown or it\n\
1916 disconnected %1 because %1\n\
1917 was not fast enough. Try to restart\n\
1918 JACK, reconnect and save the session."), PROGRAM_NAME);
1921 MessageDialog msg (*editor, msgstr);
1926 free ((char*) reason);
1931 ARDOUR_UI::do_engine_start ()
1939 error << _("Unable to start the session running")
1949 ARDOUR_UI::setup_theme ()
1951 theme_manager->setup_theme();
1955 ARDOUR_UI::update_clocks ()
1957 if (!editor || !editor->dragging_playhead()) {
1958 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1963 ARDOUR_UI::start_clocking ()
1965 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1969 ARDOUR_UI::stop_clocking ()
1971 clock_signal_connection.disconnect ();
1975 ARDOUR_UI::toggle_clocking ()
1978 if (clock_button.get_active()) {
1987 ARDOUR_UI::_blink (void *arg)
1990 ((ARDOUR_UI *) arg)->blink ();
1997 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2001 ARDOUR_UI::start_blinking ()
2003 /* Start the blink signal. Everybody with a blinking widget
2004 uses Blink to drive the widget's state.
2007 if (blink_timeout_tag < 0) {
2009 blink_timeout_tag = g_timeout_add (240, _blink, this);
2014 ARDOUR_UI::stop_blinking ()
2016 if (blink_timeout_tag >= 0) {
2017 g_source_remove (blink_timeout_tag);
2018 blink_timeout_tag = -1;
2023 /** Ask the user for the name of a new shapshot and then take it.
2027 ARDOUR_UI::snapshot_session (bool switch_to_it)
2029 ArdourPrompter prompter (true);
2032 prompter.set_name ("Prompter");
2033 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2034 prompter.set_title (_("Take Snapshot"));
2035 prompter.set_title (_("Take Snapshot"));
2036 prompter.set_prompt (_("Name of new snapshot"));
2038 if (!switch_to_it) {
2041 struct tm local_time;
2044 localtime_r (&n, &local_time);
2045 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2046 prompter.set_initial_text (timebuf);
2050 switch (prompter.run()) {
2051 case RESPONSE_ACCEPT:
2053 prompter.get_result (snapname);
2055 bool do_save = (snapname.length() != 0);
2058 if (snapname.find ('/') != string::npos) {
2059 MessageDialog msg (_("To ensure compatibility with various systems\n"
2060 "snapshot names may not contain a '/' character"));
2064 if (snapname.find ('\\') != string::npos) {
2065 MessageDialog msg (_("To ensure compatibility with various systems\n"
2066 "snapshot names may not contain a '\\' character"));
2072 vector<sys::path> p;
2073 get_state_files_in_directory (_session->session_directory().root_path(), p);
2074 vector<string> n = get_file_names_no_extension (p);
2075 if (find (n.begin(), n.end(), snapname) != n.end()) {
2077 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2078 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2079 confirm.get_vbox()->pack_start (m, true, true);
2080 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2081 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2082 confirm.show_all ();
2083 switch (confirm.run()) {
2084 case RESPONSE_CANCEL:
2090 save_state (snapname, switch_to_it);
2101 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2103 XMLNode* node = new XMLNode (X_("UI"));
2105 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2106 if (!(*i)->rc_configured()) {
2107 node->add_child_nocopy (*((*i)->get_state ()));
2111 _session->add_extra_xml (*node);
2113 save_state_canfail (name, switch_to_it);
2117 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2122 if (name.length() == 0) {
2123 name = _session->snap_name();
2126 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2130 cerr << "SS canfail\n";
2131 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2136 ARDOUR_UI::primary_clock_value_changed ()
2139 _session->request_locate (primary_clock.current_time ());
2144 ARDOUR_UI::big_clock_value_changed ()
2147 _session->request_locate (big_clock.current_time ());
2152 ARDOUR_UI::secondary_clock_value_changed ()
2155 _session->request_locate (secondary_clock.current_time ());
2160 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2162 if (_session == 0) {
2166 if (_session->step_editing()) {
2170 Session::RecordState const r = _session->record_status ();
2171 bool const h = _session->have_rec_enabled_track ();
2173 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2175 rec_button.set_visual_state (2);
2177 rec_button.set_visual_state (0);
2179 } else if (r == Session::Recording && h) {
2180 rec_button.set_visual_state (1);
2182 rec_button.set_visual_state (0);
2187 ARDOUR_UI::save_template ()
2189 ArdourPrompter prompter (true);
2192 if (!check_audioengine()) {
2196 prompter.set_name (X_("Prompter"));
2197 prompter.set_title (_("Save Mix Template"));
2198 prompter.set_prompt (_("Name for mix template:"));
2199 prompter.set_initial_text(_session->name() + _("-template"));
2200 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2202 switch (prompter.run()) {
2203 case RESPONSE_ACCEPT:
2204 prompter.get_result (name);
2206 if (name.length()) {
2207 _session->save_template (name);
2217 ARDOUR_UI::edit_metadata ()
2219 SessionMetadataEditor dialog;
2220 dialog.set_session (_session);
2221 editor->ensure_float (dialog);
2226 ARDOUR_UI::import_metadata ()
2228 SessionMetadataImporter dialog;
2229 dialog.set_session (_session);
2230 editor->ensure_float (dialog);
2235 ARDOUR_UI::fontconfig_dialog ()
2238 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2239 may not and it can take a while to build it. Warn them.
2242 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2244 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2245 MessageDialog msg (*_startup,
2246 string_compose (_("Welcome to %1.\n\n"
2247 "The program will take a bit longer to start up\n"
2248 "while the system fonts are checked.\n\n"
2249 "This will only be done once, and you will\n"
2250 "not see this message again\n"), PROGRAM_NAME),
2263 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2265 existing_session = false;
2267 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2268 session_path = cmdline_path;
2269 existing_session = true;
2270 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2271 session_path = Glib::path_get_dirname (string (cmdline_path));
2272 existing_session = true;
2274 /* it doesn't exist, assume the best */
2275 session_path = Glib::path_get_dirname (string (cmdline_path));
2278 session_name = basename_nosuffix (string (cmdline_path));
2282 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2284 /* when this is called, the backend audio system must be running */
2286 /* the main idea here is to deal with the fact that a cmdline argument for the session
2287 can be interpreted in different ways - it could be a directory or a file, and before
2288 we load, we need to know both the session directory and the snapshot (statefile) within it
2289 that we are supposed to use.
2292 if (session_name.length() == 0 || session_path.length() == 0) {
2296 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2298 Glib::ustring predicted_session_file;
2300 predicted_session_file = session_path;
2301 predicted_session_file += '/';
2302 predicted_session_file += session_name;
2303 predicted_session_file += ARDOUR::statefile_suffix;
2305 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2306 existing_session = true;
2309 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2311 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2312 /* existing .ardour file */
2313 existing_session = true;
2317 existing_session = false;
2320 /* lets just try to load it */
2322 if (create_engine ()) {
2323 backend_audio_error (false, _startup);
2327 return load_session (session_path, session_name);
2331 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2333 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2335 MessageDialog msg (str,
2337 Gtk::MESSAGE_WARNING,
2338 Gtk::BUTTONS_YES_NO,
2342 msg.set_name (X_("OpenExistingDialog"));
2343 msg.set_title (_("Open Existing Session"));
2344 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2345 msg.set_position (Gtk::WIN_POS_MOUSE);
2348 switch (msg.run()) {
2357 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2359 BusProfile bus_profile;
2361 if (Profile->get_sae()) {
2363 bus_profile.master_out_channels = 2;
2364 bus_profile.input_ac = AutoConnectPhysical;
2365 bus_profile.output_ac = AutoConnectMaster;
2366 bus_profile.requested_physical_in = 0; // use all available
2367 bus_profile.requested_physical_out = 0; // use all available
2371 /* get settings from advanced section of NSD */
2373 if (_startup->create_master_bus()) {
2374 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2376 bus_profile.master_out_channels = 0;
2379 if (_startup->connect_inputs()) {
2380 bus_profile.input_ac = AutoConnectPhysical;
2382 bus_profile.input_ac = AutoConnectOption (0);
2385 /// @todo some minor tweaks.
2387 bus_profile.output_ac = AutoConnectOption (0);
2389 if (_startup->connect_outputs ()) {
2390 if (_startup->connect_outs_to_master()) {
2391 bus_profile.output_ac = AutoConnectMaster;
2392 } else if (_startup->connect_outs_to_physical()) {
2393 bus_profile.output_ac = AutoConnectPhysical;
2397 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2398 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2401 if (build_session (session_path, session_name, bus_profile)) {
2409 ARDOUR_UI::idle_load (const Glib::ustring& path)
2412 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2413 /* /path/to/foo => /path/to/foo, foo */
2414 load_session (path, basename_nosuffix (path));
2416 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2417 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2421 ARDOUR_COMMAND_LINE::session_name = path;
2424 * new_session_dialog doens't exist in A3
2425 * Try to remove all references to it to
2426 * see if it will compile. NOTE: this will
2427 * likely cause a runtime issue is my somewhat
2431 //if (new_session_dialog) {
2434 /* make it break out of Dialog::run() and
2438 //new_session_dialog->response (1);
2444 ARDOUR_UI::end_loading_messages ()
2450 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2453 // splash->message (msg);
2457 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2459 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2461 Glib::ustring session_name;
2462 Glib::ustring session_path;
2463 Glib::ustring template_name;
2465 bool likely_new = false;
2467 if (! load_template.empty()) {
2468 should_be_new = true;
2469 template_name = load_template;
2474 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2476 /* if they named a specific statefile, use it, otherwise they are
2477 just giving a session folder, and we want to use it as is
2478 to find the session.
2481 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2482 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2484 session_path = ARDOUR_COMMAND_LINE::session_name;
2487 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2491 bool const apply = run_startup (should_be_new, load_template);
2493 if (quit_on_cancel) {
2500 /* if we run the startup dialog again, offer more than just "new session" */
2502 should_be_new = false;
2504 session_name = _startup->session_name (likely_new);
2506 /* this shouldn't happen, but we catch it just in case it does */
2508 if (session_name.empty()) {
2511 if (_startup->use_session_template()) {
2512 template_name = _startup->session_template_name();
2513 _session_is_new = true;
2516 if (session_name[0] == '/' ||
2517 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2518 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2520 /* absolute path or cwd-relative path specified for session name: infer session folder
2521 from what was given.
2524 session_path = Glib::path_get_dirname (session_name);
2525 session_name = Glib::path_get_basename (session_name);
2529 session_path = _startup->session_folder();
2533 if (create_engine ()) {
2537 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2541 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2543 if (!ask_about_loading_existing_session (existing)) {
2544 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2549 _session_is_new = false;
2554 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2556 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2560 if (session_name.find ('/') != Glib::ustring::npos) {
2561 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2562 "session names may not contain a '/' character"));
2564 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2568 if (session_name.find ('\\') != Glib::ustring::npos) {
2569 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2570 "session names may not contain a '\\' character"));
2572 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2576 _session_is_new = true;
2579 if (likely_new && template_name.empty()) {
2581 ret = build_session_from_nsd (session_path, session_name);
2585 ret = load_session (session_path, session_name, template_name);
2586 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2587 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2597 ARDOUR_UI::close_session()
2599 if (!check_audioengine()) {
2603 if (unload_session (true)) {
2607 ARDOUR_COMMAND_LINE::session_name = "";
2609 if (get_session_parameters (true, false)) {
2613 goto_editor_window ();
2617 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2619 Session *new_session;
2623 session_loaded = false;
2625 if (!check_audioengine()) {
2629 unload_status = unload_session ();
2631 if (unload_status < 0) {
2633 } else if (unload_status > 0) {
2638 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2641 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2644 /* this one is special */
2646 catch (AudioEngine::PortRegistrationFailure& err) {
2648 MessageDialog msg (err.what(),
2651 Gtk::BUTTONS_CLOSE);
2653 msg.set_title (_("Port Registration Error"));
2654 msg.set_secondary_text (_("Click the Close button to try again."));
2655 msg.set_position (Gtk::WIN_POS_CENTER);
2659 int response = msg.run ();
2664 case RESPONSE_CANCEL:
2674 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2677 Gtk::BUTTONS_CLOSE);
2679 msg.set_title (_("Loading Error"));
2680 msg.set_secondary_text (_("Click the Close button to try again."));
2681 msg.set_position (Gtk::WIN_POS_CENTER);
2685 int response = msg.run ();
2690 case RESPONSE_CANCEL:
2698 /* Now the session been created, add the transport controls */
2699 new_session->add_controllable(roll_controllable);
2700 new_session->add_controllable(stop_controllable);
2701 new_session->add_controllable(goto_start_controllable);
2702 new_session->add_controllable(goto_end_controllable);
2703 new_session->add_controllable(auto_loop_controllable);
2704 new_session->add_controllable(play_selection_controllable);
2705 new_session->add_controllable(rec_controllable);
2707 set_session (new_session);
2709 session_loaded = true;
2711 goto_editor_window ();
2714 _session->set_clean ();
2725 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2727 Session *new_session;
2730 if (!check_audioengine()) {
2734 session_loaded = false;
2736 x = unload_session ();
2744 _session_is_new = true;
2747 new_session = new Session (*engine, path, snap_name, &bus_profile);
2752 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2758 set_session (new_session);
2760 session_loaded = true;
2762 new_session->save_state(new_session->name());
2768 ARDOUR_UI::launch_chat ()
2771 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2773 open_uri("http://webchat.freenode.net/?channels=ardour");
2778 ARDOUR_UI::show_about ()
2782 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2785 about->set_transient_for(*editor);
2790 ARDOUR_UI::launch_manual ()
2792 PBD::open_uri("http://ardour.org/flossmanual");
2796 ARDOUR_UI::launch_reference ()
2798 PBD::open_uri("http://ardour.org/refmanual");
2802 ARDOUR_UI::hide_about ()
2805 about->get_window()->set_cursor ();
2811 ARDOUR_UI::about_signal_response (int /*response*/)
2817 ARDOUR_UI::show_splash ()
2821 splash = new Splash;
2829 splash->queue_draw ();
2830 splash->get_window()->process_updates (true);
2835 ARDOUR_UI::hide_splash ()
2843 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2844 const string& plural_msg, const string& singular_msg)
2848 removed = rep.paths.size();
2851 MessageDialog msgd (*editor,
2852 _("No audio files were ready for cleanup"),
2855 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2856 msgd.set_secondary_text (_("If this seems suprising, \n\
2857 check for any existing snapshots.\n\
2858 These may still include regions that\n\
2859 require some unused files to continue to exist."));
2865 ArdourDialog results (_("Clean-up"), true, false);
2867 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2868 CleanupResultsModelColumns() {
2872 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2873 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2877 CleanupResultsModelColumns results_columns;
2878 Glib::RefPtr<Gtk::ListStore> results_model;
2879 Gtk::TreeView results_display;
2881 results_model = ListStore::create (results_columns);
2882 results_display.set_model (results_model);
2883 results_display.append_column (list_title, results_columns.visible_name);
2885 results_display.set_name ("CleanupResultsList");
2886 results_display.set_headers_visible (true);
2887 results_display.set_headers_clickable (false);
2888 results_display.set_reorderable (false);
2890 Gtk::ScrolledWindow list_scroller;
2893 Gtk::HBox dhbox; // the hbox for the image and text
2894 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2895 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2897 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2899 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2902 %1 - number of files removed
2903 %2 - location of "dead_sounds"
2904 %3 - size of files affected
2905 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2908 const char* bprefix;
2909 double space_adjusted = 0;
2911 if (rep.space < 100000.0f) {
2912 bprefix = X_("kilo");
2913 } else if (rep.space < 1000000.0f * 1000) {
2914 bprefix = X_("mega");
2915 space_adjusted = truncf((float)rep.space / 1000.0);
2917 bprefix = X_("giga");
2918 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2922 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2924 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2927 dhbox.pack_start (*dimage, true, false, 5);
2928 dhbox.pack_start (txt, true, false, 5);
2930 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2931 TreeModel::Row row = *(results_model->append());
2932 row[results_columns.visible_name] = *i;
2933 row[results_columns.fullpath] = *i;
2936 list_scroller.add (results_display);
2937 list_scroller.set_size_request (-1, 150);
2938 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2940 dvbox.pack_start (dhbox, true, false, 5);
2941 dvbox.pack_start (list_scroller, true, false, 5);
2942 ddhbox.pack_start (dvbox, true, false, 5);
2944 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2945 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2946 results.set_default_response (RESPONSE_CLOSE);
2947 results.set_position (Gtk::WIN_POS_MOUSE);
2949 results_display.show();
2950 list_scroller.show();
2957 //results.get_vbox()->show();
2958 results.set_resizable (false);
2965 ARDOUR_UI::cleanup ()
2967 if (_session == 0) {
2968 /* shouldn't happen: menu item is insensitive */
2973 MessageDialog checker (_("Are you sure you want to cleanup?"),
2975 Gtk::MESSAGE_QUESTION,
2976 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2978 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2979 ALL undo/redo information will be lost if you cleanup.\n\
2980 After cleanup, unused audio files will be moved to a \
2981 \"dead sounds\" location."));
2983 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2984 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2985 checker.set_default_response (RESPONSE_CANCEL);
2987 checker.set_name (_("CleanupDialog"));
2988 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
2989 checker.set_position (Gtk::WIN_POS_MOUSE);
2991 switch (checker.run()) {
2992 case RESPONSE_ACCEPT:
2998 ARDOUR::CleanupReport rep;
3000 editor->prepare_for_cleanup ();
3002 /* do not allow flush until a session is reloaded */
3004 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3006 act->set_sensitive (false);
3009 if (_session->cleanup_sources (rep)) {
3010 editor->finish_cleanup ();
3014 editor->finish_cleanup ();
3017 display_cleanup_results (rep,
3020 The following %1 files were not in use and \n\
3021 have been moved to:\n\
3023 Flushing the wastebasket will \n\
3024 release an additional\n\
3025 %3 %4bytes of disk space.\n"),
3027 The following file was not in use and \n \
3028 has been moved to:\n \
3030 Flushing the wastebasket will \n\
3031 release an additional\n\
3032 %3 %4bytes of disk space.\n"
3038 ARDOUR_UI::flush_trash ()
3040 if (_session == 0) {
3041 /* shouldn't happen: menu item is insensitive */
3045 ARDOUR::CleanupReport rep;
3047 if (_session->cleanup_trash_sources (rep)) {
3051 display_cleanup_results (rep,
3053 _("The following %1 files were deleted from\n\
3055 releasing %3 %4bytes of disk space"),
3056 _("The following file was deleted from\n\
3058 releasing %3 %4bytes of disk space"));
3062 ARDOUR_UI::add_route (Gtk::Window* float_window)
3070 if (add_route_dialog == 0) {
3071 add_route_dialog = new AddRouteDialog (_session);
3073 add_route_dialog->set_transient_for (*float_window);
3077 if (add_route_dialog->is_visible()) {
3078 /* we're already doing this */
3082 ResponseType r = (ResponseType) add_route_dialog->run ();
3084 add_route_dialog->hide();
3087 case RESPONSE_ACCEPT:
3094 if ((count = add_route_dialog->count()) <= 0) {
3098 string template_path = add_route_dialog->track_template();
3100 if (!template_path.empty()) {
3101 _session->new_route_from_template (count, template_path);
3105 uint32_t input_chan = add_route_dialog->channels ();
3106 uint32_t output_chan;
3107 string name_template = add_route_dialog->name_template ();
3108 bool track = add_route_dialog->track ();
3109 bool aux = !track && add_route_dialog->aux();
3110 RouteGroup* route_group = add_route_dialog->route_group ();
3112 AutoConnectOption oac = Config->get_output_auto_connect();
3114 if (oac & AutoConnectMaster) {
3115 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3117 output_chan = input_chan;
3120 /* XXX do something with name template */
3122 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3124 session_add_midi_track (route_group, count);
3126 MessageDialog msg (*editor,
3127 _("Sorry, MIDI Busses are not supported at this time."));
3129 //session_add_midi_bus();
3133 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3135 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3141 ARDOUR_UI::mixer_settings () const
3146 node = _session->instant_xml(X_("Mixer"));
3148 node = Config->instant_xml(X_("Mixer"));
3152 node = new XMLNode (X_("Mixer"));
3159 ARDOUR_UI::editor_settings () const
3164 node = _session->instant_xml(X_("Editor"));
3166 node = Config->instant_xml(X_("Editor"));
3170 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3171 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3176 node = new XMLNode (X_("Editor"));
3183 ARDOUR_UI::keyboard_settings () const
3187 node = Config->extra_xml(X_("Keyboard"));
3190 node = new XMLNode (X_("Keyboard"));
3196 ARDOUR_UI::create_xrun_marker(nframes_t where)
3198 editor->mouse_add_new_marker (where, false, true);
3202 ARDOUR_UI::halt_on_xrun_message ()
3204 MessageDialog msg (*editor,
3205 _("Recording was stopped because your system could not keep up."));
3210 ARDOUR_UI::xrun_handler(nframes_t where)
3216 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3218 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3219 create_xrun_marker(where);
3222 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3223 halt_on_xrun_message ();
3228 ARDOUR_UI::disk_overrun_handler ()
3230 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3232 if (!have_disk_speed_dialog_displayed) {
3233 have_disk_speed_dialog_displayed = true;
3234 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3235 The disk system on your computer\n\
3236 was not able to keep up with %1.\n\
3238 Specifically, it failed to write data to disk\n\
3239 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3240 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3246 ARDOUR_UI::disk_underrun_handler ()
3248 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3250 if (!have_disk_speed_dialog_displayed) {
3251 have_disk_speed_dialog_displayed = true;
3252 MessageDialog* msg = new MessageDialog (*editor,
3253 string_compose (_("The disk system on your computer\n\
3254 was not able to keep up with %1.\n\
3256 Specifically, it failed to read data from disk\n\
3257 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3258 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3264 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3266 have_disk_speed_dialog_displayed = false;
3271 ARDOUR_UI::session_dialog (std::string msg)
3273 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3278 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3280 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3289 ARDOUR_UI::pending_state_dialog ()
3291 HBox* hbox = new HBox();
3292 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3293 ArdourDialog dialog (_("Crash Recovery"), true);
3295 This session appears to have been in\n\
3296 middle of recording when ardour or\n\
3297 the computer was shutdown.\n\
3299 Ardour can recover any captured audio for\n\
3300 you, or it can ignore it. Please decide\n\
3301 what you would like to do.\n"));
3302 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3303 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3304 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3305 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3306 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3307 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3308 dialog.set_default_response (RESPONSE_ACCEPT);
3309 dialog.set_position (WIN_POS_CENTER);
3314 switch (dialog.run ()) {
3315 case RESPONSE_ACCEPT:
3323 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3325 HBox* hbox = new HBox();
3326 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3327 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3328 Label message (string_compose (_("\
3329 This session was created with a sample rate of %1 Hz\n\
3331 The audioengine is currently running at %2 Hz\n"), desired, actual));
3333 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3334 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3335 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3336 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3337 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3338 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3339 dialog.set_default_response (RESPONSE_ACCEPT);
3340 dialog.set_position (WIN_POS_CENTER);
3345 switch (dialog.run ()) {
3346 case RESPONSE_ACCEPT:
3355 ARDOUR_UI::disconnect_from_jack ()
3358 if( engine->disconnect_from_jack ()) {
3359 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3363 update_sample_rate (0);
3368 ARDOUR_UI::reconnect_to_jack ()
3371 if (engine->reconnect_to_jack ()) {
3372 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3376 update_sample_rate (0);
3381 ARDOUR_UI::use_config ()
3383 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3385 set_transport_controllable_state (*node);
3390 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3392 if (Config->get_primary_clock_delta_edit_cursor()) {
3393 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3395 primary_clock.set (pos, 0, true);
3398 if (Config->get_secondary_clock_delta_edit_cursor()) {
3399 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3401 secondary_clock.set (pos);
3404 if (big_clock_window->get()) {
3405 big_clock.set (pos);
3411 ARDOUR_UI::step_edit_status_change (bool yn)
3413 // XXX should really store pre-step edit status of things
3414 // we make insensitive
3417 rec_button.set_visual_state (3);
3418 rec_button.set_sensitive (false);
3420 rec_button.set_visual_state (0);
3421 rec_button.set_sensitive (true);
3426 ARDOUR_UI::record_state_changed ()
3428 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3430 if (!_session || !big_clock_window->get()) {
3431 /* why bother - the clock isn't visible */
3435 Session::RecordState const r = _session->record_status ();
3436 bool const h = _session->have_rec_enabled_track ();
3438 if (r == Session::Recording && h) {
3439 big_clock.set_widget_name ("BigClockRecording");
3441 big_clock.set_widget_name ("BigClockNonRecording");
3446 ARDOUR_UI::first_idle ()
3449 _session->allow_auto_play (true);
3453 editor->first_idle();
3456 Keyboard::set_can_save_keybindings (true);
3461 ARDOUR_UI::store_clock_modes ()
3463 XMLNode* node = new XMLNode(X_("ClockModes"));
3465 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3466 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3469 _session->add_extra_xml (*node);
3470 _session->set_dirty ();
3475 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3476 : Controllable (name), ui (u), type(tp)
3482 ARDOUR_UI::TransportControllable::set_value (double val)
3484 if (type == ShuttleControl) {
3491 fract = -((0.5 - val)/0.5);
3493 fract = ((val - 0.5)/0.5);
3497 ui.set_shuttle_fract (fract);
3502 /* do nothing: these are radio-style actions */
3506 const char *action = 0;
3510 action = X_("Roll");
3513 action = X_("Stop");
3516 action = X_("Goto Start");
3519 action = X_("Goto End");
3522 action = X_("Loop");
3525 action = X_("Play Selection");
3528 action = X_("Record");
3538 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3546 ARDOUR_UI::TransportControllable::get_value (void) const
3565 case ShuttleControl:
3575 ARDOUR_UI::TransportControllable::set_id (const string& str)
3581 ARDOUR_UI::setup_profile ()
3583 if (gdk_screen_width() < 1200) {
3584 Profile->set_small_screen ();
3588 if (getenv ("ARDOUR_SAE")) {
3589 Profile->set_sae ();
3590 Profile->set_single_package ();
3595 ARDOUR_UI::toggle_translations ()
3597 using namespace Glib;
3599 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3601 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3604 string i18n_killer = ARDOUR::translation_kill_path();
3606 bool already_enabled = !ARDOUR::translations_are_disabled ();
3608 if (ract->get_active ()) {
3609 /* we don't care about errors */
3610 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3613 /* we don't care about errors */
3614 unlink (i18n_killer.c_str());
3617 if (already_enabled != ract->get_active()) {
3618 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3620 Gtk::MESSAGE_WARNING,
3622 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3623 win.set_position (Gtk::WIN_POS_CENTER);
3631 /** Add a window proxy to our list, so that its state will be saved.
3632 * This call also causes the window to be created and opened if its
3633 * state was saved as `visible'.
3636 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3638 _window_proxies.push_back (p);
3642 /** Remove a window proxy from our list. Must be called if a WindowProxy
3643 * is deleted, to prevent hanging pointers.
3646 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3648 _window_proxies.remove (p);