Remove idiocy.
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blobf10f287ef8d1dab8b5bdbb77e0e2b3451e9e01c7
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 #define __STDC_FORMAT_MACROS 1
21 #include <stdint.h>
23 #include <algorithm>
24 #include <cmath>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <time.h>
29 #include <cerrno>
30 #include <fstream>
32 #include <iostream>
34 #include <sys/resource.h>
36 #include <gtkmm/messagedialog.h>
37 #include <gtkmm/accelmap.h>
39 #include "pbd/error.h"
40 #include "pbd/basename.h"
41 #include "pbd/compose.h"
42 #include "pbd/failed_constructor.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/file_utils.h"
47 #include <gtkmm2ext/gtk_ui.h>
48 #include <gtkmm2ext/utils.h>
49 #include <gtkmm2ext/click_box.h>
50 #include <gtkmm2ext/fastmeter.h>
51 #include <gtkmm2ext/stop_signal.h>
52 #include <gtkmm2ext/popup.h>
53 #include <gtkmm2ext/window_title.h>
55 #include "midi++/manager.h"
57 #include "ardour/ardour.h"
58 #include "ardour/profile.h"
59 #include "ardour/session_directory.h"
60 #include "ardour/session_route.h"
61 #include "ardour/session_state_utils.h"
62 #include "ardour/session_utils.h"
63 #include "ardour/port.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/playlist.h"
66 #include "ardour/utils.h"
67 #include "ardour/audio_diskstream.h"
68 #include "ardour/audiofilesource.h"
69 #include "ardour/recent_sessions.h"
70 #include "ardour/port.h"
71 #include "ardour/audio_track.h"
72 #include "ardour/midi_track.h"
73 #include "ardour/filesystem_paths.h"
74 #include "ardour/filename_extensions.h"
76 typedef uint64_t microseconds_t;
78 #include "actions.h"
79 #include "ardour_ui.h"
80 #include "public_editor.h"
81 #include "audio_clock.h"
82 #include "keyboard.h"
83 #include "mixer_ui.h"
84 #include "prompter.h"
85 #include "opts.h"
86 #include "add_route_dialog.h"
87 #include "about.h"
88 #include "splash.h"
89 #include "utils.h"
90 #include "gui_thread.h"
91 #include "theme_manager.h"
92 #include "bundle_manager.h"
93 #include "session_metadata_dialog.h"
94 #include "gain_meter.h"
95 #include "route_time_axis.h"
96 #include "startup.h"
97 #include "engine_dialog.h"
99 #include "i18n.h"
101 using namespace ARDOUR;
102 using namespace PBD;
103 using namespace Gtkmm2ext;
104 using namespace Gtk;
105 using namespace sigc;
107 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
108 UIConfiguration *ARDOUR_UI::ui_config = 0;
110 sigc::signal<void,bool> ARDOUR_UI::Blink;
111 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
112 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
113 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
115 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
117 : Gtkmm2ext::UI (X_("Ardour"), argcp, argvp),
119 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true),
120 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true),
121 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
122 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
124 /* preroll stuff */
126 preroll_button (_("pre\nroll")),
127 postroll_button (_("post\nroll")),
129 /* big clock */
131 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, false, true),
133 /* transport */
135 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
136 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
137 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
138 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
139 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
140 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
141 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
142 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
143 shuttle_controller_binding_proxy (shuttle_controllable),
145 roll_button (roll_controllable),
146 stop_button (stop_controllable),
147 goto_start_button (goto_start_controllable),
148 goto_end_button (goto_end_controllable),
149 auto_loop_button (auto_loop_controllable),
150 play_selection_button (play_selection_controllable),
151 rec_button (rec_controllable),
153 shuttle_units_button (_("% ")),
155 punch_in_button (_("Punch In")),
156 punch_out_button (_("Punch Out")),
157 auto_return_button (_("Auto Return")),
158 auto_play_button (_("Auto Play")),
159 auto_input_button (_("Auto Input")),
160 click_button (_("Click")),
161 time_master_button (_("time\nmaster")),
163 auditioning_alert_button (_("AUDITION")),
164 solo_alert_button (_("SOLO")),
165 shown_flag (false),
166 error_log_button (_("Errors"))
169 using namespace Gtk::Menu_Helpers;
171 Gtkmm2ext::init();
174 #ifdef TOP_MENUBAR
175 // _auto_display_errors = false;
177 * This was commented out as it wasn't defined
178 * in A3 IIRC. If this is not needed it should
179 * be completely removed.
181 #endif
183 about = 0;
184 splash = 0;
185 _startup = 0;
187 if (theArdourUI == 0) {
188 theArdourUI = this;
191 ui_config = new UIConfiguration();
192 theme_manager = new ThemeManager();
194 editor = 0;
195 mixer = 0;
196 session = 0;
197 editor = 0;
198 engine = 0;
199 _session_is_new = false;
200 big_clock_window = 0;
201 session_selector_window = 0;
202 last_key_press_time = 0;
203 _will_create_new_session_automatically = false;
204 add_route_dialog = 0;
205 route_params = 0;
206 rc_option_editor = 0;
207 session_option_editor = 0;
208 location_ui = 0;
209 open_session_selector = 0;
210 have_configure_timeout = false;
211 have_disk_speed_dialog_displayed = false;
212 session_loaded = false;
213 last_speed_displayed = -1.0f;
214 ignore_dual_punch = false;
215 _mixer_on_top = false;
217 roll_button.unset_flags (Gtk::CAN_FOCUS);
218 stop_button.unset_flags (Gtk::CAN_FOCUS);
219 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
220 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
221 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
222 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
223 rec_button.unset_flags (Gtk::CAN_FOCUS);
225 last_configure_time= 0;
227 shuttle_grabbed = false;
228 shuttle_fract = 0.0;
229 shuttle_max_speed = 8.0f;
231 shuttle_style_menu = 0;
232 shuttle_unit_menu = 0;
234 // We do not have jack linked in yet so;
236 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
238 ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
239 ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
241 /* handle dialog requests */
243 ARDOUR::Session::Dialog.connect (mem_fun(*this, &ARDOUR_UI::session_dialog));
245 /* handle pending state with a dialog */
247 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
249 /* handle sr mismatch with a dialog */
251 ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
253 /* lets get this party started */
255 try {
256 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
257 throw failed_constructor ();
260 setup_gtk_ardour_enums ();
261 setup_profile ();
263 GainMeter::setup_slider_pix ();
264 RouteTimeAxisView::setup_slider_pix ();
266 } catch (failed_constructor& err) {
267 error << _("could not initialize Ardour.") << endmsg;
268 // pass it on up
269 throw;
272 /* we like keyboards */
274 keyboard = new Keyboard;
276 reset_dpi();
278 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
279 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
281 platform_setup ();
284 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
285 bool
286 ARDOUR_UI::run_startup (bool should_be_new)
288 if (_startup == 0) {
289 _startup = new ArdourStartup ();
292 _startup->set_new_only (should_be_new);
293 _startup->present ();
295 main().run();
297 /* we don't return here until the startup assistant is finished */
299 _startup->hide ();
301 return _startup->applying ();
305 ARDOUR_UI::create_engine ()
307 // this gets called every time by new_session()
309 if (engine) {
310 return 0;
313 loading_message (_("Starting audio engine"));
315 try {
316 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
318 } catch (...) {
320 return -1;
323 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
324 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
325 engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
326 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
328 post_engine ();
330 return 0;
333 void
334 ARDOUR_UI::post_engine ()
336 /* Things to be done once we create the AudioEngine
339 MIDI::Manager::instance()->set_api_data (engine->jack());
340 setup_midi ();
342 ARDOUR::init_post_engine ();
344 ActionManager::init ();
345 _tooltips.enable();
347 if (setup_windows ()) {
348 throw failed_constructor ();
351 check_memory_locking();
353 /* this is the first point at which all the keybindings are available */
355 if (ARDOUR_COMMAND_LINE::show_key_actions) {
356 vector<string> names;
357 vector<string> paths;
358 vector<string> keys;
359 vector<AccelKey> bindings;
361 ActionManager::get_all_actions (names, paths, keys, bindings);
363 vector<string>::iterator n;
364 vector<string>::iterator k;
365 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
366 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
369 exit (0);
372 blink_timeout_tag = -1;
374 /* this being a GUI and all, we want peakfiles */
376 AudioFileSource::set_build_peakfiles (true);
377 AudioFileSource::set_build_missing_peakfiles (true);
379 /* set default clock modes */
381 if (Profile->get_sae()) {
382 primary_clock.set_mode (AudioClock::BBT);
383 secondary_clock.set_mode (AudioClock::MinSec);
384 } else {
385 primary_clock.set_mode (AudioClock::Timecode);
386 secondary_clock.set_mode (AudioClock::BBT);
389 /* start the time-of-day-clock */
391 #ifndef GTKOSX
392 /* OS X provides an always visible wallclock, so don't be stupid */
393 update_wall_clock ();
394 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
395 #endif
397 update_disk_space ();
398 update_cpu_load ();
399 update_sample_rate (engine->frame_rate());
401 /* now start and maybe save state */
403 if (do_engine_start () == 0) {
404 if (session && _session_is_new) {
405 /* we need to retain initial visual
406 settings for a new session
408 session->save_state ("");
413 ARDOUR_UI::~ARDOUR_UI ()
415 save_ardour_state ();
417 delete keyboard;
418 delete editor;
419 delete mixer;
420 delete add_route_dialog;
423 void
424 ARDOUR_UI::pop_back_splash ()
426 if (Splash::instance()) {
427 // Splash::instance()->pop_back();
428 Splash::instance()->hide ();
432 gint
433 ARDOUR_UI::configure_timeout ()
435 if (last_configure_time == 0) {
436 /* no configure events yet */
437 return TRUE;
440 /* force a gap of 0.5 seconds since the last configure event
443 if (get_microseconds() - last_configure_time < 500000) {
444 return TRUE;
445 } else {
446 have_configure_timeout = false;
447 save_ardour_state ();
448 return FALSE;
452 gboolean
453 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
455 if (have_configure_timeout) {
456 last_configure_time = get_microseconds();
457 } else {
458 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
459 have_configure_timeout = true;
462 return FALSE;
465 void
466 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
468 const XMLProperty* prop;
470 if ((prop = node.property ("roll")) != 0) {
471 roll_controllable->set_id (prop->value());
473 if ((prop = node.property ("stop")) != 0) {
474 stop_controllable->set_id (prop->value());
476 if ((prop = node.property ("goto-start")) != 0) {
477 goto_start_controllable->set_id (prop->value());
479 if ((prop = node.property ("goto-end")) != 0) {
480 goto_end_controllable->set_id (prop->value());
482 if ((prop = node.property ("auto-loop")) != 0) {
483 auto_loop_controllable->set_id (prop->value());
485 if ((prop = node.property ("play-selection")) != 0) {
486 play_selection_controllable->set_id (prop->value());
488 if ((prop = node.property ("rec")) != 0) {
489 rec_controllable->set_id (prop->value());
491 if ((prop = node.property ("shuttle")) != 0) {
492 shuttle_controllable->set_id (prop->value());
496 XMLNode&
497 ARDOUR_UI::get_transport_controllable_state ()
499 XMLNode* node = new XMLNode(X_("TransportControllables"));
500 char buf[64];
502 roll_controllable->id().print (buf, sizeof (buf));
503 node->add_property (X_("roll"), buf);
504 stop_controllable->id().print (buf, sizeof (buf));
505 node->add_property (X_("stop"), buf);
506 goto_start_controllable->id().print (buf, sizeof (buf));
507 node->add_property (X_("goto_start"), buf);
508 goto_end_controllable->id().print (buf, sizeof (buf));
509 node->add_property (X_("goto_end"), buf);
510 auto_loop_controllable->id().print (buf, sizeof (buf));
511 node->add_property (X_("auto_loop"), buf);
512 play_selection_controllable->id().print (buf, sizeof (buf));
513 node->add_property (X_("play_selection"), buf);
514 rec_controllable->id().print (buf, sizeof (buf));
515 node->add_property (X_("rec"), buf);
516 shuttle_controllable->id().print (buf, sizeof (buf));
517 node->add_property (X_("shuttle"), buf);
519 return *node;
522 void
523 ARDOUR_UI::save_ardour_state ()
525 if (!keyboard || !mixer || !editor) {
526 return;
529 /* XXX this is all a bit dubious. add_extra_xml() uses
530 a different lifetime model from add_instant_xml().
533 XMLNode* node = new XMLNode (keyboard->get_state());
534 Config->add_extra_xml (*node);
535 Config->add_extra_xml (get_transport_controllable_state());
536 if (_startup && _startup->engine_control() && _startup->engine_control()->was_used()) {
537 Config->add_extra_xml (_startup->engine_control()->get_state());
539 Config->save_state();
540 ui_config->save_state ();
542 XMLNode enode(static_cast<Stateful*>(editor)->get_state());
543 XMLNode mnode(mixer->get_state());
545 if (session) {
546 session->add_instant_xml (enode);
547 session->add_instant_xml (mnode);
548 } else {
549 Config->add_instant_xml (enode);
550 Config->add_instant_xml (mnode);
553 Keyboard::save_keybindings ();
556 gint
557 ARDOUR_UI::autosave_session ()
559 if (g_main_depth() > 1) {
560 /* inside a recursive main loop,
561 give up because we may not be able to
562 take a lock.
564 return 1;
567 if (!Config->get_periodic_safety_backups()) {
568 return 1;
571 if (session) {
572 session->maybe_write_autosave();
575 return 1;
578 void
579 ARDOUR_UI::update_autosave ()
581 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
583 if (session && session->dirty()) {
584 if (_autosave_connection.connected()) {
585 _autosave_connection.disconnect();
588 _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
589 Config->get_periodic_safety_backup_interval() * 1000);
591 } else {
592 if (_autosave_connection.connected()) {
593 _autosave_connection.disconnect();
598 void
599 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
601 string title;
602 if (we_set_params) {
603 title = _("Ardour could not start JACK");
604 } else {
605 title = _("Ardour could not connect to JACK.");
608 MessageDialog win (title,
609 false,
610 Gtk::MESSAGE_INFO,
611 Gtk::BUTTONS_NONE);
613 if (we_set_params) {
614 win.set_secondary_text(_("There are several possible reasons:\n\
616 1) You requested audio parameters that are not supported..\n\
617 2) JACK is running as another user.\n\
619 Please consider the possibilities, and perhaps try different parameters."));
620 } else {
621 win.set_secondary_text(_("There are several possible reasons:\n\
623 1) JACK is not running.\n\
624 2) JACK is running as another user, perhaps root.\n\
625 3) There is already another client called \"ardour\".\n\
627 Please consider the possibilities, and perhaps (re)start JACK."));
630 if (toplevel) {
631 win.set_transient_for (*toplevel);
634 if (we_set_params) {
635 win.add_button (Stock::OK, RESPONSE_CLOSE);
636 } else {
637 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
640 win.set_default_response (RESPONSE_CLOSE);
642 win.show_all ();
643 win.set_position (Gtk::WIN_POS_CENTER);
644 pop_back_splash ();
646 /* we just don't care about the result, but we want to block */
648 win.run ();
651 void
652 ARDOUR_UI::startup ()
654 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
656 if (audio_setup && _startup && _startup->engine_control()) {
657 _startup->engine_control()->set_state (*audio_setup);
660 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session)) {
661 exit (1);
664 use_config ();
666 goto_editor_window ();
668 BootMessage (_("Ardour is ready for use"));
669 show ();
672 void
673 ARDOUR_UI::no_memory_warning ()
675 XMLNode node (X_("no-memory-warning"));
676 Config->add_instant_xml (node);
679 void
680 ARDOUR_UI::check_memory_locking ()
682 #ifdef __APPLE__
683 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
684 return;
685 #else // !__APPLE__
687 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
689 if (engine->is_realtime() && memory_warning_node == 0) {
691 struct rlimit limits;
692 int64_t ram;
693 long pages, page_size;
695 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
696 ram = 0;
697 } else {
698 ram = (int64_t) pages * (int64_t) page_size;
701 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
702 return;
705 if (limits.rlim_cur != RLIM_INFINITY) {
707 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
710 MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. "
711 "This might cause Ardour to run out of memory before your system "
712 "runs out of memory. \n\n"
713 "You can view the memory limit with 'ulimit -l', "
714 "and it is normally controlled by /etc/security/limits.conf"));
716 VBox* vbox = msg.get_vbox();
717 HBox hbox;
718 CheckButton cb (_("Do not show this window again"));
720 cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning));
722 hbox.pack_start (cb, true, false);
723 vbox->pack_start (hbox);
724 cb.show();
725 vbox->show();
726 hbox.show ();
728 pop_back_splash ();
730 editor->ensure_float (msg);
731 msg.run ();
735 #endif // !__APPLE__
739 void
740 ARDOUR_UI::finish()
742 if (session) {
744 if (session->transport_rolling()) {
745 session->request_stop ();
746 usleep (250000);
749 if (session->dirty()) {
750 switch (ask_about_saving_session(_("quit"))) {
751 case -1:
752 return;
753 break;
754 case 1:
755 /* use the default name */
756 if (save_state_canfail ("")) {
757 /* failed - don't quit */
758 MessageDialog msg (*editor,
759 _("\
760 Ardour was unable to save your session.\n\n\
761 If you still wish to quit, please use the\n\n\
762 \"Just quit\" option."));
763 pop_back_splash();
764 msg.run ();
765 return;
767 break;
768 case 0:
769 break;
773 session->set_deletion_in_progress ();
776 ArdourDialog::close_all_dialogs ();
777 engine->stop (true);
778 save_ardour_state ();
779 quit ();
783 ARDOUR_UI::ask_about_saving_session (const string & what)
785 ArdourDialog window (_("ardour: save session?"));
786 Gtk::HBox dhbox; // the hbox for the image and text
787 Gtk::Label prompt_label;
788 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
790 string msg;
792 msg = string_compose(_("Don't %1"), what);
793 window.add_button (msg, RESPONSE_REJECT);
794 msg = string_compose(_("Just %1"), what);
795 window.add_button (msg, RESPONSE_APPLY);
796 msg = string_compose(_("Save and %1"), what);
797 window.add_button (msg, RESPONSE_ACCEPT);
799 window.set_default_response (RESPONSE_ACCEPT);
801 Gtk::Button noquit_button (msg);
802 noquit_button.set_name ("EditorGTKButton");
804 string prompt;
805 string type;
807 if (session->snap_name() == session->name()) {
808 type = _("session");
809 } else {
810 type = _("snapshot");
812 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?"),
813 type, session->snap_name());
815 prompt_label.set_text (prompt);
816 prompt_label.set_name (X_("PrompterLabel"));
817 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
819 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
820 dhbox.set_homogeneous (false);
821 dhbox.pack_start (*dimage, false, false, 5);
822 dhbox.pack_start (prompt_label, true, false, 5);
823 window.get_vbox()->pack_start (dhbox);
825 window.set_name (_("Prompter"));
826 window.set_position (Gtk::WIN_POS_MOUSE);
827 window.set_modal (true);
828 window.set_resizable (false);
830 dhbox.show();
831 prompt_label.show();
832 dimage->show();
833 window.show();
834 window.set_keep_above (true);
835 window.present ();
837 ResponseType r = (ResponseType) window.run();
839 window.hide ();
841 switch (r) {
842 case RESPONSE_ACCEPT: // save and get out of here
843 return 1;
844 case RESPONSE_APPLY: // get out of here
845 return 0;
846 default:
847 break;
850 return -1;
853 gint
854 ARDOUR_UI::every_second ()
856 update_cpu_load ();
857 update_buffer_load ();
858 update_disk_space ();
859 return TRUE;
862 gint
863 ARDOUR_UI::every_point_one_seconds ()
865 update_speed_display ();
866 RapidScreenUpdate(); /* EMIT_SIGNAL */
867 return TRUE;
870 gint
871 ARDOUR_UI::every_point_zero_one_seconds ()
873 // august 2007: actual update frequency: 40Hz, not 100Hz
875 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
876 return TRUE;
879 void
880 ARDOUR_UI::update_sample_rate (nframes_t ignored)
882 char buf[32];
884 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
886 if (!engine->connected()) {
888 snprintf (buf, sizeof (buf), _("disconnected"));
890 } else {
892 nframes_t rate = engine->frame_rate();
894 if (fmod (rate, 1000.0) != 0.0) {
895 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
896 (float) rate/1000.0f,
897 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
898 } else {
899 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
900 rate/1000,
901 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
905 sample_rate_label.set_text (buf);
908 void
909 ARDOUR_UI::update_cpu_load ()
911 char buf[32];
912 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
913 cpu_load_label.set_text (buf);
916 void
917 ARDOUR_UI::update_buffer_load ()
919 char buf[64];
920 uint32_t c, p;
922 if (session) {
923 c = session->capture_load ();
924 p = session->playback_load ();
926 push_buffer_stats (c, p);
928 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
929 session->playback_load(), session->capture_load());
930 buffer_load_label.set_text (buf);
931 } else {
932 buffer_load_label.set_text ("");
936 void
937 ARDOUR_UI::count_recenabled_streams (Route& route)
939 Track* track = dynamic_cast<Track*>(&route);
940 if (track && track->diskstream()->record_enabled()) {
941 rec_enabled_streams += track->n_inputs().n_total();
945 void
946 ARDOUR_UI::update_disk_space()
948 if (session == 0) {
949 return;
952 nframes_t frames = session->available_capture_duration();
953 char buf[64];
954 nframes_t fr = session->frame_rate();
956 if (frames == max_frames) {
957 strcpy (buf, _("Disk: 24hrs+"));
958 } else {
959 rec_enabled_streams = 0;
960 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
962 if (rec_enabled_streams) {
963 frames /= rec_enabled_streams;
966 int hrs;
967 int mins;
968 int secs;
970 hrs = frames / (fr * 3600);
971 frames -= hrs * fr * 3600;
972 mins = frames / (fr * 60);
973 frames -= mins * fr * 60;
974 secs = frames / fr;
976 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
979 disk_space_label.set_text (buf);
981 // An attempt to make the disk space label flash red when space has run out.
983 if (frames < fr * 60 * 5) {
984 /* disk_space_box.style ("disk_space_label_empty"); */
985 } else {
986 /* disk_space_box.style ("disk_space_label"); */
991 gint
992 ARDOUR_UI::update_wall_clock ()
994 time_t now;
995 struct tm *tm_now;
996 char buf[16];
998 time (&now);
999 tm_now = localtime (&now);
1001 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1002 wall_clock_label.set_text (buf);
1004 return TRUE;
1007 gint
1008 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1010 session_popup_menu->popup (0, 0);
1011 return TRUE;
1014 void
1015 ARDOUR_UI::redisplay_recent_sessions ()
1017 std::vector<sys::path> session_directories;
1018 RecentSessionsSorter cmp;
1020 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1021 recent_session_model->clear ();
1023 ARDOUR::RecentSessions rs;
1024 ARDOUR::read_recent_sessions (rs);
1026 if (rs.empty()) {
1027 recent_session_display.set_model (recent_session_model);
1028 return;
1031 // sort them alphabetically
1032 sort (rs.begin(), rs.end(), cmp);
1034 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1035 session_directories.push_back ((*i).second);
1038 for (vector<sys::path>::const_iterator i = session_directories.begin();
1039 i != session_directories.end(); ++i)
1041 std::vector<sys::path> state_file_paths;
1043 // now get available states for this session
1045 get_state_files_in_directory (*i, state_file_paths);
1047 vector<string*>* states;
1048 vector<const gchar*> item;
1049 string fullpath = (*i).to_string();
1051 /* remove any trailing / */
1053 if (fullpath[fullpath.length()-1] == '/') {
1054 fullpath = fullpath.substr (0, fullpath.length()-1);
1057 /* check whether session still exists */
1058 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1059 /* session doesn't exist */
1060 cerr << "skipping non-existent session " << fullpath << endl;
1061 continue;
1064 /* now get available states for this session */
1066 if ((states = Session::possible_states (fullpath)) == 0) {
1067 /* no state file? */
1068 continue;
1071 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1073 Gtk::TreeModel::Row row = *(recent_session_model->append());
1075 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1076 row[recent_session_columns.fullpath] = fullpath;
1078 if (state_file_names.size() > 1) {
1080 // add the children
1082 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1083 i2 != state_file_names.end(); ++i2)
1086 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1088 child_row[recent_session_columns.visible_name] = *i2;
1089 child_row[recent_session_columns.fullpath] = fullpath;
1094 recent_session_display.set_model (recent_session_model);
1097 void
1098 ARDOUR_UI::build_session_selector ()
1100 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1102 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1104 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1105 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1106 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1107 recent_session_model = TreeStore::create (recent_session_columns);
1108 recent_session_display.set_model (recent_session_model);
1109 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1110 recent_session_display.set_headers_visible (false);
1111 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1112 recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1114 scroller->add (recent_session_display);
1115 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1117 session_selector_window->set_name ("SessionSelectorWindow");
1118 session_selector_window->set_size_request (200, 400);
1119 session_selector_window->get_vbox()->pack_start (*scroller);
1121 recent_session_display.show();
1122 scroller->show();
1123 //session_selector_window->get_vbox()->show();
1126 void
1127 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1129 session_selector_window->response (RESPONSE_ACCEPT);
1132 void
1133 ARDOUR_UI::open_recent_session ()
1135 bool can_return = (session != 0);
1137 if (session_selector_window == 0) {
1138 build_session_selector ();
1141 redisplay_recent_sessions ();
1143 while (true) {
1145 session_selector_window->set_position (WIN_POS_MOUSE);
1147 ResponseType r = (ResponseType) session_selector_window->run ();
1149 switch (r) {
1150 case RESPONSE_ACCEPT:
1151 break;
1152 default:
1153 if (can_return) {
1154 session_selector_window->hide();
1155 return;
1156 } else {
1157 exit (1);
1161 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1162 continue;
1165 session_selector_window->hide();
1167 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1169 if (i == recent_session_model->children().end()) {
1170 return;
1173 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1174 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1176 _session_is_new = false;
1178 if (load_session (path, state) == 0) {
1179 break;
1182 can_return = false;
1186 bool
1187 ARDOUR_UI::check_audioengine ()
1189 if (engine) {
1190 if (!engine->connected()) {
1191 MessageDialog msg (_("Ardour is not connected to JACK\n"
1192 "You cannot open or close sessions in this condition"));
1193 pop_back_splash ();
1194 msg.run ();
1195 return false;
1197 return true;
1198 } else {
1199 return false;
1203 void
1204 ARDOUR_UI::open_session ()
1206 if (!check_audioengine()) {
1207 return;
1211 /* popup selector window */
1213 if (open_session_selector == 0) {
1215 /* ardour sessions are folders */
1217 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1218 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1219 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1220 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1222 FileFilter session_filter;
1223 session_filter.add_pattern ("*.ardour");
1224 session_filter.set_name (_("Ardour sessions"));
1225 open_session_selector->add_filter (session_filter);
1226 open_session_selector->set_filter (session_filter);
1229 int response = open_session_selector->run();
1230 open_session_selector->hide ();
1232 switch (response) {
1233 case RESPONSE_ACCEPT:
1234 break;
1235 default:
1236 open_session_selector->hide();
1237 return;
1240 open_session_selector->hide();
1241 string session_path = open_session_selector->get_filename();
1242 string path, name;
1243 bool isnew;
1245 if (session_path.length() > 0) {
1246 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1247 _session_is_new = isnew;
1248 load_session (path, name);
1254 void
1255 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1257 list<boost::shared_ptr<MidiTrack> > tracks;
1259 if (session == 0) {
1260 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1261 return;
1264 try {
1265 if (disk) {
1267 tracks = session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1269 if (tracks.size() != how_many) {
1270 if (how_many == 1) {
1271 error << _("could not create a new midi track") << endmsg;
1272 } else {
1273 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1276 } /*else {
1277 if ((route = session->new_midi_route ()) == 0) {
1278 error << _("could not create new midi bus") << endmsg;
1283 catch (...) {
1284 MessageDialog msg (*editor,
1285 _("There are insufficient JACK ports available\n\
1286 to create a new track or bus.\n\
1287 You should save Ardour, exit and\n\
1288 restart JACK with more ports."));
1289 msg.run ();
1294 void
1295 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1297 list<boost::shared_ptr<AudioTrack> > tracks;
1298 RouteList routes;
1300 if (session == 0) {
1301 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1302 return;
1305 try {
1306 if (track) {
1307 tracks = session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1309 if (tracks.size() != how_many) {
1310 if (how_many == 1) {
1311 error << _("could not create a new audio track") << endmsg;
1312 } else {
1313 error << string_compose (_("could only create %1 of %2 new audio %3"),
1314 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1318 } else {
1320 routes = session->new_audio_route (input_channels, output_channels, route_group, how_many);
1322 if (routes.size() != how_many) {
1323 if (how_many == 1) {
1324 error << _("could not create a new audio track") << endmsg;
1325 } else {
1326 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1331 #if CONTROLOUTS
1332 if (need_control_room_outs) {
1333 pan_t pans[2];
1335 pans[0] = 0.5;
1336 pans[1] = 0.5;
1338 route->set_stereo_control_outs (control_lr_channels);
1339 route->control_outs()->set_stereo_pan (pans, this);
1341 #endif /* CONTROLOUTS */
1344 catch (...) {
1345 MessageDialog msg (*editor,
1346 _("There are insufficient JACK ports available\n\
1347 to create a new track or bus.\n\
1348 You should save Ardour, exit and\n\
1349 restart JACK with more ports."));
1350 pop_back_splash ();
1351 msg.run ();
1355 void
1356 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1358 nframes_t _preroll = 0;
1360 if (session) {
1361 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1362 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1364 if (new_position > _preroll) {
1365 new_position -= _preroll;
1366 } else {
1367 new_position = 0;
1370 session->request_locate (new_position);
1374 void
1375 ARDOUR_UI::transport_goto_start ()
1377 if (session) {
1378 session->goto_start();
1381 /* force displayed area in editor to start no matter
1382 what "follow playhead" setting is.
1385 if (editor) {
1386 editor->reset_x_origin (session->current_start_frame());
1391 void
1392 ARDOUR_UI::transport_goto_zero ()
1394 if (session) {
1395 session->request_locate (0);
1398 /* force displayed area in editor to start no matter
1399 what "follow playhead" setting is.
1402 if (editor) {
1403 editor->reset_x_origin (0);
1408 void
1409 ARDOUR_UI::transport_goto_wallclock ()
1411 if (session && editor) {
1413 time_t now;
1414 struct tm tmnow;
1415 nframes64_t frames;
1417 time (&now);
1418 localtime_r (&now, &tmnow);
1420 frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
1421 frames += tmnow.tm_min * (60 * session->frame_rate());
1422 frames += tmnow.tm_sec * session->frame_rate();
1424 session->request_locate (frames);
1426 /* force displayed area in editor to start no matter
1427 what "follow playhead" setting is.
1430 if (editor) {
1431 editor->reset_x_origin (frames - (editor->current_page_frames()/2));
1436 void
1437 ARDOUR_UI::transport_goto_end ()
1439 if (session) {
1440 nframes_t frame = session->current_end_frame();
1441 session->request_locate (frame);
1443 /* force displayed area in editor to start no matter
1444 what "follow playhead" setting is.
1447 if (editor) {
1448 editor->reset_x_origin (frame);
1453 void
1454 ARDOUR_UI::transport_stop ()
1456 if (!session) {
1457 return;
1460 if (session->is_auditioning()) {
1461 session->cancel_audition ();
1462 return;
1465 if (session->get_play_loop ()) {
1466 session->request_play_loop (false);
1469 session->request_stop ();
1472 void
1473 ARDOUR_UI::transport_stop_and_forget_capture ()
1475 if (session) {
1476 session->request_stop (true);
1480 void
1481 ARDOUR_UI::remove_last_capture()
1483 if (editor) {
1484 editor->remove_last_capture();
1488 void
1489 ARDOUR_UI::transport_record (bool roll)
1492 if (session) {
1493 switch (session->record_status()) {
1494 case Session::Disabled:
1495 if (session->ntracks() == 0) {
1496 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1497 msg.run ();
1498 return;
1500 session->maybe_enable_record ();
1501 if (roll) {
1502 transport_roll ();
1504 break;
1505 case Session::Recording:
1506 if (roll) {
1507 session->request_stop();
1508 } else {
1509 session->disable_record (false, true);
1511 break;
1513 case Session::Enabled:
1514 session->disable_record (false, true);
1517 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1520 void
1521 ARDOUR_UI::transport_roll ()
1523 bool rolling;
1525 if (!session) {
1526 return;
1529 rolling = session->transport_rolling ();
1531 //cerr << "ARDOUR_UI::transport_roll () called session->record_status() = " << session->record_status() << endl;
1533 if (session->get_play_loop()) {
1534 session->request_play_loop (false);
1535 auto_loop_button.set_visual_state (1);
1536 roll_button.set_visual_state (1);
1537 } else if (session->get_play_range ()) {
1538 session->request_play_range (false);
1539 play_selection_button.set_visual_state (0);
1540 } else if (rolling) {
1541 session->request_locate (session->last_transport_start(), true);
1544 session->request_transport_speed (1.0f);
1547 void
1548 ARDOUR_UI::transport_loop()
1550 if (session) {
1551 if (session->get_play_loop()) {
1552 if (session->transport_rolling()) {
1553 Location * looploc = session->locations()->auto_loop_location();
1554 if (looploc) {
1555 session->request_locate (looploc->start(), true);
1559 else {
1560 session->request_play_loop (true);
1565 void
1566 ARDOUR_UI::transport_play_selection ()
1568 if (!session) {
1569 return;
1572 if (!session->get_play_range()) {
1573 session->request_stop ();
1576 editor->play_selection ();
1579 void
1580 ARDOUR_UI::transport_rewind (int option)
1582 float current_transport_speed;
1584 if (session) {
1585 current_transport_speed = session->transport_speed();
1587 if (current_transport_speed >= 0.0f) {
1588 switch (option) {
1589 case 0:
1590 session->request_transport_speed (-1.0f);
1591 break;
1592 case 1:
1593 session->request_transport_speed (-4.0f);
1594 break;
1595 case -1:
1596 session->request_transport_speed (-0.5f);
1597 break;
1599 } else {
1600 /* speed up */
1601 session->request_transport_speed (current_transport_speed * 1.5f);
1606 void
1607 ARDOUR_UI::transport_forward (int option)
1609 float current_transport_speed;
1611 if (session) {
1612 current_transport_speed = session->transport_speed();
1614 if (current_transport_speed <= 0.0f) {
1615 switch (option) {
1616 case 0:
1617 session->request_transport_speed (1.0f);
1618 break;
1619 case 1:
1620 session->request_transport_speed (4.0f);
1621 break;
1622 case -1:
1623 session->request_transport_speed (0.5f);
1624 break;
1626 } else {
1627 /* speed up */
1628 session->request_transport_speed (current_transport_speed * 1.5f);
1633 void
1634 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1636 if (session == 0) {
1637 return;
1640 boost::shared_ptr<Route> r;
1642 if ((r = session->route_by_remote_id (dstream)) != 0) {
1644 Track* t;
1646 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1647 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1650 if (session == 0) {
1651 return;
1655 void
1656 ARDOUR_UI::queue_transport_change ()
1658 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1661 void
1662 ARDOUR_UI::map_transport_state ()
1664 float sp = session->transport_speed();
1666 if (sp == 1.0f) {
1667 transport_rolling ();
1668 } else if (sp < 0.0f) {
1669 transport_rewinding ();
1670 } else if (sp > 0.0f) {
1671 transport_forwarding ();
1672 } else {
1673 transport_stopped ();
1677 void
1678 ARDOUR_UI::engine_stopped ()
1680 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1681 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1682 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1685 void
1686 ARDOUR_UI::engine_running ()
1688 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1689 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1690 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1692 Glib::RefPtr<Action> action;
1693 const char* action_name = 0;
1695 switch (engine->frames_per_cycle()) {
1696 case 32:
1697 action_name = X_("JACKLatency32");
1698 break;
1699 case 64:
1700 action_name = X_("JACKLatency64");
1701 break;
1702 case 128:
1703 action_name = X_("JACKLatency128");
1704 break;
1705 case 512:
1706 action_name = X_("JACKLatency512");
1707 break;
1708 case 1024:
1709 action_name = X_("JACKLatency1024");
1710 break;
1711 case 2048:
1712 action_name = X_("JACKLatency2048");
1713 break;
1714 case 4096:
1715 action_name = X_("JACKLatency4096");
1716 break;
1717 case 8192:
1718 action_name = X_("JACKLatency8192");
1719 break;
1720 default:
1721 /* XXX can we do anything useful ? */
1722 break;
1725 if (action_name) {
1727 action = ActionManager::get_action (X_("JACK"), action_name);
1729 if (action) {
1730 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1731 ract->set_active ();
1736 void
1737 ARDOUR_UI::engine_halted ()
1739 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1741 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1742 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1744 update_sample_rate (0);
1746 MessageDialog msg (*editor,
1747 _("\
1748 JACK has either been shutdown or it\n\
1749 disconnected Ardour because Ardour\n\
1750 was not fast enough. Try to restart\n\
1751 JACK, reconnect and save the session."));
1752 pop_back_splash ();
1753 msg.run ();
1756 int32_t
1757 ARDOUR_UI::do_engine_start ()
1759 try {
1760 engine->start();
1763 catch (...) {
1764 engine->stop ();
1765 error << _("Unable to start the session running")
1766 << endmsg;
1767 unload_session ();
1768 return -2;
1771 return 0;
1774 void
1775 ARDOUR_UI::setup_theme ()
1777 theme_manager->setup_theme();
1780 void
1781 ARDOUR_UI::update_clocks ()
1783 if (!editor || !editor->dragging_playhead()) {
1784 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1788 void
1789 ARDOUR_UI::start_clocking ()
1791 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1794 void
1795 ARDOUR_UI::stop_clocking ()
1797 clock_signal_connection.disconnect ();
1800 void
1801 ARDOUR_UI::toggle_clocking ()
1803 #if 0
1804 if (clock_button.get_active()) {
1805 start_clocking ();
1806 } else {
1807 stop_clocking ();
1809 #endif
1812 gint
1813 ARDOUR_UI::_blink (void *arg)
1816 ((ARDOUR_UI *) arg)->blink ();
1817 return TRUE;
1820 void
1821 ARDOUR_UI::blink ()
1823 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1826 void
1827 ARDOUR_UI::start_blinking ()
1829 /* Start the blink signal. Everybody with a blinking widget
1830 uses Blink to drive the widget's state.
1833 if (blink_timeout_tag < 0) {
1834 blink_on = false;
1835 blink_timeout_tag = g_timeout_add (240, _blink, this);
1839 void
1840 ARDOUR_UI::stop_blinking ()
1842 if (blink_timeout_tag >= 0) {
1843 g_source_remove (blink_timeout_tag);
1844 blink_timeout_tag = -1;
1849 /** Ask the user for the name of a new shapshot and then take it.
1851 void
1852 ARDOUR_UI::snapshot_session ()
1854 ArdourPrompter prompter (true);
1855 string snapname;
1856 char timebuf[128];
1857 time_t n;
1858 struct tm local_time;
1860 time (&n);
1861 localtime_r (&n, &local_time);
1862 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1864 prompter.set_name ("Prompter");
1865 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1866 prompter.set_title (_("Take Snapshot"));
1867 prompter.set_prompt (_("Name of New Snapshot"));
1868 prompter.set_initial_text (timebuf);
1870 switch (prompter.run()) {
1871 case RESPONSE_ACCEPT:
1873 prompter.get_result (snapname);
1875 bool do_save = (snapname.length() != 0);
1877 vector<sys::path> p;
1878 get_state_files_in_directory (session->session_directory().root_path(), p);
1879 vector<string> n = get_file_names_no_extension (p);
1880 if (find (n.begin(), n.end(), snapname) != n.end()) {
1882 ArdourDialog confirm (_("Confirm snapshot overwrite"), true);
1883 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
1884 confirm.get_vbox()->pack_start (m, true, true);
1885 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1886 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
1887 confirm.show_all ();
1888 switch (confirm.run()) {
1889 case RESPONSE_CANCEL:
1890 do_save = false;
1894 if (do_save) {
1895 save_state (snapname);
1897 break;
1900 default:
1901 break;
1905 void
1906 ARDOUR_UI::save_state (const string & name)
1908 (void) save_state_canfail (name);
1912 ARDOUR_UI::save_state_canfail (string name)
1914 if (session) {
1915 int ret;
1917 if (name.length() == 0) {
1918 name = session->snap_name();
1921 if ((ret = session->save_state (name)) != 0) {
1922 return ret;
1925 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1926 return 0;
1929 void
1930 ARDOUR_UI::primary_clock_value_changed ()
1932 if (session) {
1933 session->request_locate (primary_clock.current_time ());
1937 void
1938 ARDOUR_UI::big_clock_value_changed ()
1940 if (session) {
1941 session->request_locate (big_clock.current_time ());
1945 void
1946 ARDOUR_UI::secondary_clock_value_changed ()
1948 if (session) {
1949 session->request_locate (secondary_clock.current_time ());
1953 void
1954 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
1956 if (session == 0) {
1957 return;
1960 Session::RecordState const r = session->record_status ();
1961 bool const h = session->have_rec_enabled_diskstream ();
1963 if (r == Session::Enabled || (r == Session::Recording && !h)) {
1964 if (onoff) {
1965 rec_button.set_visual_state (2);
1966 } else {
1967 rec_button.set_visual_state (0);
1969 } else if (r == Session::Recording && h) {
1970 rec_button.set_visual_state (1);
1971 } else {
1972 rec_button.set_visual_state (0);
1976 void
1977 ARDOUR_UI::save_template ()
1979 ArdourPrompter prompter (true);
1980 string name;
1982 if (!check_audioengine()) {
1983 return;
1986 prompter.set_name (X_("Prompter"));
1987 prompter.set_title (_("Save Mix Template"));
1988 prompter.set_prompt (_("Name for mix template:"));
1989 prompter.set_initial_text(session->name() + _("-template"));
1990 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1992 switch (prompter.run()) {
1993 case RESPONSE_ACCEPT:
1994 prompter.get_result (name);
1996 if (name.length()) {
1997 session->save_template (name);
1999 break;
2001 default:
2002 break;
2006 void
2007 ARDOUR_UI::edit_metadata ()
2009 SessionMetadataEditor dialog;
2010 dialog.set_session (session);
2011 editor->ensure_float (dialog);
2012 dialog.run ();
2015 void
2016 ARDOUR_UI::import_metadata ()
2018 SessionMetadataImporter dialog;
2019 dialog.set_session (session);
2020 editor->ensure_float (dialog);
2021 dialog.run ();
2024 void
2025 ARDOUR_UI::fontconfig_dialog ()
2027 #ifdef GTKOSX
2028 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2029 may not and it can take a while to build it. Warn them.
2032 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2034 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2035 MessageDialog msg (*_startup,
2036 _("Welcome to Ardour.\n\n"
2037 "The program will take a bit longer to start up\n"
2038 "while the system fonts are checked.\n\n"
2039 "This will only be done once, and you will\n"
2040 "not see this message again\n"),
2041 true,
2042 Gtk::MESSAGE_INFO,
2043 Gtk::BUTTONS_OK);
2044 pop_back_splash ();
2045 msg.show_all ();
2046 msg.present ();
2047 msg.run ();
2049 #endif
2052 void
2053 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2055 existing_session = false;
2057 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2058 session_path = cmdline_path;
2059 existing_session = true;
2060 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2061 session_path = Glib::path_get_dirname (string (cmdline_path));
2062 existing_session = true;
2063 } else {
2064 /* it doesn't exist, assume the best */
2065 session_path = Glib::path_get_dirname (string (cmdline_path));
2068 session_name = basename_nosuffix (string (cmdline_path));
2072 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2074 /* when this is called, the backend audio system must be running */
2076 /* the main idea here is to deal with the fact that a cmdline argument for the session
2077 can be interpreted in different ways - it could be a directory or a file, and before
2078 we load, we need to know both the session directory and the snapshot (statefile) within it
2079 that we are supposed to use.
2082 if (session_name.length() == 0 || session_path.length() == 0) {
2083 return false;
2086 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2088 Glib::ustring predicted_session_file;
2090 predicted_session_file = session_path;
2091 predicted_session_file += '/';
2092 predicted_session_file += session_name;
2093 predicted_session_file += ARDOUR::statefile_suffix;
2095 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2096 existing_session = true;
2099 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2101 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2102 /* existing .ardour file */
2103 existing_session = true;
2106 } else {
2107 existing_session = false;
2110 /* lets just try to load it */
2112 if (create_engine ()) {
2113 backend_audio_error (false, _startup);
2114 return -1;
2117 return load_session (session_path, session_name);
2120 bool
2121 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2123 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2125 MessageDialog msg (str,
2126 false,
2127 Gtk::MESSAGE_WARNING,
2128 Gtk::BUTTONS_YES_NO,
2129 true);
2132 msg.set_name (X_("CleanupDialog"));
2133 msg.set_title (_("Cleanup Unused Sources"));
2134 msg.set_wmclass (X_("existing_session"), "Ardour");
2135 msg.set_position (Gtk::WIN_POS_MOUSE);
2136 pop_back_splash ();
2138 switch (msg.run()) {
2139 case RESPONSE_YES:
2140 return true;
2141 break;
2143 return false;
2147 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2150 uint32_t cchns;
2151 uint32_t mchns;
2152 AutoConnectOption iconnect;
2153 AutoConnectOption oconnect;
2154 uint32_t nphysin;
2155 uint32_t nphysout;
2157 if (Profile->get_sae()) {
2159 cchns = 0;
2160 mchns = 2;
2161 iconnect = AutoConnectPhysical;
2162 oconnect = AutoConnectMaster;
2163 nphysin = 0; // use all available
2164 nphysout = 0; // use all available
2166 } else {
2168 /* get settings from advanced section of NSD */
2170 if (_startup->create_control_bus()) {
2171 cchns = (uint32_t) _startup->control_channel_count();
2172 } else {
2173 cchns = 0;
2176 if (_startup->create_master_bus()) {
2177 mchns = (uint32_t) _startup->master_channel_count();
2178 } else {
2179 mchns = 0;
2182 if (_startup->connect_inputs()) {
2183 iconnect = AutoConnectPhysical;
2184 } else {
2185 iconnect = AutoConnectOption (0);
2188 /// @todo some minor tweaks.
2190 oconnect = AutoConnectOption (0);
2192 if (_startup->connect_outputs ()) {
2193 if (_startup->connect_outs_to_master()) {
2194 oconnect = AutoConnectMaster;
2195 } else if (_startup->connect_outs_to_physical()) {
2196 oconnect = AutoConnectPhysical;
2200 nphysin = (uint32_t) _startup->input_limit_count();
2201 nphysout = (uint32_t) _startup->output_limit_count();
2204 if (build_session (session_path,
2205 session_name,
2206 cchns,
2207 mchns,
2208 iconnect,
2209 oconnect,
2210 nphysin,
2211 nphysout,
2212 engine->frame_rate() * 60 * 5)) {
2214 return -1;
2217 return 0;
2220 void
2221 ARDOUR_UI::idle_load (const Glib::ustring& path)
2223 if (session) {
2224 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2225 /* /path/to/foo => /path/to/foo, foo */
2226 load_session (path, basename_nosuffix (path));
2227 } else {
2228 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2229 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2231 } else {
2233 ARDOUR_COMMAND_LINE::session_name = path;
2236 * new_session_dialog doens't exist in A3
2237 * Try to remove all references to it to
2238 * see if it will compile. NOTE: this will
2239 * likely cause a runtime issue is my somewhat
2240 * uneducated guess.
2243 //if (new_session_dialog) {
2246 /* make it break out of Dialog::run() and
2247 start again.
2250 //new_session_dialog->response (1);
2255 void
2256 ARDOUR_UI::end_loading_messages ()
2258 // hide_splash ();
2261 void
2262 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2264 // show_splash ();
2265 // splash->message (msg);
2266 flush_pending ();
2269 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2271 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new)
2273 Glib::ustring session_name;
2274 Glib::ustring session_path;
2275 Glib::ustring template_name;
2276 int ret = -1;
2277 bool likely_new = false;
2279 while (ret != 0) {
2281 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2283 /* if they named a specific statefile, use it, otherwise they are
2284 just giving a session folder, and we want to use it as is
2285 to find the session.
2288 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2289 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2290 } else {
2291 session_path = ARDOUR_COMMAND_LINE::session_name;
2294 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2296 } else {
2298 bool const apply = run_startup (should_be_new);
2299 if (!apply) {
2300 if (quit_on_cancel) {
2301 exit (1);
2302 } else {
2303 return ret;
2307 /* if we run the startup dialog again, offer more than just "new session" */
2309 should_be_new = false;
2311 session_name = _startup->session_name (likely_new);
2313 /* this shouldn't happen, but we catch it just in case it does */
2315 if (session_name.empty()) {
2316 break;
2318 if (_startup->use_session_template()) {
2319 template_name = _startup->session_template_name();
2320 _session_is_new = true;
2323 if (session_name[0] == '/' ||
2324 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2325 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2327 session_path = Glib::path_get_dirname (session_name);
2328 session_name = Glib::path_get_basename (session_name);
2330 } else {
2332 session_path = _startup->session_folder();
2336 if (create_engine ()) {
2337 break;
2340 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2342 if (likely_new) {
2344 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2346 if (!ask_about_loading_existing_session (existing)) {
2347 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2348 continue;
2352 _session_is_new = false;
2354 } else {
2356 if (!likely_new) {
2357 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2358 msg.run ();
2359 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2360 continue;
2363 _session_is_new = true;
2366 if (likely_new && template_name.empty()) {
2368 ret = build_session_from_nsd (session_path, session_name);
2370 } else {
2372 ret = load_session (session_path, session_name, template_name);
2373 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2374 session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2375 exit (1);
2380 return ret;
2383 void
2384 ARDOUR_UI::close_session()
2386 if (!check_audioengine()) {
2387 return;
2390 unload_session (true);
2392 ARDOUR_COMMAND_LINE::session_name = "";
2393 get_session_parameters (true, false);
2397 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2399 Session *new_session;
2400 int unload_status;
2401 int retval = -1;
2403 session_loaded = false;
2405 if (!check_audioengine()) {
2406 return -1;
2409 unload_status = unload_session ();
2411 if (unload_status < 0) {
2412 goto out;
2413 } else if (unload_status > 0) {
2414 retval = 0;
2415 goto out;
2418 loading_message (_("Please wait while Ardour loads your session"));
2420 try {
2421 new_session = new Session (*engine, path, snap_name, mix_template);
2424 /* this one is special */
2426 catch (AudioEngine::PortRegistrationFailure& err) {
2428 MessageDialog msg (err.what(),
2429 true,
2430 Gtk::MESSAGE_INFO,
2431 Gtk::BUTTONS_CLOSE);
2433 msg.set_title (_("Port Registration Error"));
2434 msg.set_secondary_text (_("Click the Close button to try again."));
2435 msg.set_position (Gtk::WIN_POS_CENTER);
2436 pop_back_splash ();
2437 msg.present ();
2439 int response = msg.run ();
2441 msg.hide ();
2443 switch (response) {
2444 case RESPONSE_CANCEL:
2445 exit (1);
2446 default:
2447 break;
2449 goto out;
2452 catch (...) {
2454 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2455 true,
2456 Gtk::MESSAGE_INFO,
2457 Gtk::BUTTONS_CLOSE);
2459 msg.set_title (_("Loading Error"));
2460 msg.set_secondary_text (_("Click the Close button to try again."));
2461 msg.set_position (Gtk::WIN_POS_CENTER);
2462 pop_back_splash ();
2463 msg.present ();
2465 int response = msg.run ();
2467 msg.hide ();
2469 switch (response) {
2470 case RESPONSE_CANCEL:
2471 exit (1);
2472 default:
2473 break;
2475 goto out;
2478 connect_to_session (new_session);
2480 session_loaded = true;
2482 goto_editor_window ();
2484 if (session) {
2485 session->set_clean ();
2488 flush_pending ();
2489 retval = 0;
2491 out:
2492 return retval;
2496 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2497 uint32_t control_channels,
2498 uint32_t master_channels,
2499 AutoConnectOption input_connect,
2500 AutoConnectOption output_connect,
2501 uint32_t nphysin,
2502 uint32_t nphysout,
2503 nframes_t initial_length)
2505 Session *new_session;
2506 int x;
2508 if (!check_audioengine()) {
2509 return -1;
2512 session_loaded = false;
2514 x = unload_session ();
2516 if (x < 0) {
2517 return -1;
2518 } else if (x > 0) {
2519 return 0;
2522 _session_is_new = true;
2524 try {
2525 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2526 control_channels, master_channels, nphysin, nphysout, initial_length);
2529 catch (...) {
2531 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2532 pop_back_splash ();
2533 msg.run ();
2534 return -1;
2537 connect_to_session (new_session);
2539 session_loaded = true;
2541 new_session->save_state(new_session->name());
2543 return 0;
2546 void
2547 ARDOUR_UI::show ()
2549 if (editor) {
2550 editor->show_window ();
2552 if (!shown_flag) {
2553 editor->present ();
2556 shown_flag = true;
2560 void
2561 ARDOUR_UI::show_about ()
2563 if (about == 0) {
2564 about = new About;
2565 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2568 about->show_all ();
2571 void
2572 ARDOUR_UI::hide_about ()
2574 if (about) {
2575 about->get_window()->set_cursor ();
2576 about->hide ();
2580 void
2581 ARDOUR_UI::about_signal_response (int /*response*/)
2583 hide_about();
2586 void
2587 ARDOUR_UI::show_splash ()
2589 if (splash == 0) {
2590 try {
2591 splash = new Splash;
2592 } catch (...) {
2593 return;
2597 splash->show ();
2598 splash->present ();
2599 splash->queue_draw ();
2600 splash->get_window()->process_updates (true);
2601 flush_pending ();
2604 void
2605 ARDOUR_UI::hide_splash ()
2607 if (splash) {
2608 splash->hide();
2612 void
2613 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title,
2614 const string& plural_msg, const string& singular_msg)
2616 size_t removed;
2618 removed = rep.paths.size();
2620 if (removed == 0) {
2621 MessageDialog msgd (*editor,
2622 _("No audio files were ready for cleanup"),
2623 true,
2624 Gtk::MESSAGE_INFO,
2625 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2626 msgd.set_secondary_text (_("If this seems suprising, \n\
2627 check for any existing snapshots.\n\
2628 These may still include regions that\n\
2629 require some unused files to continue to exist."));
2631 msgd.run ();
2632 return;
2635 ArdourDialog results (_("ardour: cleanup"), true, false);
2637 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2638 CleanupResultsModelColumns() {
2639 add (visible_name);
2640 add (fullpath);
2642 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2643 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2647 CleanupResultsModelColumns results_columns;
2648 Glib::RefPtr<Gtk::ListStore> results_model;
2649 Gtk::TreeView results_display;
2651 results_model = ListStore::create (results_columns);
2652 results_display.set_model (results_model);
2653 results_display.append_column (list_title, results_columns.visible_name);
2655 results_display.set_name ("CleanupResultsList");
2656 results_display.set_headers_visible (true);
2657 results_display.set_headers_clickable (false);
2658 results_display.set_reorderable (false);
2660 Gtk::ScrolledWindow list_scroller;
2661 Gtk::Label txt;
2662 Gtk::VBox dvbox;
2663 Gtk::HBox dhbox; // the hbox for the image and text
2664 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2665 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2667 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2669 const string dead_sound_directory = session->session_directory().dead_sound_path().to_string();
2674 /* subst:
2675 %1 - number of files removed
2676 %2 - location of "dead_sounds"
2677 %3 - size of files affected
2678 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2681 const char* bprefix;
2683 if (rep.space < 1048576.0f) {
2684 bprefix = X_("kilo");
2685 } else if (rep.space < 1048576.0f * 1000) {
2686 bprefix = X_("mega");
2687 } else {
2688 bprefix = X_("giga");
2691 if (removed > 1) {
2692 txt.set_text (string_compose (plural_msg, removed, dead_sound_directory, (float) rep.space / 1024.0f, bprefix));
2693 } else {
2694 txt.set_text (string_compose (singular_msg, removed, dead_sound_directory, (float) rep.space / 1024.0f, bprefix));
2697 dhbox.pack_start (*dimage, true, false, 5);
2698 dhbox.pack_start (txt, true, false, 5);
2700 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2701 TreeModel::Row row = *(results_model->append());
2702 row[results_columns.visible_name] = *i;
2703 row[results_columns.fullpath] = *i;
2706 list_scroller.add (results_display);
2707 list_scroller.set_size_request (-1, 150);
2708 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2710 dvbox.pack_start (dhbox, true, false, 5);
2711 dvbox.pack_start (list_scroller, true, false, 5);
2712 ddhbox.pack_start (dvbox, true, false, 5);
2714 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2715 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2716 results.set_default_response (RESPONSE_CLOSE);
2717 results.set_position (Gtk::WIN_POS_MOUSE);
2719 results_display.show();
2720 list_scroller.show();
2721 txt.show();
2722 dvbox.show();
2723 dhbox.show();
2724 ddhbox.show();
2725 dimage->show();
2727 //results.get_vbox()->show();
2728 results.set_resizable (false);
2730 results.run ();
2734 void
2735 ARDOUR_UI::cleanup ()
2737 if (session == 0) {
2738 /* shouldn't happen: menu item is insensitive */
2739 return;
2743 MessageDialog checker (_("Are you sure you want to cleanup?"),
2744 true,
2745 Gtk::MESSAGE_QUESTION,
2746 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2748 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2749 ALL undo/redo information will be lost if you cleanup.\n\
2750 After cleanup, unused audio files will be moved to a \
2751 \"dead sounds\" location."));
2753 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2754 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2755 checker.set_default_response (RESPONSE_CANCEL);
2757 checker.set_name (_("CleanupDialog"));
2758 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2759 checker.set_position (Gtk::WIN_POS_MOUSE);
2761 switch (checker.run()) {
2762 case RESPONSE_ACCEPT:
2763 break;
2764 default:
2765 return;
2768 Session::cleanup_report rep;
2770 editor->prepare_for_cleanup ();
2772 /* do not allow flush until a session is reloaded */
2774 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2775 if (act) {
2776 act->set_sensitive (false);
2779 if (session->cleanup_sources (rep)) {
2780 editor->finish_cleanup ();
2781 return;
2784 editor->finish_cleanup ();
2786 checker.hide();
2787 display_cleanup_results (rep,
2788 _("cleaned files"),
2789 _("\
2790 The following %1 files were not in use and \n\
2791 have been moved to:\n\
2792 %2. \n\n\
2793 Flushing the wastebasket will \n\
2794 release an additional\n\
2795 %3 %4bytes of disk space.\n"),
2796 _("\
2797 The following file was not in use and \n \
2798 has been moved to:\n \
2799 %2. \n\n\
2800 Flushing the wastebasket will \n\
2801 release an additional\n\
2802 %3 %4bytes of disk space.\n"
2807 void
2808 ARDOUR_UI::flush_trash ()
2810 if (session == 0) {
2811 /* shouldn't happen: menu item is insensitive */
2812 return;
2815 Session::cleanup_report rep;
2817 if (session->cleanup_trash_sources (rep)) {
2818 return;
2821 display_cleanup_results (rep,
2822 _("deleted file"),
2823 _("The following %1 files were deleted from\n\
2824 %2,\n\
2825 releasing %3 %4bytes of disk space"),
2826 _("The following file was deleted from\n\
2827 %2,\n\
2828 releasing %3 %4bytes of disk space"));
2831 void
2832 ARDOUR_UI::add_route (Gtk::Window* float_window)
2834 int count;
2836 if (!session) {
2837 return;
2840 if (add_route_dialog == 0) {
2841 add_route_dialog = new AddRouteDialog (*session);
2842 if (float_window) {
2843 add_route_dialog->set_transient_for (*float_window);
2847 if (add_route_dialog->is_visible()) {
2848 /* we're already doing this */
2849 return;
2852 ResponseType r = (ResponseType) add_route_dialog->run ();
2854 add_route_dialog->hide();
2856 switch (r) {
2857 case RESPONSE_ACCEPT:
2858 break;
2859 default:
2860 return;
2861 break;
2864 if ((count = add_route_dialog->count()) <= 0) {
2865 return;
2868 string template_path = add_route_dialog->track_template();
2870 if (!template_path.empty()) {
2871 session->new_route_from_template (count, template_path);
2872 return;
2875 uint32_t input_chan = add_route_dialog->channels ();
2876 uint32_t output_chan;
2877 string name_template = add_route_dialog->name_template ();
2878 bool track = add_route_dialog->track ();
2879 RouteGroup* route_group = add_route_dialog->route_group ();
2881 AutoConnectOption oac = Config->get_output_auto_connect();
2883 if (oac & AutoConnectMaster) {
2884 output_chan = (session->master_out() ? session->master_out()->n_inputs().n_audio() : input_chan);
2885 } else {
2886 output_chan = input_chan;
2889 /* XXX do something with name template */
2891 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
2892 if (track) {
2893 session_add_midi_track (route_group, count);
2894 } else {
2895 MessageDialog msg (*editor,
2896 _("Sorry, MIDI Busses are not supported at this time."));
2897 msg.run ();
2898 //session_add_midi_bus();
2900 } else {
2901 if (track) {
2902 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
2903 } else {
2904 session_add_audio_bus (input_chan, output_chan, route_group, count);
2909 XMLNode*
2910 ARDOUR_UI::mixer_settings () const
2912 XMLNode* node = 0;
2914 if (session) {
2915 node = session->instant_xml(X_("Mixer"));
2916 } else {
2917 node = Config->instant_xml(X_("Mixer"));
2920 if (!node) {
2921 node = new XMLNode (X_("Mixer"));
2924 return node;
2927 XMLNode*
2928 ARDOUR_UI::editor_settings () const
2930 XMLNode* node = 0;
2932 if (session) {
2933 node = session->instant_xml(X_("Editor"));
2934 } else {
2935 node = Config->instant_xml(X_("Editor"));
2938 if (!node) {
2939 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
2940 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
2944 if (!node) {
2945 node = new XMLNode (X_("Editor"));
2948 return node;
2951 XMLNode*
2952 ARDOUR_UI::keyboard_settings () const
2954 XMLNode* node = 0;
2956 node = Config->extra_xml(X_("Keyboard"));
2958 if (!node) {
2959 node = new XMLNode (X_("Keyboard"));
2961 return node;
2964 void
2965 ARDOUR_UI::create_xrun_marker(nframes_t where)
2967 editor->mouse_add_new_marker (where, false, true);
2970 void
2971 ARDOUR_UI::halt_on_xrun_message ()
2973 MessageDialog msg (*editor,
2974 _("Recording was stopped because your system could not keep up."));
2975 msg.run ();
2978 void
2979 ARDOUR_UI::xrun_handler(nframes_t where)
2981 if (!session) {
2982 return;
2985 ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::xrun_handler), where));
2987 if (session && Config->get_create_xrun_marker() && session->actively_recording()) {
2988 create_xrun_marker(where);
2991 if (session && Config->get_stop_recording_on_xrun() && session->actively_recording()) {
2992 halt_on_xrun_message ();
2996 void
2997 ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
2999 time_t now;
3000 time (&now);
3002 while (disk_buffer_stats.size() > 60) {
3003 disk_buffer_stats.pop_front ();
3006 disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
3009 void
3010 ARDOUR_UI::write_buffer_stats ()
3012 struct tm tm;
3013 char buf[64];
3015 char* tmplt = (char*)calloc(strlen("ardourXXXXXX"), sizeof(char));
3016 int fd = mkstemp (tmplt);
3017 if (fd) {
3018 cerr << X_("cannot find temporary name for ardour buffer stats") << endl;
3019 return;
3022 FILE* fout = fdopen (fd, "w");
3023 if (!fout) {
3024 cerr << string_compose (X_("cannot open file %1 for ardour buffer stats"), tmplt) << endl;
3025 return;
3028 for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
3029 std::ostringstream ss;
3030 localtime_r (&(*i).when, &tm);
3031 strftime (buf, sizeof (buf), "%T", &tm);
3032 fprintf(fout, "%s %u %u\n", buf, (*i).capture, (*i).playback);
3035 disk_buffer_stats.clear ();
3037 fclose (fout);
3038 close (fd);
3040 cerr << "Ardour buffering statistics can be found in: " << tmplt << endl;
3041 free (tmplt);
3044 void
3045 ARDOUR_UI::disk_overrun_handler ()
3047 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
3049 write_buffer_stats ();
3051 if (!have_disk_speed_dialog_displayed) {
3052 have_disk_speed_dialog_displayed = true;
3053 MessageDialog* msg = new MessageDialog (*editor, _("\
3054 The disk system on your computer\n\
3055 was not able to keep up with Ardour.\n\
3057 Specifically, it failed to write data to disk\n\
3058 quickly enough to keep up with recording.\n"));
3059 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3060 msg->show ();
3064 void
3065 ARDOUR_UI::disk_underrun_handler ()
3067 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
3069 write_buffer_stats ();
3071 if (!have_disk_speed_dialog_displayed) {
3072 have_disk_speed_dialog_displayed = true;
3073 MessageDialog* msg = new MessageDialog (*editor,
3074 _("The disk system on your computer\n\
3075 was not able to keep up with Ardour.\n\
3077 Specifically, it failed to read data from disk\n\
3078 quickly enough to keep up with playback.\n"));
3079 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3080 msg->show ();
3084 void
3085 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3087 have_disk_speed_dialog_displayed = false;
3088 delete msg;
3091 void
3092 ARDOUR_UI::session_dialog (std::string msg)
3094 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
3096 MessageDialog* d;
3098 if (editor) {
3099 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3100 } else {
3101 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3104 d->show_all ();
3105 d->run ();
3106 delete d;
3110 ARDOUR_UI::pending_state_dialog ()
3112 HBox* hbox = new HBox();
3113 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3114 ArdourDialog dialog (_("Crash Recovery"), true);
3115 Label message (_("\
3116 This session appears to have been in\n\
3117 middle of recording when ardour or\n\
3118 the computer was shutdown.\n\
3120 Ardour can recover any captured audio for\n\
3121 you, or it can ignore it. Please decide\n\
3122 what you would like to do.\n"));
3123 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3124 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3125 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3126 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3127 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3128 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3129 dialog.set_default_response (RESPONSE_ACCEPT);
3130 dialog.set_position (WIN_POS_CENTER);
3131 message.show();
3132 image->show();
3133 hbox->show();
3135 switch (dialog.run ()) {
3136 case RESPONSE_ACCEPT:
3137 return 1;
3138 default:
3139 return 0;
3144 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3146 HBox* hbox = new HBox();
3147 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3148 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3149 Label message (string_compose (_("\
3150 This session was created with a sample rate of %1 Hz\n\
3152 The audioengine is currently running at %2 Hz\n"), desired, actual));
3154 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3155 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3156 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3157 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3158 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3159 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3160 dialog.set_default_response (RESPONSE_ACCEPT);
3161 dialog.set_position (WIN_POS_CENTER);
3162 message.show();
3163 image->show();
3164 hbox->show();
3166 switch (dialog.run ()) {
3167 case RESPONSE_ACCEPT:
3168 return 0;
3169 default:
3170 return 1;
3175 void
3176 ARDOUR_UI::disconnect_from_jack ()
3178 if (engine) {
3179 if( engine->disconnect_from_jack ()) {
3180 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3181 msg.run ();
3184 update_sample_rate (0);
3188 void
3189 ARDOUR_UI::reconnect_to_jack ()
3191 if (engine) {
3192 if (engine->reconnect_to_jack ()) {
3193 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3194 msg.run ();
3197 update_sample_rate (0);
3201 void
3202 ARDOUR_UI::use_config ()
3205 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3206 if (node) {
3207 set_transport_controllable_state (*node);
3211 void
3212 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3214 if (Config->get_primary_clock_delta_edit_cursor()) {
3215 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3216 } else {
3217 primary_clock.set (pos, 0, true);
3220 if (Config->get_secondary_clock_delta_edit_cursor()) {
3221 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3222 } else {
3223 secondary_clock.set (pos);
3226 if (big_clock_window) {
3227 big_clock.set (pos);
3231 void
3232 ARDOUR_UI::record_state_changed ()
3234 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3236 if (!session || !big_clock_window) {
3237 /* why bother - the clock isn't visible */
3238 return;
3241 Session::RecordState const r = session->record_status ();
3242 bool const h = session->have_rec_enabled_diskstream ();
3244 if (r == Session::Recording && h) {
3245 big_clock.set_widget_name ("BigClockRecording");
3246 } else {
3247 big_clock.set_widget_name ("BigClockNonRecording");
3251 bool
3252 ARDOUR_UI::first_idle ()
3254 if (session) {
3255 session->allow_auto_play (true);
3258 if (editor) {
3259 editor->first_idle();
3262 Keyboard::set_can_save_keybindings (true);
3263 return false;
3266 void
3267 ARDOUR_UI::store_clock_modes ()
3269 XMLNode* node = new XMLNode(X_("ClockModes"));
3271 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3272 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3275 session->add_extra_xml (*node);
3276 session->set_dirty ();
3281 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3282 : Controllable (name), ui (u), type(tp)
3287 void
3288 ARDOUR_UI::TransportControllable::set_value (float val)
3290 if (type == ShuttleControl) {
3291 double fract;
3293 if (val == 0.5f) {
3294 fract = 0.0;
3295 } else {
3296 if (val < 0.5f) {
3297 fract = -((0.5f - val)/0.5f);
3298 } else {
3299 fract = ((val - 0.5f)/0.5f);
3303 ui.set_shuttle_fract (fract);
3304 return;
3307 if (val < 0.5f) {
3308 /* do nothing: these are radio-style actions */
3309 return;
3312 const char *action = 0;
3314 switch (type) {
3315 case Roll:
3316 action = X_("Roll");
3317 break;
3318 case Stop:
3319 action = X_("Stop");
3320 break;
3321 case GotoStart:
3322 action = X_("Goto Start");
3323 break;
3324 case GotoEnd:
3325 action = X_("Goto End");
3326 break;
3327 case AutoLoop:
3328 action = X_("Loop");
3329 break;
3330 case PlaySelection:
3331 action = X_("Play Selection");
3332 break;
3333 case RecordEnable:
3334 action = X_("Record");
3335 break;
3336 default:
3337 break;
3340 if (action == 0) {
3341 return;
3344 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3346 if (act) {
3347 act->activate ();
3351 float
3352 ARDOUR_UI::TransportControllable::get_value (void) const
3354 float val = 0.0f;
3356 switch (type) {
3357 case Roll:
3358 break;
3359 case Stop:
3360 break;
3361 case GotoStart:
3362 break;
3363 case GotoEnd:
3364 break;
3365 case AutoLoop:
3366 break;
3367 case PlaySelection:
3368 break;
3369 case RecordEnable:
3370 break;
3371 case ShuttleControl:
3372 break;
3373 default:
3374 break;
3377 return val;
3380 void
3381 ARDOUR_UI::TransportControllable::set_id (const string& str)
3383 _id = str;
3386 void
3387 ARDOUR_UI::setup_profile ()
3389 if (gdk_screen_width() < 1200) {
3390 Profile->set_small_screen ();
3394 if (getenv ("ARDOUR_SAE")) {
3395 Profile->set_sae ();
3396 Profile->set_single_package ();