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/stop_signal.h"
53 #include "gtkmm2ext/popup.h"
54 #include "gtkmm2ext/window_title.h"
56 #include "midi++/manager.h"
58 #include "ardour/ardour.h"
59 #include "ardour/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"
103 using namespace ARDOUR;
105 using namespace Gtkmm2ext;
108 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
109 UIConfiguration *ARDOUR_UI::ui_config = 0;
111 sigc::signal<void,bool> ARDOUR_UI::Blink;
112 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
113 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
114 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
116 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
118 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
120 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
121 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
122 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
123 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
127 preroll_button (_("pre\nroll")),
128 postroll_button (_("post\nroll")),
132 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
136 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
137 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
138 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
139 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
140 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
141 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
142 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
143 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
144 shuttle_controller_binding_proxy (shuttle_controllable),
146 roll_button (roll_controllable),
147 stop_button (stop_controllable),
148 goto_start_button (goto_start_controllable),
149 goto_end_button (goto_end_controllable),
150 auto_loop_button (auto_loop_controllable),
151 play_selection_button (play_selection_controllable),
152 rec_button (rec_controllable),
154 shuttle_units_button (_("% ")),
156 punch_in_button (_("Punch In")),
157 punch_out_button (_("Punch Out")),
158 auto_return_button (_("Auto Return")),
159 auto_play_button (_("Auto Play")),
160 auto_input_button (_("Auto Input")),
161 click_button (_("Click")),
162 time_master_button (_("time\nmaster")),
164 auditioning_alert_button (_("AUDITION")),
165 solo_alert_button (_("SOLO")),
167 error_log_button (_("Errors"))
170 using namespace Gtk::Menu_Helpers;
176 // _auto_display_errors = false;
178 * This was commented out as it wasn't defined
179 * in A3 IIRC. If this is not needed it should
180 * be completely removed.
188 if (theArdourUI == 0) {
192 ui_config = new UIConfiguration();
193 theme_manager = new ThemeManager();
199 _session_is_new = false;
200 big_clock_window = 0;
201 big_clock_height = 0;
202 big_clock_resize_in_progress = false;
203 session_selector_window = 0;
204 last_key_press_time = 0;
205 _will_create_new_session_automatically = false;
206 add_route_dialog = 0;
208 rc_option_editor = 0;
209 session_option_editor = 0;
211 open_session_selector = 0;
212 have_configure_timeout = false;
213 have_disk_speed_dialog_displayed = false;
214 session_loaded = false;
215 last_speed_displayed = -1.0f;
216 ignore_dual_punch = false;
217 _mixer_on_top = false;
218 original_big_clock_width = -1;
219 original_big_clock_height = -1;
220 original_big_clock_font_size = 0;
222 roll_button.unset_flags (Gtk::CAN_FOCUS);
223 stop_button.unset_flags (Gtk::CAN_FOCUS);
224 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
225 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
226 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
227 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
228 rec_button.unset_flags (Gtk::CAN_FOCUS);
230 last_configure_time= 0;
232 shuttle_grabbed = false;
234 shuttle_max_speed = 8.0f;
236 shuttle_style_menu = 0;
237 shuttle_unit_menu = 0;
239 // We do not have jack linked in yet so;
241 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
243 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
244 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
246 /* handle dialog requests */
248 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
250 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
252 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
254 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
256 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
258 /* lets get this party started */
261 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
262 throw failed_constructor ();
265 setup_gtk_ardour_enums ();
268 GainMeter::setup_slider_pix ();
269 RouteTimeAxisView::setup_slider_pix ();
270 SendProcessorEntry::setup_slider_pix ();
271 SessionEvent::create_per_thread_pool ("GUI", 512);
273 } catch (failed_constructor& err) {
274 error << _("could not initialize Ardour.") << endmsg;
279 /* we like keyboards */
281 keyboard = new ArdourKeyboard(*this);
283 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
285 keyboard->set_state (*node, Stateful::loading_state_version);
290 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
291 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
296 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
298 ARDOUR_UI::run_startup (bool should_be_new)
301 _startup = new ArdourStartup ();
304 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
306 if (audio_setup && _startup->engine_control()) {
307 _startup->engine_control()->set_state (*audio_setup);
310 _startup->set_new_only (should_be_new);
311 _startup->present ();
317 switch (_startup->response()) {
326 ARDOUR_UI::create_engine ()
328 // this gets called every time by new_session()
334 loading_message (_("Starting audio engine"));
337 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
344 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
345 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
346 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
348 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
356 ARDOUR_UI::post_engine ()
358 /* Things to be done once we create the AudioEngine
361 MIDI::Manager::instance()->set_api_data (engine->jack());
364 ARDOUR::init_post_engine ();
366 ActionManager::init ();
369 if (setup_windows ()) {
370 throw failed_constructor ();
373 check_memory_locking();
375 /* this is the first point at which all the keybindings are available */
377 if (ARDOUR_COMMAND_LINE::show_key_actions) {
378 vector<string> names;
379 vector<string> paths;
381 vector<AccelKey> bindings;
383 ActionManager::get_all_actions (names, paths, keys, bindings);
385 vector<string>::iterator n;
386 vector<string>::iterator k;
387 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
388 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
394 blink_timeout_tag = -1;
396 /* this being a GUI and all, we want peakfiles */
398 AudioFileSource::set_build_peakfiles (true);
399 AudioFileSource::set_build_missing_peakfiles (true);
401 /* set default clock modes */
403 if (Profile->get_sae()) {
404 primary_clock.set_mode (AudioClock::BBT);
405 secondary_clock.set_mode (AudioClock::MinSec);
407 primary_clock.set_mode (AudioClock::Timecode);
408 secondary_clock.set_mode (AudioClock::BBT);
411 /* start the time-of-day-clock */
414 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
415 update_wall_clock ();
416 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
419 update_disk_space ();
421 update_sample_rate (engine->frame_rate());
423 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
424 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
425 Config->map_parameters (pc);
427 /* now start and maybe save state */
429 if (do_engine_start () == 0) {
430 if (_session && _session_is_new) {
431 /* we need to retain initial visual
432 settings for a new session
434 _session->save_state ("");
439 ARDOUR_UI::~ARDOUR_UI ()
444 delete add_route_dialog;
448 ARDOUR_UI::pop_back_splash ()
450 if (Splash::instance()) {
451 // Splash::instance()->pop_back();
452 Splash::instance()->hide ();
457 ARDOUR_UI::configure_timeout ()
459 if (last_configure_time == 0) {
460 /* no configure events yet */
464 /* force a gap of 0.5 seconds since the last configure event
467 if (get_microseconds() - last_configure_time < 500000) {
470 have_configure_timeout = false;
471 cerr << "config event-driven save\n";
472 save_ardour_state ();
478 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
480 if (have_configure_timeout) {
481 last_configure_time = get_microseconds();
483 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
484 have_configure_timeout = true;
491 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
493 const XMLProperty* prop;
495 if ((prop = node.property ("roll")) != 0) {
496 roll_controllable->set_id (prop->value());
498 if ((prop = node.property ("stop")) != 0) {
499 stop_controllable->set_id (prop->value());
501 if ((prop = node.property ("goto-start")) != 0) {
502 goto_start_controllable->set_id (prop->value());
504 if ((prop = node.property ("goto-end")) != 0) {
505 goto_end_controllable->set_id (prop->value());
507 if ((prop = node.property ("auto-loop")) != 0) {
508 auto_loop_controllable->set_id (prop->value());
510 if ((prop = node.property ("play-selection")) != 0) {
511 play_selection_controllable->set_id (prop->value());
513 if ((prop = node.property ("rec")) != 0) {
514 rec_controllable->set_id (prop->value());
516 if ((prop = node.property ("shuttle")) != 0) {
517 shuttle_controllable->set_id (prop->value());
522 ARDOUR_UI::get_transport_controllable_state ()
524 XMLNode* node = new XMLNode(X_("TransportControllables"));
527 roll_controllable->id().print (buf, sizeof (buf));
528 node->add_property (X_("roll"), buf);
529 stop_controllable->id().print (buf, sizeof (buf));
530 node->add_property (X_("stop"), buf);
531 goto_start_controllable->id().print (buf, sizeof (buf));
532 node->add_property (X_("goto_start"), buf);
533 goto_end_controllable->id().print (buf, sizeof (buf));
534 node->add_property (X_("goto_end"), buf);
535 auto_loop_controllable->id().print (buf, sizeof (buf));
536 node->add_property (X_("auto_loop"), buf);
537 play_selection_controllable->id().print (buf, sizeof (buf));
538 node->add_property (X_("play_selection"), buf);
539 rec_controllable->id().print (buf, sizeof (buf));
540 node->add_property (X_("rec"), buf);
541 shuttle_controllable->id().print (buf, sizeof (buf));
542 node->add_property (X_("shuttle"), buf);
549 ARDOUR_UI::autosave_session ()
551 if (g_main_depth() > 1) {
552 /* inside a recursive main loop,
553 give up because we may not be able to
559 if (!Config->get_periodic_safety_backups()) {
564 _session->maybe_write_autosave();
571 ARDOUR_UI::update_autosave ()
573 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
575 if (_session && _session->dirty()) {
576 if (_autosave_connection.connected()) {
577 _autosave_connection.disconnect();
580 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
581 Config->get_periodic_safety_backup_interval() * 1000);
584 if (_autosave_connection.connected()) {
585 _autosave_connection.disconnect();
591 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
595 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
597 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
600 MessageDialog win (title,
606 win.set_secondary_text(_("There are several possible reasons:\n\
608 1) You requested audio parameters that are not supported..\n\
609 2) JACK is running as another user.\n\
611 Please consider the possibilities, and perhaps try different parameters."));
613 win.set_secondary_text(_("There are several possible reasons:\n\
615 1) JACK is not running.\n\
616 2) JACK is running as another user, perhaps root.\n\
617 3) There is already another client called \"ardour\".\n\
619 Please consider the possibilities, and perhaps (re)start JACK."));
623 win.set_transient_for (*toplevel);
627 win.add_button (Stock::OK, RESPONSE_CLOSE);
629 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
632 win.set_default_response (RESPONSE_CLOSE);
635 win.set_position (Gtk::WIN_POS_CENTER);
638 /* we just don't care about the result, but we want to block */
644 ARDOUR_UI::startup ()
646 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session)) {
652 goto_editor_window ();
654 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
659 ARDOUR_UI::no_memory_warning ()
661 XMLNode node (X_("no-memory-warning"));
662 Config->add_instant_xml (node);
666 ARDOUR_UI::check_memory_locking ()
669 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
673 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
675 if (engine->is_realtime() && memory_warning_node == 0) {
677 struct rlimit limits;
679 long pages, page_size;
681 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
684 ram = (int64_t) pages * (int64_t) page_size;
687 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
691 if (limits.rlim_cur != RLIM_INFINITY) {
693 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
696 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
697 "This might cause %1 to run out of memory before your system "
698 "runs out of memory. \n\n"
699 "You can view the memory limit with 'ulimit -l', "
700 "and it is normally controlled by /etc/security/limits.conf"),
701 PROGRAM_NAME).c_str());
703 VBox* vbox = msg.get_vbox();
705 CheckButton cb (_("Do not show this window again"));
707 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
709 hbox.pack_start (cb, true, false);
710 vbox->pack_start (hbox);
717 editor->ensure_float (msg);
732 if (_session->transport_rolling() && (++tries < 8)) {
733 _session->request_stop (false, true);
737 if (_session->dirty()) {
738 switch (ask_about_saving_session(_("quit"))) {
743 /* use the default name */
744 if (save_state_canfail ("")) {
745 /* failed - don't quit */
746 MessageDialog msg (*editor,
748 Ardour was unable to save your session.\n\n\
749 If you still wish to quit, please use the\n\n\
750 \"Just quit\" option."));
761 second_connection.disconnect ();
762 point_one_second_connection.disconnect ();
763 point_oh_five_second_connection.disconnect ();
764 point_zero_one_second_connection.disconnect();
766 // _session->set_deletion_in_progress ();
767 _session->remove_pending_capture_state ();
772 ArdourDialog::close_all_dialogs ();
774 cerr << "Save before quit\n";
775 save_ardour_state ();
780 ARDOUR_UI::ask_about_saving_session (const string & what)
782 ArdourDialog window (_("ardour: save session?"));
783 Gtk::HBox dhbox; // the hbox for the image and text
784 Gtk::Label prompt_label;
785 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
789 msg = string_compose(_("Don't %1"), what);
790 window.add_button (msg, RESPONSE_REJECT);
791 msg = string_compose(_("Just %1"), what);
792 window.add_button (msg, RESPONSE_APPLY);
793 msg = string_compose(_("Save and %1"), what);
794 window.add_button (msg, RESPONSE_ACCEPT);
796 window.set_default_response (RESPONSE_ACCEPT);
798 Gtk::Button noquit_button (msg);
799 noquit_button.set_name ("EditorGTKButton");
804 if (_session->snap_name() == _session->name()) {
807 type = _("snapshot");
809 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?"),
810 type, _session->snap_name());
812 prompt_label.set_text (prompt);
813 prompt_label.set_name (X_("PrompterLabel"));
814 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
816 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
817 dhbox.set_homogeneous (false);
818 dhbox.pack_start (*dimage, false, false, 5);
819 dhbox.pack_start (prompt_label, true, false, 5);
820 window.get_vbox()->pack_start (dhbox);
822 window.set_name (_("Prompter"));
823 window.set_position (Gtk::WIN_POS_MOUSE);
824 window.set_modal (true);
825 window.set_resizable (false);
831 window.set_keep_above (true);
834 ResponseType r = (ResponseType) window.run();
839 case RESPONSE_ACCEPT: // save and get out of here
841 case RESPONSE_APPLY: // get out of here
851 ARDOUR_UI::every_second ()
854 update_buffer_load ();
855 update_disk_space ();
860 ARDOUR_UI::every_point_one_seconds ()
862 update_speed_display ();
863 RapidScreenUpdate(); /* EMIT_SIGNAL */
868 ARDOUR_UI::every_point_zero_one_seconds ()
870 // august 2007: actual update frequency: 40Hz, not 100Hz
872 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
877 ARDOUR_UI::update_sample_rate (nframes_t)
881 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
883 if (!engine->connected()) {
885 snprintf (buf, sizeof (buf), _("disconnected"));
889 nframes_t rate = engine->frame_rate();
891 if (fmod (rate, 1000.0) != 0.0) {
892 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
893 (float) rate/1000.0f,
894 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
896 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
898 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
902 sample_rate_label.set_text (buf);
906 ARDOUR_UI::update_cpu_load ()
909 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
910 cpu_load_label.set_text (buf);
914 ARDOUR_UI::update_buffer_load ()
920 c = _session->capture_load ();
921 p = _session->playback_load ();
923 push_buffer_stats (c, p);
925 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
926 _session->playback_load(), _session->capture_load());
927 buffer_load_label.set_text (buf);
929 buffer_load_label.set_text ("");
934 ARDOUR_UI::count_recenabled_streams (Route& route)
936 Track* track = dynamic_cast<Track*>(&route);
937 if (track && track->diskstream()->record_enabled()) {
938 rec_enabled_streams += track->n_inputs().n_total();
943 ARDOUR_UI::update_disk_space()
949 nframes_t frames = _session->available_capture_duration();
951 nframes_t fr = _session->frame_rate();
953 if (frames == max_frames) {
954 strcpy (buf, _("Disk: 24hrs+"));
956 rec_enabled_streams = 0;
957 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
959 if (rec_enabled_streams) {
960 frames /= rec_enabled_streams;
967 hrs = frames / (fr * 3600);
968 frames -= hrs * fr * 3600;
969 mins = frames / (fr * 60);
970 frames -= mins * fr * 60;
973 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
976 disk_space_label.set_text (buf);
978 // An attempt to make the disk space label flash red when space has run out.
980 if (frames < fr * 60 * 5) {
981 /* disk_space_box.style ("disk_space_label_empty"); */
983 /* disk_space_box.style ("disk_space_label"); */
989 ARDOUR_UI::update_wall_clock ()
996 tm_now = localtime (&now);
998 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
999 wall_clock_label.set_text (buf);
1005 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1007 session_popup_menu->popup (0, 0);
1012 ARDOUR_UI::redisplay_recent_sessions ()
1014 std::vector<sys::path> session_directories;
1015 RecentSessionsSorter cmp;
1017 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1018 recent_session_model->clear ();
1020 ARDOUR::RecentSessions rs;
1021 ARDOUR::read_recent_sessions (rs);
1024 recent_session_display.set_model (recent_session_model);
1028 // sort them alphabetically
1029 sort (rs.begin(), rs.end(), cmp);
1031 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1032 session_directories.push_back ((*i).second);
1035 for (vector<sys::path>::const_iterator i = session_directories.begin();
1036 i != session_directories.end(); ++i)
1038 std::vector<sys::path> state_file_paths;
1040 // now get available states for this session
1042 get_state_files_in_directory (*i, state_file_paths);
1044 vector<string*>* states;
1045 vector<const gchar*> item;
1046 string fullpath = (*i).to_string();
1048 /* remove any trailing / */
1050 if (fullpath[fullpath.length()-1] == '/') {
1051 fullpath = fullpath.substr (0, fullpath.length()-1);
1054 /* check whether session still exists */
1055 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1056 /* session doesn't exist */
1057 cerr << "skipping non-existent session " << fullpath << endl;
1061 /* now get available states for this session */
1063 if ((states = Session::possible_states (fullpath)) == 0) {
1064 /* no state file? */
1068 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1070 Gtk::TreeModel::Row row = *(recent_session_model->append());
1072 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1073 row[recent_session_columns.fullpath] = fullpath;
1075 if (state_file_names.size() > 1) {
1079 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1080 i2 != state_file_names.end(); ++i2)
1083 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1085 child_row[recent_session_columns.visible_name] = *i2;
1086 child_row[recent_session_columns.fullpath] = fullpath;
1091 recent_session_display.set_model (recent_session_model);
1095 ARDOUR_UI::build_session_selector ()
1097 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1099 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1101 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1102 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1103 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1104 recent_session_model = TreeStore::create (recent_session_columns);
1105 recent_session_display.set_model (recent_session_model);
1106 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1107 recent_session_display.set_headers_visible (false);
1108 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1109 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1111 scroller->add (recent_session_display);
1112 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1114 session_selector_window->set_name ("SessionSelectorWindow");
1115 session_selector_window->set_size_request (200, 400);
1116 session_selector_window->get_vbox()->pack_start (*scroller);
1118 recent_session_display.show();
1120 //session_selector_window->get_vbox()->show();
1124 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1126 session_selector_window->response (RESPONSE_ACCEPT);
1130 ARDOUR_UI::open_recent_session ()
1132 bool can_return = (_session != 0);
1134 if (session_selector_window == 0) {
1135 build_session_selector ();
1138 redisplay_recent_sessions ();
1142 session_selector_window->set_position (WIN_POS_MOUSE);
1144 ResponseType r = (ResponseType) session_selector_window->run ();
1147 case RESPONSE_ACCEPT:
1151 session_selector_window->hide();
1158 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1162 session_selector_window->hide();
1164 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1166 if (i == recent_session_model->children().end()) {
1170 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1171 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1173 _session_is_new = false;
1175 if (load_session (path, state) == 0) {
1184 ARDOUR_UI::check_audioengine ()
1187 if (!engine->connected()) {
1188 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1189 "You cannot open or close sessions in this condition"),
1202 ARDOUR_UI::open_session ()
1204 if (!check_audioengine()) {
1209 /* popup selector window */
1211 if (open_session_selector == 0) {
1213 /* ardour sessions are folders */
1215 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1216 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1217 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1218 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1220 FileFilter session_filter;
1221 session_filter.add_pattern ("*.ardour");
1222 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1223 open_session_selector->add_filter (session_filter);
1224 open_session_selector->set_filter (session_filter);
1227 int response = open_session_selector->run();
1228 open_session_selector->hide ();
1231 case RESPONSE_ACCEPT:
1234 open_session_selector->hide();
1238 open_session_selector->hide();
1239 string session_path = open_session_selector->get_filename();
1243 if (session_path.length() > 0) {
1244 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1245 _session_is_new = isnew;
1246 load_session (path, name);
1253 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1255 list<boost::shared_ptr<MidiTrack> > tracks;
1257 if (_session == 0) {
1258 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1265 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1267 if (tracks.size() != how_many) {
1268 if (how_many == 1) {
1269 error << _("could not create a new midi track") << endmsg;
1271 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1275 if ((route = _session->new_midi_route ()) == 0) {
1276 error << _("could not create new midi bus") << endmsg;
1282 MessageDialog msg (*editor,
1283 _("There are insufficient JACK ports available\n\
1284 to create a new track or bus.\n\
1285 You should save Ardour, exit and\n\
1286 restart JACK with more ports."));
1293 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)
1295 list<boost::shared_ptr<AudioTrack> > tracks;
1298 if (_session == 0) {
1299 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1305 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1307 if (tracks.size() != how_many) {
1308 if (how_many == 1) {
1309 error << _("could not create a new audio track") << endmsg;
1311 error << string_compose (_("could only create %1 of %2 new audio %3"),
1312 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1318 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1320 if (routes.size() != how_many) {
1321 if (how_many == 1) {
1322 error << _("could not create a new audio track") << endmsg;
1324 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1331 MessageDialog msg (*editor,
1332 _("There are insufficient JACK ports available\n\
1333 to create a new track or bus.\n\
1334 You should save Ardour, exit and\n\
1335 restart JACK with more ports."));
1342 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1344 nframes_t _preroll = 0;
1347 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1348 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1350 if (new_position > _preroll) {
1351 new_position -= _preroll;
1356 _session->request_locate (new_position);
1361 ARDOUR_UI::transport_goto_start ()
1364 _session->goto_start();
1366 /* force displayed area in editor to start no matter
1367 what "follow playhead" setting is.
1371 editor->center_screen (_session->current_start_frame ());
1377 ARDOUR_UI::transport_goto_zero ()
1380 _session->request_locate (0);
1382 /* force displayed area in editor to start no matter
1383 what "follow playhead" setting is.
1387 editor->reset_x_origin (0);
1393 ARDOUR_UI::transport_goto_wallclock ()
1395 if (_session && editor) {
1402 localtime_r (&now, &tmnow);
1404 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1405 frames += tmnow.tm_min * (60 * _session->frame_rate());
1406 frames += tmnow.tm_sec * _session->frame_rate();
1408 _session->request_locate (frames);
1410 /* force displayed area in editor to start no matter
1411 what "follow playhead" setting is.
1415 editor->center_screen (frames);
1421 ARDOUR_UI::transport_goto_end ()
1424 nframes_t const frame = _session->current_end_frame();
1425 _session->request_locate (frame);
1427 /* force displayed area in editor to start no matter
1428 what "follow playhead" setting is.
1432 editor->center_screen (frame);
1438 ARDOUR_UI::transport_stop ()
1444 if (_session->is_auditioning()) {
1445 _session->cancel_audition ();
1449 _session->request_stop (false, true);
1453 ARDOUR_UI::transport_stop_and_forget_capture ()
1456 _session->request_stop (true, true);
1461 ARDOUR_UI::remove_last_capture()
1464 editor->remove_last_capture();
1469 ARDOUR_UI::transport_record (bool roll)
1473 switch (_session->record_status()) {
1474 case Session::Disabled:
1475 if (_session->ntracks() == 0) {
1476 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1480 _session->maybe_enable_record ();
1485 case Session::Recording:
1487 _session->request_stop();
1489 _session->disable_record (false, true);
1493 case Session::Enabled:
1494 _session->disable_record (false, true);
1497 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1501 ARDOUR_UI::transport_roll ()
1507 if (_session->is_auditioning()) {
1511 if (_session->config.get_external_sync()) {
1512 switch (_session->config.get_sync_source()) {
1516 /* transport controlled by the master */
1521 bool rolling = _session->transport_rolling();
1523 if (_session->get_play_loop()) {
1524 /* XXX it is not possible to just leave seamless loop and keep
1525 playing at present (nov 4th 2009)
1527 if (!Config->get_seamless_loop()) {
1528 _session->request_play_loop (false, true);
1530 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1531 /* stop playing a range if we currently are */
1532 _session->request_play_range (0, true);
1535 if (join_play_range_button.get_active()) {
1536 _session->request_play_range (&editor->get_selection().time, true);
1540 _session->request_transport_speed (1.0f);
1545 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1552 if (_session->is_auditioning()) {
1553 _session->cancel_audition ();
1557 if (_session->config.get_external_sync()) {
1558 switch (_session->config.get_sync_source()) {
1562 /* transport controlled by the master */
1567 bool rolling = _session->transport_rolling();
1568 bool affect_transport = true;
1570 if (rolling && roll_out_of_bounded_mode) {
1571 /* drop out of loop/range playback but leave transport rolling */
1572 if (_session->get_play_loop()) {
1573 if (Config->get_seamless_loop()) {
1574 /* the disk buffers contain copies of the loop - we can't
1575 just keep playing, so stop the transport. the user
1576 can restart as they wish.
1578 affect_transport = true;
1580 /* disk buffers are normal, so we can keep playing */
1581 affect_transport = false;
1583 _session->request_play_loop (false, true);
1584 } else if (_session->get_play_range ()) {
1585 affect_transport = false;
1586 _session->request_play_range (0, true);
1590 if (affect_transport) {
1592 _session->request_stop (with_abort, true);
1594 if (join_play_range_button.get_active()) {
1595 _session->request_play_range (&editor->get_selection().time, true);
1598 _session->request_transport_speed (1.0f);
1604 ARDOUR_UI::toggle_session_auto_loop ()
1607 if (_session->get_play_loop()) {
1608 if (_session->transport_rolling()) {
1609 Location * looploc = _session->locations()->auto_loop_location();
1611 _session->request_locate (looploc->start(), true);
1614 _session->request_play_loop (false);
1617 Location * looploc = _session->locations()->auto_loop_location();
1619 _session->request_play_loop (true);
1626 ARDOUR_UI::transport_play_selection ()
1632 editor->play_selection ();
1636 ARDOUR_UI::transport_rewind (int option)
1638 float current_transport_speed;
1641 current_transport_speed = _session->transport_speed();
1643 if (current_transport_speed >= 0.0f) {
1646 _session->request_transport_speed (-1.0f);
1649 _session->request_transport_speed (-4.0f);
1652 _session->request_transport_speed (-0.5f);
1657 _session->request_transport_speed (current_transport_speed * 1.5f);
1663 ARDOUR_UI::transport_forward (int option)
1665 float current_transport_speed;
1668 current_transport_speed = _session->transport_speed();
1670 if (current_transport_speed <= 0.0f) {
1673 _session->request_transport_speed (1.0f);
1676 _session->request_transport_speed (4.0f);
1679 _session->request_transport_speed (0.5f);
1684 _session->request_transport_speed (current_transport_speed * 1.5f);
1691 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1693 if (_session == 0) {
1697 boost::shared_ptr<Route> r;
1699 if ((r = _session->route_by_remote_id (dstream)) != 0) {
1703 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1704 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1707 if (_session == 0) {
1713 ARDOUR_UI::map_transport_state ()
1715 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1718 auto_loop_button.set_visual_state (0);
1719 play_selection_button.set_visual_state (0);
1720 roll_button.set_visual_state (0);
1721 stop_button.set_visual_state (1);
1725 float sp = _session->transport_speed();
1728 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1729 shuttle_box.queue_draw ();
1730 } else if (sp == 0.0f) {
1732 shuttle_box.queue_draw ();
1733 update_disk_space ();
1740 if (_session->get_play_range()) {
1742 play_selection_button.set_visual_state (1);
1743 roll_button.set_visual_state (0);
1744 auto_loop_button.set_visual_state (0);
1746 } else if (_session->get_play_loop ()) {
1748 auto_loop_button.set_visual_state (1);
1749 play_selection_button.set_visual_state (0);
1750 roll_button.set_visual_state (0);
1754 roll_button.set_visual_state (1);
1755 play_selection_button.set_visual_state (0);
1756 auto_loop_button.set_visual_state (0);
1759 if (join_play_range_button.get_active()) {
1760 /* light up both roll and play-selection if they are joined */
1761 roll_button.set_visual_state (1);
1762 play_selection_button.set_visual_state (1);
1765 stop_button.set_visual_state (0);
1769 stop_button.set_visual_state (1);
1770 roll_button.set_visual_state (0);
1771 play_selection_button.set_visual_state (0);
1772 auto_loop_button.set_visual_state (0);
1777 ARDOUR_UI::engine_stopped ()
1779 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1780 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1781 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1785 ARDOUR_UI::engine_running ()
1787 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1788 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1789 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1791 Glib::RefPtr<Action> action;
1792 const char* action_name = 0;
1794 switch (engine->frames_per_cycle()) {
1796 action_name = X_("JACKLatency32");
1799 action_name = X_("JACKLatency64");
1802 action_name = X_("JACKLatency128");
1805 action_name = X_("JACKLatency512");
1808 action_name = X_("JACKLatency1024");
1811 action_name = X_("JACKLatency2048");
1814 action_name = X_("JACKLatency4096");
1817 action_name = X_("JACKLatency8192");
1820 /* XXX can we do anything useful ? */
1826 action = ActionManager::get_action (X_("JACK"), action_name);
1829 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1830 ract->set_active ();
1836 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1838 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1839 /* we can't rely on the original string continuing to exist when we are called
1840 again in the GUI thread, so make a copy and note that we need to
1843 char *copy = strdup (reason);
1844 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1848 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1849 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1851 update_sample_rate (0);
1855 /* if the reason is a non-empty string, it means that the backend was shutdown
1856 rather than just Ardour.
1859 if (strlen (reason)) {
1860 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1863 JACK has either been shutdown or it\n\
1864 disconnected Ardour because Ardour\n\
1865 was not fast enough. Try to restart\n\
1866 JACK, reconnect and save the session.");
1869 MessageDialog msg (*editor, msgstr);
1874 free ((char*) reason);
1879 ARDOUR_UI::do_engine_start ()
1887 error << _("Unable to start the session running")
1897 ARDOUR_UI::setup_theme ()
1899 theme_manager->setup_theme();
1903 ARDOUR_UI::update_clocks ()
1905 if (!editor || !editor->dragging_playhead()) {
1906 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1911 ARDOUR_UI::start_clocking ()
1913 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1917 ARDOUR_UI::stop_clocking ()
1919 clock_signal_connection.disconnect ();
1923 ARDOUR_UI::toggle_clocking ()
1926 if (clock_button.get_active()) {
1935 ARDOUR_UI::_blink (void *arg)
1938 ((ARDOUR_UI *) arg)->blink ();
1945 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1949 ARDOUR_UI::start_blinking ()
1951 /* Start the blink signal. Everybody with a blinking widget
1952 uses Blink to drive the widget's state.
1955 if (blink_timeout_tag < 0) {
1957 blink_timeout_tag = g_timeout_add (240, _blink, this);
1962 ARDOUR_UI::stop_blinking ()
1964 if (blink_timeout_tag >= 0) {
1965 g_source_remove (blink_timeout_tag);
1966 blink_timeout_tag = -1;
1971 /** Ask the user for the name of a new shapshot and then take it.
1975 ARDOUR_UI::snapshot_session (bool switch_to_it)
1977 ArdourPrompter prompter (true);
1980 prompter.set_name ("Prompter");
1981 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1982 prompter.set_title (_("Take Snapshot"));
1983 prompter.set_title (_("Take Snapshot"));
1984 prompter.set_prompt (_("Name of New Snapshot"));
1986 if (!switch_to_it) {
1989 struct tm local_time;
1992 localtime_r (&n, &local_time);
1993 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1994 prompter.set_initial_text (timebuf);
1998 switch (prompter.run()) {
1999 case RESPONSE_ACCEPT:
2001 prompter.get_result (snapname);
2003 bool do_save = (snapname.length() != 0);
2006 if (snapname.find ('/') != string::npos) {
2007 MessageDialog msg (_("To ensure compatibility with various systems\n"
2008 "snapshot names may not contain a '/' character"));
2012 if (snapname.find ('\\') != string::npos) {
2013 MessageDialog msg (_("To ensure compatibility with various systems\n"
2014 "snapshot names may not contain a '\\' character"));
2020 vector<sys::path> p;
2021 get_state_files_in_directory (_session->session_directory().root_path(), p);
2022 vector<string> n = get_file_names_no_extension (p);
2023 if (find (n.begin(), n.end(), snapname) != n.end()) {
2025 ArdourDialog confirm (_("Confirm snapshot overwrite"), true);
2026 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2027 confirm.get_vbox()->pack_start (m, true, true);
2028 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2029 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2030 confirm.show_all ();
2031 switch (confirm.run()) {
2032 case RESPONSE_CANCEL:
2038 save_state (snapname, switch_to_it);
2049 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2051 save_state_canfail (name, switch_to_it);
2055 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2060 if (name.length() == 0) {
2061 name = _session->snap_name();
2064 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2068 cerr << "SS canfail\n";
2069 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2074 ARDOUR_UI::primary_clock_value_changed ()
2077 _session->request_locate (primary_clock.current_time ());
2082 ARDOUR_UI::big_clock_value_changed ()
2085 _session->request_locate (big_clock.current_time ());
2090 ARDOUR_UI::secondary_clock_value_changed ()
2093 _session->request_locate (secondary_clock.current_time ());
2098 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2100 if (_session == 0) {
2104 Session::RecordState const r = _session->record_status ();
2105 bool const h = _session->have_rec_enabled_diskstream ();
2107 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2109 rec_button.set_visual_state (2);
2111 rec_button.set_visual_state (0);
2113 } else if (r == Session::Recording && h) {
2114 rec_button.set_visual_state (1);
2116 rec_button.set_visual_state (0);
2121 ARDOUR_UI::save_template ()
2123 ArdourPrompter prompter (true);
2126 if (!check_audioengine()) {
2130 prompter.set_name (X_("Prompter"));
2131 prompter.set_title (_("Save Mix Template"));
2132 prompter.set_prompt (_("Name for mix template:"));
2133 prompter.set_initial_text(_session->name() + _("-template"));
2134 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2136 switch (prompter.run()) {
2137 case RESPONSE_ACCEPT:
2138 prompter.get_result (name);
2140 if (name.length()) {
2141 _session->save_template (name);
2151 ARDOUR_UI::edit_metadata ()
2153 SessionMetadataEditor dialog;
2154 dialog.set_session (_session);
2155 editor->ensure_float (dialog);
2160 ARDOUR_UI::import_metadata ()
2162 SessionMetadataImporter dialog;
2163 dialog.set_session (_session);
2164 editor->ensure_float (dialog);
2169 ARDOUR_UI::fontconfig_dialog ()
2172 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2173 may not and it can take a while to build it. Warn them.
2176 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2178 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2179 MessageDialog msg (*_startup,
2180 _("Welcome to Ardour.\n\n"
2181 "The program will take a bit longer to start up\n"
2182 "while the system fonts are checked.\n\n"
2183 "This will only be done once, and you will\n"
2184 "not see this message again\n"),
2197 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2199 existing_session = false;
2201 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2202 session_path = cmdline_path;
2203 existing_session = true;
2204 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2205 session_path = Glib::path_get_dirname (string (cmdline_path));
2206 existing_session = true;
2208 /* it doesn't exist, assume the best */
2209 session_path = Glib::path_get_dirname (string (cmdline_path));
2212 session_name = basename_nosuffix (string (cmdline_path));
2216 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2218 /* when this is called, the backend audio system must be running */
2220 /* the main idea here is to deal with the fact that a cmdline argument for the session
2221 can be interpreted in different ways - it could be a directory or a file, and before
2222 we load, we need to know both the session directory and the snapshot (statefile) within it
2223 that we are supposed to use.
2226 if (session_name.length() == 0 || session_path.length() == 0) {
2230 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2232 Glib::ustring predicted_session_file;
2234 predicted_session_file = session_path;
2235 predicted_session_file += '/';
2236 predicted_session_file += session_name;
2237 predicted_session_file += ARDOUR::statefile_suffix;
2239 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2240 existing_session = true;
2243 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2245 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2246 /* existing .ardour file */
2247 existing_session = true;
2251 existing_session = false;
2254 /* lets just try to load it */
2256 if (create_engine ()) {
2257 backend_audio_error (false, _startup);
2261 return load_session (session_path, session_name);
2265 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2267 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2269 MessageDialog msg (str,
2271 Gtk::MESSAGE_WARNING,
2272 Gtk::BUTTONS_YES_NO,
2276 msg.set_name (X_("OpenExistingDialog"));
2277 msg.set_title (_("Open Existing Session"));
2278 msg.set_wmclass (X_("existing_session"), "Ardour");
2279 msg.set_position (Gtk::WIN_POS_MOUSE);
2282 switch (msg.run()) {
2291 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2293 BusProfile bus_profile;
2295 if (Profile->get_sae()) {
2297 bus_profile.master_out_channels = 2;
2298 bus_profile.input_ac = AutoConnectPhysical;
2299 bus_profile.output_ac = AutoConnectMaster;
2300 bus_profile.requested_physical_in = 0; // use all available
2301 bus_profile.requested_physical_out = 0; // use all available
2305 /* get settings from advanced section of NSD */
2307 if (_startup->create_master_bus()) {
2308 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2310 bus_profile.master_out_channels = 0;
2313 if (_startup->connect_inputs()) {
2314 bus_profile.input_ac = AutoConnectPhysical;
2316 bus_profile.input_ac = AutoConnectOption (0);
2319 /// @todo some minor tweaks.
2321 bus_profile.output_ac = AutoConnectOption (0);
2323 if (_startup->connect_outputs ()) {
2324 if (_startup->connect_outs_to_master()) {
2325 bus_profile.output_ac = AutoConnectMaster;
2326 } else if (_startup->connect_outs_to_physical()) {
2327 bus_profile.output_ac = AutoConnectPhysical;
2331 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2332 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2335 if (build_session (session_path, session_name, bus_profile)) {
2343 ARDOUR_UI::idle_load (const Glib::ustring& path)
2346 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2347 /* /path/to/foo => /path/to/foo, foo */
2348 load_session (path, basename_nosuffix (path));
2350 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2351 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2355 ARDOUR_COMMAND_LINE::session_name = path;
2358 * new_session_dialog doens't exist in A3
2359 * Try to remove all references to it to
2360 * see if it will compile. NOTE: this will
2361 * likely cause a runtime issue is my somewhat
2365 //if (new_session_dialog) {
2368 /* make it break out of Dialog::run() and
2372 //new_session_dialog->response (1);
2378 ARDOUR_UI::end_loading_messages ()
2384 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2387 // splash->message (msg);
2391 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2393 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new)
2395 Glib::ustring session_name;
2396 Glib::ustring session_path;
2397 Glib::ustring template_name;
2399 bool likely_new = false;
2403 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2405 /* if they named a specific statefile, use it, otherwise they are
2406 just giving a session folder, and we want to use it as is
2407 to find the session.
2410 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2411 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2413 session_path = ARDOUR_COMMAND_LINE::session_name;
2416 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2420 bool const apply = run_startup (should_be_new);
2422 if (quit_on_cancel) {
2429 /* if we run the startup dialog again, offer more than just "new session" */
2431 should_be_new = false;
2433 session_name = _startup->session_name (likely_new);
2435 /* this shouldn't happen, but we catch it just in case it does */
2437 if (session_name.empty()) {
2440 if (_startup->use_session_template()) {
2441 template_name = _startup->session_template_name();
2442 _session_is_new = true;
2445 if (session_name[0] == '/' ||
2446 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2447 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2449 /* absolute path or cwd-relative path specified for session name: infer session folder
2450 from what was given.
2453 session_path = Glib::path_get_dirname (session_name);
2454 session_name = Glib::path_get_basename (session_name);
2458 session_path = _startup->session_folder();
2462 if (create_engine ()) {
2466 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2470 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2472 if (!ask_about_loading_existing_session (existing)) {
2473 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2478 _session_is_new = false;
2483 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2485 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2489 if (session_name.find ('/') != Glib::ustring::npos) {
2490 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2491 "session names may not contain a '/' character"));
2493 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2497 if (session_name.find ('\\') != Glib::ustring::npos) {
2498 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2499 "session names may not contain a '\\' character"));
2501 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2505 _session_is_new = true;
2508 if (likely_new && template_name.empty()) {
2510 ret = build_session_from_nsd (session_path, session_name);
2514 ret = load_session (session_path, session_name, template_name);
2515 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2516 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2526 ARDOUR_UI::close_session()
2528 if (!check_audioengine()) {
2532 if (unload_session (true)) {
2536 ARDOUR_COMMAND_LINE::session_name = "";
2537 get_session_parameters (true, false);
2541 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2543 Session *new_session;
2547 session_loaded = false;
2549 if (!check_audioengine()) {
2553 unload_status = unload_session ();
2555 if (unload_status < 0) {
2557 } else if (unload_status > 0) {
2562 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2565 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2568 /* this one is special */
2570 catch (AudioEngine::PortRegistrationFailure& err) {
2572 MessageDialog msg (err.what(),
2575 Gtk::BUTTONS_CLOSE);
2577 msg.set_title (_("Port Registration Error"));
2578 msg.set_secondary_text (_("Click the Close button to try again."));
2579 msg.set_position (Gtk::WIN_POS_CENTER);
2583 int response = msg.run ();
2588 case RESPONSE_CANCEL:
2598 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2601 Gtk::BUTTONS_CLOSE);
2603 msg.set_title (_("Loading Error"));
2604 msg.set_secondary_text (_("Click the Close button to try again."));
2605 msg.set_position (Gtk::WIN_POS_CENTER);
2609 int response = msg.run ();
2614 case RESPONSE_CANCEL:
2622 set_session (new_session);
2624 session_loaded = true;
2626 goto_editor_window ();
2629 _session->set_clean ();
2640 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2642 Session *new_session;
2645 if (!check_audioengine()) {
2649 session_loaded = false;
2651 x = unload_session ();
2659 _session_is_new = true;
2662 new_session = new Session (*engine, path, snap_name, &bus_profile);
2667 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2673 set_session (new_session);
2675 session_loaded = true;
2677 new_session->save_state(new_session->name());
2686 editor->show_window ();
2697 ARDOUR_UI::launch_chat ()
2700 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2702 open_uri("http://webchat.freenode.net/?channels=ardour");
2707 ARDOUR_UI::show_about ()
2711 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2714 about->set_transient_for(*editor);
2719 ARDOUR_UI::hide_about ()
2722 about->get_window()->set_cursor ();
2728 ARDOUR_UI::about_signal_response (int /*response*/)
2734 ARDOUR_UI::show_splash ()
2738 splash = new Splash;
2746 splash->queue_draw ();
2747 splash->get_window()->process_updates (true);
2752 ARDOUR_UI::hide_splash ()
2760 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2761 const string& plural_msg, const string& singular_msg)
2765 removed = rep.paths.size();
2768 MessageDialog msgd (*editor,
2769 _("No audio files were ready for cleanup"),
2772 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2773 msgd.set_secondary_text (_("If this seems suprising, \n\
2774 check for any existing snapshots.\n\
2775 These may still include regions that\n\
2776 require some unused files to continue to exist."));
2782 ArdourDialog results (_("ardour: cleanup"), true, false);
2784 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2785 CleanupResultsModelColumns() {
2789 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2790 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2794 CleanupResultsModelColumns results_columns;
2795 Glib::RefPtr<Gtk::ListStore> results_model;
2796 Gtk::TreeView results_display;
2798 results_model = ListStore::create (results_columns);
2799 results_display.set_model (results_model);
2800 results_display.append_column (list_title, results_columns.visible_name);
2802 results_display.set_name ("CleanupResultsList");
2803 results_display.set_headers_visible (true);
2804 results_display.set_headers_clickable (false);
2805 results_display.set_reorderable (false);
2807 Gtk::ScrolledWindow list_scroller;
2810 Gtk::HBox dhbox; // the hbox for the image and text
2811 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2812 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2814 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2816 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2819 %1 - number of files removed
2820 %2 - location of "dead_sounds"
2821 %3 - size of files affected
2822 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2825 const char* bprefix;
2826 double space_adjusted = 0;
2828 if (rep.space < 100000.0f) {
2829 bprefix = X_("kilo");
2830 } else if (rep.space < 1000000.0f * 1000) {
2831 bprefix = X_("mega");
2832 space_adjusted = truncf((float)rep.space / 1000.0);
2834 bprefix = X_("giga");
2835 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2839 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2841 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2844 dhbox.pack_start (*dimage, true, false, 5);
2845 dhbox.pack_start (txt, true, false, 5);
2847 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2848 TreeModel::Row row = *(results_model->append());
2849 row[results_columns.visible_name] = *i;
2850 row[results_columns.fullpath] = *i;
2853 list_scroller.add (results_display);
2854 list_scroller.set_size_request (-1, 150);
2855 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2857 dvbox.pack_start (dhbox, true, false, 5);
2858 dvbox.pack_start (list_scroller, true, false, 5);
2859 ddhbox.pack_start (dvbox, true, false, 5);
2861 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2862 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2863 results.set_default_response (RESPONSE_CLOSE);
2864 results.set_position (Gtk::WIN_POS_MOUSE);
2866 results_display.show();
2867 list_scroller.show();
2874 //results.get_vbox()->show();
2875 results.set_resizable (false);
2882 ARDOUR_UI::cleanup ()
2884 if (_session == 0) {
2885 /* shouldn't happen: menu item is insensitive */
2890 MessageDialog checker (_("Are you sure you want to cleanup?"),
2892 Gtk::MESSAGE_QUESTION,
2893 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2895 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2896 ALL undo/redo information will be lost if you cleanup.\n\
2897 After cleanup, unused audio files will be moved to a \
2898 \"dead sounds\" location."));
2900 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2901 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2902 checker.set_default_response (RESPONSE_CANCEL);
2904 checker.set_name (_("CleanupDialog"));
2905 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2906 checker.set_position (Gtk::WIN_POS_MOUSE);
2908 switch (checker.run()) {
2909 case RESPONSE_ACCEPT:
2915 ARDOUR::CleanupReport rep;
2917 editor->prepare_for_cleanup ();
2919 /* do not allow flush until a session is reloaded */
2921 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2923 act->set_sensitive (false);
2926 if (_session->cleanup_sources (rep)) {
2927 editor->finish_cleanup ();
2931 editor->finish_cleanup ();
2934 display_cleanup_results (rep,
2937 The following %1 files were not in use and \n\
2938 have been moved to:\n\
2940 Flushing the wastebasket will \n\
2941 release an additional\n\
2942 %3 %4bytes of disk space.\n"),
2944 The following file was not in use and \n \
2945 has been moved to:\n \
2947 Flushing the wastebasket will \n\
2948 release an additional\n\
2949 %3 %4bytes of disk space.\n"
2955 ARDOUR_UI::flush_trash ()
2957 if (_session == 0) {
2958 /* shouldn't happen: menu item is insensitive */
2962 ARDOUR::CleanupReport rep;
2964 if (_session->cleanup_trash_sources (rep)) {
2968 display_cleanup_results (rep,
2970 _("The following %1 files were deleted from\n\
2972 releasing %3 %4bytes of disk space"),
2973 _("The following file was deleted from\n\
2975 releasing %3 %4bytes of disk space"));
2979 ARDOUR_UI::add_route (Gtk::Window* float_window)
2987 if (add_route_dialog == 0) {
2988 add_route_dialog = new AddRouteDialog (_session);
2990 add_route_dialog->set_transient_for (*float_window);
2994 if (add_route_dialog->is_visible()) {
2995 /* we're already doing this */
2999 ResponseType r = (ResponseType) add_route_dialog->run ();
3001 add_route_dialog->hide();
3004 case RESPONSE_ACCEPT:
3011 if ((count = add_route_dialog->count()) <= 0) {
3015 string template_path = add_route_dialog->track_template();
3017 if (!template_path.empty()) {
3018 _session->new_route_from_template (count, template_path);
3022 uint32_t input_chan = add_route_dialog->channels ();
3023 uint32_t output_chan;
3024 string name_template = add_route_dialog->name_template ();
3025 bool track = add_route_dialog->track ();
3026 bool aux = !track && add_route_dialog->aux();
3027 RouteGroup* route_group = add_route_dialog->route_group ();
3029 AutoConnectOption oac = Config->get_output_auto_connect();
3031 if (oac & AutoConnectMaster) {
3032 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3034 output_chan = input_chan;
3037 /* XXX do something with name template */
3039 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3041 session_add_midi_track (route_group, count);
3043 MessageDialog msg (*editor,
3044 _("Sorry, MIDI Busses are not supported at this time."));
3046 //session_add_midi_bus();
3050 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3052 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3058 ARDOUR_UI::mixer_settings () const
3063 node = _session->instant_xml(X_("Mixer"));
3065 node = Config->instant_xml(X_("Mixer"));
3069 node = new XMLNode (X_("Mixer"));
3076 ARDOUR_UI::editor_settings () const
3081 node = _session->instant_xml(X_("Editor"));
3083 node = Config->instant_xml(X_("Editor"));
3087 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3088 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3093 node = new XMLNode (X_("Editor"));
3100 ARDOUR_UI::keyboard_settings () const
3104 node = Config->extra_xml(X_("Keyboard"));
3107 node = new XMLNode (X_("Keyboard"));
3113 ARDOUR_UI::create_xrun_marker(nframes_t where)
3115 editor->mouse_add_new_marker (where, false, true);
3119 ARDOUR_UI::halt_on_xrun_message ()
3121 MessageDialog msg (*editor,
3122 _("Recording was stopped because your system could not keep up."));
3127 ARDOUR_UI::xrun_handler(nframes_t where)
3133 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3135 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3136 create_xrun_marker(where);
3139 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3140 halt_on_xrun_message ();
3145 ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
3150 while (disk_buffer_stats.size() > 60) {
3151 disk_buffer_stats.pop_front ();
3154 disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
3158 ARDOUR_UI::write_buffer_stats ()
3163 char path[PATH_MAX+1]; int fd;
3165 strcpy (path, "ardourBufferingXXXXXX");
3167 if ((fd = mkstemp (path )) < 0) {
3168 cerr << X_("cannot find temporary name for buffer stats") << endl;
3176 cerr << string_compose (X_("cannot open file %1 for buffer stats"), path) << endl;
3180 for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
3181 localtime_r (&(*i).when, &tm);
3182 strftime (buf, sizeof (buf), "%T", &tm);
3183 fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
3186 disk_buffer_stats.clear ();
3190 cerr << "buffering statistics can be found in: " << path << endl;
3194 ARDOUR_UI::disk_overrun_handler ()
3196 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3198 write_buffer_stats ();
3200 if (!have_disk_speed_dialog_displayed) {
3201 have_disk_speed_dialog_displayed = true;
3202 MessageDialog* msg = new MessageDialog (*editor, _("\
3203 The disk system on your computer\n\
3204 was not able to keep up with Ardour.\n\
3206 Specifically, it failed to write data to disk\n\
3207 quickly enough to keep up with recording.\n"));
3208 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3214 ARDOUR_UI::disk_underrun_handler ()
3216 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3218 write_buffer_stats ();
3220 if (!have_disk_speed_dialog_displayed) {
3221 have_disk_speed_dialog_displayed = true;
3222 MessageDialog* msg = new MessageDialog (*editor,
3223 _("The disk system on your computer\n\
3224 was not able to keep up with Ardour.\n\
3226 Specifically, it failed to read data from disk\n\
3227 quickly enough to keep up with playback.\n"));
3228 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3234 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3236 have_disk_speed_dialog_displayed = false;
3241 ARDOUR_UI::session_dialog (std::string msg)
3243 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3248 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3250 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3259 ARDOUR_UI::pending_state_dialog ()
3261 HBox* hbox = new HBox();
3262 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3263 ArdourDialog dialog (_("Crash Recovery"), true);
3265 This session appears to have been in\n\
3266 middle of recording when ardour or\n\
3267 the computer was shutdown.\n\
3269 Ardour can recover any captured audio for\n\
3270 you, or it can ignore it. Please decide\n\
3271 what you would like to do.\n"));
3272 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3273 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3274 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3275 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3276 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3277 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3278 dialog.set_default_response (RESPONSE_ACCEPT);
3279 dialog.set_position (WIN_POS_CENTER);
3284 switch (dialog.run ()) {
3285 case RESPONSE_ACCEPT:
3293 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3295 HBox* hbox = new HBox();
3296 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3297 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3298 Label message (string_compose (_("\
3299 This session was created with a sample rate of %1 Hz\n\
3301 The audioengine is currently running at %2 Hz\n"), desired, actual));
3303 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3304 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3305 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3306 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3307 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3308 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3309 dialog.set_default_response (RESPONSE_ACCEPT);
3310 dialog.set_position (WIN_POS_CENTER);
3315 switch (dialog.run ()) {
3316 case RESPONSE_ACCEPT:
3325 ARDOUR_UI::disconnect_from_jack ()
3328 if( engine->disconnect_from_jack ()) {
3329 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3333 update_sample_rate (0);
3338 ARDOUR_UI::reconnect_to_jack ()
3341 if (engine->reconnect_to_jack ()) {
3342 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3346 update_sample_rate (0);
3351 ARDOUR_UI::use_config ()
3354 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3356 set_transport_controllable_state (*node);
3359 node = Config->extra_xml (X_("UI"));
3362 const XMLProperty* prop = node->property (X_("show-big-clock"));
3363 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleBigClock"));
3365 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
3366 tact->set_active (string_is_affirmative (prop->value()));
3372 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3374 if (Config->get_primary_clock_delta_edit_cursor()) {
3375 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3377 primary_clock.set (pos, 0, true);
3380 if (Config->get_secondary_clock_delta_edit_cursor()) {
3381 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3383 secondary_clock.set (pos);
3386 if (big_clock_window) {
3387 big_clock.set (pos);
3392 ARDOUR_UI::record_state_changed ()
3394 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3396 if (!_session || !big_clock_window) {
3397 /* why bother - the clock isn't visible */
3401 Session::RecordState const r = _session->record_status ();
3402 bool const h = _session->have_rec_enabled_diskstream ();
3404 if (r == Session::Recording && h) {
3405 big_clock.set_widget_name ("BigClockRecording");
3407 big_clock.set_widget_name ("BigClockNonRecording");
3412 ARDOUR_UI::first_idle ()
3415 _session->allow_auto_play (true);
3419 editor->first_idle();
3422 Keyboard::set_can_save_keybindings (true);
3427 ARDOUR_UI::store_clock_modes ()
3429 XMLNode* node = new XMLNode(X_("ClockModes"));
3431 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3432 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3435 _session->add_extra_xml (*node);
3436 _session->set_dirty ();
3441 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3442 : Controllable (name), ui (u), type(tp)
3448 ARDOUR_UI::TransportControllable::set_value (float val)
3450 if (type == ShuttleControl) {
3457 fract = -((0.5f - val)/0.5f);
3459 fract = ((val - 0.5f)/0.5f);
3463 ui.set_shuttle_fract (fract);
3468 /* do nothing: these are radio-style actions */
3472 const char *action = 0;
3476 action = X_("Roll");
3479 action = X_("Stop");
3482 action = X_("Goto Start");
3485 action = X_("Goto End");
3488 action = X_("Loop");
3491 action = X_("Play Selection");
3494 action = X_("Record");
3504 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3512 ARDOUR_UI::TransportControllable::get_value (void) const
3531 case ShuttleControl:
3541 ARDOUR_UI::TransportControllable::set_id (const string& str)
3547 ARDOUR_UI::setup_profile ()
3549 if (gdk_screen_width() < 1200) {
3550 Profile->set_small_screen ();
3554 if (getenv ("ARDOUR_SAE")) {
3555 Profile->set_sae ();
3556 Profile->set_single_package ();