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 ()
1001 snprintf (buf
, sizeof (buf
), _("Buffers p:%" PRIu32
"%% c:%" PRIu32
"%%"),
1002 _session
->playback_load(), _session
->capture_load());
1003 buffer_load_label
.set_text (buf
);
1005 buffer_load_label
.set_text ("");
1010 ARDOUR_UI::count_recenabled_streams (Route
& route
)
1012 Track
* track
= dynamic_cast<Track
*>(&route
);
1013 if (track
&& track
->record_enabled()) {
1014 rec_enabled_streams
+= track
->n_inputs().n_total();
1019 ARDOUR_UI::update_disk_space()
1021 if (_session
== 0) {
1025 framecnt_t frames
= _session
->available_capture_duration();
1027 framecnt_t fr
= _session
->frame_rate();
1029 if (frames
== max_framecnt
) {
1030 strcpy (buf
, _("Disk: 24hrs+"));
1032 rec_enabled_streams
= 0;
1033 _session
->foreach_route (this, &ARDOUR_UI::count_recenabled_streams
);
1035 if (rec_enabled_streams
) {
1036 frames
/= rec_enabled_streams
;
1043 hrs
= frames
/ (fr
* 3600);
1044 frames
-= hrs
* fr
* 3600;
1045 mins
= frames
/ (fr
* 60);
1046 frames
-= mins
* fr
* 60;
1049 snprintf (buf
, sizeof(buf
), _("Disk: %02dh:%02dm:%02ds"), hrs
, mins
, secs
);
1052 disk_space_label
.set_text (buf
);
1054 // An attempt to make the disk space label flash red when space has run out.
1056 if (frames
< fr
* 60 * 5) {
1057 /* disk_space_box.style ("disk_space_label_empty"); */
1059 /* disk_space_box.style ("disk_space_label"); */
1065 ARDOUR_UI::update_wall_clock ()
1072 tm_now
= localtime (&now
);
1074 sprintf (buf
, "%02d:%02d", tm_now
->tm_hour
, tm_now
->tm_min
);
1075 wall_clock_label
.set_text (buf
);
1081 ARDOUR_UI::session_menu (GdkEventButton */
*ev*/
)
1083 session_popup_menu
->popup (0, 0);
1088 ARDOUR_UI::redisplay_recent_sessions ()
1090 std::vector
<sys::path
> session_directories
;
1091 RecentSessionsSorter cmp
;
1093 recent_session_display
.set_model (Glib::RefPtr
<TreeModel
>(0));
1094 recent_session_model
->clear ();
1096 ARDOUR::RecentSessions rs
;
1097 ARDOUR::read_recent_sessions (rs
);
1100 recent_session_display
.set_model (recent_session_model
);
1104 // sort them alphabetically
1105 sort (rs
.begin(), rs
.end(), cmp
);
1107 for (ARDOUR::RecentSessions::iterator i
= rs
.begin(); i
!= rs
.end(); ++i
) {
1108 session_directories
.push_back ((*i
).second
);
1111 for (vector
<sys::path
>::const_iterator i
= session_directories
.begin();
1112 i
!= session_directories
.end(); ++i
)
1114 std::vector
<sys::path
> state_file_paths
;
1116 // now get available states for this session
1118 get_state_files_in_directory (*i
, state_file_paths
);
1120 vector
<string
*>* states
;
1121 vector
<const gchar
*> item
;
1122 string fullpath
= (*i
).to_string();
1124 /* remove any trailing / */
1126 if (fullpath
[fullpath
.length()-1] == '/') {
1127 fullpath
= fullpath
.substr (0, fullpath
.length()-1);
1130 /* check whether session still exists */
1131 if (!Glib::file_test(fullpath
.c_str(), Glib::FILE_TEST_EXISTS
)) {
1132 /* session doesn't exist */
1133 cerr
<< "skipping non-existent session " << fullpath
<< endl
;
1137 /* now get available states for this session */
1139 if ((states
= Session::possible_states (fullpath
)) == 0) {
1140 /* no state file? */
1144 std::vector
<string
> state_file_names(get_file_names_no_extension (state_file_paths
));
1146 Gtk::TreeModel::Row row
= *(recent_session_model
->append());
1148 row
[recent_session_columns
.visible_name
] = Glib::path_get_basename (fullpath
);
1149 row
[recent_session_columns
.fullpath
] = fullpath
;
1151 if (state_file_names
.size() > 1) {
1155 for (std::vector
<std::string
>::iterator i2
= state_file_names
.begin();
1156 i2
!= state_file_names
.end(); ++i2
)
1159 Gtk::TreeModel::Row child_row
= *(recent_session_model
->append (row
.children()));
1161 child_row
[recent_session_columns
.visible_name
] = *i2
;
1162 child_row
[recent_session_columns
.fullpath
] = fullpath
;
1167 recent_session_display
.set_model (recent_session_model
);
1171 ARDOUR_UI::build_session_selector ()
1173 session_selector_window
= new ArdourDialog (_("Recent Sessions"));
1175 Gtk::ScrolledWindow
*scroller
= manage (new Gtk::ScrolledWindow
);
1177 session_selector_window
->add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
1178 session_selector_window
->add_button (Stock::OPEN
, RESPONSE_ACCEPT
);
1179 session_selector_window
->set_default_response (RESPONSE_ACCEPT
);
1180 recent_session_model
= TreeStore::create (recent_session_columns
);
1181 recent_session_display
.set_model (recent_session_model
);
1182 recent_session_display
.append_column (_("Recent Sessions"), recent_session_columns
.visible_name
);
1183 recent_session_display
.set_headers_visible (false);
1184 recent_session_display
.get_selection()->set_mode (SELECTION_BROWSE
);
1185 recent_session_display
.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated
));
1187 scroller
->add (recent_session_display
);
1188 scroller
->set_policy (Gtk::POLICY_NEVER
, Gtk::POLICY_AUTOMATIC
);
1190 session_selector_window
->set_name ("SessionSelectorWindow");
1191 session_selector_window
->set_size_request (200, 400);
1192 session_selector_window
->get_vbox()->pack_start (*scroller
);
1194 recent_session_display
.show();
1196 //session_selector_window->get_vbox()->show();
1200 ARDOUR_UI::recent_session_row_activated (const TreePath
& /*path*/, TreeViewColumn
* /*col*/)
1202 session_selector_window
->response (RESPONSE_ACCEPT
);
1206 ARDOUR_UI::open_recent_session ()
1208 bool can_return
= (_session
!= 0);
1210 if (session_selector_window
== 0) {
1211 build_session_selector ();
1214 redisplay_recent_sessions ();
1218 session_selector_window
->set_position (WIN_POS_MOUSE
);
1220 ResponseType r
= (ResponseType
) session_selector_window
->run ();
1223 case RESPONSE_ACCEPT
:
1227 session_selector_window
->hide();
1234 if (recent_session_display
.get_selection()->count_selected_rows() == 0) {
1238 session_selector_window
->hide();
1240 Gtk::TreeModel::iterator i
= recent_session_display
.get_selection()->get_selected();
1242 if (i
== recent_session_model
->children().end()) {
1246 std::string path
= (*i
)[recent_session_columns
.fullpath
];
1247 std::string state
= (*i
)[recent_session_columns
.visible_name
];
1249 _session_is_new
= false;
1251 if (load_session (path
, state
) == 0) {
1260 ARDOUR_UI::check_audioengine ()
1263 if (!engine
->connected()) {
1264 MessageDialog
msg (string_compose (
1265 _("%1 is not connected to JACK\n"
1266 "You cannot open or close sessions in this condition"),
1279 ARDOUR_UI::open_session ()
1281 if (!check_audioengine()) {
1286 /* popup selector window */
1288 if (open_session_selector
== 0) {
1290 /* ardour sessions are folders */
1292 open_session_selector
= new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN
);
1293 open_session_selector
->add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
1294 open_session_selector
->add_button (Gtk::Stock::OPEN
, Gtk::RESPONSE_ACCEPT
);
1295 open_session_selector
->set_default_response(Gtk::RESPONSE_ACCEPT
);
1297 FileFilter session_filter
;
1298 session_filter
.add_pattern ("*.ardour");
1299 session_filter
.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME
));
1300 open_session_selector
->add_filter (session_filter
);
1301 open_session_selector
->set_filter (session_filter
);
1304 int response
= open_session_selector
->run();
1305 open_session_selector
->hide ();
1308 case RESPONSE_ACCEPT
:
1311 open_session_selector
->hide();
1315 open_session_selector
->hide();
1316 string session_path
= open_session_selector
->get_filename();
1320 if (session_path
.length() > 0) {
1321 if (ARDOUR::find_session (session_path
, path
, name
, isnew
) == 0) {
1322 _session_is_new
= isnew
;
1323 load_session (path
, name
);
1330 ARDOUR_UI::session_add_midi_route (bool disk
, RouteGroup
* route_group
, uint32_t how_many
, string
const & name_template
)
1332 list
<boost::shared_ptr
<MidiTrack
> > tracks
;
1334 if (_session
== 0) {
1335 warning
<< _("You cannot add a track without a session already loaded.") << endmsg
;
1342 tracks
= _session
->new_midi_track (ARDOUR::Normal
, route_group
, how_many
, name_template
);
1344 if (tracks
.size() != how_many
) {
1345 if (how_many
== 1) {
1346 error
<< _("could not create a new midi track") << endmsg
;
1348 error
<< string_compose (_("could not create %1 new midi tracks"), how_many
) << endmsg
;
1352 if ((route = _session->new_midi_route ()) == 0) {
1353 error << _("could not create new midi bus") << endmsg;
1359 MessageDialog
msg (*editor
,
1360 string_compose (_("There are insufficient JACK ports available\n\
1361 to create a new track or bus.\n\
1362 You should save %1, exit and\n\
1363 restart JACK with more ports."), PROGRAM_NAME
));
1370 ARDOUR_UI::session_add_audio_route (
1372 int32_t input_channels
,
1373 int32_t output_channels
,
1374 ARDOUR::TrackMode mode
,
1375 RouteGroup
* route_group
,
1377 string
const & name_template
1380 list
<boost::shared_ptr
<AudioTrack
> > tracks
;
1383 if (_session
== 0) {
1384 warning
<< _("You cannot add a track or bus without a session already loaded.") << endmsg
;
1390 tracks
= _session
->new_audio_track (input_channels
, output_channels
, mode
, route_group
, how_many
, name_template
);
1392 if (tracks
.size() != how_many
) {
1393 if (how_many
== 1) {
1394 error
<< _("could not create a new audio track") << endmsg
;
1396 error
<< string_compose (_("could only create %1 of %2 new audio %3"),
1397 tracks
.size(), how_many
, (track
? _("tracks") : _("busses"))) << endmsg
;
1403 routes
= _session
->new_audio_route (input_channels
, output_channels
, route_group
, how_many
, name_template
);
1405 if (routes
.size() != how_many
) {
1406 if (how_many
== 1) {
1407 error
<< _("could not create a new audio track") << endmsg
;
1409 error
<< string_compose (_("could not create %1 new audio tracks"), how_many
) << endmsg
;
1416 MessageDialog
msg (*editor
,
1417 string_compose (_("There are insufficient JACK ports available\n\
1418 to create a new track or bus.\n\
1419 You should save %1, exit and\n\
1420 restart JACK with more ports."), PROGRAM_NAME
));
1427 ARDOUR_UI::do_transport_locate (framepos_t new_position
, bool with_roll
)
1429 framecnt_t _preroll
= 0;
1432 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1433 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1435 if (new_position
> _preroll
) {
1436 new_position
-= _preroll
;
1441 _session
->request_locate (new_position
, with_roll
);
1446 ARDOUR_UI::transport_goto_start ()
1449 _session
->goto_start();
1451 /* force displayed area in editor to start no matter
1452 what "follow playhead" setting is.
1456 editor
->center_screen (_session
->current_start_frame ());
1462 ARDOUR_UI::transport_goto_zero ()
1465 _session
->request_locate (0);
1467 /* force displayed area in editor to start no matter
1468 what "follow playhead" setting is.
1472 editor
->reset_x_origin (0);
1478 ARDOUR_UI::transport_goto_wallclock ()
1480 if (_session
&& editor
) {
1487 localtime_r (&now
, &tmnow
);
1489 frames
= tmnow
.tm_hour
* (60 * 60 * _session
->frame_rate());
1490 frames
+= tmnow
.tm_min
* (60 * _session
->frame_rate());
1491 frames
+= tmnow
.tm_sec
* _session
->frame_rate();
1493 _session
->request_locate (frames
, _session
->transport_rolling ());
1495 /* force displayed area in editor to start no matter
1496 what "follow playhead" setting is.
1500 editor
->center_screen (frames
);
1506 ARDOUR_UI::transport_goto_end ()
1509 framepos_t
const frame
= _session
->current_end_frame();
1510 _session
->request_locate (frame
);
1512 /* force displayed area in editor to start no matter
1513 what "follow playhead" setting is.
1517 editor
->center_screen (frame
);
1523 ARDOUR_UI::transport_stop ()
1529 if (_session
->is_auditioning()) {
1530 _session
->cancel_audition ();
1534 _session
->request_stop (false, true);
1538 ARDOUR_UI::transport_stop_and_forget_capture ()
1541 _session
->request_stop (true, true);
1546 ARDOUR_UI::remove_last_capture()
1549 editor
->remove_last_capture();
1554 ARDOUR_UI::transport_record (bool roll
)
1558 switch (_session
->record_status()) {
1559 case Session::Disabled
:
1560 if (_session
->ntracks() == 0) {
1561 MessageDialog
msg (*editor
, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1565 _session
->maybe_enable_record ();
1570 case Session::Recording
:
1572 _session
->request_stop();
1574 _session
->disable_record (false, true);
1578 case Session::Enabled
:
1579 _session
->disable_record (false, true);
1582 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1586 ARDOUR_UI::transport_roll ()
1592 if (_session
->is_auditioning()) {
1597 if (_session
->config
.get_external_sync()) {
1598 switch (_session
->config
.get_sync_source()) {
1602 /* transport controlled by the master */
1608 bool rolling
= _session
->transport_rolling();
1610 if (_session
->get_play_loop()) {
1611 /* XXX it is not possible to just leave seamless loop and keep
1612 playing at present (nov 4th 2009)
1614 if (!Config
->get_seamless_loop()) {
1615 _session
->request_play_loop (false, true);
1617 } else if (_session
->get_play_range () && !join_play_range_button
.get_active()) {
1618 /* stop playing a range if we currently are */
1619 _session
->request_play_range (0, true);
1622 if (join_play_range_button
.get_active()) {
1623 _session
->request_play_range (&editor
->get_selection().time
, true);
1627 _session
->request_transport_speed (1.0f
);
1632 ARDOUR_UI::toggle_roll (bool with_abort
, bool roll_out_of_bounded_mode
)
1639 if (_session
->is_auditioning()) {
1640 _session
->cancel_audition ();
1644 if (_session
->config
.get_external_sync()) {
1645 switch (_session
->config
.get_sync_source()) {
1649 /* transport controlled by the master */
1654 bool rolling
= _session
->transport_rolling();
1655 bool affect_transport
= true;
1657 if (rolling
&& roll_out_of_bounded_mode
) {
1658 /* drop out of loop/range playback but leave transport rolling */
1659 if (_session
->get_play_loop()) {
1660 if (Config
->get_seamless_loop()) {
1661 /* the disk buffers contain copies of the loop - we can't
1662 just keep playing, so stop the transport. the user
1663 can restart as they wish.
1665 affect_transport
= true;
1667 /* disk buffers are normal, so we can keep playing */
1668 affect_transport
= false;
1670 _session
->request_play_loop (false, true);
1671 } else if (_session
->get_play_range ()) {
1672 affect_transport
= false;
1673 _session
->request_play_range (0, true);
1677 if (affect_transport
) {
1679 _session
->request_stop (with_abort
, true);
1681 if (join_play_range_button
.get_active()) {
1682 _session
->request_play_range (&editor
->get_selection().time
, true);
1685 _session
->request_transport_speed (1.0f
);
1691 ARDOUR_UI::toggle_session_auto_loop ()
1697 if (_session
->get_play_loop()) {
1699 if (_session
->transport_rolling()) {
1701 Location
* looploc
= _session
->locations()->auto_loop_location();
1704 _session
->request_locate (looploc
->start(), true);
1705 _session
->request_play_loop (false);
1709 _session
->request_play_loop (false);
1713 Location
* looploc
= _session
->locations()->auto_loop_location();
1716 _session
->request_play_loop (true);
1722 ARDOUR_UI::transport_play_selection ()
1728 editor
->play_selection ();
1732 ARDOUR_UI::transport_rewind (int option
)
1734 float current_transport_speed
;
1737 current_transport_speed
= _session
->transport_speed();
1739 if (current_transport_speed
>= 0.0f
) {
1742 _session
->request_transport_speed (-1.0f
);
1745 _session
->request_transport_speed (-4.0f
);
1748 _session
->request_transport_speed (-0.5f
);
1753 _session
->request_transport_speed (current_transport_speed
* 1.5f
);
1759 ARDOUR_UI::transport_forward (int option
)
1761 float current_transport_speed
;
1764 current_transport_speed
= _session
->transport_speed();
1766 if (current_transport_speed
<= 0.0f
) {
1769 _session
->request_transport_speed (1.0f
);
1772 _session
->request_transport_speed (4.0f
);
1775 _session
->request_transport_speed (0.5f
);
1780 _session
->request_transport_speed (current_transport_speed
* 1.5f
);
1787 ARDOUR_UI::toggle_record_enable (uint32_t rid
)
1789 if (_session
== 0) {
1793 boost::shared_ptr
<Route
> r
;
1795 if ((r
= _session
->route_by_remote_id (rid
)) != 0) {
1799 if ((t
= dynamic_cast<Track
*>(r
.get())) != 0) {
1800 t
->set_record_enabled (!t
->record_enabled(), this);
1803 if (_session
== 0) {
1809 ARDOUR_UI::map_transport_state ()
1812 auto_loop_button
.set_visual_state (0);
1813 play_selection_button
.set_visual_state (0);
1814 roll_button
.set_visual_state (0);
1815 stop_button
.set_visual_state (1);
1819 shuttle_box
->map_transport_state ();
1821 float sp
= _session
->transport_speed();
1827 if (_session
->get_play_range()) {
1829 play_selection_button
.set_visual_state (1);
1830 roll_button
.set_visual_state (0);
1831 auto_loop_button
.set_visual_state (0);
1833 } else if (_session
->get_play_loop ()) {
1835 auto_loop_button
.set_visual_state (1);
1836 play_selection_button
.set_visual_state (0);
1837 roll_button
.set_visual_state (0);
1841 roll_button
.set_visual_state (1);
1842 play_selection_button
.set_visual_state (0);
1843 auto_loop_button
.set_visual_state (0);
1846 if (join_play_range_button
.get_active()) {
1847 /* light up both roll and play-selection if they are joined */
1848 roll_button
.set_visual_state (1);
1849 play_selection_button
.set_visual_state (1);
1852 stop_button
.set_visual_state (0);
1856 stop_button
.set_visual_state (1);
1857 roll_button
.set_visual_state (0);
1858 play_selection_button
.set_visual_state (0);
1859 auto_loop_button
.set_visual_state (0);
1860 update_disk_space ();
1865 ARDOUR_UI::engine_stopped ()
1867 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped
)
1868 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, false);
1869 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, true);
1873 ARDOUR_UI::engine_running ()
1875 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running
)
1876 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, true);
1877 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, false);
1879 Glib::RefPtr
<Action
> action
;
1880 const char* action_name
= 0;
1882 switch (engine
->frames_per_cycle()) {
1884 action_name
= X_("JACKLatency32");
1887 action_name
= X_("JACKLatency64");
1890 action_name
= X_("JACKLatency128");
1893 action_name
= X_("JACKLatency512");
1896 action_name
= X_("JACKLatency1024");
1899 action_name
= X_("JACKLatency2048");
1902 action_name
= X_("JACKLatency4096");
1905 action_name
= X_("JACKLatency8192");
1908 /* XXX can we do anything useful ? */
1914 action
= ActionManager::get_action (X_("JACK"), action_name
);
1917 Glib::RefPtr
<RadioAction
> ract
= Glib::RefPtr
<RadioAction
>::cast_dynamic (action
);
1918 ract
->set_active ();
1924 ARDOUR_UI::engine_halted (const char* reason
, bool free_reason
)
1926 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1927 /* we can't rely on the original string continuing to exist when we are called
1928 again in the GUI thread, so make a copy and note that we need to
1931 char *copy
= strdup (reason
);
1932 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted
, this, copy
, true));
1936 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions
, false);
1937 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions
, true);
1939 update_sample_rate (0);
1943 /* if the reason is a non-empty string, it means that the backend was shutdown
1944 rather than just Ardour.
1947 if (strlen (reason
)) {
1948 msgstr
= string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason
);
1950 msgstr
= string_compose (_("\
1951 JACK has either been shutdown or it\n\
1952 disconnected %1 because %1\n\
1953 was not fast enough. Try to restart\n\
1954 JACK, reconnect and save the session."), PROGRAM_NAME
);
1957 MessageDialog
msg (*editor
, msgstr
);
1962 free ((char*) reason
);
1967 ARDOUR_UI::do_engine_start ()
1975 error
<< _("Unable to start the session running")
1985 ARDOUR_UI::setup_theme ()
1987 theme_manager
->setup_theme();
1991 ARDOUR_UI::update_clocks ()
1993 if (!editor
|| !editor
->dragging_playhead()) {
1994 Clock (_session
->audible_frame(), false, editor
->get_preferred_edit_position()); /* EMIT_SIGNAL */
1999 ARDOUR_UI::start_clocking ()
2001 clock_signal_connection
= RapidScreenUpdate
.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks
));
2005 ARDOUR_UI::stop_clocking ()
2007 clock_signal_connection
.disconnect ();
2011 ARDOUR_UI::toggle_clocking ()
2014 if (clock_button
.get_active()) {
2023 ARDOUR_UI::_blink (void *arg
)
2026 ((ARDOUR_UI
*) arg
)->blink ();
2033 Blink (blink_on
= !blink_on
); /* EMIT_SIGNAL */
2037 ARDOUR_UI::start_blinking ()
2039 /* Start the blink signal. Everybody with a blinking widget
2040 uses Blink to drive the widget's state.
2043 if (blink_timeout_tag
< 0) {
2045 blink_timeout_tag
= g_timeout_add (240, _blink
, this);
2050 ARDOUR_UI::stop_blinking ()
2052 if (blink_timeout_tag
>= 0) {
2053 g_source_remove (blink_timeout_tag
);
2054 blink_timeout_tag
= -1;
2059 /** Ask the user for the name of a new shapshot and then take it.
2063 ARDOUR_UI::snapshot_session (bool switch_to_it
)
2065 ArdourPrompter
prompter (true);
2068 prompter
.set_name ("Prompter");
2069 prompter
.add_button (Gtk::Stock::SAVE
, Gtk::RESPONSE_ACCEPT
);
2070 prompter
.set_title (_("Take Snapshot"));
2071 prompter
.set_title (_("Take Snapshot"));
2072 prompter
.set_prompt (_("Name of new snapshot"));
2074 if (!switch_to_it
) {
2077 struct tm local_time
;
2080 localtime_r (&n
, &local_time
);
2081 strftime (timebuf
, sizeof(timebuf
), "%FT%T", &local_time
);
2082 prompter
.set_initial_text (timebuf
);
2086 switch (prompter
.run()) {
2087 case RESPONSE_ACCEPT
:
2089 prompter
.get_result (snapname
);
2091 bool do_save
= (snapname
.length() != 0);
2094 if (snapname
.find ('/') != string::npos
) {
2095 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2096 "snapshot names may not contain a '/' character"));
2100 if (snapname
.find ('\\') != string::npos
) {
2101 MessageDialog
msg (_("To ensure compatibility with various systems\n"
2102 "snapshot names may not contain a '\\' character"));
2108 vector
<sys::path
> p
;
2109 get_state_files_in_directory (_session
->session_directory().root_path(), p
);
2110 vector
<string
> n
= get_file_names_no_extension (p
);
2111 if (find (n
.begin(), n
.end(), snapname
) != n
.end()) {
2113 ArdourDialog
confirm (_("Confirm Snapshot Overwrite"), true);
2114 Label
m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2115 confirm
.get_vbox()->pack_start (m
, true, true);
2116 confirm
.add_button (Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
2117 confirm
.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT
);
2118 confirm
.show_all ();
2119 switch (confirm
.run()) {
2120 case RESPONSE_CANCEL
:
2126 save_state (snapname
, switch_to_it
);
2137 ARDOUR_UI::save_state (const string
& name
, bool switch_to_it
)
2139 XMLNode
* node
= new XMLNode (X_("UI"));
2141 for (list
<WindowProxyBase
*>::iterator i
= _window_proxies
.begin(); i
!= _window_proxies
.end(); ++i
) {
2142 if (!(*i
)->rc_configured()) {
2143 node
->add_child_nocopy (*((*i
)->get_state ()));
2147 _session
->add_extra_xml (*node
);
2149 save_state_canfail (name
, switch_to_it
);
2153 ARDOUR_UI::save_state_canfail (string name
, bool switch_to_it
)
2158 if (name
.length() == 0) {
2159 name
= _session
->snap_name();
2162 if ((ret
= _session
->save_state (name
, false, switch_to_it
)) != 0) {
2167 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2172 ARDOUR_UI::primary_clock_value_changed ()
2175 _session
->request_locate (primary_clock
->current_time ());
2180 ARDOUR_UI::big_clock_value_changed ()
2183 _session
->request_locate (big_clock
->current_time ());
2188 ARDOUR_UI::secondary_clock_value_changed ()
2191 _session
->request_locate (secondary_clock
->current_time ());
2196 ARDOUR_UI::transport_rec_enable_blink (bool onoff
)
2198 if (_session
== 0) {
2202 if (_session
->step_editing()) {
2206 Session::RecordState
const r
= _session
->record_status ();
2207 bool const h
= _session
->have_rec_enabled_track ();
2209 if (r
== Session::Enabled
|| (r
== Session::Recording
&& !h
)) {
2211 rec_button
.set_visual_state (2);
2213 rec_button
.set_visual_state (0);
2215 } else if (r
== Session::Recording
&& h
) {
2216 rec_button
.set_visual_state (1);
2218 rec_button
.set_visual_state (0);
2223 ARDOUR_UI::save_template ()
2225 ArdourPrompter
prompter (true);
2228 if (!check_audioengine()) {
2232 prompter
.set_name (X_("Prompter"));
2233 prompter
.set_title (_("Save Template"));
2234 prompter
.set_prompt (_("Name for template:"));
2235 prompter
.set_initial_text(_session
->name() + _("-template"));
2236 prompter
.add_button (Gtk::Stock::SAVE
, Gtk::RESPONSE_ACCEPT
);
2238 switch (prompter
.run()) {
2239 case RESPONSE_ACCEPT
:
2240 prompter
.get_result (name
);
2242 if (name
.length()) {
2243 _session
->save_template (name
);
2253 ARDOUR_UI::edit_metadata ()
2255 SessionMetadataEditor dialog
;
2256 dialog
.set_session (_session
);
2257 editor
->ensure_float (dialog
);
2262 ARDOUR_UI::import_metadata ()
2264 SessionMetadataImporter dialog
;
2265 dialog
.set_session (_session
);
2266 editor
->ensure_float (dialog
);
2271 ARDOUR_UI::ask_about_loading_existing_session (const std::string
& session_path
)
2273 std::string str
= string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path
);
2275 MessageDialog
msg (str
,
2277 Gtk::MESSAGE_WARNING
,
2278 Gtk::BUTTONS_YES_NO
,
2282 msg
.set_name (X_("OpenExistingDialog"));
2283 msg
.set_title (_("Open Existing Session"));
2284 msg
.set_wmclass (X_("existing_session"), PROGRAM_NAME
);
2285 msg
.set_position (Gtk::WIN_POS_MOUSE
);
2288 switch (msg
.run()) {
2297 ARDOUR_UI::build_session_from_nsd (const std::string
& session_path
, const std::string
& session_name
)
2299 BusProfile bus_profile
;
2301 if (Profile
->get_sae()) {
2303 bus_profile
.master_out_channels
= 2;
2304 bus_profile
.input_ac
= AutoConnectPhysical
;
2305 bus_profile
.output_ac
= AutoConnectMaster
;
2306 bus_profile
.requested_physical_in
= 0; // use all available
2307 bus_profile
.requested_physical_out
= 0; // use all available
2311 /* get settings from advanced section of NSD */
2313 if (_startup
->create_master_bus()) {
2314 bus_profile
.master_out_channels
= (uint32_t) _startup
->master_channel_count();
2316 bus_profile
.master_out_channels
= 0;
2319 if (_startup
->connect_inputs()) {
2320 bus_profile
.input_ac
= AutoConnectPhysical
;
2322 bus_profile
.input_ac
= AutoConnectOption (0);
2325 /// @todo some minor tweaks.
2327 bus_profile
.output_ac
= AutoConnectOption (0);
2329 if (_startup
->connect_outputs ()) {
2330 if (_startup
->connect_outs_to_master()) {
2331 bus_profile
.output_ac
= AutoConnectMaster
;
2332 } else if (_startup
->connect_outs_to_physical()) {
2333 bus_profile
.output_ac
= AutoConnectPhysical
;
2337 bus_profile
.requested_physical_in
= (uint32_t) _startup
->input_limit_count();
2338 bus_profile
.requested_physical_out
= (uint32_t) _startup
->output_limit_count();
2341 if (build_session (session_path
, session_name
, bus_profile
)) {
2349 ARDOUR_UI::idle_load (const std::string
& path
)
2352 if (Glib::file_test (path
, Glib::FILE_TEST_IS_DIR
)) {
2353 /* /path/to/foo => /path/to/foo, foo */
2354 load_session (path
, basename_nosuffix (path
));
2356 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2357 load_session (Glib::path_get_dirname (path
), basename_nosuffix (path
));
2361 ARDOUR_COMMAND_LINE::session_name
= path
;
2364 * new_session_dialog doens't exist in A3
2365 * Try to remove all references to it to
2366 * see if it will compile. NOTE: this will
2367 * likely cause a runtime issue is my somewhat
2371 //if (new_session_dialog) {
2374 /* make it break out of Dialog::run() and
2378 //new_session_dialog->response (1);
2384 ARDOUR_UI::end_loading_messages ()
2390 ARDOUR_UI::loading_message (const std::string
& /*msg*/)
2393 // splash->message (msg);
2397 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2399 ARDOUR_UI::get_session_parameters (bool quit_on_cancel
, bool should_be_new
, string load_template
)
2401 string session_name
;
2402 string session_path
;
2403 string template_name
;
2405 bool likely_new
= false;
2407 if (!load_template
.empty()) {
2408 should_be_new
= true;
2409 template_name
= load_template
;
2414 if (!should_be_new
&& !ARDOUR_COMMAND_LINE::session_name
.empty()) {
2416 /* if they named a specific statefile, use it, otherwise they are
2417 just giving a session folder, and we want to use it as is
2418 to find the session.
2421 string::size_type suffix
= ARDOUR_COMMAND_LINE::session_name
.find (statefile_suffix
);
2423 if (suffix
!= string::npos
) {
2424 session_path
= Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name
);
2425 session_name
= ARDOUR_COMMAND_LINE::session_name
.substr (0, suffix
);
2426 session_name
= Glib::path_get_basename (session_name
);
2428 session_path
= ARDOUR_COMMAND_LINE::session_name
;
2429 session_name
= Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name
);
2434 bool const apply
= run_startup (should_be_new
, load_template
);
2437 if (quit_on_cancel
) {
2444 /* if we run the startup dialog again, offer more than just "new session" */
2446 should_be_new
= false;
2448 session_name
= _startup
->session_name (likely_new
);
2450 /* this shouldn't happen, but we catch it just in case it does */
2452 if (session_name
.empty()) {
2456 if (_startup
->use_session_template()) {
2457 template_name
= _startup
->session_template_name();
2458 _session_is_new
= true;
2461 if (session_name
[0] == G_DIR_SEPARATOR
||
2462 (session_name
.length() > 2 && session_name
[0] == '.' && session_name
[1] == G_DIR_SEPARATOR
) ||
2463 (session_name
.length() > 3 && session_name
[0] == '.' && session_name
[1] == '.' && session_name
[2] == G_DIR_SEPARATOR
)) {
2465 /* absolute path or cwd-relative path specified for session name: infer session folder
2466 from what was given.
2469 session_path
= Glib::path_get_dirname (session_name
);
2470 session_name
= Glib::path_get_basename (session_name
);
2474 session_path
= _startup
->session_folder();
2476 if (session_name
.find ('/') != string::npos
) {
2477 MessageDialog
msg (*_startup
,
2478 _("To ensure compatibility with various systems\n"
2479 "session names may not contain a '/' character"));
2481 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2485 if (session_name
.find ('\\') != string::npos
) {
2486 MessageDialog
msg (*_startup
,
2487 _("To ensure compatibility with various systems\n"
2488 "session names may not contain a '\\' character"));
2490 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2496 if (create_engine ()) {
2500 if (Glib::file_test (session_path
, Glib::FileTest (G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_DIR
))) {
2504 std::string existing
= Glib::build_filename (session_path
, session_name
);
2506 if (!ask_about_loading_existing_session (existing
)) {
2507 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2512 _session_is_new
= false;
2517 MessageDialog
msg (string_compose (_("There is no existing session at \"%1\""), session_path
));
2519 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2523 if (session_name
.find ('/') != std::string::npos
) {
2524 MessageDialog
msg (*_startup
,
2525 _("To ensure compatibility with various systems\n"
2526 "session names may not contain a '/' character"));
2528 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2532 if (session_name
.find ('\\') != std::string::npos
) {
2533 MessageDialog
msg (*_startup
,
2534 _("To ensure compatibility with various systems\n"
2535 "session names may not contain a '\\' character"));
2537 ARDOUR_COMMAND_LINE::session_name
= ""; // cancel that
2541 _session_is_new
= true;
2544 if (likely_new
&& template_name
.empty()) {
2546 ret
= build_session_from_nsd (session_path
, session_name
);
2550 ret
= load_session (session_path
, session_name
, template_name
);
2553 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2557 if (!ARDOUR_COMMAND_LINE::immediate_save
.empty()) {
2558 _session
->save_state (ARDOUR_COMMAND_LINE::immediate_save
, false);
2568 ARDOUR_UI::close_session()
2570 if (!check_audioengine()) {
2574 if (unload_session (true)) {
2578 ARDOUR_COMMAND_LINE::session_name
= "";
2580 if (get_session_parameters (true, false)) {
2584 goto_editor_window ();
2587 /** @param snap_name Snapshot name (without .ardour suffix).
2588 * @return -2 if the load failed because we are not connected to the AudioEngine.
2591 ARDOUR_UI::load_session (const std::string
& path
, const std::string
& snap_name
, std::string mix_template
)
2593 Session
*new_session
;
2597 session_loaded
= false;
2599 if (!check_audioengine()) {
2603 unload_status
= unload_session ();
2605 if (unload_status
< 0) {
2607 } else if (unload_status
> 0) {
2612 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME
));
2615 new_session
= new Session (*engine
, path
, snap_name
, 0, mix_template
);
2618 /* this one is special */
2620 catch (AudioEngine::PortRegistrationFailure
& err
) {
2622 MessageDialog
msg (err
.what(),
2625 Gtk::BUTTONS_CLOSE
);
2627 msg
.set_title (_("Port Registration Error"));
2628 msg
.set_secondary_text (_("Click the Close button to try again."));
2629 msg
.set_position (Gtk::WIN_POS_CENTER
);
2633 int response
= msg
.run ();
2638 case RESPONSE_CANCEL
:
2648 MessageDialog
msg (string_compose(
2649 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2655 msg
.set_title (_("Loading Error"));
2656 msg
.set_secondary_text (_("Click the Refresh button to try again."));
2657 msg
.add_button (Stock::REFRESH
, 1);
2658 msg
.set_position (Gtk::WIN_POS_CENTER
);
2662 int response
= msg
.run ();
2677 list
<string
> const u
= new_session
->unknown_processors ();
2679 MissingPluginDialog
d (_session
, u
);
2684 /* Now the session been created, add the transport controls */
2685 new_session
->add_controllable(roll_controllable
);
2686 new_session
->add_controllable(stop_controllable
);
2687 new_session
->add_controllable(goto_start_controllable
);
2688 new_session
->add_controllable(goto_end_controllable
);
2689 new_session
->add_controllable(auto_loop_controllable
);
2690 new_session
->add_controllable(play_selection_controllable
);
2691 new_session
->add_controllable(rec_controllable
);
2693 set_session (new_session
);
2695 session_loaded
= true;
2697 goto_editor_window ();
2700 _session
->set_clean ();
2711 ARDOUR_UI::build_session (const std::string
& path
, const std::string
& snap_name
, BusProfile
& bus_profile
)
2713 Session
*new_session
;
2716 if (!check_audioengine()) {
2720 session_loaded
= false;
2722 x
= unload_session ();
2730 _session_is_new
= true;
2733 new_session
= new Session (*engine
, path
, snap_name
, &bus_profile
);
2738 MessageDialog
msg (string_compose(_("Could not create session in \"%1\""), path
));
2744 /* Give the new session the default GUI state, if such things exist */
2747 n
= Config
->instant_xml (X_("Editor"));
2749 new_session
->add_instant_xml (*n
, false);
2751 n
= Config
->instant_xml (X_("Mixer"));
2753 new_session
->add_instant_xml (*n
, false);
2756 /* Put the playhead at 0 and scroll fully left */
2757 n
= new_session
->instant_xml (X_("Editor"));
2759 n
->add_property (X_("playhead"), X_("0"));
2760 n
->add_property (X_("left-frame"), X_("0"));
2763 set_session (new_session
);
2765 session_loaded
= true;
2767 new_session
->save_state(new_session
->name());
2773 ARDOUR_UI::launch_chat ()
2776 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2778 open_uri("http://webchat.freenode.net/?channels=ardour");
2783 ARDOUR_UI::show_about ()
2787 about
->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response
) );
2790 about
->set_transient_for(*editor
);
2795 ARDOUR_UI::launch_manual ()
2797 PBD::open_uri("http://ardour.org/flossmanual");
2801 ARDOUR_UI::launch_reference ()
2803 PBD::open_uri("http://ardour.org/refmanual");
2807 ARDOUR_UI::hide_about ()
2810 about
->get_window()->set_cursor ();
2816 ARDOUR_UI::about_signal_response (int /*response*/)
2822 ARDOUR_UI::show_splash ()
2826 splash
= new Splash
;
2834 splash
->queue_draw ();
2835 splash
->get_window()->process_updates (true);
2840 ARDOUR_UI::hide_splash ()
2848 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport
& rep
, const gchar
* list_title
,
2849 const string
& plural_msg
, const string
& singular_msg
)
2853 removed
= rep
.paths
.size();
2856 MessageDialog
msgd (*editor
,
2857 _("No files were ready for clean-up"),
2860 (Gtk::ButtonsType
)(Gtk::BUTTONS_OK
) );
2861 msgd
.set_title (_("Clean-up"));
2862 msgd
.set_secondary_text (_("If this seems suprising, \n\
2863 check for any existing snapshots.\n\
2864 These may still include regions that\n\
2865 require some unused files to continue to exist."));
2871 ArdourDialog
results (_("Clean-up"), true, false);
2873 struct CleanupResultsModelColumns
: public Gtk::TreeModel::ColumnRecord
{
2874 CleanupResultsModelColumns() {
2878 Gtk::TreeModelColumn
<std::string
> visible_name
;
2879 Gtk::TreeModelColumn
<std::string
> fullpath
;
2883 CleanupResultsModelColumns results_columns
;
2884 Glib::RefPtr
<Gtk::ListStore
> results_model
;
2885 Gtk::TreeView results_display
;
2887 results_model
= ListStore::create (results_columns
);
2888 results_display
.set_model (results_model
);
2889 results_display
.append_column (list_title
, results_columns
.visible_name
);
2891 results_display
.set_name ("CleanupResultsList");
2892 results_display
.set_headers_visible (true);
2893 results_display
.set_headers_clickable (false);
2894 results_display
.set_reorderable (false);
2896 Gtk::ScrolledWindow list_scroller
;
2899 Gtk::HBox dhbox
; // the hbox for the image and text
2900 Gtk::HBox ddhbox
; // the hbox we eventually pack into the dialog's vbox
2901 Gtk::Image
* dimage
= manage (new Gtk::Image(Stock::DIALOG_INFO
, Gtk::ICON_SIZE_DIALOG
));
2903 dimage
->set_alignment(ALIGN_LEFT
, ALIGN_TOP
);
2905 const string dead_directory
= _session
->session_directory().dead_path().to_string();
2908 %1 - number of files removed
2909 %2 - location of "dead"
2910 %3 - size of files affected
2911 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2914 const char* bprefix
;
2915 double space_adjusted
= 0;
2917 if (rep
.space
< 1000) {
2919 space_adjusted
= rep
.space
;
2920 } else if (rep
.space
< 1000000) {
2921 bprefix
= X_("kilo");
2922 space_adjusted
= truncf((float)rep
.space
/ 1000.0);
2923 } else if (rep
.space
< 1000000 * 1000) {
2924 bprefix
= X_("mega");
2925 space_adjusted
= truncf((float)rep
.space
/ (1000.0 * 1000.0));
2927 bprefix
= X_("giga");
2928 space_adjusted
= truncf((float)rep
.space
/ (1000.0 * 1000 * 1000.0));
2932 txt
.set_text (string_compose (plural_msg
, removed
, dead_directory
, space_adjusted
, bprefix
));
2934 txt
.set_text (string_compose (singular_msg
, removed
, dead_directory
, space_adjusted
, bprefix
));
2937 dhbox
.pack_start (*dimage
, true, false, 5);
2938 dhbox
.pack_start (txt
, true, false, 5);
2940 for (vector
<string
>::iterator i
= rep
.paths
.begin(); i
!= rep
.paths
.end(); ++i
) {
2941 TreeModel::Row row
= *(results_model
->append());
2942 row
[results_columns
.visible_name
] = *i
;
2943 row
[results_columns
.fullpath
] = *i
;
2946 list_scroller
.add (results_display
);
2947 list_scroller
.set_size_request (-1, 150);
2948 list_scroller
.set_policy (Gtk::POLICY_NEVER
, Gtk::POLICY_AUTOMATIC
);
2950 dvbox
.pack_start (dhbox
, true, false, 5);
2951 dvbox
.pack_start (list_scroller
, true, false, 5);
2952 ddhbox
.pack_start (dvbox
, true, false, 5);
2954 results
.get_vbox()->pack_start (ddhbox
, true, false, 5);
2955 results
.add_button (Stock::CLOSE
, RESPONSE_CLOSE
);
2956 results
.set_default_response (RESPONSE_CLOSE
);
2957 results
.set_position (Gtk::WIN_POS_MOUSE
);
2959 results_display
.show();
2960 list_scroller
.show();
2967 //results.get_vbox()->show();
2968 results
.set_resizable (false);
2975 ARDOUR_UI::cleanup ()
2977 if (_session
== 0) {
2978 /* shouldn't happen: menu item is insensitive */
2983 MessageDialog
checker (_("Are you sure you want to clean-up?"),
2985 Gtk::MESSAGE_QUESTION
,
2986 (Gtk::ButtonsType
)(Gtk::BUTTONS_NONE
));
2988 checker
.set_title (_("Clean-up"));
2990 checker
.set_secondary_text(_("Clean-up is a destructive operation.\n\
2991 ALL undo/redo information will be lost if you clean-up.\n\
2992 Clean-up will move all unused files to a \"dead\" location."));
2994 checker
.add_button (Stock::CANCEL
, RESPONSE_CANCEL
);
2995 checker
.add_button (_("Clean-up"), RESPONSE_ACCEPT
);
2996 checker
.set_default_response (RESPONSE_CANCEL
);
2998 checker
.set_name (_("CleanupDialog"));
2999 checker
.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME
);
3000 checker
.set_position (Gtk::WIN_POS_MOUSE
);
3002 switch (checker
.run()) {
3003 case RESPONSE_ACCEPT
:
3009 ARDOUR::CleanupReport rep
;
3011 editor
->prepare_for_cleanup ();
3013 /* do not allow flush until a session is reloaded */
3015 Glib::RefPtr
<Action
> act
= ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3017 act
->set_sensitive (false);
3020 if (_session
->cleanup_sources (rep
)) {
3021 editor
->finish_cleanup ();
3025 editor
->finish_cleanup ();
3028 display_cleanup_results (rep
,
3031 The following %1 files were not in use and \n\
3032 have been moved to:\n\n\
3034 After a restart of Ardour,\n\n\
3035 Session -> Clean-up -> Flush Wastebasket\n\n\
3036 will release an additional\n\
3037 %3 %4bytes of disk space.\n"),
3039 The following file was not in use and \n\
3040 has been moved to:\n \
3042 After a restart of Ardour,\n\n\
3043 Session -> Clean-up -> Flush Wastebasket\n\n\
3044 will release an additional\n\
3045 %3 %4bytes of disk space.\n"
3051 ARDOUR_UI::flush_trash ()
3053 if (_session
== 0) {
3054 /* shouldn't happen: menu item is insensitive */
3058 ARDOUR::CleanupReport rep
;
3060 if (_session
->cleanup_trash_sources (rep
)) {
3064 display_cleanup_results (rep
,
3066 _("The following %1 files were deleted from\n\
3068 releasing %3 %4bytes of disk space"),
3069 _("The following file was deleted from\n\
3071 releasing %3 %4bytes of disk space"));
3075 ARDOUR_UI::add_route (Gtk::Window
* float_window
)
3083 if (add_route_dialog
== 0) {
3084 add_route_dialog
= new AddRouteDialog (_session
);
3086 add_route_dialog
->set_transient_for (*float_window
);
3090 if (add_route_dialog
->is_visible()) {
3091 /* we're already doing this */
3095 ResponseType r
= (ResponseType
) add_route_dialog
->run ();
3097 add_route_dialog
->hide();
3100 case RESPONSE_ACCEPT
:
3107 if ((count
= add_route_dialog
->count()) <= 0) {
3111 string template_path
= add_route_dialog
->track_template();
3113 if (!template_path
.empty()) {
3114 _session
->new_route_from_template (count
, template_path
);
3118 uint32_t input_chan
= add_route_dialog
->channels ();
3119 uint32_t output_chan
;
3120 string name_template
= add_route_dialog
->name_template ();
3121 bool track
= add_route_dialog
->track ();
3122 RouteGroup
* route_group
= add_route_dialog
->route_group ();
3124 AutoConnectOption oac
= Config
->get_output_auto_connect();
3126 if (oac
& AutoConnectMaster
) {
3127 output_chan
= (_session
->master_out() ? _session
->master_out()->n_inputs().n_audio() : input_chan
);
3129 output_chan
= input_chan
;
3132 /* XXX do something with name template */
3134 if (add_route_dialog
->type() == ARDOUR::DataType::MIDI
) {
3136 session_add_midi_track (route_group
, count
, name_template
);
3138 MessageDialog
msg (*editor
,
3139 _("Sorry, MIDI Busses are not supported at this time."));
3141 //session_add_midi_bus();
3145 session_add_audio_track (input_chan
, output_chan
, add_route_dialog
->mode(), route_group
, count
, name_template
);
3147 session_add_audio_bus (input_chan
, output_chan
, route_group
, count
, name_template
);
3153 ARDOUR_UI::mixer_settings () const
3158 node
= _session
->instant_xml(X_("Mixer"));
3160 node
= Config
->instant_xml(X_("Mixer"));
3164 node
= new XMLNode (X_("Mixer"));
3171 ARDOUR_UI::editor_settings () const
3176 node
= _session
->instant_xml(X_("Editor"));
3178 node
= Config
->instant_xml(X_("Editor"));
3182 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3183 node
= Config
->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3188 node
= new XMLNode (X_("Editor"));
3195 ARDOUR_UI::keyboard_settings () const
3199 node
= Config
->extra_xml(X_("Keyboard"));
3202 node
= new XMLNode (X_("Keyboard"));
3209 ARDOUR_UI::create_xrun_marker (framepos_t where
)
3211 editor
->mouse_add_new_marker (where
, false, true);
3215 ARDOUR_UI::halt_on_xrun_message ()
3217 MessageDialog
msg (*editor
,
3218 _("Recording was stopped because your system could not keep up."));
3223 ARDOUR_UI::xrun_handler (framepos_t where
)
3229 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler
, where
)
3231 if (_session
&& Config
->get_create_xrun_marker() && _session
->actively_recording()) {
3232 create_xrun_marker(where
);
3235 if (_session
&& Config
->get_stop_recording_on_xrun() && _session
->actively_recording()) {
3236 halt_on_xrun_message ();
3241 ARDOUR_UI::disk_overrun_handler ()
3243 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler
)
3245 if (!have_disk_speed_dialog_displayed
) {
3246 have_disk_speed_dialog_displayed
= true;
3247 MessageDialog
* msg
= new MessageDialog (*editor
, string_compose (_("\
3248 The disk system on your computer\n\
3249 was not able to keep up with %1.\n\
3251 Specifically, it failed to write data to disk\n\
3252 quickly enough to keep up with recording.\n"), PROGRAM_NAME
));
3253 msg
->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone
), msg
));
3259 ARDOUR_UI::disk_underrun_handler ()
3261 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler
)
3263 if (!have_disk_speed_dialog_displayed
) {
3264 have_disk_speed_dialog_displayed
= true;
3265 MessageDialog
* msg
= new MessageDialog (
3266 *editor
, string_compose (_("The disk system on your computer\n\
3267 was not able to keep up with %1.\n\
3269 Specifically, it failed to read data from disk\n\
3270 quickly enough to keep up with playback.\n"), PROGRAM_NAME
));
3271 msg
->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone
), msg
));
3277 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog
* msg
)
3279 have_disk_speed_dialog_displayed
= false;
3284 ARDOUR_UI::session_dialog (std::string msg
)
3286 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog
, msg
)
3291 d
= new MessageDialog (*editor
, msg
, false, MESSAGE_INFO
, BUTTONS_OK
, true);
3293 d
= new MessageDialog (msg
, false, MESSAGE_INFO
, BUTTONS_OK
, true);
3302 ARDOUR_UI::pending_state_dialog ()
3304 HBox
* hbox
= new HBox();
3305 Image
* image
= new Image (Stock::DIALOG_QUESTION
, ICON_SIZE_DIALOG
);
3306 ArdourDialog
dialog (_("Crash Recovery"), true);
3308 This session appears to have been in\n\
3309 middle of recording when ardour or\n\
3310 the computer was shutdown.\n\
3312 Ardour can recover any captured audio for\n\
3313 you, or it can ignore it. Please decide\n\
3314 what you would like to do.\n"));
3315 image
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
3316 hbox
->pack_start (*image
, PACK_EXPAND_WIDGET
, 12);
3317 hbox
->pack_end (message
, PACK_EXPAND_PADDING
, 12);
3318 dialog
.get_vbox()->pack_start(*hbox
, PACK_EXPAND_PADDING
, 6);
3319 dialog
.add_button (_("Ignore crash data"), RESPONSE_REJECT
);
3320 dialog
.add_button (_("Recover from crash"), RESPONSE_ACCEPT
);
3321 dialog
.set_default_response (RESPONSE_ACCEPT
);
3322 dialog
.set_position (WIN_POS_CENTER
);
3327 switch (dialog
.run ()) {
3328 case RESPONSE_ACCEPT
:
3336 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired
, framecnt_t actual
)
3338 HBox
* hbox
= new HBox();
3339 Image
* image
= new Image (Stock::DIALOG_QUESTION
, ICON_SIZE_DIALOG
);
3340 ArdourDialog
dialog (_("Sample Rate Mismatch"), true);
3341 Label
message (string_compose (_("\
3342 This session was created with a sample rate of %1 Hz\n\
3344 The audioengine is currently running at %2 Hz\n"), desired
, actual
));
3346 image
->set_alignment(ALIGN_CENTER
, ALIGN_TOP
);
3347 hbox
->pack_start (*image
, PACK_EXPAND_WIDGET
, 12);
3348 hbox
->pack_end (message
, PACK_EXPAND_PADDING
, 12);
3349 dialog
.get_vbox()->pack_start(*hbox
, PACK_EXPAND_PADDING
, 6);
3350 dialog
.add_button (_("Do not load session"), RESPONSE_REJECT
);
3351 dialog
.add_button (_("Load session anyway"), RESPONSE_ACCEPT
);
3352 dialog
.set_default_response (RESPONSE_ACCEPT
);
3353 dialog
.set_position (WIN_POS_CENTER
);
3358 switch (dialog
.run ()) {
3359 case RESPONSE_ACCEPT
:
3368 ARDOUR_UI::disconnect_from_jack ()
3371 if( engine
->disconnect_from_jack ()) {
3372 MessageDialog
msg (*editor
, _("Could not disconnect from JACK"));
3376 update_sample_rate (0);
3381 ARDOUR_UI::reconnect_to_jack ()
3384 if (engine
->reconnect_to_jack ()) {
3385 MessageDialog
msg (*editor
, _("Could not reconnect to JACK"));
3389 update_sample_rate (0);
3394 ARDOUR_UI::use_config ()
3396 XMLNode
* node
= Config
->extra_xml (X_("TransportControllables"));
3398 set_transport_controllable_state (*node
);
3403 ARDOUR_UI::update_transport_clocks (framepos_t pos
)
3405 if (Config
->get_primary_clock_delta_edit_cursor()) {
3406 primary_clock
->set (pos
, false, editor
->get_preferred_edit_position(), 1);
3408 primary_clock
->set (pos
, 0, true);
3411 if (Config
->get_secondary_clock_delta_edit_cursor()) {
3412 secondary_clock
->set (pos
, false, editor
->get_preferred_edit_position(), 2);
3414 secondary_clock
->set (pos
);
3417 if (big_clock_window
->get()) {
3418 big_clock
->set (pos
);
3424 ARDOUR_UI::step_edit_status_change (bool yn
)
3426 // XXX should really store pre-step edit status of things
3427 // we make insensitive
3430 rec_button
.set_visual_state (3);
3431 rec_button
.set_sensitive (false);
3433 rec_button
.set_visual_state (0);
3434 rec_button
.set_sensitive (true);
3439 ARDOUR_UI::record_state_changed ()
3441 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed
);
3443 if (!_session
|| !big_clock_window
->get()) {
3444 /* why bother - the clock isn't visible */
3448 Session::RecordState
const r
= _session
->record_status ();
3449 bool const h
= _session
->have_rec_enabled_track ();
3451 if (r
== Session::Recording
&& h
) {
3452 big_clock
->set_widget_name ("BigClockRecording");
3454 big_clock
->set_widget_name ("BigClockNonRecording");
3459 ARDOUR_UI::first_idle ()
3462 _session
->allow_auto_play (true);
3466 editor
->first_idle();
3469 Keyboard::set_can_save_keybindings (true);
3474 ARDOUR_UI::store_clock_modes ()
3476 XMLNode
* node
= new XMLNode(X_("ClockModes"));
3478 for (vector
<AudioClock
*>::iterator x
= AudioClock::clocks
.begin(); x
!= AudioClock::clocks
.end(); ++x
) {
3479 XMLNode
* child
= new XMLNode (X_("Clock"));
3481 child
->add_property (X_("name"), (*x
)->name());
3482 child
->add_property (X_("mode"), enum_2_string ((*x
)->mode()));
3483 child
->add_property (X_("on"), ((*x
)->off() ? X_("no") : X_("yes")));
3485 node
->add_child_nocopy (*child
);
3488 _session
->add_extra_xml (*node
);
3489 _session
->set_dirty ();
3492 ARDOUR_UI::TransportControllable::TransportControllable (std::string name
, ARDOUR_UI
& u
, ToggleType tp
)
3493 : Controllable (name
), ui (u
), type(tp
)
3499 ARDOUR_UI::TransportControllable::set_value (double val
)
3502 /* do nothing: these are radio-style actions */
3506 const char *action
= 0;
3510 action
= X_("Roll");
3513 action
= X_("Stop");
3516 action
= X_("Goto Start");
3519 action
= X_("Goto End");
3522 action
= X_("Loop");
3525 action
= X_("Play Selection");
3528 action
= X_("Record");
3538 Glib::RefPtr
<Action
> act
= ActionManager::get_action ("Transport", action
);
3546 ARDOUR_UI::TransportControllable::get_value (void) const
3573 ARDOUR_UI::TransportControllable::set_id (const string
& str
)
3579 ARDOUR_UI::setup_profile ()
3581 if (gdk_screen_width() < 1200) {
3582 Profile
->set_small_screen ();
3586 if (getenv ("ARDOUR_SAE")) {
3587 Profile
->set_sae ();
3588 Profile
->set_single_package ();
3593 ARDOUR_UI::toggle_translations ()
3595 using namespace Glib
;
3597 RefPtr
<Action
> act
= ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3599 RefPtr
<ToggleAction
> ract
= RefPtr
<ToggleAction
>::cast_dynamic (act
);
3602 string i18n_killer
= ARDOUR::translation_kill_path();
3604 bool already_enabled
= !ARDOUR::translations_are_disabled ();
3606 if (ract
->get_active ()) {
3607 /* we don't care about errors */
3608 int fd
= ::open (i18n_killer
.c_str(), O_RDONLY
|O_CREAT
, 0644);
3611 /* we don't care about errors */
3612 unlink (i18n_killer
.c_str());
3615 if (already_enabled
!= ract
->get_active()) {
3616 MessageDialog
win (already_enabled
? _("Translations disabled") : _("Translations enabled"),
3618 Gtk::MESSAGE_WARNING
,
3620 win
.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME
));
3621 win
.set_position (Gtk::WIN_POS_CENTER
);
3629 /** Add a window proxy to our list, so that its state will be saved.
3630 * This call also causes the window to be created and opened if its
3631 * state was saved as `visible'.
3634 ARDOUR_UI::add_window_proxy (WindowProxyBase
* p
)
3636 _window_proxies
.push_back (p
);
3640 /** Remove a window proxy from our list. Must be called if a WindowProxy
3641 * is deleted, to prevent hanging pointers.
3644 ARDOUR_UI::remove_window_proxy (WindowProxyBase
* p
)
3646 _window_proxies
.remove (p
);
3650 ARDOUR_UI::missing_file (Session
*s
, std::string str
, DataType type
)
3652 MissingFileDialog
dialog (s
, str
, type
);
3657 int result
= dialog
.run ();
3664 return 1; // quit entire session load
3667 result
= dialog
.get_action ();
3673 ARDOUR_UI::ambiguous_file (std::string file
, std::string path
, std::vector
<std::string
> hits
)
3675 AmbiguousFileDialog
dialog (file
, hits
);
3681 return dialog
.get_which ();