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.
21 #include "gtk2ardour-config.h"
37 #include <sys/resource.h>
39 #include <gtkmm/messagedialog.h>
40 #include <gtkmm/accelmap.h>
42 #include "pbd/error.h"
43 #include "pbd/basename.h"
44 #include "pbd/compose.h"
45 #include "pbd/failed_constructor.h"
46 #include "pbd/enumwriter.h"
47 #include "pbd/memento_command.h"
48 #include "pbd/openuri.h"
49 #include "pbd/file_utils.h"
51 #include "gtkmm2ext/application.h"
52 #include "gtkmm2ext/gtk_ui.h"
53 #include "gtkmm2ext/utils.h"
54 #include "gtkmm2ext/click_box.h"
55 #include "gtkmm2ext/fastmeter.h"
56 #include "gtkmm2ext/popup.h"
57 #include "gtkmm2ext/window_title.h"
59 #include "midi++/manager.h"
61 #include "ardour/ardour.h"
62 #include "ardour/callback.h"
63 #include "ardour/profile.h"
64 #include "ardour/session_directory.h"
65 #include "ardour/session_route.h"
66 #include "ardour/session_state_utils.h"
67 #include "ardour/session_utils.h"
68 #include "ardour/port.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/playlist.h"
71 #include "ardour/utils.h"
72 #include "ardour/audio_diskstream.h"
73 #include "ardour/audiofilesource.h"
74 #include "ardour/recent_sessions.h"
75 #include "ardour/port.h"
76 #include "ardour/audio_track.h"
77 #include "ardour/midi_track.h"
78 #include "ardour/filesystem_paths.h"
79 #include "ardour/filename_extensions.h"
81 typedef uint64_t microseconds_t
;
85 #include "add_route_dialog.h"
86 #include "ambiguous_file_dialog.h"
87 #include "ardour_ui.h"
88 #include "audio_clock.h"
89 #include "bundle_manager.h"
90 #include "engine_dialog.h"
91 #include "gain_meter.h"
92 #include "global_port_matrix.h"
93 #include "gui_thread.h"
95 #include "location_ui.h"
96 #include "missing_file_dialog.h"
97 #include "missing_plugin_dialog.h"
100 #include "processor_box.h"
101 #include "prompter.h"
102 #include "public_editor.h"
103 #include "route_time_axis.h"
104 #include "session_metadata_dialog.h"
105 #include "speaker_dialog.h"
108 #include "theme_manager.h"
109 #include "time_axis_view_item.h"
111 #include "window_proxy.h"
115 using namespace ARDOUR
;
117 using namespace Gtkmm2ext
;
120 ARDOUR_UI
*ARDOUR_UI::theArdourUI
= 0;
121 UIConfiguration
*ARDOUR_UI::ui_config
= 0;
123 sigc::signal
<void,bool> ARDOUR_UI::Blink
;
124 sigc::signal
<void> ARDOUR_UI::RapidScreenUpdate
;
125 sigc::signal
<void> ARDOUR_UI::SuperRapidScreenUpdate
;
126 sigc::signal
<void, framepos_t
, bool, framepos_t
> ARDOUR_UI::Clock
;
128 bool could_be_a_valid_path (const string
& path
);
130 ARDOUR_UI::ARDOUR_UI (int *argcp
, char **argvp
[])
132 : Gtkmm2ext::UI (PROGRAM_NAME
, argcp
, argvp
),
134 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
135 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
136 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
137 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
141 preroll_button (_("pre\nroll")),
142 postroll_button (_("post\nroll")),
146 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
150 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll
)),
151 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop
)),
152 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart
)),
153 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd
)),
154 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop
)),
155 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection
)),
156 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable
)),
157 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl
)),
158 shuttle_controller_binding_proxy (shuttle_controllable
),
160 roll_button (roll_controllable
),
161 stop_button (stop_controllable
),
162 goto_start_button (goto_start_controllable
),
163 goto_end_button (goto_end_controllable
),
164 auto_loop_button (auto_loop_controllable
),
165 play_selection_button (play_selection_controllable
),
166 rec_button (rec_controllable
),
168 shuttle_units_button (_("% ")),
170 punch_in_button (_("Punch In")),
171 punch_out_button (_("Punch Out")),
172 auto_return_button (_("Auto Return")),
173 auto_play_button (_("Auto Play")),
174 auto_input_button (_("Auto Input")),
175 click_button (_("Click")),
176 time_master_button (_("time\nmaster")),
178 auditioning_alert_button (_("AUDITION")),
179 solo_alert_button (_("SOLO")),
181 error_log_button (_("Errors"))
184 using namespace Gtk::Menu_Helpers
;
190 // _auto_display_errors = false;
192 * This was commented out as it wasn't defined
193 * in A3 IIRC. If this is not needed it should
194 * be completely removed.
202 if (theArdourUI
== 0) {
206 ui_config
= new UIConfiguration();
207 theme_manager
= new ThemeManager();
213 _session_is_new
= false;
214 big_clock_window
= 0;
215 big_clock_height
= 0;
216 big_clock_resize_in_progress
= false;
217 session_selector_window
= 0;
218 last_key_press_time
= 0;
219 _will_create_new_session_automatically
= false;
220 add_route_dialog
= 0;
222 rc_option_editor
= 0;
223 session_option_editor
= 0;
225 open_session_selector
= 0;
226 have_configure_timeout
= false;
227 have_disk_speed_dialog_displayed
= false;
228 session_loaded
= false;
229 last_speed_displayed
= -1.0f
;
230 ignore_dual_punch
= false;
231 original_big_clock_width
= -1;
232 original_big_clock_height
= -1;
233 original_big_clock_font_size
= 0;
235 roll_button
.unset_flags (Gtk::CAN_FOCUS
);
236 stop_button
.unset_flags (Gtk::CAN_FOCUS
);
237 goto_start_button
.unset_flags (Gtk::CAN_FOCUS
);
238 goto_end_button
.unset_flags (Gtk::CAN_FOCUS
);
239 auto_loop_button
.unset_flags (Gtk::CAN_FOCUS
);
240 play_selection_button
.unset_flags (Gtk::CAN_FOCUS
);
241 rec_button
.unset_flags (Gtk::CAN_FOCUS
);
243 last_configure_time
= 0;
245 shuttle_grabbed
= false;
247 shuttle_max_speed
= 8.0f
;
249 shuttle_style_menu
= 0;
250 shuttle_unit_menu
= 0;
252 // We do not have jack linked in yet so;
254 last_shuttle_request
= last_peak_grab
= 0; // get_microseconds();
256 ARDOUR::Diskstream::DiskOverrun
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::disk_overrun_handler
, this), gui_context());
257 ARDOUR::Diskstream::DiskUnderrun
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::disk_underrun_handler
, this), gui_context());
259 /* handle dialog requests */
261 ARDOUR::Session::Dialog
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::session_dialog
, this, _1
), gui_context());
263 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
265 ARDOUR::Session::AskAboutPendingState
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::pending_state_dialog
, this));
267 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
269 ARDOUR::Session::AskAboutSampleRateMismatch
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::sr_mismatch_dialog
, this, _1
, _2
));
271 /* handle requests to quit (coming from JACK session) */
273 ARDOUR::Session::Quit
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::finish
, this), gui_context ());
275 /* handle requests to deal with missing files */
277 ARDOUR::Session::MissingFile
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::missing_file
, this, _1
, _2
, _3
));
279 /* and ambiguous files */
281 ARDOUR::FileSource::AmbiguousFileName
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::ambiguous_file
, this, _1
, _2
, _3
));
283 /* lets get this party started */
286 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst
, ARDOUR_COMMAND_LINE::try_hw_optimization
)) {
287 throw failed_constructor ();
290 setup_gtk_ardour_enums ();
293 GainMeter::setup_slider_pix ();
294 RouteTimeAxisView::setup_slider_pix ();
295 SendProcessorEntry::setup_slider_pix ();
296 SessionEvent::create_per_thread_pool ("GUI", 512);
298 } catch (failed_constructor
& err
) {
299 error
<< string_compose (_("could not initialize %1."), PROGRAM_NAME
) << endmsg
;
304 /* we like keyboards */
306 keyboard
= new ArdourKeyboard(*this);
308 XMLNode
* node
= ARDOUR_UI::instance()->keyboard_settings();
310 keyboard
->set_state (*node
, Stateful::loading_state_version
);
315 TimeAxisViewItem::set_constant_heights ();
317 /* The following must happen after ARDOUR::init() so that Config is set up */
319 location_ui
= new ActionWindowProxy
<LocationUIWindow
> (X_("locations"), Config
->extra_xml (X_("UI")), X_("ToggleLocations"));
320 big_clock_window
= new ActionWindowProxy
<Gtk::Window
> (X_("bigclock"), Config
->extra_xml (X_("UI")), X_("ToggleBigClock"));
321 speaker_config_window
= new ActionWindowProxy
<SpeakerDialog
> (X_("speakerconf"), Config
->extra_xml (X_("UI")), X_("toggle-speaker-config"));
323 for (ARDOUR::DataType::iterator i
= ARDOUR::DataType::begin(); i
!= ARDOUR::DataType::end(); ++i
) {
324 _global_port_matrix
[*i
] = new ActionWindowProxy
<GlobalPortMatrixWindow
> (
325 string_compose ("GlobalPortMatrix-%1", (*i
).to_string()),
326 Config
->extra_xml (X_("UI")),
327 string_compose ("toggle-%1-connection-manager", (*i
).to_string())
332 speaker_config_window
->set (new SpeakerDialog
);
334 starting
.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup
));
335 stopping
.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown
));
340 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
342 ARDOUR_UI::run_startup (bool should_be_new
, string load_template
)
345 _startup
= new ArdourStartup ();
347 XMLNode
* audio_setup
= Config
->extra_xml ("AudioSetup");
349 if (audio_setup
&& _startup
->engine_control()) {
350 _startup
->engine_control()->set_state (*audio_setup
);
353 _startup
->set_new_only (should_be_new
);
354 if (!load_template
.empty()) {
355 _startup
->set_load_template( load_template
);
357 _startup
->present ();
363 switch (_startup
->response()) {
372 ARDOUR_UI::create_engine ()
374 // this gets called every time by new_session()
380 loading_message (_("Starting audio engine"));
383 engine
= new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name
, ARDOUR_COMMAND_LINE::jack_session_uuid
);
390 engine
->Stopped
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::engine_stopped
, this), gui_context());
391 engine
->Running
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::engine_running
, this), gui_context());
392 engine
->SampleRateChanged
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::update_sample_rate
, this, _1
), gui_context());
394 engine
->Halted
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::engine_halted
, this, _1
, false));
396 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports
);
404 ARDOUR_UI::post_engine ()
406 /* Things to be done once we create the AudioEngine
409 ARDOUR::init_post_engine ();
411 ActionManager::init ();
414 if (setup_windows ()) {
415 throw failed_constructor ();
418 check_memory_locking();
420 /* this is the first point at which all the keybindings are available */
422 if (ARDOUR_COMMAND_LINE::show_key_actions
) {
423 vector
<string
> names
;
424 vector
<string
> paths
;
425 vector
<string
> tooltips
;
427 vector
<AccelKey
> bindings
;
429 ActionManager::get_all_actions (names
, paths
, tooltips
, keys
, bindings
);
431 vector
<string
>::iterator n
;
432 vector
<string
>::iterator k
;
433 for (n
= names
.begin(), k
= keys
.begin(); n
!= names
.end(); ++n
, ++k
) {
434 cerr
<< "Action: " << (*n
) << " bound to " << (*k
) << endl
;
440 blink_timeout_tag
= -1;
442 /* this being a GUI and all, we want peakfiles */
444 AudioFileSource::set_build_peakfiles (true);
445 AudioFileSource::set_build_missing_peakfiles (true);
447 /* set default clock modes */
449 if (Profile
->get_sae()) {
450 primary_clock
.set_mode (AudioClock::BBT
);
451 secondary_clock
.set_mode (AudioClock::MinSec
);
453 primary_clock
.set_mode (AudioClock::Timecode
);
454 secondary_clock
.set_mode (AudioClock::BBT
);
457 /* start the time-of-day-clock */
460 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
461 update_wall_clock ();
462 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock
), 60000);
465 update_disk_space ();
467 update_sample_rate (engine
->frame_rate());
469 Config
->ParameterChanged
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::parameter_changed
, this, _1
), gui_context());
470 boost::function
<void (string
)> pc (boost::bind (&ARDOUR_UI::parameter_changed
, this, _1
));
471 Config
->map_parameters (pc
);
473 /* now start and maybe save state */
475 if (do_engine_start () == 0) {
476 if (_session
&& _session_is_new
) {
477 /* we need to retain initial visual
478 settings for a new session
480 _session
->save_state ("");
485 ARDOUR_UI::~ARDOUR_UI ()
490 delete add_route_dialog
;
494 ARDOUR_UI::pop_back_splash ()
496 if (Splash::instance()) {
497 // Splash::instance()->pop_back();
498 Splash::instance()->hide ();
503 ARDOUR_UI::configure_timeout ()
505 if (last_configure_time
== 0) {
506 /* no configure events yet */
510 /* force a gap of 0.5 seconds since the last configure event
513 if (get_microseconds() - last_configure_time
< 500000) {
516 have_configure_timeout
= false;
517 cerr
<< "config event-driven save\n";
518 save_ardour_state ();
524 ARDOUR_UI::configure_handler (GdkEventConfigure
* /*conf*/)
526 if (have_configure_timeout
) {
527 last_configure_time
= get_microseconds();
529 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout
), 100);
530 have_configure_timeout
= true;
537 ARDOUR_UI::set_transport_controllable_state (const XMLNode
& node
)
539 const XMLProperty
* prop
;
541 if ((prop
= node
.property ("roll")) != 0) {
542 roll_controllable
->set_id (prop
->value());
544 if ((prop
= node
.property ("stop")) != 0) {
545 stop_controllable
->set_id (prop
->value());
547 if ((prop
= node
.property ("goto-start")) != 0) {
548 goto_start_controllable
->set_id (prop
->value());
550 if ((prop
= node
.property ("goto-end")) != 0) {
551 goto_end_controllable
->set_id (prop
->value());
553 if ((prop
= node
.property ("auto-loop")) != 0) {
554 auto_loop_controllable
->set_id (prop
->value());
556 if ((prop
= node
.property ("play-selection")) != 0) {
557 play_selection_controllable
->set_id (prop
->value());
559 if ((prop
= node
.property ("rec")) != 0) {
560 rec_controllable
->set_id (prop
->value());
562 if ((prop
= node
.property ("shuttle")) != 0) {
563 shuttle_controllable
->set_id (prop
->value());
568 ARDOUR_UI::get_transport_controllable_state ()
570 XMLNode
* node
= new XMLNode(X_("TransportControllables"));
573 roll_controllable
->id().print (buf
, sizeof (buf
));
574 node
->add_property (X_("roll"), buf
);
575 stop_controllable
->id().print (buf
, sizeof (buf
));
576 node
->add_property (X_("stop"), buf
);
577 goto_start_controllable
->id().print (buf
, sizeof (buf
));
578 node
->add_property (X_("goto_start"), buf
);
579 goto_end_controllable
->id().print (buf
, sizeof (buf
));
580 node
->add_property (X_("goto_end"), buf
);
581 auto_loop_controllable
->id().print (buf
, sizeof (buf
));
582 node
->add_property (X_("auto_loop"), buf
);
583 play_selection_controllable
->id().print (buf
, sizeof (buf
));
584 node
->add_property (X_("play_selection"), buf
);
585 rec_controllable
->id().print (buf
, sizeof (buf
));
586 node
->add_property (X_("rec"), buf
);
587 shuttle_controllable
->id().print (buf
, sizeof (buf
));
588 node
->add_property (X_("shuttle"), buf
);
595 ARDOUR_UI::autosave_session ()
597 if (g_main_depth() > 1) {
598 /* inside a recursive main loop,
599 give up because we may not be able to
605 if (!Config
->get_periodic_safety_backups()) {
610 _session
->maybe_write_autosave();
617 ARDOUR_UI::update_autosave ()
619 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave
)
621 if (_session
&& _session
->dirty()) {
622 if (_autosave_connection
.connected()) {
623 _autosave_connection
.disconnect();
626 _autosave_connection
= Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session
),
627 Config
->get_periodic_safety_backup_interval() * 1000);
630 if (_autosave_connection
.connected()) {
631 _autosave_connection
.disconnect();
637 ARDOUR_UI::backend_audio_error (bool we_set_params
, Gtk::Window
* toplevel
)
641 title
= string_compose (_("%1 could not start JACK"), PROGRAM_NAME
);
643 title
= string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME
);
646 MessageDialog
win (title
,
652 win
.set_secondary_text(_("There are several possible reasons:\n\
654 1) You requested audio parameters that are not supported..\n\
655 2) JACK is running as another user.\n\
657 Please consider the possibilities, and perhaps try different parameters."));
659 win
.set_secondary_text(_("There are several possible reasons:\n\
661 1) JACK is not running.\n\
662 2) JACK is running as another user, perhaps root.\n\
663 3) There is already another client called \"ardour\".\n\
665 Please consider the possibilities, and perhaps (re)start JACK."));
669 win
.set_transient_for (*toplevel
);
673 win
.add_button (Stock::OK
, RESPONSE_CLOSE
);
675 win
.add_button (Stock::QUIT
, RESPONSE_CLOSE
);
678 win
.set_default_response (RESPONSE_CLOSE
);
681 win
.set_position (Gtk::WIN_POS_CENTER
);
684 /* we just don't care about the result, but we want to block */
690 ARDOUR_UI::startup ()
692 Application
* app
= Application::instance ();
694 app
->ShouldQuit
.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish
));
695 app
->ShouldLoad
.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load
));
698 call_the_mothership (VERSIONSTRING
);
703 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session
, ARDOUR_COMMAND_LINE::load_template
)) {
709 goto_editor_window ();
711 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
712 to be opened on top of the editor window that goto_editor_window() just opened.
714 add_window_proxy (location_ui
);
715 add_window_proxy (big_clock_window
);
716 for (ARDOUR::DataType::iterator i
= ARDOUR::DataType::begin(); i
!= ARDOUR::DataType::end(); ++i
) {
717 add_window_proxy (_global_port_matrix
[*i
]);
720 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME
));
724 ARDOUR_UI::no_memory_warning ()
726 XMLNode
node (X_("no-memory-warning"));
727 Config
->add_instant_xml (node
);
731 ARDOUR_UI::check_memory_locking ()
734 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
738 XMLNode
* memory_warning_node
= Config
->instant_xml (X_("no-memory-warning"));
740 if (engine
->is_realtime() && memory_warning_node
== 0) {
742 struct rlimit limits
;
744 long pages
, page_size
;
746 if ((page_size
= sysconf (_SC_PAGESIZE
)) < 0 ||(pages
= sysconf (_SC_PHYS_PAGES
)) < 0) {
749 ram
= (int64_t) pages
* (int64_t) page_size
;
752 if (getrlimit (RLIMIT_MEMLOCK
, &limits
)) {
756 if (limits
.rlim_cur
!= RLIM_INFINITY
) {
758 if (ram
== 0 || ((double) limits
.rlim_cur
/ ram
) < 0.75) {
762 string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
763 "This might cause %1 to run out of memory before your system "
764 "runs out of memory. \n\n"
765 "You can view the memory limit with 'ulimit -l', "
766 "and it is normally controlled by /etc/security/limits.conf"),
767 PROGRAM_NAME
).c_str());
769 VBox
* vbox
= msg
.get_vbox();
771 CheckButton
cb (_("Do not show this window again"));
773 cb
.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning
));
775 hbox
.pack_start (cb
, true, false);
776 vbox
->pack_start (hbox
);
783 editor
->ensure_float (msg
);
793 ARDOUR_UI::queue_finish ()
795 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish
));
799 ARDOUR_UI::idle_finish ()
802 return false; /* do not call again */
811 if (_session
->transport_rolling() && (++tries
< 8)) {
812 _session
->request_stop (false, true);
816 if (_session
->dirty()) {
817 switch (ask_about_saving_session(_("quit"))) {
822 /* use the default name */
823 if (save_state_canfail ("")) {
824 /* failed - don't quit */
825 MessageDialog
msg (*editor
,
827 Ardour was unable to save your session.\n\n\
828 If you still wish to quit, please use the\n\n\
829 \"Just quit\" option."));
840 second_connection
.disconnect ();
841 point_one_second_connection
.disconnect ();
842 point_oh_five_second_connection
.disconnect ();
843 point_zero_one_second_connection
.disconnect();
846 /* Save state before deleting the session, as that causes some
847 windows to be destroyed before their visible state can be
850 save_ardour_state ();
853 // _session->set_deletion_in_progress ();
854 _session
->set_clean ();
855 _session
->remove_pending_capture_state ();
860 ArdourDialog::close_all_dialogs ();
866 ARDOUR_UI::ask_about_saving_session (const string
& what
)
868 ArdourDialog
window (_("Unsaved Session"));
869 Gtk::HBox dhbox
; // the hbox for the image and text
870 Gtk::Label prompt_label
;
871 Gtk::Image
* dimage
= manage (new Gtk::Image(Stock::DIALOG_WARNING
, Gtk::ICON_SIZE_DIALOG
));
875 msg
= string_compose(_("Don't %1"), what
);
876 window
.add_button (msg
, RESPONSE_REJECT
);
877 msg
= string_compose(_("Just %1"), what
);
878 window
.add_button (msg
, RESPONSE_APPLY
);
879 msg
= string_compose(_("Save and %1"), what
);
880 window
.add_button (msg
, RESPONSE_ACCEPT
);
882 window
.set_default_response (RESPONSE_ACCEPT
);
884 Gtk::Button
noquit_button (msg
);
885 noquit_button
.set_name ("EditorGTKButton");
890 if (_session
->snap_name() == _session
->name()) {
893 type
= _("snapshot");
895 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?"),
896 type
, _session
->snap_name());
898 prompt_label
.set_text (prompt
);
899 prompt_label
.set_name (X_("PrompterLabel"));
900 prompt_label
.set_alignment(ALIGN_LEFT
, ALIGN_TOP
);
902 dimage
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
903 dhbox
.set_homogeneous (false);
904 dhbox
.pack_start (*dimage
, false, false, 5);
905 dhbox
.pack_start (prompt_label
, true, false, 5);
906 window
.get_vbox()->pack_start (dhbox
);
908 window
.set_name (_("Prompter"));
909 window
.set_position (Gtk::WIN_POS_MOUSE
);
910 window
.set_modal (true);
911 window
.set_resizable (false);
917 window
.set_keep_above (true);
920 ResponseType r
= (ResponseType
) window
.run();
925 case RESPONSE_ACCEPT
: // save and get out of here
927 case RESPONSE_APPLY
: // get out of here
937 ARDOUR_UI::every_second ()
940 update_buffer_load ();
941 update_disk_space ();
946 ARDOUR_UI::every_point_one_seconds ()
948 update_speed_display ();
949 RapidScreenUpdate(); /* EMIT_SIGNAL */
954 ARDOUR_UI::every_point_zero_one_seconds ()
956 // august 2007: actual update frequency: 40Hz, not 100Hz
958 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
963 ARDOUR_UI::update_sample_rate (framecnt_t
)
967 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate
, ignored
)
969 if (!engine
->connected()) {
971 snprintf (buf
, sizeof (buf
), _("disconnected"));
975 framecnt_t rate
= engine
->frame_rate();
977 if (fmod (rate
, 1000.0) != 0.0) {
978 snprintf (buf
, sizeof (buf
), _("%.1f kHz / %4.1f ms"),
979 (float) rate
/1000.0f
,
980 (engine
->frames_per_cycle() / (float) rate
) * 1000.0f
);
982 snprintf (buf
, sizeof (buf
), _("%" PRId64
" kHz / %4.1f ms"),
984 (engine
->frames_per_cycle() / (float) rate
) * 1000.0f
);
988 sample_rate_label
.set_text (buf
);
992 ARDOUR_UI::update_cpu_load ()
995 snprintf (buf
, sizeof (buf
), _("DSP: %5.1f%%"), engine
->get_cpu_load());
996 cpu_load_label
.set_text (buf
);
1000 ARDOUR_UI::update_buffer_load ()
1006 c
= _session
->capture_load ();
1007 p
= _session
->playback_load ();
1009 snprintf (buf
, sizeof (buf
), _("Buffers p:%" PRIu32
"%% c:%" PRIu32
"%%"),
1010 _session
->playback_load(), _session
->capture_load());
1011 buffer_load_label
.set_text (buf
);
1013 buffer_load_label
.set_text ("");
1018 ARDOUR_UI::count_recenabled_streams (Route
& route
)
1020 Track
* track
= dynamic_cast<Track
*>(&route
);
1021 if (track
&& track
->record_enabled()) {
1022 rec_enabled_streams
+= track
->n_inputs().n_total();
1027 ARDOUR_UI::update_disk_space()
1029 if (_session
== 0) {
1033 framecnt_t frames
= _session
->available_capture_duration();
1035 framecnt_t fr
= _session
->frame_rate();
1037 if (frames
== max_framecnt
) {
1038 strcpy (buf
, _("Disk: 24hrs+"));
1040 rec_enabled_streams
= 0;
1041 _session
->foreach_route (this, &ARDOUR_UI::count_recenabled_streams
);
1043 if (rec_enabled_streams
) {
1044 frames
/= rec_enabled_streams
;
1051 hrs
= frames
/ (fr
* 3600);
1052 frames
-= hrs
* fr
* 3600;
1053 mins
= frames
/ (fr
* 60);
1054 frames
-= mins
* fr
* 60;
1057 snprintf (buf
, sizeof(buf
), _("Disk: %02dh:%02dm:%02ds"), hrs
, mins
, secs
);
1060 disk_space_label
.set_text (buf
);
1062 // An attempt to make the disk space label flash red when space has run out.
1064 if (frames
< fr
* 60 * 5) {
1065 /* disk_space_box.style ("disk_space_label_empty"); */
1067 /* disk_space_box.style ("disk_space_label"); */
1073 ARDOUR_UI::update_wall_clock ()
1080 tm_now
= localtime (&now
);
1082 sprintf (buf
, "%02d:%02d", tm_now
->tm_hour
, tm_now
->tm_min
);
1083 wall_clock_label
.set_text (buf
);
1089 ARDOUR_UI::session_menu (GdkEventButton */
*ev*/
)
1091 session_popup_menu
->popup (0, 0);
1096 ARDOUR_UI::redisplay_recent_sessions ()
1098 std::vector
<sys::path
> session_directories
;
1099 RecentSessionsSorter cmp
;
1101 recent_session_display
.set_model (Glib::RefPtr
<TreeModel
>(0));
1102 recent_session_model
->clear ();
1104 ARDOUR::RecentSessions rs
;
1105 ARDOUR::read_recent_sessions (rs
);
1108 recent_session_display
.set_model (recent_session_model
);
1112 // sort them alphabetically
1113 sort (rs
.begin(), rs
.end(), cmp
);
1115 for (ARDOUR::RecentSessions::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
1116 session_directories
.push_back ((*i
).second
);
1119 for (vector
<sys::path
>::const_iterator i
= session_directories
.begin();
1120 i
!= session_directories
.end(); ++i
)
1122 std::vector
<sys::path
> state_file_paths
;
1124 // now get available states for this session
1126 get_state_files_in_directory (*i
, state_file_paths
);
1128 vector
<string
*>* states
;
1129 vector
<const gchar
*> item
;
1130 string fullpath
= (*i
).to_string();
1132 /* remove any trailing / */
1134 if (fullpath
[fullpath
.length()-1] == '/') {
1135 fullpath
= fullpath
.substr (0, fullpath
.length()-1);
1138 /* check whether session still exists */
1139 if (!Glib::file_test(fullpath
.c_str(), Glib::FILE_TEST_EXISTS
)) {
1140 /* session doesn't exist */
1141 cerr
<< "skipping non-existent session " << fullpath
<< endl
;
1145 /* now get available states for this session */
1147 if ((states
= Session::possible_states (fullpath
)) == 0) {
1148 /* no state file? */
1152 std::vector
<string
> state_file_names(get_file_names_no_extension (state_file_paths
));
1154 Gtk::TreeModel::Row row
= *(recent_session_model
->append());
1156 row
[recent_session_columns
.visible_name
] = Glib::path_get_basename (fullpath
);
1157 row
[recent_session_columns
.fullpath
] = fullpath
;
1159 if (state_file_names
.size() > 1) {
1163 for (std::vector
<std::string
>::iterator i2
= state_file_names
.begin();
1164 i2
!= state_file_names
.end(); ++i2
)
1167 Gtk::TreeModel::Row child_row
= *(recent_session_model
->append (row
.children()));
1169 child_row
[recent_session_columns
.visible_name
] = *i2
;
1170 child_row
[recent_session_columns
.fullpath
] = fullpath
;
1175 recent_session_display
.set_model (recent_session_model
);
1179 ARDOUR_UI::build_session_selector ()
1181 session_selector_window
= new ArdourDialog (_("Recent Sessions"));
1183 Gtk::ScrolledWindow
*scroller
= manage (new Gtk::ScrolledWindow
);
1185 session_selector_window
->add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
1186 session_selector_window
->add_button (Stock::OPEN
, RESPONSE_ACCEPT
);
1187 session_selector_window
->set_default_response (RESPONSE_ACCEPT
);
1188 recent_session_model
= TreeStore::create (recent_session_columns
);
1189 recent_session_display
.set_model (recent_session_model
);
1190 recent_session_display
.append_column (_("Recent Sessions"), recent_session_columns
.visible_name
);
1191 recent_session_display
.set_headers_visible (false);
1192 recent_session_display
.get_selection()->set_mode (SELECTION_BROWSE
);
1193 recent_session_display
.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated
));
1195 scroller
->add (recent_session_display
);
1196 scroller
->set_policy (Gtk::POLICY_NEVER
, Gtk::POLICY_AUTOMATIC
);
1198 session_selector_window
->set_name ("SessionSelectorWindow");
1199 session_selector_window
->set_size_request (200, 400);
1200 session_selector_window
->get_vbox()->pack_start (*scroller
);
1202 recent_session_display
.show();
1204 //session_selector_window->get_vbox()->show();
1208 ARDOUR_UI::recent_session_row_activated (const TreePath
& /*path*/, TreeViewColumn
* /*col*/)
1210 session_selector_window
->response (RESPONSE_ACCEPT
);
1214 ARDOUR_UI::open_recent_session ()
1216 bool can_return
= (_session
!= 0);
1218 if (session_selector_window
== 0) {
1219 build_session_selector ();
1222 redisplay_recent_sessions ();
1226 session_selector_window
->set_position (WIN_POS_MOUSE
);
1228 ResponseType r
= (ResponseType
) session_selector_window
->run ();
1231 case RESPONSE_ACCEPT
:
1235 session_selector_window
->hide();
1242 if (recent_session_display
.get_selection()->count_selected_rows() == 0) {
1246 session_selector_window
->hide();
1248 Gtk::TreeModel::iterator i
= recent_session_display
.get_selection()->get_selected();
1250 if (i
== recent_session_model
->children().end()) {
1254 std::string path
= (*i
)[recent_session_columns
.fullpath
];
1255 std::string state
= (*i
)[recent_session_columns
.visible_name
];
1257 _session_is_new
= false;
1259 if (load_session (path
, state
) == 0) {
1268 ARDOUR_UI::check_audioengine ()
1271 if (!engine
->connected()) {
1272 MessageDialog
msg (string_compose (_("%1 is not connected to JACK\n"
1273 "You cannot open or close sessions in this condition"),
1286 ARDOUR_UI::open_session ()
1288 if (!check_audioengine()) {
1293 /* popup selector window */
1295 if (open_session_selector
== 0) {
1297 /* ardour sessions are folders */
1299 open_session_selector
= new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN
);
1300 open_session_selector
->add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
1301 open_session_selector
->add_button (Gtk::Stock::OPEN
, Gtk::RESPONSE_ACCEPT
);
1302 open_session_selector
->set_default_response(Gtk::RESPONSE_ACCEPT
);
1304 FileFilter session_filter
;
1305 session_filter
.add_pattern ("*.ardour");
1306 session_filter
.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME
));
1307 open_session_selector
->add_filter (session_filter
);
1308 open_session_selector
->set_filter (session_filter
);
1311 int response
= open_session_selector
->run();
1312 open_session_selector
->hide ();
1315 case RESPONSE_ACCEPT
:
1318 open_session_selector
->hide();
1322 open_session_selector
->hide();
1323 string session_path
= open_session_selector
->get_filename();
1327 if (session_path
.length() > 0) {
1328 if (ARDOUR::find_session (session_path
, path
, name
, isnew
) == 0) {
1329 _session_is_new
= isnew
;
1330 load_session (path
, name
);
1337 ARDOUR_UI::session_add_midi_route (bool disk
, RouteGroup
* route_group
, uint32_t how_many
, string
const & name_template
)
1339 list
<boost::shared_ptr
<MidiTrack
> > tracks
;
1341 if (_session
== 0) {
1342 warning
<< _("You cannot add a track without a session already loaded.") << endmsg
;
1349 tracks
= _session
->new_midi_track (ARDOUR::Normal
, route_group
, how_many
, name_template
);
1351 if (tracks
.size() != how_many
) {
1352 if (how_many
== 1) {
1353 error
<< _("could not create a new midi track") << endmsg
;
1355 error
<< string_compose (_("could not create %1 new midi tracks"), how_many
) << endmsg
;
1359 if ((route = _session->new_midi_route ()) == 0) {
1360 error << _("could not create new midi bus") << endmsg;
1366 MessageDialog
msg (*editor
,
1367 string_compose (_("There are insufficient JACK ports available\n\
1368 to create a new track or bus.\n\
1369 You should save %1, exit and\n\
1370 restart JACK with more ports."), PROGRAM_NAME
));
1377 ARDOUR_UI::session_add_audio_route (
1379 int32_t input_channels
,
1380 int32_t output_channels
,
1381 ARDOUR::TrackMode mode
,
1382 RouteGroup
* route_group
,
1384 string
const & name_template
1387 list
<boost::shared_ptr
<AudioTrack
> > tracks
;
1390 if (_session
== 0) {
1391 warning
<< _("You cannot add a track or bus without a session already loaded.") << endmsg
;
1397 tracks
= _session
->new_audio_track (input_channels
, output_channels
, mode
, route_group
, how_many
, name_template
);
1399 if (tracks
.size() != how_many
) {
1400 if (how_many
== 1) {
1401 error
<< _("could not create a new audio track") << endmsg
;
1403 error
<< string_compose (_("could only create %1 of %2 new audio %3"),
1404 tracks
.size(), how_many
, (track
? _("tracks") : _("busses"))) << endmsg
;
1410 routes
= _session
->new_audio_route (input_channels
, output_channels
, route_group
, how_many
, name_template
);
1412 if (routes
.size() != how_many
) {
1413 if (how_many
== 1) {
1414 error
<< _("could not create a new audio track") << endmsg
;
1416 error
<< string_compose (_("could not create %1 new audio tracks"), how_many
) << endmsg
;
1423 MessageDialog
msg (*editor
,
1424 string_compose (_("There are insufficient JACK ports available\n\
1425 to create a new track or bus.\n\
1426 You should save %1, exit and\n\
1427 restart JACK with more ports."), PROGRAM_NAME
));
1434 ARDOUR_UI::do_transport_locate (framepos_t new_position
, bool with_roll
)
1436 framecnt_t _preroll
= 0;
1439 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1440 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1442 if (new_position
> _preroll
) {
1443 new_position
-= _preroll
;
1448 _session
->request_locate (new_position
, with_roll
);
1453 ARDOUR_UI::transport_goto_start ()
1456 _session
->goto_start();
1458 /* force displayed area in editor to start no matter
1459 what "follow playhead" setting is.
1463 editor
->center_screen (_session
->current_start_frame ());
1469 ARDOUR_UI::transport_goto_zero ()
1472 _session
->request_locate (0);
1474 /* force displayed area in editor to start no matter
1475 what "follow playhead" setting is.
1479 editor
->reset_x_origin (0);
1485 ARDOUR_UI::transport_goto_wallclock ()
1487 if (_session
&& editor
) {
1494 localtime_r (&now
, &tmnow
);
1496 frames
= tmnow
.tm_hour
* (60 * 60 * _session
->frame_rate());
1497 frames
+= tmnow
.tm_min
* (60 * _session
->frame_rate());
1498 frames
+= tmnow
.tm_sec
* _session
->frame_rate();
1500 _session
->request_locate (frames
, _session
->transport_rolling ());
1502 /* force displayed area in editor to start no matter
1503 what "follow playhead" setting is.
1507 editor
->center_screen (frames
);
1513 ARDOUR_UI::transport_goto_end ()
1516 framepos_t
const frame
= _session
->current_end_frame();
1517 _session
->request_locate (frame
);
1519 /* force displayed area in editor to start no matter
1520 what "follow playhead" setting is.
1524 editor
->center_screen (frame
);
1530 ARDOUR_UI::transport_stop ()
1536 if (_session
->is_auditioning()) {
1537 _session
->cancel_audition ();
1541 _session
->request_stop (false, true);
1545 ARDOUR_UI::transport_stop_and_forget_capture ()
1548 _session
->request_stop (true, true);
1553 ARDOUR_UI::remove_last_capture()
1556 editor
->remove_last_capture();
1561 ARDOUR_UI::transport_record (bool roll
)
1565 switch (_session
->record_status()) {
1566 case Session::Disabled
:
1567 if (_session
->ntracks() == 0) {
1568 MessageDialog
msg (*editor
, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1572 _session
->maybe_enable_record ();
1577 case Session::Recording
:
1579 _session
->request_stop();
1581 _session
->disable_record (false, true);
1585 case Session::Enabled
:
1586 _session
->disable_record (false, true);
1589 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1593 ARDOUR_UI::transport_roll ()
1599 if (_session
->is_auditioning()) {
1604 if (_session
->config
.get_external_sync()) {
1605 switch (_session
->config
.get_sync_source()) {
1609 /* transport controlled by the master */
1615 bool rolling
= _session
->transport_rolling();
1617 if (_session
->get_play_loop()) {
1618 /* XXX it is not possible to just leave seamless loop and keep
1619 playing at present (nov 4th 2009)
1621 if (!Config
->get_seamless_loop()) {
1622 _session
->request_play_loop (false, true);
1624 } else if (_session
->get_play_range () && !join_play_range_button
.get_active()) {
1625 /* stop playing a range if we currently are */
1626 _session
->request_play_range (0, true);
1629 if (join_play_range_button
.get_active()) {
1630 _session
->request_play_range (&editor
->get_selection().time
, true);
1634 _session
->request_transport_speed (1.0f
);
1639 ARDOUR_UI::toggle_roll (bool with_abort
, bool roll_out_of_bounded_mode
)
1646 if (_session
->is_auditioning()) {
1647 _session
->cancel_audition ();
1652 if (_session
->config
.get_external_sync()) {
1653 switch (_session
->config
.get_sync_source()) {
1657 /* transport controlled by the master */
1663 bool rolling
= _session
->transport_rolling();
1664 bool affect_transport
= true;
1666 if (rolling
&& roll_out_of_bounded_mode
) {
1667 /* drop out of loop/range playback but leave transport rolling */
1668 if (_session
->get_play_loop()) {
1669 if (Config
->get_seamless_loop()) {
1670 /* the disk buffers contain copies of the loop - we can't
1671 just keep playing, so stop the transport. the user
1672 can restart as they wish.
1674 affect_transport
= true;
1676 /* disk buffers are normal, so we can keep playing */
1677 affect_transport
= false;
1679 _session
->request_play_loop (false, true);
1680 } else if (_session
->get_play_range ()) {
1681 affect_transport
= false;
1682 _session
->request_play_range (0, true);
1686 if (affect_transport
) {
1688 _session
->request_stop (with_abort
, true);
1690 if (join_play_range_button
.get_active()) {
1691 _session
->request_play_range (&editor
->get_selection().time
, true);
1694 _session
->request_transport_speed (1.0f
);
1700 ARDOUR_UI::toggle_session_auto_loop ()
1706 if (_session
->get_play_loop()) {
1708 if (_session
->transport_rolling()) {
1710 Location
* looploc
= _session
->locations()->auto_loop_location();
1713 _session
->request_locate (looploc
->start(), true);
1714 _session
->request_play_loop (false);
1718 _session
->request_play_loop (false);
1722 Location
* looploc
= _session
->locations()->auto_loop_location();
1725 _session
->request_play_loop (true);
1731 ARDOUR_UI::transport_play_selection ()
1737 editor
->play_selection ();
1741 ARDOUR_UI::transport_rewind (int option
)
1743 float current_transport_speed
;
1746 current_transport_speed
= _session
->transport_speed();
1748 if (current_transport_speed
>= 0.0f
) {
1751 _session
->request_transport_speed (-1.0f
);
1754 _session
->request_transport_speed (-4.0f
);
1757 _session
->request_transport_speed (-0.5f
);
1762 _session
->request_transport_speed (current_transport_speed
* 1.5f
);
1768 ARDOUR_UI::transport_forward (int option
)
1770 float current_transport_speed
;
1773 current_transport_speed
= _session
->transport_speed();
1775 if (current_transport_speed
<= 0.0f
) {
1778 _session
->request_transport_speed (1.0f
);
1781 _session
->request_transport_speed (4.0f
);
1784 _session
->request_transport_speed (0.5f
);
1789 _session
->request_transport_speed (current_transport_speed
* 1.5f
);
1796 ARDOUR_UI::toggle_record_enable (uint32_t rid
)
1798 if (_session
== 0) {
1802 boost::shared_ptr
<Route
> r
;
1804 if ((r
= _session
->route_by_remote_id (rid
)) != 0) {
1808 if ((t
= dynamic_cast<Track
*>(r
.get())) != 0) {
1809 t
->set_record_enabled (!t
->record_enabled(), this);
1812 if (_session
== 0) {
1818 ARDOUR_UI::map_transport_state ()
1820 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state
)
1823 auto_loop_button
.set_visual_state (0);
1824 play_selection_button
.set_visual_state (0);
1825 roll_button
.set_visual_state (0);
1826 stop_button
.set_visual_state (1);
1830 float sp
= _session
->transport_speed();
1833 shuttle_fract
= SHUTTLE_FRACT_SPEED1
; /* speed = 1.0, believe it or not */
1834 shuttle_box
.queue_draw ();
1835 } else if (sp
== 0.0f
) {
1837 shuttle_box
.queue_draw ();
1838 update_disk_space ();
1845 if (_session
->get_play_range()) {
1847 play_selection_button
.set_visual_state (1);
1848 roll_button
.set_visual_state (0);
1849 auto_loop_button
.set_visual_state (0);
1851 } else if (_session
->get_play_loop ()) {
1853 auto_loop_button
.set_visual_state (1);
1854 play_selection_button
.set_visual_state (0);
1855 roll_button
.set_visual_state (0);
1859 roll_button
.set_visual_state (1);
1860 play_selection_button
.set_visual_state (0);
1861 auto_loop_button
.set_visual_state (0);
1864 if (join_play_range_button
.get_active()) {
1865 /* light up both roll and play-selection if they are joined */
1866 roll_button
.set_visual_state (1);
1867 play_selection_button
.set_visual_state (1);
1870 stop_button
.set_visual_state (0);
1874 stop_button
.set_visual_state (1);
1875 roll_button
.set_visual_state (0);
1876 play_selection_button
.set_visual_state (0);
1877 auto_loop_button
.set_visual_state (0);
1882 ARDOUR_UI::engine_stopped ()
1884 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped
)
1885 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, false);
1886 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, true);
1890 ARDOUR_UI::engine_running ()
1892 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running
)
1893 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, true);
1894 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, false);
1896 Glib::RefPtr
<Action
> action
;
1897 const char* action_name
= 0;
1899 switch (engine
->frames_per_cycle()) {
1901 action_name
= X_("JACKLatency32");
1904 action_name
= X_("JACKLatency64");
1907 action_name
= X_("JACKLatency128");
1910 action_name
= X_("JACKLatency512");
1913 action_name
= X_("JACKLatency1024");
1916 action_name
= X_("JACKLatency2048");
1919 action_name
= X_("JACKLatency4096");
1922 action_name
= X_("JACKLatency8192");
1925 /* XXX can we do anything useful ? */
1931 action
= ActionManager::get_action (X_("JACK"), action_name
);
1934 Glib::RefPtr
<RadioAction
> ract
= Glib::RefPtr
<RadioAction
>::cast_dynamic (action
);
1935 ract
->set_active ();
1941 ARDOUR_UI::engine_halted (const char* reason
, bool free_reason
)
1943 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1944 /* we can't rely on the original string continuing to exist when we are called
1945 again in the GUI thread, so make a copy and note that we need to
1948 char *copy
= strdup (reason
);
1949 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted
, this, copy
, true));
1953 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, false);
1954 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, true);
1956 update_sample_rate (0);
1960 /* if the reason is a non-empty string, it means that the backend was shutdown
1961 rather than just Ardour.
1964 if (strlen (reason
)) {
1965 msgstr
= string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason
);
1967 msgstr
= string_compose (_("\
1968 JACK has either been shutdown or it\n\
1969 disconnected %1 because %1\n\
1970 was not fast enough. Try to restart\n\
1971 JACK, reconnect and save the session."), PROGRAM_NAME
);
1974 MessageDialog
msg (*editor
, msgstr
);
1979 free ((char*) reason
);
1984 ARDOUR_UI::do_engine_start ()
1992 error
<< _("Unable to start the session running")
2002 ARDOUR_UI::setup_theme ()
2004 theme_manager
->setup_theme();
2008 ARDOUR_UI::update_clocks ()
2010 if (!editor
|| !editor
->dragging_playhead()) {
2011 Clock (_session
->audible_frame(), false, editor
->get_preferred_edit_position()); /* EMIT_SIGNAL */
2016 ARDOUR_UI::start_clocking ()
2018 clock_signal_connection
= RapidScreenUpdate
.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks
));
2022 ARDOUR_UI::stop_clocking ()
2024 clock_signal_connection
.disconnect ();
2028 ARDOUR_UI::toggle_clocking ()
2031 if (clock_button
.get_active()) {
2040 ARDOUR_UI::_blink (void *arg
)
2043 ((ARDOUR_UI
*) arg
)->blink ();
2050 Blink (blink_on
= !blink_on
); /* EMIT_SIGNAL */
2054 ARDOUR_UI::start_blinking ()
2056 /* Start the blink signal. Everybody with a blinking widget
2057 uses Blink to drive the widget's state.
2060 if (blink_timeout_tag
< 0) {
2062 blink_timeout_tag
= g_timeout_add (240, _blink
, this);
2067 ARDOUR_UI::stop_blinking ()
2069 if (blink_timeout_tag
>= 0) {
2070 g_source_remove (blink_timeout_tag
);
2071 blink_timeout_tag
= -1;
2076 /** Ask the user for the name of a new shapshot and then take it.
2080 ARDOUR_UI::snapshot_session (bool switch_to_it
)
2082 ArdourPrompter
prompter (true);
2085 prompter
.set_name ("Prompter");
2086 prompter
.add_button (Gtk::Stock::SAVE
, Gtk::RESPONSE_ACCEPT
);
2087 prompter
.set_title (_("Take Snapshot"));
2088 prompter
.set_title (_("Take Snapshot"));
2089 prompter
.set_prompt (_("Name of new snapshot"));
2091 if (!switch_to_it
) {
2094 struct tm local_time
;
2097 localtime_r (&n
, &local_time
);
2098 strftime (timebuf
, sizeof(timebuf
), "%FT%T", &local_time
);
2099 prompter
.set_initial_text (timebuf
);
2103 switch (prompter
.run()) {
2104 case RESPONSE_ACCEPT
:
2106 prompter
.get_result (snapname
);
2108 bool do_save
= (snapname
.length() != 0);
2111 if (snapname
.find ('/') != string::npos
) {
2112 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2113 "snapshot names may not contain a '/' character"));
2117 if (snapname
.find ('\\') != string::npos
) {
2118 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2119 "snapshot names may not contain a '\\' character"));
2125 vector
<sys::path
> p
;
2126 get_state_files_in_directory (_session
->session_directory().root_path(), p
);
2127 vector
<string
> n
= get_file_names_no_extension (p
);
2128 if (find (n
.begin(), n
.end(), snapname
) != n
.end()) {
2130 ArdourDialog
confirm (_("Confirm Snapshot Overwrite"), true);
2131 Label
m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2132 confirm
.get_vbox()->pack_start (m
, true, true);
2133 confirm
.add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
2134 confirm
.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT
);
2135 confirm
.show_all ();
2136 switch (confirm
.run()) {
2137 case RESPONSE_CANCEL
:
2143 save_state (snapname
, switch_to_it
);
2154 ARDOUR_UI::save_state (const string
& name
, bool switch_to_it
)
2156 XMLNode
* node
= new XMLNode (X_("UI"));
2158 for (list
<WindowProxyBase
*>::iterator i
= _window_proxies
.begin(); i
!= _window_proxies
.end(); ++i
) {
2159 if (!(*i
)->rc_configured()) {
2160 node
->add_child_nocopy (*((*i
)->get_state ()));
2164 _session
->add_extra_xml (*node
);
2166 save_state_canfail (name
, switch_to_it
);
2170 ARDOUR_UI::save_state_canfail (string name
, bool switch_to_it
)
2175 if (name
.length() == 0) {
2176 name
= _session
->snap_name();
2179 if ((ret
= _session
->save_state (name
, false, switch_to_it
)) != 0) {
2183 cerr
<< "SS canfail\n";
2184 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2189 ARDOUR_UI::primary_clock_value_changed ()
2192 _session
->request_locate (primary_clock
.current_time ());
2197 ARDOUR_UI::big_clock_value_changed ()
2200 _session
->request_locate (big_clock
.current_time ());
2205 ARDOUR_UI::secondary_clock_value_changed ()
2208 _session
->request_locate (secondary_clock
.current_time ());
2213 ARDOUR_UI::transport_rec_enable_blink (bool onoff
)
2215 if (_session
== 0) {
2219 if (_session
->step_editing()) {
2223 Session::RecordState
const r
= _session
->record_status ();
2224 bool const h
= _session
->have_rec_enabled_track ();
2226 if (r
== Session::Enabled
|| (r
== Session::Recording
&& !h
)) {
2228 rec_button
.set_visual_state (2);
2230 rec_button
.set_visual_state (0);
2232 } else if (r
== Session::Recording
&& h
) {
2233 rec_button
.set_visual_state (1);
2235 rec_button
.set_visual_state (0);
2240 ARDOUR_UI::save_template ()
2242 ArdourPrompter
prompter (true);
2245 if (!check_audioengine()) {
2249 prompter
.set_name (X_("Prompter"));
2250 prompter
.set_title (_("Save Template"));
2251 prompter
.set_prompt (_("Name for template:"));
2252 prompter
.set_initial_text(_session
->name() + _("-template"));
2253 prompter
.add_button (Gtk::Stock::SAVE
, Gtk::RESPONSE_ACCEPT
);
2255 switch (prompter
.run()) {
2256 case RESPONSE_ACCEPT
:
2257 prompter
.get_result (name
);
2259 if (name
.length()) {
2260 _session
->save_template (name
);
2270 ARDOUR_UI::edit_metadata ()
2272 SessionMetadataEditor dialog
;
2273 dialog
.set_session (_session
);
2274 editor
->ensure_float (dialog
);
2279 ARDOUR_UI::import_metadata ()
2281 SessionMetadataImporter dialog
;
2282 dialog
.set_session (_session
);
2283 editor
->ensure_float (dialog
);
2288 ARDOUR_UI::fontconfig_dialog ()
2291 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2292 may not and it can take a while to build it. Warn them.
2295 std::string fontconfig
= Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2297 if (!Glib::file_test (fontconfig
, Glib::FILE_TEST_EXISTS
|Glib::FILE_TEST_IS_DIR
)) {
2298 MessageDialog
msg (*_startup
,
2299 string_compose (_("Welcome to %1.\n\n"
2300 "The program will take a bit longer to start up\n"
2301 "while the system fonts are checked.\n\n"
2302 "This will only be done once, and you will\n"
2303 "not see this message again\n"), PROGRAM_NAME
),
2316 ARDOUR_UI::parse_cmdline_path (const std::string
& cmdline_path
, std::string
& session_name
, std::string
& session_path
, bool& existing_session
)
2318 existing_session
= false;
2320 if (Glib::file_test (cmdline_path
, Glib::FILE_TEST_IS_DIR
)) {
2321 session_path
= cmdline_path
;
2322 existing_session
= true;
2323 } else if (Glib::file_test (cmdline_path
, Glib::FILE_TEST_IS_REGULAR
)) {
2324 session_path
= Glib::path_get_dirname (string (cmdline_path
));
2325 existing_session
= true;
2327 /* it doesn't exist, assume the best */
2328 session_path
= Glib::path_get_dirname (string (cmdline_path
));
2331 session_name
= basename_nosuffix (string (cmdline_path
));
2335 ARDOUR_UI::load_cmdline_session (const std::string
& session_name
, const std::string
& session_path
, bool& existing_session
)
2337 /* when this is called, the backend audio system must be running */
2339 /* the main idea here is to deal with the fact that a cmdline argument for the session
2340 can be interpreted in different ways - it could be a directory or a file, and before
2341 we load, we need to know both the session directory and the snapshot (statefile) within it
2342 that we are supposed to use.
2345 if (session_name
.length() == 0 || session_path
.length() == 0) {
2349 if (Glib::file_test (session_path
, Glib::FILE_TEST_IS_DIR
)) {
2351 std::string predicted_session_file
;
2353 predicted_session_file
= session_path
;
2354 predicted_session_file
+= '/';
2355 predicted_session_file
+= session_name
;
2356 predicted_session_file
+= ARDOUR::statefile_suffix
;
2358 if (Glib::file_test (predicted_session_file
, Glib::FILE_TEST_EXISTS
)) {
2359 existing_session
= true;
2362 } else if (Glib::file_test (session_path
, Glib::FILE_TEST_EXISTS
)) {
2364 if (session_path
.find (ARDOUR::statefile_suffix
) == session_path
.length() - 7) {
2365 /* existing .ardour file */
2366 existing_session
= true;
2370 existing_session
= false;
2373 /* lets just try to load it */
2375 if (create_engine ()) {
2376 backend_audio_error (false, _startup
);
2380 return load_session (session_path
, session_name
);
2384 ARDOUR_UI::ask_about_loading_existing_session (const std::string
& session_path
)
2386 std::string str
= string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path
);
2388 MessageDialog
msg (str
,
2390 Gtk::MESSAGE_WARNING
,
2391 Gtk::BUTTONS_YES_NO
,
2395 msg
.set_name (X_("OpenExistingDialog"));
2396 msg
.set_title (_("Open Existing Session"));
2397 msg
.set_wmclass (X_("existing_session"), PROGRAM_NAME
);
2398 msg
.set_position (Gtk::WIN_POS_MOUSE
);
2401 switch (msg
.run()) {
2410 ARDOUR_UI::build_session_from_nsd (const std::string
& session_path
, const std::string
& session_name
)
2412 BusProfile bus_profile
;
2414 if (Profile
->get_sae()) {
2416 bus_profile
.master_out_channels
= 2;
2417 bus_profile
.input_ac
= AutoConnectPhysical
;
2418 bus_profile
.output_ac
= AutoConnectMaster
;
2419 bus_profile
.requested_physical_in
= 0; // use all available
2420 bus_profile
.requested_physical_out
= 0; // use all available
2424 /* get settings from advanced section of NSD */
2426 if (_startup
->create_master_bus()) {
2427 bus_profile
.master_out_channels
= (uint32_t) _startup
->master_channel_count();
2429 bus_profile
.master_out_channels
= 0;
2432 if (_startup
->connect_inputs()) {
2433 bus_profile
.input_ac
= AutoConnectPhysical
;
2435 bus_profile
.input_ac
= AutoConnectOption (0);
2438 /// @todo some minor tweaks.
2440 bus_profile
.output_ac
= AutoConnectOption (0);
2442 if (_startup
->connect_outputs ()) {
2443 if (_startup
->connect_outs_to_master()) {
2444 bus_profile
.output_ac
= AutoConnectMaster
;
2445 } else if (_startup
->connect_outs_to_physical()) {
2446 bus_profile
.output_ac
= AutoConnectPhysical
;
2450 bus_profile
.requested_physical_in
= (uint32_t) _startup
->input_limit_count();
2451 bus_profile
.requested_physical_out
= (uint32_t) _startup
->output_limit_count();
2454 if (build_session (session_path
, session_name
, bus_profile
)) {
2462 ARDOUR_UI::idle_load (const std::string
& path
)
2465 if (Glib::file_test (path
, Glib::FILE_TEST_IS_DIR
)) {
2466 /* /path/to/foo => /path/to/foo, foo */
2467 load_session (path
, basename_nosuffix (path
));
2469 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2470 load_session (Glib::path_get_dirname (path
), basename_nosuffix (path
));
2474 ARDOUR_COMMAND_LINE::session_name
= path
;
2477 * new_session_dialog doens't exist in A3
2478 * Try to remove all references to it to
2479 * see if it will compile. NOTE: this will
2480 * likely cause a runtime issue is my somewhat
2484 //if (new_session_dialog) {
2487 /* make it break out of Dialog::run() and
2491 //new_session_dialog->response (1);
2497 ARDOUR_UI::end_loading_messages ()
2503 ARDOUR_UI::loading_message (const std::string
& /*msg*/)
2506 // splash->message (msg);
2510 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2512 ARDOUR_UI::get_session_parameters (bool quit_on_cancel
, bool should_be_new
, string load_template
)
2514 string session_name
;
2515 string session_path
;
2516 string template_name
;
2518 bool likely_new
= false;
2520 if (! load_template
.empty()) {
2521 should_be_new
= true;
2522 template_name
= load_template
;
2527 if (!should_be_new
&& !ARDOUR_COMMAND_LINE::session_name
.empty()) {
2529 /* if they named a specific statefile, use it, otherwise they are
2530 just giving a session folder, and we want to use it as is
2531 to find the session.
2534 if (ARDOUR_COMMAND_LINE::session_name
.find (statefile_suffix
) != string::npos
) {
2535 session_path
= Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name
);
2537 session_path
= ARDOUR_COMMAND_LINE::session_name
;
2540 session_name
= Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name
);
2544 bool const apply
= run_startup (should_be_new
, load_template
);
2547 if (quit_on_cancel
) {
2554 /* if we run the startup dialog again, offer more than just "new session" */
2556 should_be_new
= false;
2558 session_name
= _startup
->session_name (likely_new
);
2560 /* this shouldn't happen, but we catch it just in case it does */
2562 if (session_name
.empty()) {
2566 if (_startup
->use_session_template()) {
2567 template_name
= _startup
->session_template_name();
2568 _session_is_new
= true;
2571 if (session_name
[0] == G_DIR_SEPARATOR
||
2572 (session_name
.length() > 2 && session_name
[0] == '.' && session_name
[1] == G_DIR_SEPARATOR
) ||
2573 (session_name
.length() > 3 && session_name
[0] == '.' && session_name
[1] == '.' && session_name
[2] == G_DIR_SEPARATOR
)) {
2575 /* absolute path or cwd-relative path specified for session name: infer session folder
2576 from what was given.
2579 session_path
= Glib::path_get_dirname (session_name
);
2580 session_name
= Glib::path_get_basename (session_name
);
2584 session_path
= _startup
->session_folder();
2586 if (session_name
.find ('/') != string::npos
) {
2587 MessageDialog
msg (*_startup
, _("To ensure compatibility with various systems\n"
2588 "session names may not contain a '/' character"));
2590 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2594 if (session_name
.find ('\\') != string::npos
) {
2595 MessageDialog
msg (*_startup
, _("To ensure compatibility with various systems\n"
2596 "session names may not contain a '\\' character"));
2598 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2604 if (create_engine ()) {
2608 if (Glib::file_test (session_path
, Glib::FileTest (G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_DIR
))) {
2612 std::string existing
= Glib::build_filename (session_path
, session_name
);
2614 if (!ask_about_loading_existing_session (existing
)) {
2615 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2620 _session_is_new
= false;
2625 MessageDialog
msg (string_compose (_("There is no existing session at \"%1\""), session_path
));
2627 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2631 if (session_name
.find ('/') != std::string::npos
) {
2632 MessageDialog
msg (*_startup
, _("To ensure compatibility with various systems\n"
2633 "session names may not contain a '/' character"));
2635 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2639 if (session_name
.find ('\\') != std::string::npos
) {
2640 MessageDialog
msg (*_startup
, _("To ensure compatibility with various systems\n"
2641 "session names may not contain a '\\' character"));
2643 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2647 _session_is_new
= true;
2650 if (likely_new
&& template_name
.empty()) {
2652 ret
= build_session_from_nsd (session_path
, session_name
);
2656 ret
= load_session (session_path
, session_name
, template_name
);
2659 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2663 if (!ARDOUR_COMMAND_LINE::immediate_save
.empty()) {
2664 _session
->save_state (ARDOUR_COMMAND_LINE::immediate_save
, false);
2674 ARDOUR_UI::close_session()
2676 if (!check_audioengine()) {
2680 if (unload_session (true)) {
2684 ARDOUR_COMMAND_LINE::session_name
= "";
2686 if (get_session_parameters (true, false)) {
2690 goto_editor_window ();
2693 /** @return -2 if the load failed because we are not connected to the AudioEngine */
2695 ARDOUR_UI::load_session (const std::string
& path
, const std::string
& snap_name
, std::string mix_template
)
2697 Session
*new_session
;
2701 session_loaded
= false;
2703 if (!check_audioengine()) {
2707 unload_status
= unload_session ();
2709 if (unload_status
< 0) {
2711 } else if (unload_status
> 0) {
2716 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME
));
2719 new_session
= new Session (*engine
, path
, snap_name
, 0, mix_template
);
2722 /* this one is special */
2724 catch (AudioEngine::PortRegistrationFailure
& err
) {
2726 MessageDialog
msg (err
.what(),
2729 Gtk::BUTTONS_CLOSE
);
2731 msg
.set_title (_("Port Registration Error"));
2732 msg
.set_secondary_text (_("Click the Close button to try again."));
2733 msg
.set_position (Gtk::WIN_POS_CENTER
);
2737 int response
= msg
.run ();
2742 case RESPONSE_CANCEL
:
2752 MessageDialog
msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path
, snap_name
),
2757 msg
.set_title (_("Loading Error"));
2758 msg
.set_secondary_text (_("Click the Refresh button to try again."));
2759 msg
.add_button (Stock::REFRESH
, 1);
2760 msg
.set_position (Gtk::WIN_POS_CENTER
);
2764 int response
= msg
.run ();
2779 list
<string
> const u
= new_session
->unknown_processors ();
2781 MissingPluginDialog
d (_session
, u
);
2786 /* Now the session been created, add the transport controls */
2787 new_session
->add_controllable(roll_controllable
);
2788 new_session
->add_controllable(stop_controllable
);
2789 new_session
->add_controllable(goto_start_controllable
);
2790 new_session
->add_controllable(goto_end_controllable
);
2791 new_session
->add_controllable(auto_loop_controllable
);
2792 new_session
->add_controllable(play_selection_controllable
);
2793 new_session
->add_controllable(rec_controllable
);
2795 set_session (new_session
);
2797 session_loaded
= true;
2799 goto_editor_window ();
2802 _session
->set_clean ();
2813 ARDOUR_UI::build_session (const std::string
& path
, const std::string
& snap_name
, BusProfile
& bus_profile
)
2815 Session
*new_session
;
2818 if (!check_audioengine()) {
2822 session_loaded
= false;
2824 x
= unload_session ();
2832 _session_is_new
= true;
2835 new_session
= new Session (*engine
, path
, snap_name
, &bus_profile
);
2840 MessageDialog
msg (string_compose(_("Could not create session in \"%1\""), path
));
2846 /* Give the new session the default GUI state, if such things exist */
2849 n
= Config
->instant_xml (X_("Editor"));
2851 new_session
->add_instant_xml (*n
, false);
2853 n
= Config
->instant_xml (X_("Mixer"));
2855 new_session
->add_instant_xml (*n
, false);
2858 /* Put the playhead at 0 and scroll fully left */
2859 n
= new_session
->instant_xml (X_("Editor"));
2861 n
->add_property (X_("playhead"), X_("0"));
2862 n
->add_property (X_("left-frame"), X_("0"));
2865 set_session (new_session
);
2867 session_loaded
= true;
2869 new_session
->save_state(new_session
->name());
2875 ARDOUR_UI::launch_chat ()
2878 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2880 open_uri("http://webchat.freenode.net/?channels=ardour");
2885 ARDOUR_UI::show_about ()
2889 about
->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response
) );
2892 about
->set_transient_for(*editor
);
2897 ARDOUR_UI::launch_manual ()
2899 PBD::open_uri("http://ardour.org/flossmanual");
2903 ARDOUR_UI::launch_reference ()
2905 PBD::open_uri("http://ardour.org/refmanual");
2909 ARDOUR_UI::hide_about ()
2912 about
->get_window()->set_cursor ();
2918 ARDOUR_UI::about_signal_response (int /*response*/)
2924 ARDOUR_UI::show_splash ()
2928 splash
= new Splash
;
2936 splash
->queue_draw ();
2937 splash
->get_window()->process_updates (true);
2942 ARDOUR_UI::hide_splash ()
2950 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport
& rep
, const gchar
* list_title
,
2951 const string
& plural_msg
, const string
& singular_msg
)
2955 removed
= rep
.paths
.size();
2958 MessageDialog
msgd (*editor
,
2959 _("No files were ready for cleanup"),
2962 (Gtk::ButtonsType
)(Gtk::BUTTONS_OK
) );
2963 msgd
.set_secondary_text (_("If this seems suprising, \n\
2964 check for any existing snapshots.\n\
2965 These may still include regions that\n\
2966 require some unused files to continue to exist."));
2972 ArdourDialog
results (_("Clean-up"), true, false);
2974 struct CleanupResultsModelColumns
: public Gtk::TreeModel::ColumnRecord
{
2975 CleanupResultsModelColumns() {
2979 Gtk::TreeModelColumn
<std::string
> visible_name
;
2980 Gtk::TreeModelColumn
<std::string
> fullpath
;
2984 CleanupResultsModelColumns results_columns
;
2985 Glib::RefPtr
<Gtk::ListStore
> results_model
;
2986 Gtk::TreeView results_display
;
2988 results_model
= ListStore::create (results_columns
);
2989 results_display
.set_model (results_model
);
2990 results_display
.append_column (list_title
, results_columns
.visible_name
);
2992 results_display
.set_name ("CleanupResultsList");
2993 results_display
.set_headers_visible (true);
2994 results_display
.set_headers_clickable (false);
2995 results_display
.set_reorderable (false);
2997 Gtk::ScrolledWindow list_scroller
;
3000 Gtk::HBox dhbox
; // the hbox for the image and text
3001 Gtk::HBox ddhbox
; // the hbox we eventually pack into the dialog's vbox
3002 Gtk::Image
* dimage
= manage (new Gtk::Image(Stock::DIALOG_INFO
, Gtk::ICON_SIZE_DIALOG
));
3004 dimage
->set_alignment(ALIGN_LEFT
, ALIGN_TOP
);
3006 const string dead_directory
= _session
->session_directory().dead_path().to_string();
3009 %1 - number of files removed
3010 %2 - location of "dead"
3011 %3 - size of files affected
3012 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3015 const char* bprefix
;
3016 double space_adjusted
= 0;
3018 if (rep
.space
< 1000) {
3020 space_adjusted
= rep
.space
;
3021 } else if (rep
.space
< 1000000) {
3022 bprefix
= X_("kilo");
3023 space_adjusted
= truncf((float)rep
.space
/ 1000.0);
3024 } else if (rep
.space
< 1000000 * 1000) {
3025 bprefix
= X_("mega");
3026 space_adjusted
= truncf((float)rep
.space
/ (1000.0 * 1000.0));
3028 bprefix
= X_("giga");
3029 space_adjusted
= truncf((float)rep
.space
/ (1000.0 * 1000 * 1000.0));
3033 txt
.set_text (string_compose (plural_msg
, removed
, dead_directory
, space_adjusted
, bprefix
));
3035 txt
.set_text (string_compose (singular_msg
, removed
, dead_directory
, space_adjusted
, bprefix
));
3038 dhbox
.pack_start (*dimage
, true, false, 5);
3039 dhbox
.pack_start (txt
, true, false, 5);
3041 for (vector
<string
>::iterator i
= rep
.paths
.begin(); i
!= rep
.paths
.end(); ++i
) {
3042 TreeModel::Row row
= *(results_model
->append());
3043 row
[results_columns
.visible_name
] = *i
;
3044 row
[results_columns
.fullpath
] = *i
;
3047 list_scroller
.add (results_display
);
3048 list_scroller
.set_size_request (-1, 150);
3049 list_scroller
.set_policy (Gtk::POLICY_NEVER
, Gtk::POLICY_AUTOMATIC
);
3051 dvbox
.pack_start (dhbox
, true, false, 5);
3052 dvbox
.pack_start (list_scroller
, true, false, 5);
3053 ddhbox
.pack_start (dvbox
, true, false, 5);
3055 results
.get_vbox()->pack_start (ddhbox
, true, false, 5);
3056 results
.add_button (Stock::CLOSE
, RESPONSE_CLOSE
);
3057 results
.set_default_response (RESPONSE_CLOSE
);
3058 results
.set_position (Gtk::WIN_POS_MOUSE
);
3060 results_display
.show();
3061 list_scroller
.show();
3068 //results.get_vbox()->show();
3069 results
.set_resizable (false);
3076 ARDOUR_UI::cleanup ()
3078 if (_session
== 0) {
3079 /* shouldn't happen: menu item is insensitive */
3084 MessageDialog
checker (_("Are you sure you want to cleanup?"),
3086 Gtk::MESSAGE_QUESTION
,
3087 (Gtk::ButtonsType
)(Gtk::BUTTONS_NONE
));
3089 checker
.set_secondary_text(_("Cleanup is a destructive operation.\n\
3090 ALL undo/redo information will be lost if you cleanup.\n\
3091 Cleanup will move all unused files to a \"dead\" location."));
3093 checker
.add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
3094 checker
.add_button (_("Clean Up"), RESPONSE_ACCEPT
);
3095 checker
.set_default_response (RESPONSE_CANCEL
);
3097 checker
.set_name (_("CleanupDialog"));
3098 checker
.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME
);
3099 checker
.set_position (Gtk::WIN_POS_MOUSE
);
3101 switch (checker
.run()) {
3102 case RESPONSE_ACCEPT
:
3108 ARDOUR::CleanupReport rep
;
3110 editor
->prepare_for_cleanup ();
3112 /* do not allow flush until a session is reloaded */
3114 Glib::RefPtr
<Action
> act
= ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3116 act
->set_sensitive (false);
3119 if (_session
->cleanup_sources (rep
)) {
3120 editor
->finish_cleanup ();
3124 editor
->finish_cleanup ();
3127 display_cleanup_results (rep
,
3130 The following %1 files were not in use and \n\
3131 have been moved to:\n\n\
3133 After a restart of Ardour,\n\n\
3134 Session -> Cleanup -> Flush Wastebasket\n\n\
3135 will release an additional\n\
3136 %3 %4bytes of disk space.\n"),
3138 The following file was not in use and \n \
3139 has been moved to:\n \
3141 After a restart of Ardour,\n\n\
3142 Session -> Cleanup -> Flush Wastebasket\n\n\
3143 will release an additional\n\
3144 %3 %4bytes of disk space.\n"
3150 ARDOUR_UI::flush_trash ()
3152 if (_session
== 0) {
3153 /* shouldn't happen: menu item is insensitive */
3157 ARDOUR::CleanupReport rep
;
3159 if (_session
->cleanup_trash_sources (rep
)) {
3163 display_cleanup_results (rep
,
3165 _("The following %1 files were deleted from\n\
3167 releasing %3 %4bytes of disk space"),
3168 _("The following file was deleted from\n\
3170 releasing %3 %4bytes of disk space"));
3174 ARDOUR_UI::add_route (Gtk::Window
* float_window
)
3182 if (add_route_dialog
== 0) {
3183 add_route_dialog
= new AddRouteDialog (_session
);
3185 add_route_dialog
->set_transient_for (*float_window
);
3189 if (add_route_dialog
->is_visible()) {
3190 /* we're already doing this */
3194 ResponseType r
= (ResponseType
) add_route_dialog
->run ();
3196 add_route_dialog
->hide();
3199 case RESPONSE_ACCEPT
:
3206 if ((count
= add_route_dialog
->count()) <= 0) {
3210 string template_path
= add_route_dialog
->track_template();
3212 if (!template_path
.empty()) {
3213 _session
->new_route_from_template (count
, template_path
);
3217 uint32_t input_chan
= add_route_dialog
->channels ();
3218 uint32_t output_chan
;
3219 string name_template
= add_route_dialog
->name_template ();
3220 bool track
= add_route_dialog
->track ();
3221 RouteGroup
* route_group
= add_route_dialog
->route_group ();
3223 AutoConnectOption oac
= Config
->get_output_auto_connect();
3225 if (oac
& AutoConnectMaster
) {
3226 output_chan
= (_session
->master_out() ? _session
->master_out()->n_inputs().n_audio() : input_chan
);
3228 output_chan
= input_chan
;
3231 /* XXX do something with name template */
3233 if (add_route_dialog
->type() == ARDOUR::DataType::MIDI
) {
3235 session_add_midi_track (route_group
, count
, name_template
);
3237 MessageDialog
msg (*editor
,
3238 _("Sorry, MIDI Busses are not supported at this time."));
3240 //session_add_midi_bus();
3244 session_add_audio_track (input_chan
, output_chan
, add_route_dialog
->mode(), route_group
, count
, name_template
);
3246 session_add_audio_bus (input_chan
, output_chan
, route_group
, count
, name_template
);
3252 ARDOUR_UI::mixer_settings () const
3257 node
= _session
->instant_xml(X_("Mixer"));
3259 node
= Config
->instant_xml(X_("Mixer"));
3263 node
= new XMLNode (X_("Mixer"));
3270 ARDOUR_UI::editor_settings () const
3275 node
= _session
->instant_xml(X_("Editor"));
3277 node
= Config
->instant_xml(X_("Editor"));
3281 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3282 node
= Config
->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3287 node
= new XMLNode (X_("Editor"));
3294 ARDOUR_UI::keyboard_settings () const
3298 node
= Config
->extra_xml(X_("Keyboard"));
3301 node
= new XMLNode (X_("Keyboard"));
3307 ARDOUR_UI::create_xrun_marker (framepos_t where
)
3309 editor
->mouse_add_new_marker (where
, false, true);
3313 ARDOUR_UI::halt_on_xrun_message ()
3315 MessageDialog
msg (*editor
,
3316 _("Recording was stopped because your system could not keep up."));
3321 ARDOUR_UI::xrun_handler (framepos_t where
)
3327 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler
, where
)
3329 if (_session
&& Config
->get_create_xrun_marker() && _session
->actively_recording()) {
3330 create_xrun_marker(where
);
3333 if (_session
&& Config
->get_stop_recording_on_xrun() && _session
->actively_recording()) {
3334 halt_on_xrun_message ();
3339 ARDOUR_UI::disk_overrun_handler ()
3341 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler
)
3343 if (!have_disk_speed_dialog_displayed
) {
3344 have_disk_speed_dialog_displayed
= true;
3345 MessageDialog
* msg
= new MessageDialog (*editor
, string_compose (_("\
3346 The disk system on your computer\n\
3347 was not able to keep up with %1.\n\
3349 Specifically, it failed to write data to disk\n\
3350 quickly enough to keep up with recording.\n"), PROGRAM_NAME
));
3351 msg
->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone
), msg
));
3357 ARDOUR_UI::disk_underrun_handler ()
3359 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler
)
3361 if (!have_disk_speed_dialog_displayed
) {
3362 have_disk_speed_dialog_displayed
= true;
3363 MessageDialog
* msg
= new MessageDialog (*editor
,
3364 string_compose (_("The disk system on your computer\n\
3365 was not able to keep up with %1.\n\
3367 Specifically, it failed to read data from disk\n\
3368 quickly enough to keep up with playback.\n"), PROGRAM_NAME
));
3369 msg
->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone
), msg
));
3375 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog
* msg
)
3377 have_disk_speed_dialog_displayed
= false;
3382 ARDOUR_UI::session_dialog (std::string msg
)
3384 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog
, msg
)
3389 d
= new MessageDialog (*editor
, msg
, false, MESSAGE_INFO
, BUTTONS_OK
, true);
3391 d
= new MessageDialog (msg
, false, MESSAGE_INFO
, BUTTONS_OK
, true);
3400 ARDOUR_UI::pending_state_dialog ()
3402 HBox
* hbox
= new HBox();
3403 Image
* image
= new Image (Stock::DIALOG_QUESTION
, ICON_SIZE_DIALOG
);
3404 ArdourDialog
dialog (_("Crash Recovery"), true);
3406 This session appears to have been in\n\
3407 middle of recording when ardour or\n\
3408 the computer was shutdown.\n\
3410 Ardour can recover any captured audio for\n\
3411 you, or it can ignore it. Please decide\n\
3412 what you would like to do.\n"));
3413 image
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
3414 hbox
->pack_start (*image
, PACK_EXPAND_WIDGET
, 12);
3415 hbox
->pack_end (message
, PACK_EXPAND_PADDING
, 12);
3416 dialog
.get_vbox()->pack_start(*hbox
, PACK_EXPAND_PADDING
, 6);
3417 dialog
.add_button (_("Ignore crash data"), RESPONSE_REJECT
);
3418 dialog
.add_button (_("Recover from crash"), RESPONSE_ACCEPT
);
3419 dialog
.set_default_response (RESPONSE_ACCEPT
);
3420 dialog
.set_position (WIN_POS_CENTER
);
3425 switch (dialog
.run ()) {
3426 case RESPONSE_ACCEPT
:
3434 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired
, framecnt_t actual
)
3436 HBox
* hbox
= new HBox();
3437 Image
* image
= new Image (Stock::DIALOG_QUESTION
, ICON_SIZE_DIALOG
);
3438 ArdourDialog
dialog (_("Sample Rate Mismatch"), true);
3439 Label
message (string_compose (_("\
3440 This session was created with a sample rate of %1 Hz\n\
3442 The audioengine is currently running at %2 Hz\n"), desired
, actual
));
3444 image
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
3445 hbox
->pack_start (*image
, PACK_EXPAND_WIDGET
, 12);
3446 hbox
->pack_end (message
, PACK_EXPAND_PADDING
, 12);
3447 dialog
.get_vbox()->pack_start(*hbox
, PACK_EXPAND_PADDING
, 6);
3448 dialog
.add_button (_("Do not load session"), RESPONSE_REJECT
);
3449 dialog
.add_button (_("Load session anyway"), RESPONSE_ACCEPT
);
3450 dialog
.set_default_response (RESPONSE_ACCEPT
);
3451 dialog
.set_position (WIN_POS_CENTER
);
3456 switch (dialog
.run ()) {
3457 case RESPONSE_ACCEPT
:
3466 ARDOUR_UI::disconnect_from_jack ()
3469 if( engine
->disconnect_from_jack ()) {
3470 MessageDialog
msg (*editor
, _("Could not disconnect from JACK"));
3474 update_sample_rate (0);
3479 ARDOUR_UI::reconnect_to_jack ()
3482 if (engine
->reconnect_to_jack ()) {
3483 MessageDialog
msg (*editor
, _("Could not reconnect to JACK"));
3487 update_sample_rate (0);
3492 ARDOUR_UI::use_config ()
3494 XMLNode
* node
= Config
->extra_xml (X_("TransportControllables"));
3496 set_transport_controllable_state (*node
);
3501 ARDOUR_UI::update_transport_clocks (framepos_t pos
)
3503 if (Config
->get_primary_clock_delta_edit_cursor()) {
3504 primary_clock
.set (pos
, false, editor
->get_preferred_edit_position(), 1);
3506 primary_clock
.set (pos
, 0, true);
3509 if (Config
->get_secondary_clock_delta_edit_cursor()) {
3510 secondary_clock
.set (pos
, false, editor
->get_preferred_edit_position(), 2);
3512 secondary_clock
.set (pos
);
3515 if (big_clock_window
->get()) {
3516 big_clock
.set (pos
);
3522 ARDOUR_UI::step_edit_status_change (bool yn
)
3524 // XXX should really store pre-step edit status of things
3525 // we make insensitive
3528 rec_button
.set_visual_state (3);
3529 rec_button
.set_sensitive (false);
3531 rec_button
.set_visual_state (0);
3532 rec_button
.set_sensitive (true);
3537 ARDOUR_UI::record_state_changed ()
3539 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed
);
3541 if (!_session
|| !big_clock_window
->get()) {
3542 /* why bother - the clock isn't visible */
3546 Session::RecordState
const r
= _session
->record_status ();
3547 bool const h
= _session
->have_rec_enabled_track ();
3549 if (r
== Session::Recording
&& h
) {
3550 big_clock
.set_widget_name ("BigClockRecording");
3552 big_clock
.set_widget_name ("BigClockNonRecording");
3557 ARDOUR_UI::first_idle ()
3560 _session
->allow_auto_play (true);
3564 editor
->first_idle();
3567 Keyboard::set_can_save_keybindings (true);
3572 ARDOUR_UI::store_clock_modes ()
3574 XMLNode
* node
= new XMLNode(X_("ClockModes"));
3576 for (vector
<AudioClock
*>::iterator x
= AudioClock::clocks
.begin(); x
!= AudioClock::clocks
.end(); ++x
) {
3577 node
->add_property ((*x
)->name().c_str(), enum_2_string ((*x
)->mode()));
3580 _session
->add_extra_xml (*node
);
3581 _session
->set_dirty ();
3586 ARDOUR_UI::TransportControllable::TransportControllable (std::string name
, ARDOUR_UI
& u
, ToggleType tp
)
3587 : Controllable (name
), ui (u
), type(tp
)
3593 ARDOUR_UI::TransportControllable::set_value (double val
)
3595 if (type
== ShuttleControl
) {
3602 fract
= -((0.5 - val
)/0.5);
3604 fract
= ((val
- 0.5)/0.5);
3608 ui
.set_shuttle_fract (fract
);
3613 /* do nothing: these are radio-style actions */
3617 const char *action
= 0;
3621 action
= X_("Roll");
3624 action
= X_("Stop");
3627 action
= X_("Goto Start");
3630 action
= X_("Goto End");
3633 action
= X_("Loop");
3636 action
= X_("Play Selection");
3639 action
= X_("Record");
3649 Glib::RefPtr
<Action
> act
= ActionManager::get_action ("Transport", action
);
3657 ARDOUR_UI::TransportControllable::get_value (void) const
3676 case ShuttleControl
:
3686 ARDOUR_UI::TransportControllable::set_id (const string
& str
)
3692 ARDOUR_UI::setup_profile ()
3694 if (gdk_screen_width() < 1200) {
3695 Profile
->set_small_screen ();
3699 if (getenv ("ARDOUR_SAE")) {
3700 Profile
->set_sae ();
3701 Profile
->set_single_package ();
3706 ARDOUR_UI::toggle_translations ()
3708 using namespace Glib
;
3710 RefPtr
<Action
> act
= ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3712 RefPtr
<ToggleAction
> ract
= RefPtr
<ToggleAction
>::cast_dynamic (act
);
3715 string i18n_killer
= ARDOUR::translation_kill_path();
3717 bool already_enabled
= !ARDOUR::translations_are_disabled ();
3719 if (ract
->get_active ()) {
3720 /* we don't care about errors */
3721 int fd
= ::open (i18n_killer
.c_str(), O_RDONLY
|O_CREAT
, 0644);
3724 /* we don't care about errors */
3725 unlink (i18n_killer
.c_str());
3728 if (already_enabled
!= ract
->get_active()) {
3729 MessageDialog
win (already_enabled
? _("Translations disabled") : _("Translations enabled"),
3731 Gtk::MESSAGE_WARNING
,
3733 win
.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME
));
3734 win
.set_position (Gtk::WIN_POS_CENTER
);
3742 /** Add a window proxy to our list, so that its state will be saved.
3743 * This call also causes the window to be created and opened if its
3744 * state was saved as `visible'.
3747 ARDOUR_UI::add_window_proxy (WindowProxyBase
* p
)
3749 _window_proxies
.push_back (p
);
3753 /** Remove a window proxy from our list. Must be called if a WindowProxy
3754 * is deleted, to prevent hanging pointers.
3757 ARDOUR_UI::remove_window_proxy (WindowProxyBase
* p
)
3759 _window_proxies
.remove (p
);
3763 ARDOUR_UI::missing_file (Session
*s
, std::string str
, DataType type
)
3765 MissingFileDialog
dialog (s
, str
, type
);
3770 int result
= dialog
.run ();
3777 return 1; // quit entire session load
3780 result
= dialog
.get_action ();
3786 ARDOUR_UI::ambiguous_file (std::string file
, std::string path
, std::vector
<std::string
> hits
)
3788 AmbiguousFileDialog
dialog (file
, hits
);
3794 return dialog
.get_which ();