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/bindings.h"
53 #include "gtkmm2ext/gtk_ui.h"
54 #include "gtkmm2ext/utils.h"
55 #include "gtkmm2ext/click_box.h"
56 #include "gtkmm2ext/fastmeter.h"
57 #include "gtkmm2ext/popup.h"
58 #include "gtkmm2ext/window_title.h"
60 #include "midi++/manager.h"
62 #include "ardour/ardour.h"
63 #include "ardour/callback.h"
64 #include "ardour/profile.h"
65 #include "ardour/session_directory.h"
66 #include "ardour/session_route.h"
67 #include "ardour/session_state_utils.h"
68 #include "ardour/session_utils.h"
69 #include "ardour/port.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/playlist.h"
72 #include "ardour/utils.h"
73 #include "ardour/audio_diskstream.h"
74 #include "ardour/audiofilesource.h"
75 #include "ardour/recent_sessions.h"
76 #include "ardour/port.h"
77 #include "ardour/audio_track.h"
78 #include "ardour/midi_track.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/filename_extensions.h"
82 typedef uint64_t microseconds_t
;
86 #include "add_route_dialog.h"
87 #include "ambiguous_file_dialog.h"
88 #include "ardour_ui.h"
89 #include "audio_clock.h"
90 #include "bundle_manager.h"
91 #include "engine_dialog.h"
92 #include "gain_meter.h"
93 #include "global_port_matrix.h"
94 #include "gui_thread.h"
96 #include "location_ui.h"
97 #include "missing_file_dialog.h"
98 #include "missing_plugin_dialog.h"
101 #include "processor_box.h"
102 #include "prompter.h"
103 #include "public_editor.h"
104 #include "route_time_axis.h"
105 #include "session_metadata_dialog.h"
106 #include "shuttle_control.h"
107 #include "speaker_dialog.h"
110 #include "theme_manager.h"
111 #include "time_axis_view_item.h"
113 #include "window_proxy.h"
117 using namespace ARDOUR
;
119 using namespace Gtkmm2ext
;
122 ARDOUR_UI
*ARDOUR_UI::theArdourUI
= 0;
123 UIConfiguration
*ARDOUR_UI::ui_config
= 0;
125 sigc::signal
<void,bool> ARDOUR_UI::Blink
;
126 sigc::signal
<void> ARDOUR_UI::RapidScreenUpdate
;
127 sigc::signal
<void> ARDOUR_UI::SuperRapidScreenUpdate
;
128 sigc::signal
<void, framepos_t
, bool, framepos_t
> ARDOUR_UI::Clock
;
130 bool could_be_a_valid_path (const string
& path
);
132 ARDOUR_UI::ARDOUR_UI (int *argcp
, char **argvp
[])
134 : Gtkmm2ext::UI (PROGRAM_NAME
, argcp
, argvp
)
136 , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
137 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
138 , preroll_clock (new AudioClock (X_("preroll"), false, X_("PreRollClock"), true, false, true))
139 , postroll_clock (new AudioClock (X_("postroll"), false, X_("PostRollClock"), true, false, true))
143 , preroll_button (_("pre\nroll"))
144 , postroll_button (_("post\nroll"))
148 , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
152 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll
))
153 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop
))
154 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart
))
155 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd
))
156 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop
))
157 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection
))
158 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable
))
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 , auto_return_button (_("Auto Return"))
169 , auto_play_button (_("Auto Play"))
170 , auto_input_button (_("Auto Input"))
171 // , click_button (_("Click"))
172 , time_master_button (_("time\nmaster"))
174 , auditioning_alert_button (_("AUDITION"))
175 , solo_alert_button (_("SOLO"))
177 , error_log_button (_("Errors"))
180 using namespace Gtk::Menu_Helpers
;
186 // _auto_display_errors = false;
188 * This was commented out as it wasn't defined
189 * in A3 IIRC. If this is not needed it should
190 * be completely removed.
198 if (theArdourUI
== 0) {
202 ui_config
= new UIConfiguration();
203 theme_manager
= new ThemeManager();
211 _session_is_new
= false;
212 big_clock_window
= 0;
213 big_clock_height
= 0;
214 big_clock_resize_in_progress
= false;
215 session_selector_window
= 0;
216 last_key_press_time
= 0;
217 _will_create_new_session_automatically
= false;
218 add_route_dialog
= 0;
221 rc_option_editor
= 0;
222 session_option_editor
= 0;
224 open_session_selector
= 0;
225 have_configure_timeout
= false;
226 have_disk_speed_dialog_displayed
= false;
227 session_loaded
= false;
228 ignore_dual_punch
= false;
229 original_big_clock_width
= -1;
230 original_big_clock_height
= -1;
231 original_big_clock_font_size
= 0;
233 roll_button
.unset_flags (Gtk::CAN_FOCUS
);
234 stop_button
.unset_flags (Gtk::CAN_FOCUS
);
235 goto_start_button
.unset_flags (Gtk::CAN_FOCUS
);
236 goto_end_button
.unset_flags (Gtk::CAN_FOCUS
);
237 auto_loop_button
.unset_flags (Gtk::CAN_FOCUS
);
238 play_selection_button
.unset_flags (Gtk::CAN_FOCUS
);
239 rec_button
.unset_flags (Gtk::CAN_FOCUS
);
240 join_play_range_button
.unset_flags (Gtk::CAN_FOCUS
);
241 last_configure_time
= 0;
244 ARDOUR::Diskstream::DiskOverrun
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::disk_overrun_handler
, this), gui_context());
245 ARDOUR::Diskstream::DiskUnderrun
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::disk_underrun_handler
, this), gui_context());
247 /* handle dialog requests */
249 ARDOUR::Session::Dialog
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::session_dialog
, this, _1
), gui_context());
251 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
253 ARDOUR::Session::AskAboutPendingState
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::pending_state_dialog
, this));
255 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
257 ARDOUR::Session::AskAboutSampleRateMismatch
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::sr_mismatch_dialog
, this, _1
, _2
));
259 /* handle requests to quit (coming from JACK session) */
261 ARDOUR::Session::Quit
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::finish
, this), gui_context ());
263 /* handle requests to deal with missing files */
265 ARDOUR::Session::MissingFile
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::missing_file
, this, _1
, _2
, _3
));
267 /* and ambiguous files */
269 ARDOUR::FileSource::AmbiguousFileName
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::ambiguous_file
, this, _1
, _2
, _3
));
271 /* lets get this party started */
274 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst
, ARDOUR_COMMAND_LINE::try_hw_optimization
)) {
275 throw failed_constructor ();
278 setup_gtk_ardour_enums ();
281 GainMeter::setup_slider_pix ();
282 RouteTimeAxisView::setup_slider_pix ();
283 SendProcessorEntry::setup_slider_pix ();
284 SessionEvent::create_per_thread_pool ("GUI", 512);
286 } catch (failed_constructor
& err
) {
287 error
<< string_compose (_("could not initialize %1."), PROGRAM_NAME
) << endmsg
;
292 /* we like keyboards */
294 keyboard
= new ArdourKeyboard(*this);
297 XMLNode
* node
= ARDOUR_UI::instance()->keyboard_settings();
299 keyboard
->set_state (*node
, Stateful::loading_state_version
);
302 /* we don't like certain modifiers */
303 Bindings::set_ignored_state (GDK_LOCK_MASK
|GDK_MOD2_MASK
|GDK_MOD3_MASK
);
307 TimeAxisViewItem::set_constant_heights ();
309 /* The following must happen after ARDOUR::init() so that Config is set up */
311 location_ui
= new ActionWindowProxy
<LocationUIWindow
> (X_("locations"), Config
->extra_xml (X_("UI")), X_("ToggleLocations"));
312 big_clock_window
= new ActionWindowProxy
<Gtk::Window
> (X_("bigclock"), Config
->extra_xml (X_("UI")), X_("ToggleBigClock"));
313 speaker_config_window
= new ActionWindowProxy
<SpeakerDialog
> (X_("speakerconf"), Config
->extra_xml (X_("UI")), X_("toggle-speaker-config"));
315 for (ARDOUR::DataType::iterator i
= ARDOUR::DataType::begin(); i
!= ARDOUR::DataType::end(); ++i
) {
316 _global_port_matrix
[*i
] = new ActionWindowProxy
<GlobalPortMatrixWindow
> (
317 string_compose ("GlobalPortMatrix-%1", (*i
).to_string()),
318 Config
->extra_xml (X_("UI")),
319 string_compose ("toggle-%1-connection-manager", (*i
).to_string())
325 SpeakerDialog
* s
= new SpeakerDialog ();
326 s
->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction
), X_("<Actions>/Common/toggle-speaker-config")));
327 speaker_config_window
->set (s
);
329 starting
.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup
));
330 stopping
.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown
));
333 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
335 ARDOUR_UI::run_startup (bool should_be_new
, string load_template
)
338 _startup
= new ArdourStartup ();
340 XMLNode
* audio_setup
= Config
->extra_xml ("AudioSetup");
342 if (audio_setup
&& _startup
->engine_control()) {
343 _startup
->engine_control()->set_state (*audio_setup
);
346 _startup
->set_new_only (should_be_new
);
347 if (!load_template
.empty()) {
348 _startup
->set_load_template( load_template
);
350 _startup
->present ();
356 switch (_startup
->response()) {
365 ARDOUR_UI::create_engine ()
367 // this gets called every time by new_session()
373 loading_message (_("Starting audio engine"));
376 engine
= new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name
, ARDOUR_COMMAND_LINE::jack_session_uuid
);
383 engine
->Stopped
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::engine_stopped
, this), gui_context());
384 engine
->Running
.connect (forever_connections
, MISSING_INVALIDATOR
, boost::bind (&ARDOUR_UI::engine_running
, this), gui_context());
385 engine
->SampleRateChanged
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::update_sample_rate
, this, _1
), gui_context());
387 engine
->Halted
.connect_same_thread (forever_connections
, boost::bind (&ARDOUR_UI::engine_halted
, this, _1
, false));
389 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports
);
397 ARDOUR_UI::post_engine ()
399 /* Things to be done once we create the AudioEngine
402 ARDOUR::init_post_engine ();
404 ActionManager::init ();
407 if (setup_windows ()) {
408 throw failed_constructor ();
411 check_memory_locking();
413 /* this is the first point at which all the keybindings are available */
415 if (ARDOUR_COMMAND_LINE::show_key_actions
) {
416 vector
<string
> names
;
417 vector
<string
> paths
;
418 vector
<string
> tooltips
;
420 vector
<AccelKey
> bindings
;
422 ActionManager::get_all_actions (names
, paths
, tooltips
, keys
, bindings
);
424 vector
<string
>::iterator n
;
425 vector
<string
>::iterator k
;
426 for (n
= names
.begin(), k
= keys
.begin(); n
!= names
.end(); ++n
, ++k
) {
427 cerr
<< "Action: " << (*n
) << " bound to " << (*k
) << endl
;
433 blink_timeout_tag
= -1;
435 /* this being a GUI and all, we want peakfiles */
437 AudioFileSource::set_build_peakfiles (true);
438 AudioFileSource::set_build_missing_peakfiles (true);
440 /* set default clock modes */
442 if (Profile
->get_sae()) {
443 primary_clock
->set_mode (AudioClock::BBT
);
444 secondary_clock
->set_mode (AudioClock::MinSec
);
446 primary_clock
->set_mode (AudioClock::Timecode
);
447 secondary_clock
->set_mode (AudioClock::BBT
);
450 /* start the time-of-day-clock */
453 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
454 update_wall_clock ();
455 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock
), 60000);
458 update_disk_space ();
460 update_sample_rate (engine
->frame_rate());
462 Config
->ParameterChanged
.connect (forever_connections
, MISSING_INVALIDATOR
, ui_bind (&ARDOUR_UI::parameter_changed
, this, _1
), gui_context());
463 boost::function
<void (string
)> pc (boost::bind (&ARDOUR_UI::parameter_changed
, this, _1
));
464 Config
->map_parameters (pc
);
466 /* now start and maybe save state */
468 if (do_engine_start () == 0) {
469 if (_session
&& _session_is_new
) {
470 /* we need to retain initial visual
471 settings for a new session
473 _session
->save_state ("");
478 ARDOUR_UI::~ARDOUR_UI ()
483 delete add_route_dialog
;
487 ARDOUR_UI::pop_back_splash ()
489 if (Splash::instance()) {
490 // Splash::instance()->pop_back();
491 Splash::instance()->hide ();
496 ARDOUR_UI::configure_timeout ()
498 if (last_configure_time
== 0) {
499 /* no configure events yet */
503 /* force a gap of 0.5 seconds since the last configure event
506 if (get_microseconds() - last_configure_time
< 500000) {
509 have_configure_timeout
= false;
510 cerr
<< "config event-driven save\n";
511 save_ardour_state ();
517 ARDOUR_UI::configure_handler (GdkEventConfigure
* /*conf*/)
519 if (have_configure_timeout
) {
520 last_configure_time
= get_microseconds();
522 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout
), 100);
523 have_configure_timeout
= true;
530 ARDOUR_UI::set_transport_controllable_state (const XMLNode
& node
)
532 const XMLProperty
* prop
;
534 if ((prop
= node
.property ("roll")) != 0) {
535 roll_controllable
->set_id (prop
->value());
537 if ((prop
= node
.property ("stop")) != 0) {
538 stop_controllable
->set_id (prop
->value());
540 if ((prop
= node
.property ("goto-start")) != 0) {
541 goto_start_controllable
->set_id (prop
->value());
543 if ((prop
= node
.property ("goto-end")) != 0) {
544 goto_end_controllable
->set_id (prop
->value());
546 if ((prop
= node
.property ("auto-loop")) != 0) {
547 auto_loop_controllable
->set_id (prop
->value());
549 if ((prop
= node
.property ("play-selection")) != 0) {
550 play_selection_controllable
->set_id (prop
->value());
552 if ((prop
= node
.property ("rec")) != 0) {
553 rec_controllable
->set_id (prop
->value());
555 if ((prop
= node
.property ("shuttle")) != 0) {
556 shuttle_box
->controllable()->set_id (prop
->value());
562 ARDOUR_UI::get_transport_controllable_state ()
564 XMLNode
* node
= new XMLNode(X_("TransportControllables"));
567 roll_controllable
->id().print (buf
, sizeof (buf
));
568 node
->add_property (X_("roll"), buf
);
569 stop_controllable
->id().print (buf
, sizeof (buf
));
570 node
->add_property (X_("stop"), buf
);
571 goto_start_controllable
->id().print (buf
, sizeof (buf
));
572 node
->add_property (X_("goto_start"), buf
);
573 goto_end_controllable
->id().print (buf
, sizeof (buf
));
574 node
->add_property (X_("goto_end"), buf
);
575 auto_loop_controllable
->id().print (buf
, sizeof (buf
));
576 node
->add_property (X_("auto_loop"), buf
);
577 play_selection_controllable
->id().print (buf
, sizeof (buf
));
578 node
->add_property (X_("play_selection"), buf
);
579 rec_controllable
->id().print (buf
, sizeof (buf
));
580 node
->add_property (X_("rec"), buf
);
581 shuttle_box
->controllable()->id().print (buf
, sizeof (buf
));
582 node
->add_property (X_("shuttle"), buf
);
589 ARDOUR_UI::autosave_session ()
591 if (g_main_depth() > 1) {
592 /* inside a recursive main loop,
593 give up because we may not be able to
599 if (!Config
->get_periodic_safety_backups()) {
604 _session
->maybe_write_autosave();
611 ARDOUR_UI::update_autosave ()
613 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave
)
615 if (_session
&& _session
->dirty()) {
616 if (_autosave_connection
.connected()) {
617 _autosave_connection
.disconnect();
620 _autosave_connection
= Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session
),
621 Config
->get_periodic_safety_backup_interval() * 1000);
624 if (_autosave_connection
.connected()) {
625 _autosave_connection
.disconnect();
631 ARDOUR_UI::backend_audio_error (bool we_set_params
, Gtk::Window
* toplevel
)
635 title
= string_compose (_("%1 could not start JACK"), PROGRAM_NAME
);
637 title
= string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME
);
640 MessageDialog
win (title
,
646 win
.set_secondary_text(_("There are several possible reasons:\n\
648 1) You requested audio parameters that are not supported..\n\
649 2) JACK is running as another user.\n\
651 Please consider the possibilities, and perhaps try different parameters."));
653 win
.set_secondary_text(_("There are several possible reasons:\n\
655 1) JACK is not running.\n\
656 2) JACK is running as another user, perhaps root.\n\
657 3) There is already another client called \"ardour\".\n\
659 Please consider the possibilities, and perhaps (re)start JACK."));
663 win
.set_transient_for (*toplevel
);
667 win
.add_button (Stock::OK
, RESPONSE_CLOSE
);
669 win
.add_button (Stock::QUIT
, RESPONSE_CLOSE
);
672 win
.set_default_response (RESPONSE_CLOSE
);
675 win
.set_position (Gtk::WIN_POS_CENTER
);
678 /* we just don't care about the result, but we want to block */
684 ARDOUR_UI::startup ()
686 Application
* app
= Application::instance ();
688 app
->ShouldQuit
.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish
));
689 app
->ShouldLoad
.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load
));
692 call_the_mothership (VERSIONSTRING
);
697 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session
, ARDOUR_COMMAND_LINE::load_template
)) {
703 goto_editor_window ();
705 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
706 to be opened on top of the editor window that goto_editor_window() just opened.
708 add_window_proxy (location_ui
);
709 add_window_proxy (big_clock_window
);
710 for (ARDOUR::DataType::iterator i
= ARDOUR::DataType::begin(); i
!= ARDOUR::DataType::end(); ++i
) {
711 add_window_proxy (_global_port_matrix
[*i
]);
714 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME
));
718 ARDOUR_UI::no_memory_warning ()
720 XMLNode
node (X_("no-memory-warning"));
721 Config
->add_instant_xml (node
);
725 ARDOUR_UI::check_memory_locking ()
728 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
732 XMLNode
* memory_warning_node
= Config
->instant_xml (X_("no-memory-warning"));
734 if (engine
->is_realtime() && memory_warning_node
== 0) {
736 struct rlimit limits
;
738 long pages
, page_size
;
740 if ((page_size
= sysconf (_SC_PAGESIZE
)) < 0 ||(pages
= sysconf (_SC_PHYS_PAGES
)) < 0) {
743 ram
= (int64_t) pages
* (int64_t) page_size
;
746 if (getrlimit (RLIMIT_MEMLOCK
, &limits
)) {
750 if (limits
.rlim_cur
!= RLIM_INFINITY
) {
752 if (ram
== 0 || ((double) limits
.rlim_cur
/ ram
) < 0.75) {
756 _("WARNING: Your system has a limit for maximum amount of locked memory. "
757 "This might cause %1 to run out of memory before your system "
758 "runs out of memory. \n\n"
759 "You can view the memory limit with 'ulimit -l', "
760 "and it is normally controlled by /etc/security/limits.conf"),
761 PROGRAM_NAME
).c_str());
763 VBox
* vbox
= msg
.get_vbox();
765 CheckButton
cb (_("Do not show this window again"));
767 cb
.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning
));
769 hbox
.pack_start (cb
, true, false);
770 vbox
->pack_start (hbox
);
777 editor
->ensure_float (msg
);
787 ARDOUR_UI::queue_finish ()
789 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish
));
793 ARDOUR_UI::idle_finish ()
796 return false; /* do not call again */
805 if (_session
->transport_rolling() && (++tries
< 8)) {
806 _session
->request_stop (false, true);
810 if (_session
->dirty()) {
811 vector
<string
> actions
;
812 actions
.push_back (_("Don't quit"));
813 actions
.push_back (_("Just quit"));
814 actions
.push_back (_("Save and quit"));
815 switch (ask_about_saving_session(actions
)) {
820 /* use the default name */
821 if (save_state_canfail ("")) {
822 /* failed - don't quit */
823 MessageDialog
msg (*editor
,
825 Ardour was unable to save your session.\n\n\
826 If you still wish to quit, please use the\n\n\
827 \"Just quit\" option."));
838 second_connection
.disconnect ();
839 point_one_second_connection
.disconnect ();
840 point_oh_five_second_connection
.disconnect ();
841 point_zero_one_second_connection
.disconnect();
844 /* Save state before deleting the session, as that causes some
845 windows to be destroyed before their visible state can be
848 save_ardour_state ();
851 // _session->set_deletion_in_progress ();
852 _session
->set_clean ();
853 _session
->remove_pending_capture_state ();
858 ArdourDialog::close_all_dialogs ();
864 ARDOUR_UI::ask_about_saving_session (const vector
<string
>& actions
)
866 ArdourDialog
window (_("Unsaved Session"));
867 Gtk::HBox dhbox
; // the hbox for the image and text
868 Gtk::Label prompt_label
;
869 Gtk::Image
* dimage
= manage (new Gtk::Image(Stock::DIALOG_WARNING
, Gtk::ICON_SIZE_DIALOG
));
873 assert (actions
.size() >= 3);
875 window
.add_button (actions
[0], RESPONSE_REJECT
);
876 window
.add_button (actions
[1], RESPONSE_APPLY
);
877 window
.add_button (actions
[2], RESPONSE_ACCEPT
);
879 window
.set_default_response (RESPONSE_ACCEPT
);
881 Gtk::Button
noquit_button (msg
);
882 noquit_button
.set_name ("EditorGTKButton");
886 if (_session
->snap_name() == _session
->name()) {
887 prompt
= string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
888 _session
->snap_name());
890 prompt
= string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
891 _session
->snap_name());
894 prompt_label
.set_text (prompt
);
895 prompt_label
.set_name (X_("PrompterLabel"));
896 prompt_label
.set_alignment(ALIGN_LEFT
, ALIGN_TOP
);
898 dimage
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
899 dhbox
.set_homogeneous (false);
900 dhbox
.pack_start (*dimage
, false, false, 5);
901 dhbox
.pack_start (prompt_label
, true, false, 5);
902 window
.get_vbox()->pack_start (dhbox
);
904 window
.set_name (_("Prompter"));
905 window
.set_position (Gtk::WIN_POS_MOUSE
);
906 window
.set_modal (true);
907 window
.set_resizable (false);
913 window
.set_keep_above (true);
916 ResponseType r
= (ResponseType
) window
.run();
921 case RESPONSE_ACCEPT
: // save and get out of here
923 case RESPONSE_APPLY
: // get out of here
933 ARDOUR_UI::every_second ()
936 update_buffer_load ();
937 update_disk_space ();
942 ARDOUR_UI::every_point_one_seconds ()
944 shuttle_box
->update_speed_display ();
945 RapidScreenUpdate(); /* EMIT_SIGNAL */
950 ARDOUR_UI::every_point_zero_one_seconds ()
952 // august 2007: actual update frequency: 40Hz, not 100Hz
954 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
959 ARDOUR_UI::update_sample_rate (framecnt_t
)
963 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate
, ignored
)
965 if (!engine
->connected()) {
967 snprintf (buf
, sizeof (buf
), _("disconnected"));
971 framecnt_t rate
= engine
->frame_rate();
973 if (fmod (rate
, 1000.0) != 0.0) {
974 snprintf (buf
, sizeof (buf
), _("%.1f kHz / %4.1f ms"),
975 (float) rate
/1000.0f
,
976 (engine
->frames_per_cycle() / (float) rate
) * 1000.0f
);
978 snprintf (buf
, sizeof (buf
), _("%" PRId64
" kHz / %4.1f ms"),
980 (engine
->frames_per_cycle() / (float) rate
) * 1000.0f
);
984 sample_rate_label
.set_text (buf
);
988 ARDOUR_UI::update_cpu_load ()
991 snprintf (buf
, sizeof (buf
), _("DSP: %5.1f%%"), engine
->get_cpu_load());
992 cpu_load_label
.set_text (buf
);
996 ARDOUR_UI::update_buffer_load ()
1002 c
= _session
->capture_load ();
1003 p
= _session
->playback_load ();
1005 snprintf (buf
, sizeof (buf
), _("Buffers p:%" PRIu32
"%% c:%" PRIu32
"%%"),
1006 _session
->playback_load(), _session
->capture_load());
1007 buffer_load_label
.set_text (buf
);
1009 buffer_load_label
.set_text ("");
1014 ARDOUR_UI::count_recenabled_streams (Route
& route
)
1016 Track
* track
= dynamic_cast<Track
*>(&route
);
1017 if (track
&& track
->record_enabled()) {
1018 rec_enabled_streams
+= track
->n_inputs().n_total();
1023 ARDOUR_UI::update_disk_space()
1025 if (_session
== 0) {
1029 framecnt_t frames
= _session
->available_capture_duration();
1031 framecnt_t fr
= _session
->frame_rate();
1033 if (frames
== max_framecnt
) {
1034 strcpy (buf
, _("Disk: 24hrs+"));
1036 rec_enabled_streams
= 0;
1037 _session
->foreach_route (this, &ARDOUR_UI::count_recenabled_streams
);
1039 if (rec_enabled_streams
) {
1040 frames
/= rec_enabled_streams
;
1047 hrs
= frames
/ (fr
* 3600);
1048 frames
-= hrs
* fr
* 3600;
1049 mins
= frames
/ (fr
* 60);
1050 frames
-= mins
* fr
* 60;
1053 snprintf (buf
, sizeof(buf
), _("Disk: %02dh:%02dm:%02ds"), hrs
, mins
, secs
);
1056 disk_space_label
.set_text (buf
);
1058 // An attempt to make the disk space label flash red when space has run out.
1060 if (frames
< fr
* 60 * 5) {
1061 /* disk_space_box.style ("disk_space_label_empty"); */
1063 /* disk_space_box.style ("disk_space_label"); */
1069 ARDOUR_UI::update_wall_clock ()
1076 tm_now
= localtime (&now
);
1078 sprintf (buf
, "%02d:%02d", tm_now
->tm_hour
, tm_now
->tm_min
);
1079 wall_clock_label
.set_text (buf
);
1085 ARDOUR_UI::session_menu (GdkEventButton */
*ev*/
)
1087 session_popup_menu
->popup (0, 0);
1092 ARDOUR_UI::redisplay_recent_sessions ()
1094 std::vector
<sys::path
> session_directories
;
1095 RecentSessionsSorter cmp
;
1097 recent_session_display
.set_model (Glib::RefPtr
<TreeModel
>(0));
1098 recent_session_model
->clear ();
1100 ARDOUR::RecentSessions rs
;
1101 ARDOUR::read_recent_sessions (rs
);
1104 recent_session_display
.set_model (recent_session_model
);
1108 // sort them alphabetically
1109 sort (rs
.begin(), rs
.end(), cmp
);
1111 for (ARDOUR::RecentSessions::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
1112 session_directories
.push_back ((*i
).second
);
1115 for (vector
<sys::path
>::const_iterator i
= session_directories
.begin();
1116 i
!= session_directories
.end(); ++i
)
1118 std::vector
<sys::path
> state_file_paths
;
1120 // now get available states for this session
1122 get_state_files_in_directory (*i
, state_file_paths
);
1124 vector
<string
*>* states
;
1125 vector
<const gchar
*> item
;
1126 string fullpath
= (*i
).to_string();
1128 /* remove any trailing / */
1130 if (fullpath
[fullpath
.length()-1] == '/') {
1131 fullpath
= fullpath
.substr (0, fullpath
.length()-1);
1134 /* check whether session still exists */
1135 if (!Glib::file_test(fullpath
.c_str(), Glib::FILE_TEST_EXISTS
)) {
1136 /* session doesn't exist */
1137 cerr
<< "skipping non-existent session " << fullpath
<< endl
;
1141 /* now get available states for this session */
1143 if ((states
= Session::possible_states (fullpath
)) == 0) {
1144 /* no state file? */
1148 std::vector
<string
> state_file_names(get_file_names_no_extension (state_file_paths
));
1150 Gtk::TreeModel::Row row
= *(recent_session_model
->append());
1152 row
[recent_session_columns
.visible_name
] = Glib::path_get_basename (fullpath
);
1153 row
[recent_session_columns
.fullpath
] = fullpath
;
1155 if (state_file_names
.size() > 1) {
1159 for (std::vector
<std::string
>::iterator i2
= state_file_names
.begin();
1160 i2
!= state_file_names
.end(); ++i2
)
1163 Gtk::TreeModel::Row child_row
= *(recent_session_model
->append (row
.children()));
1165 child_row
[recent_session_columns
.visible_name
] = *i2
;
1166 child_row
[recent_session_columns
.fullpath
] = fullpath
;
1171 recent_session_display
.set_model (recent_session_model
);
1175 ARDOUR_UI::build_session_selector ()
1177 session_selector_window
= new ArdourDialog (_("Recent Sessions"));
1179 Gtk::ScrolledWindow
*scroller
= manage (new Gtk::ScrolledWindow
);
1181 session_selector_window
->add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
1182 session_selector_window
->add_button (Stock::OPEN
, RESPONSE_ACCEPT
);
1183 session_selector_window
->set_default_response (RESPONSE_ACCEPT
);
1184 recent_session_model
= TreeStore::create (recent_session_columns
);
1185 recent_session_display
.set_model (recent_session_model
);
1186 recent_session_display
.append_column (_("Recent Sessions"), recent_session_columns
.visible_name
);
1187 recent_session_display
.set_headers_visible (false);
1188 recent_session_display
.get_selection()->set_mode (SELECTION_BROWSE
);
1189 recent_session_display
.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated
));
1191 scroller
->add (recent_session_display
);
1192 scroller
->set_policy (Gtk::POLICY_NEVER
, Gtk::POLICY_AUTOMATIC
);
1194 session_selector_window
->set_name ("SessionSelectorWindow");
1195 session_selector_window
->set_size_request (200, 400);
1196 session_selector_window
->get_vbox()->pack_start (*scroller
);
1198 recent_session_display
.show();
1200 //session_selector_window->get_vbox()->show();
1204 ARDOUR_UI::recent_session_row_activated (const TreePath
& /*path*/, TreeViewColumn
* /*col*/)
1206 session_selector_window
->response (RESPONSE_ACCEPT
);
1210 ARDOUR_UI::open_recent_session ()
1212 bool can_return
= (_session
!= 0);
1214 if (session_selector_window
== 0) {
1215 build_session_selector ();
1218 redisplay_recent_sessions ();
1222 session_selector_window
->set_position (WIN_POS_MOUSE
);
1224 ResponseType r
= (ResponseType
) session_selector_window
->run ();
1227 case RESPONSE_ACCEPT
:
1231 session_selector_window
->hide();
1238 if (recent_session_display
.get_selection()->count_selected_rows() == 0) {
1242 session_selector_window
->hide();
1244 Gtk::TreeModel::iterator i
= recent_session_display
.get_selection()->get_selected();
1246 if (i
== recent_session_model
->children().end()) {
1250 std::string path
= (*i
)[recent_session_columns
.fullpath
];
1251 std::string state
= (*i
)[recent_session_columns
.visible_name
];
1253 _session_is_new
= false;
1255 if (load_session (path
, state
) == 0) {
1264 ARDOUR_UI::check_audioengine ()
1267 if (!engine
->connected()) {
1268 MessageDialog
msg (string_compose (
1269 _("%1 is not connected to JACK\n"
1270 "You cannot open or close sessions in this condition"),
1283 ARDOUR_UI::open_session ()
1285 if (!check_audioengine()) {
1290 /* popup selector window */
1292 if (open_session_selector
== 0) {
1294 /* ardour sessions are folders */
1296 open_session_selector
= new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN
);
1297 open_session_selector
->add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
1298 open_session_selector
->add_button (Gtk::Stock::OPEN
, Gtk::RESPONSE_ACCEPT
);
1299 open_session_selector
->set_default_response(Gtk::RESPONSE_ACCEPT
);
1301 FileFilter session_filter
;
1302 session_filter
.add_pattern ("*.ardour");
1303 session_filter
.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME
));
1304 open_session_selector
->add_filter (session_filter
);
1305 open_session_selector
->set_filter (session_filter
);
1308 int response
= open_session_selector
->run();
1309 open_session_selector
->hide ();
1312 case RESPONSE_ACCEPT
:
1315 open_session_selector
->hide();
1319 open_session_selector
->hide();
1320 string session_path
= open_session_selector
->get_filename();
1324 if (session_path
.length() > 0) {
1325 if (ARDOUR::find_session (session_path
, path
, name
, isnew
) == 0) {
1326 _session_is_new
= isnew
;
1327 load_session (path
, name
);
1334 ARDOUR_UI::session_add_midi_route (bool disk
, RouteGroup
* route_group
, uint32_t how_many
, string
const & name_template
)
1336 list
<boost::shared_ptr
<MidiTrack
> > tracks
;
1338 if (_session
== 0) {
1339 warning
<< _("You cannot add a track without a session already loaded.") << endmsg
;
1346 tracks
= _session
->new_midi_track (ARDOUR::Normal
, route_group
, how_many
, name_template
);
1348 if (tracks
.size() != how_many
) {
1349 if (how_many
== 1) {
1350 error
<< _("could not create a new midi track") << endmsg
;
1352 error
<< string_compose (_("could not create %1 new midi tracks"), how_many
) << endmsg
;
1356 if ((route = _session->new_midi_route ()) == 0) {
1357 error << _("could not create new midi bus") << endmsg;
1363 MessageDialog
msg (*editor
,
1364 string_compose (_("There are insufficient JACK ports available\n\
1365 to create a new track or bus.\n\
1366 You should save %1, exit and\n\
1367 restart JACK with more ports."), PROGRAM_NAME
));
1374 ARDOUR_UI::session_add_audio_route (
1376 int32_t input_channels
,
1377 int32_t output_channels
,
1378 ARDOUR::TrackMode mode
,
1379 RouteGroup
* route_group
,
1381 string
const & name_template
1384 list
<boost::shared_ptr
<AudioTrack
> > tracks
;
1387 if (_session
== 0) {
1388 warning
<< _("You cannot add a track or bus without a session already loaded.") << endmsg
;
1394 tracks
= _session
->new_audio_track (input_channels
, output_channels
, mode
, route_group
, how_many
, name_template
);
1396 if (tracks
.size() != how_many
) {
1397 if (how_many
== 1) {
1398 error
<< _("could not create a new audio track") << endmsg
;
1400 error
<< string_compose (_("could only create %1 of %2 new audio %3"),
1401 tracks
.size(), how_many
, (track
? _("tracks") : _("busses"))) << endmsg
;
1407 routes
= _session
->new_audio_route (input_channels
, output_channels
, route_group
, how_many
, name_template
);
1409 if (routes
.size() != how_many
) {
1410 if (how_many
== 1) {
1411 error
<< _("could not create a new audio track") << endmsg
;
1413 error
<< string_compose (_("could not create %1 new audio tracks"), how_many
) << endmsg
;
1420 MessageDialog
msg (*editor
,
1421 string_compose (_("There are insufficient JACK ports available\n\
1422 to create a new track or bus.\n\
1423 You should save %1, exit and\n\
1424 restart JACK with more ports."), PROGRAM_NAME
));
1431 ARDOUR_UI::do_transport_locate (framepos_t new_position
, bool with_roll
)
1433 framecnt_t _preroll
= 0;
1436 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1437 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1439 if (new_position
> _preroll
) {
1440 new_position
-= _preroll
;
1445 _session
->request_locate (new_position
, with_roll
);
1450 ARDOUR_UI::transport_goto_start ()
1453 _session
->goto_start();
1455 /* force displayed area in editor to start no matter
1456 what "follow playhead" setting is.
1460 editor
->center_screen (_session
->current_start_frame ());
1466 ARDOUR_UI::transport_goto_zero ()
1469 _session
->request_locate (0);
1471 /* force displayed area in editor to start no matter
1472 what "follow playhead" setting is.
1476 editor
->reset_x_origin (0);
1482 ARDOUR_UI::transport_goto_wallclock ()
1484 if (_session
&& editor
) {
1491 localtime_r (&now
, &tmnow
);
1493 frames
= tmnow
.tm_hour
* (60 * 60 * _session
->frame_rate());
1494 frames
+= tmnow
.tm_min
* (60 * _session
->frame_rate());
1495 frames
+= tmnow
.tm_sec
* _session
->frame_rate();
1497 _session
->request_locate (frames
, _session
->transport_rolling ());
1499 /* force displayed area in editor to start no matter
1500 what "follow playhead" setting is.
1504 editor
->center_screen (frames
);
1510 ARDOUR_UI::transport_goto_end ()
1513 framepos_t
const frame
= _session
->current_end_frame();
1514 _session
->request_locate (frame
);
1516 /* force displayed area in editor to start no matter
1517 what "follow playhead" setting is.
1521 editor
->center_screen (frame
);
1527 ARDOUR_UI::transport_stop ()
1533 if (_session
->is_auditioning()) {
1534 _session
->cancel_audition ();
1538 _session
->request_stop (false, true);
1542 ARDOUR_UI::transport_stop_and_forget_capture ()
1545 _session
->request_stop (true, true);
1550 ARDOUR_UI::remove_last_capture()
1553 editor
->remove_last_capture();
1558 ARDOUR_UI::transport_record (bool roll
)
1562 switch (_session
->record_status()) {
1563 case Session::Disabled
:
1564 if (_session
->ntracks() == 0) {
1565 MessageDialog
msg (*editor
, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1569 _session
->maybe_enable_record ();
1574 case Session::Recording
:
1576 _session
->request_stop();
1578 _session
->disable_record (false, true);
1582 case Session::Enabled
:
1583 _session
->disable_record (false, true);
1586 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1590 ARDOUR_UI::transport_roll ()
1596 if (_session
->is_auditioning()) {
1601 if (_session
->config
.get_external_sync()) {
1602 switch (_session
->config
.get_sync_source()) {
1606 /* transport controlled by the master */
1612 bool rolling
= _session
->transport_rolling();
1614 if (_session
->get_play_loop()) {
1615 /* XXX it is not possible to just leave seamless loop and keep
1616 playing at present (nov 4th 2009)
1618 if (!Config
->get_seamless_loop()) {
1619 _session
->request_play_loop (false, true);
1621 } else if (_session
->get_play_range () && !join_play_range_button
.get_active()) {
1622 /* stop playing a range if we currently are */
1623 _session
->request_play_range (0, true);
1626 if (join_play_range_button
.get_active()) {
1627 _session
->request_play_range (&editor
->get_selection().time
, true);
1631 _session
->request_transport_speed (1.0f
);
1636 ARDOUR_UI::toggle_roll (bool with_abort
, bool roll_out_of_bounded_mode
)
1643 if (_session
->is_auditioning()) {
1644 _session
->cancel_audition ();
1648 if (_session
->config
.get_external_sync()) {
1649 switch (_session
->config
.get_sync_source()) {
1653 /* transport controlled by the master */
1658 bool rolling
= _session
->transport_rolling();
1659 bool affect_transport
= true;
1661 if (rolling
&& roll_out_of_bounded_mode
) {
1662 /* drop out of loop/range playback but leave transport rolling */
1663 if (_session
->get_play_loop()) {
1664 if (Config
->get_seamless_loop()) {
1665 /* the disk buffers contain copies of the loop - we can't
1666 just keep playing, so stop the transport. the user
1667 can restart as they wish.
1669 affect_transport
= true;
1671 /* disk buffers are normal, so we can keep playing */
1672 affect_transport
= false;
1674 _session
->request_play_loop (false, true);
1675 } else if (_session
->get_play_range ()) {
1676 affect_transport
= false;
1677 _session
->request_play_range (0, true);
1681 if (affect_transport
) {
1683 _session
->request_stop (with_abort
, true);
1685 if (join_play_range_button
.get_active()) {
1686 _session
->request_play_range (&editor
->get_selection().time
, true);
1689 _session
->request_transport_speed (1.0f
);
1695 ARDOUR_UI::toggle_session_auto_loop ()
1701 if (_session
->get_play_loop()) {
1703 if (_session
->transport_rolling()) {
1705 Location
* looploc
= _session
->locations()->auto_loop_location();
1708 _session
->request_locate (looploc
->start(), true);
1709 _session
->request_play_loop (false);
1713 _session
->request_play_loop (false);
1717 Location
* looploc
= _session
->locations()->auto_loop_location();
1720 _session
->request_play_loop (true);
1726 ARDOUR_UI::transport_play_selection ()
1732 editor
->play_selection ();
1736 ARDOUR_UI::transport_rewind (int option
)
1738 float current_transport_speed
;
1741 current_transport_speed
= _session
->transport_speed();
1743 if (current_transport_speed
>= 0.0f
) {
1746 _session
->request_transport_speed (-1.0f
);
1749 _session
->request_transport_speed (-4.0f
);
1752 _session
->request_transport_speed (-0.5f
);
1757 _session
->request_transport_speed (current_transport_speed
* 1.5f
);
1763 ARDOUR_UI::transport_forward (int option
)
1765 float current_transport_speed
;
1768 current_transport_speed
= _session
->transport_speed();
1770 if (current_transport_speed
<= 0.0f
) {
1773 _session
->request_transport_speed (1.0f
);
1776 _session
->request_transport_speed (4.0f
);
1779 _session
->request_transport_speed (0.5f
);
1784 _session
->request_transport_speed (current_transport_speed
* 1.5f
);
1791 ARDOUR_UI::toggle_record_enable (uint32_t rid
)
1793 if (_session
== 0) {
1797 boost::shared_ptr
<Route
> r
;
1799 if ((r
= _session
->route_by_remote_id (rid
)) != 0) {
1803 if ((t
= dynamic_cast<Track
*>(r
.get())) != 0) {
1804 t
->set_record_enabled (!t
->record_enabled(), this);
1807 if (_session
== 0) {
1813 ARDOUR_UI::map_transport_state ()
1816 auto_loop_button
.set_visual_state (0);
1817 play_selection_button
.set_visual_state (0);
1818 roll_button
.set_visual_state (0);
1819 stop_button
.set_visual_state (1);
1823 shuttle_box
->map_transport_state ();
1825 float sp
= _session
->transport_speed();
1831 if (_session
->get_play_range()) {
1833 play_selection_button
.set_visual_state (1);
1834 roll_button
.set_visual_state (0);
1835 auto_loop_button
.set_visual_state (0);
1837 } else if (_session
->get_play_loop ()) {
1839 auto_loop_button
.set_visual_state (1);
1840 play_selection_button
.set_visual_state (0);
1841 roll_button
.set_visual_state (0);
1845 roll_button
.set_visual_state (1);
1846 play_selection_button
.set_visual_state (0);
1847 auto_loop_button
.set_visual_state (0);
1850 if (join_play_range_button
.get_active()) {
1851 /* light up both roll and play-selection if they are joined */
1852 roll_button
.set_visual_state (1);
1853 play_selection_button
.set_visual_state (1);
1856 stop_button
.set_visual_state (0);
1860 stop_button
.set_visual_state (1);
1861 roll_button
.set_visual_state (0);
1862 play_selection_button
.set_visual_state (0);
1863 auto_loop_button
.set_visual_state (0);
1864 update_disk_space ();
1869 ARDOUR_UI::engine_stopped ()
1871 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped
)
1872 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, false);
1873 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, true);
1877 ARDOUR_UI::engine_running ()
1879 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running
)
1880 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, true);
1881 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, false);
1883 Glib::RefPtr
<Action
> action
;
1884 const char* action_name
= 0;
1886 switch (engine
->frames_per_cycle()) {
1888 action_name
= X_("JACKLatency32");
1891 action_name
= X_("JACKLatency64");
1894 action_name
= X_("JACKLatency128");
1897 action_name
= X_("JACKLatency512");
1900 action_name
= X_("JACKLatency1024");
1903 action_name
= X_("JACKLatency2048");
1906 action_name
= X_("JACKLatency4096");
1909 action_name
= X_("JACKLatency8192");
1912 /* XXX can we do anything useful ? */
1918 action
= ActionManager::get_action (X_("JACK"), action_name
);
1921 Glib::RefPtr
<RadioAction
> ract
= Glib::RefPtr
<RadioAction
>::cast_dynamic (action
);
1922 ract
->set_active ();
1928 ARDOUR_UI::engine_halted (const char* reason
, bool free_reason
)
1930 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1931 /* we can't rely on the original string continuing to exist when we are called
1932 again in the GUI thread, so make a copy and note that we need to
1935 char *copy
= strdup (reason
);
1936 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted
, this, copy
, true));
1940 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, false);
1941 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, true);
1943 update_sample_rate (0);
1947 /* if the reason is a non-empty string, it means that the backend was shutdown
1948 rather than just Ardour.
1951 if (strlen (reason
)) {
1952 msgstr
= string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason
);
1954 msgstr
= string_compose (_("\
1955 JACK has either been shutdown or it\n\
1956 disconnected %1 because %1\n\
1957 was not fast enough. Try to restart\n\
1958 JACK, reconnect and save the session."), PROGRAM_NAME
);
1961 MessageDialog
msg (*editor
, msgstr
);
1966 free ((char*) reason
);
1971 ARDOUR_UI::do_engine_start ()
1979 error
<< _("Unable to start the session running")
1989 ARDOUR_UI::setup_theme ()
1991 theme_manager
->setup_theme();
1995 ARDOUR_UI::update_clocks ()
1997 if (!editor
|| !editor
->dragging_playhead()) {
1998 Clock (_session
->audible_frame(), false, editor
->get_preferred_edit_position()); /* EMIT_SIGNAL */
2003 ARDOUR_UI::start_clocking ()
2005 clock_signal_connection
= RapidScreenUpdate
.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks
));
2009 ARDOUR_UI::stop_clocking ()
2011 clock_signal_connection
.disconnect ();
2015 ARDOUR_UI::toggle_clocking ()
2018 if (clock_button
.get_active()) {
2027 ARDOUR_UI::_blink (void *arg
)
2030 ((ARDOUR_UI
*) arg
)->blink ();
2037 Blink (blink_on
= !blink_on
); /* EMIT_SIGNAL */
2041 ARDOUR_UI::start_blinking ()
2043 /* Start the blink signal. Everybody with a blinking widget
2044 uses Blink to drive the widget's state.
2047 if (blink_timeout_tag
< 0) {
2049 blink_timeout_tag
= g_timeout_add (240, _blink
, this);
2054 ARDOUR_UI::stop_blinking ()
2056 if (blink_timeout_tag
>= 0) {
2057 g_source_remove (blink_timeout_tag
);
2058 blink_timeout_tag
= -1;
2063 /** Ask the user for the name of a new shapshot and then take it.
2067 ARDOUR_UI::snapshot_session (bool switch_to_it
)
2069 ArdourPrompter
prompter (true);
2072 prompter
.set_name ("Prompter");
2073 prompter
.add_button (Gtk::Stock::SAVE
, Gtk::RESPONSE_ACCEPT
);
2074 prompter
.set_title (_("Take Snapshot"));
2075 prompter
.set_title (_("Take Snapshot"));
2076 prompter
.set_prompt (_("Name of new snapshot"));
2078 if (!switch_to_it
) {
2081 struct tm local_time
;
2084 localtime_r (&n
, &local_time
);
2085 strftime (timebuf
, sizeof(timebuf
), "%FT%T", &local_time
);
2086 prompter
.set_initial_text (timebuf
);
2090 switch (prompter
.run()) {
2091 case RESPONSE_ACCEPT
:
2093 prompter
.get_result (snapname
);
2095 bool do_save
= (snapname
.length() != 0);
2098 if (snapname
.find ('/') != string::npos
) {
2099 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2100 "snapshot names may not contain a '/' character"));
2104 if (snapname
.find ('\\') != string::npos
) {
2105 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2106 "snapshot names may not contain a '\\' character"));
2112 vector
<sys::path
> p
;
2113 get_state_files_in_directory (_session
->session_directory().root_path(), p
);
2114 vector
<string
> n
= get_file_names_no_extension (p
);
2115 if (find (n
.begin(), n
.end(), snapname
) != n
.end()) {
2117 ArdourDialog
confirm (_("Confirm Snapshot Overwrite"), true);
2118 Label
m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2119 confirm
.get_vbox()->pack_start (m
, true, true);
2120 confirm
.add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
2121 confirm
.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT
);
2122 confirm
.show_all ();
2123 switch (confirm
.run()) {
2124 case RESPONSE_CANCEL
:
2130 save_state (snapname
, switch_to_it
);
2141 ARDOUR_UI::save_state (const string
& name
, bool switch_to_it
)
2143 XMLNode
* node
= new XMLNode (X_("UI"));
2145 for (list
<WindowProxyBase
*>::iterator i
= _window_proxies
.begin(); i
!= _window_proxies
.end(); ++i
) {
2146 if (!(*i
)->rc_configured()) {
2147 node
->add_child_nocopy (*((*i
)->get_state ()));
2151 _session
->add_extra_xml (*node
);
2153 save_state_canfail (name
, switch_to_it
);
2157 ARDOUR_UI::save_state_canfail (string name
, bool switch_to_it
)
2162 if (name
.length() == 0) {
2163 name
= _session
->snap_name();
2166 if ((ret
= _session
->save_state (name
, false, switch_to_it
)) != 0) {
2171 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2176 ARDOUR_UI::primary_clock_value_changed ()
2179 _session
->request_locate (primary_clock
->current_time ());
2184 ARDOUR_UI::big_clock_value_changed ()
2187 _session
->request_locate (big_clock
->current_time ());
2192 ARDOUR_UI::secondary_clock_value_changed ()
2195 _session
->request_locate (secondary_clock
->current_time ());
2200 ARDOUR_UI::transport_rec_enable_blink (bool onoff
)
2202 if (_session
== 0) {
2206 if (_session
->step_editing()) {
2210 Session::RecordState
const r
= _session
->record_status ();
2211 bool const h
= _session
->have_rec_enabled_track ();
2213 if (r
== Session::Enabled
|| (r
== Session::Recording
&& !h
)) {
2215 rec_button
.set_visual_state (2);
2217 rec_button
.set_visual_state (0);
2219 } else if (r
== Session::Recording
&& h
) {
2220 rec_button
.set_visual_state (1);
2222 rec_button
.set_visual_state (0);
2227 ARDOUR_UI::save_template ()
2229 ArdourPrompter
prompter (true);
2232 if (!check_audioengine()) {
2236 prompter
.set_name (X_("Prompter"));
2237 prompter
.set_title (_("Save Template"));
2238 prompter
.set_prompt (_("Name for template:"));
2239 prompter
.set_initial_text(_session
->name() + _("-template"));
2240 prompter
.add_button (Gtk::Stock::SAVE
, Gtk::RESPONSE_ACCEPT
);
2242 switch (prompter
.run()) {
2243 case RESPONSE_ACCEPT
:
2244 prompter
.get_result (name
);
2246 if (name
.length()) {
2247 _session
->save_template (name
);
2257 ARDOUR_UI::edit_metadata ()
2259 SessionMetadataEditor dialog
;
2260 dialog
.set_session (_session
);
2261 editor
->ensure_float (dialog
);
2266 ARDOUR_UI::import_metadata ()
2268 SessionMetadataImporter dialog
;
2269 dialog
.set_session (_session
);
2270 editor
->ensure_float (dialog
);
2275 ARDOUR_UI::ask_about_loading_existing_session (const std::string
& session_path
)
2277 std::string str
= string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path
);
2279 MessageDialog
msg (str
,
2281 Gtk::MESSAGE_WARNING
,
2282 Gtk::BUTTONS_YES_NO
,
2286 msg
.set_name (X_("OpenExistingDialog"));
2287 msg
.set_title (_("Open Existing Session"));
2288 msg
.set_wmclass (X_("existing_session"), PROGRAM_NAME
);
2289 msg
.set_position (Gtk::WIN_POS_MOUSE
);
2292 switch (msg
.run()) {
2301 ARDOUR_UI::build_session_from_nsd (const std::string
& session_path
, const std::string
& session_name
)
2303 BusProfile bus_profile
;
2305 if (Profile
->get_sae()) {
2307 bus_profile
.master_out_channels
= 2;
2308 bus_profile
.input_ac
= AutoConnectPhysical
;
2309 bus_profile
.output_ac
= AutoConnectMaster
;
2310 bus_profile
.requested_physical_in
= 0; // use all available
2311 bus_profile
.requested_physical_out
= 0; // use all available
2315 /* get settings from advanced section of NSD */
2317 if (_startup
->create_master_bus()) {
2318 bus_profile
.master_out_channels
= (uint32_t) _startup
->master_channel_count();
2320 bus_profile
.master_out_channels
= 0;
2323 if (_startup
->connect_inputs()) {
2324 bus_profile
.input_ac
= AutoConnectPhysical
;
2326 bus_profile
.input_ac
= AutoConnectOption (0);
2329 /// @todo some minor tweaks.
2331 bus_profile
.output_ac
= AutoConnectOption (0);
2333 if (_startup
->connect_outputs ()) {
2334 if (_startup
->connect_outs_to_master()) {
2335 bus_profile
.output_ac
= AutoConnectMaster
;
2336 } else if (_startup
->connect_outs_to_physical()) {
2337 bus_profile
.output_ac
= AutoConnectPhysical
;
2341 bus_profile
.requested_physical_in
= (uint32_t) _startup
->input_limit_count();
2342 bus_profile
.requested_physical_out
= (uint32_t) _startup
->output_limit_count();
2345 if (build_session (session_path
, session_name
, bus_profile
)) {
2353 ARDOUR_UI::idle_load (const std::string
& path
)
2356 if (Glib::file_test (path
, Glib::FILE_TEST_IS_DIR
)) {
2357 /* /path/to/foo => /path/to/foo, foo */
2358 load_session (path
, basename_nosuffix (path
));
2360 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2361 load_session (Glib::path_get_dirname (path
), basename_nosuffix (path
));
2365 ARDOUR_COMMAND_LINE::session_name
= path
;
2368 * new_session_dialog doens't exist in A3
2369 * Try to remove all references to it to
2370 * see if it will compile. NOTE: this will
2371 * likely cause a runtime issue is my somewhat
2375 //if (new_session_dialog) {
2378 /* make it break out of Dialog::run() and
2382 //new_session_dialog->response (1);
2388 ARDOUR_UI::end_loading_messages ()
2394 ARDOUR_UI::loading_message (const std::string
& /*msg*/)
2397 // splash->message (msg);
2401 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2403 ARDOUR_UI::get_session_parameters (bool quit_on_cancel
, bool should_be_new
, string load_template
)
2405 string session_name
;
2406 string session_path
;
2407 string template_name
;
2409 bool likely_new
= false;
2411 if (!load_template
.empty()) {
2412 should_be_new
= true;
2413 template_name
= load_template
;
2418 if (!should_be_new
&& !ARDOUR_COMMAND_LINE::session_name
.empty()) {
2420 /* if they named a specific statefile, use it, otherwise they are
2421 just giving a session folder, and we want to use it as is
2422 to find the session.
2425 string::size_type suffix
= ARDOUR_COMMAND_LINE::session_name
.find (statefile_suffix
);
2427 if (suffix
!= string::npos
) {
2428 session_path
= Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name
);
2429 session_name
= ARDOUR_COMMAND_LINE::session_name
.substr (0, suffix
);
2430 session_name
= Glib::path_get_basename (session_name
);
2432 session_path
= ARDOUR_COMMAND_LINE::session_name
;
2433 session_name
= Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name
);
2438 bool const apply
= run_startup (should_be_new
, load_template
);
2441 if (quit_on_cancel
) {
2448 /* if we run the startup dialog again, offer more than just "new session" */
2450 should_be_new
= false;
2452 session_name
= _startup
->session_name (likely_new
);
2454 /* this shouldn't happen, but we catch it just in case it does */
2456 if (session_name
.empty()) {
2460 if (_startup
->use_session_template()) {
2461 template_name
= _startup
->session_template_name();
2462 _session_is_new
= true;
2465 if (session_name
[0] == G_DIR_SEPARATOR
||
2466 (session_name
.length() > 2 && session_name
[0] == '.' && session_name
[1] == G_DIR_SEPARATOR
) ||
2467 (session_name
.length() > 3 && session_name
[0] == '.' && session_name
[1] == '.' && session_name
[2] == G_DIR_SEPARATOR
)) {
2469 /* absolute path or cwd-relative path specified for session name: infer session folder
2470 from what was given.
2473 session_path
= Glib::path_get_dirname (session_name
);
2474 session_name
= Glib::path_get_basename (session_name
);
2478 session_path
= _startup
->session_folder();
2480 if (session_name
.find ('/') != string::npos
) {
2481 MessageDialog
msg (*_startup
,
2482 _("To ensure compatibility with various systems\n"
2483 "session names may not contain a '/' character"));
2485 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2489 if (session_name
.find ('\\') != string::npos
) {
2490 MessageDialog
msg (*_startup
,
2491 _("To ensure compatibility with various systems\n"
2492 "session names may not contain a '\\' character"));
2494 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2500 if (create_engine ()) {
2504 if (Glib::file_test (session_path
, Glib::FileTest (G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_DIR
))) {
2508 std::string existing
= Glib::build_filename (session_path
, session_name
);
2510 if (!ask_about_loading_existing_session (existing
)) {
2511 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2516 _session_is_new
= false;
2521 MessageDialog
msg (string_compose (_("There is no existing session at \"%1\""), session_path
));
2523 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2527 if (session_name
.find ('/') != std::string::npos
) {
2528 MessageDialog
msg (*_startup
,
2529 _("To ensure compatibility with various systems\n"
2530 "session names may not contain a '/' character"));
2532 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2536 if (session_name
.find ('\\') != std::string::npos
) {
2537 MessageDialog
msg (*_startup
,
2538 _("To ensure compatibility with various systems\n"
2539 "session names may not contain a '\\' character"));
2541 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2545 _session_is_new
= true;
2548 if (likely_new
&& template_name
.empty()) {
2550 ret
= build_session_from_nsd (session_path
, session_name
);
2554 ret
= load_session (session_path
, session_name
, template_name
);
2557 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2561 if (!ARDOUR_COMMAND_LINE::immediate_save
.empty()) {
2562 _session
->save_state (ARDOUR_COMMAND_LINE::immediate_save
, false);
2572 ARDOUR_UI::close_session()
2574 if (!check_audioengine()) {
2578 if (unload_session (true)) {
2582 ARDOUR_COMMAND_LINE::session_name
= "";
2584 if (get_session_parameters (true, false)) {
2588 goto_editor_window ();
2591 /** @param snap_name Snapshot name (without .ardour suffix).
2592 * @return -2 if the load failed because we are not connected to the AudioEngine.
2595 ARDOUR_UI::load_session (const std::string
& path
, const std::string
& snap_name
, std::string mix_template
)
2597 Session
*new_session
;
2601 session_loaded
= false;
2603 if (!check_audioengine()) {
2607 unload_status
= unload_session ();
2609 if (unload_status
< 0) {
2611 } else if (unload_status
> 0) {
2616 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME
));
2619 new_session
= new Session (*engine
, path
, snap_name
, 0, mix_template
);
2622 /* this one is special */
2624 catch (AudioEngine::PortRegistrationFailure
& err
) {
2626 MessageDialog
msg (err
.what(),
2629 Gtk::BUTTONS_CLOSE
);
2631 msg
.set_title (_("Port Registration Error"));
2632 msg
.set_secondary_text (_("Click the Close button to try again."));
2633 msg
.set_position (Gtk::WIN_POS_CENTER
);
2637 int response
= msg
.run ();
2642 case RESPONSE_CANCEL
:
2652 MessageDialog
msg (string_compose(
2653 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2659 msg
.set_title (_("Loading Error"));
2660 msg
.set_secondary_text (_("Click the Refresh button to try again."));
2661 msg
.add_button (Stock::REFRESH
, 1);
2662 msg
.set_position (Gtk::WIN_POS_CENTER
);
2666 int response
= msg
.run ();
2681 list
<string
> const u
= new_session
->unknown_processors ();
2683 MissingPluginDialog
d (_session
, u
);
2688 /* Now the session been created, add the transport controls */
2689 new_session
->add_controllable(roll_controllable
);
2690 new_session
->add_controllable(stop_controllable
);
2691 new_session
->add_controllable(goto_start_controllable
);
2692 new_session
->add_controllable(goto_end_controllable
);
2693 new_session
->add_controllable(auto_loop_controllable
);
2694 new_session
->add_controllable(play_selection_controllable
);
2695 new_session
->add_controllable(rec_controllable
);
2697 set_session (new_session
);
2699 session_loaded
= true;
2701 goto_editor_window ();
2704 _session
->set_clean ();
2715 ARDOUR_UI::build_session (const std::string
& path
, const std::string
& snap_name
, BusProfile
& bus_profile
)
2717 Session
*new_session
;
2720 if (!check_audioengine()) {
2724 session_loaded
= false;
2726 x
= unload_session ();
2734 _session_is_new
= true;
2737 new_session
= new Session (*engine
, path
, snap_name
, &bus_profile
);
2742 MessageDialog
msg (string_compose(_("Could not create session in \"%1\""), path
));
2748 /* Give the new session the default GUI state, if such things exist */
2751 n
= Config
->instant_xml (X_("Editor"));
2753 new_session
->add_instant_xml (*n
, false);
2755 n
= Config
->instant_xml (X_("Mixer"));
2757 new_session
->add_instant_xml (*n
, false);
2760 /* Put the playhead at 0 and scroll fully left */
2761 n
= new_session
->instant_xml (X_("Editor"));
2763 n
->add_property (X_("playhead"), X_("0"));
2764 n
->add_property (X_("left-frame"), X_("0"));
2767 set_session (new_session
);
2769 session_loaded
= true;
2771 new_session
->save_state(new_session
->name());
2777 ARDOUR_UI::launch_chat ()
2780 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2782 open_uri("http://webchat.freenode.net/?channels=ardour");
2787 ARDOUR_UI::show_about ()
2791 about
->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response
) );
2794 about
->set_transient_for(*editor
);
2799 ARDOUR_UI::launch_manual ()
2801 PBD::open_uri("http://ardour.org/flossmanual");
2805 ARDOUR_UI::launch_reference ()
2807 PBD::open_uri("http://ardour.org/refmanual");
2811 ARDOUR_UI::hide_about ()
2814 about
->get_window()->set_cursor ();
2820 ARDOUR_UI::about_signal_response (int /*response*/)
2826 ARDOUR_UI::show_splash ()
2830 splash
= new Splash
;
2838 splash
->queue_draw ();
2839 splash
->get_window()->process_updates (true);
2844 ARDOUR_UI::hide_splash ()
2852 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport
& rep
, const gchar
* list_title
,
2853 const string
& plural_msg
, const string
& singular_msg
)
2857 removed
= rep
.paths
.size();
2860 MessageDialog
msgd (*editor
,
2861 _("No files were ready for clean-up"),
2864 (Gtk::ButtonsType
)(Gtk::BUTTONS_OK
) );
2865 msgd
.set_title (_("Clean-up"));
2866 msgd
.set_secondary_text (_("If this seems suprising, \n\
2867 check for any existing snapshots.\n\
2868 These may still include regions that\n\
2869 require some unused files to continue to exist."));
2875 ArdourDialog
results (_("Clean-up"), true, false);
2877 struct CleanupResultsModelColumns
: public Gtk::TreeModel::ColumnRecord
{
2878 CleanupResultsModelColumns() {
2882 Gtk::TreeModelColumn
<std::string
> visible_name
;
2883 Gtk::TreeModelColumn
<std::string
> fullpath
;
2887 CleanupResultsModelColumns results_columns
;
2888 Glib::RefPtr
<Gtk::ListStore
> results_model
;
2889 Gtk::TreeView results_display
;
2891 results_model
= ListStore::create (results_columns
);
2892 results_display
.set_model (results_model
);
2893 results_display
.append_column (list_title
, results_columns
.visible_name
);
2895 results_display
.set_name ("CleanupResultsList");
2896 results_display
.set_headers_visible (true);
2897 results_display
.set_headers_clickable (false);
2898 results_display
.set_reorderable (false);
2900 Gtk::ScrolledWindow list_scroller
;
2903 Gtk::HBox dhbox
; // the hbox for the image and text
2904 Gtk::HBox ddhbox
; // the hbox we eventually pack into the dialog's vbox
2905 Gtk::Image
* dimage
= manage (new Gtk::Image(Stock::DIALOG_INFO
, Gtk::ICON_SIZE_DIALOG
));
2907 dimage
->set_alignment(ALIGN_LEFT
, ALIGN_TOP
);
2909 const string dead_directory
= _session
->session_directory().dead_path().to_string();
2912 %1 - number of files removed
2913 %2 - location of "dead"
2914 %3 - size of files affected
2915 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2918 const char* bprefix
;
2919 double space_adjusted
= 0;
2921 if (rep
.space
< 1000) {
2923 space_adjusted
= rep
.space
;
2924 } else if (rep
.space
< 1000000) {
2925 bprefix
= X_("kilo");
2926 space_adjusted
= truncf((float)rep
.space
/ 1000.0);
2927 } else if (rep
.space
< 1000000 * 1000) {
2928 bprefix
= X_("mega");
2929 space_adjusted
= truncf((float)rep
.space
/ (1000.0 * 1000.0));
2931 bprefix
= X_("giga");
2932 space_adjusted
= truncf((float)rep
.space
/ (1000.0 * 1000 * 1000.0));
2936 txt
.set_text (string_compose (plural_msg
, removed
, dead_directory
, space_adjusted
, bprefix
));
2938 txt
.set_text (string_compose (singular_msg
, removed
, dead_directory
, space_adjusted
, bprefix
));
2941 dhbox
.pack_start (*dimage
, true, false, 5);
2942 dhbox
.pack_start (txt
, true, false, 5);
2944 for (vector
<string
>::iterator i
= rep
.paths
.begin(); i
!= rep
.paths
.end(); ++i
) {
2945 TreeModel::Row row
= *(results_model
->append());
2946 row
[results_columns
.visible_name
] = *i
;
2947 row
[results_columns
.fullpath
] = *i
;
2950 list_scroller
.add (results_display
);
2951 list_scroller
.set_size_request (-1, 150);
2952 list_scroller
.set_policy (Gtk::POLICY_NEVER
, Gtk::POLICY_AUTOMATIC
);
2954 dvbox
.pack_start (dhbox
, true, false, 5);
2955 dvbox
.pack_start (list_scroller
, true, false, 5);
2956 ddhbox
.pack_start (dvbox
, true, false, 5);
2958 results
.get_vbox()->pack_start (ddhbox
, true, false, 5);
2959 results
.add_button (Stock::CLOSE
, RESPONSE_CLOSE
);
2960 results
.set_default_response (RESPONSE_CLOSE
);
2961 results
.set_position (Gtk::WIN_POS_MOUSE
);
2963 results_display
.show();
2964 list_scroller
.show();
2971 //results.get_vbox()->show();
2972 results
.set_resizable (false);
2979 ARDOUR_UI::cleanup ()
2981 if (_session
== 0) {
2982 /* shouldn't happen: menu item is insensitive */
2987 MessageDialog
checker (_("Are you sure you want to clean-up?"),
2989 Gtk::MESSAGE_QUESTION
,
2990 (Gtk::ButtonsType
)(Gtk::BUTTONS_NONE
));
2992 checker
.set_title (_("Clean-up"));
2994 checker
.set_secondary_text(_("Clean-up is a destructive operation.\n\
2995 ALL undo/redo information will be lost if you clean-up.\n\
2996 Clean-up will move all unused files to a \"dead\" location."));
2998 checker
.add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
2999 checker
.add_button (_("Clean-up"), RESPONSE_ACCEPT
);
3000 checker
.set_default_response (RESPONSE_CANCEL
);
3002 checker
.set_name (_("CleanupDialog"));
3003 checker
.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME
);
3004 checker
.set_position (Gtk::WIN_POS_MOUSE
);
3006 switch (checker
.run()) {
3007 case RESPONSE_ACCEPT
:
3013 ARDOUR::CleanupReport rep
;
3015 editor
->prepare_for_cleanup ();
3017 /* do not allow flush until a session is reloaded */
3019 Glib::RefPtr
<Action
> act
= ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3021 act
->set_sensitive (false);
3024 if (_session
->cleanup_sources (rep
)) {
3025 editor
->finish_cleanup ();
3029 editor
->finish_cleanup ();
3032 display_cleanup_results (rep
,
3035 The following %1 files were not in use and \n\
3036 have been moved to:\n\n\
3038 After a restart of Ardour,\n\n\
3039 Session -> Clean-up -> Flush Wastebasket\n\n\
3040 will release an additional\n\
3041 %3 %4bytes of disk space.\n"),
3043 The following file was not in use and \n\
3044 has been moved to:\n \
3046 After a restart of Ardour,\n\n\
3047 Session -> Clean-up -> Flush Wastebasket\n\n\
3048 will release an additional\n\
3049 %3 %4bytes of disk space.\n"
3055 ARDOUR_UI::flush_trash ()
3057 if (_session
== 0) {
3058 /* shouldn't happen: menu item is insensitive */
3062 ARDOUR::CleanupReport rep
;
3064 if (_session
->cleanup_trash_sources (rep
)) {
3068 display_cleanup_results (rep
,
3070 _("The following %1 files were deleted from\n\
3072 releasing %3 %4bytes of disk space"),
3073 _("The following file was deleted from\n\
3075 releasing %3 %4bytes of disk space"));
3079 ARDOUR_UI::add_route (Gtk::Window
* float_window
)
3087 if (add_route_dialog
== 0) {
3088 add_route_dialog
= new AddRouteDialog (_session
);
3090 add_route_dialog
->set_transient_for (*float_window
);
3094 if (add_route_dialog
->is_visible()) {
3095 /* we're already doing this */
3099 ResponseType r
= (ResponseType
) add_route_dialog
->run ();
3101 add_route_dialog
->hide();
3104 case RESPONSE_ACCEPT
:
3111 if ((count
= add_route_dialog
->count()) <= 0) {
3115 string template_path
= add_route_dialog
->track_template();
3117 if (!template_path
.empty()) {
3118 _session
->new_route_from_template (count
, template_path
);
3122 uint32_t input_chan
= add_route_dialog
->channels ();
3123 uint32_t output_chan
;
3124 string name_template
= add_route_dialog
->name_template ();
3125 bool track
= add_route_dialog
->track ();
3126 RouteGroup
* route_group
= add_route_dialog
->route_group ();
3128 AutoConnectOption oac
= Config
->get_output_auto_connect();
3130 if (oac
& AutoConnectMaster
) {
3131 output_chan
= (_session
->master_out() ? _session
->master_out()->n_inputs().n_audio() : input_chan
);
3133 output_chan
= input_chan
;
3136 /* XXX do something with name template */
3138 if (add_route_dialog
->type() == ARDOUR::DataType::MIDI
) {
3140 session_add_midi_track (route_group
, count
, name_template
);
3142 MessageDialog
msg (*editor
,
3143 _("Sorry, MIDI Busses are not supported at this time."));
3145 //session_add_midi_bus();
3149 session_add_audio_track (input_chan
, output_chan
, add_route_dialog
->mode(), route_group
, count
, name_template
);
3151 session_add_audio_bus (input_chan
, output_chan
, route_group
, count
, name_template
);
3157 ARDOUR_UI::mixer_settings () const
3162 node
= _session
->instant_xml(X_("Mixer"));
3164 node
= Config
->instant_xml(X_("Mixer"));
3168 node
= new XMLNode (X_("Mixer"));
3175 ARDOUR_UI::editor_settings () const
3180 node
= _session
->instant_xml(X_("Editor"));
3182 node
= Config
->instant_xml(X_("Editor"));
3186 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3187 node
= Config
->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3192 node
= new XMLNode (X_("Editor"));
3199 ARDOUR_UI::keyboard_settings () const
3203 node
= Config
->extra_xml(X_("Keyboard"));
3206 node
= new XMLNode (X_("Keyboard"));
3213 ARDOUR_UI::create_xrun_marker (framepos_t where
)
3215 editor
->mouse_add_new_marker (where
, false, true);
3219 ARDOUR_UI::halt_on_xrun_message ()
3221 MessageDialog
msg (*editor
,
3222 _("Recording was stopped because your system could not keep up."));
3227 ARDOUR_UI::xrun_handler (framepos_t where
)
3233 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler
, where
)
3235 if (_session
&& Config
->get_create_xrun_marker() && _session
->actively_recording()) {
3236 create_xrun_marker(where
);
3239 if (_session
&& Config
->get_stop_recording_on_xrun() && _session
->actively_recording()) {
3240 halt_on_xrun_message ();
3245 ARDOUR_UI::disk_overrun_handler ()
3247 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler
)
3249 if (!have_disk_speed_dialog_displayed
) {
3250 have_disk_speed_dialog_displayed
= true;
3251 MessageDialog
* msg
= new MessageDialog (*editor
, string_compose (_("\
3252 The disk system on your computer\n\
3253 was not able to keep up with %1.\n\
3255 Specifically, it failed to write data to disk\n\
3256 quickly enough to keep up with recording.\n"), PROGRAM_NAME
));
3257 msg
->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone
), msg
));
3263 ARDOUR_UI::disk_underrun_handler ()
3265 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler
)
3267 if (!have_disk_speed_dialog_displayed
) {
3268 have_disk_speed_dialog_displayed
= true;
3269 MessageDialog
* msg
= new MessageDialog (
3270 *editor
, string_compose (_("The disk system on your computer\n\
3271 was not able to keep up with %1.\n\
3273 Specifically, it failed to read data from disk\n\
3274 quickly enough to keep up with playback.\n"), PROGRAM_NAME
));
3275 msg
->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone
), msg
));
3281 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog
* msg
)
3283 have_disk_speed_dialog_displayed
= false;
3288 ARDOUR_UI::session_dialog (std::string msg
)
3290 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog
, msg
)
3295 d
= new MessageDialog (*editor
, msg
, false, MESSAGE_INFO
, BUTTONS_OK
, true);
3297 d
= new MessageDialog (msg
, false, MESSAGE_INFO
, BUTTONS_OK
, true);
3306 ARDOUR_UI::pending_state_dialog ()
3308 HBox
* hbox
= new HBox();
3309 Image
* image
= new Image (Stock::DIALOG_QUESTION
, ICON_SIZE_DIALOG
);
3310 ArdourDialog
dialog (_("Crash Recovery"), true);
3312 This session appears to have been in\n\
3313 middle of recording when ardour or\n\
3314 the computer was shutdown.\n\
3316 Ardour can recover any captured audio for\n\
3317 you, or it can ignore it. Please decide\n\
3318 what you would like to do.\n"));
3319 image
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
3320 hbox
->pack_start (*image
, PACK_EXPAND_WIDGET
, 12);
3321 hbox
->pack_end (message
, PACK_EXPAND_PADDING
, 12);
3322 dialog
.get_vbox()->pack_start(*hbox
, PACK_EXPAND_PADDING
, 6);
3323 dialog
.add_button (_("Ignore crash data"), RESPONSE_REJECT
);
3324 dialog
.add_button (_("Recover from crash"), RESPONSE_ACCEPT
);
3325 dialog
.set_default_response (RESPONSE_ACCEPT
);
3326 dialog
.set_position (WIN_POS_CENTER
);
3331 switch (dialog
.run ()) {
3332 case RESPONSE_ACCEPT
:
3340 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired
, framecnt_t actual
)
3342 HBox
* hbox
= new HBox();
3343 Image
* image
= new Image (Stock::DIALOG_QUESTION
, ICON_SIZE_DIALOG
);
3344 ArdourDialog
dialog (_("Sample Rate Mismatch"), true);
3345 Label
message (string_compose (_("\
3346 This session was created with a sample rate of %1 Hz\n\
3348 The audioengine is currently running at %2 Hz\n"), desired
, actual
));
3350 image
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
3351 hbox
->pack_start (*image
, PACK_EXPAND_WIDGET
, 12);
3352 hbox
->pack_end (message
, PACK_EXPAND_PADDING
, 12);
3353 dialog
.get_vbox()->pack_start(*hbox
, PACK_EXPAND_PADDING
, 6);
3354 dialog
.add_button (_("Do not load session"), RESPONSE_REJECT
);
3355 dialog
.add_button (_("Load session anyway"), RESPONSE_ACCEPT
);
3356 dialog
.set_default_response (RESPONSE_ACCEPT
);
3357 dialog
.set_position (WIN_POS_CENTER
);
3362 switch (dialog
.run ()) {
3363 case RESPONSE_ACCEPT
:
3372 ARDOUR_UI::disconnect_from_jack ()
3375 if( engine
->disconnect_from_jack ()) {
3376 MessageDialog
msg (*editor
, _("Could not disconnect from JACK"));
3380 update_sample_rate (0);
3385 ARDOUR_UI::reconnect_to_jack ()
3388 if (engine
->reconnect_to_jack ()) {
3389 MessageDialog
msg (*editor
, _("Could not reconnect to JACK"));
3393 update_sample_rate (0);
3398 ARDOUR_UI::use_config ()
3400 XMLNode
* node
= Config
->extra_xml (X_("TransportControllables"));
3402 set_transport_controllable_state (*node
);
3407 ARDOUR_UI::update_transport_clocks (framepos_t pos
)
3409 if (Config
->get_primary_clock_delta_edit_cursor()) {
3410 primary_clock
->set (pos
, false, editor
->get_preferred_edit_position(), 1);
3412 primary_clock
->set (pos
, 0, true);
3415 if (Config
->get_secondary_clock_delta_edit_cursor()) {
3416 secondary_clock
->set (pos
, false, editor
->get_preferred_edit_position(), 2);
3418 secondary_clock
->set (pos
);
3421 if (big_clock_window
->get()) {
3422 big_clock
->set (pos
);
3428 ARDOUR_UI::step_edit_status_change (bool yn
)
3430 // XXX should really store pre-step edit status of things
3431 // we make insensitive
3434 rec_button
.set_visual_state (3);
3435 rec_button
.set_sensitive (false);
3437 rec_button
.set_visual_state (0);
3438 rec_button
.set_sensitive (true);
3443 ARDOUR_UI::record_state_changed ()
3445 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed
);
3447 if (!_session
|| !big_clock_window
->get()) {
3448 /* why bother - the clock isn't visible */
3452 Session::RecordState
const r
= _session
->record_status ();
3453 bool const h
= _session
->have_rec_enabled_track ();
3455 if (r
== Session::Recording
&& h
) {
3456 big_clock
->set_widget_name ("BigClockRecording");
3458 big_clock
->set_widget_name ("BigClockNonRecording");
3463 ARDOUR_UI::first_idle ()
3466 _session
->allow_auto_play (true);
3470 editor
->first_idle();
3473 Keyboard::set_can_save_keybindings (true);
3478 ARDOUR_UI::store_clock_modes ()
3480 XMLNode
* node
= new XMLNode(X_("ClockModes"));
3482 for (vector
<AudioClock
*>::iterator x
= AudioClock::clocks
.begin(); x
!= AudioClock::clocks
.end(); ++x
) {
3483 XMLNode
* child
= new XMLNode (X_("Clock"));
3485 child
->add_property (X_("name"), (*x
)->name());
3486 child
->add_property (X_("mode"), enum_2_string ((*x
)->mode()));
3487 child
->add_property (X_("on"), ((*x
)->off() ? X_("no") : X_("yes")));
3489 node
->add_child_nocopy (*child
);
3492 _session
->add_extra_xml (*node
);
3493 _session
->set_dirty ();
3496 ARDOUR_UI::TransportControllable::TransportControllable (std::string name
, ARDOUR_UI
& u
, ToggleType tp
)
3497 : Controllable (name
), ui (u
), type(tp
)
3503 ARDOUR_UI::TransportControllable::set_value (double val
)
3506 /* do nothing: these are radio-style actions */
3510 const char *action
= 0;
3514 action
= X_("Roll");
3517 action
= X_("Stop");
3520 action
= X_("Goto Start");
3523 action
= X_("Goto End");
3526 action
= X_("Loop");
3529 action
= X_("Play Selection");
3532 action
= X_("Record");
3542 Glib::RefPtr
<Action
> act
= ActionManager::get_action ("Transport", action
);
3550 ARDOUR_UI::TransportControllable::get_value (void) const
3577 ARDOUR_UI::TransportControllable::set_id (const string
& str
)
3583 ARDOUR_UI::setup_profile ()
3585 if (gdk_screen_width() < 1200) {
3586 Profile
->set_small_screen ();
3590 if (getenv ("ARDOUR_SAE")) {
3591 Profile
->set_sae ();
3592 Profile
->set_single_package ();
3597 ARDOUR_UI::toggle_translations ()
3599 using namespace Glib
;
3601 RefPtr
<Action
> act
= ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3603 RefPtr
<ToggleAction
> ract
= RefPtr
<ToggleAction
>::cast_dynamic (act
);
3606 string i18n_killer
= ARDOUR::translation_kill_path();
3608 bool already_enabled
= !ARDOUR::translations_are_disabled ();
3610 if (ract
->get_active ()) {
3611 /* we don't care about errors */
3612 int fd
= ::open (i18n_killer
.c_str(), O_RDONLY
|O_CREAT
, 0644);
3615 /* we don't care about errors */
3616 unlink (i18n_killer
.c_str());
3619 if (already_enabled
!= ract
->get_active()) {
3620 MessageDialog
win (already_enabled
? _("Translations disabled") : _("Translations enabled"),
3622 Gtk::MESSAGE_WARNING
,
3624 win
.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME
));
3625 win
.set_position (Gtk::WIN_POS_CENTER
);
3633 /** Add a window proxy to our list, so that its state will be saved.
3634 * This call also causes the window to be created and opened if its
3635 * state was saved as `visible'.
3638 ARDOUR_UI::add_window_proxy (WindowProxyBase
* p
)
3640 _window_proxies
.push_back (p
);
3644 /** Remove a window proxy from our list. Must be called if a WindowProxy
3645 * is deleted, to prevent hanging pointers.
3648 ARDOUR_UI::remove_window_proxy (WindowProxyBase
* p
)
3650 _window_proxies
.remove (p
);
3654 ARDOUR_UI::missing_file (Session
*s
, std::string str
, DataType type
)
3656 MissingFileDialog
dialog (s
, str
, type
);
3661 int result
= dialog
.run ();
3668 return 1; // quit entire session load
3671 result
= dialog
.get_action ();
3677 ARDOUR_UI::ambiguous_file (std::string file
, std::string path
, std::vector
<std::string
> hits
)
3679 AmbiguousFileDialog
dialog (file
, hits
);
3685 return dialog
.get_which ();