more NSD changes. if JACK is not running and no interface has ever been chosen, show...
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blob4f57dec90516910d382265328717c06cb6c4ade5
1 /*
2 Copyright (C) 1999-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <algorithm>
21 #include <cmath>
22 #include <fcntl.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <time.h>
26 #include <cerrno>
27 #include <fstream>
29 #include <iostream>
31 #include <sys/resource.h>
33 #include <gtkmm/messagedialog.h>
34 #include <gtkmm/accelmap.h>
36 #include <pbd/error.h>
37 #include <pbd/basename.h>
38 #include <pbd/compose.h>
39 #include <pbd/pathscanner.h>
40 #include <pbd/failed_constructor.h>
41 #include <pbd/enumwriter.h>
42 #include <pbd/stacktrace.h>
43 #include <gtkmm2ext/gtk_ui.h>
44 #include <gtkmm2ext/utils.h>
45 #include <gtkmm2ext/click_box.h>
46 #include <gtkmm2ext/fastmeter.h>
47 #include <gtkmm2ext/stop_signal.h>
48 #include <gtkmm2ext/popup.h>
49 #include <gtkmm2ext/window_title.h>
51 #include <midi++/port.h>
52 #include <midi++/mmc.h>
54 #include <ardour/ardour.h>
55 #include <ardour/profile.h>
56 #include <ardour/session_route.h>
57 #include <ardour/port.h>
58 #include <ardour/audioengine.h>
59 #include <ardour/playlist.h>
60 #include <ardour/utils.h>
61 #include <ardour/plugin.h>
62 #include <ardour/audio_diskstream.h>
63 #include <ardour/audiofilesource.h>
64 #include <ardour/recent_sessions.h>
65 #include <ardour/port.h>
66 #include <ardour/audio_track.h>
68 typedef uint64_t microseconds_t;
70 #include "actions.h"
71 #include "ardour_ui.h"
72 #include "public_editor.h"
73 #include "audio_clock.h"
74 #include "keyboard.h"
75 #include "mixer_ui.h"
76 #include "prompter.h"
77 #include "opts.h"
78 #include "add_route_dialog.h"
79 #include "new_session_dialog.h"
80 #include "about.h"
81 #include "splash.h"
82 #include "nag.h"
83 #include "utils.h"
84 #include "gui_thread.h"
85 #include "theme_manager.h"
86 #include "engine_dialog.h"
87 #include "gain_meter.h"
88 #include "route_time_axis.h"
90 #include "i18n.h"
92 using namespace ARDOUR;
93 using namespace PBD;
94 using namespace Gtkmm2ext;
95 using namespace Gtk;
96 using namespace sigc;
98 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
99 UIConfiguration *ARDOUR_UI::ui_config = 0;
101 sigc::signal<void,bool> ARDOUR_UI::Blink;
102 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
103 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
104 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
106 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
108 : Gtkmm2ext::UI (X_("Ardour"), argcp, argvp),
110 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true),
111 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true),
112 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
113 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
115 /* preroll stuff */
117 preroll_button (_("pre\nroll")),
118 postroll_button (_("post\nroll")),
120 /* big clock */
122 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, false, true),
124 /* transport */
126 roll_controllable ("transport roll", *this, TransportControllable::Roll),
127 stop_controllable ("transport stop", *this, TransportControllable::Stop),
128 goto_start_controllable ("transport goto start", *this, TransportControllable::GotoStart),
129 goto_end_controllable ("transport goto end", *this, TransportControllable::GotoEnd),
130 auto_loop_controllable ("transport auto loop", *this, TransportControllable::AutoLoop),
131 play_selection_controllable ("transport play selection", *this, TransportControllable::PlaySelection),
132 rec_controllable ("transport rec-enable", *this, TransportControllable::RecordEnable),
133 shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl),
134 shuttle_controller_binding_proxy (shuttle_controllable),
136 roll_button (&roll_controllable),
137 stop_button (&stop_controllable),
138 goto_start_button (&goto_start_controllable),
139 goto_end_button (&goto_end_controllable),
140 auto_loop_button (&auto_loop_controllable),
141 play_selection_button (&play_selection_controllable),
142 rec_button (&rec_controllable),
144 shuttle_units_button (_("% ")),
146 punch_in_button (_("Punch In")),
147 punch_out_button (_("Punch Out")),
148 auto_return_button (_("Auto Return")),
149 auto_play_button (_("Auto Play")),
150 auto_input_button (_("Auto Input")),
151 click_button (_("Click")),
152 time_master_button (_("time\nmaster")),
154 auditioning_alert_button (_("AUDITION")),
155 solo_alert_button (_("SOLO")),
156 shown_flag (false),
157 error_log_button (_("Errors"))
159 using namespace Gtk::Menu_Helpers;
161 Gtkmm2ext::init();
163 #ifdef TOP_MENUBAR
164 _auto_display_errors = false;
165 #endif
167 about = 0;
168 splash = 0;
170 if (ARDOUR_COMMAND_LINE::session_name.length()) {
171 /* only show this if we're not going to post the new session dialog */
172 show_splash ();
175 if (theArdourUI == 0) {
176 theArdourUI = this;
179 ui_config = new UIConfiguration();
180 theme_manager = new ThemeManager();
182 engine = 0;
183 editor = 0;
184 mixer = 0;
185 session = 0;
186 _session_is_new = false;
187 big_clock_window = 0;
188 session_selector_window = 0;
189 new_session_dialog = 0;
190 last_key_press_time = 0;
191 connection_editor = 0;
192 add_route_dialog = 0;
193 route_params = 0;
194 option_editor = 0;
195 location_ui = 0;
196 key_editor = 0;
197 open_session_selector = 0;
198 have_configure_timeout = false;
199 have_disk_speed_dialog_displayed = false;
200 _will_create_new_session_automatically = false;
201 session_loaded = false;
202 last_speed_displayed = -1.0f;
203 ignore_dual_punch = false;
204 _mixer_on_top = false;
206 roll_button.unset_flags (Gtk::CAN_FOCUS);
207 stop_button.unset_flags (Gtk::CAN_FOCUS);
208 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
209 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
210 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
211 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
212 rec_button.unset_flags (Gtk::CAN_FOCUS);
214 last_configure_time= 0;
216 shuttle_grabbed = false;
217 shuttle_fract = 0.0;
218 shuttle_max_speed = 8.0f;
220 shuttle_style_menu = 0;
221 shuttle_unit_menu = 0;
223 // We do not have jack linked in yet so;
225 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
227 ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
228 ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
230 ARDOUR::Plugin::PresetFileExists.connect (mem_fun(*this, &ARDOUR_UI::preset_file_exists_handler));
232 /* handle dialog requests */
234 ARDOUR::Session::Dialog.connect (mem_fun(*this, &ARDOUR_UI::session_dialog));
236 /* handle pending state with a dialog */
238 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
240 /* handle sr mismatch with a dialog */
242 ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
244 /* lets get this party started */
246 try {
247 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
248 throw failed_constructor ();
251 setup_gtk_ardour_enums ();
252 Config->set_current_owner (ConfigVariableBase::Interface);
253 setup_profile ();
255 GainMeter::setup_slider_pix ();
256 RouteTimeAxisView::setup_slider_pix ();
258 } catch (failed_constructor& err) {
259 error << _("could not initialize Ardour.") << endmsg;
260 // pass it on up
261 throw;
264 /* we like keyboards */
266 keyboard = new Keyboard;
268 reset_dpi();
270 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
271 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
273 platform_setup ();
277 ARDOUR_UI::create_engine ()
279 // this gets called every time by new_session()
281 if (engine) {
282 return 0;
285 loading_message (_("Starting audio engine"));
287 try {
288 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
290 } catch (...) {
292 return -1;
295 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
296 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
297 engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
298 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
300 post_engine ();
302 return 0;
305 void
306 ARDOUR_UI::post_engine ()
308 /* Things to be done once we create the AudioEngine
311 check_memory_locking();
313 ActionManager::init ();
314 _tooltips.enable();
316 if (setup_windows ()) {
317 throw failed_constructor ();
320 /* this is the first point at which all the keybindings are available */
322 if (ARDOUR_COMMAND_LINE::show_key_actions) {
323 vector<string> names;
324 vector<string> paths;
325 vector<string> keys;
326 vector<AccelKey> bindings;
328 ActionManager::get_all_actions (names, paths, keys, bindings);
330 vector<string>::iterator n;
331 vector<string>::iterator k;
332 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
333 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
336 exit (0);
339 blink_timeout_tag = -1;
341 /* the global configuration object is now valid */
343 use_config ();
345 /* this being a GUI and all, we want peakfiles */
347 AudioFileSource::set_build_peakfiles (true);
348 AudioFileSource::set_build_missing_peakfiles (true);
350 /* set default clock modes */
352 if (Profile->get_sae()) {
353 primary_clock.set_mode (AudioClock::BBT);
354 secondary_clock.set_mode (AudioClock::MinSec);
355 } else {
356 primary_clock.set_mode (AudioClock::SMPTE);
357 secondary_clock.set_mode (AudioClock::BBT);
360 /* start the time-of-day-clock */
362 #ifndef GTKOSX
363 /* OS X provides an always visible wallclock, so don't be stupid */
364 update_wall_clock ();
365 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
366 #endif
368 update_disk_space ();
369 update_cpu_load ();
370 update_sample_rate (engine->frame_rate());
372 platform_specific ();
374 /* now start and maybe save state */
376 if (do_engine_start () == 0) {
377 if (session && _session_is_new) {
378 /* we need to retain initial visual
379 settings for a new session
381 session->save_state ("");
386 ARDOUR_UI::~ARDOUR_UI ()
388 save_ardour_state ();
390 if (keyboard) {
391 delete keyboard;
394 if (editor) {
395 delete editor;
398 if (mixer) {
399 delete mixer;
402 if (add_route_dialog) {
403 delete add_route_dialog;
406 if (new_session_dialog) {
407 delete new_session_dialog;
411 void
412 ARDOUR_UI::pop_back_splash ()
414 if (Splash::instance()) {
415 // Splash::instance()->pop_back();
416 Splash::instance()->hide ();
420 gint
421 ARDOUR_UI::configure_timeout ()
423 if (last_configure_time == 0) {
424 /* no configure events yet */
425 return TRUE;
428 /* force a gap of 0.5 seconds since the last configure event
431 if (get_microseconds() - last_configure_time < 500000) {
432 return TRUE;
433 } else {
434 have_configure_timeout = false;
435 save_ardour_state ();
436 return FALSE;
440 gboolean
441 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
443 if (have_configure_timeout) {
444 last_configure_time = get_microseconds();
445 } else {
446 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
447 have_configure_timeout = true;
450 return FALSE;
453 void
454 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
456 const XMLProperty* prop;
458 if ((prop = node.property ("roll")) != 0) {
459 roll_controllable.set_id (prop->value());
461 if ((prop = node.property ("stop")) != 0) {
462 stop_controllable.set_id (prop->value());
464 if ((prop = node.property ("goto_start")) != 0) {
465 goto_start_controllable.set_id (prop->value());
467 if ((prop = node.property ("goto_end")) != 0) {
468 goto_end_controllable.set_id (prop->value());
470 if ((prop = node.property ("auto_loop")) != 0) {
471 auto_loop_controllable.set_id (prop->value());
473 if ((prop = node.property ("play_selection")) != 0) {
474 play_selection_controllable.set_id (prop->value());
476 if ((prop = node.property ("rec")) != 0) {
477 rec_controllable.set_id (prop->value());
479 if ((prop = node.property ("shuttle")) != 0) {
480 shuttle_controllable.set_id (prop->value());
484 XMLNode&
485 ARDOUR_UI::get_transport_controllable_state ()
487 XMLNode* node = new XMLNode(X_("TransportControllables"));
488 char buf[64];
490 roll_controllable.id().print (buf, sizeof (buf));
491 node->add_property (X_("roll"), buf);
492 stop_controllable.id().print (buf, sizeof (buf));
493 node->add_property (X_("stop"), buf);
494 goto_start_controllable.id().print (buf, sizeof (buf));
495 node->add_property (X_("goto_start"), buf);
496 goto_end_controllable.id().print (buf, sizeof (buf));
497 node->add_property (X_("goto_end"), buf);
498 auto_loop_controllable.id().print (buf, sizeof (buf));
499 node->add_property (X_("auto_loop"), buf);
500 play_selection_controllable.id().print (buf, sizeof (buf));
501 node->add_property (X_("play_selection"), buf);
502 rec_controllable.id().print (buf, sizeof (buf));
503 node->add_property (X_("rec"), buf);
504 shuttle_controllable.id().print (buf, sizeof (buf));
505 node->add_property (X_("shuttle"), buf);
507 return *node;
510 void
511 ARDOUR_UI::save_ardour_state ()
513 if (!keyboard || !mixer || !editor) {
514 return;
517 /* XXX this is all a bit dubious. add_extra_xml() uses
518 a different lifetime model from add_instant_xml().
521 XMLNode* node = new XMLNode (keyboard->get_state());
522 Config->add_extra_xml (*node);
523 Config->add_extra_xml (get_transport_controllable_state());
524 if (new_session_dialog) {
525 if (new_session_dialog->engine_control.was_used()) {
526 Config->add_extra_xml (new_session_dialog->engine_control.get_state());
529 Config->save_state();
530 ui_config->save_state ();
532 XMLNode enode(static_cast<Stateful*>(editor)->get_state());
533 XMLNode mnode(mixer->get_state());
535 if (session) {
536 session->add_instant_xml (enode, session->path());
537 session->add_instant_xml (mnode, session->path());
538 } else {
539 Config->add_instant_xml (enode, get_user_ardour_path());
540 Config->add_instant_xml (mnode, get_user_ardour_path());
543 Keyboard::save_keybindings ();
546 gint
547 ARDOUR_UI::autosave_session ()
549 if (g_main_depth() > 1) {
550 /* inside a recursive main loop,
551 give up because we may not be able to
552 take a lock.
554 return 1;
557 if (!Config->get_periodic_safety_backups())
558 return 1;
560 if (session) {
561 session->maybe_write_autosave();
564 return 1;
567 void
568 ARDOUR_UI::update_autosave ()
570 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
572 if (session->dirty()) {
573 if (_autosave_connection.connected()) {
574 _autosave_connection.disconnect();
577 _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
578 Config->get_periodic_safety_backup_interval() * 1000);
580 } else {
581 if (_autosave_connection.connected()) {
582 _autosave_connection.disconnect();
587 void
588 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
590 string title;
591 if (we_set_params) {
592 title = _("Ardour could not start JACK");
593 } else {
594 title = _("Ardour could not connect to JACK.");
597 MessageDialog win (title,
598 false,
599 Gtk::MESSAGE_INFO,
600 Gtk::BUTTONS_NONE);
602 if (we_set_params) {
603 win.set_secondary_text(_("There are several possible reasons:\n\
605 1) You requested audio parameters that are not supported..\n\
606 2) JACK is running as another user.\n\
608 Please consider the possibilities, and perhaps try different parameters."));
609 } else {
610 win.set_secondary_text(_("There are several possible reasons:\n\
612 1) JACK is not running.\n\
613 2) JACK is running as another user, perhaps root.\n\
614 3) There is already another client called \"ardour\".\n\
616 Please consider the possibilities, and perhaps (re)start JACK."));
619 if (toplevel) {
620 win.set_transient_for (*toplevel);
623 if (we_set_params) {
624 win.add_button (Stock::OK, RESPONSE_CLOSE);
625 } else {
626 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
629 win.set_default_response (RESPONSE_CLOSE);
631 win.show_all ();
632 win.set_position (Gtk::WIN_POS_CENTER);
633 pop_back_splash ();
635 /* we just don't care about the result, but we want to block */
637 win.run ();
640 void
641 ARDOUR_UI::startup ()
643 string name, path;
645 new_session_dialog = new NewSessionDialog();
647 bool backend_audio_is_running = EngineControl::engine_running();
648 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
650 if (audio_setup) {
651 new_session_dialog->engine_control.set_state (*audio_setup);
654 if (!get_session_parameters (backend_audio_is_running, ARDOUR_COMMAND_LINE::new_session)) {
655 return;
658 BootMessage (_("Ardour is ready for use"));
659 show ();
662 void
663 ARDOUR_UI::no_memory_warning ()
665 XMLNode node (X_("no-memory-warning"));
666 Config->add_instant_xml (node, get_user_ardour_path());
669 void
670 ARDOUR_UI::check_memory_locking ()
672 #ifdef __APPLE__
673 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
674 return;
675 #else // !__APPLE__
677 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path());
679 if (engine->is_realtime() && memory_warning_node == 0) {
681 struct rlimit limits;
682 int64_t ram;
683 long pages, page_size;
685 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
686 ram = 0;
687 } else {
688 ram = (int64_t) pages * (int64_t) page_size;
691 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
692 return;
695 if (limits.rlim_cur != RLIM_INFINITY) {
697 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
700 MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. "
701 "This might cause Ardour to run out of memory before your system "
702 "runs out of memory. \n\n"
703 "You can view the memory limit with 'ulimit -l', "
704 "and it is normally controlled by /etc/security/limits.conf"));
706 VBox* vbox = msg.get_vbox();
707 HBox hbox;
708 CheckButton cb (_("Do not show this window again"));
710 cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning));
712 hbox.pack_start (cb, true, false);
713 vbox->pack_start (hbox);
714 hbox.show_all ();
716 pop_back_splash ();
718 msg.run ();
722 #endif // !__APPLE__
726 void
727 ARDOUR_UI::finish()
729 if (session) {
731 if (session->transport_rolling()) {
732 session->request_stop ();
733 usleep (2500000);
736 if (session->dirty()) {
737 switch (ask_about_saving_session(_("quit"))) {
738 case -1:
739 return;
740 break;
741 case 1:
742 /* use the default name */
743 if (save_state_canfail ("")) {
744 /* failed - don't quit */
745 MessageDialog msg (*editor,
746 _("\
747 Ardour was unable to save your session.\n\n\
748 If you still wish to quit, please use the\n\n\
749 \"Just quit\" option."));
750 pop_back_splash();
751 msg.run ();
752 return;
754 break;
755 case 0:
756 break;
760 session->set_deletion_in_progress ();
763 ArdourDialog::close_all_dialogs ();
764 engine->stop (true);
765 save_ardour_state ();
766 quit ();
770 ARDOUR_UI::ask_about_saving_session (const string & what)
772 ArdourDialog window (_("ardour: save session?"));
773 Gtk::HBox dhbox; // the hbox for the image and text
774 Gtk::Label prompt_label;
775 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
777 string msg;
779 msg = string_compose(_("Don't %1"), what);
780 window.add_button (msg, RESPONSE_REJECT);
781 msg = string_compose(_("Just %1"), what);
782 window.add_button (msg, RESPONSE_APPLY);
783 msg = string_compose(_("Save and %1"), what);
784 window.add_button (msg, RESPONSE_ACCEPT);
786 window.set_default_response (RESPONSE_ACCEPT);
788 Gtk::Button noquit_button (msg);
789 noquit_button.set_name ("EditorGTKButton");
791 string prompt;
792 string type;
794 if (session->snap_name() == session->name()) {
795 type = _("session");
796 } else {
797 type = _("snapshot");
799 prompt = string_compose(_("The %1\"%2\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
800 type, session->snap_name());
802 prompt_label.set_text (prompt);
803 prompt_label.set_name (X_("PrompterLabel"));
804 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
806 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
808 dhbox.set_homogeneous (false);
809 dhbox.pack_start (*dimage, false, false, 5);
810 dhbox.pack_start (prompt_label, true, false, 5);
811 window.get_vbox()->pack_start (dhbox);
813 window.set_name (_("Prompter"));
814 window.set_position (Gtk::WIN_POS_MOUSE);
815 window.set_modal (true);
816 window.set_resizable (false);
817 window.show_all ();
819 window.set_keep_above (true);
820 window.present ();
822 ResponseType r = (ResponseType) window.run();
824 window.hide ();
826 switch (r) {
827 case RESPONSE_ACCEPT: // save and get out of here
828 return 1;
829 case RESPONSE_APPLY: // get out of here
830 return 0;
831 default:
832 break;
835 return -1;
839 ARDOUR_UI::every_second ()
841 update_cpu_load ();
842 update_buffer_load ();
843 update_disk_space ();
844 return TRUE;
847 gint
848 ARDOUR_UI::every_point_one_seconds ()
850 update_speed_display ();
851 RapidScreenUpdate(); /* EMIT_SIGNAL */
852 return TRUE;
855 gint
856 ARDOUR_UI::every_point_zero_one_seconds ()
858 // august 2007: actual update frequency: 40Hz, not 100Hz
860 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
861 return TRUE;
864 void
865 ARDOUR_UI::update_sample_rate (nframes_t ignored)
867 char buf[32];
869 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
871 if (!engine->connected()) {
873 snprintf (buf, sizeof (buf), _("disconnected"));
875 } else {
877 nframes_t rate = engine->frame_rate();
879 if (fmod (rate, 1000.0) != 0.0) {
880 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
881 (float) rate/1000.0f,
882 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
883 } else {
884 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
885 rate/1000,
886 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
890 sample_rate_label.set_text (buf);
893 void
894 ARDOUR_UI::update_cpu_load ()
896 char buf[32];
897 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
898 cpu_load_label.set_text (buf);
901 void
902 ARDOUR_UI::update_buffer_load ()
904 char buf[64];
905 uint32_t c, p;
907 if (session) {
908 c = session->capture_load ();
909 p = session->playback_load ();
911 push_buffer_stats (c, p);
913 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
914 session->playback_load(), session->capture_load());
915 buffer_load_label.set_text (buf);
916 } else {
917 buffer_load_label.set_text ("");
921 void
922 ARDOUR_UI::count_recenabled_streams (Route& route)
924 Track* track = dynamic_cast<Track*>(&route);
925 if (track && track->diskstream()->record_enabled()) {
926 rec_enabled_streams += track->n_inputs();
930 void
931 ARDOUR_UI::update_disk_space()
933 if (session == 0) {
934 return;
937 nframes_t frames = session->available_capture_duration();
938 char buf[64];
940 if (frames == max_frames) {
941 strcpy (buf, _("Disk: 24hrs+"));
942 } else {
943 int hrs;
944 int mins;
945 int secs;
946 nframes_t fr = session->frame_rate();
948 rec_enabled_streams = 0;
949 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
951 if (rec_enabled_streams) {
952 frames /= rec_enabled_streams;
955 hrs = frames / (fr * 3600);
956 frames -= hrs * fr * 3600;
957 mins = frames / (fr * 60);
958 frames -= mins * fr * 60;
959 secs = frames / fr;
961 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
964 disk_space_label.set_text (buf);
967 gint
968 ARDOUR_UI::update_wall_clock ()
970 time_t now;
971 struct tm *tm_now;
972 char buf[16];
974 time (&now);
975 tm_now = localtime (&now);
977 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
978 wall_clock_label.set_text (buf);
980 return TRUE;
983 gint
984 ARDOUR_UI::session_menu (GdkEventButton *ev)
986 session_popup_menu->popup (0, 0);
987 return TRUE;
990 void
991 ARDOUR_UI::redisplay_recent_sessions ()
993 vector<string *> *sessions;
994 vector<string *>::iterator i;
995 RecentSessionsSorter cmp;
997 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
998 recent_session_model->clear ();
1000 RecentSessions rs;
1001 ARDOUR::read_recent_sessions (rs);
1003 if (rs.empty()) {
1004 recent_session_display.set_model (recent_session_model);
1005 return;
1008 /* sort them alphabetically */
1009 sort (rs.begin(), rs.end(), cmp);
1010 sessions = new vector<string*>;
1012 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1013 sessions->push_back (new string ((*i).second));
1016 for (i = sessions->begin(); i != sessions->end(); ++i) {
1018 vector<string*>* states;
1019 vector<const gchar*> item;
1020 string fullpath = *(*i);
1022 /* remove any trailing / */
1024 if (fullpath[fullpath.length()-1] == '/') {
1025 fullpath = fullpath.substr (0, fullpath.length()-1);
1028 /* check whether session still exists */
1029 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1030 /* session doesn't exist */
1031 cerr << "skipping non-existent session " << fullpath << endl;
1032 continue;
1035 /* now get available states for this session */
1037 if ((states = Session::possible_states (fullpath)) == 0) {
1038 /* no state file? */
1039 continue;
1042 TreeModel::Row row = *(recent_session_model->append());
1044 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1045 row[recent_session_columns.fullpath] = fullpath;
1047 if (states->size() > 1) {
1049 /* add the children */
1051 for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
1053 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1055 child_row[recent_session_columns.visible_name] = **i2;
1056 child_row[recent_session_columns.fullpath] = fullpath;
1058 delete *i2;
1062 delete states;
1065 recent_session_display.set_model (recent_session_model);
1066 delete sessions;
1069 void
1070 ARDOUR_UI::build_session_selector ()
1072 session_selector_window = new ArdourDialog ("session selector");
1074 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1076 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1077 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1078 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1079 recent_session_model = TreeStore::create (recent_session_columns);
1080 recent_session_display.set_model (recent_session_model);
1081 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1082 recent_session_display.set_headers_visible (false);
1083 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1084 recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1086 scroller->add (recent_session_display);
1087 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1089 session_selector_window->set_name ("SessionSelectorWindow");
1090 session_selector_window->set_size_request (200, 400);
1091 session_selector_window->get_vbox()->pack_start (*scroller);
1092 session_selector_window->show_all_children();
1095 void
1096 ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
1098 session_selector_window->response (RESPONSE_ACCEPT);
1101 void
1102 ARDOUR_UI::open_recent_session ()
1104 bool can_return = (session != 0);
1106 if (session_selector_window == 0) {
1107 build_session_selector ();
1110 redisplay_recent_sessions ();
1112 while (true) {
1114 session_selector_window->set_position (WIN_POS_MOUSE);
1116 ResponseType r = (ResponseType) session_selector_window->run ();
1118 switch (r) {
1119 case RESPONSE_ACCEPT:
1120 break;
1121 default:
1122 if (can_return) {
1123 session_selector_window->hide();
1124 return;
1125 } else {
1126 exit (1);
1130 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1131 continue;
1134 session_selector_window->hide();
1136 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1138 if (i == recent_session_model->children().end()) {
1139 return;
1142 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1143 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1145 _session_is_new = false;
1147 if (load_session (path, state) == 0) {
1148 break;
1151 can_return = false;
1155 bool
1156 ARDOUR_UI::check_audioengine ()
1158 if (engine) {
1159 if (!engine->connected()) {
1160 MessageDialog msg (_("Ardour is not connected to JACK\n"
1161 "You cannot open or close sessions in this condition"));
1162 pop_back_splash ();
1163 msg.run ();
1164 return false;
1166 return true;
1167 } else {
1168 return false;
1172 void
1173 ARDOUR_UI::open_session ()
1175 if (!check_audioengine()) {
1176 return;
1179 /* popup selector window */
1181 if (open_session_selector == 0) {
1183 /* ardour sessions are folders */
1185 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
1186 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1187 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1188 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1190 FileFilter session_filter;
1191 session_filter.add_pattern ("*.ardour");
1192 session_filter.set_name (_("Ardour sessions"));
1193 open_session_selector->add_filter (session_filter);
1194 open_session_selector->set_filter (session_filter);
1197 int response = open_session_selector->run();
1198 open_session_selector->hide ();
1200 switch (response) {
1201 case RESPONSE_ACCEPT:
1202 break;
1203 default:
1204 open_session_selector->hide();
1205 return;
1208 open_session_selector->hide();
1209 string session_path = open_session_selector->get_filename();
1210 string path, name;
1211 bool isnew;
1213 if (session_path.length() > 0) {
1214 if (Session::find_session (session_path, path, name, isnew) == 0) {
1215 _session_is_new = isnew;
1216 load_session (path, name);
1222 void
1223 ARDOUR_UI::session_add_midi_track ()
1225 cerr << _("Patience is a virtue.\n");
1228 void
1229 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
1231 list<boost::shared_ptr<AudioTrack> > tracks;
1232 Session::RouteList routes;
1234 if (session == 0) {
1235 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1236 return;
1239 try {
1240 if (track) {
1241 tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
1243 if (tracks.size() != how_many) {
1244 if (how_many == 1) {
1245 error << _("could not create a new audio track") << endmsg;
1246 } else {
1247 error << string_compose (_("could only create %1 of %2 new audio %3"),
1248 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1252 } else {
1254 routes = session->new_audio_route (input_channels, output_channels, how_many);
1256 if (routes.size() != how_many) {
1257 if (how_many == 1) {
1258 error << _("could not create a new audio track") << endmsg;
1259 } else {
1260 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1265 #if CONTROLOUTS
1266 if (need_control_room_outs) {
1267 pan_t pans[2];
1269 pans[0] = 0.5;
1270 pans[1] = 0.5;
1272 route->set_stereo_control_outs (control_lr_channels);
1273 route->control_outs()->set_stereo_pan (pans, this);
1275 #endif /* CONTROLOUTS */
1278 catch (...) {
1279 MessageDialog msg (*editor,
1280 _("There are insufficient JACK ports available\n\
1281 to create a new track or bus.\n\
1282 You should save Ardour, exit and\n\
1283 restart JACK with more ports."));
1284 pop_back_splash ();
1285 msg.run ();
1289 void
1290 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1292 nframes_t _preroll = 0;
1294 if (session) {
1295 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1296 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1298 if (new_position > _preroll) {
1299 new_position -= _preroll;
1300 } else {
1301 new_position = 0;
1304 session->request_locate (new_position);
1308 void
1309 ARDOUR_UI::transport_goto_start ()
1311 if (session) {
1312 session->goto_start();
1315 /* force displayed area in editor to start no matter
1316 what "follow playhead" setting is.
1319 if (editor) {
1320 editor->reset_x_origin (session->current_start_frame());
1325 void
1326 ARDOUR_UI::transport_goto_zero ()
1328 if (session) {
1329 session->request_locate (0);
1332 /* force displayed area in editor to start no matter
1333 what "follow playhead" setting is.
1336 if (editor) {
1337 editor->reset_x_origin (0);
1342 void
1343 ARDOUR_UI::transport_goto_wallclock ()
1345 if (session && editor) {
1347 time_t now;
1348 struct tm tmnow;
1349 nframes64_t frames;
1351 time (&now);
1352 localtime_r (&now, &tmnow);
1354 frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
1355 frames += tmnow.tm_min * (60 * session->frame_rate());
1356 frames += tmnow.tm_sec * session->frame_rate();
1358 session->request_locate (frames);
1360 /* force displayed area in editor to start no matter
1361 what "follow playhead" setting is.
1364 if (editor) {
1365 editor->reset_x_origin (frames - (editor->current_page_frames()/2));
1370 void
1371 ARDOUR_UI::transport_goto_end ()
1373 if (session) {
1374 nframes_t frame = session->current_end_frame();
1375 session->request_locate (frame);
1377 /* force displayed area in editor to start no matter
1378 what "follow playhead" setting is.
1381 if (editor) {
1382 editor->reset_x_origin (frame);
1387 void
1388 ARDOUR_UI::transport_stop ()
1390 if (!session) {
1391 return;
1394 if (session->is_auditioning()) {
1395 session->cancel_audition ();
1396 return;
1399 if (session->get_play_loop ()) {
1400 session->request_play_loop (false);
1403 session->request_stop ();
1406 void
1407 ARDOUR_UI::transport_stop_and_forget_capture ()
1409 if (session) {
1410 session->request_stop (true);
1414 void
1415 ARDOUR_UI::remove_last_capture()
1417 if (editor) {
1418 editor->remove_last_capture();
1422 void
1423 ARDOUR_UI::transport_record (bool roll)
1426 if (session) {
1427 switch (session->record_status()) {
1428 case Session::Disabled:
1429 if (session->ntracks() == 0) {
1430 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1431 msg.run ();
1432 return;
1434 session->maybe_enable_record ();
1435 if (roll) {
1436 transport_roll ();
1438 break;
1439 case Session::Recording:
1440 if (roll) {
1441 session->request_stop();
1442 } else {
1443 session->disable_record (false, true);
1445 break;
1447 case Session::Enabled:
1448 session->disable_record (false, true);
1451 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1454 void
1455 ARDOUR_UI::transport_roll ()
1457 bool rolling;
1459 if (!session) {
1460 return;
1463 rolling = session->transport_rolling ();
1465 //cerr << "ARDOUR_UI::transport_roll () called session->record_status() = " << session->record_status() << endl;
1467 if (session->get_play_loop()) {
1468 session->request_play_loop (false);
1469 auto_loop_button.set_visual_state (1);
1470 roll_button.set_visual_state (1);
1471 } else if (session->get_play_range ()) {
1472 session->request_play_range (false);
1473 play_selection_button.set_visual_state (0);
1474 } else if (rolling) {
1475 session->request_locate (session->last_transport_start(), true);
1478 session->request_transport_speed (1.0f);
1481 void
1482 ARDOUR_UI::transport_loop()
1484 if (session) {
1485 if (session->get_play_loop()) {
1486 if (session->transport_rolling()) {
1487 Location * looploc = session->locations()->auto_loop_location();
1488 if (looploc) {
1489 session->request_locate (looploc->start(), true);
1493 else {
1494 session->request_play_loop (true);
1499 void
1500 ARDOUR_UI::transport_play_selection ()
1502 if (!session) {
1503 return;
1506 if (!session->get_play_range()) {
1507 session->request_stop ();
1510 editor->play_selection ();
1513 void
1514 ARDOUR_UI::transport_rewind (int option)
1516 float current_transport_speed;
1518 if (session) {
1519 current_transport_speed = session->transport_speed();
1521 if (current_transport_speed >= 0.0f) {
1522 switch (option) {
1523 case 0:
1524 session->request_transport_speed (-1.0f);
1525 break;
1526 case 1:
1527 session->request_transport_speed (-4.0f);
1528 break;
1529 case -1:
1530 session->request_transport_speed (-0.5f);
1531 break;
1533 } else {
1534 /* speed up */
1535 session->request_transport_speed (current_transport_speed * 1.5f);
1540 void
1541 ARDOUR_UI::transport_forward (int option)
1543 float current_transport_speed;
1545 if (session) {
1546 current_transport_speed = session->transport_speed();
1548 if (current_transport_speed <= 0.0f) {
1549 switch (option) {
1550 case 0:
1551 session->request_transport_speed (1.0f);
1552 break;
1553 case 1:
1554 session->request_transport_speed (4.0f);
1555 break;
1556 case -1:
1557 session->request_transport_speed (0.5f);
1558 break;
1560 } else {
1561 /* speed up */
1562 session->request_transport_speed (current_transport_speed * 1.5f);
1567 void
1568 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1570 if (session == 0) {
1571 return;
1574 boost::shared_ptr<Route> r;
1576 if ((r = session->route_by_remote_id (dstream)) != 0) {
1578 Track* t;
1580 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1581 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1584 if (session == 0) {
1585 return;
1589 void
1590 ARDOUR_UI::queue_transport_change ()
1592 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1595 void
1596 ARDOUR_UI::map_transport_state ()
1598 float sp = session->transport_speed();
1600 if (sp == 1.0f) {
1601 transport_rolling ();
1602 } else if (sp < 0.0f) {
1603 transport_rewinding ();
1604 } else if (sp > 0.0f) {
1605 transport_forwarding ();
1606 } else {
1607 transport_stopped ();
1611 void
1612 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1614 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1615 (int) adj.get_value()].c_str());
1618 void
1619 ARDOUR_UI::engine_stopped ()
1621 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1622 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1623 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1626 void
1627 ARDOUR_UI::engine_running ()
1629 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1630 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1631 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1633 Glib::RefPtr<Action> action;
1634 const char* action_name = 0;
1636 switch (engine->frames_per_cycle()) {
1637 case 32:
1638 action_name = X_("JACKLatency32");
1639 break;
1640 case 64:
1641 action_name = X_("JACKLatency64");
1642 break;
1643 case 128:
1644 action_name = X_("JACKLatency128");
1645 break;
1646 case 512:
1647 action_name = X_("JACKLatency512");
1648 break;
1649 case 1024:
1650 action_name = X_("JACKLatency1024");
1651 break;
1652 case 2048:
1653 action_name = X_("JACKLatency2048");
1654 break;
1655 case 4096:
1656 action_name = X_("JACKLatency4096");
1657 break;
1658 case 8192:
1659 action_name = X_("JACKLatency8192");
1660 break;
1661 default:
1662 /* XXX can we do anything useful ? */
1663 break;
1666 if (action_name) {
1668 action = ActionManager::get_action (X_("JACK"), action_name);
1670 if (action) {
1671 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1672 ract->set_active ();
1677 void
1678 ARDOUR_UI::engine_halted ()
1680 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1682 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1683 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1685 update_sample_rate (0);
1687 MessageDialog msg (*editor,
1688 _("\
1689 JACK has either been shutdown or it\n\
1690 disconnected Ardour because Ardour\n\
1691 was not fast enough. Try to restart\n\
1692 JACK, reconnect and save the session."));
1693 pop_back_splash ();
1694 msg.run ();
1697 int32_t
1698 ARDOUR_UI::do_engine_start ()
1700 try {
1701 engine->start();
1704 catch (...) {
1705 engine->stop ();
1706 error << _("Unable to start the session running")
1707 << endmsg;
1708 unload_session ();
1709 return -2;
1712 return 0;
1715 void
1716 ARDOUR_UI::setup_theme ()
1718 theme_manager->setup_theme();
1721 void
1722 ARDOUR_UI::update_clocks ()
1724 if (!editor || !editor->dragging_playhead()) {
1725 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1729 void
1730 ARDOUR_UI::start_clocking ()
1732 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1735 void
1736 ARDOUR_UI::stop_clocking ()
1738 clock_signal_connection.disconnect ();
1741 void
1742 ARDOUR_UI::toggle_clocking ()
1744 #if 0
1745 if (clock_button.get_active()) {
1746 start_clocking ();
1747 } else {
1748 stop_clocking ();
1750 #endif
1753 gint
1754 ARDOUR_UI::_blink (void *arg)
1757 ((ARDOUR_UI *) arg)->blink ();
1758 return TRUE;
1761 void
1762 ARDOUR_UI::blink ()
1764 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1767 void
1768 ARDOUR_UI::start_blinking ()
1770 /* Start the blink signal. Everybody with a blinking widget
1771 uses Blink to drive the widget's state.
1774 if (blink_timeout_tag < 0) {
1775 blink_on = false;
1776 blink_timeout_tag = g_timeout_add (240, _blink, this);
1780 void
1781 ARDOUR_UI::stop_blinking ()
1783 if (blink_timeout_tag >= 0) {
1784 g_source_remove (blink_timeout_tag);
1785 blink_timeout_tag = -1;
1789 void
1790 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1791 string& buf,
1792 IO& io,
1793 bool in)
1795 if (in) {
1796 if (io.n_inputs() == 0) {
1797 buf = _("none");
1798 return;
1801 /* XXX we're not handling multiple ports yet. */
1803 const char **connections = io.input(0)->get_connections();
1805 if (connections == 0 || connections[0] == '\0') {
1806 buf = _("off");
1807 } else {
1808 buf = connections[0];
1811 free (connections);
1813 } else {
1815 if (io.n_outputs() == 0) {
1816 buf = _("none");
1817 return;
1820 /* XXX we're not handling multiple ports yet. */
1822 const char **connections = io.output(0)->get_connections();
1824 if (connections == 0 || connections[0] == '\0') {
1825 buf = _("off");
1826 } else {
1827 buf = connections[0];
1830 free (connections);
1834 /** Ask the user for the name of a new shapshot and then take it.
1836 void
1837 ARDOUR_UI::snapshot_session ()
1839 ArdourPrompter prompter (true);
1840 string snapname;
1841 char timebuf[128];
1842 time_t n;
1843 struct tm local_time;
1845 time (&n);
1846 localtime_r (&n, &local_time);
1847 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1849 prompter.set_name ("Prompter");
1850 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1851 prompter.set_prompt (_("Name of New Snapshot"));
1852 prompter.set_initial_text (timebuf);
1854 again:
1855 switch (prompter.run()) {
1856 case RESPONSE_ACCEPT:
1857 prompter.get_result (snapname);
1858 if (snapname.length()){
1859 if (snapname.find ('/') != string::npos) {
1860 MessageDialog msg (_("To ensure compatibility with various systems\n"
1861 "snapshot names may not contain a '/' character"));
1862 msg.run ();
1863 goto again;
1865 if (snapname.find ('\\') != string::npos) {
1866 MessageDialog msg (_("To ensure compatibility with various systems\n"
1867 "snapshot names may not contain a '\\' character"));
1868 msg.run ();
1869 goto again;
1871 save_state (snapname);
1873 break;
1875 default:
1876 break;
1880 void
1881 ARDOUR_UI::save_state (const string & name)
1883 (void) save_state_canfail (name);
1887 ARDOUR_UI::save_state_canfail (string name)
1889 if (session) {
1890 int ret;
1892 if (name.length() == 0) {
1893 name = session->snap_name();
1896 if ((ret = session->save_state (name)) != 0) {
1897 return ret;
1900 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1901 return 0;
1904 void
1905 ARDOUR_UI::primary_clock_value_changed ()
1907 if (session) {
1908 session->request_locate (primary_clock.current_time ());
1912 void
1913 ARDOUR_UI::big_clock_value_changed ()
1915 if (session) {
1916 session->request_locate (big_clock.current_time ());
1920 void
1921 ARDOUR_UI::secondary_clock_value_changed ()
1923 if (session) {
1924 session->request_locate (secondary_clock.current_time ());
1928 void
1929 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
1931 if (session == 0) {
1932 return;
1935 switch (session->record_status()) {
1936 case Session::Enabled:
1937 if (onoff) {
1938 rec_button.set_visual_state (2);
1939 } else {
1940 rec_button.set_visual_state (0);
1942 break;
1944 case Session::Recording:
1945 rec_button.set_visual_state (1);
1946 break;
1948 default:
1949 rec_button.set_visual_state (0);
1950 break;
1954 void
1955 ARDOUR_UI::save_template ()
1958 ArdourPrompter prompter (true);
1959 string name;
1961 if (!check_audioengine()) {
1962 return;
1965 prompter.set_name (X_("Prompter"));
1966 prompter.set_prompt (_("Name for mix template:"));
1967 prompter.set_initial_text(session->name() + _("-template"));
1968 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1970 switch (prompter.run()) {
1971 case RESPONSE_ACCEPT:
1972 prompter.get_result (name);
1974 if (name.length()) {
1975 session->save_template (name);
1977 break;
1979 default:
1980 break;
1984 void
1985 ARDOUR_UI::fontconfig_dialog ()
1987 #ifdef GTKOSX
1988 /* X11 users will always have fontconfig info around, but new GTK-OSX users
1989 may not and it can take a while to build it. Warn them.
1992 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
1994 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
1995 MessageDialog msg (*new_session_dialog,
1996 _("Welcome to Ardour.\n\n"
1997 "The program will take a bit longer to start up\n"
1998 "while the system fonts are checked.\n\n"
1999 "This will only be done once, and you will\n"
2000 "not see this message again\n"),
2001 true,
2002 Gtk::MESSAGE_INFO,
2003 Gtk::BUTTONS_OK);
2004 pop_back_splash ();
2005 msg.show_all ();
2006 msg.present ();
2007 msg.run ();
2009 #endif
2012 void
2013 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2015 existing_session = false;
2017 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2018 session_path = cmdline_path;
2019 existing_session = true;
2020 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2021 session_path = Glib::path_get_dirname (string (cmdline_path));
2022 existing_session = true;
2023 } else {
2024 /* it doesn't exist, assume the best */
2025 session_path = Glib::path_get_dirname (string (cmdline_path));
2028 session_name = basename_nosuffix (string (cmdline_path));
2032 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2034 /* when this is called, the backend audio system must be running */
2036 /* the main idea here is to deal with the fact that a cmdline argument for the session
2037 can be interpreted in different ways - it could be a directory or a file, and before
2038 we load, we need to know both the session directory and the snapshot (statefile) within it
2039 that we are supposed to use.
2042 if (session_name.length() == 0 || session_path.length() == 0) {
2043 return false;
2046 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2048 Glib::ustring predicted_session_file;
2050 predicted_session_file = session_path;
2051 predicted_session_file += '/';
2052 predicted_session_file += session_name;
2053 predicted_session_file += Session::statefile_suffix();
2055 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2056 existing_session = true;
2059 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2061 if (session_path.find (Session::statefile_suffix()) == session_path.length() - 7) {
2062 /* existing .ardour file */
2063 existing_session = true;
2066 } else {
2067 existing_session = false;
2070 /* lets just try to load it */
2072 if (create_engine ()) {
2073 backend_audio_error (false, new_session_dialog);
2074 return -1;
2077 return load_session (session_path, session_name);
2080 bool
2081 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2083 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2085 MessageDialog msg (str,
2086 false,
2087 Gtk::MESSAGE_WARNING,
2088 Gtk::BUTTONS_YES_NO,
2089 true);
2092 msg.set_name (X_("CleanupDialog"));
2093 msg.set_wmclass (X_("existing_session"), "Ardour");
2094 msg.set_position (Gtk::WIN_POS_MOUSE);
2095 pop_back_splash ();
2097 switch (msg.run()) {
2098 case RESPONSE_YES:
2099 return true;
2100 break;
2102 return false;
2106 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2109 uint32_t cchns;
2110 uint32_t mchns;
2111 AutoConnectOption iconnect;
2112 AutoConnectOption oconnect;
2113 uint32_t nphysin;
2114 uint32_t nphysout;
2116 if (Profile->get_sae()) {
2118 cchns = 0;
2119 mchns = 2;
2120 iconnect = AutoConnectPhysical;
2121 oconnect = AutoConnectMaster;
2122 nphysin = 0; // use all available
2123 nphysout = 0; // use all available
2125 } else {
2127 /* get settings from advanced section of NSD */
2129 if (new_session_dialog->create_control_bus()) {
2130 cchns = (uint32_t) new_session_dialog->control_channel_count();
2131 } else {
2132 cchns = 0;
2135 if (new_session_dialog->create_master_bus()) {
2136 mchns = (uint32_t) new_session_dialog->master_channel_count();
2137 } else {
2138 mchns = 0;
2141 if (new_session_dialog->connect_inputs()) {
2142 iconnect = AutoConnectPhysical;
2143 } else {
2144 iconnect = AutoConnectOption (0);
2147 /// @todo some minor tweaks.
2149 if (new_session_dialog->connect_outs_to_master()) {
2150 oconnect = AutoConnectMaster;
2151 } else if (new_session_dialog->connect_outs_to_physical()) {
2152 oconnect = AutoConnectPhysical;
2153 } else {
2154 oconnect = AutoConnectOption (0);
2157 nphysin = (uint32_t) new_session_dialog->input_limit_count();
2158 nphysout = (uint32_t) new_session_dialog->output_limit_count();
2161 if (build_session (session_path,
2162 session_name,
2163 cchns,
2164 mchns,
2165 iconnect,
2166 oconnect,
2167 nphysin,
2168 nphysout,
2169 engine->frame_rate() * 60 * 5)) {
2171 return -1;
2174 return 0;
2177 void
2178 ARDOUR_UI::end_loading_messages ()
2180 // hide_splash ();
2183 void
2184 ARDOUR_UI::loading_message (const std::string& msg)
2186 show_splash ();
2187 splash->message (msg);
2188 flush_pending ();
2191 void
2192 ARDOUR_UI::idle_load (const Glib::ustring& path)
2194 if (session) {
2195 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2196 /* /path/to/foo => /path/to/foo, foo */
2197 load_session (path, basename_nosuffix (path));
2198 } else {
2199 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2200 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2202 } else {
2204 ARDOUR_COMMAND_LINE::session_name = path;
2206 if (new_session_dialog) {
2209 /* make it break out of Dialog::run() and
2210 start again.
2213 new_session_dialog->response (1);
2218 bool
2219 ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
2221 bool existing_session = false;
2222 Glib::ustring session_name;
2223 Glib::ustring session_path;
2224 Glib::ustring template_name;
2225 int response;
2227 begin:
2228 response = Gtk::RESPONSE_NONE;
2230 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2232 parse_cmdline_path (ARDOUR_COMMAND_LINE::session_name, session_name, session_path, existing_session);
2234 /* don't ever reuse this */
2236 ARDOUR_COMMAND_LINE::session_name = string();
2238 if (existing_session && backend_audio_is_running) {
2240 /* just load the thing already */
2242 if (load_cmdline_session (session_name, session_path, existing_session) == 0) {
2243 return true;
2247 /* make the NSD use whatever information we have */
2249 new_session_dialog->set_session_name (session_name);
2250 new_session_dialog->set_session_folder (session_path);
2253 /* loading failed, or we need the NSD for something */
2255 new_session_dialog->set_modal (false);
2256 new_session_dialog->set_position (WIN_POS_CENTER);
2257 new_session_dialog->set_current_page (0);
2258 new_session_dialog->set_existing_session (existing_session);
2259 new_session_dialog->reset_recent();
2261 do {
2262 new_session_dialog->set_have_engine (backend_audio_is_running);
2263 new_session_dialog->present ();
2264 response = new_session_dialog->run ();
2266 _session_is_new = false;
2268 /* handle possible negative responses */
2270 switch (response) {
2271 case 1:
2272 /* sent by idle_load, meaning restart the whole process again */
2273 new_session_dialog->hide();
2274 new_session_dialog->reset();
2275 goto begin;
2276 break;
2278 case Gtk::RESPONSE_CANCEL:
2279 case Gtk::RESPONSE_DELETE_EVENT:
2280 if (!session) {
2281 if (engine && engine->running()) {
2282 engine->stop (true);
2284 quit();
2286 new_session_dialog->hide ();
2287 return false;
2289 case Gtk::RESPONSE_NONE:
2290 /* "Clear" was pressed */
2291 goto try_again;
2294 fontconfig_dialog();
2296 if (!backend_audio_is_running) {
2297 int ret = new_session_dialog->engine_control.setup_engine ();
2298 if (ret < 0) {
2299 return false;
2300 } else if (ret > 0) {
2301 response = Gtk::RESPONSE_REJECT;
2302 goto try_again;
2305 /* hide the NSD while we start up the engine */
2307 new_session_dialog->hide ();
2308 flush_pending ();
2311 if (create_engine ()) {
2313 backend_audio_error (!backend_audio_is_running, new_session_dialog);
2314 flush_pending ();
2316 new_session_dialog->set_existing_session (false);
2317 new_session_dialog->set_current_page (2);
2319 response = Gtk::RESPONSE_NONE;
2320 goto try_again;
2323 backend_audio_is_running = true;
2325 if (response == Gtk::RESPONSE_OK) {
2327 session_name = new_session_dialog->session_name();
2329 if (session_name.empty()) {
2330 response = Gtk::RESPONSE_NONE;
2331 goto try_again;
2334 /* if the user mistakenly typed path information into the session filename entry,
2335 convert what they typed into a path & a name
2338 if (session_name[0] == '/' ||
2339 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2340 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2342 session_path = Glib::path_get_dirname (session_name);
2343 session_name = Glib::path_get_basename (session_name);
2345 } else {
2347 session_path = new_session_dialog->session_folder();
2350 template_name = Glib::ustring();
2351 switch (new_session_dialog->which_page()) {
2353 case NewSessionDialog::OpenPage:
2354 goto loadit;
2355 break;
2357 case NewSessionDialog::EnginePage:
2358 if (new_session_dialog->engine_control.interface_chosen() && !session_path.empty()) {
2359 goto loadit;
2360 } else {
2361 goto try_again;
2363 break;
2365 case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
2367 should_be_new = true;
2369 if (session_name.find ('/') != Glib::ustring::npos) {
2370 MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
2371 "session names may not contain a '/' character"));
2372 msg.run ();
2373 response = RESPONSE_NONE;
2374 goto try_again;
2377 if (session_name.find ('\\') != Glib::ustring::npos) {
2378 MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
2379 "session names may not contain a '\\' character"));
2380 msg.run ();
2381 response = RESPONSE_NONE;
2382 goto try_again;
2385 //XXX This is needed because session constructor wants a
2386 //non-existant path. hopefully this will be fixed at some point.
2388 session_path = Glib::build_filename (session_path, session_name);
2390 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2392 if (ask_about_loading_existing_session (session_path)) {
2393 goto loadit;
2394 } else {
2395 response = RESPONSE_NONE;
2396 goto try_again;
2400 _session_is_new = true;
2402 if (new_session_dialog->use_session_template()) {
2404 template_name = new_session_dialog->session_template_name();
2405 goto loadit;
2407 } else {
2408 if (build_session_from_nsd (session_path, session_name)) {
2409 response = RESPONSE_NONE;
2410 goto try_again;
2412 goto done;
2414 break;
2416 default:
2417 break;
2420 loadit:
2421 new_session_dialog->hide ();
2423 if (load_session (session_path, session_name, template_name)) {
2424 /* force a retry */
2425 response = Gtk::RESPONSE_NONE;
2428 try_again:
2429 if (response == Gtk::RESPONSE_NONE) {
2430 new_session_dialog->set_existing_session (false);
2431 new_session_dialog->reset ();
2435 } while (response == Gtk::RESPONSE_NONE || response == Gtk::RESPONSE_REJECT);
2437 done:
2438 show();
2439 new_session_dialog->hide();
2440 new_session_dialog->reset();
2441 goto_editor_window ();
2442 return true;
2445 void
2446 ARDOUR_UI::close_session ()
2448 if (!check_audioengine()) {
2449 return;
2452 if (unload_session (true)) {
2453 return;
2456 get_session_parameters (true, false);
2460 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2462 Session *new_session;
2463 int unload_status;
2464 int retval = -1;
2466 session_loaded = false;
2468 if (!check_audioengine()) {
2469 return -1;
2472 unload_status = unload_session ();
2474 if (unload_status < 0) {
2475 goto out;
2476 } else if (unload_status > 0) {
2477 retval = 0;
2478 goto out;
2481 /* if it already exists, we must have write access */
2483 if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) {
2484 MessageDialog msg (*editor, _("You do not have write access to this session.\n"
2485 "This prevents the session from being loaded."));
2486 pop_back_splash ();
2487 msg.run ();
2488 goto out;
2491 loading_message (_("Please wait while Ardour loads your session"));
2493 try {
2494 new_session = new Session (*engine, path, snap_name, mix_template);
2497 /* this one is special */
2499 catch (AudioEngine::PortRegistrationFailure& err) {
2501 MessageDialog msg (err.what(),
2502 true,
2503 Gtk::MESSAGE_INFO,
2504 Gtk::BUTTONS_CLOSE);
2506 msg.set_title (_("Port Registration Error"));
2507 msg.set_secondary_text (_("Click the Close button to try again."));
2508 msg.set_position (Gtk::WIN_POS_CENTER);
2509 pop_back_splash ();
2510 msg.present ();
2512 int response = msg.run ();
2514 msg.hide ();
2516 switch (response) {
2517 case RESPONSE_CANCEL:
2518 exit (1);
2519 default:
2520 break;
2522 goto out;
2525 catch (...) {
2527 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2528 true,
2529 Gtk::MESSAGE_INFO,
2530 Gtk::BUTTONS_CLOSE);
2532 msg.set_title (_("Loading Error"));
2533 msg.set_secondary_text (_("Click the Close button to try again."));
2534 msg.set_position (Gtk::WIN_POS_CENTER);
2535 pop_back_splash ();
2536 msg.present ();
2538 int response = msg.run ();
2540 msg.hide ();
2542 switch (response) {
2543 case RESPONSE_CANCEL:
2544 exit (1);
2545 default:
2546 break;
2548 goto out;
2551 connect_to_session (new_session);
2553 Config->set_current_owner (ConfigVariableBase::Interface);
2555 session_loaded = true;
2557 goto_editor_window ();
2559 if (session) {
2560 session->set_clean ();
2563 flush_pending ();
2564 retval = 0;
2566 out:
2567 return retval;
2571 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2572 uint32_t control_channels,
2573 uint32_t master_channels,
2574 AutoConnectOption input_connect,
2575 AutoConnectOption output_connect,
2576 uint32_t nphysin,
2577 uint32_t nphysout,
2578 nframes_t initial_length)
2580 Session *new_session;
2581 int x;
2583 if (!check_audioengine()) {
2584 return -1;
2587 session_loaded = false;
2589 x = unload_session ();
2591 if (x < 0) {
2592 return -1;
2593 } else if (x > 0) {
2594 return 0;
2597 _session_is_new = true;
2599 try {
2600 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2601 control_channels, master_channels, nphysin, nphysout, initial_length);
2604 catch (...) {
2606 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2607 pop_back_splash ();
2608 msg.run ();
2609 return -1;
2612 connect_to_session (new_session);
2614 session_loaded = true;
2616 new_session->save_state(new_session->name());
2618 return 0;
2621 void
2622 ARDOUR_UI::show ()
2624 if (editor) {
2625 editor->show_window ();
2627 if (!shown_flag) {
2628 editor->present ();
2631 shown_flag = true;
2635 void
2636 ARDOUR_UI::show_about ()
2638 if (about == 0) {
2639 about = new About;
2640 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2643 about->show_all ();
2646 void
2647 ARDOUR_UI::launch_chat ()
2649 #ifdef __APPLE__
2650 NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2651 #else
2652 NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour");
2653 #endif
2656 void
2657 ARDOUR_UI::hide_about ()
2659 if (about) {
2660 about->get_window()->set_cursor ();
2661 about->hide ();
2665 void
2666 ARDOUR_UI::about_signal_response(int response)
2668 hide_about();
2671 void
2672 ARDOUR_UI::show_splash ()
2674 if (splash == 0) {
2675 try {
2676 splash = new Splash;
2677 } catch (...) {
2678 return;
2682 splash->show ();
2683 splash->present ();
2684 splash->queue_draw ();
2685 splash->get_window()->process_updates (true);
2686 flush_pending ();
2689 void
2690 ARDOUR_UI::hide_splash ()
2692 if (splash) {
2693 splash->hide();
2697 void
2698 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title,
2699 const string& plural_msg, const string& singular_msg)
2701 size_t removed;
2703 removed = rep.paths.size();
2705 if (removed == 0) {
2706 MessageDialog msgd (*editor,
2707 _("No audio files were ready for cleanup"),
2708 true,
2709 Gtk::MESSAGE_INFO,
2710 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2711 msgd.set_secondary_text (_("If this seems suprising, \n\
2712 check for any existing snapshots.\n\
2713 These may still include regions that\n\
2714 require some unused files to continue to exist."));
2716 msgd.run ();
2717 return;
2720 ArdourDialog results (_("ardour: cleanup"), true, false);
2722 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2723 CleanupResultsModelColumns() {
2724 add (visible_name);
2725 add (fullpath);
2727 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2728 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2732 CleanupResultsModelColumns results_columns;
2733 Glib::RefPtr<Gtk::ListStore> results_model;
2734 Gtk::TreeView results_display;
2736 results_model = ListStore::create (results_columns);
2737 results_display.set_model (results_model);
2738 results_display.append_column (list_title, results_columns.visible_name);
2740 results_display.set_name ("CleanupResultsList");
2741 results_display.set_headers_visible (true);
2742 results_display.set_headers_clickable (false);
2743 results_display.set_reorderable (false);
2745 Gtk::ScrolledWindow list_scroller;
2746 Gtk::Label txt;
2747 Gtk::VBox dvbox;
2748 Gtk::HBox dhbox; // the hbox for the image and text
2749 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2750 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2752 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2755 /* subst:
2756 %1 - number of files removed
2757 %2 - location of "dead_sounds"
2758 %3 - size of files affected
2759 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2762 const char* bprefix;
2763 float space_adjusted;
2765 if (rep.space < 1000000.0f) {
2766 bprefix = X_("kilo");
2767 space_adjusted = truncf((float)rep.space / 1000.0f);
2768 } else if (rep.space < (1000000.0f * 1000)) {
2769 bprefix = X_("mega");
2770 space_adjusted = truncf((float)rep.space / (1000000.0f));
2771 } else {
2772 bprefix = X_("giga");
2773 space_adjusted = truncf((float)rep.space / (1000000.0f * 1000));
2776 if (removed > 1) {
2777 txt.set_text (string_compose (plural_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
2778 } else {
2779 txt.set_text (string_compose (singular_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
2782 dhbox.pack_start (*dimage, true, false, 5);
2783 dhbox.pack_start (txt, true, false, 5);
2785 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2786 TreeModel::Row row = *(results_model->append());
2787 row[results_columns.visible_name] = *i;
2788 row[results_columns.fullpath] = *i;
2791 list_scroller.add (results_display);
2792 list_scroller.set_size_request (-1, 150);
2793 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2795 dvbox.pack_start (dhbox, true, false, 5);
2796 dvbox.pack_start (list_scroller, true, false, 5);
2797 ddhbox.pack_start (dvbox, true, false, 5);
2799 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2800 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2801 results.set_default_response (RESPONSE_CLOSE);
2802 results.set_position (Gtk::WIN_POS_MOUSE);
2803 results.show_all_children ();
2804 results.set_resizable (false);
2806 results.run ();
2810 void
2811 ARDOUR_UI::cleanup ()
2813 if (session == 0) {
2814 /* shouldn't happen: menu item is insensitive */
2815 return;
2819 MessageDialog checker (_("Are you sure you want to cleanup?"),
2820 true,
2821 Gtk::MESSAGE_QUESTION,
2822 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2824 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2825 ALL undo/redo information will be lost if you cleanup.\n\
2826 After cleanup, unused audio files will be moved to a \
2827 \"dead sounds\" location."));
2829 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2830 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2831 checker.set_default_response (RESPONSE_CANCEL);
2833 checker.set_name (_("CleanupDialog"));
2834 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2835 checker.set_position (Gtk::WIN_POS_MOUSE);
2837 switch (checker.run()) {
2838 case RESPONSE_ACCEPT:
2839 break;
2840 default:
2841 return;
2844 Session::cleanup_report rep;
2846 editor->prepare_for_cleanup ();
2848 /* do not allow flush until a session is reloaded */
2850 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2851 if (act) {
2852 act->set_sensitive (false);
2855 if (session->cleanup_sources (rep)) {
2856 editor->finish_cleanup ();
2857 return;
2860 editor->finish_cleanup ();
2862 checker.hide();
2863 display_cleanup_results (rep,
2864 _("cleaned files"),
2865 _("\
2866 The following %1 files were not in use and \n\
2867 have been moved to:\n\
2868 %2. \n\n\
2869 Flushing the wastebasket will \n\
2870 release an additional\n\
2871 %3 %4bytes of disk space.\n"),
2872 _("\
2873 The following file was not in use and \n \
2874 has been moved to:\n \
2875 %2. \n\n\
2876 Flushing the wastebasket will \n\
2877 release an additional\n\
2878 %3 %4bytes of disk space.\n"
2883 void
2884 ARDOUR_UI::flush_trash ()
2886 if (session == 0) {
2887 /* shouldn't happen: menu item is insensitive */
2888 return;
2891 Session::cleanup_report rep;
2893 if (session->cleanup_trash_sources (rep)) {
2894 return;
2897 display_cleanup_results (rep,
2898 _("deleted file"),
2899 _("The following %1 files were deleted from\n\
2900 %2,\n\
2901 releasing %3 %4bytes of disk space"),
2902 _("The following file was deleted from\n\
2903 %2,\n\
2904 releasing %3 %4bytes of disk space"));
2907 void
2908 ARDOUR_UI::add_route (Gtk::Window* float_window)
2910 int count;
2912 if (!session) {
2913 return;
2916 if (add_route_dialog == 0) {
2917 add_route_dialog = new AddRouteDialog;
2918 if (float_window) {
2919 add_route_dialog->set_transient_for (*float_window);
2923 if (add_route_dialog->is_visible()) {
2924 /* we're already doing this */
2925 return;
2928 ResponseType r = (ResponseType) add_route_dialog->run ();
2930 add_route_dialog->hide();
2932 switch (r) {
2933 case RESPONSE_ACCEPT:
2934 break;
2935 default:
2936 return;
2937 break;
2940 if ((count = add_route_dialog->count()) <= 0) {
2941 return;
2944 string template_path = add_route_dialog->track_template();
2946 if (!template_path.empty()) {
2947 session->new_route_from_template (count, template_path);
2948 return;
2951 uint32_t input_chan = add_route_dialog->channels ();
2952 uint32_t output_chan;
2953 string name_template = add_route_dialog->name_template ();
2954 bool track = add_route_dialog->track ();
2956 AutoConnectOption oac = Config->get_output_auto_connect();
2958 if (oac & AutoConnectMaster) {
2959 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2960 } else {
2961 output_chan = input_chan;
2964 /* XXX do something with name template */
2966 if (track) {
2967 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
2968 } else {
2969 session_add_audio_bus (input_chan, output_chan, count);
2973 XMLNode*
2974 ARDOUR_UI::mixer_settings () const
2976 XMLNode* node = 0;
2978 if (session) {
2979 node = session->instant_xml(X_("Mixer"), session->path());
2980 } else {
2981 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
2984 if (!node) {
2985 node = new XMLNode (X_("Mixer"));
2988 return node;
2991 XMLNode*
2992 ARDOUR_UI::editor_settings () const
2994 XMLNode* node = 0;
2996 if (session) {
2997 node = session->instant_xml(X_("Editor"), session->path());
2998 } else {
2999 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
3002 if (!node) {
3003 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3004 node = Config->instant_xml(X_("Editor"), getenv("ARDOUR_INSTANT_XML_PATH"));
3008 if (!node) {
3009 node = new XMLNode (X_("Editor"));
3011 return node;
3014 XMLNode*
3015 ARDOUR_UI::keyboard_settings () const
3017 XMLNode* node = 0;
3019 node = Config->extra_xml(X_("Keyboard"));
3021 if (!node) {
3022 node = new XMLNode (X_("Keyboard"));
3024 return node;
3027 void
3028 ARDOUR_UI::create_xrun_marker(nframes_t where)
3030 editor->mouse_add_new_marker (where, false, true);
3033 void
3034 ARDOUR_UI::halt_on_xrun_message ()
3036 MessageDialog msg (*editor,
3037 _("Recording was stopped because your system could not keep up."));
3038 msg.run ();
3041 void
3042 ARDOUR_UI::xrun_handler(nframes_t where)
3044 if (!session) {
3045 return;
3048 ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::xrun_handler), where));
3050 if (session && Config->get_create_xrun_marker() && session->actively_recording()) {
3051 create_xrun_marker(where);
3054 if (session && Config->get_stop_recording_on_xrun() && session->actively_recording()) {
3055 halt_on_xrun_message ();
3059 bool
3060 ARDOUR_UI::preset_file_exists_handler ()
3062 /* if driven from another thread, say "do not overwrite" and show the user nothing.
3065 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) { \
3066 return false;
3069 HBox* hbox = new HBox();
3070 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3071 Gtk::Dialog dialog (_("Preset Exists"), true, false);
3072 Label message (_("\
3073 A preset with this name already exists for this plugin.\n\
3075 What you would like to do?\n"));
3076 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3077 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3078 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3079 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3080 dialog.add_button (_("Overwrite the existing preset"), RESPONSE_ACCEPT);
3081 dialog.add_button (_("Leave the existing preset alone"), RESPONSE_REJECT);
3082 dialog.set_default_response (RESPONSE_ACCEPT);
3083 dialog.set_position (WIN_POS_MOUSE);
3084 dialog.set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY); // need to make it float above the preset name dialog
3086 message.show();
3087 image->show();
3088 hbox->show();
3090 switch (dialog.run ()) {
3091 case RESPONSE_ACCEPT:
3092 return true;
3093 default:
3094 return false;
3098 void
3099 ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
3101 time_t now;
3102 time (&now);
3104 while (disk_buffer_stats.size() > 60) {
3105 disk_buffer_stats.pop_front ();
3108 disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
3111 void
3112 ARDOUR_UI::write_buffer_stats ()
3114 std::ofstream fout;
3115 struct tm tm;
3116 char buf[64];
3117 char* path;
3119 if ((path = tempnam (0, "ardourBuffering")) == 0) {
3120 cerr << X_("cannot find temporary name for ardour buffer stats") << endl;
3121 return;
3124 fout.open (path);
3126 if (!fout) {
3127 cerr << string_compose (X_("cannot open file %1 for ardour buffer stats"), path) << endl;
3128 return;
3131 for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
3132 localtime_r (&(*i).when, &tm);
3133 strftime (buf, sizeof (buf), "%T", &tm);
3134 fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
3137 disk_buffer_stats.clear ();
3139 fout.close ();
3141 cerr << "Ardour buffering statistics can be found in: " << path << endl;
3142 free (path);
3145 void
3146 ARDOUR_UI::disk_overrun_handler ()
3149 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
3151 write_buffer_stats ();
3153 if (!have_disk_speed_dialog_displayed) {
3154 have_disk_speed_dialog_displayed = true;
3155 MessageDialog* msg = new MessageDialog (*editor, _("\
3156 The disk system on your computer\n\
3157 was not able to keep up with Ardour.\n\
3159 Specifically, it failed to write data to disk\n\
3160 quickly enough to keep up with recording.\n"));
3161 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3162 msg->show_all ();
3166 void
3167 ARDOUR_UI::disk_underrun_handler ()
3170 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
3172 write_buffer_stats ();
3174 if (!have_disk_speed_dialog_displayed) {
3175 have_disk_speed_dialog_displayed = true;
3176 MessageDialog* msg = new MessageDialog (*editor,
3177 _("The disk system on your computer\n\
3178 was not able to keep up with Ardour.\n\
3180 Specifically, it failed to read data from disk\n\
3181 quickly enough to keep up with playback.\n"));
3182 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3183 msg->show_all ();
3187 void
3188 ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
3190 have_disk_speed_dialog_displayed = false;
3191 delete msg;
3194 void
3195 ARDOUR_UI::session_dialog (std::string msg)
3197 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
3199 MessageDialog* d;
3201 if (editor) {
3202 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3203 } else {
3204 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3207 d->show_all ();
3208 d->run ();
3209 delete d;
3213 ARDOUR_UI::pending_state_dialog ()
3215 HBox* hbox = new HBox();
3216 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3217 ArdourDialog dialog (_("Crash Recovery"), true);
3218 Label message (_("\
3219 This session appears to have been in\n\
3220 middle of recording when ardour or\n\
3221 the computer was shutdown.\n\
3223 Ardour can recover any captured audio for\n\
3224 you, or it can ignore it. Please decide\n\
3225 what you would like to do.\n"));
3226 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3227 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3228 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3229 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3230 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3231 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3232 dialog.set_default_response (RESPONSE_ACCEPT);
3233 dialog.set_position (WIN_POS_CENTER);
3234 message.show();
3235 image->show();
3236 hbox->show();
3238 pop_back_splash ();
3240 switch (dialog.run ()) {
3241 case RESPONSE_ACCEPT:
3242 return 1;
3243 default:
3244 return 0;
3249 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3251 HBox* hbox = new HBox();
3252 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3253 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3254 Label message (string_compose (_("\
3255 This session was created with a sample rate of %1 Hz\n\
3257 The audioengine is currently running at %2 Hz\n"), desired, actual));
3259 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3260 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3261 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3262 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3263 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3264 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3265 dialog.set_default_response (RESPONSE_ACCEPT);
3266 dialog.set_position (WIN_POS_CENTER);
3267 message.show();
3268 image->show();
3269 hbox->show();
3271 switch (dialog.run ()) {
3272 case RESPONSE_ACCEPT:
3273 return 0;
3274 default:
3275 return 1;
3280 void
3281 ARDOUR_UI::disconnect_from_jack ()
3283 if (engine) {
3284 if( engine->disconnect_from_jack ()) {
3285 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3286 msg.run ();
3289 update_sample_rate (0);
3293 void
3294 ARDOUR_UI::reconnect_to_jack ()
3296 if (engine) {
3297 if (engine->reconnect_to_jack ()) {
3298 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3299 msg.run ();
3302 update_sample_rate (0);
3306 void
3307 ARDOUR_UI::use_config ()
3309 Glib::RefPtr<Action> act;
3311 switch (Config->get_native_file_data_format ()) {
3312 case FormatFloat:
3313 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
3314 break;
3315 case FormatInt24:
3316 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
3317 break;
3318 case FormatInt16:
3319 act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit"));
3320 break;
3323 if (act) {
3324 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3325 ract->set_active ();
3328 switch (Config->get_native_file_header_format ()) {
3329 case BWF:
3330 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
3331 break;
3332 case WAVE:
3333 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
3334 break;
3335 case WAVE64:
3336 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
3337 break;
3338 case iXML:
3339 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
3340 break;
3341 case RF64:
3342 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
3343 break;
3344 case CAF:
3345 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
3346 break;
3347 case AIFF:
3348 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
3349 break;
3352 if (act) {
3353 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3354 ract->set_active ();
3357 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3358 if (node) {
3359 set_transport_controllable_state (*node);
3363 void
3364 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3366 if (Config->get_primary_clock_delta_edit_cursor()) {
3367 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3368 } else {
3369 primary_clock.set (pos, 0, true);
3372 if (Config->get_secondary_clock_delta_edit_cursor()) {
3373 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3374 } else {
3375 secondary_clock.set (pos);
3378 if (big_clock_window) {
3379 big_clock.set (pos);
3383 void
3384 ARDOUR_UI::record_state_changed ()
3386 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3388 if (!session || !big_clock_window) {
3389 /* why bother - the clock isn't visible */
3390 return;
3393 switch (session->record_status()) {
3394 case Session::Recording:
3395 big_clock.set_widget_name ("BigClockRecording");
3396 break;
3397 default:
3398 big_clock.set_widget_name ("BigClockNonRecording");
3399 break;
3403 bool
3404 ARDOUR_UI::first_idle ()
3406 if (session) {
3407 session->allow_auto_play (true);
3410 if (editor) {
3411 editor->first_idle();
3414 Keyboard::set_can_save_keybindings (true);
3415 return false;
3418 void
3419 ARDOUR_UI::store_clock_modes ()
3421 XMLNode* node = new XMLNode(X_("ClockModes"));
3423 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3424 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3427 session->add_extra_xml (*node);
3428 session->set_dirty ();
3433 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3434 : Controllable (name), ui (u), type(tp)
3439 void
3440 ARDOUR_UI::TransportControllable::set_value (float val)
3442 if (type == ShuttleControl) {
3443 double fract;
3445 if (val == 0.5f) {
3446 fract = 0.0;
3447 } else {
3448 if (val < 0.5f) {
3449 fract = -((0.5f - val)/0.5f);
3450 } else {
3451 fract = ((val - 0.5f)/0.5f);
3455 ui.set_shuttle_fract (fract);
3456 return;
3459 if (val < 0.5f) {
3460 /* do nothing: these are radio-style actions */
3461 return;
3464 const char *action = 0;
3466 switch (type) {
3467 case Roll:
3468 action = X_("Roll");
3469 break;
3470 case Stop:
3471 action = X_("Stop");
3472 break;
3473 case GotoStart:
3474 action = X_("Goto Start");
3475 break;
3476 case GotoEnd:
3477 action = X_("Goto End");
3478 break;
3479 case AutoLoop:
3480 action = X_("Loop");
3481 break;
3482 case PlaySelection:
3483 action = X_("Play Selection");
3484 break;
3485 case RecordEnable:
3486 action = X_("Record");
3487 break;
3488 default:
3489 break;
3492 if (action == 0) {
3493 return;
3496 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3498 if (act) {
3499 act->activate ();
3503 float
3504 ARDOUR_UI::TransportControllable::get_value (void) const
3506 float val = 0.0f;
3508 switch (type) {
3509 case Roll:
3510 break;
3511 case Stop:
3512 break;
3513 case GotoStart:
3514 break;
3515 case GotoEnd:
3516 break;
3517 case AutoLoop:
3518 break;
3519 case PlaySelection:
3520 break;
3521 case RecordEnable:
3522 break;
3523 case ShuttleControl:
3524 break;
3525 default:
3526 break;
3529 return val;
3532 void
3533 ARDOUR_UI::TransportControllable::set_id (const string& str)
3535 _id = str;
3538 void
3539 ARDOUR_UI::setup_profile ()
3541 if (gdk_screen_width() < 1200) {
3542 Profile->set_small_screen ();
3545 if (getenv ("ARDOUR_SAE")) {
3546 Profile->set_sae ();
3547 Profile->set_single_package ();