colinf's patch to make the cursor be the dbl vertical arrow when over the track resiz...
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blobb8520b2f8e6d311cab01ceb078710dbb607d9c91
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>
28 #include <stdlib.h>
29 #include <cstring>
31 #include <iostream>
33 #include <sys/resource.h>
35 #include <gtkmm/messagedialog.h>
36 #include <gtkmm/accelmap.h>
38 #include <pbd/error.h>
39 #include <pbd/basename.h>
40 #include <pbd/compose.h>
41 #include <pbd/pathscanner.h>
42 #include <pbd/failed_constructor.h>
43 #include <pbd/enumwriter.h>
44 #include <pbd/stacktrace.h>
45 #include <gtkmm2ext/gtk_ui.h>
46 #include <gtkmm2ext/utils.h>
47 #include <gtkmm2ext/click_box.h>
48 #include <gtkmm2ext/fastmeter.h>
49 #include <gtkmm2ext/stop_signal.h>
50 #include <gtkmm2ext/popup.h>
51 #include <gtkmm2ext/window_title.h>
53 #include <midi++/port.h>
54 #include <midi++/mmc.h>
56 #include <ardour/ardour.h>
57 #include <ardour/profile.h>
58 #include <ardour/session_route.h>
59 #include <ardour/port.h>
60 #include <ardour/audioengine.h>
61 #include <ardour/playlist.h>
62 #include <ardour/utils.h>
63 #include <ardour/plugin.h>
64 #include <ardour/audio_diskstream.h>
65 #include <ardour/audiofilesource.h>
66 #include <ardour/recent_sessions.h>
67 #include <ardour/port.h>
68 #include <ardour/audio_track.h>
70 typedef uint64_t microseconds_t;
72 #include "actions.h"
73 #include "ardour_ui.h"
74 #include "public_editor.h"
75 #include "audio_clock.h"
76 #include "keyboard.h"
77 #include "mixer_ui.h"
78 #include "prompter.h"
79 #include "opts.h"
80 #include "add_route_dialog.h"
81 #include "new_session_dialog.h"
82 #include "about.h"
83 #include "splash.h"
84 #include "nag.h"
85 #include "utils.h"
86 #include "gui_thread.h"
87 #include "theme_manager.h"
88 #include "engine_dialog.h"
89 #include "gain_meter.h"
90 #include "route_time_axis.h"
92 #include "i18n.h"
94 using namespace ARDOUR;
95 using namespace PBD;
96 using namespace Gtkmm2ext;
97 using namespace Gtk;
98 using namespace sigc;
100 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
101 UIConfiguration *ARDOUR_UI::ui_config = 0;
103 sigc::signal<void,bool> ARDOUR_UI::Blink;
104 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
105 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
106 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
108 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
110 : Gtkmm2ext::UI (X_("Ardour"), argcp, argvp),
112 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true),
113 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true),
114 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
115 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
117 /* preroll stuff */
119 preroll_button (_("pre\nroll")),
120 postroll_button (_("post\nroll")),
122 /* big clock */
124 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, false, true),
126 /* transport */
128 roll_controllable ("transport roll", *this, TransportControllable::Roll),
129 stop_controllable ("transport stop", *this, TransportControllable::Stop),
130 goto_start_controllable ("transport goto start", *this, TransportControllable::GotoStart),
131 goto_end_controllable ("transport goto end", *this, TransportControllable::GotoEnd),
132 auto_loop_controllable ("transport auto loop", *this, TransportControllable::AutoLoop),
133 play_selection_controllable ("transport play selection", *this, TransportControllable::PlaySelection),
134 rec_controllable ("transport rec-enable", *this, TransportControllable::RecordEnable),
135 shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl),
136 shuttle_controller_binding_proxy (shuttle_controllable),
138 roll_button (&roll_controllable),
139 stop_button (&stop_controllable),
140 goto_start_button (&goto_start_controllable),
141 goto_end_button (&goto_end_controllable),
142 auto_loop_button (&auto_loop_controllable),
143 play_selection_button (&play_selection_controllable),
144 rec_button (&rec_controllable),
146 shuttle_units_button (_("% ")),
148 punch_in_button (_("Punch In")),
149 punch_out_button (_("Punch Out")),
150 auto_return_button (_("Auto Return")),
151 auto_play_button (_("Auto Play")),
152 auto_input_button (_("Auto Input")),
153 click_button (_("Click")),
154 time_master_button (_("time\nmaster")),
156 auditioning_alert_button (_("AUDITION")),
157 solo_alert_button (_("SOLO")),
158 shown_flag (false),
159 error_log_button (_("Errors"))
161 using namespace Gtk::Menu_Helpers;
163 Gtkmm2ext::init();
165 #ifdef TOP_MENUBAR
166 _auto_display_errors = false;
167 #endif
169 about = 0;
170 splash = 0;
172 if (ARDOUR_COMMAND_LINE::session_name.length()) {
173 /* only show this if we're not going to post the new session dialog */
174 show_splash ();
177 if (theArdourUI == 0) {
178 theArdourUI = this;
181 ui_config = new UIConfiguration();
182 theme_manager = new ThemeManager();
184 engine = 0;
185 editor = 0;
186 mixer = 0;
187 session = 0;
188 _session_is_new = false;
189 big_clock_window = 0;
190 session_selector_window = 0;
191 new_session_dialog = 0;
192 last_key_press_time = 0;
193 connection_editor = 0;
194 add_route_dialog = 0;
195 route_params = 0;
196 option_editor = 0;
197 location_ui = 0;
198 key_editor = 0;
199 open_session_selector = 0;
200 have_configure_timeout = false;
201 have_disk_speed_dialog_displayed = false;
202 _will_create_new_session_automatically = false;
203 session_loaded = false;
204 last_speed_displayed = -1.0f;
205 ignore_dual_punch = false;
206 _mixer_on_top = false;
208 roll_button.unset_flags (Gtk::CAN_FOCUS);
209 stop_button.unset_flags (Gtk::CAN_FOCUS);
210 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
211 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
212 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
213 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
214 rec_button.unset_flags (Gtk::CAN_FOCUS);
216 last_configure_time= 0;
218 shuttle_grabbed = false;
219 shuttle_fract = 0.0;
220 shuttle_max_speed = 8.0f;
222 shuttle_style_menu = 0;
223 shuttle_unit_menu = 0;
225 // We do not have jack linked in yet so;
227 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
229 ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
230 ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
232 ARDOUR::Plugin::PresetFileExists.connect (mem_fun(*this, &ARDOUR_UI::preset_file_exists_handler));
234 /* handle dialog requests */
236 ARDOUR::Session::Dialog.connect (mem_fun(*this, &ARDOUR_UI::session_dialog));
238 /* handle pending state with a dialog */
240 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
242 /* handle sr mismatch with a dialog */
244 ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
246 /* lets get this party started */
248 try {
249 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
250 throw failed_constructor ();
253 setup_gtk_ardour_enums ();
254 Config->set_current_owner (ConfigVariableBase::Interface);
255 setup_profile ();
257 GainMeter::setup_slider_pix ();
258 RouteTimeAxisView::setup_slider_pix ();
260 } catch (failed_constructor& err) {
261 error << _("could not initialize Ardour.") << endmsg;
262 // pass it on up
263 throw;
266 /* we like keyboards */
268 keyboard = new Keyboard;
270 reset_dpi();
272 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
273 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
275 platform_setup ();
279 ARDOUR_UI::create_engine ()
281 // this gets called every time by new_session()
283 if (engine) {
284 return 0;
287 loading_message (_("Starting audio engine"));
289 try {
290 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
292 } catch (...) {
294 return -1;
297 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
298 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
299 engine->Halted.connect (bind (mem_fun(*this, &ARDOUR_UI::engine_halted), false));
300 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
302 post_engine ();
304 return 0;
307 void
308 ARDOUR_UI::post_engine ()
310 /* Things to be done once we create the AudioEngine
313 check_memory_locking();
315 ActionManager::init ();
316 _tooltips.enable();
318 if (setup_windows ()) {
319 throw failed_constructor ();
322 /* this is the first point at which all the keybindings are available */
324 if (ARDOUR_COMMAND_LINE::show_key_actions) {
325 vector<string> names;
326 vector<string> paths;
327 vector<string> keys;
328 vector<AccelKey> bindings;
330 ActionManager::get_all_actions (names, paths, keys, bindings);
332 vector<string>::iterator n;
333 vector<string>::iterator k;
334 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
335 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
338 exit (0);
341 blink_timeout_tag = -1;
343 /* the global configuration object is now valid */
345 use_config ();
347 /* this being a GUI and all, we want peakfiles */
349 AudioFileSource::set_build_peakfiles (true);
350 AudioFileSource::set_build_missing_peakfiles (true);
352 /* set default clock modes */
354 if (Profile->get_sae()) {
355 primary_clock.set_mode (AudioClock::BBT);
356 secondary_clock.set_mode (AudioClock::MinSec);
357 } else {
358 primary_clock.set_mode (AudioClock::SMPTE);
359 secondary_clock.set_mode (AudioClock::BBT);
362 /* start the time-of-day-clock */
364 #ifndef GTKOSX
365 /* OS X provides an always visible wallclock, so don't be stupid */
366 update_wall_clock ();
367 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
368 #endif
370 update_disk_space ();
371 update_cpu_load ();
372 update_sample_rate (engine->frame_rate());
374 platform_specific ();
376 /* now start and maybe save state */
378 if (do_engine_start () == 0) {
379 if (session && _session_is_new) {
380 /* we need to retain initial visual
381 settings for a new session
383 session->save_state ("");
388 ARDOUR_UI::~ARDOUR_UI ()
390 save_ardour_state ();
392 if (keyboard) {
393 delete keyboard;
396 if (editor) {
397 delete editor;
400 if (mixer) {
401 delete mixer;
404 if (add_route_dialog) {
405 delete add_route_dialog;
408 if (new_session_dialog) {
409 delete new_session_dialog;
413 void
414 ARDOUR_UI::pop_back_splash ()
416 if (Splash::instance()) {
417 // Splash::instance()->pop_back();
418 Splash::instance()->hide ();
422 gint
423 ARDOUR_UI::configure_timeout ()
425 if (last_configure_time == 0) {
426 /* no configure events yet */
427 return TRUE;
430 /* force a gap of 0.5 seconds since the last configure event
433 if (get_microseconds() - last_configure_time < 500000) {
434 return TRUE;
435 } else {
436 have_configure_timeout = false;
437 save_ardour_state ();
438 return FALSE;
442 gboolean
443 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
445 if (have_configure_timeout) {
446 last_configure_time = get_microseconds();
447 } else {
448 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
449 have_configure_timeout = true;
452 return FALSE;
455 void
456 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
458 const XMLProperty* prop;
460 if ((prop = node.property ("roll")) != 0) {
461 roll_controllable.set_id (prop->value());
463 if ((prop = node.property ("stop")) != 0) {
464 stop_controllable.set_id (prop->value());
466 if ((prop = node.property ("goto_start")) != 0) {
467 goto_start_controllable.set_id (prop->value());
469 if ((prop = node.property ("goto_end")) != 0) {
470 goto_end_controllable.set_id (prop->value());
472 if ((prop = node.property ("auto_loop")) != 0) {
473 auto_loop_controllable.set_id (prop->value());
475 if ((prop = node.property ("play_selection")) != 0) {
476 play_selection_controllable.set_id (prop->value());
478 if ((prop = node.property ("rec")) != 0) {
479 rec_controllable.set_id (prop->value());
481 if ((prop = node.property ("shuttle")) != 0) {
482 shuttle_controllable.set_id (prop->value());
486 XMLNode&
487 ARDOUR_UI::get_transport_controllable_state ()
489 XMLNode* node = new XMLNode(X_("TransportControllables"));
490 char buf[64];
492 roll_controllable.id().print (buf, sizeof (buf));
493 node->add_property (X_("roll"), buf);
494 stop_controllable.id().print (buf, sizeof (buf));
495 node->add_property (X_("stop"), buf);
496 goto_start_controllable.id().print (buf, sizeof (buf));
497 node->add_property (X_("goto_start"), buf);
498 goto_end_controllable.id().print (buf, sizeof (buf));
499 node->add_property (X_("goto_end"), buf);
500 auto_loop_controllable.id().print (buf, sizeof (buf));
501 node->add_property (X_("auto_loop"), buf);
502 play_selection_controllable.id().print (buf, sizeof (buf));
503 node->add_property (X_("play_selection"), buf);
504 rec_controllable.id().print (buf, sizeof (buf));
505 node->add_property (X_("rec"), buf);
506 shuttle_controllable.id().print (buf, sizeof (buf));
507 node->add_property (X_("shuttle"), buf);
509 return *node;
512 void
513 ARDOUR_UI::save_ardour_state ()
515 if (!keyboard || !mixer || !editor) {
516 return;
519 /* XXX this is all a bit dubious. add_extra_xml() uses
520 a different lifetime model from add_instant_xml().
523 XMLNode* node = new XMLNode (keyboard->get_state());
524 Config->add_extra_xml (*node);
525 Config->add_extra_xml (get_transport_controllable_state());
526 if (new_session_dialog) {
527 if (new_session_dialog->engine_control.was_used()) {
528 Config->add_extra_xml (new_session_dialog->engine_control.get_state());
531 Config->save_state();
532 ui_config->save_state ();
534 XMLNode enode(static_cast<Stateful*>(editor)->get_state());
535 XMLNode mnode(mixer->get_state());
537 if (session) {
538 session->add_instant_xml (enode, session->path());
539 session->add_instant_xml (mnode, session->path());
540 } else {
541 Config->add_instant_xml (enode, get_user_ardour_path());
542 Config->add_instant_xml (mnode, get_user_ardour_path());
545 Keyboard::save_keybindings ();
548 gint
549 ARDOUR_UI::autosave_session ()
551 if (g_main_depth() > 1) {
552 /* inside a recursive main loop,
553 give up because we may not be able to
554 take a lock.
556 return 1;
559 if (!Config->get_periodic_safety_backups())
560 return 1;
562 if (session) {
563 session->maybe_write_autosave();
566 return 1;
569 void
570 ARDOUR_UI::update_autosave ()
572 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
574 if (session && session->dirty()) {
575 if (_autosave_connection.connected()) {
576 _autosave_connection.disconnect();
579 _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
580 Config->get_periodic_safety_backup_interval() * 1000);
582 } else {
583 if (_autosave_connection.connected()) {
584 _autosave_connection.disconnect();
589 void
590 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
592 string title;
593 if (we_set_params) {
594 title = _("Ardour could not start JACK");
595 } else {
596 title = _("Ardour could not connect to JACK.");
599 MessageDialog win (title,
600 false,
601 Gtk::MESSAGE_INFO,
602 Gtk::BUTTONS_NONE);
604 if (we_set_params) {
605 win.set_secondary_text(_("There are several possible reasons:\n\
607 1) You requested audio parameters that are not supported..\n\
608 2) JACK is running as another user.\n\
610 Please consider the possibilities, and perhaps try different parameters."));
611 } else {
612 win.set_secondary_text(_("There are several possible reasons:\n\
614 1) JACK is not running.\n\
615 2) JACK is running as another user, perhaps root.\n\
616 3) There is already another client called \"ardour\".\n\
618 Please consider the possibilities, and perhaps (re)start JACK."));
621 if (toplevel) {
622 win.set_transient_for (*toplevel);
625 if (we_set_params) {
626 win.add_button (Stock::OK, RESPONSE_CLOSE);
627 } else {
628 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
631 win.set_default_response (RESPONSE_CLOSE);
633 win.show_all ();
634 win.set_position (Gtk::WIN_POS_CENTER);
635 pop_back_splash ();
637 /* we just don't care about the result, but we want to block */
639 win.run ();
642 void
643 ARDOUR_UI::startup ()
645 string name, path;
647 new_session_dialog = new NewSessionDialog();
649 bool backend_audio_is_running = EngineControl::engine_running();
650 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
652 if (audio_setup) {
653 new_session_dialog->engine_control.set_state (*audio_setup);
656 if (!get_session_parameters (backend_audio_is_running, ARDOUR_COMMAND_LINE::new_session)) {
657 return;
660 BootMessage (_("Ardour is ready for use"));
661 show ();
664 void
665 ARDOUR_UI::no_memory_warning ()
667 XMLNode node (X_("no-memory-warning"));
668 Config->add_instant_xml (node, get_user_ardour_path());
671 void
672 ARDOUR_UI::check_memory_locking ()
674 #ifdef __APPLE__
675 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
676 return;
677 #else // !__APPLE__
679 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path());
681 if (engine->is_realtime() && memory_warning_node == 0) {
683 struct rlimit limits;
684 int64_t ram;
685 long pages, page_size;
687 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
688 ram = 0;
689 } else {
690 ram = (int64_t) pages * (int64_t) page_size;
693 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
694 return;
697 if (limits.rlim_cur != RLIM_INFINITY) {
699 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
702 MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. "
703 "This might cause Ardour to run out of memory before your system "
704 "runs out of memory. \n\n"
705 "You can view the memory limit with 'ulimit -l', "
706 "and it is normally controlled by /etc/security/limits.conf"));
708 VBox* vbox = msg.get_vbox();
709 HBox hbox;
710 CheckButton cb (_("Do not show this window again"));
712 cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning));
714 hbox.pack_start (cb, true, false);
715 vbox->pack_start (hbox);
716 hbox.show_all ();
718 pop_back_splash ();
720 msg.run ();
724 #endif // !__APPLE__
727 void
728 ARDOUR_UI::queue_finish ()
730 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
733 bool
734 ARDOUR_UI::idle_finish ()
736 finish ();
737 return false; /* do not call again */
740 void
741 ARDOUR_UI::finish()
743 if (session) {
745 int tries = 0;
747 while (session->transport_rolling() && (++tries < 8)) {
748 /* stop but do not abort capture */
749 session->request_stop (false, true);
750 usleep (10000);
753 if (session->dirty()) {
754 switch (ask_about_saving_session(_("quit"))) {
755 case -1:
756 return;
757 break;
758 case 1:
759 /* use the default name */
760 if (save_state_canfail ("")) {
761 /* failed - don't quit */
762 MessageDialog msg (*editor,
763 _("\
764 Ardour was unable to save your session.\n\n\
765 If you still wish to quit, please use the\n\n\
766 \"Just quit\" option."));
767 pop_back_splash();
768 msg.run ();
769 return;
771 break;
772 case 0:
773 break;
777 session->set_clean();
778 session->set_deletion_in_progress ();
779 unload_session(true);
782 ArdourDialog::close_all_dialogs ();
783 engine->stop (true);
784 save_ardour_state ();
785 quit ();
789 ARDOUR_UI::ask_about_saving_session (const string & what)
791 ArdourDialog window (_("ardour: save session?"));
792 Gtk::HBox dhbox; // the hbox for the image and text
793 Gtk::Label prompt_label;
794 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
796 string msg;
798 msg = string_compose(_("Don't %1"), what);
799 window.add_button (msg, RESPONSE_REJECT);
800 msg = string_compose(_("Just %1"), what);
801 window.add_button (msg, RESPONSE_APPLY);
802 msg = string_compose(_("Save and %1"), what);
803 window.add_button (msg, RESPONSE_ACCEPT);
805 window.set_default_response (RESPONSE_ACCEPT);
807 Gtk::Button noquit_button (msg);
808 noquit_button.set_name ("EditorGTKButton");
810 string prompt;
811 string type;
813 if (session->snap_name() == session->name()) {
814 type = _("session");
815 } else {
816 type = _("snapshot");
818 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?"),
819 type, session->snap_name());
821 prompt_label.set_text (prompt);
822 prompt_label.set_name (X_("PrompterLabel"));
823 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
825 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
827 dhbox.set_homogeneous (false);
828 dhbox.pack_start (*dimage, false, false, 5);
829 dhbox.pack_start (prompt_label, true, false, 5);
830 window.get_vbox()->pack_start (dhbox);
832 window.set_name (_("Prompter"));
833 window.set_position (Gtk::WIN_POS_MOUSE);
834 window.set_modal (true);
835 window.set_resizable (false);
836 window.show_all ();
838 window.set_keep_above (true);
839 window.present ();
841 ResponseType r = (ResponseType) window.run();
843 window.hide ();
845 switch (r) {
846 case RESPONSE_ACCEPT: // save and get out of here
847 return 1;
848 case RESPONSE_APPLY: // get out of here
849 return 0;
850 default:
851 break;
854 return -1;
858 ARDOUR_UI::every_second ()
860 update_cpu_load ();
861 update_buffer_load ();
862 update_disk_space ();
863 return TRUE;
866 gint
867 ARDOUR_UI::every_point_one_seconds ()
869 update_speed_display ();
870 RapidScreenUpdate(); /* EMIT_SIGNAL */
871 return TRUE;
874 gint
875 ARDOUR_UI::every_point_zero_one_seconds ()
877 // august 2007: actual update frequency: 40Hz, not 100Hz
879 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
880 return TRUE;
883 void
884 ARDOUR_UI::update_sample_rate (nframes_t ignored)
886 char buf[32];
888 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
890 if (!engine->connected()) {
892 snprintf (buf, sizeof (buf), _("disconnected"));
894 } else {
896 nframes_t rate = engine->frame_rate();
898 if (fmod (rate, 1000.0) != 0.0) {
899 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
900 (float) rate/1000.0f,
901 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
902 } else {
903 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
904 rate/1000,
905 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
909 sample_rate_label.set_text (buf);
912 void
913 ARDOUR_UI::update_cpu_load ()
915 char buf[32];
916 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
917 cpu_load_label.set_text (buf);
920 void
921 ARDOUR_UI::update_buffer_load ()
923 char buf[64];
924 uint32_t c, p;
926 if (session) {
927 c = session->capture_load ();
928 p = session->playback_load ();
930 push_buffer_stats (c, p);
932 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
933 session->playback_load(), session->capture_load());
934 buffer_load_label.set_text (buf);
935 } else {
936 buffer_load_label.set_text ("");
940 void
941 ARDOUR_UI::count_recenabled_streams (Route& route)
943 Track* track = dynamic_cast<Track*>(&route);
944 if (track && track->diskstream()->record_enabled()) {
945 rec_enabled_streams += track->n_inputs();
949 void
950 ARDOUR_UI::update_disk_space()
952 if (session == 0) {
953 return;
956 nframes_t frames = session->available_capture_duration();
957 char buf[64];
959 if (frames == max_frames) {
960 strcpy (buf, _("Disk: 24hrs+"));
961 } else {
962 int hrs;
963 int mins;
964 int secs;
965 nframes_t fr = session->frame_rate();
967 rec_enabled_streams = 0;
968 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
970 if (rec_enabled_streams) {
971 frames /= rec_enabled_streams;
974 hrs = frames / (fr * 3600);
975 frames -= hrs * fr * 3600;
976 mins = frames / (fr * 60);
977 frames -= mins * fr * 60;
978 secs = frames / fr;
980 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
983 disk_space_label.set_text (buf);
986 gint
987 ARDOUR_UI::update_wall_clock ()
989 time_t now;
990 struct tm *tm_now;
991 char buf[16];
993 time (&now);
994 tm_now = localtime (&now);
996 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
997 wall_clock_label.set_text (buf);
999 return TRUE;
1002 gint
1003 ARDOUR_UI::session_menu (GdkEventButton *ev)
1005 session_popup_menu->popup (0, 0);
1006 return TRUE;
1009 void
1010 ARDOUR_UI::redisplay_recent_sessions ()
1012 vector<string *> *sessions;
1013 vector<string *>::iterator i;
1014 RecentSessionsSorter cmp;
1016 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1017 recent_session_model->clear ();
1019 RecentSessions rs;
1020 ARDOUR::read_recent_sessions (rs);
1022 if (rs.empty()) {
1023 recent_session_display.set_model (recent_session_model);
1024 return;
1027 /* sort them alphabetically */
1028 sort (rs.begin(), rs.end(), cmp);
1029 sessions = new vector<string*>;
1031 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1032 sessions->push_back (new string ((*i).second));
1035 for (i = sessions->begin(); i != sessions->end(); ++i) {
1037 vector<string*>* states;
1038 vector<const gchar*> item;
1039 string fullpath = *(*i);
1041 /* remove any trailing / */
1043 if (fullpath[fullpath.length()-1] == '/') {
1044 fullpath = fullpath.substr (0, fullpath.length()-1);
1047 /* check whether session still exists */
1048 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1049 /* session doesn't exist */
1050 cerr << "skipping non-existent session " << fullpath << endl;
1051 continue;
1054 /* now get available states for this session */
1056 if ((states = Session::possible_states (fullpath)) == 0) {
1057 /* no state file? */
1058 continue;
1061 TreeModel::Row row = *(recent_session_model->append());
1063 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1064 row[recent_session_columns.fullpath] = fullpath;
1066 if (states->size() > 1) {
1068 /* add the children */
1070 for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
1072 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1074 child_row[recent_session_columns.visible_name] = **i2;
1075 child_row[recent_session_columns.fullpath] = fullpath;
1077 delete *i2;
1081 delete states;
1084 recent_session_display.set_model (recent_session_model);
1085 delete sessions;
1088 void
1089 ARDOUR_UI::build_session_selector ()
1091 session_selector_window = new ArdourDialog ("session selector");
1093 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1095 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1096 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1097 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1098 recent_session_model = TreeStore::create (recent_session_columns);
1099 recent_session_display.set_model (recent_session_model);
1100 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1101 recent_session_display.set_headers_visible (false);
1102 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1103 recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1105 scroller->add (recent_session_display);
1106 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1108 session_selector_window->set_name ("SessionSelectorWindow");
1109 session_selector_window->set_size_request (200, 400);
1110 session_selector_window->get_vbox()->pack_start (*scroller);
1111 session_selector_window->show_all_children();
1114 void
1115 ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
1117 session_selector_window->response (RESPONSE_ACCEPT);
1120 void
1121 ARDOUR_UI::open_recent_session ()
1123 bool can_return = (session != 0);
1125 if (session_selector_window == 0) {
1126 build_session_selector ();
1129 redisplay_recent_sessions ();
1131 while (true) {
1133 session_selector_window->set_position (WIN_POS_MOUSE);
1135 ResponseType r = (ResponseType) session_selector_window->run ();
1137 switch (r) {
1138 case RESPONSE_ACCEPT:
1139 break;
1140 default:
1141 if (can_return) {
1142 session_selector_window->hide();
1143 return;
1144 } else {
1145 exit (1);
1149 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1150 continue;
1153 session_selector_window->hide();
1155 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1157 if (i == recent_session_model->children().end()) {
1158 return;
1161 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1162 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1164 _session_is_new = false;
1166 if (load_session (path, state) == 0) {
1167 break;
1170 can_return = false;
1174 bool
1175 ARDOUR_UI::check_audioengine ()
1177 if (engine) {
1178 if (!engine->connected()) {
1179 MessageDialog msg (_("Ardour is not connected to JACK\n"
1180 "You cannot open or close sessions in this condition"));
1181 pop_back_splash ();
1182 msg.set_position (WIN_POS_CENTER);
1183 msg.run ();
1184 return false;
1186 return true;
1187 } else {
1188 return false;
1192 void
1193 ARDOUR_UI::open_session ()
1195 if (!check_audioengine()) {
1196 return;
1199 /* popup selector window */
1201 if (open_session_selector == 0) {
1203 /* ardour sessions are folders */
1205 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1206 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1207 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1208 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1210 FileFilter session_filter;
1211 session_filter.add_pattern ("*.ardour");
1212 session_filter.set_name (_("Ardour sessions"));
1213 open_session_selector->add_filter (session_filter);
1214 open_session_selector->set_filter (session_filter);
1217 int response = open_session_selector->run();
1218 open_session_selector->hide ();
1220 switch (response) {
1221 case RESPONSE_ACCEPT:
1222 break;
1223 default:
1224 open_session_selector->hide();
1225 return;
1228 open_session_selector->hide();
1229 string session_path = open_session_selector->get_filename();
1230 string path, name;
1231 bool isnew;
1233 if (session_path.length() > 0) {
1234 if (Session::find_session (session_path, path, name, isnew) == 0) {
1235 _session_is_new = isnew;
1236 load_session (path, name);
1242 void
1243 ARDOUR_UI::session_add_midi_track ()
1245 cerr << _("Patience is a virtue.\n");
1248 void
1249 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
1251 list<boost::shared_ptr<AudioTrack> > tracks;
1252 Session::RouteList routes;
1254 if (session == 0) {
1255 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1256 return;
1259 try {
1260 if (track) {
1261 tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
1263 if (tracks.size() != how_many) {
1264 if (how_many == 1) {
1265 error << _("could not create a new audio track") << endmsg;
1266 } else {
1267 error << string_compose (_("could only create %1 of %2 new audio %3"),
1268 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1272 } else {
1274 routes = session->new_audio_route (input_channels, output_channels, how_many);
1276 if (routes.size() != how_many) {
1277 if (how_many == 1) {
1278 error << _("could not create a new audio track") << endmsg;
1279 } else {
1280 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1285 #if CONTROLOUTS
1286 if (need_control_room_outs) {
1287 pan_t pans[2];
1289 pans[0] = 0.5;
1290 pans[1] = 0.5;
1292 route->set_stereo_control_outs (control_lr_channels);
1293 route->control_outs()->set_stereo_pan (pans, this);
1295 #endif /* CONTROLOUTS */
1298 catch (...) {
1299 MessageDialog msg (*editor,
1300 _("There are insufficient JACK ports available\n\
1301 to create a new track or bus.\n\
1302 You should save Ardour, exit and\n\
1303 restart JACK with more ports."));
1304 pop_back_splash ();
1305 msg.run ();
1309 void
1310 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1312 nframes_t _preroll = 0;
1314 if (session) {
1315 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1316 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1318 if (new_position > _preroll) {
1319 new_position -= _preroll;
1320 } else {
1321 new_position = 0;
1324 session->request_locate (new_position);
1328 void
1329 ARDOUR_UI::transport_goto_start ()
1331 if (session) {
1332 session->goto_start();
1335 /* force displayed area in editor to start no matter
1336 what "follow playhead" setting is.
1339 if (editor) {
1340 editor->reset_x_origin (session->current_start_frame());
1345 void
1346 ARDOUR_UI::transport_goto_zero ()
1348 if (session) {
1349 session->request_locate (0);
1352 /* force displayed area in editor to start no matter
1353 what "follow playhead" setting is.
1356 if (editor) {
1357 editor->reset_x_origin (0);
1362 void
1363 ARDOUR_UI::transport_goto_wallclock ()
1365 if (session && editor) {
1367 time_t now;
1368 struct tm tmnow;
1369 nframes64_t frames;
1371 time (&now);
1372 localtime_r (&now, &tmnow);
1374 frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
1375 frames += tmnow.tm_min * (60 * session->frame_rate());
1376 frames += tmnow.tm_sec * session->frame_rate();
1378 session->request_locate (frames);
1380 /* force displayed area in editor to start no matter
1381 what "follow playhead" setting is.
1384 if (editor) {
1385 editor->reset_x_origin (frames - (editor->current_page_frames()/2));
1390 void
1391 ARDOUR_UI::transport_goto_end ()
1393 if (session) {
1394 nframes_t frame = session->current_end_frame();
1395 session->request_locate (frame);
1397 /* force displayed area in editor to start no matter
1398 what "follow playhead" setting is.
1401 if (editor) {
1402 editor->reset_x_origin (frame);
1407 void
1408 ARDOUR_UI::transport_stop ()
1410 if (!session) {
1411 return;
1414 if (session->is_auditioning()) {
1415 session->cancel_audition ();
1416 return;
1419 session->request_stop (false, true);
1422 void
1423 ARDOUR_UI::transport_stop_and_forget_capture ()
1425 if (session) {
1426 session->request_stop (true, true);
1430 void
1431 ARDOUR_UI::remove_last_capture()
1433 if (editor) {
1434 editor->remove_last_capture();
1438 void
1439 ARDOUR_UI::transport_record (bool roll)
1442 if (session) {
1443 switch (session->record_status()) {
1444 case Session::Disabled:
1445 if (session->ntracks() == 0) {
1446 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1447 msg.run ();
1448 return;
1450 session->maybe_enable_record ();
1451 if (roll) {
1452 transport_roll ();
1454 break;
1455 case Session::Recording:
1456 if (roll) {
1457 session->request_stop();
1458 } else {
1459 session->disable_record (false, true);
1461 break;
1463 case Session::Enabled:
1464 session->disable_record (false, true);
1467 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1470 void
1471 ARDOUR_UI::transport_roll ()
1473 if (!session) {
1474 return;
1477 if (session->is_auditioning()) {
1478 return;
1481 switch (Config->get_slave_source()) {
1482 case None:
1483 case JACK:
1484 break;
1485 default:
1486 /* transport controlled by the master */
1487 return;
1490 bool rolling = session->transport_rolling();
1492 if (session->get_play_loop()) {
1493 /* XXX it is not possible to just leave seamless loop and keep
1494 playing at present (nov 4th 2009)
1496 if (!Config->get_seamless_loop()) {
1497 /* off, and stop */
1498 session->request_play_loop (false, true);
1499 } else {
1500 return;
1502 } else if (session->get_play_range ()) {
1503 session->request_play_range (0, true);
1506 if (!rolling) {
1507 session->request_transport_speed (1.0f);
1510 map_transport_state ();
1513 void
1514 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1517 if (!session) {
1518 return;
1521 if (session->is_auditioning()) {
1522 session->cancel_audition ();
1523 return;
1526 switch (Config->get_slave_source()) {
1527 case None:
1528 case JACK:
1529 break;
1530 default:
1531 /* transport controlled by the master */
1532 return;
1535 bool rolling = session->transport_rolling();
1536 bool affect_transport = true;
1538 if (rolling && roll_out_of_bounded_mode) {
1539 /* drop out of loop/range playback but leave transport rolling */
1540 if (session->get_play_loop()) {
1541 if (Config->get_seamless_loop()) {
1542 /* the disk buffers contain copies of the loop - we can't
1543 just keep playing, so stop the transport. the user
1544 can restart as they wish.
1546 affect_transport = true;
1547 } else {
1548 /* disk buffers are normal, so we can keep playing */
1549 affect_transport = false;
1551 session->request_play_loop (false, true);
1552 } else if (session->get_play_range ()) {
1553 affect_transport = false;
1554 session->request_play_range (0, true);
1558 if (affect_transport) {
1559 if (rolling) {
1560 session->request_stop (with_abort, true);
1561 } else {
1562 session->request_transport_speed (1.0f);
1566 map_transport_state ();
1569 void
1570 ARDOUR_UI::toggle_session_auto_loop ()
1572 if (session) {
1573 if (session->get_play_loop()) {
1574 if (session->transport_rolling()) {
1575 Location * looploc = session->locations()->auto_loop_location();
1576 if (looploc) {
1577 session->request_locate (looploc->start(), true);
1579 } else {
1580 session->request_play_loop (false);
1582 } else {
1583 Location * looploc = session->locations()->auto_loop_location();
1584 if (looploc) {
1585 session->request_play_loop (true);
1591 void
1592 ARDOUR_UI::transport_play_selection ()
1594 if (!session) {
1595 return;
1598 editor->play_selection ();
1601 void
1602 ARDOUR_UI::transport_rewind (int option)
1604 float current_transport_speed;
1606 if (session) {
1607 current_transport_speed = session->transport_speed();
1609 if (current_transport_speed >= 0.0f) {
1610 switch (option) {
1611 case 0:
1612 session->request_transport_speed (-1.0f);
1613 break;
1614 case 1:
1615 session->request_transport_speed (-4.0f);
1616 break;
1617 case -1:
1618 session->request_transport_speed (-0.5f);
1619 break;
1621 } else {
1622 /* speed up */
1623 session->request_transport_speed (current_transport_speed * 1.5f);
1628 void
1629 ARDOUR_UI::transport_forward (int option)
1631 float current_transport_speed;
1633 if (session) {
1634 current_transport_speed = session->transport_speed();
1636 if (current_transport_speed <= 0.0f) {
1637 switch (option) {
1638 case 0:
1639 session->request_transport_speed (1.0f);
1640 break;
1641 case 1:
1642 session->request_transport_speed (4.0f);
1643 break;
1644 case -1:
1645 session->request_transport_speed (0.5f);
1646 break;
1648 } else {
1649 /* speed up */
1650 session->request_transport_speed (current_transport_speed * 1.5f);
1655 void
1656 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1658 if (session == 0) {
1659 return;
1662 boost::shared_ptr<Route> r;
1664 if ((r = session->route_by_remote_id (dstream)) != 0) {
1666 Track* t;
1668 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1669 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1672 if (session == 0) {
1673 return;
1677 void
1678 ARDOUR_UI::queue_transport_change ()
1680 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1683 void
1684 ARDOUR_UI::map_transport_state ()
1686 if (!session) {
1687 auto_loop_button.set_visual_state (0);
1688 play_selection_button.set_visual_state (0);
1689 roll_button.set_visual_state (0);
1690 stop_button.set_visual_state (1);
1691 return;
1694 float sp = session->transport_speed();
1696 if (sp == 1.0f) {
1697 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1698 shuttle_box.queue_draw ();
1699 } else if (sp == 0.0f) {
1700 shuttle_fract = 0;
1701 shuttle_box.queue_draw ();
1702 update_disk_space ();
1705 if (sp != 0.0) {
1707 if (session->get_play_range()) {
1709 play_selection_button.set_visual_state (1);
1710 roll_button.set_visual_state (0);
1711 auto_loop_button.set_visual_state (0);
1713 } else if (session->get_play_loop ()) {
1715 auto_loop_button.set_visual_state (1);
1716 play_selection_button.set_visual_state (0);
1717 roll_button.set_visual_state (0);
1719 } else {
1721 roll_button.set_visual_state (1);
1722 play_selection_button.set_visual_state (0);
1723 auto_loop_button.set_visual_state (0);
1726 stop_button.set_visual_state (0);
1728 } else {
1730 stop_button.set_visual_state (1);
1731 roll_button.set_visual_state (0);
1732 play_selection_button.set_visual_state (0);
1733 auto_loop_button.set_visual_state (0);
1738 void
1739 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1741 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1742 (int) adj.get_value()].c_str());
1745 void
1746 ARDOUR_UI::engine_stopped ()
1748 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1749 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1750 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1753 void
1754 ARDOUR_UI::engine_running ()
1756 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1757 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1758 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1760 Glib::RefPtr<Action> action;
1761 const char* action_name = 0;
1763 switch (engine->frames_per_cycle()) {
1764 case 32:
1765 action_name = X_("JACKLatency32");
1766 break;
1767 case 64:
1768 action_name = X_("JACKLatency64");
1769 break;
1770 case 128:
1771 action_name = X_("JACKLatency128");
1772 break;
1773 case 512:
1774 action_name = X_("JACKLatency512");
1775 break;
1776 case 1024:
1777 action_name = X_("JACKLatency1024");
1778 break;
1779 case 2048:
1780 action_name = X_("JACKLatency2048");
1781 break;
1782 case 4096:
1783 action_name = X_("JACKLatency4096");
1784 break;
1785 case 8192:
1786 action_name = X_("JACKLatency8192");
1787 break;
1788 default:
1789 /* XXX can we do anything useful ? */
1790 break;
1793 if (action_name) {
1795 action = ActionManager::get_action (X_("JACK"), action_name);
1797 if (action) {
1798 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1799 ract->set_active ();
1804 void
1805 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1807 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1808 /* we can't rely on the original string continuing to exist when we are called
1809 again in the GUI thread, so make a copy and note that we need to
1810 free it later.
1812 char *copy = strdup (reason);
1813 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*this, &ARDOUR_UI::engine_halted), copy, true));
1814 return;
1817 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1818 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1820 update_sample_rate (0);
1822 string msgstr;
1824 /* if the reason is a non-empty string, it means that the backend was shutdown
1825 rather than just Ardour.
1828 if (strlen (reason)) {
1829 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1830 } else {
1831 msgstr = _("\
1832 JACK has either been shutdown or it\n\
1833 disconnected Ardour because Ardour\n\
1834 was not fast enough. Try to restart\n\
1835 JACK, reconnect and save the session.");
1838 MessageDialog msg (*editor, msgstr);
1839 pop_back_splash ();
1840 msg.run ();
1842 if (free_reason) {
1843 free ((char *) reason);
1847 int32_t
1848 ARDOUR_UI::do_engine_start ()
1850 try {
1851 engine->start();
1854 catch (...) {
1855 engine->stop ();
1856 error << _("Unable to start the session running")
1857 << endmsg;
1858 unload_session ();
1859 return -2;
1862 return 0;
1865 void
1866 ARDOUR_UI::setup_theme ()
1868 theme_manager->setup_theme();
1871 void
1872 ARDOUR_UI::update_clocks ()
1874 if (!editor || !editor->dragging_playhead()) {
1875 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1879 void
1880 ARDOUR_UI::start_clocking ()
1882 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1885 void
1886 ARDOUR_UI::stop_clocking ()
1888 clock_signal_connection.disconnect ();
1891 void
1892 ARDOUR_UI::toggle_clocking ()
1894 #if 0
1895 if (clock_button.get_active()) {
1896 start_clocking ();
1897 } else {
1898 stop_clocking ();
1900 #endif
1903 gint
1904 ARDOUR_UI::_blink (void *arg)
1907 ((ARDOUR_UI *) arg)->blink ();
1908 return TRUE;
1911 void
1912 ARDOUR_UI::blink ()
1914 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1917 void
1918 ARDOUR_UI::start_blinking ()
1920 /* Start the blink signal. Everybody with a blinking widget
1921 uses Blink to drive the widget's state.
1924 if (blink_timeout_tag < 0) {
1925 blink_on = false;
1926 blink_timeout_tag = g_timeout_add (240, _blink, this);
1930 void
1931 ARDOUR_UI::stop_blinking ()
1933 if (blink_timeout_tag >= 0) {
1934 g_source_remove (blink_timeout_tag);
1935 blink_timeout_tag = -1;
1939 void
1940 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1941 string& buf,
1942 IO& io,
1943 bool in)
1945 if (in) {
1946 if (io.n_inputs() == 0) {
1947 buf = _("none");
1948 return;
1951 /* XXX we're not handling multiple ports yet. */
1953 const char **connections = io.input(0)->get_connections();
1955 if (connections == 0 || connections[0] == '\0') {
1956 buf = _("off");
1957 } else {
1958 buf = connections[0];
1961 free (connections);
1963 } else {
1965 if (io.n_outputs() == 0) {
1966 buf = _("none");
1967 return;
1970 /* XXX we're not handling multiple ports yet. */
1972 const char **connections = io.output(0)->get_connections();
1974 if (connections == 0 || connections[0] == '\0') {
1975 buf = _("off");
1976 } else {
1977 buf = connections[0];
1980 free (connections);
1984 /** Ask the user for the name of a new shapshot and then take it.
1986 void
1987 ARDOUR_UI::snapshot_session (bool switch_to_it)
1989 ArdourPrompter prompter (true);
1990 string snapname;
1992 prompter.set_name ("Prompter");
1993 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1994 prompter.set_title (_("Take Snapshot"));
1995 prompter.set_prompt (_("Name of New Snapshot"));
1997 if (!switch_to_it) {
1998 char timebuf[128];
1999 time_t n;
2000 struct tm local_time;
2002 time (&n);
2003 localtime_r (&n, &local_time);
2004 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2006 prompter.set_initial_text (timebuf);
2009 again:
2010 switch (prompter.run()) {
2011 case RESPONSE_ACCEPT:
2012 prompter.get_result (snapname);
2013 if (snapname.length()){
2014 if (snapname.find ('/') != string::npos) {
2015 MessageDialog msg (_("To ensure compatibility with various systems\n"
2016 "snapshot names may not contain a '/' character"));
2017 msg.run ();
2018 goto again;
2020 if (snapname.find ('\\') != string::npos) {
2021 MessageDialog msg (_("To ensure compatibility with various systems\n"
2022 "snapshot names may not contain a '\\' character"));
2023 msg.run ();
2024 goto again;
2026 save_state (snapname, switch_to_it);
2028 break;
2030 default:
2031 break;
2035 void
2036 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2038 (void) save_state_canfail (name, switch_to_it);
2042 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2044 if (session) {
2045 int ret;
2047 if (name.length() == 0) {
2048 name = session->snap_name();
2051 if ((ret = session->save_state (name, false, switch_to_it)) != 0) {
2052 return ret;
2055 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2056 return 0;
2059 void
2060 ARDOUR_UI::primary_clock_value_changed ()
2062 if (session) {
2063 session->request_locate (primary_clock.current_time ());
2067 void
2068 ARDOUR_UI::big_clock_value_changed ()
2070 if (session) {
2071 session->request_locate (big_clock.current_time ());
2075 void
2076 ARDOUR_UI::secondary_clock_value_changed ()
2078 if (session) {
2079 session->request_locate (secondary_clock.current_time ());
2083 void
2084 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2086 if (session == 0) {
2087 return;
2090 switch (session->record_status()) {
2091 case Session::Enabled:
2092 if (onoff) {
2093 rec_button.set_visual_state (2);
2094 } else {
2095 rec_button.set_visual_state (0);
2097 break;
2099 case Session::Recording:
2100 rec_button.set_visual_state (1);
2101 break;
2103 default:
2104 rec_button.set_visual_state (0);
2105 break;
2109 void
2110 ARDOUR_UI::save_template ()
2112 ArdourPrompter prompter (true);
2113 string name;
2115 if (!check_audioengine()) {
2116 return;
2119 prompter.set_name (X_("Prompter"));
2120 prompter.set_title (_("Save Mix Template"));
2121 prompter.set_prompt (_("Name for mix template:"));
2122 prompter.set_initial_text(session->name() + _("-template"));
2123 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2125 switch (prompter.run()) {
2126 case RESPONSE_ACCEPT:
2127 prompter.get_result (name);
2129 if (name.length()) {
2130 session->save_template (name);
2132 break;
2134 default:
2135 break;
2139 void
2140 ARDOUR_UI::fontconfig_dialog ()
2142 #if 0
2143 /* this issue seems to have gone away with changes to font handling in GTK/Quartz
2145 #ifdef GTKOSX
2146 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2147 may not and it can take a while to build it. Warn them.
2150 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2152 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2153 MessageDialog msg (*new_session_dialog,
2154 _("Welcome to Ardour.\n\n"
2155 "The program will take a bit longer to start up\n"
2156 "while the system fonts are checked.\n\n"
2157 "This will only be done once, and you will\n"
2158 "not see this message again\n"),
2159 true,
2160 Gtk::MESSAGE_INFO,
2161 Gtk::BUTTONS_OK);
2162 pop_back_splash ();
2163 msg.show_all ();
2164 msg.present ();
2165 msg.run ();
2167 #endif
2168 #endif
2171 void
2172 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2174 existing_session = false;
2176 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2177 session_path = cmdline_path;
2178 existing_session = true;
2179 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2180 session_path = Glib::path_get_dirname (string (cmdline_path));
2181 existing_session = true;
2182 } else {
2183 /* it doesn't exist, assume the best */
2184 session_path = Glib::path_get_dirname (string (cmdline_path));
2187 session_name = basename_nosuffix (string (cmdline_path));
2191 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2193 /* when this is called, the backend audio system must be running */
2195 /* the main idea here is to deal with the fact that a cmdline argument for the session
2196 can be interpreted in different ways - it could be a directory or a file, and before
2197 we load, we need to know both the session directory and the snapshot (statefile) within it
2198 that we are supposed to use.
2201 if (session_name.length() == 0 || session_path.length() == 0) {
2202 return false;
2205 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2207 Glib::ustring predicted_session_file;
2209 predicted_session_file = session_path;
2210 predicted_session_file += '/';
2211 predicted_session_file += session_name;
2212 predicted_session_file += Session::statefile_suffix();
2214 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2215 existing_session = true;
2218 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2220 if (session_path.find (Session::statefile_suffix()) == session_path.length() - 7) {
2221 /* existing .ardour file */
2222 existing_session = true;
2225 } else {
2226 existing_session = false;
2229 /* lets just try to load it */
2231 if (create_engine ()) {
2232 backend_audio_error (false, new_session_dialog);
2233 return -1;
2236 return load_session (session_path, session_name);
2239 bool
2240 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2242 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2244 MessageDialog msg (str,
2245 false,
2246 Gtk::MESSAGE_WARNING,
2247 Gtk::BUTTONS_YES_NO,
2248 true);
2251 msg.set_name (X_("CleanupDialog"));
2252 msg.set_title (_("Cleanup Unused Sources"));
2253 msg.set_wmclass (X_("existing_session"), "Ardour");
2254 msg.set_position (Gtk::WIN_POS_MOUSE);
2255 pop_back_splash ();
2257 switch (msg.run()) {
2258 case RESPONSE_YES:
2259 return true;
2260 break;
2262 return false;
2266 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2269 uint32_t cchns;
2270 uint32_t mchns;
2271 AutoConnectOption iconnect;
2272 AutoConnectOption oconnect;
2273 uint32_t nphysin;
2274 uint32_t nphysout;
2276 if (Profile->get_sae()) {
2278 cchns = 0;
2279 mchns = 2;
2280 iconnect = AutoConnectPhysical;
2281 oconnect = AutoConnectMaster;
2282 nphysin = 0; // use all available
2283 nphysout = 0; // use all available
2285 } else {
2287 /* get settings from advanced section of NSD */
2289 if (new_session_dialog->create_control_bus()) {
2290 cchns = (uint32_t) new_session_dialog->control_channel_count();
2291 } else {
2292 cchns = 0;
2295 if (new_session_dialog->create_master_bus()) {
2296 mchns = (uint32_t) new_session_dialog->master_channel_count();
2297 } else {
2298 mchns = 0;
2301 if (new_session_dialog->connect_inputs()) {
2302 iconnect = AutoConnectPhysical;
2303 } else {
2304 iconnect = AutoConnectOption (0);
2307 /// @todo some minor tweaks.
2309 oconnect = AutoConnectOption (0);
2311 if (new_session_dialog->connect_outputs()) {
2312 if (new_session_dialog->connect_outs_to_master()) {
2313 oconnect = AutoConnectMaster;
2314 } else if (new_session_dialog->connect_outs_to_physical()) {
2315 oconnect = AutoConnectPhysical;
2319 nphysin = (uint32_t) new_session_dialog->input_limit_count();
2320 nphysout = (uint32_t) new_session_dialog->output_limit_count();
2323 if (build_session (session_path,
2324 session_name,
2325 cchns,
2326 mchns,
2327 iconnect,
2328 oconnect,
2329 nphysin,
2330 nphysout,
2331 engine->frame_rate() * 60 * 5)) {
2333 return -1;
2336 return 0;
2339 void
2340 ARDOUR_UI::end_loading_messages ()
2342 // hide_splash ();
2345 void
2346 ARDOUR_UI::loading_message (const std::string& msg)
2348 show_splash ();
2349 splash->message (msg);
2350 flush_pending ();
2353 void
2354 ARDOUR_UI::idle_load (const Glib::ustring& path)
2356 if (session) {
2357 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2358 /* /path/to/foo => /path/to/foo, foo */
2359 load_session (path, basename_nosuffix (path));
2360 } else {
2361 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2362 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2364 } else {
2366 ARDOUR_COMMAND_LINE::session_name = path;
2368 if (new_session_dialog) {
2371 /* make it break out of Dialog::run() and
2372 start again.
2375 new_session_dialog->response (1);
2380 bool
2381 ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
2383 bool existing_session = false;
2384 Glib::ustring session_name;
2385 Glib::ustring session_path;
2386 Glib::ustring template_name;
2387 int response;
2389 begin:
2390 response = Gtk::RESPONSE_NONE;
2392 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2394 parse_cmdline_path (ARDOUR_COMMAND_LINE::session_name, session_name, session_path, existing_session);
2396 /* don't ever reuse this */
2398 ARDOUR_COMMAND_LINE::session_name = string();
2400 if (existing_session && backend_audio_is_running) {
2402 /* just load the thing already */
2404 if (load_cmdline_session (session_name, session_path, existing_session) == 0) {
2405 return true;
2409 /* make the NSD use whatever information we have */
2411 new_session_dialog->set_session_name (session_name);
2412 new_session_dialog->set_session_folder (session_path);
2415 /* loading failed, or we need the NSD for something */
2417 new_session_dialog->set_modal (false);
2418 new_session_dialog->set_position (WIN_POS_CENTER);
2419 new_session_dialog->set_current_page (0);
2420 new_session_dialog->set_existing_session (existing_session);
2421 new_session_dialog->reset_recent();
2423 do {
2424 new_session_dialog->set_have_engine (backend_audio_is_running);
2425 new_session_dialog->present ();
2426 response = new_session_dialog->run ();
2428 _session_is_new = false;
2430 /* handle possible negative responses */
2432 switch (response) {
2433 case 1:
2434 /* sent by idle_load, meaning restart the whole process again */
2435 new_session_dialog->hide();
2436 new_session_dialog->reset();
2437 goto begin;
2438 break;
2440 case Gtk::RESPONSE_CANCEL:
2441 case Gtk::RESPONSE_DELETE_EVENT:
2442 if (!session) {
2443 if (engine && engine->running()) {
2444 engine->stop (true);
2446 quit();
2448 new_session_dialog->hide ();
2449 return false;
2451 case Gtk::RESPONSE_NONE:
2452 /* "Clear" was pressed */
2453 goto try_again;
2456 fontconfig_dialog();
2458 if (!backend_audio_is_running) {
2459 int ret = new_session_dialog->engine_control.setup_engine ();
2460 if (ret < 0) {
2461 return false;
2462 } else if (ret > 0) {
2463 response = Gtk::RESPONSE_REJECT;
2464 goto try_again;
2467 /* hide the NSD while we start up the engine */
2469 new_session_dialog->hide ();
2470 flush_pending ();
2473 if (create_engine ()) {
2475 backend_audio_error (!backend_audio_is_running, new_session_dialog);
2476 flush_pending ();
2478 new_session_dialog->set_existing_session (false);
2479 new_session_dialog->set_current_page (0); // new engine page
2480 new_session_dialog->engine_control.unset_interface_chosen ();
2482 response = Gtk::RESPONSE_NONE;
2483 goto try_again;
2486 backend_audio_is_running = true;
2488 if (response == Gtk::RESPONSE_OK) {
2490 session_name = new_session_dialog->session_name();
2492 if (session_name.empty()) {
2493 response = Gtk::RESPONSE_NONE;
2494 goto try_again;
2497 /* if the user mistakenly typed path information into the session filename entry,
2498 convert what they typed into a path & a name
2501 if (session_name[0] == '/' ||
2502 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2503 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2505 session_path = Glib::path_get_dirname (session_name);
2506 session_name = Glib::path_get_basename (session_name);
2508 } else {
2510 session_path = new_session_dialog->session_folder();
2514 template_name = Glib::ustring();
2515 switch (new_session_dialog->which_page()) {
2517 case NewSessionDialog::OpenPage:
2518 goto loadit;
2519 break;
2521 case NewSessionDialog::EnginePage:
2522 if (new_session_dialog->engine_control.interface_chosen() && !session_path.empty()) {
2523 goto loadit;
2524 } else {
2525 goto try_again;
2527 break;
2529 case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
2531 should_be_new = true;
2533 if (session_name.find ('/') != Glib::ustring::npos) {
2534 MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
2535 "session names may not contain a '/' character"));
2536 msg.run ();
2537 response = RESPONSE_NONE;
2538 goto try_again;
2541 if (session_name.find ('\\') != Glib::ustring::npos) {
2542 MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
2543 "session names may not contain a '\\' character"));
2544 msg.run ();
2545 response = RESPONSE_NONE;
2546 goto try_again;
2549 //XXX This is needed because session constructor wants a
2550 //non-existant path. hopefully this will be fixed at some point.
2552 session_path = Glib::build_filename (session_path, session_name);
2554 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2556 new_session_dialog->hide ();
2558 if (ask_about_loading_existing_session (session_path)) {
2559 goto loadit;
2560 } else {
2561 response = RESPONSE_NONE;
2562 goto try_again;
2566 _session_is_new = true;
2568 if (new_session_dialog->use_session_template()) {
2570 template_name = new_session_dialog->session_template_name();
2571 goto loadit;
2573 } else {
2574 if (build_session_from_nsd (session_path, session_name)) {
2575 response = RESPONSE_NONE;
2576 goto try_again;
2578 goto done;
2580 break;
2582 default:
2583 break;
2586 loadit:
2587 new_session_dialog->hide ();
2589 if (load_session (session_path, session_name, template_name)) {
2590 /* force a retry */
2591 response = Gtk::RESPONSE_NONE;
2594 try_again:
2595 if (response == Gtk::RESPONSE_NONE) {
2596 new_session_dialog->set_existing_session (false);
2597 new_session_dialog->reset ();
2601 } while (response == Gtk::RESPONSE_NONE || response == Gtk::RESPONSE_REJECT);
2603 done:
2604 show();
2605 new_session_dialog->hide();
2606 new_session_dialog->reset();
2607 goto_editor_window ();
2608 return true;
2611 void
2612 ARDOUR_UI::close_session ()
2614 if (!check_audioengine()) {
2615 return;
2618 if (unload_session (true)) {
2619 return;
2622 get_session_parameters (true, false);
2626 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2628 Session *new_session;
2629 int unload_status;
2630 int retval = -1;
2632 session_loaded = false;
2634 if (!check_audioengine()) {
2635 return -1;
2638 unload_status = unload_session ();
2640 if (unload_status < 0) {
2641 goto out;
2642 } else if (unload_status > 0) {
2643 retval = 0;
2644 goto out;
2647 loading_message (_("Please wait while Ardour loads your session"));
2649 try {
2650 new_session = new Session (*engine, path, snap_name, mix_template);
2653 /* this one is special */
2655 catch (AudioEngine::PortRegistrationFailure& err) {
2657 MessageDialog msg (err.what(),
2658 true,
2659 Gtk::MESSAGE_INFO,
2660 Gtk::BUTTONS_CLOSE);
2662 msg.set_title (_("Port Registration Error"));
2663 msg.set_secondary_text (_("Click the Close button to try again."));
2664 msg.set_position (Gtk::WIN_POS_CENTER);
2665 pop_back_splash ();
2666 msg.present ();
2668 int response = msg.run ();
2670 msg.hide ();
2672 switch (response) {
2673 case RESPONSE_CANCEL:
2674 exit (1);
2675 default:
2676 break;
2678 goto out;
2681 /* this exception is also special */
2683 catch (Session::SRMismatchRejected& err) {
2684 goto out; /* just go back and reload something else, etc. */
2687 catch (...) {
2689 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2690 true,
2691 Gtk::MESSAGE_INFO,
2692 Gtk::BUTTONS_CLOSE);
2694 msg.set_title (_("Loading Error"));
2695 msg.set_secondary_text (_("Click the Close button to try again."));
2696 msg.set_position (Gtk::WIN_POS_CENTER);
2697 pop_back_splash ();
2698 msg.present ();
2700 int response = msg.run ();
2702 msg.hide ();
2704 switch (response) {
2705 case RESPONSE_CANCEL:
2706 exit (1);
2707 default:
2708 break;
2710 goto out;
2713 connect_to_session (new_session);
2715 Config->set_current_owner (ConfigVariableBase::Interface);
2717 session_loaded = true;
2719 goto_editor_window ();
2721 if (session) {
2722 session->set_clean ();
2725 flush_pending ();
2726 retval = 0;
2728 out:
2729 return retval;
2733 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2734 uint32_t control_channels,
2735 uint32_t master_channels,
2736 AutoConnectOption input_connect,
2737 AutoConnectOption output_connect,
2738 uint32_t nphysin,
2739 uint32_t nphysout,
2740 nframes_t initial_length)
2742 Session *new_session;
2743 int x;
2745 if (!check_audioengine()) {
2746 return -1;
2749 session_loaded = false;
2751 x = unload_session ();
2753 if (x < 0) {
2754 return -1;
2755 } else if (x > 0) {
2756 return 0;
2759 _session_is_new = true;
2761 try {
2762 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2763 control_channels, master_channels, nphysin, nphysout, initial_length);
2766 catch (...) {
2768 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2769 pop_back_splash ();
2770 msg.run ();
2771 return -1;
2774 connect_to_session (new_session);
2776 session_loaded = true;
2778 new_session->save_state(new_session->name());
2780 return 0;
2783 void
2784 ARDOUR_UI::show ()
2786 if (editor) {
2787 editor->show_window ();
2789 if (!shown_flag) {
2790 editor->present ();
2793 shown_flag = true;
2797 void
2798 ARDOUR_UI::show_about ()
2800 if (about == 0) {
2801 about = new About;
2802 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2805 about->set_transient_for(*editor);
2807 about->show_all ();
2810 void
2811 ARDOUR_UI::launch_chat ()
2813 #ifdef __APPLE__
2814 NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2815 #else
2816 NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour");
2817 #endif
2820 void
2821 ARDOUR_UI::hide_about ()
2823 if (about) {
2824 about->get_window()->set_cursor ();
2825 about->hide ();
2829 void
2830 ARDOUR_UI::about_signal_response(int response)
2832 hide_about();
2835 void
2836 ARDOUR_UI::show_splash ()
2838 if (splash == 0) {
2839 try {
2840 splash = new Splash;
2841 } catch (...) {
2842 return;
2846 splash->show ();
2847 splash->present ();
2848 splash->queue_draw ();
2849 splash->get_window()->process_updates (true);
2850 flush_pending ();
2853 void
2854 ARDOUR_UI::hide_splash ()
2856 if (splash) {
2857 splash->hide();
2861 void
2862 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title,
2863 const string& plural_msg, const string& singular_msg)
2865 size_t removed;
2867 removed = rep.paths.size();
2869 if (removed == 0) {
2870 MessageDialog msgd (*editor,
2871 _("No audio files were ready for cleanup"),
2872 true,
2873 Gtk::MESSAGE_INFO,
2874 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2875 msgd.set_secondary_text (_("If this seems suprising, \n\
2876 check for any existing snapshots.\n\
2877 These may still include regions that\n\
2878 require some unused files to continue to exist."));
2880 msgd.run ();
2881 return;
2884 ArdourDialog results (_("ardour: cleanup"), true, false);
2886 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2887 CleanupResultsModelColumns() {
2888 add (visible_name);
2889 add (fullpath);
2891 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2892 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2896 CleanupResultsModelColumns results_columns;
2897 Glib::RefPtr<Gtk::ListStore> results_model;
2898 Gtk::TreeView results_display;
2900 results_model = ListStore::create (results_columns);
2901 results_display.set_model (results_model);
2902 results_display.append_column (list_title, results_columns.visible_name);
2904 results_display.set_name ("CleanupResultsList");
2905 results_display.set_headers_visible (true);
2906 results_display.set_headers_clickable (false);
2907 results_display.set_reorderable (false);
2909 Gtk::ScrolledWindow list_scroller;
2910 Gtk::Label txt;
2911 Gtk::VBox dvbox;
2912 Gtk::HBox dhbox; // the hbox for the image and text
2913 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2914 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2916 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2919 /* subst:
2920 %1 - number of files removed
2921 %2 - location of "dead_sounds"
2922 %3 - size of files affected
2923 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2926 const char* bprefix;
2927 float space_adjusted;
2929 if (rep.space < 1000000.0f) {
2930 bprefix = X_("kilo");
2931 space_adjusted = truncf((float)rep.space / 1000.0f);
2932 } else if (rep.space < (1000000.0f * 1000)) {
2933 bprefix = X_("mega");
2934 space_adjusted = truncf((float)rep.space / (1000000.0f));
2935 } else {
2936 bprefix = X_("giga");
2937 space_adjusted = truncf((float)rep.space / (1000000.0f * 1000));
2940 if (removed > 1) {
2941 txt.set_text (string_compose (plural_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
2942 } else {
2943 txt.set_text (string_compose (singular_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
2946 dhbox.pack_start (*dimage, true, false, 5);
2947 dhbox.pack_start (txt, true, false, 5);
2949 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2950 TreeModel::Row row = *(results_model->append());
2951 row[results_columns.visible_name] = *i;
2952 row[results_columns.fullpath] = *i;
2955 list_scroller.add (results_display);
2956 list_scroller.set_size_request (-1, 150);
2957 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2959 dvbox.pack_start (dhbox, true, false, 5);
2960 dvbox.pack_start (list_scroller, true, false, 5);
2961 ddhbox.pack_start (dvbox, true, false, 5);
2963 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2964 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2965 results.set_default_response (RESPONSE_CLOSE);
2966 results.set_position (Gtk::WIN_POS_MOUSE);
2967 results.show_all_children ();
2968 results.set_resizable (false);
2970 results.run ();
2974 void
2975 ARDOUR_UI::cleanup ()
2977 if (session == 0) {
2978 /* shouldn't happen: menu item is insensitive */
2979 return;
2983 MessageDialog checker (_("Are you sure you want to cleanup?"),
2984 true,
2985 Gtk::MESSAGE_QUESTION,
2986 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2988 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2989 ALL undo/redo information will be lost if you cleanup.\n\
2990 After cleanup, unused audio files will be moved to a \
2991 \"dead sounds\" location."));
2993 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2994 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2995 checker.set_default_response (RESPONSE_CANCEL);
2997 checker.set_name (_("CleanupDialog"));
2998 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2999 checker.set_position (Gtk::WIN_POS_MOUSE);
3001 switch (checker.run()) {
3002 case RESPONSE_ACCEPT:
3003 break;
3004 default:
3005 return;
3008 Session::cleanup_report rep;
3010 editor->prepare_for_cleanup ();
3012 /* do not allow flush until a session is reloaded */
3014 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3015 if (act) {
3016 act->set_sensitive (false);
3019 if (session->cleanup_sources (rep)) {
3020 editor->finish_cleanup ();
3021 return;
3024 editor->finish_cleanup ();
3026 checker.hide();
3027 display_cleanup_results (rep,
3028 _("cleaned files"),
3029 _("\
3030 The following %1 files were not in use and \n\
3031 have been moved to:\n\
3032 %2. \n\n\
3033 Flushing the wastebasket will \n\
3034 release an additional\n\
3035 %3 %4bytes of disk space.\n"),
3036 _("\
3037 The following file was not in use and \n \
3038 has been moved to:\n \
3039 %2. \n\n\
3040 Flushing the wastebasket will \n\
3041 release an additional\n\
3042 %3 %4bytes of disk space.\n"
3047 void
3048 ARDOUR_UI::flush_trash ()
3050 if (session == 0) {
3051 /* shouldn't happen: menu item is insensitive */
3052 return;
3055 Session::cleanup_report rep;
3057 if (session->cleanup_trash_sources (rep)) {
3058 return;
3061 display_cleanup_results (rep,
3062 _("deleted file"),
3063 _("The following %1 files were deleted from\n\
3064 %2,\n\
3065 releasing %3 %4bytes of disk space"),
3066 _("The following file was deleted from\n\
3067 %2,\n\
3068 releasing %3 %4bytes of disk space"));
3071 void
3072 ARDOUR_UI::add_route (Gtk::Window* float_window)
3074 int count;
3076 if (!session) {
3077 return;
3080 if (add_route_dialog == 0) {
3081 add_route_dialog = new AddRouteDialog;
3082 if (float_window) {
3083 add_route_dialog->set_transient_for (*float_window);
3087 if (add_route_dialog->is_visible()) {
3088 /* we're already doing this */
3089 return;
3092 ResponseType r = (ResponseType) add_route_dialog->run ();
3094 add_route_dialog->hide();
3096 switch (r) {
3097 case RESPONSE_ACCEPT:
3098 break;
3099 default:
3100 return;
3101 break;
3104 if ((count = add_route_dialog->count()) <= 0) {
3105 return;
3108 string template_path = add_route_dialog->track_template();
3110 if (!template_path.empty()) {
3111 session->new_route_from_template (count, template_path);
3112 return;
3115 uint32_t input_chan = add_route_dialog->channels ();
3116 uint32_t output_chan;
3117 string name_template = add_route_dialog->name_template ();
3118 bool track = add_route_dialog->track ();
3120 AutoConnectOption oac = Config->get_output_auto_connect();
3122 if (oac & AutoConnectMaster) {
3123 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
3124 } else {
3125 output_chan = input_chan;
3128 /* XXX do something with name template */
3130 if (track) {
3131 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
3132 } else {
3133 session_add_audio_bus (input_chan, output_chan, count);
3137 XMLNode*
3138 ARDOUR_UI::mixer_settings () const
3140 XMLNode* node = 0;
3142 if (session) {
3143 node = session->instant_xml(X_("Mixer"), session->path());
3144 } else {
3145 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
3148 if (!node) {
3149 node = new XMLNode (X_("Mixer"));
3152 return node;
3155 XMLNode*
3156 ARDOUR_UI::editor_settings () const
3158 XMLNode* node = 0;
3160 if (session) {
3161 node = session->instant_xml(X_("Editor"), session->path());
3162 } else {
3163 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
3166 if (!node) {
3167 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3168 node = Config->instant_xml(X_("Editor"), getenv("ARDOUR_INSTANT_XML_PATH"));
3172 if (!node) {
3173 node = new XMLNode (X_("Editor"));
3175 return node;
3178 XMLNode*
3179 ARDOUR_UI::keyboard_settings () const
3181 XMLNode* node = 0;
3183 node = Config->extra_xml(X_("Keyboard"));
3185 if (!node) {
3186 node = new XMLNode (X_("Keyboard"));
3188 return node;
3191 void
3192 ARDOUR_UI::create_xrun_marker(nframes_t where)
3194 editor->mouse_add_new_marker (where, false, true);
3197 void
3198 ARDOUR_UI::halt_on_xrun_message ()
3200 MessageDialog msg (*editor,
3201 _("Recording was stopped because your system could not keep up."));
3202 msg.run ();
3205 void
3206 ARDOUR_UI::xrun_handler(nframes_t where)
3208 if (!session) {
3209 return;
3212 ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::xrun_handler), where));
3214 if (session && Config->get_create_xrun_marker() && session->actively_recording()) {
3215 create_xrun_marker(where);
3218 if (session && Config->get_stop_recording_on_xrun() && session->actively_recording()) {
3219 halt_on_xrun_message ();
3223 bool
3224 ARDOUR_UI::preset_file_exists_handler ()
3226 /* if driven from another thread, say "do not overwrite" and show the user nothing.
3229 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) { \
3230 return false;
3233 HBox* hbox = new HBox();
3234 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3235 Gtk::Dialog dialog (_("Preset Exists"), true, false);
3236 Label message (_("\
3237 A preset with this name already exists for this plugin.\n\
3239 What you would like to do?\n"));
3240 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3241 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3242 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3243 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3244 dialog.add_button (_("Overwrite the existing preset"), RESPONSE_ACCEPT);
3245 dialog.add_button (_("Leave the existing preset alone"), RESPONSE_REJECT);
3246 dialog.set_default_response (RESPONSE_ACCEPT);
3247 dialog.set_position (WIN_POS_MOUSE);
3248 dialog.set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY); // need to make it float above the preset name dialog
3250 message.show();
3251 image->show();
3252 hbox->show();
3254 switch (dialog.run ()) {
3255 case RESPONSE_ACCEPT:
3256 return true;
3257 default:
3258 return false;
3262 void
3263 ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
3265 time_t now;
3266 time (&now);
3268 while (disk_buffer_stats.size() > 60) {
3269 disk_buffer_stats.pop_front ();
3272 disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
3275 void
3276 ARDOUR_UI::write_buffer_stats ()
3278 std::ofstream fout;
3279 struct tm tm;
3280 char buf[64];
3281 char path[PATH_MAX+1]; int fd;
3283 strcpy (path, "ardourBufferingXXXXXX");
3285 if ((fd = mkstemp (path )) < 0) {
3286 cerr << X_("cannot find temporary name for ardour buffer stats") << endl;
3287 return;
3290 fout.open (path);
3291 close (fd);
3293 if (!fout) {
3294 cerr << string_compose (X_("cannot open file %1 for ardour buffer stats"), path) << endl;
3295 return;
3298 for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
3299 localtime_r (&(*i).when, &tm);
3300 strftime (buf, sizeof (buf), "%T", &tm);
3301 fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
3304 disk_buffer_stats.clear ();
3306 fout.close ();
3308 cerr << "Ardour buffering statistics can be found in: " << path << endl;
3311 void
3312 ARDOUR_UI::disk_overrun_handler ()
3315 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
3317 write_buffer_stats ();
3319 if (!have_disk_speed_dialog_displayed) {
3320 have_disk_speed_dialog_displayed = true;
3321 MessageDialog* msg = new MessageDialog (*editor, _("\
3322 The disk system on your computer\n\
3323 was not able to keep up with Ardour.\n\
3325 Specifically, it failed to write data to disk\n\
3326 quickly enough to keep up with recording.\n"));
3327 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3328 msg->show_all ();
3332 void
3333 ARDOUR_UI::disk_underrun_handler ()
3336 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
3338 write_buffer_stats ();
3340 if (!have_disk_speed_dialog_displayed) {
3341 have_disk_speed_dialog_displayed = true;
3342 MessageDialog* msg = new MessageDialog (*editor,
3343 _("The disk system on your computer\n\
3344 was not able to keep up with Ardour.\n\
3346 Specifically, it failed to read data from disk\n\
3347 quickly enough to keep up with playback.\n"));
3348 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3349 msg->show_all ();
3353 void
3354 ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
3356 have_disk_speed_dialog_displayed = false;
3357 delete msg;
3360 void
3361 ARDOUR_UI::session_dialog (std::string msg)
3363 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
3365 MessageDialog* d;
3367 if (editor) {
3368 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3369 } else {
3370 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3373 d->show_all ();
3374 d->run ();
3375 delete d;
3379 ARDOUR_UI::pending_state_dialog ()
3381 HBox* hbox = new HBox();
3382 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3383 ArdourDialog dialog (_("Crash Recovery"), true);
3384 Label message (_("\
3385 This session appears to have been in\n\
3386 middle of recording when ardour or\n\
3387 the computer was shutdown.\n\
3389 Ardour can recover any captured audio for\n\
3390 you, or it can ignore it. Please decide\n\
3391 what you would like to do.\n"));
3392 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3393 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3394 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3395 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3396 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3397 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3398 dialog.set_default_response (RESPONSE_ACCEPT);
3399 dialog.set_position (WIN_POS_CENTER);
3400 message.show();
3401 image->show();
3402 hbox->show();
3404 pop_back_splash ();
3406 switch (dialog.run ()) {
3407 case RESPONSE_ACCEPT:
3408 return 1;
3409 default:
3410 return 0;
3415 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3417 HBox* hbox = new HBox();
3418 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3419 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3420 Label message (string_compose (_("\
3421 This session was created with a sample rate of %1 Hz\n\
3423 The audioengine is currently running at %2 Hz\n"), desired, actual));
3425 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3426 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3427 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3428 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3429 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3430 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3431 dialog.set_default_response (RESPONSE_ACCEPT);
3432 dialog.set_position (WIN_POS_CENTER);
3433 message.show();
3434 image->show();
3435 hbox->show();
3437 switch (dialog.run ()) {
3438 case RESPONSE_ACCEPT:
3439 return 0;
3440 default:
3441 return 1;
3446 void
3447 ARDOUR_UI::disconnect_from_jack ()
3449 if (engine) {
3450 if( engine->disconnect_from_jack ()) {
3451 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3452 msg.run ();
3455 update_sample_rate (0);
3459 void
3460 ARDOUR_UI::reconnect_to_jack ()
3462 if (engine) {
3463 if (engine->reconnect_to_jack ()) {
3464 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3465 msg.run ();
3468 update_sample_rate (0);
3472 void
3473 ARDOUR_UI::use_config ()
3475 Glib::RefPtr<Action> act;
3477 switch (Config->get_native_file_data_format ()) {
3478 case FormatFloat:
3479 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
3480 break;
3481 case FormatInt24:
3482 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
3483 break;
3484 case FormatInt16:
3485 act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit"));
3486 break;
3489 if (act) {
3490 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3491 ract->set_active ();
3494 switch (Config->get_native_file_header_format ()) {
3495 case BWF:
3496 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
3497 break;
3498 case WAVE:
3499 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
3500 break;
3501 case WAVE64:
3502 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
3503 break;
3504 case iXML:
3505 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
3506 break;
3507 case RF64:
3508 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
3509 break;
3510 case CAF:
3511 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
3512 break;
3513 case AIFF:
3514 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
3515 break;
3518 if (act) {
3519 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3520 ract->set_active ();
3523 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3524 if (node) {
3525 set_transport_controllable_state (*node);
3529 void
3530 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3532 if (Config->get_primary_clock_delta_edit_cursor()) {
3533 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3534 } else {
3535 primary_clock.set (pos, 0, true);
3538 if (Config->get_secondary_clock_delta_edit_cursor()) {
3539 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3540 } else {
3541 secondary_clock.set (pos);
3544 if (big_clock_window) {
3545 big_clock.set (pos);
3549 void
3550 ARDOUR_UI::record_state_changed ()
3552 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3554 if (!session || !big_clock_window) {
3555 /* why bother - the clock isn't visible */
3556 return;
3559 switch (session->record_status()) {
3560 case Session::Recording:
3561 big_clock.set_widget_name ("BigClockRecording");
3562 break;
3563 default:
3564 big_clock.set_widget_name ("BigClockNonRecording");
3565 break;
3569 bool
3570 ARDOUR_UI::first_idle ()
3572 if (session) {
3573 session->allow_auto_play (true);
3576 if (editor) {
3577 editor->first_idle();
3580 Keyboard::set_can_save_keybindings (true);
3581 return false;
3584 void
3585 ARDOUR_UI::store_clock_modes ()
3587 XMLNode* node = new XMLNode(X_("ClockModes"));
3589 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3590 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3593 session->add_extra_xml (*node);
3594 session->set_dirty ();
3599 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3600 : Controllable (name), ui (u), type(tp)
3605 void
3606 ARDOUR_UI::TransportControllable::set_value (float val)
3608 if (type == ShuttleControl) {
3609 double fract;
3611 if (val == 0.5f) {
3612 fract = 0.0;
3613 } else {
3614 if (val < 0.5f) {
3615 fract = -((0.5f - val)/0.5f);
3616 } else {
3617 fract = ((val - 0.5f)/0.5f);
3621 ui.set_shuttle_fract (fract);
3622 return;
3625 if (val < 0.5f) {
3626 /* do nothing: these are radio-style actions */
3627 return;
3630 const char *action = 0;
3632 switch (type) {
3633 case Roll:
3634 action = X_("Roll");
3635 break;
3636 case Stop:
3637 action = X_("Stop");
3638 break;
3639 case GotoStart:
3640 action = X_("Goto Start");
3641 break;
3642 case GotoEnd:
3643 action = X_("Goto End");
3644 break;
3645 case AutoLoop:
3646 action = X_("Loop");
3647 break;
3648 case PlaySelection:
3649 action = X_("Play Selection");
3650 break;
3651 case RecordEnable:
3652 action = X_("Record");
3653 break;
3654 default:
3655 break;
3658 if (action == 0) {
3659 return;
3662 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3664 if (act) {
3665 act->activate ();
3669 float
3670 ARDOUR_UI::TransportControllable::get_value (void) const
3672 float val = 0.0f;
3674 switch (type) {
3675 case Roll:
3676 break;
3677 case Stop:
3678 break;
3679 case GotoStart:
3680 break;
3681 case GotoEnd:
3682 break;
3683 case AutoLoop:
3684 break;
3685 case PlaySelection:
3686 break;
3687 case RecordEnable:
3688 break;
3689 case ShuttleControl:
3690 break;
3691 default:
3692 break;
3695 return val;
3698 void
3699 ARDOUR_UI::TransportControllable::set_id (const string& str)
3701 _id = str;
3704 void
3705 ARDOUR_UI::setup_profile ()
3707 if (gdk_screen_width() < 1200) {
3708 Profile->set_small_screen ();
3711 if (getenv ("ARDOUR_SAE")) {
3712 Profile->set_sae ();
3713 Profile->set_single_package ();