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 save_state_canfail (name, switch_to_it);
2107 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2112 if (name.length() == 0) {
2113 name = _session->snap_name();
2116 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2120 cerr << "SS canfail\n";
2121 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2126 ARDOUR_UI::primary_clock_value_changed ()
2129 _session->request_locate (primary_clock.current_time ());
2134 ARDOUR_UI::big_clock_value_changed ()
2137 _session->request_locate (big_clock.current_time ());
2142 ARDOUR_UI::secondary_clock_value_changed ()
2145 _session->request_locate (secondary_clock.current_time ());
2150 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2152 if (_session == 0) {
2156 if (_session->step_editing()) {
2160 Session::RecordState const r = _session->record_status ();
2161 bool const h = _session->have_rec_enabled_track ();
2163 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2165 rec_button.set_visual_state (2);
2167 rec_button.set_visual_state (0);
2169 } else if (r == Session::Recording && h) {
2170 rec_button.set_visual_state (1);
2172 rec_button.set_visual_state (0);
2177 ARDOUR_UI::save_template ()
2179 ArdourPrompter prompter (true);
2182 if (!check_audioengine()) {
2186 prompter.set_name (X_("Prompter"));
2187 prompter.set_title (_("Save Mix Template"));
2188 prompter.set_prompt (_("Name for mix template:"));
2189 prompter.set_initial_text(_session->name() + _("-template"));
2190 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2192 switch (prompter.run()) {
2193 case RESPONSE_ACCEPT:
2194 prompter.get_result (name);
2196 if (name.length()) {
2197 _session->save_template (name);
2207 ARDOUR_UI::edit_metadata ()
2209 SessionMetadataEditor dialog;
2210 dialog.set_session (_session);
2211 editor->ensure_float (dialog);
2216 ARDOUR_UI::import_metadata ()
2218 SessionMetadataImporter dialog;
2219 dialog.set_session (_session);
2220 editor->ensure_float (dialog);
2225 ARDOUR_UI::fontconfig_dialog ()
2228 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2229 may not and it can take a while to build it. Warn them.
2232 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2234 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2235 MessageDialog msg (*_startup,
2236 string_compose (_("Welcome to %1.\n\n"
2237 "The program will take a bit longer to start up\n"
2238 "while the system fonts are checked.\n\n"
2239 "This will only be done once, and you will\n"
2240 "not see this message again\n"), PROGRAM_NAME),
2253 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2255 existing_session = false;
2257 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2258 session_path = cmdline_path;
2259 existing_session = true;
2260 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2261 session_path = Glib::path_get_dirname (string (cmdline_path));
2262 existing_session = true;
2264 /* it doesn't exist, assume the best */
2265 session_path = Glib::path_get_dirname (string (cmdline_path));
2268 session_name = basename_nosuffix (string (cmdline_path));
2272 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2274 /* when this is called, the backend audio system must be running */
2276 /* the main idea here is to deal with the fact that a cmdline argument for the session
2277 can be interpreted in different ways - it could be a directory or a file, and before
2278 we load, we need to know both the session directory and the snapshot (statefile) within it
2279 that we are supposed to use.
2282 if (session_name.length() == 0 || session_path.length() == 0) {
2286 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2288 Glib::ustring predicted_session_file;
2290 predicted_session_file = session_path;
2291 predicted_session_file += '/';
2292 predicted_session_file += session_name;
2293 predicted_session_file += ARDOUR::statefile_suffix;
2295 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2296 existing_session = true;
2299 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2301 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2302 /* existing .ardour file */
2303 existing_session = true;
2307 existing_session = false;
2310 /* lets just try to load it */
2312 if (create_engine ()) {
2313 backend_audio_error (false, _startup);
2317 return load_session (session_path, session_name);
2321 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2323 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2325 MessageDialog msg (str,
2327 Gtk::MESSAGE_WARNING,
2328 Gtk::BUTTONS_YES_NO,
2332 msg.set_name (X_("OpenExistingDialog"));
2333 msg.set_title (_("Open Existing Session"));
2334 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2335 msg.set_position (Gtk::WIN_POS_MOUSE);
2338 switch (msg.run()) {
2347 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2349 BusProfile bus_profile;
2351 if (Profile->get_sae()) {
2353 bus_profile.master_out_channels = 2;
2354 bus_profile.input_ac = AutoConnectPhysical;
2355 bus_profile.output_ac = AutoConnectMaster;
2356 bus_profile.requested_physical_in = 0; // use all available
2357 bus_profile.requested_physical_out = 0; // use all available
2361 /* get settings from advanced section of NSD */
2363 if (_startup->create_master_bus()) {
2364 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2366 bus_profile.master_out_channels = 0;
2369 if (_startup->connect_inputs()) {
2370 bus_profile.input_ac = AutoConnectPhysical;
2372 bus_profile.input_ac = AutoConnectOption (0);
2375 /// @todo some minor tweaks.
2377 bus_profile.output_ac = AutoConnectOption (0);
2379 if (_startup->connect_outputs ()) {
2380 if (_startup->connect_outs_to_master()) {
2381 bus_profile.output_ac = AutoConnectMaster;
2382 } else if (_startup->connect_outs_to_physical()) {
2383 bus_profile.output_ac = AutoConnectPhysical;
2387 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2388 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2391 if (build_session (session_path, session_name, bus_profile)) {
2399 ARDOUR_UI::idle_load (const Glib::ustring& path)
2402 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2403 /* /path/to/foo => /path/to/foo, foo */
2404 load_session (path, basename_nosuffix (path));
2406 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2407 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2411 ARDOUR_COMMAND_LINE::session_name = path;
2414 * new_session_dialog doens't exist in A3
2415 * Try to remove all references to it to
2416 * see if it will compile. NOTE: this will
2417 * likely cause a runtime issue is my somewhat
2421 //if (new_session_dialog) {
2424 /* make it break out of Dialog::run() and
2428 //new_session_dialog->response (1);
2434 ARDOUR_UI::end_loading_messages ()
2440 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2443 // splash->message (msg);
2447 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2449 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2451 Glib::ustring session_name;
2452 Glib::ustring session_path;
2453 Glib::ustring template_name;
2455 bool likely_new = false;
2457 if (! load_template.empty()) {
2458 should_be_new = true;
2459 template_name = load_template;
2464 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2466 /* if they named a specific statefile, use it, otherwise they are
2467 just giving a session folder, and we want to use it as is
2468 to find the session.
2471 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2472 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2474 session_path = ARDOUR_COMMAND_LINE::session_name;
2477 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2481 bool const apply = run_startup (should_be_new, load_template);
2483 if (quit_on_cancel) {
2490 /* if we run the startup dialog again, offer more than just "new session" */
2492 should_be_new = false;
2494 session_name = _startup->session_name (likely_new);
2496 /* this shouldn't happen, but we catch it just in case it does */
2498 if (session_name.empty()) {
2501 if (_startup->use_session_template()) {
2502 template_name = _startup->session_template_name();
2503 _session_is_new = true;
2506 if (session_name[0] == '/' ||
2507 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2508 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2510 /* absolute path or cwd-relative path specified for session name: infer session folder
2511 from what was given.
2514 session_path = Glib::path_get_dirname (session_name);
2515 session_name = Glib::path_get_basename (session_name);
2519 session_path = _startup->session_folder();
2523 if (create_engine ()) {
2527 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2531 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2533 if (!ask_about_loading_existing_session (existing)) {
2534 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2539 _session_is_new = false;
2544 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2546 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2550 if (session_name.find ('/') != Glib::ustring::npos) {
2551 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2552 "session names may not contain a '/' character"));
2554 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2558 if (session_name.find ('\\') != Glib::ustring::npos) {
2559 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2560 "session names may not contain a '\\' character"));
2562 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2566 _session_is_new = true;
2569 if (likely_new && template_name.empty()) {
2571 ret = build_session_from_nsd (session_path, session_name);
2575 ret = load_session (session_path, session_name, template_name);
2576 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2577 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2587 ARDOUR_UI::close_session()
2589 if (!check_audioengine()) {
2593 if (unload_session (true)) {
2597 ARDOUR_COMMAND_LINE::session_name = "";
2599 if (get_session_parameters (true, false)) {
2603 goto_editor_window ();
2607 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2609 Session *new_session;
2613 session_loaded = false;
2615 if (!check_audioengine()) {
2619 unload_status = unload_session ();
2621 if (unload_status < 0) {
2623 } else if (unload_status > 0) {
2628 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2631 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2634 /* this one is special */
2636 catch (AudioEngine::PortRegistrationFailure& err) {
2638 MessageDialog msg (err.what(),
2641 Gtk::BUTTONS_CLOSE);
2643 msg.set_title (_("Port Registration Error"));
2644 msg.set_secondary_text (_("Click the Close button to try again."));
2645 msg.set_position (Gtk::WIN_POS_CENTER);
2649 int response = msg.run ();
2654 case RESPONSE_CANCEL:
2664 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2667 Gtk::BUTTONS_CLOSE);
2669 msg.set_title (_("Loading Error"));
2670 msg.set_secondary_text (_("Click the Close button to try again."));
2671 msg.set_position (Gtk::WIN_POS_CENTER);
2675 int response = msg.run ();
2680 case RESPONSE_CANCEL:
2688 /* Now the session been created, add the transport controls */
2689 new_session->add_controllable(roll_controllable);
2690 new_session->add_controllable(stop_controllable);
2691 new_session->add_controllable(goto_start_controllable);
2692 new_session->add_controllable(goto_end_controllable);
2693 new_session->add_controllable(auto_loop_controllable);
2694 new_session->add_controllable(play_selection_controllable);
2695 new_session->add_controllable(rec_controllable);
2697 set_session (new_session);
2699 session_loaded = true;
2701 goto_editor_window ();
2704 _session->set_clean ();
2715 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2717 Session *new_session;
2720 if (!check_audioengine()) {
2724 session_loaded = false;
2726 x = unload_session ();
2734 _session_is_new = true;
2737 new_session = new Session (*engine, path, snap_name, &bus_profile);
2742 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2748 set_session (new_session);
2750 session_loaded = true;
2752 new_session->save_state(new_session->name());
2758 ARDOUR_UI::launch_chat ()
2761 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2763 open_uri("http://webchat.freenode.net/?channels=ardour");
2768 ARDOUR_UI::show_about ()
2772 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2775 about->set_transient_for(*editor);
2780 ARDOUR_UI::launch_manual ()
2782 PBD::open_uri("http://ardour.org/flossmanual");
2786 ARDOUR_UI::launch_reference ()
2788 PBD::open_uri("http://ardour.org/refmanual");
2792 ARDOUR_UI::hide_about ()
2795 about->get_window()->set_cursor ();
2801 ARDOUR_UI::about_signal_response (int /*response*/)
2807 ARDOUR_UI::show_splash ()
2811 splash = new Splash;
2819 splash->queue_draw ();
2820 splash->get_window()->process_updates (true);
2825 ARDOUR_UI::hide_splash ()
2833 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2834 const string& plural_msg, const string& singular_msg)
2838 removed = rep.paths.size();
2841 MessageDialog msgd (*editor,
2842 _("No audio files were ready for cleanup"),
2845 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2846 msgd.set_secondary_text (_("If this seems suprising, \n\
2847 check for any existing snapshots.\n\
2848 These may still include regions that\n\
2849 require some unused files to continue to exist."));
2855 ArdourDialog results (_("Clean-up"), true, false);
2857 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2858 CleanupResultsModelColumns() {
2862 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2863 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2867 CleanupResultsModelColumns results_columns;
2868 Glib::RefPtr<Gtk::ListStore> results_model;
2869 Gtk::TreeView results_display;
2871 results_model = ListStore::create (results_columns);
2872 results_display.set_model (results_model);
2873 results_display.append_column (list_title, results_columns.visible_name);
2875 results_display.set_name ("CleanupResultsList");
2876 results_display.set_headers_visible (true);
2877 results_display.set_headers_clickable (false);
2878 results_display.set_reorderable (false);
2880 Gtk::ScrolledWindow list_scroller;
2883 Gtk::HBox dhbox; // the hbox for the image and text
2884 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2885 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2887 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2889 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2892 %1 - number of files removed
2893 %2 - location of "dead_sounds"
2894 %3 - size of files affected
2895 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2898 const char* bprefix;
2899 double space_adjusted = 0;
2901 if (rep.space < 100000.0f) {
2902 bprefix = X_("kilo");
2903 } else if (rep.space < 1000000.0f * 1000) {
2904 bprefix = X_("mega");
2905 space_adjusted = truncf((float)rep.space / 1000.0);
2907 bprefix = X_("giga");
2908 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2912 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2914 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2917 dhbox.pack_start (*dimage, true, false, 5);
2918 dhbox.pack_start (txt, true, false, 5);
2920 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2921 TreeModel::Row row = *(results_model->append());
2922 row[results_columns.visible_name] = *i;
2923 row[results_columns.fullpath] = *i;
2926 list_scroller.add (results_display);
2927 list_scroller.set_size_request (-1, 150);
2928 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2930 dvbox.pack_start (dhbox, true, false, 5);
2931 dvbox.pack_start (list_scroller, true, false, 5);
2932 ddhbox.pack_start (dvbox, true, false, 5);
2934 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2935 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2936 results.set_default_response (RESPONSE_CLOSE);
2937 results.set_position (Gtk::WIN_POS_MOUSE);
2939 results_display.show();
2940 list_scroller.show();
2947 //results.get_vbox()->show();
2948 results.set_resizable (false);
2955 ARDOUR_UI::cleanup ()
2957 if (_session == 0) {
2958 /* shouldn't happen: menu item is insensitive */
2963 MessageDialog checker (_("Are you sure you want to cleanup?"),
2965 Gtk::MESSAGE_QUESTION,
2966 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2968 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2969 ALL undo/redo information will be lost if you cleanup.\n\
2970 After cleanup, unused audio files will be moved to a \
2971 \"dead sounds\" location."));
2973 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2974 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2975 checker.set_default_response (RESPONSE_CANCEL);
2977 checker.set_name (_("CleanupDialog"));
2978 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
2979 checker.set_position (Gtk::WIN_POS_MOUSE);
2981 switch (checker.run()) {
2982 case RESPONSE_ACCEPT:
2988 ARDOUR::CleanupReport rep;
2990 editor->prepare_for_cleanup ();
2992 /* do not allow flush until a session is reloaded */
2994 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2996 act->set_sensitive (false);
2999 if (_session->cleanup_sources (rep)) {
3000 editor->finish_cleanup ();
3004 editor->finish_cleanup ();
3007 display_cleanup_results (rep,
3010 The following %1 files were not in use and \n\
3011 have been moved to:\n\
3013 Flushing the wastebasket will \n\
3014 release an additional\n\
3015 %3 %4bytes of disk space.\n"),
3017 The following file was not in use and \n \
3018 has been moved to:\n \
3020 Flushing the wastebasket will \n\
3021 release an additional\n\
3022 %3 %4bytes of disk space.\n"
3028 ARDOUR_UI::flush_trash ()
3030 if (_session == 0) {
3031 /* shouldn't happen: menu item is insensitive */
3035 ARDOUR::CleanupReport rep;
3037 if (_session->cleanup_trash_sources (rep)) {
3041 display_cleanup_results (rep,
3043 _("The following %1 files were deleted from\n\
3045 releasing %3 %4bytes of disk space"),
3046 _("The following file was deleted from\n\
3048 releasing %3 %4bytes of disk space"));
3052 ARDOUR_UI::add_route (Gtk::Window* float_window)
3060 if (add_route_dialog == 0) {
3061 add_route_dialog = new AddRouteDialog (_session);
3063 add_route_dialog->set_transient_for (*float_window);
3067 if (add_route_dialog->is_visible()) {
3068 /* we're already doing this */
3072 ResponseType r = (ResponseType) add_route_dialog->run ();
3074 add_route_dialog->hide();
3077 case RESPONSE_ACCEPT:
3084 if ((count = add_route_dialog->count()) <= 0) {
3088 string template_path = add_route_dialog->track_template();
3090 if (!template_path.empty()) {
3091 _session->new_route_from_template (count, template_path);
3095 uint32_t input_chan = add_route_dialog->channels ();
3096 uint32_t output_chan;
3097 string name_template = add_route_dialog->name_template ();
3098 bool track = add_route_dialog->track ();
3099 bool aux = !track && add_route_dialog->aux();
3100 RouteGroup* route_group = add_route_dialog->route_group ();
3102 AutoConnectOption oac = Config->get_output_auto_connect();
3104 if (oac & AutoConnectMaster) {
3105 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3107 output_chan = input_chan;
3110 /* XXX do something with name template */
3112 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3114 session_add_midi_track (route_group, count);
3116 MessageDialog msg (*editor,
3117 _("Sorry, MIDI Busses are not supported at this time."));
3119 //session_add_midi_bus();
3123 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3125 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3131 ARDOUR_UI::mixer_settings () const
3136 node = _session->instant_xml(X_("Mixer"));
3138 node = Config->instant_xml(X_("Mixer"));
3142 node = new XMLNode (X_("Mixer"));
3149 ARDOUR_UI::editor_settings () const
3154 node = _session->instant_xml(X_("Editor"));
3156 node = Config->instant_xml(X_("Editor"));
3160 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3161 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3166 node = new XMLNode (X_("Editor"));
3173 ARDOUR_UI::keyboard_settings () const
3177 node = Config->extra_xml(X_("Keyboard"));
3180 node = new XMLNode (X_("Keyboard"));
3186 ARDOUR_UI::create_xrun_marker(nframes_t where)
3188 editor->mouse_add_new_marker (where, false, true);
3192 ARDOUR_UI::halt_on_xrun_message ()
3194 MessageDialog msg (*editor,
3195 _("Recording was stopped because your system could not keep up."));
3200 ARDOUR_UI::xrun_handler(nframes_t where)
3206 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3208 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3209 create_xrun_marker(where);
3212 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3213 halt_on_xrun_message ();
3218 ARDOUR_UI::disk_overrun_handler ()
3220 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3222 if (!have_disk_speed_dialog_displayed) {
3223 have_disk_speed_dialog_displayed = true;
3224 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3225 The disk system on your computer\n\
3226 was not able to keep up with %1.\n\
3228 Specifically, it failed to write data to disk\n\
3229 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3230 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3236 ARDOUR_UI::disk_underrun_handler ()
3238 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3240 if (!have_disk_speed_dialog_displayed) {
3241 have_disk_speed_dialog_displayed = true;
3242 MessageDialog* msg = new MessageDialog (*editor,
3243 string_compose (_("The disk system on your computer\n\
3244 was not able to keep up with %1.\n\
3246 Specifically, it failed to read data from disk\n\
3247 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3248 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3254 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3256 have_disk_speed_dialog_displayed = false;
3261 ARDOUR_UI::session_dialog (std::string msg)
3263 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3268 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3270 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3279 ARDOUR_UI::pending_state_dialog ()
3281 HBox* hbox = new HBox();
3282 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3283 ArdourDialog dialog (_("Crash Recovery"), true);
3285 This session appears to have been in\n\
3286 middle of recording when ardour or\n\
3287 the computer was shutdown.\n\
3289 Ardour can recover any captured audio for\n\
3290 you, or it can ignore it. Please decide\n\
3291 what you would like to do.\n"));
3292 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3293 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3294 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3295 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3296 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3297 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3298 dialog.set_default_response (RESPONSE_ACCEPT);
3299 dialog.set_position (WIN_POS_CENTER);
3304 switch (dialog.run ()) {
3305 case RESPONSE_ACCEPT:
3313 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3315 HBox* hbox = new HBox();
3316 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3317 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3318 Label message (string_compose (_("\
3319 This session was created with a sample rate of %1 Hz\n\
3321 The audioengine is currently running at %2 Hz\n"), desired, actual));
3323 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3324 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3325 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3326 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3327 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3328 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3329 dialog.set_default_response (RESPONSE_ACCEPT);
3330 dialog.set_position (WIN_POS_CENTER);
3335 switch (dialog.run ()) {
3336 case RESPONSE_ACCEPT:
3345 ARDOUR_UI::disconnect_from_jack ()
3348 if( engine->disconnect_from_jack ()) {
3349 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3353 update_sample_rate (0);
3358 ARDOUR_UI::reconnect_to_jack ()
3361 if (engine->reconnect_to_jack ()) {
3362 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3366 update_sample_rate (0);
3371 ARDOUR_UI::use_config ()
3373 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3375 set_transport_controllable_state (*node);
3380 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3382 if (Config->get_primary_clock_delta_edit_cursor()) {
3383 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3385 primary_clock.set (pos, 0, true);
3388 if (Config->get_secondary_clock_delta_edit_cursor()) {
3389 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3391 secondary_clock.set (pos);
3394 if (big_clock_window->get()) {
3395 big_clock.set (pos);
3401 ARDOUR_UI::step_edit_status_change (bool yn)
3403 // XXX should really store pre-step edit status of things
3404 // we make insensitive
3407 rec_button.set_visual_state (3);
3408 rec_button.set_sensitive (false);
3410 rec_button.set_visual_state (0);
3411 rec_button.set_sensitive (true);
3416 ARDOUR_UI::record_state_changed ()
3418 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3420 if (!_session || !big_clock_window->get()) {
3421 /* why bother - the clock isn't visible */
3425 Session::RecordState const r = _session->record_status ();
3426 bool const h = _session->have_rec_enabled_track ();
3428 if (r == Session::Recording && h) {
3429 big_clock.set_widget_name ("BigClockRecording");
3431 big_clock.set_widget_name ("BigClockNonRecording");
3436 ARDOUR_UI::first_idle ()
3439 _session->allow_auto_play (true);
3443 editor->first_idle();
3446 Keyboard::set_can_save_keybindings (true);
3451 ARDOUR_UI::store_clock_modes ()
3453 XMLNode* node = new XMLNode(X_("ClockModes"));
3455 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3456 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3459 _session->add_extra_xml (*node);
3460 _session->set_dirty ();
3465 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3466 : Controllable (name), ui (u), type(tp)
3472 ARDOUR_UI::TransportControllable::set_value (double val)
3474 if (type == ShuttleControl) {
3481 fract = -((0.5 - val)/0.5);
3483 fract = ((val - 0.5)/0.5);
3487 ui.set_shuttle_fract (fract);
3492 /* do nothing: these are radio-style actions */
3496 const char *action = 0;
3500 action = X_("Roll");
3503 action = X_("Stop");
3506 action = X_("Goto Start");
3509 action = X_("Goto End");
3512 action = X_("Loop");
3515 action = X_("Play Selection");
3518 action = X_("Record");
3528 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3536 ARDOUR_UI::TransportControllable::get_value (void) const
3555 case ShuttleControl:
3565 ARDOUR_UI::TransportControllable::set_id (const string& str)
3571 ARDOUR_UI::setup_profile ()
3573 if (gdk_screen_width() < 1200) {
3574 Profile->set_small_screen ();
3578 if (getenv ("ARDOUR_SAE")) {
3579 Profile->set_sae ();
3580 Profile->set_single_package ();
3585 ARDOUR_UI::toggle_translations ()
3587 using namespace Glib;
3589 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3591 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3594 string i18n_killer = ARDOUR::translation_kill_path();
3596 bool already_enabled = !ARDOUR::translations_are_disabled ();
3598 if (ract->get_active ()) {
3599 /* we don't care about errors */
3600 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3603 /* we don't care about errors */
3604 unlink (i18n_killer.c_str());
3607 if (already_enabled != ract->get_active()) {
3608 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3610 Gtk::MESSAGE_WARNING,
3612 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3613 win.set_position (Gtk::WIN_POS_CENTER);
3621 /** Add a window proxy to our list, so that its state will be saved.
3622 * This call also causes the window to be created and opened if its
3623 * state was saved as `visible'.
3626 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3628 _window_proxies.push_back (p);
3632 /** Remove a window proxy from our list. Must be called if a WindowProxy
3633 * is deleted, to prevent hanging pointers.
3636 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3638 _window_proxies.remove (p);