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.
31 #include <sys/resource.h>
33 #include <gtkmm/messagedialog.h>
34 #include <gtkmm/accelmap.h>
36 #include <pbd/error.h>
37 #include <pbd/basename.h>
38 #include <pbd/compose.h>
39 #include <pbd/pathscanner.h>
40 #include <pbd/failed_constructor.h>
41 #include <pbd/enumwriter.h>
42 #include <pbd/stacktrace.h>
43 #include <gtkmm2ext/gtk_ui.h>
44 #include <gtkmm2ext/utils.h>
45 #include <gtkmm2ext/click_box.h>
46 #include <gtkmm2ext/fastmeter.h>
47 #include <gtkmm2ext/stop_signal.h>
48 #include <gtkmm2ext/popup.h>
49 #include <gtkmm2ext/window_title.h>
51 #include <midi++/port.h>
52 #include <midi++/mmc.h>
54 #include <ardour/ardour.h>
55 #include <ardour/profile.h>
56 #include <ardour/session_route.h>
57 #include <ardour/port.h>
58 #include <ardour/audioengine.h>
59 #include <ardour/playlist.h>
60 #include <ardour/utils.h>
61 #include <ardour/audio_diskstream.h>
62 #include <ardour/audiofilesource.h>
63 #include <ardour/recent_sessions.h>
64 #include <ardour/port.h>
65 #include <ardour/audio_track.h>
67 typedef uint64_t microseconds_t;
70 #include "ardour_ui.h"
71 #include "public_editor.h"
72 #include "audio_clock.h"
77 #include "add_route_dialog.h"
78 #include "new_session_dialog.h"
82 #include "gui_thread.h"
83 #include "theme_manager.h"
84 #include "engine_dialog.h"
85 #include "gain_meter.h"
86 #include "route_time_axis.h"
90 using namespace ARDOUR;
92 using namespace Gtkmm2ext;
96 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
97 UIConfiguration *ARDOUR_UI::ui_config = 0;
99 sigc::signal<void,bool> ARDOUR_UI::Blink;
100 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
101 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
102 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
104 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
106 : Gtkmm2ext::UI (X_("Ardour"), argcp, argvp),
108 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true),
109 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true),
110 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
111 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
115 preroll_button (_("pre\nroll")),
116 postroll_button (_("post\nroll")),
120 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, false, true),
124 roll_controllable ("transport roll", *this, TransportControllable::Roll),
125 stop_controllable ("transport stop", *this, TransportControllable::Stop),
126 goto_start_controllable ("transport goto start", *this, TransportControllable::GotoStart),
127 goto_end_controllable ("transport goto end", *this, TransportControllable::GotoEnd),
128 auto_loop_controllable ("transport auto loop", *this, TransportControllable::AutoLoop),
129 play_selection_controllable ("transport play selection", *this, TransportControllable::PlaySelection),
130 rec_controllable ("transport rec-enable", *this, TransportControllable::RecordEnable),
131 shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl),
132 shuttle_controller_binding_proxy (shuttle_controllable),
134 roll_button (roll_controllable),
135 stop_button (stop_controllable),
136 goto_start_button (goto_start_controllable),
137 goto_end_button (goto_end_controllable),
138 auto_loop_button (auto_loop_controllable),
139 play_selection_button (play_selection_controllable),
140 rec_button (rec_controllable),
142 shuttle_units_button (_("% ")),
144 punch_in_button (_("Punch In")),
145 punch_out_button (_("Punch Out")),
146 auto_return_button (_("Auto Return")),
147 auto_play_button (_("Auto Play")),
148 auto_input_button (_("Auto Input")),
149 click_button (_("Click")),
150 time_master_button (_("time\nmaster")),
152 auditioning_alert_button (_("AUDITION")),
153 solo_alert_button (_("SOLO")),
155 error_log_button (_("Errors"))
157 using namespace Gtk::Menu_Helpers;
162 _auto_display_errors = false;
168 if (ARDOUR_COMMAND_LINE::session_name.length()) {
169 /* only show this if we're not going to post the new session dialog */
173 if (theArdourUI == 0) {
177 ui_config = new UIConfiguration();
178 theme_manager = new ThemeManager();
184 _session_is_new = false;
185 big_clock_window = 0;
186 session_selector_window = 0;
187 new_session_dialog = 0;
188 last_key_press_time = 0;
189 connection_editor = 0;
190 add_route_dialog = 0;
195 open_session_selector = 0;
196 have_configure_timeout = false;
197 have_disk_speed_dialog_displayed = false;
198 _will_create_new_session_automatically = false;
199 session_loaded = false;
200 last_speed_displayed = -1.0f;
201 ignore_dual_punch = false;
203 last_configure_time= 0;
205 shuttle_grabbed = false;
207 shuttle_max_speed = 8.0f;
209 shuttle_style_menu = 0;
210 shuttle_unit_menu = 0;
212 // We do not have jack linked in yet so;
214 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
216 ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
217 ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
219 /* handle dialog requests */
221 ARDOUR::Session::Dialog.connect (mem_fun(*this, &ARDOUR_UI::session_dialog));
223 /* handle pending state with a dialog */
225 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
227 /* handle sr mismatch with a dialog */
229 ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
231 /* lets get this party started */
234 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
235 throw failed_constructor ();
238 setup_gtk_ardour_enums ();
239 Config->set_current_owner (ConfigVariableBase::Interface);
242 GainMeter::setup_slider_pix ();
243 RouteTimeAxisView::setup_slider_pix ();
245 } catch (failed_constructor& err) {
246 error << _("could not initialize Ardour.") << endmsg;
251 /* we like keyboards */
253 keyboard = new Keyboard;
257 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
258 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
264 ARDOUR_UI::create_engine ()
266 // this gets called every time by new_session()
272 loading_message (_("Starting audio engine"));
275 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
282 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
283 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
284 engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
285 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
293 ARDOUR_UI::post_engine ()
295 /* Things to be done once we create the AudioEngine
298 check_memory_locking();
300 ActionManager::init ();
303 if (setup_windows ()) {
304 throw failed_constructor ();
307 /* this is the first point at which all the keybindings are available */
309 if (ARDOUR_COMMAND_LINE::show_key_actions) {
310 vector<string> names;
311 vector<string> paths;
313 vector<AccelKey> bindings;
315 ActionManager::get_all_actions (names, paths, keys, bindings);
317 vector<string>::iterator n;
318 vector<string>::iterator k;
319 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
320 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
326 blink_timeout_tag = -1;
328 /* the global configuration object is now valid */
332 /* this being a GUI and all, we want peakfiles */
334 AudioFileSource::set_build_peakfiles (true);
335 AudioFileSource::set_build_missing_peakfiles (true);
337 /* set default clock modes */
339 if (Profile->get_sae()) {
340 primary_clock.set_mode (AudioClock::MinSec);
342 primary_clock.set_mode (AudioClock::SMPTE);
344 secondary_clock.set_mode (AudioClock::BBT);
346 /* start the time-of-day-clock */
349 /* OS X provides an always visible wallclock, so don't be stupid */
350 update_wall_clock ();
351 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
354 update_disk_space ();
356 update_sample_rate (engine->frame_rate());
358 platform_specific ();
360 /* now start and maybe save state */
362 if (do_engine_start () == 0) {
363 if (session && _session_is_new) {
364 /* we need to retain initial visual
365 settings for a new session
367 session->save_state ("");
372 ARDOUR_UI::~ARDOUR_UI ()
374 save_ardour_state ();
388 if (add_route_dialog) {
389 delete add_route_dialog;
392 if (new_session_dialog) {
393 delete new_session_dialog;
398 ARDOUR_UI::pop_back_splash ()
400 if (Splash::instance()) {
401 // Splash::instance()->pop_back();
402 Splash::instance()->hide ();
407 ARDOUR_UI::configure_timeout ()
409 if (last_configure_time == 0) {
410 /* no configure events yet */
414 /* force a gap of 0.5 seconds since the last configure event
417 if (get_microseconds() - last_configure_time < 500000) {
420 have_configure_timeout = false;
421 save_ardour_state ();
427 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
429 if (have_configure_timeout) {
430 last_configure_time = get_microseconds();
432 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
433 have_configure_timeout = true;
440 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
442 const XMLProperty* prop;
444 if ((prop = node.property ("roll")) != 0) {
445 roll_controllable.set_id (prop->value());
447 if ((prop = node.property ("stop")) != 0) {
448 stop_controllable.set_id (prop->value());
450 if ((prop = node.property ("goto_start")) != 0) {
451 goto_start_controllable.set_id (prop->value());
453 if ((prop = node.property ("goto_end")) != 0) {
454 goto_end_controllable.set_id (prop->value());
456 if ((prop = node.property ("auto_loop")) != 0) {
457 auto_loop_controllable.set_id (prop->value());
459 if ((prop = node.property ("play_selection")) != 0) {
460 play_selection_controllable.set_id (prop->value());
462 if ((prop = node.property ("rec")) != 0) {
463 rec_controllable.set_id (prop->value());
465 if ((prop = node.property ("shuttle")) != 0) {
466 shuttle_controllable.set_id (prop->value());
471 ARDOUR_UI::get_transport_controllable_state ()
473 XMLNode* node = new XMLNode(X_("TransportControllables"));
476 roll_controllable.id().print (buf, sizeof (buf));
477 node->add_property (X_("roll"), buf);
478 stop_controllable.id().print (buf, sizeof (buf));
479 node->add_property (X_("stop"), buf);
480 goto_start_controllable.id().print (buf, sizeof (buf));
481 node->add_property (X_("goto_start"), buf);
482 goto_end_controllable.id().print (buf, sizeof (buf));
483 node->add_property (X_("goto_end"), buf);
484 auto_loop_controllable.id().print (buf, sizeof (buf));
485 node->add_property (X_("auto_loop"), buf);
486 play_selection_controllable.id().print (buf, sizeof (buf));
487 node->add_property (X_("play_selection"), buf);
488 rec_controllable.id().print (buf, sizeof (buf));
489 node->add_property (X_("rec"), buf);
490 shuttle_controllable.id().print (buf, sizeof (buf));
491 node->add_property (X_("shuttle"), buf);
497 ARDOUR_UI::save_ardour_state ()
499 if (!keyboard || !mixer || !editor) {
503 /* XXX this is all a bit dubious. add_extra_xml() uses
504 a different lifetime model from add_instant_xml().
507 XMLNode* node = new XMLNode (keyboard->get_state());
508 Config->add_extra_xml (*node);
509 Config->add_extra_xml (get_transport_controllable_state());
510 if (new_session_dialog) {
511 if (new_session_dialog->engine_control.was_used()) {
512 Config->add_extra_xml (new_session_dialog->engine_control.get_state());
515 Config->save_state();
516 ui_config->save_state ();
518 XMLNode enode(static_cast<Stateful*>(editor)->get_state());
519 XMLNode mnode(mixer->get_state());
522 session->add_instant_xml (enode, session->path());
523 session->add_instant_xml (mnode, session->path());
525 Config->add_instant_xml (enode, get_user_ardour_path());
526 Config->add_instant_xml (mnode, get_user_ardour_path());
529 Keyboard::save_keybindings ();
533 ARDOUR_UI::autosave_session ()
535 if (g_main_depth() > 1) {
536 /* inside a recursive main loop,
537 give up because we may not be able to
543 if (!Config->get_periodic_safety_backups())
547 session->maybe_write_autosave();
554 ARDOUR_UI::update_autosave ()
556 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
558 if (session->dirty()) {
559 if (_autosave_connection.connected()) {
560 _autosave_connection.disconnect();
563 _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
564 Config->get_periodic_safety_backup_interval() * 1000);
567 if (_autosave_connection.connected()) {
568 _autosave_connection.disconnect();
574 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
578 title = _("Ardour could not start JACK");
580 title = _("Ardour could not connect to JACK.");
583 MessageDialog win (title,
589 win.set_secondary_text(_("There are several possible reasons:\n\
591 1) You requested audio parameters that are not supported..\n\
592 2) JACK is running as another user.\n\
594 Please consider the possibilities, and perhaps try different parameters."));
596 win.set_secondary_text(_("There are several possible reasons:\n\
598 1) JACK is not running.\n\
599 2) JACK is running as another user, perhaps root.\n\
600 3) There is already another client called \"ardour\".\n\
602 Please consider the possibilities, and perhaps (re)start JACK."));
606 win.set_transient_for (*toplevel);
610 win.add_button (Stock::OK, RESPONSE_CLOSE);
612 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
615 win.set_default_response (RESPONSE_CLOSE);
618 win.set_position (Gtk::WIN_POS_CENTER);
621 /* we just don't care about the result, but we want to block */
627 ARDOUR_UI::startup ()
631 new_session_dialog = new NewSessionDialog();
633 bool backend_audio_is_running = EngineControl::engine_running();
634 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
637 new_session_dialog->engine_control.set_state (*audio_setup);
640 if (!get_session_parameters (backend_audio_is_running, ARDOUR_COMMAND_LINE::new_session)) {
644 BootMessage (_("Ardour is ready for use"));
649 ARDOUR_UI::no_memory_warning ()
651 XMLNode node (X_("no-memory-warning"));
652 Config->add_instant_xml (node, get_user_ardour_path());
656 ARDOUR_UI::check_memory_locking ()
659 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
663 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path());
665 if (engine->is_realtime() && memory_warning_node == 0) {
667 struct rlimit limits;
669 long pages, page_size;
671 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
674 ram = (int64_t) pages * (int64_t) page_size;
677 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
681 if (limits.rlim_cur != RLIM_INFINITY) {
683 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
686 MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. "
687 "This might cause Ardour to run out of memory before your system "
688 "runs out of memory. \n\n"
689 "You can view the memory limit with 'ulimit -l', "
690 "and it is normally controlled by /etc/security/limits.conf"));
692 VBox* vbox = msg.get_vbox();
694 CheckButton cb (_("Do not show this window again"));
696 cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning));
698 hbox.pack_start (cb, true, false);
699 vbox->pack_start (hbox);
717 if (session->transport_rolling()) {
718 session->request_stop ();
722 if (session->dirty()) {
723 switch (ask_about_saving_session(_("quit"))) {
728 /* use the default name */
729 if (save_state_canfail ("")) {
730 /* failed - don't quit */
731 MessageDialog msg (*editor,
733 Ardour was unable to save your session.\n\n\
734 If you still wish to quit, please use the\n\n\
735 \"Just quit\" option."));
746 session->set_deletion_in_progress ();
750 save_ardour_state ();
755 ARDOUR_UI::ask_about_saving_session (const string & what)
757 ArdourDialog window (_("ardour: save session?"));
758 Gtk::HBox dhbox; // the hbox for the image and text
759 Gtk::Label prompt_label;
760 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
764 msg = string_compose(_("Don't %1"), what);
765 window.add_button (msg, RESPONSE_REJECT);
766 msg = string_compose(_("Just %1"), what);
767 window.add_button (msg, RESPONSE_APPLY);
768 msg = string_compose(_("Save and %1"), what);
769 window.add_button (msg, RESPONSE_ACCEPT);
771 window.set_default_response (RESPONSE_ACCEPT);
773 Gtk::Button noquit_button (msg);
774 noquit_button.set_name ("EditorGTKButton");
779 if (session->snap_name() == session->name()) {
782 type = _("snapshot");
784 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?"),
785 type, session->snap_name());
787 prompt_label.set_text (prompt);
788 prompt_label.set_name (X_("PrompterLabel"));
789 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
791 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
793 dhbox.set_homogeneous (false);
794 dhbox.pack_start (*dimage, false, false, 5);
795 dhbox.pack_start (prompt_label, true, false, 5);
796 window.get_vbox()->pack_start (dhbox);
798 window.set_name (_("Prompter"));
799 window.set_position (Gtk::WIN_POS_MOUSE);
800 window.set_modal (true);
801 window.set_resizable (false);
804 window.set_keep_above (true);
807 ResponseType r = (ResponseType) window.run();
812 case RESPONSE_ACCEPT: // save and get out of here
814 case RESPONSE_APPLY: // get out of here
824 ARDOUR_UI::every_second ()
827 update_buffer_load ();
828 update_disk_space ();
833 ARDOUR_UI::every_point_one_seconds ()
835 update_speed_display ();
836 RapidScreenUpdate(); /* EMIT_SIGNAL */
841 ARDOUR_UI::every_point_zero_one_seconds ()
843 // august 2007: actual update frequency: 40Hz, not 100Hz
845 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
850 ARDOUR_UI::update_sample_rate (nframes_t ignored)
854 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
856 if (!engine->connected()) {
858 snprintf (buf, sizeof (buf), _("disconnected"));
862 nframes_t rate = engine->frame_rate();
864 if (fmod (rate, 1000.0) != 0.0) {
865 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
866 (float) rate/1000.0f,
867 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
869 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
871 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
875 sample_rate_label.set_text (buf);
879 ARDOUR_UI::update_cpu_load ()
882 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
883 cpu_load_label.set_text (buf);
887 ARDOUR_UI::update_buffer_load ()
892 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
893 session->playback_load(), session->capture_load());
894 buffer_load_label.set_text (buf);
896 buffer_load_label.set_text ("");
901 ARDOUR_UI::count_recenabled_streams (Route& route)
903 Track* track = dynamic_cast<Track*>(&route);
904 if (track && track->diskstream()->record_enabled()) {
905 rec_enabled_streams += track->n_inputs();
910 ARDOUR_UI::update_disk_space()
916 nframes_t frames = session->available_capture_duration();
919 if (frames == max_frames) {
920 strcpy (buf, _("Disk: 24hrs+"));
925 nframes_t fr = session->frame_rate();
927 rec_enabled_streams = 0;
928 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
930 if (rec_enabled_streams) {
931 frames /= rec_enabled_streams;
934 hrs = frames / (fr * 3600);
935 frames -= hrs * fr * 3600;
936 mins = frames / (fr * 60);
937 frames -= mins * fr * 60;
940 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
943 disk_space_label.set_text (buf);
947 ARDOUR_UI::update_wall_clock ()
954 tm_now = localtime (&now);
956 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
957 wall_clock_label.set_text (buf);
963 ARDOUR_UI::session_menu (GdkEventButton *ev)
965 session_popup_menu->popup (0, 0);
970 ARDOUR_UI::redisplay_recent_sessions ()
972 vector<string *> *sessions;
973 vector<string *>::iterator i;
974 RecentSessionsSorter cmp;
976 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
977 recent_session_model->clear ();
980 ARDOUR::read_recent_sessions (rs);
983 recent_session_display.set_model (recent_session_model);
987 /* sort them alphabetically */
988 sort (rs.begin(), rs.end(), cmp);
989 sessions = new vector<string*>;
991 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
992 sessions->push_back (new string ((*i).second));
995 for (i = sessions->begin(); i != sessions->end(); ++i) {
997 vector<string*>* states;
998 vector<const gchar*> item;
999 string fullpath = *(*i);
1001 /* remove any trailing / */
1003 if (fullpath[fullpath.length()-1] == '/') {
1004 fullpath = fullpath.substr (0, fullpath.length()-1);
1007 /* check whether session still exists */
1008 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1009 /* session doesn't exist */
1010 cerr << "skipping non-existent session " << fullpath << endl;
1014 /* now get available states for this session */
1016 if ((states = Session::possible_states (fullpath)) == 0) {
1017 /* no state file? */
1021 TreeModel::Row row = *(recent_session_model->append());
1023 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1024 row[recent_session_columns.fullpath] = fullpath;
1026 if (states->size() > 1) {
1028 /* add the children */
1030 for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
1032 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1034 child_row[recent_session_columns.visible_name] = **i2;
1035 child_row[recent_session_columns.fullpath] = fullpath;
1044 recent_session_display.set_model (recent_session_model);
1049 ARDOUR_UI::build_session_selector ()
1051 session_selector_window = new ArdourDialog ("session selector");
1053 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1055 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1056 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1057 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1058 recent_session_model = TreeStore::create (recent_session_columns);
1059 recent_session_display.set_model (recent_session_model);
1060 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1061 recent_session_display.set_headers_visible (false);
1062 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1063 recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1065 scroller->add (recent_session_display);
1066 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1068 session_selector_window->set_name ("SessionSelectorWindow");
1069 session_selector_window->set_size_request (200, 400);
1070 session_selector_window->get_vbox()->pack_start (*scroller);
1071 session_selector_window->show_all_children();
1075 ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
1077 session_selector_window->response (RESPONSE_ACCEPT);
1081 ARDOUR_UI::open_recent_session ()
1083 bool can_return = (session != 0);
1085 if (session_selector_window == 0) {
1086 build_session_selector ();
1089 redisplay_recent_sessions ();
1093 session_selector_window->set_position (WIN_POS_MOUSE);
1095 ResponseType r = (ResponseType) session_selector_window->run ();
1098 case RESPONSE_ACCEPT:
1102 session_selector_window->hide();
1109 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1113 session_selector_window->hide();
1115 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1117 if (i == recent_session_model->children().end()) {
1121 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1122 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1124 _session_is_new = false;
1126 if (load_session (path, state) == 0) {
1135 ARDOUR_UI::check_audioengine ()
1138 if (!engine->connected()) {
1139 MessageDialog msg (_("Ardour is not connected to JACK\n"
1140 "You cannot open or close sessions in this condition"));
1152 ARDOUR_UI::open_session ()
1154 if (!check_audioengine()) {
1158 /* popup selector window */
1160 if (open_session_selector == 0) {
1162 /* ardour sessions are folders */
1164 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
1165 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1166 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1167 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1169 FileFilter session_filter;
1170 session_filter.add_pattern ("*.ardour");
1171 session_filter.set_name (_("Ardour sessions"));
1172 open_session_selector->add_filter (session_filter);
1173 open_session_selector->set_filter (session_filter);
1176 int response = open_session_selector->run();
1177 open_session_selector->hide ();
1180 case RESPONSE_ACCEPT:
1183 open_session_selector->hide();
1187 open_session_selector->hide();
1188 string session_path = open_session_selector->get_filename();
1192 if (session_path.length() > 0) {
1193 if (Session::find_session (session_path, path, name, isnew) == 0) {
1194 _session_is_new = isnew;
1195 load_session (path, name);
1202 ARDOUR_UI::session_add_midi_track ()
1204 cerr << _("Patience is a virtue.\n");
1208 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
1210 list<boost::shared_ptr<AudioTrack> > tracks;
1211 Session::RouteList routes;
1214 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1220 tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
1222 if (tracks.size() != how_many) {
1223 if (how_many == 1) {
1224 error << _("could not create a new audio track") << endmsg;
1226 error << string_compose (_("could only create %1 of %2 new audio %3"),
1227 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1233 routes = session->new_audio_route (input_channels, output_channels, how_many);
1235 if (routes.size() != how_many) {
1236 if (how_many == 1) {
1237 error << _("could not create a new audio track") << endmsg;
1239 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1245 if (need_control_room_outs) {
1251 route->set_stereo_control_outs (control_lr_channels);
1252 route->control_outs()->set_stereo_pan (pans, this);
1254 #endif /* CONTROLOUTS */
1258 MessageDialog msg (*editor,
1259 _("There are insufficient JACK ports available\n\
1260 to create a new track or bus.\n\
1261 You should save Ardour, exit and\n\
1262 restart JACK with more ports."));
1269 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1271 nframes_t _preroll = 0;
1274 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1275 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1277 if (new_position > _preroll) {
1278 new_position -= _preroll;
1283 session->request_locate (new_position);
1288 ARDOUR_UI::transport_goto_start ()
1291 session->goto_start();
1294 /* force displayed area in editor to start no matter
1295 what "follow playhead" setting is.
1299 editor->reset_x_origin (session->current_start_frame());
1305 ARDOUR_UI::transport_goto_zero ()
1308 session->request_locate (0);
1311 /* force displayed area in editor to start no matter
1312 what "follow playhead" setting is.
1316 editor->reset_x_origin (0);
1322 ARDOUR_UI::transport_goto_wallclock ()
1324 if (session && editor) {
1331 localtime_r (&now, &tmnow);
1333 frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
1334 frames += tmnow.tm_min * (60 * session->frame_rate());
1335 frames += tmnow.tm_sec * session->frame_rate();
1337 session->request_locate (frames);
1339 /* force displayed area in editor to start no matter
1340 what "follow playhead" setting is.
1344 editor->reset_x_origin (frames - (editor->current_page_frames()/2));
1350 ARDOUR_UI::transport_goto_end ()
1353 nframes_t frame = session->current_end_frame();
1354 session->request_locate (frame);
1356 /* force displayed area in editor to start no matter
1357 what "follow playhead" setting is.
1361 editor->reset_x_origin (frame);
1367 ARDOUR_UI::transport_stop ()
1373 if (session->is_auditioning()) {
1374 session->cancel_audition ();
1378 if (session->get_play_loop ()) {
1379 session->request_play_loop (false);
1382 session->request_stop ();
1386 ARDOUR_UI::transport_stop_and_forget_capture ()
1389 session->request_stop (true);
1394 ARDOUR_UI::remove_last_capture()
1397 editor->remove_last_capture();
1402 ARDOUR_UI::transport_record (bool roll)
1406 switch (session->record_status()) {
1407 case Session::Disabled:
1408 if (session->ntracks() == 0) {
1409 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1413 session->maybe_enable_record ();
1418 case Session::Recording:
1420 session->request_stop();
1422 session->disable_record (false, true);
1426 case Session::Enabled:
1427 session->disable_record (false, true);
1430 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1434 ARDOUR_UI::transport_roll ()
1442 rolling = session->transport_rolling ();
1444 //cerr << "ARDOUR_UI::transport_roll () called session->record_status() = " << session->record_status() << endl;
1446 if (session->get_play_loop()) {
1447 session->request_play_loop (false);
1448 auto_loop_button.set_visual_state (1);
1449 roll_button.set_visual_state (1);
1450 } else if (session->get_play_range ()) {
1451 session->request_play_range (false);
1452 play_selection_button.set_visual_state (0);
1453 } else if (rolling) {
1454 session->request_locate (session->last_transport_start(), true);
1457 session->request_transport_speed (1.0f);
1461 ARDOUR_UI::transport_loop()
1464 if (session->get_play_loop()) {
1465 if (session->transport_rolling()) {
1466 Location * looploc = session->locations()->auto_loop_location();
1468 session->request_locate (looploc->start(), true);
1473 session->request_play_loop (true);
1479 ARDOUR_UI::transport_play_selection ()
1485 if (!session->get_play_range()) {
1486 session->request_stop ();
1489 editor->play_selection ();
1493 ARDOUR_UI::transport_rewind (int option)
1495 float current_transport_speed;
1498 current_transport_speed = session->transport_speed();
1500 if (current_transport_speed >= 0.0f) {
1503 session->request_transport_speed (-1.0f);
1506 session->request_transport_speed (-4.0f);
1509 session->request_transport_speed (-0.5f);
1514 session->request_transport_speed (current_transport_speed * 1.5f);
1520 ARDOUR_UI::transport_forward (int option)
1522 float current_transport_speed;
1525 current_transport_speed = session->transport_speed();
1527 if (current_transport_speed <= 0.0f) {
1530 session->request_transport_speed (1.0f);
1533 session->request_transport_speed (4.0f);
1536 session->request_transport_speed (0.5f);
1541 session->request_transport_speed (current_transport_speed * 1.5f);
1547 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1553 boost::shared_ptr<Route> r;
1555 if ((r = session->route_by_remote_id (dstream)) != 0) {
1559 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1560 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1569 ARDOUR_UI::queue_transport_change ()
1571 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1575 ARDOUR_UI::map_transport_state ()
1577 float sp = session->transport_speed();
1580 transport_rolling ();
1581 } else if (sp < 0.0f) {
1582 transport_rewinding ();
1583 } else if (sp > 0.0f) {
1584 transport_forwarding ();
1586 transport_stopped ();
1591 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1593 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1594 (int) adj.get_value()].c_str());
1598 ARDOUR_UI::engine_stopped ()
1600 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1601 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1602 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1606 ARDOUR_UI::engine_running ()
1608 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1609 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1610 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1612 Glib::RefPtr<Action> action;
1613 const char* action_name = 0;
1615 switch (engine->frames_per_cycle()) {
1617 action_name = X_("JACKLatency32");
1620 action_name = X_("JACKLatency64");
1623 action_name = X_("JACKLatency128");
1626 action_name = X_("JACKLatency512");
1629 action_name = X_("JACKLatency1024");
1632 action_name = X_("JACKLatency2048");
1635 action_name = X_("JACKLatency4096");
1638 action_name = X_("JACKLatency8192");
1641 /* XXX can we do anything useful ? */
1647 action = ActionManager::get_action (X_("JACK"), action_name);
1650 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1651 ract->set_active ();
1657 ARDOUR_UI::engine_halted ()
1659 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1661 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1662 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1664 update_sample_rate (0);
1666 MessageDialog msg (*editor,
1668 JACK has either been shutdown or it\n\
1669 disconnected Ardour because Ardour\n\
1670 was not fast enough. You can save the\n\
1671 session and/or try to reconnect to JACK ."));
1677 ARDOUR_UI::do_engine_start ()
1685 error << _("Unable to start the session running")
1695 ARDOUR_UI::setup_theme ()
1697 theme_manager->setup_theme();
1701 ARDOUR_UI::update_clocks ()
1703 if (!editor || !editor->dragging_playhead()) {
1704 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1709 ARDOUR_UI::start_clocking ()
1711 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1715 ARDOUR_UI::stop_clocking ()
1717 clock_signal_connection.disconnect ();
1721 ARDOUR_UI::toggle_clocking ()
1724 if (clock_button.get_active()) {
1733 ARDOUR_UI::_blink (void *arg)
1736 ((ARDOUR_UI *) arg)->blink ();
1743 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1747 ARDOUR_UI::start_blinking ()
1749 /* Start the blink signal. Everybody with a blinking widget
1750 uses Blink to drive the widget's state.
1753 if (blink_timeout_tag < 0) {
1755 blink_timeout_tag = g_timeout_add (240, _blink, this);
1760 ARDOUR_UI::stop_blinking ()
1762 if (blink_timeout_tag >= 0) {
1763 g_source_remove (blink_timeout_tag);
1764 blink_timeout_tag = -1;
1769 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1775 if (io.n_inputs() == 0) {
1780 /* XXX we're not handling multiple ports yet. */
1782 const char **connections = io.input(0)->get_connections();
1784 if (connections == 0 || connections[0] == '\0') {
1787 buf = connections[0];
1794 if (io.n_outputs() == 0) {
1799 /* XXX we're not handling multiple ports yet. */
1801 const char **connections = io.output(0)->get_connections();
1803 if (connections == 0 || connections[0] == '\0') {
1806 buf = connections[0];
1813 /** Ask the user for the name of a new shapshot and then take it.
1816 ARDOUR_UI::snapshot_session ()
1818 ArdourPrompter prompter (true);
1822 struct tm local_time;
1825 localtime_r (&n, &local_time);
1826 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1828 prompter.set_name ("Prompter");
1829 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1830 prompter.set_prompt (_("Name of New Snapshot"));
1831 prompter.set_initial_text (timebuf);
1833 switch (prompter.run()) {
1834 case RESPONSE_ACCEPT:
1835 prompter.get_result (snapname);
1836 if (snapname.length()){
1837 save_state (snapname);
1847 ARDOUR_UI::save_state (const string & name)
1849 (void) save_state_canfail (name);
1853 ARDOUR_UI::save_state_canfail (string name)
1858 if (name.length() == 0) {
1859 name = session->snap_name();
1862 if ((ret = session->save_state (name)) != 0) {
1866 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1871 ARDOUR_UI::primary_clock_value_changed ()
1874 session->request_locate (primary_clock.current_time ());
1879 ARDOUR_UI::big_clock_value_changed ()
1882 session->request_locate (big_clock.current_time ());
1887 ARDOUR_UI::secondary_clock_value_changed ()
1890 session->request_locate (secondary_clock.current_time ());
1895 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
1901 switch (session->record_status()) {
1902 case Session::Enabled:
1904 rec_button.set_visual_state (2);
1906 rec_button.set_visual_state (0);
1910 case Session::Recording:
1911 rec_button.set_visual_state (1);
1915 rec_button.set_visual_state (0);
1921 ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
1929 ARDOUR_UI::save_template ()
1932 ArdourPrompter prompter (true);
1935 if (!check_audioengine()) {
1939 prompter.set_name (X_("Prompter"));
1940 prompter.set_prompt (_("Name for mix template:"));
1941 prompter.set_initial_text(session->name() + _("-template"));
1942 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1944 switch (prompter.run()) {
1945 case RESPONSE_ACCEPT:
1946 prompter.get_result (name);
1948 if (name.length()) {
1949 session->save_template (name);
1959 ARDOUR_UI::fontconfig_dialog ()
1962 /* X11 users will always have fontconfig info around, but new GTK-OSX users
1963 may not and it can take a while to build it. Warn them.
1966 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
1968 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
1969 MessageDialog msg (*new_session_dialog,
1970 _("Welcome to Ardour.\n\n"
1971 "The program will take a bit longer to start up\n"
1972 "while the system fonts are checked.\n\n"
1973 "This will only be done once, and you will\n"
1974 "not see this message again\n"),
1987 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
1989 existing_session = false;
1991 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
1992 session_path = cmdline_path;
1993 existing_session = true;
1994 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
1995 session_path = Glib::path_get_dirname (string (cmdline_path));
1996 existing_session = true;
1998 /* it doesn't exist, assume the best */
1999 session_path = Glib::path_get_dirname (string (cmdline_path));
2002 session_name = basename_nosuffix (string (cmdline_path));
2006 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2008 /* when this is called, the backend audio system must be running */
2010 /* the main idea here is to deal with the fact that a cmdline argument for the session
2011 can be interpreted in different ways - it could be a directory or a file, and before
2012 we load, we need to know both the session directory and the snapshot (statefile) within it
2013 that we are supposed to use.
2016 if (session_name.length() == 0 || session_path.length() == 0) {
2020 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2022 Glib::ustring predicted_session_file;
2024 predicted_session_file = session_path;
2025 predicted_session_file += '/';
2026 predicted_session_file += session_name;
2027 predicted_session_file += Session::statefile_suffix();
2029 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2030 existing_session = true;
2033 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2035 if (session_path.find (Session::statefile_suffix()) == session_path.length() - 7) {
2036 /* existing .ardour file */
2037 existing_session = true;
2041 existing_session = false;
2044 /* lets just try to load it */
2046 if (create_engine ()) {
2047 backend_audio_error (false, new_session_dialog);
2051 return load_session (session_path, session_name);
2055 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2057 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2059 MessageDialog msg (str,
2061 Gtk::MESSAGE_WARNING,
2062 Gtk::BUTTONS_YES_NO,
2066 msg.set_name (X_("CleanupDialog"));
2067 msg.set_wmclass (X_("existing_session"), "Ardour");
2068 msg.set_position (Gtk::WIN_POS_MOUSE);
2071 switch (msg.run()) {
2080 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2085 AutoConnectOption iconnect;
2086 AutoConnectOption oconnect;
2090 if (Profile->get_sae()) {
2094 iconnect = AutoConnectPhysical;
2095 oconnect = AutoConnectMaster;
2096 nphysin = 0; // use all available
2097 nphysout = 0; // use all available
2101 /* get settings from advanced section of NSD */
2103 if (new_session_dialog->create_control_bus()) {
2104 cchns = (uint32_t) new_session_dialog->control_channel_count();
2109 if (new_session_dialog->create_master_bus()) {
2110 mchns = (uint32_t) new_session_dialog->master_channel_count();
2115 if (new_session_dialog->connect_inputs()) {
2116 iconnect = AutoConnectPhysical;
2118 iconnect = AutoConnectOption (0);
2121 /// @todo some minor tweaks.
2123 if (new_session_dialog->connect_outs_to_master()) {
2124 oconnect = AutoConnectMaster;
2125 } else if (new_session_dialog->connect_outs_to_physical()) {
2126 oconnect = AutoConnectPhysical;
2128 oconnect = AutoConnectOption (0);
2131 nphysin = (uint32_t) new_session_dialog->input_limit_count();
2132 nphysout = (uint32_t) new_session_dialog->output_limit_count();
2135 if (build_session (session_path,
2143 engine->frame_rate() * 60 * 5)) {
2152 ARDOUR_UI::end_loading_messages ()
2158 ARDOUR_UI::loading_message (const std::string& msg)
2161 splash->message (msg);
2166 ARDOUR_UI::idle_load (const Glib::ustring& path)
2169 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2170 /* /path/to/foo => /path/to/foo, foo */
2171 load_session (path, basename_nosuffix (path));
2173 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2174 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2177 ARDOUR_COMMAND_LINE::session_name = path;
2178 if (new_session_dialog) {
2179 /* make it break out of Dialog::run() and
2182 new_session_dialog->response (1);
2188 ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
2190 bool existing_session = false;
2191 Glib::ustring session_name;
2192 Glib::ustring session_path;
2193 Glib::ustring template_name;
2197 response = Gtk::RESPONSE_NONE;
2199 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2201 parse_cmdline_path (ARDOUR_COMMAND_LINE::session_name, session_name, session_path, existing_session);
2203 /* don't ever reuse this */
2205 ARDOUR_COMMAND_LINE::session_name = string();
2207 if (existing_session && backend_audio_is_running) {
2209 /* just load the thing already */
2211 if (load_cmdline_session (session_name, session_path, existing_session) == 0) {
2216 /* make the NSD use whatever information we have */
2218 new_session_dialog->set_session_name (session_name);
2219 new_session_dialog->set_session_folder (session_path);
2222 /* loading failed, or we need the NSD for something */
2224 new_session_dialog->set_modal (false);
2225 new_session_dialog->set_position (WIN_POS_CENTER);
2226 new_session_dialog->set_current_page (0);
2227 new_session_dialog->set_existing_session (existing_session);
2228 new_session_dialog->reset_recent();
2231 new_session_dialog->set_have_engine (backend_audio_is_running);
2232 new_session_dialog->present ();
2233 response = new_session_dialog->run ();
2235 _session_is_new = false;
2237 /* handle possible negative responses */
2241 /* sent by idle_load, meaning restart the whole process again */
2242 new_session_dialog->hide();
2243 new_session_dialog->reset();
2247 case Gtk::RESPONSE_CANCEL:
2248 case Gtk::RESPONSE_DELETE_EVENT:
2252 new_session_dialog->hide ();
2255 case Gtk::RESPONSE_NONE:
2256 /* "Clear" was pressed */
2260 fontconfig_dialog();
2262 if (!backend_audio_is_running) {
2263 int ret = new_session_dialog->engine_control.setup_engine ();
2266 } else if (ret > 0) {
2267 response = Gtk::RESPONSE_REJECT;
2272 if (create_engine ()) {
2274 backend_audio_error (!backend_audio_is_running, new_session_dialog);
2277 new_session_dialog->set_existing_session (false);
2278 new_session_dialog->set_current_page (2);
2280 response = Gtk::RESPONSE_NONE;
2284 backend_audio_is_running = true;
2286 if (response == Gtk::RESPONSE_OK) {
2288 session_name = new_session_dialog->session_name();
2290 if (session_name.empty()) {
2291 response = Gtk::RESPONSE_NONE;
2295 /* if the user mistakenly typed path information into the session filename entry,
2296 convert what they typed into a path & a name
2299 if (session_name[0] == '/' ||
2300 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2301 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2303 session_path = Glib::path_get_dirname (session_name);
2304 session_name = Glib::path_get_basename (session_name);
2308 session_path = new_session_dialog->session_folder();
2311 template_name = Glib::ustring();
2312 switch (new_session_dialog->which_page()) {
2314 case NewSessionDialog::OpenPage:
2315 case NewSessionDialog::EnginePage:
2319 case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
2321 should_be_new = true;
2323 //XXX This is needed because session constructor wants a
2324 //non-existant path. hopefully this will be fixed at some point.
2326 session_path = Glib::build_filename (session_path, session_name);
2328 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2330 if (ask_about_loading_existing_session (session_path)) {
2333 response = RESPONSE_NONE;
2338 _session_is_new = true;
2340 if (new_session_dialog->use_session_template()) {
2342 template_name = new_session_dialog->session_template_name();
2346 if (build_session_from_nsd (session_path, session_name)) {
2347 response = RESPONSE_NONE;
2359 new_session_dialog->hide ();
2361 if (load_session (session_path, session_name, template_name)) {
2363 response = Gtk::RESPONSE_NONE;
2367 if (response == Gtk::RESPONSE_NONE) {
2368 new_session_dialog->set_existing_session (false);
2369 new_session_dialog->reset ();
2373 } while (response == Gtk::RESPONSE_NONE || response == Gtk::RESPONSE_REJECT);
2377 new_session_dialog->hide();
2378 new_session_dialog->reset();
2379 goto_editor_window ();
2384 ARDOUR_UI::close_session ()
2386 if (!check_audioengine()) {
2390 unload_session (true);
2392 get_session_parameters (true, false);
2396 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2398 Session *new_session;
2402 session_loaded = false;
2404 if (!check_audioengine()) {
2408 unload_status = unload_session ();
2410 if (unload_status < 0) {
2412 } else if (unload_status > 0) {
2417 /* if it already exists, we must have write access */
2419 if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) {
2420 MessageDialog msg (*editor, _("You do not have write access to this session.\n"
2421 "This prevents the session from being loaded."));
2427 loading_message (_("Please wait while Ardour loads your session"));
2430 new_session = new Session (*engine, path, snap_name, mix_template);
2433 /* this one is special */
2435 catch (AudioEngine::PortRegistrationFailure& err) {
2437 MessageDialog msg (err.what(),
2440 Gtk::BUTTONS_OK_CANCEL);
2442 msg.set_title (_("Loading Error"));
2443 msg.set_secondary_text (_("Click the OK button to try again."));
2444 msg.set_position (Gtk::WIN_POS_CENTER);
2448 int response = msg.run ();
2453 case RESPONSE_CANCEL:
2463 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2466 Gtk::BUTTONS_OK_CANCEL);
2468 msg.set_title (_("Loading Error"));
2469 msg.set_secondary_text (_("Click the OK button to try again."));
2470 msg.set_position (Gtk::WIN_POS_CENTER);
2474 int response = msg.run ();
2479 case RESPONSE_CANCEL:
2487 connect_to_session (new_session);
2489 Config->set_current_owner (ConfigVariableBase::Interface);
2491 session_loaded = true;
2493 goto_editor_window ();
2496 session->set_clean ();
2507 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2508 uint32_t control_channels,
2509 uint32_t master_channels,
2510 AutoConnectOption input_connect,
2511 AutoConnectOption output_connect,
2514 nframes_t initial_length)
2516 Session *new_session;
2519 if (!check_audioengine()) {
2523 session_loaded = false;
2525 x = unload_session ();
2533 _session_is_new = true;
2536 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2537 control_channels, master_channels, nphysin, nphysout, initial_length);
2542 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2548 connect_to_session (new_session);
2550 session_loaded = true;
2558 editor->show_window ();
2569 ARDOUR_UI::show_about ()
2573 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2580 ARDOUR_UI::hide_about ()
2583 about->get_window()->set_cursor ();
2589 ARDOUR_UI::about_signal_response(int response)
2595 ARDOUR_UI::show_splash ()
2599 splash = new Splash;
2607 splash->queue_draw ();
2608 splash->get_window()->process_updates (true);
2613 ARDOUR_UI::hide_splash ()
2621 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
2625 removed = rep.paths.size();
2628 MessageDialog msgd (*editor,
2629 _("No audio files were ready for cleanup"),
2632 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2633 msgd.set_secondary_text (_("If this seems suprising, \n\
2634 check for any existing snapshots.\n\
2635 These may still include regions that\n\
2636 require some unused files to continue to exist."));
2642 ArdourDialog results (_("ardour: cleanup"), true, false);
2644 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2645 CleanupResultsModelColumns() {
2649 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2650 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2654 CleanupResultsModelColumns results_columns;
2655 Glib::RefPtr<Gtk::ListStore> results_model;
2656 Gtk::TreeView results_display;
2658 results_model = ListStore::create (results_columns);
2659 results_display.set_model (results_model);
2660 results_display.append_column (list_title, results_columns.visible_name);
2662 results_display.set_name ("CleanupResultsList");
2663 results_display.set_headers_visible (true);
2664 results_display.set_headers_clickable (false);
2665 results_display.set_reorderable (false);
2667 Gtk::ScrolledWindow list_scroller;
2670 Gtk::HBox dhbox; // the hbox for the image and text
2671 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2672 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2674 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2676 if (rep.space < 1048576.0f) {
2678 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2680 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2684 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2686 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2690 dhbox.pack_start (*dimage, true, false, 5);
2691 dhbox.pack_start (txt, true, false, 5);
2693 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2694 TreeModel::Row row = *(results_model->append());
2695 row[results_columns.visible_name] = *i;
2696 row[results_columns.fullpath] = *i;
2699 list_scroller.add (results_display);
2700 list_scroller.set_size_request (-1, 150);
2701 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2703 dvbox.pack_start (dhbox, true, false, 5);
2704 dvbox.pack_start (list_scroller, true, false, 5);
2705 ddhbox.pack_start (dvbox, true, false, 5);
2707 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2708 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2709 results.set_default_response (RESPONSE_CLOSE);
2710 results.set_position (Gtk::WIN_POS_MOUSE);
2711 results.show_all_children ();
2712 results.set_resizable (false);
2719 ARDOUR_UI::cleanup ()
2722 /* shouldn't happen: menu item is insensitive */
2727 MessageDialog checker (_("Are you sure you want to cleanup?"),
2729 Gtk::MESSAGE_QUESTION,
2730 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2732 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2733 ALL undo/redo information will be lost if you cleanup.\n\
2734 After cleanup, unused audio files will be moved to a \
2735 \"dead sounds\" location."));
2737 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2738 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2739 checker.set_default_response (RESPONSE_CANCEL);
2741 checker.set_name (_("CleanupDialog"));
2742 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2743 checker.set_position (Gtk::WIN_POS_MOUSE);
2745 switch (checker.run()) {
2746 case RESPONSE_ACCEPT:
2752 Session::cleanup_report rep;
2754 editor->prepare_for_cleanup ();
2756 /* do not allow flush until a session is reloaded */
2758 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2760 act->set_sensitive (false);
2763 if (session->cleanup_sources (rep)) {
2764 editor->finish_cleanup ();
2768 editor->finish_cleanup ();
2771 display_cleanup_results (rep,
2774 The following %1 %2 not in use and \n\
2775 have been moved to:\n\
2777 Flushing the wastebasket will \n\
2778 release an additional\n\
2779 %4 %5bytes of disk space.\n"
2785 ARDOUR_UI::flush_trash ()
2788 /* shouldn't happen: menu item is insensitive */
2792 Session::cleanup_report rep;
2794 if (session->cleanup_trash_sources (rep)) {
2798 display_cleanup_results (rep,
2800 _("The following %1 %2 deleted from\n\
2802 releasing %4 %5bytes of disk space"));
2806 ARDOUR_UI::add_route (Gtk::Window* float_window)
2814 if (add_route_dialog == 0) {
2815 add_route_dialog = new AddRouteDialog;
2817 add_route_dialog->set_transient_for (*float_window);
2821 if (add_route_dialog->is_visible()) {
2822 /* we're already doing this */
2826 ResponseType r = (ResponseType) add_route_dialog->run ();
2828 add_route_dialog->hide();
2831 case RESPONSE_ACCEPT:
2838 if ((count = add_route_dialog->count()) <= 0) {
2842 uint32_t input_chan = add_route_dialog->channels ();
2843 uint32_t output_chan;
2844 string name_template = add_route_dialog->name_template ();
2845 bool track = add_route_dialog->track ();
2847 AutoConnectOption oac = Config->get_output_auto_connect();
2849 if (oac & AutoConnectMaster) {
2850 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2852 output_chan = input_chan;
2855 /* XXX do something with name template */
2857 cerr << "Adding with " << input_chan << " in and " << output_chan << "out\n";
2860 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
2862 session_add_audio_bus (input_chan, output_chan, count);
2867 ARDOUR_UI::mixer_settings () const
2872 node = session->instant_xml(X_("Mixer"), session->path());
2874 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
2878 node = new XMLNode (X_("Mixer"));
2885 ARDOUR_UI::editor_settings () const
2890 node = session->instant_xml(X_("Editor"), session->path());
2892 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
2896 node = new XMLNode (X_("Editor"));
2902 ARDOUR_UI::keyboard_settings () const
2906 node = Config->extra_xml(X_("Keyboard"));
2909 node = new XMLNode (X_("Keyboard"));
2915 ARDOUR_UI::create_xrun_marker(nframes_t where)
2917 editor->mouse_add_new_marker (where, false, true);
2921 ARDOUR_UI::halt_on_xrun_message ()
2923 MessageDialog msg (*editor,
2924 _("Recording was stopped because your system could not keep up."));
2929 ARDOUR_UI::xrun_handler(nframes_t where)
2931 ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::xrun_handler), where));
2933 if (Config->get_create_xrun_marker() && session->actively_recording()) {
2934 create_xrun_marker(where);
2937 if (Config->get_stop_recording_on_xrun() && session->actively_recording()) {
2938 halt_on_xrun_message ();
2943 ARDOUR_UI::disk_overrun_handler ()
2945 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
2947 if (!have_disk_speed_dialog_displayed) {
2948 have_disk_speed_dialog_displayed = true;
2949 MessageDialog* msg = new MessageDialog (*editor, _("\
2950 The disk system on your computer\n\
2951 was not able to keep up with Ardour.\n\
2953 Specifically, it failed to write data to disk\n\
2954 quickly enough to keep up with recording.\n"));
2955 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
2961 ARDOUR_UI::disk_underrun_handler ()
2963 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2965 if (!have_disk_speed_dialog_displayed) {
2966 have_disk_speed_dialog_displayed = true;
2967 MessageDialog* msg = new MessageDialog (*editor,
2968 _("The disk system on your computer\n\
2969 was not able to keep up with Ardour.\n\
2971 Specifically, it failed to read data from disk\n\
2972 quickly enough to keep up with playback.\n"));
2973 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
2979 ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
2981 have_disk_speed_dialog_displayed = false;
2986 ARDOUR_UI::session_dialog (std::string msg)
2988 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
2993 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
2995 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3004 ARDOUR_UI::pending_state_dialog ()
3006 HBox* hbox = new HBox();
3007 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3008 ArdourDialog dialog (_("Crash Recovery"), true);
3010 This session appears to have been in\n\
3011 middle of recording when ardour or\n\
3012 the computer was shutdown.\n\
3014 Ardour can recover any captured audio for\n\
3015 you, or it can ignore it. Please decide\n\
3016 what you would like to do.\n"));
3017 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3018 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3019 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3020 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3021 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3022 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3023 dialog.set_default_response (RESPONSE_ACCEPT);
3024 dialog.set_position (WIN_POS_CENTER);
3029 switch (dialog.run ()) {
3030 case RESPONSE_ACCEPT:
3038 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3040 HBox* hbox = new HBox();
3041 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3042 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3043 Label message (string_compose (_("\
3044 This session was created with a sample rate of %1 Hz\n\
3046 The audioengine is currently running at %2 Hz\n"), desired, actual));
3048 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3049 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3050 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3051 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3052 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3053 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3054 dialog.set_default_response (RESPONSE_ACCEPT);
3055 dialog.set_position (WIN_POS_CENTER);
3060 switch (dialog.run ()) {
3061 case RESPONSE_ACCEPT:
3070 ARDOUR_UI::disconnect_from_jack ()
3073 if( engine->disconnect_from_jack ()) {
3074 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3078 update_sample_rate (0);
3083 ARDOUR_UI::reconnect_to_jack ()
3086 if (engine->reconnect_to_jack ()) {
3087 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3091 update_sample_rate (0);
3096 ARDOUR_UI::use_config ()
3098 Glib::RefPtr<Action> act;
3100 switch (Config->get_native_file_data_format ()) {
3102 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
3105 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
3108 act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit"));
3113 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3114 ract->set_active ();
3117 switch (Config->get_native_file_header_format ()) {
3119 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
3122 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
3125 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
3128 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
3131 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
3134 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
3137 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
3142 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3143 ract->set_active ();
3146 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3148 set_transport_controllable_state (*node);
3153 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3155 if (Config->get_primary_clock_delta_edit_cursor()) {
3156 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3158 primary_clock.set (pos, 0, true);
3161 if (Config->get_secondary_clock_delta_edit_cursor()) {
3162 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3164 secondary_clock.set (pos);
3167 if (big_clock_window) {
3168 big_clock.set (pos);
3173 ARDOUR_UI::record_state_changed ()
3175 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3177 if (!session || !big_clock_window) {
3178 /* why bother - the clock isn't visible */
3182 switch (session->record_status()) {
3183 case Session::Recording:
3184 big_clock.set_widget_name ("BigClockRecording");
3187 big_clock.set_widget_name ("BigClockNonRecording");
3193 ARDOUR_UI::first_idle ()
3196 session->allow_auto_play (true);
3200 editor->first_idle();
3203 Keyboard::set_can_save_keybindings (true);
3208 ARDOUR_UI::store_clock_modes ()
3210 XMLNode* node = new XMLNode(X_("ClockModes"));
3212 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3213 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3216 session->add_extra_xml (*node);
3217 session->set_dirty ();
3222 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3223 : Controllable (name), ui (u), type(tp)
3229 ARDOUR_UI::TransportControllable::set_value (float val)
3231 if (type == ShuttleControl) {
3238 fract = -((0.5f - val)/0.5f);
3240 fract = ((val - 0.5f)/0.5f);
3244 ui.set_shuttle_fract (fract);
3249 /* do nothing: these are radio-style actions */
3253 const char *action = 0;
3257 action = X_("Roll");
3260 action = X_("Stop");
3263 action = X_("Goto Start");
3266 action = X_("Goto End");
3269 action = X_("Loop");
3272 action = X_("Play Selection");
3275 action = X_("Record");
3285 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3293 ARDOUR_UI::TransportControllable::get_value (void) const
3312 case ShuttleControl:
3322 ARDOUR_UI::TransportControllable::set_id (const string& str)
3328 ARDOUR_UI::setup_profile ()
3330 if (gdk_screen_width() < 1200) {
3331 Profile->set_small_screen ();
3334 if (getenv ("ARDOUR_SAE")) {
3335 Profile->set_sae ();
3336 Profile->set_single_package ();