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.
30 #include <sys/resource.h>
32 #include <gtkmm/messagedialog.h>
33 #include <gtkmm/accelmap.h>
35 #include <pbd/error.h>
36 #include <pbd/basename.h>
37 #include <pbd/compose.h>
38 #include <pbd/pathscanner.h>
39 #include <pbd/failed_constructor.h>
40 #include <pbd/enumwriter.h>
41 #include <pbd/stacktrace.h>
42 #include <gtkmm2ext/gtk_ui.h>
43 #include <gtkmm2ext/utils.h>
44 #include <gtkmm2ext/click_box.h>
45 #include <gtkmm2ext/fastmeter.h>
46 #include <gtkmm2ext/stop_signal.h>
47 #include <gtkmm2ext/popup.h>
48 #include <gtkmm2ext/window_title.h>
50 #include <midi++/port.h>
51 #include <midi++/mmc.h>
53 #include <ardour/ardour.h>
54 #include <ardour/profile.h>
55 #include <ardour/session_route.h>
56 #include <ardour/port.h>
57 #include <ardour/audioengine.h>
58 #include <ardour/playlist.h>
59 #include <ardour/utils.h>
60 #include <ardour/audio_diskstream.h>
61 #include <ardour/audiofilesource.h>
62 #include <ardour/recent_sessions.h>
63 #include <ardour/port.h>
64 #include <ardour/audio_track.h>
67 #include "ardour_ui.h"
68 #include "public_editor.h"
69 #include "audio_clock.h"
74 #include "add_route_dialog.h"
75 #include "new_session_dialog.h"
79 #include "gui_thread.h"
80 #include "theme_manager.h"
81 #include "engine_dialog.h"
85 using namespace ARDOUR;
87 using namespace Gtkmm2ext;
91 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
92 UIConfiguration *ARDOUR_UI::ui_config = 0;
94 sigc::signal<void,bool> ARDOUR_UI::Blink;
95 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
96 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
97 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
99 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
101 : Gtkmm2ext::UI (X_("Ardour"), argcp, argvp),
103 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true),
104 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true),
105 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
106 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
110 adjuster_table (3, 3),
114 preroll_button (_("pre\nroll")),
115 postroll_button (_("post\nroll")),
119 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, false, true),
123 roll_controllable ("transport roll", *this, TransportControllable::Roll),
124 stop_controllable ("transport stop", *this, TransportControllable::Stop),
125 goto_start_controllable ("transport goto start", *this, TransportControllable::GotoStart),
126 goto_end_controllable ("transport goto end", *this, TransportControllable::GotoEnd),
127 auto_loop_controllable ("transport auto loop", *this, TransportControllable::AutoLoop),
128 play_selection_controllable ("transport play selection", *this, TransportControllable::PlaySelection),
129 rec_controllable ("transport rec-enable", *this, TransportControllable::RecordEnable),
130 shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl),
131 shuttle_controller_binding_proxy (shuttle_controllable),
133 roll_button (roll_controllable),
134 stop_button (stop_controllable),
135 goto_start_button (goto_start_controllable),
136 goto_end_button (goto_end_controllable),
137 auto_loop_button (auto_loop_controllable),
138 play_selection_button (play_selection_controllable),
139 rec_button (rec_controllable),
141 shuttle_units_button (_("% ")),
143 punch_in_button (_("Punch In")),
144 punch_out_button (_("Punch Out")),
145 auto_return_button (_("Auto Return")),
146 auto_play_button (_("Auto Play")),
147 auto_input_button (_("Auto Input")),
148 click_button (_("Click")),
149 time_master_button (_("time\nmaster")),
151 auditioning_alert_button (_("AUDITION")),
152 solo_alert_button (_("SOLO")),
154 error_log_button (_("Errors"))
156 using namespace Gtk::Menu_Helpers;
161 _auto_display_errors = false;
167 if (ARDOUR_COMMAND_LINE::session_name.length()) {
168 /* only show this if we're not going to post the new session dialog */
172 if (theArdourUI == 0) {
176 ui_config = new UIConfiguration();
177 theme_manager = new ThemeManager();
183 _session_is_new = false;
184 big_clock_window = 0;
185 session_selector_window = 0;
186 new_session_dialog = 0;
187 last_key_press_time = 0;
188 connection_editor = 0;
189 add_route_dialog = 0;
194 open_session_selector = 0;
195 have_configure_timeout = false;
196 have_disk_speed_dialog_displayed = false;
197 _will_create_new_session_automatically = false;
198 session_loaded = false;
199 last_speed_displayed = -1.0f;
200 ignore_dual_punch = false;
202 last_configure_time.tv_sec = 0;
203 last_configure_time.tv_usec = 0;
205 shuttle_grabbed = false;
207 shuttle_max_speed = 8.0f;
209 shuttle_style_menu = 0;
210 shuttle_unit_menu = 0;
212 gettimeofday (&last_peak_grab, 0);
213 gettimeofday (&last_shuttle_request, 0);
215 ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
216 ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
218 /* handle pending state with a dialog */
220 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
222 /* handle sr mismatch with a dialog */
224 ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
226 /* lets get this party started */
229 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
230 throw failed_constructor ();
233 setup_gtk_ardour_enums ();
234 Config->set_current_owner (ConfigVariableBase::Interface);
237 } catch (failed_constructor& err) {
238 error << _("could not initialize Ardour.") << endmsg;
243 /* we like keyboards */
245 keyboard = new Keyboard;
249 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
250 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
256 ARDOUR_UI::create_engine ()
258 // this gets called every time by new_session()
264 loading_message (_("Starting audio engine"));
267 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
274 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
275 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
276 engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
277 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
285 ARDOUR_UI::post_engine ()
287 /* Things to be done once we create the AudioEngine
290 check_memory_locking();
292 ActionManager::init ();
295 if (setup_windows ()) {
296 throw failed_constructor ();
299 /* this is the first point at which all the keybindings are available */
301 if (ARDOUR_COMMAND_LINE::show_key_actions) {
302 vector<string> names;
303 vector<string> paths;
305 vector<AccelKey> bindings;
307 ActionManager::get_all_actions (names, paths, keys, bindings);
309 vector<string>::iterator n;
310 vector<string>::iterator k;
311 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
312 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
318 blink_timeout_tag = -1;
320 /* the global configuration object is now valid */
324 /* this being a GUI and all, we want peakfiles */
326 AudioFileSource::set_build_peakfiles (true);
327 AudioFileSource::set_build_missing_peakfiles (true);
329 /* set default clock modes */
331 if (Profile->get_sae()) {
332 primary_clock.set_mode (AudioClock::MinSec);
334 primary_clock.set_mode (AudioClock::SMPTE);
336 secondary_clock.set_mode (AudioClock::BBT);
338 /* start the time-of-day-clock */
341 /* OS X provides an always visible wallclock, so don't be stupid */
342 update_wall_clock ();
343 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
346 update_disk_space ();
348 update_sample_rate (engine->frame_rate());
350 platform_specific ();
352 /* now start and maybe save state */
354 if (do_engine_start () == 0) {
355 if (session && _session_is_new) {
356 /* we need to retain initial visual
357 settings for a new session
359 session->save_state ("");
364 ARDOUR_UI::~ARDOUR_UI ()
366 save_ardour_state ();
380 if (add_route_dialog) {
381 delete add_route_dialog;
384 if (new_session_dialog) {
385 delete new_session_dialog;
390 ARDOUR_UI::pop_back_splash ()
392 if (Splash::instance()) {
393 // Splash::instance()->pop_back();
394 Splash::instance()->hide ();
399 ARDOUR_UI::configure_timeout ()
404 if (last_configure_time.tv_sec == 0 && last_configure_time.tv_usec == 0) {
405 /* no configure events yet */
409 gettimeofday (&now, 0);
410 timersub (&now, &last_configure_time, &diff);
412 /* force a gap of 0.5 seconds since the last configure event
415 if (diff.tv_sec == 0 && diff.tv_usec < 500000) {
418 have_configure_timeout = false;
419 save_ardour_state ();
425 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
427 if (have_configure_timeout) {
428 gettimeofday (&last_configure_time, 0);
430 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
431 have_configure_timeout = true;
438 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
440 const XMLProperty* prop;
442 if ((prop = node.property ("roll")) != 0) {
443 roll_controllable.set_id (prop->value());
445 if ((prop = node.property ("stop")) != 0) {
446 stop_controllable.set_id (prop->value());
448 if ((prop = node.property ("goto_start")) != 0) {
449 goto_start_controllable.set_id (prop->value());
451 if ((prop = node.property ("goto_end")) != 0) {
452 goto_end_controllable.set_id (prop->value());
454 if ((prop = node.property ("auto_loop")) != 0) {
455 auto_loop_controllable.set_id (prop->value());
457 if ((prop = node.property ("play_selection")) != 0) {
458 play_selection_controllable.set_id (prop->value());
460 if ((prop = node.property ("rec")) != 0) {
461 rec_controllable.set_id (prop->value());
463 if ((prop = node.property ("shuttle")) != 0) {
464 shuttle_controllable.set_id (prop->value());
469 ARDOUR_UI::get_transport_controllable_state ()
471 XMLNode* node = new XMLNode(X_("TransportControllables"));
474 roll_controllable.id().print (buf, sizeof (buf));
475 node->add_property (X_("roll"), buf);
476 stop_controllable.id().print (buf, sizeof (buf));
477 node->add_property (X_("stop"), buf);
478 goto_start_controllable.id().print (buf, sizeof (buf));
479 node->add_property (X_("goto_start"), buf);
480 goto_end_controllable.id().print (buf, sizeof (buf));
481 node->add_property (X_("goto_end"), buf);
482 auto_loop_controllable.id().print (buf, sizeof (buf));
483 node->add_property (X_("auto_loop"), buf);
484 play_selection_controllable.id().print (buf, sizeof (buf));
485 node->add_property (X_("play_selection"), buf);
486 rec_controllable.id().print (buf, sizeof (buf));
487 node->add_property (X_("rec"), buf);
488 shuttle_controllable.id().print (buf, sizeof (buf));
489 node->add_property (X_("shuttle"), buf);
495 ARDOUR_UI::save_ardour_state ()
497 if (!keyboard || !mixer || !editor) {
501 /* XXX this is all a bit dubious. add_extra_xml() uses
502 a different lifetime model from add_instant_xml().
505 XMLNode* node = new XMLNode (keyboard->get_state());
506 Config->add_extra_xml (*node);
507 Config->add_extra_xml (get_transport_controllable_state());
508 if (new_session_dialog) {
509 if (new_session_dialog->engine_control.was_used()) {
510 Config->add_extra_xml (new_session_dialog->engine_control.get_state());
513 Config->save_state();
514 ui_config->save_state ();
516 XMLNode enode(static_cast<Stateful*>(editor)->get_state());
517 XMLNode mnode(mixer->get_state());
520 session->add_instant_xml (enode, session->path());
521 session->add_instant_xml (mnode, session->path());
523 Config->add_instant_xml (enode, get_user_ardour_path());
524 Config->add_instant_xml (mnode, get_user_ardour_path());
527 Keyboard::save_keybindings ();
531 ARDOUR_UI::autosave_session ()
533 if (!Config->get_periodic_safety_backups())
537 session->maybe_write_autosave();
544 ARDOUR_UI::update_autosave ()
546 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
548 if (session->dirty()) {
549 if (_autosave_connection.connected()) {
550 _autosave_connection.disconnect();
553 _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
554 Config->get_periodic_safety_backup_interval() * 1000);
557 if (_autosave_connection.connected()) {
558 _autosave_connection.disconnect();
564 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
568 title = _("Ardour could not start JACK");
570 title = _("Ardour could not connect to JACK.");
573 MessageDialog win (title,
579 win.set_secondary_text(_("There are several possible reasons:\n\
581 1) You requested audio parameters that are not supported..\n\
582 2) JACK is running as another user.\n\
584 Please consider the possibilities, and perhaps try different parameters."));
586 win.set_secondary_text(_("There are several possible reasons:\n\
588 1) JACK is not running.\n\
589 2) JACK is running as another user, perhaps root.\n\
590 3) There is already another client called \"ardour\".\n\
592 Please consider the possibilities, and perhaps (re)start JACK."));
596 win.set_transient_for (*toplevel);
600 win.add_button (Stock::OK, RESPONSE_CLOSE);
602 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
605 win.set_default_response (RESPONSE_CLOSE);
608 win.set_position (Gtk::WIN_POS_CENTER);
611 /* we just don't care about the result, but we want to block */
617 ARDOUR_UI::startup ()
621 new_session_dialog = new NewSessionDialog();
623 bool backend_audio_is_running = EngineControl::engine_running();
624 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
627 new_session_dialog->engine_control.set_state (*audio_setup);
630 if (!get_session_parameters (backend_audio_is_running, ARDOUR_COMMAND_LINE::new_session)) {
634 BootMessage (_("Ardour is ready for use"));
639 ARDOUR_UI::no_memory_warning ()
641 XMLNode node (X_("no-memory-warning"));
642 Config->add_instant_xml (node, get_user_ardour_path());
646 ARDOUR_UI::check_memory_locking ()
649 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
653 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path());
655 if (engine->is_realtime() && memory_warning_node == 0) {
657 struct rlimit limits;
659 long pages, page_size;
661 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
664 ram = (int64_t) pages * (int64_t) page_size;
667 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
671 if (limits.rlim_cur != RLIM_INFINITY) {
673 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
676 MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. "
677 "This might cause Ardour to run out of memory before your system "
678 "runs out of memory. \n\n"
679 "You can view the memory limit with 'ulimit -l', "
680 "and it is normally controlled by /etc/security/limits.conf"));
682 VBox* vbox = msg.get_vbox();
684 CheckButton cb (_("Do not show this window again"));
686 cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning));
688 hbox.pack_start (cb, true, false);
689 vbox->pack_start (hbox);
707 if (session->transport_rolling()) {
708 session->request_stop ();
712 if (session->dirty()) {
713 switch (ask_about_saving_session(_("quit"))) {
718 /* use the default name */
719 if (save_state_canfail ("")) {
720 /* failed - don't quit */
721 MessageDialog msg (*editor,
723 Ardour was unable to save your session.\n\n\
724 If you still wish to quit, please use the\n\n\
725 \"Just quit\" option."));
736 session->set_deletion_in_progress ();
740 save_ardour_state ();
745 ARDOUR_UI::ask_about_saving_session (const string & what)
747 ArdourDialog window (_("ardour: save session?"));
748 Gtk::HBox dhbox; // the hbox for the image and text
749 Gtk::Label prompt_label;
750 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
754 msg = string_compose(_("Don't %1"), what);
755 window.add_button (msg, RESPONSE_REJECT);
756 msg = string_compose(_("Just %1"), what);
757 window.add_button (msg, RESPONSE_APPLY);
758 msg = string_compose(_("Save and %1"), what);
759 window.add_button (msg, RESPONSE_ACCEPT);
761 window.set_default_response (RESPONSE_ACCEPT);
763 Gtk::Button noquit_button (msg);
764 noquit_button.set_name ("EditorGTKButton");
769 if (session->snap_name() == session->name()) {
772 type = _("snapshot");
774 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?"),
775 type, session->snap_name());
777 prompt_label.set_text (prompt);
778 prompt_label.set_name (X_("PrompterLabel"));
779 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
781 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
783 dhbox.set_homogeneous (false);
784 dhbox.pack_start (*dimage, false, false, 5);
785 dhbox.pack_start (prompt_label, true, false, 5);
786 window.get_vbox()->pack_start (dhbox);
788 window.set_name (_("Prompter"));
789 window.set_position (Gtk::WIN_POS_MOUSE);
790 window.set_modal (true);
791 window.set_resizable (false);
794 save_the_session = 0;
796 window.set_keep_above (true);
799 ResponseType r = (ResponseType) window.run();
804 case RESPONSE_ACCEPT: // save and get out of here
806 case RESPONSE_APPLY: // get out of here
816 ARDOUR_UI::every_second ()
819 update_buffer_load ();
820 update_disk_space ();
825 ARDOUR_UI::every_point_one_seconds ()
827 update_speed_display ();
828 RapidScreenUpdate(); /* EMIT_SIGNAL */
833 ARDOUR_UI::every_point_zero_one_seconds ()
835 // august 2007: actual update frequency: 40Hz, not 100Hz
837 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
842 ARDOUR_UI::update_sample_rate (nframes_t ignored)
846 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
848 if (!engine->connected()) {
850 snprintf (buf, sizeof (buf), _("disconnected"));
854 nframes_t rate = engine->frame_rate();
856 if (fmod (rate, 1000.0) != 0.0) {
857 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
858 (float) rate/1000.0f,
859 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
861 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
863 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
867 sample_rate_label.set_text (buf);
871 ARDOUR_UI::update_cpu_load ()
874 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
875 cpu_load_label.set_text (buf);
879 ARDOUR_UI::update_buffer_load ()
884 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
885 session->playback_load(), session->capture_load());
886 buffer_load_label.set_text (buf);
888 buffer_load_label.set_text ("");
893 ARDOUR_UI::count_recenabled_streams (Route& route)
895 Track* track = dynamic_cast<Track*>(&route);
896 if (track && track->diskstream()->record_enabled()) {
897 rec_enabled_streams += track->n_inputs();
902 ARDOUR_UI::update_disk_space()
908 nframes_t frames = session->available_capture_duration();
911 if (frames == max_frames) {
912 strcpy (buf, _("Disk: 24hrs+"));
917 nframes_t fr = session->frame_rate();
919 rec_enabled_streams = 0;
920 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
922 if (rec_enabled_streams) {
923 frames /= rec_enabled_streams;
926 hrs = frames / (fr * 3600);
927 frames -= hrs * fr * 3600;
928 mins = frames / (fr * 60);
929 frames -= mins * fr * 60;
932 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
935 disk_space_label.set_text (buf);
939 ARDOUR_UI::update_wall_clock ()
946 tm_now = localtime (&now);
948 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
949 wall_clock_label.set_text (buf);
955 ARDOUR_UI::session_menu (GdkEventButton *ev)
957 session_popup_menu->popup (0, 0);
962 ARDOUR_UI::redisplay_recent_sessions ()
964 vector<string *> *sessions;
965 vector<string *>::iterator i;
966 RecentSessionsSorter cmp;
968 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
969 recent_session_model->clear ();
972 ARDOUR::read_recent_sessions (rs);
975 recent_session_display.set_model (recent_session_model);
979 /* sort them alphabetically */
980 sort (rs.begin(), rs.end(), cmp);
981 sessions = new vector<string*>;
983 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
984 sessions->push_back (new string ((*i).second));
987 for (i = sessions->begin(); i != sessions->end(); ++i) {
989 vector<string*>* states;
990 vector<const gchar*> item;
991 string fullpath = *(*i);
993 /* remove any trailing / */
995 if (fullpath[fullpath.length()-1] == '/') {
996 fullpath = fullpath.substr (0, fullpath.length()-1);
999 /* check whether session still exists */
1000 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1001 /* session doesn't exist */
1002 cerr << "skipping non-existent session " << fullpath << endl;
1006 /* now get available states for this session */
1008 if ((states = Session::possible_states (fullpath)) == 0) {
1009 /* no state file? */
1013 TreeModel::Row row = *(recent_session_model->append());
1015 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1016 row[recent_session_columns.fullpath] = fullpath;
1018 if (states->size() > 1) {
1020 /* add the children */
1022 for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
1024 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1026 child_row[recent_session_columns.visible_name] = **i2;
1027 child_row[recent_session_columns.fullpath] = fullpath;
1036 recent_session_display.set_model (recent_session_model);
1041 ARDOUR_UI::build_session_selector ()
1043 session_selector_window = new ArdourDialog ("session selector");
1045 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1047 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1048 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1049 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1050 recent_session_model = TreeStore::create (recent_session_columns);
1051 recent_session_display.set_model (recent_session_model);
1052 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1053 recent_session_display.set_headers_visible (false);
1054 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1055 recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1057 scroller->add (recent_session_display);
1058 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1060 session_selector_window->set_name ("SessionSelectorWindow");
1061 session_selector_window->set_size_request (200, 400);
1062 session_selector_window->get_vbox()->pack_start (*scroller);
1063 session_selector_window->show_all_children();
1067 ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
1069 session_selector_window->response (RESPONSE_ACCEPT);
1073 ARDOUR_UI::open_recent_session ()
1075 bool can_return = (session != 0);
1077 if (session_selector_window == 0) {
1078 build_session_selector ();
1081 redisplay_recent_sessions ();
1085 session_selector_window->set_position (WIN_POS_MOUSE);
1087 ResponseType r = (ResponseType) session_selector_window->run ();
1090 case RESPONSE_ACCEPT:
1094 session_selector_window->hide();
1101 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1105 session_selector_window->hide();
1107 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1109 if (i == recent_session_model->children().end()) {
1113 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1114 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1116 _session_is_new = false;
1118 if (load_session (path, state) == 0) {
1127 ARDOUR_UI::filter_ardour_session_dirs (const FileFilter::Info& info)
1129 struct stat statbuf;
1131 if (stat (info.filename.c_str(), &statbuf) != 0) {
1135 if (!S_ISDIR(statbuf.st_mode)) {
1141 string session_file = info.filename;
1142 session_file += '/';
1143 session_file += Glib::path_get_basename (info.filename);
1144 session_file += ".ardour";
1146 if (stat (session_file.c_str(), &statbuf) != 0) {
1150 return S_ISREG (statbuf.st_mode);
1154 ARDOUR_UI::check_audioengine ()
1157 if (!engine->connected()) {
1158 MessageDialog msg (_("Ardour is not connected to JACK\n"
1159 "You cannot open or close sessions in this condition"));
1171 ARDOUR_UI::open_session ()
1173 if (!check_audioengine()) {
1177 /* popup selector window */
1179 if (open_session_selector == 0) {
1181 /* ardour sessions are folders */
1183 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
1184 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1185 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1186 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1188 FileFilter session_filter;
1189 session_filter.add_pattern ("*.ardour");
1190 session_filter.set_name (_("Ardour sessions"));
1191 open_session_selector->add_filter (session_filter);
1192 open_session_selector->set_filter (session_filter);
1195 int response = open_session_selector->run();
1196 open_session_selector->hide ();
1199 case RESPONSE_ACCEPT:
1202 open_session_selector->hide();
1206 open_session_selector->hide();
1207 string session_path = open_session_selector->get_filename();
1211 if (session_path.length() > 0) {
1212 if (Session::find_session (session_path, path, name, isnew) == 0) {
1213 _session_is_new = isnew;
1214 load_session (path, name);
1221 ARDOUR_UI::session_add_midi_track ()
1223 cerr << _("Patience is a virtue.\n");
1227 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
1229 list<boost::shared_ptr<AudioTrack> > tracks;
1230 Session::RouteList routes;
1233 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1239 tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
1241 if (tracks.size() != how_many) {
1242 if (how_many == 1) {
1243 error << _("could not create a new audio track") << endmsg;
1245 error << string_compose (_("could only create %1 of %2 new audio %3"),
1246 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1252 routes = session->new_audio_route (input_channels, output_channels, how_many);
1254 if (routes.size() != how_many) {
1255 if (how_many == 1) {
1256 error << _("could not create a new audio track") << endmsg;
1258 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1264 if (need_control_room_outs) {
1270 route->set_stereo_control_outs (control_lr_channels);
1271 route->control_outs()->set_stereo_pan (pans, this);
1273 #endif /* CONTROLOUTS */
1277 MessageDialog msg (*editor,
1278 _("There are insufficient JACK ports available\n\
1279 to create a new track or bus.\n\
1280 You should save Ardour, exit and\n\
1281 restart JACK with more ports."));
1288 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1290 nframes_t _preroll = 0;
1293 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1294 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1296 if (new_position > _preroll) {
1297 new_position -= _preroll;
1302 session->request_locate (new_position);
1307 ARDOUR_UI::transport_goto_start ()
1310 session->goto_start();
1313 /* force displayed area in editor to start no matter
1314 what "follow playhead" setting is.
1318 editor->reset_x_origin (session->current_start_frame());
1324 ARDOUR_UI::transport_goto_zero ()
1327 session->request_locate (0);
1330 /* force displayed area in editor to start no matter
1331 what "follow playhead" setting is.
1335 editor->reset_x_origin (0);
1341 ARDOUR_UI::transport_goto_end ()
1344 nframes_t frame = session->current_end_frame();
1345 session->request_locate (frame);
1347 /* force displayed area in editor to start no matter
1348 what "follow playhead" setting is.
1352 editor->reset_x_origin (frame);
1358 ARDOUR_UI::transport_stop ()
1364 if (session->is_auditioning()) {
1365 session->cancel_audition ();
1369 if (session->get_play_loop ()) {
1370 session->request_play_loop (false);
1373 session->request_stop ();
1377 ARDOUR_UI::transport_stop_and_forget_capture ()
1380 session->request_stop (true);
1385 ARDOUR_UI::remove_last_capture()
1388 editor->remove_last_capture();
1393 ARDOUR_UI::transport_record (bool roll)
1397 switch (session->record_status()) {
1398 case Session::Disabled:
1399 if (session->ntracks() == 0) {
1400 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1404 session->maybe_enable_record ();
1409 case Session::Recording:
1411 session->request_stop();
1413 session->disable_record (false, true);
1417 case Session::Enabled:
1418 session->disable_record (false, true);
1421 cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1425 ARDOUR_UI::transport_roll ()
1433 rolling = session->transport_rolling ();
1435 cerr << "ARDOUR_UI::transport_roll () called session->record_status() = " << session->record_status() << endl;
1437 if (session->get_play_loop()) {
1438 session->request_play_loop (false);
1439 auto_loop_button.set_visual_state (1);
1440 roll_button.set_visual_state (1);
1441 } else if (session->get_play_range ()) {
1442 session->request_play_range (false);
1443 play_selection_button.set_visual_state (0);
1444 } else if (rolling) {
1445 session->request_locate (session->last_transport_start(), true);
1448 session->request_transport_speed (1.0f);
1452 ARDOUR_UI::transport_loop()
1455 if (session->get_play_loop()) {
1456 if (session->transport_rolling()) {
1457 Location * looploc = session->locations()->auto_loop_location();
1459 session->request_locate (looploc->start(), true);
1464 session->request_play_loop (true);
1470 ARDOUR_UI::transport_play_selection ()
1476 if (!session->get_play_range()) {
1477 session->request_stop ();
1480 editor->play_selection ();
1484 ARDOUR_UI::transport_rewind (int option)
1486 float current_transport_speed;
1489 current_transport_speed = session->transport_speed();
1491 if (current_transport_speed >= 0.0f) {
1494 session->request_transport_speed (-1.0f);
1497 session->request_transport_speed (-4.0f);
1500 session->request_transport_speed (-0.5f);
1505 session->request_transport_speed (current_transport_speed * 1.5f);
1511 ARDOUR_UI::transport_forward (int option)
1513 float current_transport_speed;
1516 current_transport_speed = session->transport_speed();
1518 if (current_transport_speed <= 0.0f) {
1521 session->request_transport_speed (1.0f);
1524 session->request_transport_speed (4.0f);
1527 session->request_transport_speed (0.5f);
1532 session->request_transport_speed (current_transport_speed * 1.5f);
1538 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1544 boost::shared_ptr<Route> r;
1546 if ((r = session->route_by_remote_id (dstream)) != 0) {
1550 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1551 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1560 ARDOUR_UI::queue_transport_change ()
1562 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1566 ARDOUR_UI::map_transport_state ()
1568 float sp = session->transport_speed();
1571 transport_rolling ();
1572 } else if (sp < 0.0f) {
1573 transport_rewinding ();
1574 } else if (sp > 0.0f) {
1575 transport_forwarding ();
1577 transport_stopped ();
1582 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1584 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1585 (int) adj.get_value()].c_str());
1589 ARDOUR_UI::engine_stopped ()
1591 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1592 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1593 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1597 ARDOUR_UI::engine_running ()
1599 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1600 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1601 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1603 Glib::RefPtr<Action> action;
1604 const char* action_name = 0;
1606 switch (engine->frames_per_cycle()) {
1608 action_name = X_("JACKLatency32");
1611 action_name = X_("JACKLatency64");
1614 action_name = X_("JACKLatency128");
1617 action_name = X_("JACKLatency512");
1620 action_name = X_("JACKLatency1024");
1623 action_name = X_("JACKLatency2048");
1626 action_name = X_("JACKLatency4096");
1629 action_name = X_("JACKLatency8192");
1632 /* XXX can we do anything useful ? */
1638 action = ActionManager::get_action (X_("JACK"), action_name);
1641 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1642 ract->set_active ();
1648 ARDOUR_UI::engine_halted ()
1650 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1652 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1653 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1655 update_sample_rate (0);
1657 MessageDialog msg (*editor,
1659 JACK has either been shutdown or it\n\
1660 disconnected Ardour because Ardour\n\
1661 was not fast enough. You can save the\n\
1662 session and/or try to reconnect to JACK ."));
1668 ARDOUR_UI::do_engine_start ()
1676 error << _("Unable to start the session running")
1686 ARDOUR_UI::setup_theme ()
1688 theme_manager->setup_theme();
1692 ARDOUR_UI::update_clocks ()
1694 if (!editor || !editor->dragging_playhead()) {
1695 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1700 ARDOUR_UI::start_clocking ()
1702 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1706 ARDOUR_UI::stop_clocking ()
1708 clock_signal_connection.disconnect ();
1712 ARDOUR_UI::toggle_clocking ()
1715 if (clock_button.get_active()) {
1724 ARDOUR_UI::_blink (void *arg)
1727 ((ARDOUR_UI *) arg)->blink ();
1734 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1738 ARDOUR_UI::start_blinking ()
1740 /* Start the blink signal. Everybody with a blinking widget
1741 uses Blink to drive the widget's state.
1744 if (blink_timeout_tag < 0) {
1746 blink_timeout_tag = g_timeout_add (240, _blink, this);
1751 ARDOUR_UI::stop_blinking ()
1753 if (blink_timeout_tag >= 0) {
1754 g_source_remove (blink_timeout_tag);
1755 blink_timeout_tag = -1;
1760 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1766 if (io.n_inputs() == 0) {
1771 /* XXX we're not handling multiple ports yet. */
1773 const char **connections = io.input(0)->get_connections();
1775 if (connections == 0 || connections[0] == '\0') {
1778 buf = connections[0];
1785 if (io.n_outputs() == 0) {
1790 /* XXX we're not handling multiple ports yet. */
1792 const char **connections = io.output(0)->get_connections();
1794 if (connections == 0 || connections[0] == '\0') {
1797 buf = connections[0];
1804 /** Ask the user for the name of a new shapshot and then take it.
1807 ARDOUR_UI::snapshot_session ()
1809 ArdourPrompter prompter (true);
1813 struct tm local_time;
1816 localtime_r (&n, &local_time);
1817 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1819 prompter.set_name ("Prompter");
1820 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1821 prompter.set_prompt (_("Name of New Snapshot"));
1822 prompter.set_initial_text (timebuf);
1824 switch (prompter.run()) {
1825 case RESPONSE_ACCEPT:
1826 prompter.get_result (snapname);
1827 if (snapname.length()){
1828 save_state (snapname);
1838 ARDOUR_UI::save_state (const string & name)
1840 (void) save_state_canfail (name);
1844 ARDOUR_UI::save_state_canfail (string name)
1849 if (name.length() == 0) {
1850 name = session->snap_name();
1853 if ((ret = session->save_state (name)) != 0) {
1857 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1862 ARDOUR_UI::restore_state (string name)
1865 if (name.length() == 0) {
1866 name = session->name();
1868 session->restore_state (name);
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::rec_enable_button_blink (bool onoff, AudioDiskstream *dstream, Widget *w)
1899 if (session && dstream && dstream->record_enabled()) {
1901 Session::RecordState rs;
1903 rs = session->record_status ();
1906 case Session::Disabled:
1907 case Session::Enabled:
1908 if (w->get_state() != STATE_SELECTED) {
1909 w->set_state (STATE_SELECTED);
1913 case Session::Recording:
1914 if (w->get_state() != STATE_ACTIVE) {
1915 w->set_state (STATE_ACTIVE);
1921 if (w->get_state() != STATE_NORMAL) {
1922 w->set_state (STATE_NORMAL);
1928 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
1934 switch (session->record_status()) {
1935 case Session::Enabled:
1937 rec_button.set_visual_state (2);
1939 rec_button.set_visual_state (0);
1943 case Session::Recording:
1944 rec_button.set_visual_state (1);
1948 rec_button.set_visual_state (0);
1954 ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
1962 ARDOUR_UI::save_template ()
1965 ArdourPrompter prompter (true);
1968 if (!check_audioengine()) {
1972 prompter.set_name (X_("Prompter"));
1973 prompter.set_prompt (_("Name for mix template:"));
1974 prompter.set_initial_text(session->name() + _("-template"));
1975 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1977 switch (prompter.run()) {
1978 case RESPONSE_ACCEPT:
1979 prompter.get_result (name);
1981 if (name.length()) {
1982 session->save_template (name);
1992 ARDOUR_UI::fontconfig_dialog ()
1995 /* X11 users will always have fontconfig info around, but new GTK-OSX users
1996 may not and it can take a while to build it. Warn them.
1999 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2001 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2002 MessageDialog msg (*new_session_dialog,
2003 _("Welcome to Ardour.\n\n"
2004 "The program will take a bit longer to start up\n"
2005 "while the system fonts are checked.\n\n"
2006 "This will only be done once, and you will\n"
2007 "not see this message again\n"),
2020 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2022 existing_session = false;
2024 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2025 session_path = cmdline_path;
2026 existing_session = true;
2027 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2028 session_path = Glib::path_get_dirname (string (cmdline_path));
2029 existing_session = true;
2031 /* it doesn't exist, assume the best */
2032 session_path = Glib::path_get_dirname (string (cmdline_path));
2035 session_name = basename_nosuffix (string (cmdline_path));
2039 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2041 /* when this is called, the backend audio system must be running */
2043 /* the main idea here is to deal with the fact that a cmdline argument for the session
2044 can be interpreted in different ways - it could be a directory or a file, and before
2045 we load, we need to know both the session directory and the snapshot (statefile) within it
2046 that we are supposed to use.
2049 if (session_name.length() == 0 || session_path.length() == 0) {
2053 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2055 Glib::ustring predicted_session_file;
2057 predicted_session_file = session_path;
2058 predicted_session_file += '/';
2059 predicted_session_file += session_name;
2060 predicted_session_file += Session::statefile_suffix();
2062 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2063 existing_session = true;
2066 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2068 if (session_path.find (Session::statefile_suffix()) == session_path.length() - 7) {
2069 /* existing .ardour file */
2070 existing_session = true;
2074 existing_session = false;
2077 /* lets just try to load it */
2079 if (create_engine ()) {
2080 backend_audio_error (false, new_session_dialog);
2084 return load_session (session_path, session_name);
2088 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2090 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2092 MessageDialog msg (str,
2094 Gtk::MESSAGE_WARNING,
2095 Gtk::BUTTONS_YES_NO,
2099 msg.set_name (X_("CleanupDialog"));
2100 msg.set_wmclass (X_("existing_session"), "Ardour");
2101 msg.set_position (Gtk::WIN_POS_MOUSE);
2104 switch (msg.run()) {
2113 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2118 AutoConnectOption iconnect;
2119 AutoConnectOption oconnect;
2123 if (Profile->get_sae()) {
2127 iconnect = AutoConnectPhysical;
2128 oconnect = AutoConnectMaster;
2129 nphysin = 0; // use all available
2130 nphysout = 0; // use all available
2134 /* get settings from advanced section of NSD */
2136 if (new_session_dialog->create_control_bus()) {
2137 cchns = (uint32_t) new_session_dialog->control_channel_count();
2142 if (new_session_dialog->create_master_bus()) {
2143 mchns = (uint32_t) new_session_dialog->master_channel_count();
2148 if (new_session_dialog->connect_inputs()) {
2149 iconnect = AutoConnectPhysical;
2151 iconnect = AutoConnectOption (0);
2154 /// @todo some minor tweaks.
2156 if (new_session_dialog->connect_outs_to_master()) {
2157 oconnect = AutoConnectMaster;
2158 } else if (new_session_dialog->connect_outs_to_physical()) {
2159 oconnect = AutoConnectPhysical;
2161 oconnect = AutoConnectOption (0);
2164 nphysin = (uint32_t) new_session_dialog->input_limit_count();
2165 nphysout = (uint32_t) new_session_dialog->output_limit_count();
2168 if (build_session (session_path,
2176 engine->frame_rate() * 60 * 5)) {
2185 ARDOUR_UI::end_loading_messages ()
2191 ARDOUR_UI::loading_message (const std::string& msg)
2194 splash->message (msg);
2199 ARDOUR_UI::idle_load (const Glib::ustring& path)
2202 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2203 /* /path/to/foo => /path/to/foo, foo */
2204 load_session (path, basename_nosuffix (path));
2206 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2207 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2210 ARDOUR_COMMAND_LINE::session_name = path;
2211 if (new_session_dialog) {
2212 /* make it break out of Dialog::run() and
2215 new_session_dialog->response (1);
2221 ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
2223 bool existing_session = false;
2224 Glib::ustring session_name;
2225 Glib::ustring session_path;
2226 Glib::ustring template_name;
2230 response = Gtk::RESPONSE_NONE;
2232 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2234 parse_cmdline_path (ARDOUR_COMMAND_LINE::session_name, session_name, session_path, existing_session);
2236 /* don't ever reuse this */
2238 ARDOUR_COMMAND_LINE::session_name = string();
2240 if (existing_session && backend_audio_is_running) {
2242 /* just load the thing already */
2244 if (load_cmdline_session (session_name, session_path, existing_session) == 0) {
2249 /* make the NSD use whatever information we have */
2251 new_session_dialog->set_session_name (session_name);
2252 new_session_dialog->set_session_folder (session_path);
2255 /* loading failed, or we need the NSD for something */
2257 new_session_dialog->set_modal (false);
2258 new_session_dialog->set_position (WIN_POS_CENTER);
2259 new_session_dialog->set_current_page (0);
2260 new_session_dialog->set_existing_session (existing_session);
2261 new_session_dialog->reset_recent();
2264 new_session_dialog->set_have_engine (backend_audio_is_running);
2265 new_session_dialog->present ();
2266 response = new_session_dialog->run ();
2268 _session_is_new = false;
2270 /* handle possible negative responses */
2274 /* sent by idle_load, meaning restart the whole process again */
2275 new_session_dialog->hide();
2276 new_session_dialog->reset();
2280 case Gtk::RESPONSE_CANCEL:
2281 case Gtk::RESPONSE_DELETE_EVENT:
2285 new_session_dialog->hide ();
2288 case Gtk::RESPONSE_NONE:
2289 /* "Clear" was pressed */
2293 fontconfig_dialog();
2295 if (!backend_audio_is_running) {
2296 if (new_session_dialog->engine_control.setup_engine ()) {
2297 new_session_dialog->hide ();
2302 if (create_engine ()) {
2304 backend_audio_error (!backend_audio_is_running, new_session_dialog);
2307 new_session_dialog->set_existing_session (false);
2308 new_session_dialog->set_current_page (2);
2310 response = Gtk::RESPONSE_NONE;
2314 backend_audio_is_running = true;
2316 if (response == Gtk::RESPONSE_OK) {
2318 session_name = new_session_dialog->session_name();
2320 if (session_name.empty()) {
2321 response = Gtk::RESPONSE_NONE;
2325 /* if the user mistakenly typed path information into the session filename entry,
2326 convert what they typed into a path & a name
2329 if (session_name[0] == '/' ||
2330 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2331 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2333 session_path = Glib::path_get_dirname (session_name);
2334 session_name = Glib::path_get_basename (session_name);
2338 session_path = new_session_dialog->session_folder();
2341 template_name = Glib::ustring();
2342 switch (new_session_dialog->which_page()) {
2344 case NewSessionDialog::OpenPage:
2345 case NewSessionDialog::EnginePage:
2349 case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
2351 should_be_new = true;
2353 //XXX This is needed because session constructor wants a
2354 //non-existant path. hopefully this will be fixed at some point.
2356 session_path = Glib::build_filename (session_path, session_name);
2358 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2360 if (ask_about_loading_existing_session (session_path)) {
2363 response = RESPONSE_NONE;
2368 _session_is_new = true;
2370 if (new_session_dialog->use_session_template()) {
2372 template_name = new_session_dialog->session_template_name();
2376 if (build_session_from_nsd (session_path, session_name)) {
2377 response = RESPONSE_NONE;
2389 new_session_dialog->hide ();
2391 if (load_session (session_path, session_name, template_name)) {
2393 response = Gtk::RESPONSE_NONE;
2397 if (response == Gtk::RESPONSE_NONE) {
2398 new_session_dialog->set_existing_session (false);
2399 new_session_dialog->reset ();
2403 } while (response == Gtk::RESPONSE_NONE);
2407 new_session_dialog->hide();
2408 new_session_dialog->reset();
2409 goto_editor_window ();
2414 ARDOUR_UI::close_session ()
2416 if (!check_audioengine()) {
2420 unload_session (true);
2422 get_session_parameters (true, false);
2426 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2428 Session *new_session;
2432 session_loaded = false;
2434 if (!check_audioengine()) {
2438 unload_status = unload_session ();
2440 if (unload_status < 0) {
2442 } else if (unload_status > 0) {
2447 /* if it already exists, we must have write access */
2449 if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) {
2450 MessageDialog msg (*editor, _("You do not have write access to this session.\n"
2451 "This prevents the session from being loaded."));
2457 loading_message (_("Please wait while Ardour loads your session"));
2460 new_session = new Session (*engine, path, snap_name, mix_template);
2463 /* this one is special */
2465 catch (AudioEngine::PortRegistrationFailure& err) {
2467 MessageDialog msg (err.what(),
2470 Gtk::BUTTONS_OK_CANCEL);
2472 msg.set_title (_("Loading Error"));
2473 msg.set_secondary_text (_("Click the OK button to try again."));
2474 msg.set_position (Gtk::WIN_POS_CENTER);
2478 int response = msg.run ();
2483 case RESPONSE_CANCEL:
2493 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2496 Gtk::BUTTONS_OK_CANCEL);
2498 msg.set_title (_("Loading Error"));
2499 msg.set_secondary_text (_("Click the OK button to try again."));
2500 msg.set_position (Gtk::WIN_POS_CENTER);
2504 int response = msg.run ();
2509 case RESPONSE_CANCEL:
2517 connect_to_session (new_session);
2519 Config->set_current_owner (ConfigVariableBase::Interface);
2521 session_loaded = true;
2523 goto_editor_window ();
2526 session->set_clean ();
2537 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2538 uint32_t control_channels,
2539 uint32_t master_channels,
2540 AutoConnectOption input_connect,
2541 AutoConnectOption output_connect,
2544 nframes_t initial_length)
2546 Session *new_session;
2549 if (!check_audioengine()) {
2553 session_loaded = false;
2555 x = unload_session ();
2563 _session_is_new = true;
2566 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2567 control_channels, master_channels, nphysin, nphysout, initial_length);
2572 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2578 connect_to_session (new_session);
2580 session_loaded = true;
2588 editor->show_window ();
2599 ARDOUR_UI::show_about ()
2603 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2610 ARDOUR_UI::hide_about ()
2613 about->get_window()->set_cursor ();
2619 ARDOUR_UI::about_signal_response(int response)
2625 ARDOUR_UI::show_splash ()
2629 splash = new Splash;
2637 splash->queue_draw ();
2638 splash->get_window()->process_updates (true);
2643 ARDOUR_UI::hide_splash ()
2651 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
2655 removed = rep.paths.size();
2658 MessageDialog msgd (*editor,
2659 _("No audio files were ready for cleanup"),
2662 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2663 msgd.set_secondary_text (_("If this seems suprising, \n\
2664 check for any existing snapshots.\n\
2665 These may still include regions that\n\
2666 require some unused files to continue to exist."));
2672 ArdourDialog results (_("ardour: cleanup"), true, false);
2674 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2675 CleanupResultsModelColumns() {
2679 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2680 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2684 CleanupResultsModelColumns results_columns;
2685 Glib::RefPtr<Gtk::ListStore> results_model;
2686 Gtk::TreeView results_display;
2688 results_model = ListStore::create (results_columns);
2689 results_display.set_model (results_model);
2690 results_display.append_column (list_title, results_columns.visible_name);
2692 results_display.set_name ("CleanupResultsList");
2693 results_display.set_headers_visible (true);
2694 results_display.set_headers_clickable (false);
2695 results_display.set_reorderable (false);
2697 Gtk::ScrolledWindow list_scroller;
2700 Gtk::HBox dhbox; // the hbox for the image and text
2701 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2702 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2704 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2706 if (rep.space < 1048576.0f) {
2708 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2710 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2714 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2716 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2720 dhbox.pack_start (*dimage, true, false, 5);
2721 dhbox.pack_start (txt, true, false, 5);
2723 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2724 TreeModel::Row row = *(results_model->append());
2725 row[results_columns.visible_name] = *i;
2726 row[results_columns.fullpath] = *i;
2729 list_scroller.add (results_display);
2730 list_scroller.set_size_request (-1, 150);
2731 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2733 dvbox.pack_start (dhbox, true, false, 5);
2734 dvbox.pack_start (list_scroller, true, false, 5);
2735 ddhbox.pack_start (dvbox, true, false, 5);
2737 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2738 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2739 results.set_default_response (RESPONSE_CLOSE);
2740 results.set_position (Gtk::WIN_POS_MOUSE);
2741 results.show_all_children ();
2742 results.set_resizable (false);
2749 ARDOUR_UI::cleanup ()
2752 /* shouldn't happen: menu item is insensitive */
2757 MessageDialog checker (_("Are you sure you want to cleanup?"),
2759 Gtk::MESSAGE_QUESTION,
2760 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2762 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2763 ALL undo/redo information will be lost if you cleanup.\n\
2764 After cleanup, unused audio files will be moved to a \
2765 \"dead sounds\" location."));
2767 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2768 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2769 checker.set_default_response (RESPONSE_CANCEL);
2771 checker.set_name (_("CleanupDialog"));
2772 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2773 checker.set_position (Gtk::WIN_POS_MOUSE);
2775 switch (checker.run()) {
2776 case RESPONSE_ACCEPT:
2782 Session::cleanup_report rep;
2784 editor->prepare_for_cleanup ();
2786 /* do not allow flush until a session is reloaded */
2788 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2790 act->set_sensitive (false);
2793 if (session->cleanup_sources (rep)) {
2798 display_cleanup_results (rep,
2801 The following %1 %2 not in use and \n\
2802 have been moved to:\n\
2804 Flushing the wastebasket will \n\
2805 release an additional\n\
2806 %4 %5bytes of disk space.\n"
2814 ARDOUR_UI::flush_trash ()
2817 /* shouldn't happen: menu item is insensitive */
2821 Session::cleanup_report rep;
2823 if (session->cleanup_trash_sources (rep)) {
2827 display_cleanup_results (rep,
2829 _("The following %1 %2 deleted from\n\
2831 releasing %4 %5bytes of disk space"));
2835 ARDOUR_UI::add_route (Gtk::Window* float_window)
2843 if (add_route_dialog == 0) {
2844 add_route_dialog = new AddRouteDialog;
2846 add_route_dialog->set_transient_for (*float_window);
2850 if (add_route_dialog->is_visible()) {
2851 /* we're already doing this */
2855 ResponseType r = (ResponseType) add_route_dialog->run ();
2857 add_route_dialog->hide();
2860 case RESPONSE_ACCEPT:
2867 if ((count = add_route_dialog->count()) <= 0) {
2871 uint32_t input_chan = add_route_dialog->channels ();
2872 uint32_t output_chan;
2873 string name_template = add_route_dialog->name_template ();
2874 bool track = add_route_dialog->track ();
2876 AutoConnectOption oac = Config->get_output_auto_connect();
2878 if (oac & AutoConnectMaster) {
2879 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2881 output_chan = input_chan;
2884 /* XXX do something with name template */
2886 cerr << "Adding with " << input_chan << " in and " << output_chan << "out\n";
2889 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
2891 session_add_audio_bus (input_chan, output_chan, count);
2896 ARDOUR_UI::mixer_settings () const
2901 node = session->instant_xml(X_("Mixer"), session->path());
2903 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
2907 node = new XMLNode (X_("Mixer"));
2914 ARDOUR_UI::editor_settings () const
2919 node = session->instant_xml(X_("Editor"), session->path());
2921 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
2925 node = new XMLNode (X_("Editor"));
2931 ARDOUR_UI::keyboard_settings () const
2935 node = Config->extra_xml(X_("Keyboard"));
2938 node = new XMLNode (X_("Keyboard"));
2944 ARDOUR_UI::create_xrun_marker(nframes_t where)
2946 ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::create_xrun_marker), where));
2947 editor->mouse_add_new_marker (where, false, true);
2951 ARDOUR_UI::halt_on_xrun_message ()
2953 MessageDialog msg (*editor,
2954 _("Recording was stopped because your system could not keep up."));
2959 ARDOUR_UI::xrun_handler(nframes_t where)
2961 if (Config->get_create_xrun_marker() && session->actively_recording()) {
2962 create_xrun_marker(where);
2965 if (Config->get_stop_recording_on_xrun() && session->actively_recording()) {
2966 halt_on_xrun_message ();
2971 ARDOUR_UI::disk_overrun_handler ()
2973 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
2975 if (!have_disk_speed_dialog_displayed) {
2976 have_disk_speed_dialog_displayed = true;
2977 MessageDialog* msg = new MessageDialog (*editor, _("\
2978 The disk system on your computer\n\
2979 was not able to keep up with Ardour.\n\
2981 Specifically, it failed to write data to disk\n\
2982 quickly enough to keep up with recording.\n"));
2983 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
2989 ARDOUR_UI::disk_underrun_handler ()
2991 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2993 if (!have_disk_speed_dialog_displayed) {
2994 have_disk_speed_dialog_displayed = true;
2995 MessageDialog* msg = new MessageDialog (*editor,
2996 _("The disk system on your computer\n\
2997 was not able to keep up with Ardour.\n\
2999 Specifically, it failed to read data from disk\n\
3000 quickly enough to keep up with playback.\n"));
3001 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3007 ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
3009 have_disk_speed_dialog_displayed = false;
3014 ARDOUR_UI::pending_state_dialog ()
3016 HBox* hbox = new HBox();
3017 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3018 ArdourDialog dialog (_("Crash Recovery"), true);
3020 This session appears to have been in\n\
3021 middle of recording when ardour or\n\
3022 the computer was shutdown.\n\
3024 Ardour can recover any captured audio for\n\
3025 you, or it can ignore it. Please decide\n\
3026 what you would like to do.\n"));
3027 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3028 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3029 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3030 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3031 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3032 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3033 dialog.set_default_response (RESPONSE_ACCEPT);
3034 dialog.set_position (WIN_POS_CENTER);
3039 switch (dialog.run ()) {
3040 case RESPONSE_ACCEPT:
3048 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3050 HBox* hbox = new HBox();
3051 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3052 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3053 Label message (string_compose (_("\
3054 This session was created with a sample rate of %1 Hz\n\
3056 The audioengine is currently running at %2 Hz\n"), desired, actual));
3058 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3059 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3060 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3061 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3062 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3063 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3064 dialog.set_default_response (RESPONSE_ACCEPT);
3065 dialog.set_position (WIN_POS_CENTER);
3070 switch (dialog.run ()) {
3071 case RESPONSE_ACCEPT:
3080 ARDOUR_UI::disconnect_from_jack ()
3083 if( engine->disconnect_from_jack ()) {
3084 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3088 update_sample_rate (0);
3093 ARDOUR_UI::reconnect_to_jack ()
3096 if (engine->reconnect_to_jack ()) {
3097 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3101 update_sample_rate (0);
3106 ARDOUR_UI::use_config ()
3108 Glib::RefPtr<Action> act;
3110 switch (Config->get_native_file_data_format ()) {
3112 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
3115 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
3118 act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit"));
3123 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3124 ract->set_active ();
3127 switch (Config->get_native_file_header_format ()) {
3129 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
3132 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
3135 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
3138 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
3141 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
3144 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
3147 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
3152 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3153 ract->set_active ();
3156 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3158 set_transport_controllable_state (*node);
3163 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3165 if (Config->get_primary_clock_delta_edit_cursor()) {
3166 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3168 primary_clock.set (pos, 0, true);
3171 if (Config->get_secondary_clock_delta_edit_cursor()) {
3172 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3174 secondary_clock.set (pos);
3177 if (big_clock_window) {
3178 big_clock.set (pos);
3183 ARDOUR_UI::record_state_changed ()
3185 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3187 if (!session || !big_clock_window) {
3188 /* why bother - the clock isn't visible */
3192 switch (session->record_status()) {
3193 case Session::Recording:
3194 big_clock.set_widget_name ("BigClockRecording");
3197 big_clock.set_widget_name ("BigClockNonRecording");
3203 ARDOUR_UI::first_idle ()
3206 session->allow_auto_play (true);
3210 editor->first_idle();
3213 Keyboard::set_can_save_keybindings (true);
3218 ARDOUR_UI::store_clock_modes ()
3220 XMLNode* node = new XMLNode(X_("ClockModes"));
3222 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3223 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3226 session->add_extra_xml (*node);
3227 session->set_dirty ();
3232 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3233 : Controllable (name), ui (u), type(tp)
3239 ARDOUR_UI::TransportControllable::set_value (float val)
3241 if (type == ShuttleControl) {
3248 fract = -((0.5f - val)/0.5f);
3250 fract = ((val - 0.5f)/0.5f);
3254 ui.set_shuttle_fract (fract);
3259 /* do nothing: these are radio-style actions */
3263 const char *action = 0;
3267 action = X_("Roll");
3270 action = X_("Stop");
3273 action = X_("Goto Start");
3276 action = X_("Goto End");
3279 action = X_("Loop");
3282 action = X_("Play Selection");
3285 action = X_("Record");
3295 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3303 ARDOUR_UI::TransportControllable::get_value (void) const
3322 case ShuttleControl:
3332 ARDOUR_UI::TransportControllable::set_id (const string& str)
3338 ARDOUR_UI::setup_profile ()
3340 if (gdk_screen_width() < 1200) {
3341 Profile->set_small_screen ();
3344 if (getenv ("ARDOUR_SAE")) {
3345 Profile->set_sae ();
3346 Profile->set_single_package ();