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;
202 _mixer_on_top = false;
204 last_configure_time= 0;
206 shuttle_grabbed = false;
208 shuttle_max_speed = 8.0f;
210 shuttle_style_menu = 0;
211 shuttle_unit_menu = 0;
213 // We do not have jack linked in yet so;
215 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
217 ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
218 ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
220 /* handle dialog requests */
222 ARDOUR::Session::Dialog.connect (mem_fun(*this, &ARDOUR_UI::session_dialog));
224 /* handle pending state with a dialog */
226 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
228 /* handle sr mismatch with a dialog */
230 ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
232 /* lets get this party started */
235 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
236 throw failed_constructor ();
239 setup_gtk_ardour_enums ();
240 Config->set_current_owner (ConfigVariableBase::Interface);
243 GainMeter::setup_slider_pix ();
244 RouteTimeAxisView::setup_slider_pix ();
246 } catch (failed_constructor& err) {
247 error << _("could not initialize Ardour.") << endmsg;
252 /* we like keyboards */
254 keyboard = new Keyboard;
258 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
259 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
265 ARDOUR_UI::create_engine ()
267 // this gets called every time by new_session()
273 loading_message (_("Starting audio engine"));
276 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
283 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
284 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
285 engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
286 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
294 ARDOUR_UI::post_engine ()
296 /* Things to be done once we create the AudioEngine
299 check_memory_locking();
301 ActionManager::init ();
304 if (setup_windows ()) {
305 throw failed_constructor ();
308 /* this is the first point at which all the keybindings are available */
310 if (ARDOUR_COMMAND_LINE::show_key_actions) {
311 vector<string> names;
312 vector<string> paths;
314 vector<AccelKey> bindings;
316 ActionManager::get_all_actions (names, paths, keys, bindings);
318 vector<string>::iterator n;
319 vector<string>::iterator k;
320 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
321 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
327 blink_timeout_tag = -1;
329 /* the global configuration object is now valid */
333 /* this being a GUI and all, we want peakfiles */
335 AudioFileSource::set_build_peakfiles (true);
336 AudioFileSource::set_build_missing_peakfiles (true);
338 /* set default clock modes */
340 if (Profile->get_sae()) {
341 primary_clock.set_mode (AudioClock::MinSec);
343 primary_clock.set_mode (AudioClock::SMPTE);
345 secondary_clock.set_mode (AudioClock::BBT);
347 /* start the time-of-day-clock */
350 /* OS X provides an always visible wallclock, so don't be stupid */
351 update_wall_clock ();
352 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
355 update_disk_space ();
357 update_sample_rate (engine->frame_rate());
359 platform_specific ();
361 /* now start and maybe save state */
363 if (do_engine_start () == 0) {
364 if (session && _session_is_new) {
365 /* we need to retain initial visual
366 settings for a new session
368 session->save_state ("");
373 ARDOUR_UI::~ARDOUR_UI ()
375 save_ardour_state ();
389 if (add_route_dialog) {
390 delete add_route_dialog;
393 if (new_session_dialog) {
394 delete new_session_dialog;
399 ARDOUR_UI::pop_back_splash ()
401 if (Splash::instance()) {
402 // Splash::instance()->pop_back();
403 Splash::instance()->hide ();
408 ARDOUR_UI::configure_timeout ()
410 if (last_configure_time == 0) {
411 /* no configure events yet */
415 /* force a gap of 0.5 seconds since the last configure event
418 if (get_microseconds() - last_configure_time < 500000) {
421 have_configure_timeout = false;
422 save_ardour_state ();
428 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
430 if (have_configure_timeout) {
431 last_configure_time = get_microseconds();
433 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
434 have_configure_timeout = true;
441 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
443 const XMLProperty* prop;
445 if ((prop = node.property ("roll")) != 0) {
446 roll_controllable.set_id (prop->value());
448 if ((prop = node.property ("stop")) != 0) {
449 stop_controllable.set_id (prop->value());
451 if ((prop = node.property ("goto_start")) != 0) {
452 goto_start_controllable.set_id (prop->value());
454 if ((prop = node.property ("goto_end")) != 0) {
455 goto_end_controllable.set_id (prop->value());
457 if ((prop = node.property ("auto_loop")) != 0) {
458 auto_loop_controllable.set_id (prop->value());
460 if ((prop = node.property ("play_selection")) != 0) {
461 play_selection_controllable.set_id (prop->value());
463 if ((prop = node.property ("rec")) != 0) {
464 rec_controllable.set_id (prop->value());
466 if ((prop = node.property ("shuttle")) != 0) {
467 shuttle_controllable.set_id (prop->value());
472 ARDOUR_UI::get_transport_controllable_state ()
474 XMLNode* node = new XMLNode(X_("TransportControllables"));
477 roll_controllable.id().print (buf, sizeof (buf));
478 node->add_property (X_("roll"), buf);
479 stop_controllable.id().print (buf, sizeof (buf));
480 node->add_property (X_("stop"), buf);
481 goto_start_controllable.id().print (buf, sizeof (buf));
482 node->add_property (X_("goto_start"), buf);
483 goto_end_controllable.id().print (buf, sizeof (buf));
484 node->add_property (X_("goto_end"), buf);
485 auto_loop_controllable.id().print (buf, sizeof (buf));
486 node->add_property (X_("auto_loop"), buf);
487 play_selection_controllable.id().print (buf, sizeof (buf));
488 node->add_property (X_("play_selection"), buf);
489 rec_controllable.id().print (buf, sizeof (buf));
490 node->add_property (X_("rec"), buf);
491 shuttle_controllable.id().print (buf, sizeof (buf));
492 node->add_property (X_("shuttle"), buf);
498 ARDOUR_UI::save_ardour_state ()
500 if (!keyboard || !mixer || !editor) {
504 /* XXX this is all a bit dubious. add_extra_xml() uses
505 a different lifetime model from add_instant_xml().
508 XMLNode* node = new XMLNode (keyboard->get_state());
509 Config->add_extra_xml (*node);
510 Config->add_extra_xml (get_transport_controllable_state());
511 if (new_session_dialog) {
512 if (new_session_dialog->engine_control.was_used()) {
513 Config->add_extra_xml (new_session_dialog->engine_control.get_state());
516 Config->save_state();
517 ui_config->save_state ();
519 XMLNode enode(static_cast<Stateful*>(editor)->get_state());
520 XMLNode mnode(mixer->get_state());
523 session->add_instant_xml (enode, session->path());
524 session->add_instant_xml (mnode, session->path());
526 Config->add_instant_xml (enode, get_user_ardour_path());
527 Config->add_instant_xml (mnode, get_user_ardour_path());
530 Keyboard::save_keybindings ();
534 ARDOUR_UI::autosave_session ()
536 if (g_main_depth() > 1) {
537 /* inside a recursive main loop,
538 give up because we may not be able to
544 if (!Config->get_periodic_safety_backups())
548 session->maybe_write_autosave();
555 ARDOUR_UI::update_autosave ()
557 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
559 if (session->dirty()) {
560 if (_autosave_connection.connected()) {
561 _autosave_connection.disconnect();
564 _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
565 Config->get_periodic_safety_backup_interval() * 1000);
568 if (_autosave_connection.connected()) {
569 _autosave_connection.disconnect();
575 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
579 title = _("Ardour could not start JACK");
581 title = _("Ardour could not connect to JACK.");
584 MessageDialog win (title,
590 win.set_secondary_text(_("There are several possible reasons:\n\
592 1) You requested audio parameters that are not supported..\n\
593 2) JACK is running as another user.\n\
595 Please consider the possibilities, and perhaps try different parameters."));
597 win.set_secondary_text(_("There are several possible reasons:\n\
599 1) JACK is not running.\n\
600 2) JACK is running as another user, perhaps root.\n\
601 3) There is already another client called \"ardour\".\n\
603 Please consider the possibilities, and perhaps (re)start JACK."));
607 win.set_transient_for (*toplevel);
611 win.add_button (Stock::OK, RESPONSE_CLOSE);
613 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
616 win.set_default_response (RESPONSE_CLOSE);
619 win.set_position (Gtk::WIN_POS_CENTER);
622 /* we just don't care about the result, but we want to block */
628 ARDOUR_UI::startup ()
632 new_session_dialog = new NewSessionDialog();
634 bool backend_audio_is_running = EngineControl::engine_running();
635 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
638 new_session_dialog->engine_control.set_state (*audio_setup);
641 if (!get_session_parameters (backend_audio_is_running, ARDOUR_COMMAND_LINE::new_session)) {
645 BootMessage (_("Ardour is ready for use"));
650 ARDOUR_UI::no_memory_warning ()
652 XMLNode node (X_("no-memory-warning"));
653 Config->add_instant_xml (node, get_user_ardour_path());
657 ARDOUR_UI::check_memory_locking ()
660 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
664 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path());
666 if (engine->is_realtime() && memory_warning_node == 0) {
668 struct rlimit limits;
670 long pages, page_size;
672 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
675 ram = (int64_t) pages * (int64_t) page_size;
678 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
682 if (limits.rlim_cur != RLIM_INFINITY) {
684 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
687 MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. "
688 "This might cause Ardour to run out of memory before your system "
689 "runs out of memory. \n\n"
690 "You can view the memory limit with 'ulimit -l', "
691 "and it is normally controlled by /etc/security/limits.conf"));
693 VBox* vbox = msg.get_vbox();
695 CheckButton cb (_("Do not show this window again"));
697 cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning));
699 hbox.pack_start (cb, true, false);
700 vbox->pack_start (hbox);
718 if (session->transport_rolling()) {
719 session->request_stop ();
723 if (session->dirty()) {
724 switch (ask_about_saving_session(_("quit"))) {
729 /* use the default name */
730 if (save_state_canfail ("")) {
731 /* failed - don't quit */
732 MessageDialog msg (*editor,
734 Ardour was unable to save your session.\n\n\
735 If you still wish to quit, please use the\n\n\
736 \"Just quit\" option."));
747 session->set_deletion_in_progress ();
750 ArdourDialog::close_all_dialogs ();
752 save_ardour_state ();
757 ARDOUR_UI::ask_about_saving_session (const string & what)
759 ArdourDialog window (_("ardour: save session?"));
760 Gtk::HBox dhbox; // the hbox for the image and text
761 Gtk::Label prompt_label;
762 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
766 msg = string_compose(_("Don't %1"), what);
767 window.add_button (msg, RESPONSE_REJECT);
768 msg = string_compose(_("Just %1"), what);
769 window.add_button (msg, RESPONSE_APPLY);
770 msg = string_compose(_("Save and %1"), what);
771 window.add_button (msg, RESPONSE_ACCEPT);
773 window.set_default_response (RESPONSE_ACCEPT);
775 Gtk::Button noquit_button (msg);
776 noquit_button.set_name ("EditorGTKButton");
781 if (session->snap_name() == session->name()) {
784 type = _("snapshot");
786 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?"),
787 type, session->snap_name());
789 prompt_label.set_text (prompt);
790 prompt_label.set_name (X_("PrompterLabel"));
791 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
793 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
795 dhbox.set_homogeneous (false);
796 dhbox.pack_start (*dimage, false, false, 5);
797 dhbox.pack_start (prompt_label, true, false, 5);
798 window.get_vbox()->pack_start (dhbox);
800 window.set_name (_("Prompter"));
801 window.set_position (Gtk::WIN_POS_MOUSE);
802 window.set_modal (true);
803 window.set_resizable (false);
806 window.set_keep_above (true);
809 ResponseType r = (ResponseType) window.run();
814 case RESPONSE_ACCEPT: // save and get out of here
816 case RESPONSE_APPLY: // get out of here
826 ARDOUR_UI::every_second ()
829 update_buffer_load ();
830 update_disk_space ();
835 ARDOUR_UI::every_point_one_seconds ()
837 update_speed_display ();
838 RapidScreenUpdate(); /* EMIT_SIGNAL */
843 ARDOUR_UI::every_point_zero_one_seconds ()
845 // august 2007: actual update frequency: 40Hz, not 100Hz
847 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
852 ARDOUR_UI::update_sample_rate (nframes_t ignored)
856 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
858 if (!engine->connected()) {
860 snprintf (buf, sizeof (buf), _("disconnected"));
864 nframes_t rate = engine->frame_rate();
866 if (fmod (rate, 1000.0) != 0.0) {
867 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
868 (float) rate/1000.0f,
869 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
871 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
873 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
877 sample_rate_label.set_text (buf);
881 ARDOUR_UI::update_cpu_load ()
884 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
885 cpu_load_label.set_text (buf);
889 ARDOUR_UI::update_buffer_load ()
894 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
895 session->playback_load(), session->capture_load());
896 buffer_load_label.set_text (buf);
898 buffer_load_label.set_text ("");
903 ARDOUR_UI::count_recenabled_streams (Route& route)
905 Track* track = dynamic_cast<Track*>(&route);
906 if (track && track->diskstream()->record_enabled()) {
907 rec_enabled_streams += track->n_inputs();
912 ARDOUR_UI::update_disk_space()
918 nframes_t frames = session->available_capture_duration();
921 if (frames == max_frames) {
922 strcpy (buf, _("Disk: 24hrs+"));
927 nframes_t fr = session->frame_rate();
929 rec_enabled_streams = 0;
930 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
932 if (rec_enabled_streams) {
933 frames /= rec_enabled_streams;
936 hrs = frames / (fr * 3600);
937 frames -= hrs * fr * 3600;
938 mins = frames / (fr * 60);
939 frames -= mins * fr * 60;
942 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
945 disk_space_label.set_text (buf);
949 ARDOUR_UI::update_wall_clock ()
956 tm_now = localtime (&now);
958 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
959 wall_clock_label.set_text (buf);
965 ARDOUR_UI::session_menu (GdkEventButton *ev)
967 session_popup_menu->popup (0, 0);
972 ARDOUR_UI::redisplay_recent_sessions ()
974 vector<string *> *sessions;
975 vector<string *>::iterator i;
976 RecentSessionsSorter cmp;
978 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
979 recent_session_model->clear ();
982 ARDOUR::read_recent_sessions (rs);
985 recent_session_display.set_model (recent_session_model);
989 /* sort them alphabetically */
990 sort (rs.begin(), rs.end(), cmp);
991 sessions = new vector<string*>;
993 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
994 sessions->push_back (new string ((*i).second));
997 for (i = sessions->begin(); i != sessions->end(); ++i) {
999 vector<string*>* states;
1000 vector<const gchar*> item;
1001 string fullpath = *(*i);
1003 /* remove any trailing / */
1005 if (fullpath[fullpath.length()-1] == '/') {
1006 fullpath = fullpath.substr (0, fullpath.length()-1);
1009 /* check whether session still exists */
1010 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1011 /* session doesn't exist */
1012 cerr << "skipping non-existent session " << fullpath << endl;
1016 /* now get available states for this session */
1018 if ((states = Session::possible_states (fullpath)) == 0) {
1019 /* no state file? */
1023 TreeModel::Row row = *(recent_session_model->append());
1025 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1026 row[recent_session_columns.fullpath] = fullpath;
1028 if (states->size() > 1) {
1030 /* add the children */
1032 for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
1034 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1036 child_row[recent_session_columns.visible_name] = **i2;
1037 child_row[recent_session_columns.fullpath] = fullpath;
1046 recent_session_display.set_model (recent_session_model);
1051 ARDOUR_UI::build_session_selector ()
1053 session_selector_window = new ArdourDialog ("session selector");
1055 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1057 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1058 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1059 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1060 recent_session_model = TreeStore::create (recent_session_columns);
1061 recent_session_display.set_model (recent_session_model);
1062 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1063 recent_session_display.set_headers_visible (false);
1064 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1065 recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1067 scroller->add (recent_session_display);
1068 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1070 session_selector_window->set_name ("SessionSelectorWindow");
1071 session_selector_window->set_size_request (200, 400);
1072 session_selector_window->get_vbox()->pack_start (*scroller);
1073 session_selector_window->show_all_children();
1077 ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
1079 session_selector_window->response (RESPONSE_ACCEPT);
1083 ARDOUR_UI::open_recent_session ()
1085 bool can_return = (session != 0);
1087 if (session_selector_window == 0) {
1088 build_session_selector ();
1091 redisplay_recent_sessions ();
1095 session_selector_window->set_position (WIN_POS_MOUSE);
1097 ResponseType r = (ResponseType) session_selector_window->run ();
1100 case RESPONSE_ACCEPT:
1104 session_selector_window->hide();
1111 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1115 session_selector_window->hide();
1117 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1119 if (i == recent_session_model->children().end()) {
1123 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1124 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1126 _session_is_new = false;
1128 if (load_session (path, state) == 0) {
1137 ARDOUR_UI::check_audioengine ()
1140 if (!engine->connected()) {
1141 MessageDialog msg (_("Ardour is not connected to JACK\n"
1142 "You cannot open or close sessions in this condition"));
1154 ARDOUR_UI::open_session ()
1156 if (!check_audioengine()) {
1160 /* popup selector window */
1162 if (open_session_selector == 0) {
1164 /* ardour sessions are folders */
1166 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
1167 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1168 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1169 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1171 FileFilter session_filter;
1172 session_filter.add_pattern ("*.ardour");
1173 session_filter.set_name (_("Ardour sessions"));
1174 open_session_selector->add_filter (session_filter);
1175 open_session_selector->set_filter (session_filter);
1178 int response = open_session_selector->run();
1179 open_session_selector->hide ();
1182 case RESPONSE_ACCEPT:
1185 open_session_selector->hide();
1189 open_session_selector->hide();
1190 string session_path = open_session_selector->get_filename();
1194 if (session_path.length() > 0) {
1195 if (Session::find_session (session_path, path, name, isnew) == 0) {
1196 _session_is_new = isnew;
1197 load_session (path, name);
1204 ARDOUR_UI::session_add_midi_track ()
1206 cerr << _("Patience is a virtue.\n");
1210 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
1212 list<boost::shared_ptr<AudioTrack> > tracks;
1213 Session::RouteList routes;
1216 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1222 tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
1224 if (tracks.size() != how_many) {
1225 if (how_many == 1) {
1226 error << _("could not create a new audio track") << endmsg;
1228 error << string_compose (_("could only create %1 of %2 new audio %3"),
1229 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1235 routes = session->new_audio_route (input_channels, output_channels, how_many);
1237 if (routes.size() != how_many) {
1238 if (how_many == 1) {
1239 error << _("could not create a new audio track") << endmsg;
1241 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1247 if (need_control_room_outs) {
1253 route->set_stereo_control_outs (control_lr_channels);
1254 route->control_outs()->set_stereo_pan (pans, this);
1256 #endif /* CONTROLOUTS */
1260 MessageDialog msg (*editor,
1261 _("There are insufficient JACK ports available\n\
1262 to create a new track or bus.\n\
1263 You should save Ardour, exit and\n\
1264 restart JACK with more ports."));
1271 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1273 nframes_t _preroll = 0;
1276 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1277 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1279 if (new_position > _preroll) {
1280 new_position -= _preroll;
1285 session->request_locate (new_position);
1290 ARDOUR_UI::transport_goto_start ()
1293 session->goto_start();
1296 /* force displayed area in editor to start no matter
1297 what "follow playhead" setting is.
1301 editor->reset_x_origin (session->current_start_frame());
1307 ARDOUR_UI::transport_goto_zero ()
1310 session->request_locate (0);
1313 /* force displayed area in editor to start no matter
1314 what "follow playhead" setting is.
1318 editor->reset_x_origin (0);
1324 ARDOUR_UI::transport_goto_wallclock ()
1326 if (session && editor) {
1333 localtime_r (&now, &tmnow);
1335 frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
1336 frames += tmnow.tm_min * (60 * session->frame_rate());
1337 frames += tmnow.tm_sec * session->frame_rate();
1339 session->request_locate (frames);
1341 /* force displayed area in editor to start no matter
1342 what "follow playhead" setting is.
1346 editor->reset_x_origin (frames - (editor->current_page_frames()/2));
1352 ARDOUR_UI::transport_goto_end ()
1355 nframes_t frame = session->current_end_frame();
1356 session->request_locate (frame);
1358 /* force displayed area in editor to start no matter
1359 what "follow playhead" setting is.
1363 editor->reset_x_origin (frame);
1369 ARDOUR_UI::transport_stop ()
1375 if (session->is_auditioning()) {
1376 session->cancel_audition ();
1380 if (session->get_play_loop ()) {
1381 session->request_play_loop (false);
1384 session->request_stop ();
1388 ARDOUR_UI::transport_stop_and_forget_capture ()
1391 session->request_stop (true);
1396 ARDOUR_UI::remove_last_capture()
1399 editor->remove_last_capture();
1404 ARDOUR_UI::transport_record (bool roll)
1408 switch (session->record_status()) {
1409 case Session::Disabled:
1410 if (session->ntracks() == 0) {
1411 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1415 session->maybe_enable_record ();
1420 case Session::Recording:
1422 session->request_stop();
1424 session->disable_record (false, true);
1428 case Session::Enabled:
1429 session->disable_record (false, true);
1432 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1436 ARDOUR_UI::transport_roll ()
1444 rolling = session->transport_rolling ();
1446 //cerr << "ARDOUR_UI::transport_roll () called session->record_status() = " << session->record_status() << endl;
1448 if (session->get_play_loop()) {
1449 session->request_play_loop (false);
1450 auto_loop_button.set_visual_state (1);
1451 roll_button.set_visual_state (1);
1452 } else if (session->get_play_range ()) {
1453 session->request_play_range (false);
1454 play_selection_button.set_visual_state (0);
1455 } else if (rolling) {
1456 session->request_locate (session->last_transport_start(), true);
1459 session->request_transport_speed (1.0f);
1463 ARDOUR_UI::transport_loop()
1466 if (session->get_play_loop()) {
1467 if (session->transport_rolling()) {
1468 Location * looploc = session->locations()->auto_loop_location();
1470 session->request_locate (looploc->start(), true);
1475 session->request_play_loop (true);
1481 ARDOUR_UI::transport_play_selection ()
1487 if (!session->get_play_range()) {
1488 session->request_stop ();
1491 editor->play_selection ();
1495 ARDOUR_UI::transport_rewind (int option)
1497 float current_transport_speed;
1500 current_transport_speed = session->transport_speed();
1502 if (current_transport_speed >= 0.0f) {
1505 session->request_transport_speed (-1.0f);
1508 session->request_transport_speed (-4.0f);
1511 session->request_transport_speed (-0.5f);
1516 session->request_transport_speed (current_transport_speed * 1.5f);
1522 ARDOUR_UI::transport_forward (int option)
1524 float current_transport_speed;
1527 current_transport_speed = session->transport_speed();
1529 if (current_transport_speed <= 0.0f) {
1532 session->request_transport_speed (1.0f);
1535 session->request_transport_speed (4.0f);
1538 session->request_transport_speed (0.5f);
1543 session->request_transport_speed (current_transport_speed * 1.5f);
1549 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1555 boost::shared_ptr<Route> r;
1557 if ((r = session->route_by_remote_id (dstream)) != 0) {
1561 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1562 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1571 ARDOUR_UI::queue_transport_change ()
1573 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1577 ARDOUR_UI::map_transport_state ()
1579 float sp = session->transport_speed();
1582 transport_rolling ();
1583 } else if (sp < 0.0f) {
1584 transport_rewinding ();
1585 } else if (sp > 0.0f) {
1586 transport_forwarding ();
1588 transport_stopped ();
1593 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1595 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1596 (int) adj.get_value()].c_str());
1600 ARDOUR_UI::engine_stopped ()
1602 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1603 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1604 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1608 ARDOUR_UI::engine_running ()
1610 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1611 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1612 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1614 Glib::RefPtr<Action> action;
1615 const char* action_name = 0;
1617 switch (engine->frames_per_cycle()) {
1619 action_name = X_("JACKLatency32");
1622 action_name = X_("JACKLatency64");
1625 action_name = X_("JACKLatency128");
1628 action_name = X_("JACKLatency512");
1631 action_name = X_("JACKLatency1024");
1634 action_name = X_("JACKLatency2048");
1637 action_name = X_("JACKLatency4096");
1640 action_name = X_("JACKLatency8192");
1643 /* XXX can we do anything useful ? */
1649 action = ActionManager::get_action (X_("JACK"), action_name);
1652 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1653 ract->set_active ();
1659 ARDOUR_UI::engine_halted ()
1661 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1663 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1664 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1666 update_sample_rate (0);
1668 MessageDialog msg (*editor,
1670 JACK has either been shutdown or it\n\
1671 disconnected Ardour because Ardour\n\
1672 was not fast enough. Try to restart\n\
1673 JACK, reconnect and save the session."));
1679 ARDOUR_UI::do_engine_start ()
1687 error << _("Unable to start the session running")
1697 ARDOUR_UI::setup_theme ()
1699 theme_manager->setup_theme();
1703 ARDOUR_UI::update_clocks ()
1705 if (!editor || !editor->dragging_playhead()) {
1706 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1711 ARDOUR_UI::start_clocking ()
1713 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1717 ARDOUR_UI::stop_clocking ()
1719 clock_signal_connection.disconnect ();
1723 ARDOUR_UI::toggle_clocking ()
1726 if (clock_button.get_active()) {
1735 ARDOUR_UI::_blink (void *arg)
1738 ((ARDOUR_UI *) arg)->blink ();
1745 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1749 ARDOUR_UI::start_blinking ()
1751 /* Start the blink signal. Everybody with a blinking widget
1752 uses Blink to drive the widget's state.
1755 if (blink_timeout_tag < 0) {
1757 blink_timeout_tag = g_timeout_add (240, _blink, this);
1762 ARDOUR_UI::stop_blinking ()
1764 if (blink_timeout_tag >= 0) {
1765 g_source_remove (blink_timeout_tag);
1766 blink_timeout_tag = -1;
1771 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1777 if (io.n_inputs() == 0) {
1782 /* XXX we're not handling multiple ports yet. */
1784 const char **connections = io.input(0)->get_connections();
1786 if (connections == 0 || connections[0] == '\0') {
1789 buf = connections[0];
1796 if (io.n_outputs() == 0) {
1801 /* XXX we're not handling multiple ports yet. */
1803 const char **connections = io.output(0)->get_connections();
1805 if (connections == 0 || connections[0] == '\0') {
1808 buf = connections[0];
1815 /** Ask the user for the name of a new shapshot and then take it.
1818 ARDOUR_UI::snapshot_session ()
1820 ArdourPrompter prompter (true);
1824 struct tm local_time;
1827 localtime_r (&n, &local_time);
1828 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1830 prompter.set_name ("Prompter");
1831 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1832 prompter.set_prompt (_("Name of New Snapshot"));
1833 prompter.set_initial_text (timebuf);
1835 switch (prompter.run()) {
1836 case RESPONSE_ACCEPT:
1837 prompter.get_result (snapname);
1838 if (snapname.length()){
1839 save_state (snapname);
1849 ARDOUR_UI::save_state (const string & name)
1851 (void) save_state_canfail (name);
1855 ARDOUR_UI::save_state_canfail (string name)
1860 if (name.length() == 0) {
1861 name = session->snap_name();
1864 if ((ret = session->save_state (name)) != 0) {
1868 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1873 ARDOUR_UI::primary_clock_value_changed ()
1876 session->request_locate (primary_clock.current_time ());
1881 ARDOUR_UI::big_clock_value_changed ()
1884 session->request_locate (big_clock.current_time ());
1889 ARDOUR_UI::secondary_clock_value_changed ()
1892 session->request_locate (secondary_clock.current_time ());
1897 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
1903 switch (session->record_status()) {
1904 case Session::Enabled:
1906 rec_button.set_visual_state (2);
1908 rec_button.set_visual_state (0);
1912 case Session::Recording:
1913 rec_button.set_visual_state (1);
1917 rec_button.set_visual_state (0);
1923 ARDOUR_UI::save_template ()
1926 ArdourPrompter prompter (true);
1929 if (!check_audioengine()) {
1933 prompter.set_name (X_("Prompter"));
1934 prompter.set_prompt (_("Name for mix template:"));
1935 prompter.set_initial_text(session->name() + _("-template"));
1936 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1938 switch (prompter.run()) {
1939 case RESPONSE_ACCEPT:
1940 prompter.get_result (name);
1942 if (name.length()) {
1943 session->save_template (name);
1953 ARDOUR_UI::fontconfig_dialog ()
1956 /* X11 users will always have fontconfig info around, but new GTK-OSX users
1957 may not and it can take a while to build it. Warn them.
1960 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
1962 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
1963 MessageDialog msg (*new_session_dialog,
1964 _("Welcome to Ardour.\n\n"
1965 "The program will take a bit longer to start up\n"
1966 "while the system fonts are checked.\n\n"
1967 "This will only be done once, and you will\n"
1968 "not see this message again\n"),
1981 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
1983 existing_session = false;
1985 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
1986 session_path = cmdline_path;
1987 existing_session = true;
1988 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
1989 session_path = Glib::path_get_dirname (string (cmdline_path));
1990 existing_session = true;
1992 /* it doesn't exist, assume the best */
1993 session_path = Glib::path_get_dirname (string (cmdline_path));
1996 session_name = basename_nosuffix (string (cmdline_path));
2000 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2002 /* when this is called, the backend audio system must be running */
2004 /* the main idea here is to deal with the fact that a cmdline argument for the session
2005 can be interpreted in different ways - it could be a directory or a file, and before
2006 we load, we need to know both the session directory and the snapshot (statefile) within it
2007 that we are supposed to use.
2010 if (session_name.length() == 0 || session_path.length() == 0) {
2014 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2016 Glib::ustring predicted_session_file;
2018 predicted_session_file = session_path;
2019 predicted_session_file += '/';
2020 predicted_session_file += session_name;
2021 predicted_session_file += Session::statefile_suffix();
2023 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2024 existing_session = true;
2027 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2029 if (session_path.find (Session::statefile_suffix()) == session_path.length() - 7) {
2030 /* existing .ardour file */
2031 existing_session = true;
2035 existing_session = false;
2038 /* lets just try to load it */
2040 if (create_engine ()) {
2041 backend_audio_error (false, new_session_dialog);
2045 return load_session (session_path, session_name);
2049 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2051 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2053 MessageDialog msg (str,
2055 Gtk::MESSAGE_WARNING,
2056 Gtk::BUTTONS_YES_NO,
2060 msg.set_name (X_("CleanupDialog"));
2061 msg.set_wmclass (X_("existing_session"), "Ardour");
2062 msg.set_position (Gtk::WIN_POS_MOUSE);
2065 switch (msg.run()) {
2074 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2079 AutoConnectOption iconnect;
2080 AutoConnectOption oconnect;
2084 if (Profile->get_sae()) {
2088 iconnect = AutoConnectPhysical;
2089 oconnect = AutoConnectMaster;
2090 nphysin = 0; // use all available
2091 nphysout = 0; // use all available
2095 /* get settings from advanced section of NSD */
2097 if (new_session_dialog->create_control_bus()) {
2098 cchns = (uint32_t) new_session_dialog->control_channel_count();
2103 if (new_session_dialog->create_master_bus()) {
2104 mchns = (uint32_t) new_session_dialog->master_channel_count();
2109 if (new_session_dialog->connect_inputs()) {
2110 iconnect = AutoConnectPhysical;
2112 iconnect = AutoConnectOption (0);
2115 /// @todo some minor tweaks.
2117 if (new_session_dialog->connect_outs_to_master()) {
2118 oconnect = AutoConnectMaster;
2119 } else if (new_session_dialog->connect_outs_to_physical()) {
2120 oconnect = AutoConnectPhysical;
2122 oconnect = AutoConnectOption (0);
2125 nphysin = (uint32_t) new_session_dialog->input_limit_count();
2126 nphysout = (uint32_t) new_session_dialog->output_limit_count();
2129 if (build_session (session_path,
2137 engine->frame_rate() * 60 * 5)) {
2146 ARDOUR_UI::end_loading_messages ()
2152 ARDOUR_UI::loading_message (const std::string& msg)
2155 splash->message (msg);
2160 ARDOUR_UI::idle_load (const Glib::ustring& path)
2163 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2164 /* /path/to/foo => /path/to/foo, foo */
2165 load_session (path, basename_nosuffix (path));
2167 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2168 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2171 ARDOUR_COMMAND_LINE::session_name = path;
2172 if (new_session_dialog) {
2173 /* make it break out of Dialog::run() and
2176 new_session_dialog->response (1);
2182 ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
2184 bool existing_session = false;
2185 Glib::ustring session_name;
2186 Glib::ustring session_path;
2187 Glib::ustring template_name;
2191 response = Gtk::RESPONSE_NONE;
2193 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2195 parse_cmdline_path (ARDOUR_COMMAND_LINE::session_name, session_name, session_path, existing_session);
2197 /* don't ever reuse this */
2199 ARDOUR_COMMAND_LINE::session_name = string();
2201 if (existing_session && backend_audio_is_running) {
2203 /* just load the thing already */
2205 if (load_cmdline_session (session_name, session_path, existing_session) == 0) {
2210 /* make the NSD use whatever information we have */
2212 new_session_dialog->set_session_name (session_name);
2213 new_session_dialog->set_session_folder (session_path);
2216 /* loading failed, or we need the NSD for something */
2218 new_session_dialog->set_modal (false);
2219 new_session_dialog->set_position (WIN_POS_CENTER);
2220 new_session_dialog->set_current_page (0);
2221 new_session_dialog->set_existing_session (existing_session);
2222 new_session_dialog->reset_recent();
2225 new_session_dialog->set_have_engine (backend_audio_is_running);
2226 new_session_dialog->present ();
2227 response = new_session_dialog->run ();
2229 _session_is_new = false;
2231 /* handle possible negative responses */
2235 /* sent by idle_load, meaning restart the whole process again */
2236 new_session_dialog->hide();
2237 new_session_dialog->reset();
2241 case Gtk::RESPONSE_CANCEL:
2242 case Gtk::RESPONSE_DELETE_EVENT:
2246 new_session_dialog->hide ();
2249 case Gtk::RESPONSE_NONE:
2250 /* "Clear" was pressed */
2254 fontconfig_dialog();
2256 if (!backend_audio_is_running) {
2257 int ret = new_session_dialog->engine_control.setup_engine ();
2260 } else if (ret > 0) {
2261 response = Gtk::RESPONSE_REJECT;
2266 if (create_engine ()) {
2268 backend_audio_error (!backend_audio_is_running, new_session_dialog);
2271 new_session_dialog->set_existing_session (false);
2272 new_session_dialog->set_current_page (2);
2274 response = Gtk::RESPONSE_NONE;
2278 backend_audio_is_running = true;
2280 if (response == Gtk::RESPONSE_OK) {
2282 session_name = new_session_dialog->session_name();
2284 if (session_name.empty()) {
2285 response = Gtk::RESPONSE_NONE;
2289 /* if the user mistakenly typed path information into the session filename entry,
2290 convert what they typed into a path & a name
2293 if (session_name[0] == '/' ||
2294 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2295 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2297 session_path = Glib::path_get_dirname (session_name);
2298 session_name = Glib::path_get_basename (session_name);
2302 session_path = new_session_dialog->session_folder();
2305 template_name = Glib::ustring();
2306 switch (new_session_dialog->which_page()) {
2308 case NewSessionDialog::OpenPage:
2309 case NewSessionDialog::EnginePage:
2313 case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
2315 should_be_new = true;
2317 //XXX This is needed because session constructor wants a
2318 //non-existant path. hopefully this will be fixed at some point.
2320 session_path = Glib::build_filename (session_path, session_name);
2322 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2324 if (ask_about_loading_existing_session (session_path)) {
2327 response = RESPONSE_NONE;
2332 _session_is_new = true;
2334 if (new_session_dialog->use_session_template()) {
2336 template_name = new_session_dialog->session_template_name();
2340 if (build_session_from_nsd (session_path, session_name)) {
2341 response = RESPONSE_NONE;
2353 new_session_dialog->hide ();
2355 if (load_session (session_path, session_name, template_name)) {
2357 response = Gtk::RESPONSE_NONE;
2361 if (response == Gtk::RESPONSE_NONE) {
2362 new_session_dialog->set_existing_session (false);
2363 new_session_dialog->reset ();
2367 } while (response == Gtk::RESPONSE_NONE || response == Gtk::RESPONSE_REJECT);
2371 new_session_dialog->hide();
2372 new_session_dialog->reset();
2373 goto_editor_window ();
2378 ARDOUR_UI::close_session ()
2380 if (!check_audioengine()) {
2384 unload_session (true);
2386 get_session_parameters (true, false);
2390 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2392 Session *new_session;
2396 session_loaded = false;
2398 if (!check_audioengine()) {
2402 unload_status = unload_session ();
2404 if (unload_status < 0) {
2406 } else if (unload_status > 0) {
2411 /* if it already exists, we must have write access */
2413 if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) {
2414 MessageDialog msg (*editor, _("You do not have write access to this session.\n"
2415 "This prevents the session from being loaded."));
2421 loading_message (_("Please wait while Ardour loads your session"));
2424 new_session = new Session (*engine, path, snap_name, mix_template);
2427 /* this one is special */
2429 catch (AudioEngine::PortRegistrationFailure& err) {
2431 MessageDialog msg (err.what(),
2434 Gtk::BUTTONS_OK_CANCEL);
2436 msg.set_title (_("Loading Error"));
2437 msg.set_secondary_text (_("Click the OK button to try again."));
2438 msg.set_position (Gtk::WIN_POS_CENTER);
2442 int response = msg.run ();
2447 case RESPONSE_CANCEL:
2457 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2460 Gtk::BUTTONS_OK_CANCEL);
2462 msg.set_title (_("Loading Error"));
2463 msg.set_secondary_text (_("Click the OK button to try again."));
2464 msg.set_position (Gtk::WIN_POS_CENTER);
2468 int response = msg.run ();
2473 case RESPONSE_CANCEL:
2481 connect_to_session (new_session);
2483 Config->set_current_owner (ConfigVariableBase::Interface);
2485 session_loaded = true;
2487 goto_editor_window ();
2490 session->set_clean ();
2501 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2502 uint32_t control_channels,
2503 uint32_t master_channels,
2504 AutoConnectOption input_connect,
2505 AutoConnectOption output_connect,
2508 nframes_t initial_length)
2510 Session *new_session;
2513 if (!check_audioengine()) {
2517 session_loaded = false;
2519 x = unload_session ();
2527 _session_is_new = true;
2530 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2531 control_channels, master_channels, nphysin, nphysout, initial_length);
2536 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2542 connect_to_session (new_session);
2544 session_loaded = true;
2552 editor->show_window ();
2563 ARDOUR_UI::show_about ()
2567 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2574 ARDOUR_UI::hide_about ()
2577 about->get_window()->set_cursor ();
2583 ARDOUR_UI::about_signal_response(int response)
2589 ARDOUR_UI::show_splash ()
2593 splash = new Splash;
2601 splash->queue_draw ();
2602 splash->get_window()->process_updates (true);
2607 ARDOUR_UI::hide_splash ()
2615 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
2619 removed = rep.paths.size();
2622 MessageDialog msgd (*editor,
2623 _("No audio files were ready for cleanup"),
2626 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2627 msgd.set_secondary_text (_("If this seems suprising, \n\
2628 check for any existing snapshots.\n\
2629 These may still include regions that\n\
2630 require some unused files to continue to exist."));
2636 ArdourDialog results (_("ardour: cleanup"), true, false);
2638 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2639 CleanupResultsModelColumns() {
2643 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2644 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2648 CleanupResultsModelColumns results_columns;
2649 Glib::RefPtr<Gtk::ListStore> results_model;
2650 Gtk::TreeView results_display;
2652 results_model = ListStore::create (results_columns);
2653 results_display.set_model (results_model);
2654 results_display.append_column (list_title, results_columns.visible_name);
2656 results_display.set_name ("CleanupResultsList");
2657 results_display.set_headers_visible (true);
2658 results_display.set_headers_clickable (false);
2659 results_display.set_reorderable (false);
2661 Gtk::ScrolledWindow list_scroller;
2664 Gtk::HBox dhbox; // the hbox for the image and text
2665 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2666 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2668 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2670 if (rep.space < 1048576.0f) {
2672 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2674 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2678 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2680 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2684 dhbox.pack_start (*dimage, true, false, 5);
2685 dhbox.pack_start (txt, true, false, 5);
2687 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2688 TreeModel::Row row = *(results_model->append());
2689 row[results_columns.visible_name] = *i;
2690 row[results_columns.fullpath] = *i;
2693 list_scroller.add (results_display);
2694 list_scroller.set_size_request (-1, 150);
2695 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2697 dvbox.pack_start (dhbox, true, false, 5);
2698 dvbox.pack_start (list_scroller, true, false, 5);
2699 ddhbox.pack_start (dvbox, true, false, 5);
2701 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2702 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2703 results.set_default_response (RESPONSE_CLOSE);
2704 results.set_position (Gtk::WIN_POS_MOUSE);
2705 results.show_all_children ();
2706 results.set_resizable (false);
2713 ARDOUR_UI::cleanup ()
2716 /* shouldn't happen: menu item is insensitive */
2721 MessageDialog checker (_("Are you sure you want to cleanup?"),
2723 Gtk::MESSAGE_QUESTION,
2724 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2726 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2727 ALL undo/redo information will be lost if you cleanup.\n\
2728 After cleanup, unused audio files will be moved to a \
2729 \"dead sounds\" location."));
2731 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2732 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2733 checker.set_default_response (RESPONSE_CANCEL);
2735 checker.set_name (_("CleanupDialog"));
2736 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2737 checker.set_position (Gtk::WIN_POS_MOUSE);
2739 switch (checker.run()) {
2740 case RESPONSE_ACCEPT:
2746 Session::cleanup_report rep;
2748 editor->prepare_for_cleanup ();
2750 /* do not allow flush until a session is reloaded */
2752 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2754 act->set_sensitive (false);
2757 if (session->cleanup_sources (rep)) {
2758 editor->finish_cleanup ();
2762 editor->finish_cleanup ();
2765 display_cleanup_results (rep,
2768 The following %1 %2 not in use and \n\
2769 have been moved to:\n\
2771 Flushing the wastebasket will \n\
2772 release an additional\n\
2773 %4 %5bytes of disk space.\n"
2779 ARDOUR_UI::flush_trash ()
2782 /* shouldn't happen: menu item is insensitive */
2786 Session::cleanup_report rep;
2788 if (session->cleanup_trash_sources (rep)) {
2792 display_cleanup_results (rep,
2794 _("The following %1 %2 deleted from\n\
2796 releasing %4 %5bytes of disk space"));
2800 ARDOUR_UI::add_route (Gtk::Window* float_window)
2808 if (add_route_dialog == 0) {
2809 add_route_dialog = new AddRouteDialog;
2811 add_route_dialog->set_transient_for (*float_window);
2815 if (add_route_dialog->is_visible()) {
2816 /* we're already doing this */
2820 ResponseType r = (ResponseType) add_route_dialog->run ();
2822 add_route_dialog->hide();
2825 case RESPONSE_ACCEPT:
2832 if ((count = add_route_dialog->count()) <= 0) {
2836 uint32_t input_chan = add_route_dialog->channels ();
2837 uint32_t output_chan;
2838 string name_template = add_route_dialog->name_template ();
2839 bool track = add_route_dialog->track ();
2841 AutoConnectOption oac = Config->get_output_auto_connect();
2843 if (oac & AutoConnectMaster) {
2844 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2846 output_chan = input_chan;
2849 /* XXX do something with name template */
2851 cerr << "Adding with " << input_chan << " in and " << output_chan << "out\n";
2854 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
2856 session_add_audio_bus (input_chan, output_chan, count);
2861 ARDOUR_UI::mixer_settings () const
2866 node = session->instant_xml(X_("Mixer"), session->path());
2868 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
2872 node = new XMLNode (X_("Mixer"));
2879 ARDOUR_UI::editor_settings () const
2884 node = session->instant_xml(X_("Editor"), session->path());
2886 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
2890 node = new XMLNode (X_("Editor"));
2896 ARDOUR_UI::keyboard_settings () const
2900 node = Config->extra_xml(X_("Keyboard"));
2903 node = new XMLNode (X_("Keyboard"));
2909 ARDOUR_UI::create_xrun_marker(nframes_t where)
2911 editor->mouse_add_new_marker (where, false, true);
2915 ARDOUR_UI::halt_on_xrun_message ()
2917 MessageDialog msg (*editor,
2918 _("Recording was stopped because your system could not keep up."));
2923 ARDOUR_UI::xrun_handler(nframes_t where)
2925 ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::xrun_handler), where));
2927 if (Config->get_create_xrun_marker() && session->actively_recording()) {
2928 create_xrun_marker(where);
2931 if (Config->get_stop_recording_on_xrun() && session->actively_recording()) {
2932 halt_on_xrun_message ();
2937 ARDOUR_UI::disk_overrun_handler ()
2939 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
2941 if (!have_disk_speed_dialog_displayed) {
2942 have_disk_speed_dialog_displayed = true;
2943 MessageDialog* msg = new MessageDialog (*editor, _("\
2944 The disk system on your computer\n\
2945 was not able to keep up with Ardour.\n\
2947 Specifically, it failed to write data to disk\n\
2948 quickly enough to keep up with recording.\n"));
2949 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
2955 ARDOUR_UI::disk_underrun_handler ()
2957 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2959 if (!have_disk_speed_dialog_displayed) {
2960 have_disk_speed_dialog_displayed = true;
2961 MessageDialog* msg = new MessageDialog (*editor,
2962 _("The disk system on your computer\n\
2963 was not able to keep up with Ardour.\n\
2965 Specifically, it failed to read data from disk\n\
2966 quickly enough to keep up with playback.\n"));
2967 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
2973 ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
2975 have_disk_speed_dialog_displayed = false;
2980 ARDOUR_UI::session_dialog (std::string msg)
2982 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
2987 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
2989 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
2998 ARDOUR_UI::pending_state_dialog ()
3000 HBox* hbox = new HBox();
3001 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3002 ArdourDialog dialog (_("Crash Recovery"), true);
3004 This session appears to have been in\n\
3005 middle of recording when ardour or\n\
3006 the computer was shutdown.\n\
3008 Ardour can recover any captured audio for\n\
3009 you, or it can ignore it. Please decide\n\
3010 what you would like to do.\n"));
3011 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3012 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3013 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3014 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3015 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3016 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3017 dialog.set_default_response (RESPONSE_ACCEPT);
3018 dialog.set_position (WIN_POS_CENTER);
3023 switch (dialog.run ()) {
3024 case RESPONSE_ACCEPT:
3032 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3034 HBox* hbox = new HBox();
3035 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3036 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3037 Label message (string_compose (_("\
3038 This session was created with a sample rate of %1 Hz\n\
3040 The audioengine is currently running at %2 Hz\n"), desired, actual));
3042 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3043 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3044 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3045 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3046 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3047 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3048 dialog.set_default_response (RESPONSE_ACCEPT);
3049 dialog.set_position (WIN_POS_CENTER);
3054 switch (dialog.run ()) {
3055 case RESPONSE_ACCEPT:
3064 ARDOUR_UI::disconnect_from_jack ()
3067 if( engine->disconnect_from_jack ()) {
3068 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3072 update_sample_rate (0);
3077 ARDOUR_UI::reconnect_to_jack ()
3080 if (engine->reconnect_to_jack ()) {
3081 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3085 update_sample_rate (0);
3090 ARDOUR_UI::use_config ()
3092 Glib::RefPtr<Action> act;
3094 switch (Config->get_native_file_data_format ()) {
3096 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
3099 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
3102 act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit"));
3107 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3108 ract->set_active ();
3111 switch (Config->get_native_file_header_format ()) {
3113 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
3116 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
3119 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
3122 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
3125 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
3128 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
3131 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
3136 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3137 ract->set_active ();
3140 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3142 set_transport_controllable_state (*node);
3147 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3149 if (Config->get_primary_clock_delta_edit_cursor()) {
3150 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3152 primary_clock.set (pos, 0, true);
3155 if (Config->get_secondary_clock_delta_edit_cursor()) {
3156 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3158 secondary_clock.set (pos);
3161 if (big_clock_window) {
3162 big_clock.set (pos);
3167 ARDOUR_UI::record_state_changed ()
3169 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3171 if (!session || !big_clock_window) {
3172 /* why bother - the clock isn't visible */
3176 switch (session->record_status()) {
3177 case Session::Recording:
3178 big_clock.set_widget_name ("BigClockRecording");
3181 big_clock.set_widget_name ("BigClockNonRecording");
3187 ARDOUR_UI::first_idle ()
3190 session->allow_auto_play (true);
3194 editor->first_idle();
3197 Keyboard::set_can_save_keybindings (true);
3202 ARDOUR_UI::store_clock_modes ()
3204 XMLNode* node = new XMLNode(X_("ClockModes"));
3206 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3207 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3210 session->add_extra_xml (*node);
3211 session->set_dirty ();
3216 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3217 : Controllable (name), ui (u), type(tp)
3223 ARDOUR_UI::TransportControllable::set_value (float val)
3225 if (type == ShuttleControl) {
3232 fract = -((0.5f - val)/0.5f);
3234 fract = ((val - 0.5f)/0.5f);
3238 ui.set_shuttle_fract (fract);
3243 /* do nothing: these are radio-style actions */
3247 const char *action = 0;
3251 action = X_("Roll");
3254 action = X_("Stop");
3257 action = X_("Goto Start");
3260 action = X_("Goto End");
3263 action = X_("Loop");
3266 action = X_("Play Selection");
3269 action = X_("Record");
3279 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3287 ARDOUR_UI::TransportControllable::get_value (void) const
3306 case ShuttleControl:
3316 ARDOUR_UI::TransportControllable::set_id (const string& str)
3322 ARDOUR_UI::setup_profile ()
3324 if (gdk_screen_width() < 1200) {
3325 Profile->set_small_screen ();
3328 if (getenv ("ARDOUR_SAE")) {
3329 Profile->set_sae ();
3330 Profile->set_single_package ();