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 ();
751 save_ardour_state ();
756 ARDOUR_UI::ask_about_saving_session (const string & what)
758 ArdourDialog window (_("ardour: save session?"));
759 Gtk::HBox dhbox; // the hbox for the image and text
760 Gtk::Label prompt_label;
761 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
765 msg = string_compose(_("Don't %1"), what);
766 window.add_button (msg, RESPONSE_REJECT);
767 msg = string_compose(_("Just %1"), what);
768 window.add_button (msg, RESPONSE_APPLY);
769 msg = string_compose(_("Save and %1"), what);
770 window.add_button (msg, RESPONSE_ACCEPT);
772 window.set_default_response (RESPONSE_ACCEPT);
774 Gtk::Button noquit_button (msg);
775 noquit_button.set_name ("EditorGTKButton");
780 if (session->snap_name() == session->name()) {
783 type = _("snapshot");
785 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?"),
786 type, session->snap_name());
788 prompt_label.set_text (prompt);
789 prompt_label.set_name (X_("PrompterLabel"));
790 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
792 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
794 dhbox.set_homogeneous (false);
795 dhbox.pack_start (*dimage, false, false, 5);
796 dhbox.pack_start (prompt_label, true, false, 5);
797 window.get_vbox()->pack_start (dhbox);
799 window.set_name (_("Prompter"));
800 window.set_position (Gtk::WIN_POS_MOUSE);
801 window.set_modal (true);
802 window.set_resizable (false);
805 window.set_keep_above (true);
808 ResponseType r = (ResponseType) window.run();
813 case RESPONSE_ACCEPT: // save and get out of here
815 case RESPONSE_APPLY: // get out of here
825 ARDOUR_UI::every_second ()
828 update_buffer_load ();
829 update_disk_space ();
834 ARDOUR_UI::every_point_one_seconds ()
836 update_speed_display ();
837 RapidScreenUpdate(); /* EMIT_SIGNAL */
842 ARDOUR_UI::every_point_zero_one_seconds ()
844 // august 2007: actual update frequency: 40Hz, not 100Hz
846 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
851 ARDOUR_UI::update_sample_rate (nframes_t ignored)
855 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
857 if (!engine->connected()) {
859 snprintf (buf, sizeof (buf), _("disconnected"));
863 nframes_t rate = engine->frame_rate();
865 if (fmod (rate, 1000.0) != 0.0) {
866 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
867 (float) rate/1000.0f,
868 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
870 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
872 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
876 sample_rate_label.set_text (buf);
880 ARDOUR_UI::update_cpu_load ()
883 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
884 cpu_load_label.set_text (buf);
888 ARDOUR_UI::update_buffer_load ()
893 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
894 session->playback_load(), session->capture_load());
895 buffer_load_label.set_text (buf);
897 buffer_load_label.set_text ("");
902 ARDOUR_UI::count_recenabled_streams (Route& route)
904 Track* track = dynamic_cast<Track*>(&route);
905 if (track && track->diskstream()->record_enabled()) {
906 rec_enabled_streams += track->n_inputs();
911 ARDOUR_UI::update_disk_space()
917 nframes_t frames = session->available_capture_duration();
920 if (frames == max_frames) {
921 strcpy (buf, _("Disk: 24hrs+"));
926 nframes_t fr = session->frame_rate();
928 rec_enabled_streams = 0;
929 session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
931 if (rec_enabled_streams) {
932 frames /= rec_enabled_streams;
935 hrs = frames / (fr * 3600);
936 frames -= hrs * fr * 3600;
937 mins = frames / (fr * 60);
938 frames -= mins * fr * 60;
941 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
944 disk_space_label.set_text (buf);
948 ARDOUR_UI::update_wall_clock ()
955 tm_now = localtime (&now);
957 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
958 wall_clock_label.set_text (buf);
964 ARDOUR_UI::session_menu (GdkEventButton *ev)
966 session_popup_menu->popup (0, 0);
971 ARDOUR_UI::redisplay_recent_sessions ()
973 vector<string *> *sessions;
974 vector<string *>::iterator i;
975 RecentSessionsSorter cmp;
977 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
978 recent_session_model->clear ();
981 ARDOUR::read_recent_sessions (rs);
984 recent_session_display.set_model (recent_session_model);
988 /* sort them alphabetically */
989 sort (rs.begin(), rs.end(), cmp);
990 sessions = new vector<string*>;
992 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
993 sessions->push_back (new string ((*i).second));
996 for (i = sessions->begin(); i != sessions->end(); ++i) {
998 vector<string*>* states;
999 vector<const gchar*> item;
1000 string fullpath = *(*i);
1002 /* remove any trailing / */
1004 if (fullpath[fullpath.length()-1] == '/') {
1005 fullpath = fullpath.substr (0, fullpath.length()-1);
1008 /* check whether session still exists */
1009 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1010 /* session doesn't exist */
1011 cerr << "skipping non-existent session " << fullpath << endl;
1015 /* now get available states for this session */
1017 if ((states = Session::possible_states (fullpath)) == 0) {
1018 /* no state file? */
1022 TreeModel::Row row = *(recent_session_model->append());
1024 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1025 row[recent_session_columns.fullpath] = fullpath;
1027 if (states->size() > 1) {
1029 /* add the children */
1031 for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
1033 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1035 child_row[recent_session_columns.visible_name] = **i2;
1036 child_row[recent_session_columns.fullpath] = fullpath;
1045 recent_session_display.set_model (recent_session_model);
1050 ARDOUR_UI::build_session_selector ()
1052 session_selector_window = new ArdourDialog ("session selector");
1054 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1056 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1057 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1058 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1059 recent_session_model = TreeStore::create (recent_session_columns);
1060 recent_session_display.set_model (recent_session_model);
1061 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1062 recent_session_display.set_headers_visible (false);
1063 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1064 recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1066 scroller->add (recent_session_display);
1067 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1069 session_selector_window->set_name ("SessionSelectorWindow");
1070 session_selector_window->set_size_request (200, 400);
1071 session_selector_window->get_vbox()->pack_start (*scroller);
1072 session_selector_window->show_all_children();
1076 ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col)
1078 session_selector_window->response (RESPONSE_ACCEPT);
1082 ARDOUR_UI::open_recent_session ()
1084 bool can_return = (session != 0);
1086 if (session_selector_window == 0) {
1087 build_session_selector ();
1090 redisplay_recent_sessions ();
1094 session_selector_window->set_position (WIN_POS_MOUSE);
1096 ResponseType r = (ResponseType) session_selector_window->run ();
1099 case RESPONSE_ACCEPT:
1103 session_selector_window->hide();
1110 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1114 session_selector_window->hide();
1116 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1118 if (i == recent_session_model->children().end()) {
1122 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1123 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1125 _session_is_new = false;
1127 if (load_session (path, state) == 0) {
1136 ARDOUR_UI::check_audioengine ()
1139 if (!engine->connected()) {
1140 MessageDialog msg (_("Ardour is not connected to JACK\n"
1141 "You cannot open or close sessions in this condition"));
1153 ARDOUR_UI::open_session ()
1155 if (!check_audioengine()) {
1159 /* popup selector window */
1161 if (open_session_selector == 0) {
1163 /* ardour sessions are folders */
1165 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
1166 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1167 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1168 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1170 FileFilter session_filter;
1171 session_filter.add_pattern ("*.ardour");
1172 session_filter.set_name (_("Ardour sessions"));
1173 open_session_selector->add_filter (session_filter);
1174 open_session_selector->set_filter (session_filter);
1177 int response = open_session_selector->run();
1178 open_session_selector->hide ();
1181 case RESPONSE_ACCEPT:
1184 open_session_selector->hide();
1188 open_session_selector->hide();
1189 string session_path = open_session_selector->get_filename();
1193 if (session_path.length() > 0) {
1194 if (Session::find_session (session_path, path, name, isnew) == 0) {
1195 _session_is_new = isnew;
1196 load_session (path, name);
1203 ARDOUR_UI::session_add_midi_track ()
1205 cerr << _("Patience is a virtue.\n");
1209 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
1211 list<boost::shared_ptr<AudioTrack> > tracks;
1212 Session::RouteList routes;
1215 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1221 tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
1223 if (tracks.size() != how_many) {
1224 if (how_many == 1) {
1225 error << _("could not create a new audio track") << endmsg;
1227 error << string_compose (_("could only create %1 of %2 new audio %3"),
1228 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1234 routes = session->new_audio_route (input_channels, output_channels, how_many);
1236 if (routes.size() != how_many) {
1237 if (how_many == 1) {
1238 error << _("could not create a new audio track") << endmsg;
1240 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1246 if (need_control_room_outs) {
1252 route->set_stereo_control_outs (control_lr_channels);
1253 route->control_outs()->set_stereo_pan (pans, this);
1255 #endif /* CONTROLOUTS */
1259 MessageDialog msg (*editor,
1260 _("There are insufficient JACK ports available\n\
1261 to create a new track or bus.\n\
1262 You should save Ardour, exit and\n\
1263 restart JACK with more ports."));
1270 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1272 nframes_t _preroll = 0;
1275 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1276 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1278 if (new_position > _preroll) {
1279 new_position -= _preroll;
1284 session->request_locate (new_position);
1289 ARDOUR_UI::transport_goto_start ()
1292 session->goto_start();
1295 /* force displayed area in editor to start no matter
1296 what "follow playhead" setting is.
1300 editor->reset_x_origin (session->current_start_frame());
1306 ARDOUR_UI::transport_goto_zero ()
1309 session->request_locate (0);
1312 /* force displayed area in editor to start no matter
1313 what "follow playhead" setting is.
1317 editor->reset_x_origin (0);
1323 ARDOUR_UI::transport_goto_wallclock ()
1325 if (session && editor) {
1332 localtime_r (&now, &tmnow);
1334 frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
1335 frames += tmnow.tm_min * (60 * session->frame_rate());
1336 frames += tmnow.tm_sec * session->frame_rate();
1338 session->request_locate (frames);
1340 /* force displayed area in editor to start no matter
1341 what "follow playhead" setting is.
1345 editor->reset_x_origin (frames - (editor->current_page_frames()/2));
1351 ARDOUR_UI::transport_goto_end ()
1354 nframes_t frame = session->current_end_frame();
1355 session->request_locate (frame);
1357 /* force displayed area in editor to start no matter
1358 what "follow playhead" setting is.
1362 editor->reset_x_origin (frame);
1368 ARDOUR_UI::transport_stop ()
1374 if (session->is_auditioning()) {
1375 session->cancel_audition ();
1379 if (session->get_play_loop ()) {
1380 session->request_play_loop (false);
1383 session->request_stop ();
1387 ARDOUR_UI::transport_stop_and_forget_capture ()
1390 session->request_stop (true);
1395 ARDOUR_UI::remove_last_capture()
1398 editor->remove_last_capture();
1403 ARDOUR_UI::transport_record (bool roll)
1407 switch (session->record_status()) {
1408 case Session::Disabled:
1409 if (session->ntracks() == 0) {
1410 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1414 session->maybe_enable_record ();
1419 case Session::Recording:
1421 session->request_stop();
1423 session->disable_record (false, true);
1427 case Session::Enabled:
1428 session->disable_record (false, true);
1431 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1435 ARDOUR_UI::transport_roll ()
1443 rolling = session->transport_rolling ();
1445 //cerr << "ARDOUR_UI::transport_roll () called session->record_status() = " << session->record_status() << endl;
1447 if (session->get_play_loop()) {
1448 session->request_play_loop (false);
1449 auto_loop_button.set_visual_state (1);
1450 roll_button.set_visual_state (1);
1451 } else if (session->get_play_range ()) {
1452 session->request_play_range (false);
1453 play_selection_button.set_visual_state (0);
1454 } else if (rolling) {
1455 session->request_locate (session->last_transport_start(), true);
1458 session->request_transport_speed (1.0f);
1462 ARDOUR_UI::transport_loop()
1465 if (session->get_play_loop()) {
1466 if (session->transport_rolling()) {
1467 Location * looploc = session->locations()->auto_loop_location();
1469 session->request_locate (looploc->start(), true);
1474 session->request_play_loop (true);
1480 ARDOUR_UI::transport_play_selection ()
1486 if (!session->get_play_range()) {
1487 session->request_stop ();
1490 editor->play_selection ();
1494 ARDOUR_UI::transport_rewind (int option)
1496 float current_transport_speed;
1499 current_transport_speed = session->transport_speed();
1501 if (current_transport_speed >= 0.0f) {
1504 session->request_transport_speed (-1.0f);
1507 session->request_transport_speed (-4.0f);
1510 session->request_transport_speed (-0.5f);
1515 session->request_transport_speed (current_transport_speed * 1.5f);
1521 ARDOUR_UI::transport_forward (int option)
1523 float current_transport_speed;
1526 current_transport_speed = session->transport_speed();
1528 if (current_transport_speed <= 0.0f) {
1531 session->request_transport_speed (1.0f);
1534 session->request_transport_speed (4.0f);
1537 session->request_transport_speed (0.5f);
1542 session->request_transport_speed (current_transport_speed * 1.5f);
1548 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1554 boost::shared_ptr<Route> r;
1556 if ((r = session->route_by_remote_id (dstream)) != 0) {
1560 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1561 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1570 ARDOUR_UI::queue_transport_change ()
1572 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1576 ARDOUR_UI::map_transport_state ()
1578 float sp = session->transport_speed();
1581 transport_rolling ();
1582 } else if (sp < 0.0f) {
1583 transport_rewinding ();
1584 } else if (sp > 0.0f) {
1585 transport_forwarding ();
1587 transport_stopped ();
1592 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1594 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1595 (int) adj.get_value()].c_str());
1599 ARDOUR_UI::engine_stopped ()
1601 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1602 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1603 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1607 ARDOUR_UI::engine_running ()
1609 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1610 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1611 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1613 Glib::RefPtr<Action> action;
1614 const char* action_name = 0;
1616 switch (engine->frames_per_cycle()) {
1618 action_name = X_("JACKLatency32");
1621 action_name = X_("JACKLatency64");
1624 action_name = X_("JACKLatency128");
1627 action_name = X_("JACKLatency512");
1630 action_name = X_("JACKLatency1024");
1633 action_name = X_("JACKLatency2048");
1636 action_name = X_("JACKLatency4096");
1639 action_name = X_("JACKLatency8192");
1642 /* XXX can we do anything useful ? */
1648 action = ActionManager::get_action (X_("JACK"), action_name);
1651 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1652 ract->set_active ();
1658 ARDOUR_UI::engine_halted ()
1660 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1662 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1663 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1665 update_sample_rate (0);
1667 MessageDialog msg (*editor,
1669 JACK has either been shutdown or it\n\
1670 disconnected Ardour because Ardour\n\
1671 was not fast enough. Try to restart\n\
1672 JACK, reconnect and save the session."));
1678 ARDOUR_UI::do_engine_start ()
1686 error << _("Unable to start the session running")
1696 ARDOUR_UI::setup_theme ()
1698 theme_manager->setup_theme();
1702 ARDOUR_UI::update_clocks ()
1704 if (!editor || !editor->dragging_playhead()) {
1705 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1710 ARDOUR_UI::start_clocking ()
1712 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1716 ARDOUR_UI::stop_clocking ()
1718 clock_signal_connection.disconnect ();
1722 ARDOUR_UI::toggle_clocking ()
1725 if (clock_button.get_active()) {
1734 ARDOUR_UI::_blink (void *arg)
1737 ((ARDOUR_UI *) arg)->blink ();
1744 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1748 ARDOUR_UI::start_blinking ()
1750 /* Start the blink signal. Everybody with a blinking widget
1751 uses Blink to drive the widget's state.
1754 if (blink_timeout_tag < 0) {
1756 blink_timeout_tag = g_timeout_add (240, _blink, this);
1761 ARDOUR_UI::stop_blinking ()
1763 if (blink_timeout_tag >= 0) {
1764 g_source_remove (blink_timeout_tag);
1765 blink_timeout_tag = -1;
1770 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1776 if (io.n_inputs() == 0) {
1781 /* XXX we're not handling multiple ports yet. */
1783 const char **connections = io.input(0)->get_connections();
1785 if (connections == 0 || connections[0] == '\0') {
1788 buf = connections[0];
1795 if (io.n_outputs() == 0) {
1800 /* XXX we're not handling multiple ports yet. */
1802 const char **connections = io.output(0)->get_connections();
1804 if (connections == 0 || connections[0] == '\0') {
1807 buf = connections[0];
1814 /** Ask the user for the name of a new shapshot and then take it.
1817 ARDOUR_UI::snapshot_session ()
1819 ArdourPrompter prompter (true);
1823 struct tm local_time;
1826 localtime_r (&n, &local_time);
1827 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1829 prompter.set_name ("Prompter");
1830 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1831 prompter.set_prompt (_("Name of New Snapshot"));
1832 prompter.set_initial_text (timebuf);
1834 switch (prompter.run()) {
1835 case RESPONSE_ACCEPT:
1836 prompter.get_result (snapname);
1837 if (snapname.length()){
1838 save_state (snapname);
1848 ARDOUR_UI::save_state (const string & name)
1850 (void) save_state_canfail (name);
1854 ARDOUR_UI::save_state_canfail (string name)
1859 if (name.length() == 0) {
1860 name = session->snap_name();
1863 if ((ret = session->save_state (name)) != 0) {
1867 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1872 ARDOUR_UI::primary_clock_value_changed ()
1875 session->request_locate (primary_clock.current_time ());
1880 ARDOUR_UI::big_clock_value_changed ()
1883 session->request_locate (big_clock.current_time ());
1888 ARDOUR_UI::secondary_clock_value_changed ()
1891 session->request_locate (secondary_clock.current_time ());
1896 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
1902 switch (session->record_status()) {
1903 case Session::Enabled:
1905 rec_button.set_visual_state (2);
1907 rec_button.set_visual_state (0);
1911 case Session::Recording:
1912 rec_button.set_visual_state (1);
1916 rec_button.set_visual_state (0);
1922 ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
1930 ARDOUR_UI::save_template ()
1933 ArdourPrompter prompter (true);
1936 if (!check_audioengine()) {
1940 prompter.set_name (X_("Prompter"));
1941 prompter.set_prompt (_("Name for mix template:"));
1942 prompter.set_initial_text(session->name() + _("-template"));
1943 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1945 switch (prompter.run()) {
1946 case RESPONSE_ACCEPT:
1947 prompter.get_result (name);
1949 if (name.length()) {
1950 session->save_template (name);
1960 ARDOUR_UI::fontconfig_dialog ()
1963 /* X11 users will always have fontconfig info around, but new GTK-OSX users
1964 may not and it can take a while to build it. Warn them.
1967 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
1969 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
1970 MessageDialog msg (*new_session_dialog,
1971 _("Welcome to Ardour.\n\n"
1972 "The program will take a bit longer to start up\n"
1973 "while the system fonts are checked.\n\n"
1974 "This will only be done once, and you will\n"
1975 "not see this message again\n"),
1988 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
1990 existing_session = false;
1992 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
1993 session_path = cmdline_path;
1994 existing_session = true;
1995 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
1996 session_path = Glib::path_get_dirname (string (cmdline_path));
1997 existing_session = true;
1999 /* it doesn't exist, assume the best */
2000 session_path = Glib::path_get_dirname (string (cmdline_path));
2003 session_name = basename_nosuffix (string (cmdline_path));
2007 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2009 /* when this is called, the backend audio system must be running */
2011 /* the main idea here is to deal with the fact that a cmdline argument for the session
2012 can be interpreted in different ways - it could be a directory or a file, and before
2013 we load, we need to know both the session directory and the snapshot (statefile) within it
2014 that we are supposed to use.
2017 if (session_name.length() == 0 || session_path.length() == 0) {
2021 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2023 Glib::ustring predicted_session_file;
2025 predicted_session_file = session_path;
2026 predicted_session_file += '/';
2027 predicted_session_file += session_name;
2028 predicted_session_file += Session::statefile_suffix();
2030 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2031 existing_session = true;
2034 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2036 if (session_path.find (Session::statefile_suffix()) == session_path.length() - 7) {
2037 /* existing .ardour file */
2038 existing_session = true;
2042 existing_session = false;
2045 /* lets just try to load it */
2047 if (create_engine ()) {
2048 backend_audio_error (false, new_session_dialog);
2052 return load_session (session_path, session_name);
2056 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2058 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2060 MessageDialog msg (str,
2062 Gtk::MESSAGE_WARNING,
2063 Gtk::BUTTONS_YES_NO,
2067 msg.set_name (X_("CleanupDialog"));
2068 msg.set_wmclass (X_("existing_session"), "Ardour");
2069 msg.set_position (Gtk::WIN_POS_MOUSE);
2072 switch (msg.run()) {
2081 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2086 AutoConnectOption iconnect;
2087 AutoConnectOption oconnect;
2091 if (Profile->get_sae()) {
2095 iconnect = AutoConnectPhysical;
2096 oconnect = AutoConnectMaster;
2097 nphysin = 0; // use all available
2098 nphysout = 0; // use all available
2102 /* get settings from advanced section of NSD */
2104 if (new_session_dialog->create_control_bus()) {
2105 cchns = (uint32_t) new_session_dialog->control_channel_count();
2110 if (new_session_dialog->create_master_bus()) {
2111 mchns = (uint32_t) new_session_dialog->master_channel_count();
2116 if (new_session_dialog->connect_inputs()) {
2117 iconnect = AutoConnectPhysical;
2119 iconnect = AutoConnectOption (0);
2122 /// @todo some minor tweaks.
2124 if (new_session_dialog->connect_outs_to_master()) {
2125 oconnect = AutoConnectMaster;
2126 } else if (new_session_dialog->connect_outs_to_physical()) {
2127 oconnect = AutoConnectPhysical;
2129 oconnect = AutoConnectOption (0);
2132 nphysin = (uint32_t) new_session_dialog->input_limit_count();
2133 nphysout = (uint32_t) new_session_dialog->output_limit_count();
2136 if (build_session (session_path,
2144 engine->frame_rate() * 60 * 5)) {
2153 ARDOUR_UI::end_loading_messages ()
2159 ARDOUR_UI::loading_message (const std::string& msg)
2162 splash->message (msg);
2167 ARDOUR_UI::idle_load (const Glib::ustring& path)
2170 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2171 /* /path/to/foo => /path/to/foo, foo */
2172 load_session (path, basename_nosuffix (path));
2174 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2175 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2178 ARDOUR_COMMAND_LINE::session_name = path;
2179 if (new_session_dialog) {
2180 /* make it break out of Dialog::run() and
2183 new_session_dialog->response (1);
2189 ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
2191 bool existing_session = false;
2192 Glib::ustring session_name;
2193 Glib::ustring session_path;
2194 Glib::ustring template_name;
2198 response = Gtk::RESPONSE_NONE;
2200 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2202 parse_cmdline_path (ARDOUR_COMMAND_LINE::session_name, session_name, session_path, existing_session);
2204 /* don't ever reuse this */
2206 ARDOUR_COMMAND_LINE::session_name = string();
2208 if (existing_session && backend_audio_is_running) {
2210 /* just load the thing already */
2212 if (load_cmdline_session (session_name, session_path, existing_session) == 0) {
2217 /* make the NSD use whatever information we have */
2219 new_session_dialog->set_session_name (session_name);
2220 new_session_dialog->set_session_folder (session_path);
2223 /* loading failed, or we need the NSD for something */
2225 new_session_dialog->set_modal (false);
2226 new_session_dialog->set_position (WIN_POS_CENTER);
2227 new_session_dialog->set_current_page (0);
2228 new_session_dialog->set_existing_session (existing_session);
2229 new_session_dialog->reset_recent();
2232 new_session_dialog->set_have_engine (backend_audio_is_running);
2233 new_session_dialog->present ();
2234 response = new_session_dialog->run ();
2236 _session_is_new = false;
2238 /* handle possible negative responses */
2242 /* sent by idle_load, meaning restart the whole process again */
2243 new_session_dialog->hide();
2244 new_session_dialog->reset();
2248 case Gtk::RESPONSE_CANCEL:
2249 case Gtk::RESPONSE_DELETE_EVENT:
2253 new_session_dialog->hide ();
2256 case Gtk::RESPONSE_NONE:
2257 /* "Clear" was pressed */
2261 fontconfig_dialog();
2263 if (!backend_audio_is_running) {
2264 int ret = new_session_dialog->engine_control.setup_engine ();
2267 } else if (ret > 0) {
2268 response = Gtk::RESPONSE_REJECT;
2273 if (create_engine ()) {
2275 backend_audio_error (!backend_audio_is_running, new_session_dialog);
2278 new_session_dialog->set_existing_session (false);
2279 new_session_dialog->set_current_page (2);
2281 response = Gtk::RESPONSE_NONE;
2285 backend_audio_is_running = true;
2287 if (response == Gtk::RESPONSE_OK) {
2289 session_name = new_session_dialog->session_name();
2291 if (session_name.empty()) {
2292 response = Gtk::RESPONSE_NONE;
2296 /* if the user mistakenly typed path information into the session filename entry,
2297 convert what they typed into a path & a name
2300 if (session_name[0] == '/' ||
2301 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2302 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2304 session_path = Glib::path_get_dirname (session_name);
2305 session_name = Glib::path_get_basename (session_name);
2309 session_path = new_session_dialog->session_folder();
2312 template_name = Glib::ustring();
2313 switch (new_session_dialog->which_page()) {
2315 case NewSessionDialog::OpenPage:
2316 case NewSessionDialog::EnginePage:
2320 case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
2322 should_be_new = true;
2324 //XXX This is needed because session constructor wants a
2325 //non-existant path. hopefully this will be fixed at some point.
2327 session_path = Glib::build_filename (session_path, session_name);
2329 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2331 if (ask_about_loading_existing_session (session_path)) {
2334 response = RESPONSE_NONE;
2339 _session_is_new = true;
2341 if (new_session_dialog->use_session_template()) {
2343 template_name = new_session_dialog->session_template_name();
2347 if (build_session_from_nsd (session_path, session_name)) {
2348 response = RESPONSE_NONE;
2360 new_session_dialog->hide ();
2362 if (load_session (session_path, session_name, template_name)) {
2364 response = Gtk::RESPONSE_NONE;
2368 if (response == Gtk::RESPONSE_NONE) {
2369 new_session_dialog->set_existing_session (false);
2370 new_session_dialog->reset ();
2374 } while (response == Gtk::RESPONSE_NONE || response == Gtk::RESPONSE_REJECT);
2378 new_session_dialog->hide();
2379 new_session_dialog->reset();
2380 goto_editor_window ();
2385 ARDOUR_UI::close_session ()
2387 if (!check_audioengine()) {
2391 unload_session (true);
2393 get_session_parameters (true, false);
2397 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2399 Session *new_session;
2403 session_loaded = false;
2405 if (!check_audioengine()) {
2409 unload_status = unload_session ();
2411 if (unload_status < 0) {
2413 } else if (unload_status > 0) {
2418 /* if it already exists, we must have write access */
2420 if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) {
2421 MessageDialog msg (*editor, _("You do not have write access to this session.\n"
2422 "This prevents the session from being loaded."));
2428 loading_message (_("Please wait while Ardour loads your session"));
2431 new_session = new Session (*engine, path, snap_name, mix_template);
2434 /* this one is special */
2436 catch (AudioEngine::PortRegistrationFailure& err) {
2438 MessageDialog msg (err.what(),
2441 Gtk::BUTTONS_OK_CANCEL);
2443 msg.set_title (_("Loading Error"));
2444 msg.set_secondary_text (_("Click the OK button to try again."));
2445 msg.set_position (Gtk::WIN_POS_CENTER);
2449 int response = msg.run ();
2454 case RESPONSE_CANCEL:
2464 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2467 Gtk::BUTTONS_OK_CANCEL);
2469 msg.set_title (_("Loading Error"));
2470 msg.set_secondary_text (_("Click the OK button to try again."));
2471 msg.set_position (Gtk::WIN_POS_CENTER);
2475 int response = msg.run ();
2480 case RESPONSE_CANCEL:
2488 connect_to_session (new_session);
2490 Config->set_current_owner (ConfigVariableBase::Interface);
2492 session_loaded = true;
2494 goto_editor_window ();
2497 session->set_clean ();
2508 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2509 uint32_t control_channels,
2510 uint32_t master_channels,
2511 AutoConnectOption input_connect,
2512 AutoConnectOption output_connect,
2515 nframes_t initial_length)
2517 Session *new_session;
2520 if (!check_audioengine()) {
2524 session_loaded = false;
2526 x = unload_session ();
2534 _session_is_new = true;
2537 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2538 control_channels, master_channels, nphysin, nphysout, initial_length);
2543 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2549 connect_to_session (new_session);
2551 session_loaded = true;
2559 editor->show_window ();
2570 ARDOUR_UI::show_about ()
2574 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2581 ARDOUR_UI::hide_about ()
2584 about->get_window()->set_cursor ();
2590 ARDOUR_UI::about_signal_response(int response)
2596 ARDOUR_UI::show_splash ()
2600 splash = new Splash;
2608 splash->queue_draw ();
2609 splash->get_window()->process_updates (true);
2614 ARDOUR_UI::hide_splash ()
2622 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
2626 removed = rep.paths.size();
2629 MessageDialog msgd (*editor,
2630 _("No audio files were ready for cleanup"),
2633 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2634 msgd.set_secondary_text (_("If this seems suprising, \n\
2635 check for any existing snapshots.\n\
2636 These may still include regions that\n\
2637 require some unused files to continue to exist."));
2643 ArdourDialog results (_("ardour: cleanup"), true, false);
2645 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2646 CleanupResultsModelColumns() {
2650 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2651 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2655 CleanupResultsModelColumns results_columns;
2656 Glib::RefPtr<Gtk::ListStore> results_model;
2657 Gtk::TreeView results_display;
2659 results_model = ListStore::create (results_columns);
2660 results_display.set_model (results_model);
2661 results_display.append_column (list_title, results_columns.visible_name);
2663 results_display.set_name ("CleanupResultsList");
2664 results_display.set_headers_visible (true);
2665 results_display.set_headers_clickable (false);
2666 results_display.set_reorderable (false);
2668 Gtk::ScrolledWindow list_scroller;
2671 Gtk::HBox dhbox; // the hbox for the image and text
2672 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2673 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2675 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2677 if (rep.space < 1048576.0f) {
2679 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2681 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2685 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2687 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2691 dhbox.pack_start (*dimage, true, false, 5);
2692 dhbox.pack_start (txt, true, false, 5);
2694 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2695 TreeModel::Row row = *(results_model->append());
2696 row[results_columns.visible_name] = *i;
2697 row[results_columns.fullpath] = *i;
2700 list_scroller.add (results_display);
2701 list_scroller.set_size_request (-1, 150);
2702 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2704 dvbox.pack_start (dhbox, true, false, 5);
2705 dvbox.pack_start (list_scroller, true, false, 5);
2706 ddhbox.pack_start (dvbox, true, false, 5);
2708 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2709 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2710 results.set_default_response (RESPONSE_CLOSE);
2711 results.set_position (Gtk::WIN_POS_MOUSE);
2712 results.show_all_children ();
2713 results.set_resizable (false);
2720 ARDOUR_UI::cleanup ()
2723 /* shouldn't happen: menu item is insensitive */
2728 MessageDialog checker (_("Are you sure you want to cleanup?"),
2730 Gtk::MESSAGE_QUESTION,
2731 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2733 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2734 ALL undo/redo information will be lost if you cleanup.\n\
2735 After cleanup, unused audio files will be moved to a \
2736 \"dead sounds\" location."));
2738 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2739 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2740 checker.set_default_response (RESPONSE_CANCEL);
2742 checker.set_name (_("CleanupDialog"));
2743 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2744 checker.set_position (Gtk::WIN_POS_MOUSE);
2746 switch (checker.run()) {
2747 case RESPONSE_ACCEPT:
2753 Session::cleanup_report rep;
2755 editor->prepare_for_cleanup ();
2757 /* do not allow flush until a session is reloaded */
2759 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2761 act->set_sensitive (false);
2764 if (session->cleanup_sources (rep)) {
2765 editor->finish_cleanup ();
2769 editor->finish_cleanup ();
2772 display_cleanup_results (rep,
2775 The following %1 %2 not in use and \n\
2776 have been moved to:\n\
2778 Flushing the wastebasket will \n\
2779 release an additional\n\
2780 %4 %5bytes of disk space.\n"
2786 ARDOUR_UI::flush_trash ()
2789 /* shouldn't happen: menu item is insensitive */
2793 Session::cleanup_report rep;
2795 if (session->cleanup_trash_sources (rep)) {
2799 display_cleanup_results (rep,
2801 _("The following %1 %2 deleted from\n\
2803 releasing %4 %5bytes of disk space"));
2807 ARDOUR_UI::add_route (Gtk::Window* float_window)
2815 if (add_route_dialog == 0) {
2816 add_route_dialog = new AddRouteDialog;
2818 add_route_dialog->set_transient_for (*float_window);
2822 if (add_route_dialog->is_visible()) {
2823 /* we're already doing this */
2827 ResponseType r = (ResponseType) add_route_dialog->run ();
2829 add_route_dialog->hide();
2832 case RESPONSE_ACCEPT:
2839 if ((count = add_route_dialog->count()) <= 0) {
2843 uint32_t input_chan = add_route_dialog->channels ();
2844 uint32_t output_chan;
2845 string name_template = add_route_dialog->name_template ();
2846 bool track = add_route_dialog->track ();
2848 AutoConnectOption oac = Config->get_output_auto_connect();
2850 if (oac & AutoConnectMaster) {
2851 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2853 output_chan = input_chan;
2856 /* XXX do something with name template */
2858 cerr << "Adding with " << input_chan << " in and " << output_chan << "out\n";
2861 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
2863 session_add_audio_bus (input_chan, output_chan, count);
2868 ARDOUR_UI::mixer_settings () const
2873 node = session->instant_xml(X_("Mixer"), session->path());
2875 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
2879 node = new XMLNode (X_("Mixer"));
2886 ARDOUR_UI::editor_settings () const
2891 node = session->instant_xml(X_("Editor"), session->path());
2893 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
2897 node = new XMLNode (X_("Editor"));
2903 ARDOUR_UI::keyboard_settings () const
2907 node = Config->extra_xml(X_("Keyboard"));
2910 node = new XMLNode (X_("Keyboard"));
2916 ARDOUR_UI::create_xrun_marker(nframes_t where)
2918 editor->mouse_add_new_marker (where, false, true);
2922 ARDOUR_UI::halt_on_xrun_message ()
2924 MessageDialog msg (*editor,
2925 _("Recording was stopped because your system could not keep up."));
2930 ARDOUR_UI::xrun_handler(nframes_t where)
2932 ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::xrun_handler), where));
2934 if (Config->get_create_xrun_marker() && session->actively_recording()) {
2935 create_xrun_marker(where);
2938 if (Config->get_stop_recording_on_xrun() && session->actively_recording()) {
2939 halt_on_xrun_message ();
2944 ARDOUR_UI::disk_overrun_handler ()
2946 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
2948 if (!have_disk_speed_dialog_displayed) {
2949 have_disk_speed_dialog_displayed = true;
2950 MessageDialog* msg = new MessageDialog (*editor, _("\
2951 The disk system on your computer\n\
2952 was not able to keep up with Ardour.\n\
2954 Specifically, it failed to write data to disk\n\
2955 quickly enough to keep up with recording.\n"));
2956 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
2962 ARDOUR_UI::disk_underrun_handler ()
2964 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2966 if (!have_disk_speed_dialog_displayed) {
2967 have_disk_speed_dialog_displayed = true;
2968 MessageDialog* msg = new MessageDialog (*editor,
2969 _("The disk system on your computer\n\
2970 was not able to keep up with Ardour.\n\
2972 Specifically, it failed to read data from disk\n\
2973 quickly enough to keep up with playback.\n"));
2974 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
2980 ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
2982 have_disk_speed_dialog_displayed = false;
2987 ARDOUR_UI::session_dialog (std::string msg)
2989 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
2994 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
2996 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3005 ARDOUR_UI::pending_state_dialog ()
3007 HBox* hbox = new HBox();
3008 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3009 ArdourDialog dialog (_("Crash Recovery"), true);
3011 This session appears to have been in\n\
3012 middle of recording when ardour or\n\
3013 the computer was shutdown.\n\
3015 Ardour can recover any captured audio for\n\
3016 you, or it can ignore it. Please decide\n\
3017 what you would like to do.\n"));
3018 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3019 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3020 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3021 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3022 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3023 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3024 dialog.set_default_response (RESPONSE_ACCEPT);
3025 dialog.set_position (WIN_POS_CENTER);
3030 switch (dialog.run ()) {
3031 case RESPONSE_ACCEPT:
3039 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3041 HBox* hbox = new HBox();
3042 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3043 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3044 Label message (string_compose (_("\
3045 This session was created with a sample rate of %1 Hz\n\
3047 The audioengine is currently running at %2 Hz\n"), desired, actual));
3049 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3050 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3051 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3052 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3053 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3054 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3055 dialog.set_default_response (RESPONSE_ACCEPT);
3056 dialog.set_position (WIN_POS_CENTER);
3061 switch (dialog.run ()) {
3062 case RESPONSE_ACCEPT:
3071 ARDOUR_UI::disconnect_from_jack ()
3074 if( engine->disconnect_from_jack ()) {
3075 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3079 update_sample_rate (0);
3084 ARDOUR_UI::reconnect_to_jack ()
3087 if (engine->reconnect_to_jack ()) {
3088 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3092 update_sample_rate (0);
3097 ARDOUR_UI::use_config ()
3099 Glib::RefPtr<Action> act;
3101 switch (Config->get_native_file_data_format ()) {
3103 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
3106 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
3109 act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit"));
3114 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3115 ract->set_active ();
3118 switch (Config->get_native_file_header_format ()) {
3120 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
3123 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
3126 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
3129 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
3132 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
3135 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
3138 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
3143 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3144 ract->set_active ();
3147 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3149 set_transport_controllable_state (*node);
3154 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3156 if (Config->get_primary_clock_delta_edit_cursor()) {
3157 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3159 primary_clock.set (pos, 0, true);
3162 if (Config->get_secondary_clock_delta_edit_cursor()) {
3163 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3165 secondary_clock.set (pos);
3168 if (big_clock_window) {
3169 big_clock.set (pos);
3174 ARDOUR_UI::record_state_changed ()
3176 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3178 if (!session || !big_clock_window) {
3179 /* why bother - the clock isn't visible */
3183 switch (session->record_status()) {
3184 case Session::Recording:
3185 big_clock.set_widget_name ("BigClockRecording");
3188 big_clock.set_widget_name ("BigClockNonRecording");
3194 ARDOUR_UI::first_idle ()
3197 session->allow_auto_play (true);
3201 editor->first_idle();
3204 Keyboard::set_can_save_keybindings (true);
3209 ARDOUR_UI::store_clock_modes ()
3211 XMLNode* node = new XMLNode(X_("ClockModes"));
3213 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3214 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3217 session->add_extra_xml (*node);
3218 session->set_dirty ();
3223 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3224 : Controllable (name), ui (u), type(tp)
3230 ARDOUR_UI::TransportControllable::set_value (float val)
3232 if (type == ShuttleControl) {
3239 fract = -((0.5f - val)/0.5f);
3241 fract = ((val - 0.5f)/0.5f);
3245 ui.set_shuttle_fract (fract);
3250 /* do nothing: these are radio-style actions */
3254 const char *action = 0;
3258 action = X_("Roll");
3261 action = X_("Stop");
3264 action = X_("Goto Start");
3267 action = X_("Goto End");
3270 action = X_("Loop");
3273 action = X_("Play Selection");
3276 action = X_("Record");
3286 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3294 ARDOUR_UI::TransportControllable::get_value (void) const
3313 case ShuttleControl:
3323 ARDOUR_UI::TransportControllable::set_id (const string& str)
3329 ARDOUR_UI::setup_profile ()
3331 if (gdk_screen_width() < 1200) {
3332 Profile->set_small_screen ();
3335 if (getenv ("ARDOUR_SAE")) {
3336 Profile->set_sae ();
3337 Profile->set_single_package ();